Age Owner TLA Line data Source code
1 : /* dynamic SQL support routines
2 : *
3 : * src/interfaces/ecpg/ecpglib/descriptor.c
4 : */
5 :
6 : #define POSTGRES_ECPG_INTERNAL
7 : #include "postgres_fe.h"
8 :
9 : #include "catalog/pg_type_d.h"
10 : #include "ecpg-pthread-win32.h"
11 : #include "ecpgerrno.h"
12 : #include "ecpglib.h"
13 : #include "ecpglib_extern.h"
14 : #include "ecpgtype.h"
15 : #include "sql3types.h"
16 : #include "sqlca.h"
17 : #include "sqlda.h"
18 :
19 : static void descriptor_free(struct descriptor *desc);
20 :
21 : /* We manage descriptors separately for each thread. */
22 : #ifdef ENABLE_THREAD_SAFETY
23 : static pthread_key_t descriptor_key;
24 : static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
25 :
26 : static void descriptor_deallocate_all(struct descriptor *list);
27 :
28 : static void
5668 meskes 29 UBC 0 : descriptor_destructor(void *arg)
30 : {
31 0 : descriptor_deallocate_all(arg);
32 0 : }
33 :
34 : static void
5668 meskes 35 CBC 9 : descriptor_key_init(void)
36 : {
37 9 : pthread_key_create(&descriptor_key, descriptor_destructor);
38 9 : }
39 :
40 : static struct descriptor *
41 1600146 : get_descriptors(void)
42 : {
43 1600146 : pthread_once(&descriptor_once, descriptor_key_init);
44 1600146 : return (struct descriptor *) pthread_getspecific(descriptor_key);
45 : }
46 :
47 : static void
2118 tgl 48 1600027 : set_descriptors(struct descriptor *value)
49 : {
5668 meskes 50 1600027 : pthread_setspecific(descriptor_key, value);
51 1600027 : }
52 : #else
53 : static struct descriptor *all_descriptors = NULL;
54 :
55 : #define get_descriptors() (all_descriptors)
56 : #define set_descriptors(value) do { all_descriptors = (value); } while(0)
57 : #endif
58 :
59 : /* old internal convenience function that might go away later */
60 : static PGresult *
5667 61 73 : ecpg_result_by_descriptor(int line, const char *name)
62 : {
63 73 : struct descriptor *desc = ecpg_find_desc(line, name);
64 :
5668 65 73 : if (desc == NULL)
5668 meskes 66 UBC 0 : return NULL;
5668 meskes 67 CBC 73 : return desc->result;
68 : }
69 :
70 : static unsigned int
5667 71 8 : ecpg_dynamic_type_DDT(Oid type)
72 : {
7329 73 8 : switch (type)
74 : {
75 8 : case DATEOID:
76 8 : return SQL3_DDT_DATE;
7329 meskes 77 UBC 0 : case TIMEOID:
78 0 : return SQL3_DDT_TIME;
79 0 : case TIMESTAMPOID:
80 0 : return SQL3_DDT_TIMESTAMP;
81 0 : case TIMESTAMPTZOID:
82 0 : return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
83 0 : case TIMETZOID:
84 0 : return SQL3_DDT_TIME_WITH_TIME_ZONE;
85 0 : default:
86 0 : return SQL3_DDT_ILLEGAL;
87 : }
88 : }
89 :
90 : bool
6339 meskes 91 CBC 12 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
92 : {
93 : PGresult *ECPGresult;
7238 bruce 94 12 : struct sqlca_t *sqlca = ECPGget_sqlca();
95 :
2855 meskes 96 12 : if (sqlca == NULL)
97 : {
2855 meskes 98 UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
99 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
100 0 : return false;
101 : }
102 :
5667 meskes 103 CBC 12 : ecpg_init_sqlca(sqlca);
104 12 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
7329 105 12 : if (!ECPGresult)
7329 meskes 106 UBC 0 : return false;
107 :
7329 meskes 108 CBC 12 : *count = PQnfields(ECPGresult);
7238 bruce 109 12 : sqlca->sqlerrd[2] = 1;
5441 peter_e 110 12 : ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
7329 meskes 111 12 : return true;
112 : }
113 :
114 : static bool
115 103 : get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
116 : {
117 103 : switch (vartype)
118 : {
7329 meskes 119 UBC 0 : case ECPGt_short:
120 0 : *(short *) var = (short) value;
121 0 : break;
7329 meskes 122 CBC 103 : case ECPGt_int:
123 103 : *(int *) var = (int) value;
124 103 : break;
7329 meskes 125 UBC 0 : case ECPGt_long:
126 0 : *(long *) var = (long) value;
127 0 : break;
128 0 : case ECPGt_unsigned_short:
129 0 : *(unsigned short *) var = (unsigned short) value;
130 0 : break;
131 0 : case ECPGt_unsigned_int:
132 0 : *(unsigned int *) var = (unsigned int) value;
133 0 : break;
134 0 : case ECPGt_unsigned_long:
135 0 : *(unsigned long *) var = (unsigned long) value;
136 0 : break;
137 0 : case ECPGt_long_long:
138 0 : *(long long int *) var = (long long int) value;
139 0 : break;
140 0 : case ECPGt_unsigned_long_long:
141 0 : *(unsigned long long int *) var = (unsigned long long int) value;
142 0 : break;
143 0 : case ECPGt_float:
144 0 : *(float *) var = (float) value;
145 0 : break;
146 0 : case ECPGt_double:
147 0 : *(double *) var = (double) value;
148 0 : break;
149 0 : default:
5667 150 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
2061 peter_e 151 0 : return false;
152 : }
153 :
2061 peter_e 154 CBC 103 : return true;
155 : }
156 :
157 : static bool
6857 meskes 158 4 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
159 : {
160 4 : switch (vartype)
161 : {
6857 meskes 162 UBC 0 : case ECPGt_short:
4228 peter_e 163 0 : *target = *(const short *) var;
6857 meskes 164 0 : break;
6857 meskes 165 CBC 4 : case ECPGt_int:
4228 peter_e 166 4 : *target = *(const int *) var;
6857 meskes 167 4 : break;
6857 meskes 168 UBC 0 : case ECPGt_long:
4228 peter_e 169 0 : *target = *(const long *) var;
6857 meskes 170 0 : break;
171 0 : case ECPGt_unsigned_short:
4228 peter_e 172 0 : *target = *(const unsigned short *) var;
6857 meskes 173 0 : break;
174 0 : case ECPGt_unsigned_int:
4228 peter_e 175 0 : *target = *(const unsigned int *) var;
6857 meskes 176 0 : break;
177 0 : case ECPGt_unsigned_long:
4228 peter_e 178 0 : *target = *(const unsigned long *) var;
6857 meskes 179 0 : break;
180 0 : case ECPGt_long_long:
4228 peter_e 181 0 : *target = *(const long long int *) var;
6857 meskes 182 0 : break;
183 0 : case ECPGt_unsigned_long_long:
4228 peter_e 184 0 : *target = *(const unsigned long long int *) var;
6857 meskes 185 0 : break;
186 0 : case ECPGt_float:
4228 peter_e 187 0 : *target = *(const float *) var;
6857 meskes 188 0 : break;
189 0 : case ECPGt_double:
4228 peter_e 190 0 : *target = *(const double *) var;
6857 meskes 191 0 : break;
192 0 : default:
5667 193 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
2061 peter_e 194 0 : return false;
195 : }
196 :
6857 meskes 197 CBC 4 : return true;
198 : }
199 :
200 : static bool
7329 201 30 : get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
202 : {
203 30 : switch (vartype)
204 : {
205 30 : case ECPGt_char:
206 : case ECPGt_unsigned_char:
207 : case ECPGt_string:
208 30 : strncpy((char *) var, value, varcharsize);
209 30 : break;
7329 meskes 210 UBC 0 : case ECPGt_varchar:
211 : {
212 0 : struct ECPGgeneric_varchar *variable =
213 : (struct ECPGgeneric_varchar *) var;
214 :
215 0 : if (varcharsize == 0)
1758 tgl 216 0 : memcpy(variable->arr, value, strlen(value));
217 : else
7329 meskes 218 0 : strncpy(variable->arr, value, varcharsize);
219 :
220 0 : variable->len = strlen(value);
221 0 : if (varcharsize > 0 && variable->len > varcharsize)
222 0 : variable->len = varcharsize;
223 : }
224 0 : break;
225 0 : default:
5667 226 0 : ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
2061 peter_e 227 0 : return false;
228 : }
229 :
2061 peter_e 230 CBC 30 : return true;
231 : }
232 :
233 : #define RETURN_IF_NO_DATA if (ntuples < 1) \
234 : { \
235 : va_end(args); \
236 : ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
237 : return false; \
238 : }
239 :
240 : bool
6339 meskes 241 61 : ECPGget_desc(int lineno, const char *desc_name, int index,...)
242 : {
243 : va_list args;
244 : PGresult *ECPGresult;
245 : enum ECPGdtype type;
246 : int ntuples,
247 : act_tuple;
248 : struct variable data_var;
7238 bruce 249 61 : struct sqlca_t *sqlca = ECPGget_sqlca();
250 :
2855 meskes 251 61 : if (sqlca == NULL)
252 : {
2855 meskes 253 UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
254 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
255 0 : return false;
256 : }
257 :
7329 meskes 258 CBC 61 : va_start(args, index);
5667 259 61 : ecpg_init_sqlca(sqlca);
260 61 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
7329 261 61 : if (!ECPGresult)
262 : {
4043 peter_e 263 UBC 0 : va_end(args);
2061 264 0 : return false;
265 : }
266 :
7329 meskes 267 CBC 61 : ntuples = PQntuples(ECPGresult);
268 :
269 61 : if (index < 1 || index > PQnfields(ECPGresult))
270 : {
5667 meskes 271 UBC 0 : ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
4043 peter_e 272 0 : va_end(args);
2061 273 0 : return false;
274 : }
275 :
5667 meskes 276 CBC 61 : ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
7329 277 61 : --index;
278 :
279 61 : type = va_arg(args, enum ECPGdtype);
280 :
281 61 : memset(&data_var, 0, sizeof data_var);
282 61 : data_var.type = ECPGt_EORT;
283 61 : data_var.ind_type = ECPGt_NO_INDICATOR;
284 :
285 234 : while (type != ECPGd_EODT)
286 : {
287 : char type_str[20];
288 : long varcharsize;
289 : long offset;
290 : long arrsize;
291 : enum ECPGttype vartype;
292 : void *var;
293 :
294 173 : vartype = va_arg(args, enum ECPGttype);
295 173 : var = va_arg(args, void *);
296 173 : varcharsize = va_arg(args, long);
297 173 : arrsize = va_arg(args, long);
298 173 : offset = va_arg(args, long);
299 :
300 173 : switch (type)
301 : {
302 26 : case (ECPGd_indicator):
4832 303 26 : RETURN_IF_NO_DATA;
7329 304 26 : data_var.ind_type = vartype;
305 26 : data_var.ind_pointer = var;
306 26 : data_var.ind_varcharsize = varcharsize;
307 26 : data_var.ind_arrsize = arrsize;
308 26 : data_var.ind_offset = offset;
6092 309 26 : if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
7329 310 10 : data_var.ind_value = *((void **) (data_var.ind_pointer));
311 : else
312 16 : data_var.ind_value = data_var.ind_pointer;
313 26 : break;
314 :
315 28 : case ECPGd_data:
4832 316 28 : RETURN_IF_NO_DATA;
7329 317 28 : data_var.type = vartype;
318 28 : data_var.pointer = var;
319 28 : data_var.varcharsize = varcharsize;
320 28 : data_var.arrsize = arrsize;
321 28 : data_var.offset = offset;
322 28 : if (data_var.arrsize == 0 || data_var.varcharsize == 0)
323 10 : data_var.value = *((void **) (data_var.pointer));
324 : else
325 18 : data_var.value = data_var.pointer;
326 28 : break;
327 :
328 30 : case ECPGd_name:
329 30 : if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
330 : {
4043 peter_e 331 UBC 0 : va_end(args);
2061 332 0 : return false;
333 : }
334 :
5667 meskes 335 CBC 30 : ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
7329 336 30 : break;
337 :
7329 meskes 338 UBC 0 : case ECPGd_nullable:
339 0 : if (!get_int_item(lineno, var, vartype, 1))
340 : {
4043 peter_e 341 0 : va_end(args);
2061 342 0 : return false;
343 : }
344 :
7329 meskes 345 0 : break;
346 :
347 0 : case ECPGd_key_member:
348 0 : if (!get_int_item(lineno, var, vartype, 0))
349 : {
4043 peter_e 350 0 : va_end(args);
2061 351 0 : return false;
352 : }
353 :
7329 meskes 354 0 : break;
355 :
7329 meskes 356 CBC 14 : case ECPGd_scale:
357 14 : if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
358 : {
4043 peter_e 359 UBC 0 : va_end(args);
2061 360 0 : return false;
361 : }
362 :
5667 meskes 363 CBC 14 : ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
7329 364 14 : break;
365 :
366 14 : case ECPGd_precision:
367 14 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
368 : {
4043 peter_e 369 UBC 0 : va_end(args);
2061 370 0 : return false;
371 : }
372 :
5667 meskes 373 CBC 14 : ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
7329 374 14 : break;
375 :
376 14 : case ECPGd_octet:
377 14 : if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
378 : {
4043 peter_e 379 UBC 0 : va_end(args);
2061 380 0 : return false;
381 : }
382 :
5667 meskes 383 CBC 14 : ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
7329 384 14 : break;
385 :
386 15 : case ECPGd_length:
387 15 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
388 : {
4043 peter_e 389 UBC 0 : va_end(args);
2061 390 0 : return false;
391 : }
392 :
5667 meskes 393 CBC 15 : ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
7329 394 15 : break;
395 :
396 14 : case ECPGd_type:
5667 397 14 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
398 : {
4043 peter_e 399 UBC 0 : va_end(args);
2061 400 0 : return false;
401 : }
402 :
5667 meskes 403 CBC 14 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
7329 404 14 : break;
405 :
406 4 : case ECPGd_di_code:
5667 407 4 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
408 : {
4043 peter_e 409 UBC 0 : va_end(args);
2061 410 0 : return false;
411 : }
412 :
5667 meskes 413 CBC 4 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
7329 414 4 : break;
415 :
7329 meskes 416 UBC 0 : case ECPGd_cardinality:
417 0 : if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
418 : {
4043 peter_e 419 0 : va_end(args);
2061 420 0 : return false;
421 : }
422 :
5667 meskes 423 0 : ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
7329 424 0 : break;
425 :
7329 meskes 426 CBC 14 : case ECPGd_ret_length:
427 : case ECPGd_ret_octet:
428 :
4832 429 14 : RETURN_IF_NO_DATA;
430 :
431 : /*
432 : * this is like ECPGstore_result
433 : */
7329 434 14 : if (arrsize > 0 && ntuples > arrsize)
435 : {
4229 peter_e 436 UBC 0 : ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
437 : lineno, ntuples, arrsize);
5667 meskes 438 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
4043 peter_e 439 0 : va_end(args);
7329 meskes 440 0 : return false;
441 : }
442 : /* allocate storage if needed */
6132 meskes 443 CBC 14 : if (arrsize == 0 && *(void **) var == NULL)
444 : {
2985 meskes 445 UBC 0 : void *mem = (void *) ecpg_auto_alloc(offset * ntuples, lineno);
446 :
6136 447 0 : if (!mem)
448 : {
4043 peter_e 449 0 : va_end(args);
6136 meskes 450 0 : return false;
451 : }
7329 452 0 : *(void **) var = mem;
453 0 : var = mem;
454 : }
455 :
7329 meskes 456 CBC 28 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
457 : {
458 14 : if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
459 : {
4043 peter_e 460 UBC 0 : va_end(args);
2061 461 0 : return false;
462 : }
7329 meskes 463 CBC 14 : var = (char *) var + offset;
5667 464 14 : ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
465 : }
7329 466 14 : break;
467 :
7329 meskes 468 UBC 0 : default:
469 0 : snprintf(type_str, sizeof(type_str), "%d", type);
5667 470 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
4043 peter_e 471 0 : va_end(args);
2061 472 0 : return false;
473 : }
474 :
7329 meskes 475 CBC 173 : type = va_arg(args, enum ECPGdtype);
476 : }
477 :
478 61 : if (data_var.type != ECPGt_EORT)
479 : {
480 : struct statement stmt;
481 :
1539 tgl 482 28 : memset(&stmt, 0, sizeof stmt);
483 28 : stmt.lineno = lineno;
484 :
485 : /* Make sure we do NOT honor the locale for numeric input */
486 : /* since the database gives the standard decimal point */
487 : /* (see comments in execute.c) */
488 : #ifdef HAVE_USELOCALE
489 :
490 : /*
491 : * To get here, the above PQnfields() test must have found nonzero
492 : * fields. One needs a connection to create such a descriptor. (EXEC
493 : * SQL SET DESCRIPTOR can populate the descriptor's "items", but it
494 : * can't change the descriptor's PQnfields().) Any successful
495 : * connection initializes ecpg_clocale.
496 : */
281 noah 497 28 : Assert(ecpg_clocale);
498 28 : stmt.oldlocale = uselocale(ecpg_clocale);
499 : #else
500 : #ifdef HAVE__CONFIGTHREADLOCALE
501 : stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
502 : #endif
503 : stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
504 : setlocale(LC_NUMERIC, "C");
505 : #endif
506 :
507 : /* desperate try to guess something sensible */
5667 meskes 508 28 : stmt.connection = ecpg_get_connection(NULL);
509 28 : ecpg_store_result(ECPGresult, index, &stmt, &data_var);
510 :
511 : #ifdef HAVE_USELOCALE
1539 tgl 512 28 : if (stmt.oldlocale != (locale_t) 0)
513 28 : uselocale(stmt.oldlocale);
514 : #else
515 : if (stmt.oldlocale)
516 : {
517 : setlocale(LC_NUMERIC, stmt.oldlocale);
518 : ecpg_free(stmt.oldlocale);
519 : }
520 : #ifdef HAVE__CONFIGTHREADLOCALE
521 : if (stmt.oldthreadlocale != -1)
522 : (void) _configthreadlocale(stmt.oldthreadlocale);
523 : #endif
524 : #endif
525 : }
6122 meskes 526 33 : else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
527 :
528 : /*
529 : * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
530 : * since this might be changed manually in the .c file let's play it
531 : * safe
532 : */
533 : {
534 : /*
535 : * this is like ECPGstore_result but since we don't have a data
536 : * variable at hand, we can't call it
537 : */
7329 538 14 : if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
539 : {
4229 peter_e 540 UBC 0 : ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
541 : lineno, ntuples, data_var.ind_arrsize);
5667 meskes 542 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
4043 peter_e 543 0 : va_end(args);
7329 meskes 544 0 : return false;
545 : }
546 :
547 : /* allocate storage if needed */
6122 meskes 548 CBC 14 : if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
549 : {
2985 meskes 550 UBC 0 : void *mem = (void *) ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
551 :
6136 552 0 : if (!mem)
553 : {
4043 peter_e 554 0 : va_end(args);
6136 meskes 555 0 : return false;
556 : }
7329 557 0 : *(void **) data_var.ind_pointer = mem;
558 0 : data_var.ind_value = mem;
559 : }
560 :
7329 meskes 561 CBC 28 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
562 : {
563 14 : if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
564 : {
4043 peter_e 565 UBC 0 : va_end(args);
2061 566 0 : return false;
567 : }
7329 meskes 568 CBC 14 : data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
5667 569 14 : ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
570 : }
571 : }
7238 bruce 572 61 : sqlca->sqlerrd[2] = ntuples;
4043 peter_e 573 61 : va_end(args);
2061 574 61 : return true;
575 : }
576 :
577 : #undef RETURN_IF_NO_DATA
578 :
579 : bool
6339 meskes 580 1 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
581 : {
5667 582 1 : struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
583 :
6852 584 1 : if (desc == NULL)
6852 meskes 585 UBC 0 : return false;
6852 meskes 586 CBC 1 : desc->count = count;
587 1 : return true;
588 : }
589 :
590 : static void
1511 591 11 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
592 : char *tobeinserted)
593 : {
594 11 : if (var->type != ECPGt_bytea)
595 9 : desc_item->is_binary = false;
596 :
597 : else
598 : {
986 michael 599 2 : struct ECPGgeneric_bytea *variable =
600 : (struct ECPGgeneric_bytea *) (var->value);
601 :
1511 meskes 602 2 : desc_item->is_binary = true;
603 2 : desc_item->data_len = variable->len;
604 : }
605 :
1418 tgl 606 11 : ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
1511 meskes 607 11 : desc_item->data = (char *) tobeinserted;
608 11 : }
609 :
610 :
611 : bool
6339 612 11 : ECPGset_desc(int lineno, const char *desc_name, int index,...)
613 : {
614 : va_list args;
615 : struct descriptor *desc;
616 : struct descriptor_item *desc_item;
617 : struct variable *var;
618 :
5667 619 11 : desc = ecpg_find_desc(lineno, desc_name);
6857 620 11 : if (desc == NULL)
6857 meskes 621 UBC 0 : return false;
622 :
6857 meskes 623 CBC 17 : for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
624 : {
625 13 : if (desc_item->num == index)
626 7 : break;
627 : }
628 :
629 11 : if (desc_item == NULL)
630 : {
5667 631 4 : desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
6136 632 4 : if (!desc_item)
6136 meskes 633 UBC 0 : return false;
6857 meskes 634 CBC 4 : desc_item->num = index;
5717 635 4 : if (desc->count < index)
636 4 : desc->count = index;
6857 637 4 : desc_item->next = desc->items;
638 4 : desc->items = desc_item;
639 : }
640 :
5667 641 11 : if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
6797 bruce 642 UBC 0 : return false;
643 :
6857 meskes 644 CBC 11 : va_start(args, index);
645 :
646 : for (;;)
647 15 : {
648 : enum ECPGdtype itemtype;
5050 bruce 649 26 : char *tobeinserted = NULL;
650 :
6857 meskes 651 26 : itemtype = va_arg(args, enum ECPGdtype);
652 :
653 26 : if (itemtype == ECPGd_EODT)
654 11 : break;
655 :
5826 656 15 : var->type = va_arg(args, enum ECPGttype);
657 15 : var->pointer = va_arg(args, char *);
658 :
659 15 : var->varcharsize = va_arg(args, long);
660 15 : var->arrsize = va_arg(args, long);
661 15 : var->offset = va_arg(args, long);
662 :
663 15 : if (var->arrsize == 0 || var->varcharsize == 0)
5826 meskes 664 UBC 0 : var->value = *((char **) (var->pointer));
665 : else
5826 meskes 666 CBC 15 : var->value = var->pointer;
667 :
668 : /*
669 : * negative values are used to indicate an array without given bounds
670 : */
671 : /* reset to zero for us */
672 15 : if (var->arrsize < 0)
5826 meskes 673 UBC 0 : var->arrsize = 0;
5826 meskes 674 CBC 15 : if (var->varcharsize < 0)
5826 meskes 675 UBC 0 : var->varcharsize = 0;
676 :
5826 meskes 677 CBC 15 : var->next = NULL;
678 :
6857 679 15 : switch (itemtype)
680 : {
681 11 : case ECPGd_data:
682 : {
5667 683 11 : if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
684 : {
5667 meskes 685 UBC 0 : ecpg_free(var);
4043 peter_e 686 0 : va_end(args);
6797 bruce 687 0 : return false;
688 : }
689 :
1511 meskes 690 CBC 11 : set_desc_attr(desc_item, var, tobeinserted);
6797 bruce 691 11 : tobeinserted = NULL;
692 11 : break;
693 : }
694 :
6857 meskes 695 4 : case ECPGd_indicator:
6853 696 4 : set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
6857 697 4 : break;
698 :
6857 meskes 699 UBC 0 : case ECPGd_length:
6853 700 0 : set_int_item(lineno, &desc_item->length, var->pointer, var->type);
6857 701 0 : break;
702 :
703 0 : case ECPGd_precision:
6853 704 0 : set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
6857 705 0 : break;
706 :
707 0 : case ECPGd_scale:
6853 708 0 : set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
6857 709 0 : break;
710 :
711 0 : case ECPGd_type:
6853 712 0 : set_int_item(lineno, &desc_item->type, var->pointer, var->type);
6857 713 0 : break;
714 :
715 0 : default:
716 : {
717 : char type_str[20];
718 :
6797 bruce 719 0 : snprintf(type_str, sizeof(type_str), "%d", itemtype);
5667 meskes 720 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
721 0 : ecpg_free(var);
4043 peter_e 722 0 : va_end(args);
6797 bruce 723 0 : return false;
724 : }
725 : }
726 : }
5667 meskes 727 CBC 11 : ecpg_free(var);
4043 peter_e 728 11 : va_end(args);
729 :
6857 meskes 730 11 : return true;
731 : }
732 :
733 : /* Free the descriptor and items in it. */
734 : static void
2118 tgl 735 800015 : descriptor_free(struct descriptor *desc)
736 : {
737 : struct descriptor_item *desc_item;
738 :
5668 meskes 739 800017 : for (desc_item = desc->items; desc_item;)
740 : {
741 : struct descriptor_item *di;
742 :
5667 743 2 : ecpg_free(desc_item->data);
5668 744 2 : di = desc_item;
745 2 : desc_item = desc_item->next;
5667 746 2 : ecpg_free(di);
747 : }
748 :
749 800015 : ecpg_free(desc->name);
5668 750 800015 : PQclear(desc->result);
5667 751 800015 : ecpg_free(desc);
5668 752 800015 : }
753 :
754 : bool
7329 755 800015 : ECPGdeallocate_desc(int line, const char *name)
756 : {
757 : struct descriptor *desc;
758 : struct descriptor *prev;
7238 bruce 759 800015 : struct sqlca_t *sqlca = ECPGget_sqlca();
760 :
2855 meskes 761 800015 : if (sqlca == NULL)
762 : {
2855 meskes 763 UBC 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
764 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
765 0 : return false;
766 : }
767 :
5667 meskes 768 CBC 800015 : ecpg_init_sqlca(sqlca);
5668 769 800020 : for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
770 : {
4121 peter_e 771 800020 : if (strcmp(name, desc->name) == 0)
772 : {
5668 meskes 773 800015 : if (prev)
774 5 : prev->next = desc->next;
775 : else
776 800010 : set_descriptors(desc->next);
777 800015 : descriptor_free(desc);
7329 778 800015 : return true;
779 : }
780 : }
5667 meskes 781 UBC 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
7329 782 0 : return false;
783 : }
784 :
785 : #ifdef ENABLE_THREAD_SAFETY
786 :
787 : /* Deallocate all descriptors in the list */
788 : static void
2118 tgl 789 0 : descriptor_deallocate_all(struct descriptor *list)
790 : {
5668 meskes 791 0 : while (list)
792 : {
793 0 : struct descriptor *next = list->next;
794 :
795 0 : descriptor_free(list);
796 0 : list = next;
797 : }
798 0 : }
799 : #endif /* ENABLE_THREAD_SAFETY */
800 :
801 : bool
7329 meskes 802 CBC 800017 : ECPGallocate_desc(int line, const char *name)
803 : {
804 : struct descriptor *new;
7238 bruce 805 800017 : struct sqlca_t *sqlca = ECPGget_sqlca();
806 :
2855 meskes 807 800017 : if (sqlca == NULL)
808 : {
2855 meskes 809 UBC 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
810 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
811 0 : return false;
812 : }
813 :
5667 meskes 814 CBC 800017 : ecpg_init_sqlca(sqlca);
815 800017 : new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
7329 816 800017 : if (!new)
7329 meskes 817 UBC 0 : return false;
5668 meskes 818 CBC 800017 : new->next = get_descriptors();
5667 819 800017 : new->name = ecpg_alloc(strlen(name) + 1, line);
7329 820 800017 : if (!new->name)
821 : {
5667 meskes 822 UBC 0 : ecpg_free(new);
7329 823 0 : return false;
824 : }
6852 meskes 825 CBC 800017 : new->count = -1;
6857 826 800017 : new->items = NULL;
7329 827 800017 : new->result = PQmakeEmptyPGresult(NULL, 0);
828 800017 : if (!new->result)
829 : {
5667 meskes 830 UBC 0 : ecpg_free(new->name);
831 0 : ecpg_free(new);
832 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
7329 833 0 : return false;
834 : }
7329 meskes 835 CBC 800017 : strcpy(new->name, name);
5668 836 800017 : set_descriptors(new);
7329 837 800017 : return true;
838 : }
839 :
840 : /* Find descriptor with name in the connection. */
841 : struct descriptor *
5667 842 114 : ecpg_find_desc(int line, const char *name)
843 : {
844 : struct descriptor *desc;
845 :
5668 846 159 : for (desc = get_descriptors(); desc; desc = desc->next)
847 : {
848 159 : if (strcmp(name, desc->name) == 0)
849 114 : return desc;
850 : }
851 :
5667 meskes 852 UBC 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
5624 bruce 853 0 : return NULL; /* not found */
854 : }
855 :
856 : bool
4790 bruce 857 CBC 21 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
858 : {
4832 meskes 859 21 : bool ret = false;
860 : struct connection *con;
861 : struct prepared_statement *prep;
862 : PGresult *res;
863 : va_list args;
864 :
865 : /* DESCRIBE INPUT is not yet supported */
866 21 : if (input)
867 : {
4832 meskes 868 UBC 0 : ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
869 0 : return ret;
870 : }
871 :
1297 tgl 872 CBC 21 : con = ecpg_get_connection(connection_name);
4832 meskes 873 21 : if (!con)
874 : {
4832 meskes 875 UBC 0 : ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
1297 tgl 876 0 : connection_name ? connection_name : ecpg_gettext("NULL"));
4832 meskes 877 0 : return ret;
878 : }
4832 meskes 879 CBC 21 : prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
880 21 : if (!prep)
881 : {
4832 meskes 882 UBC 0 : ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
883 0 : return ret;
884 : }
885 :
4832 meskes 886 CBC 21 : va_start(args, stmt_name);
887 :
888 : for (;;)
889 21 : {
890 : enum ECPGttype type;
891 : void *ptr;
892 :
893 : /* variable type */
894 42 : type = va_arg(args, enum ECPGttype);
895 :
896 42 : if (type == ECPGt_EORT)
897 21 : break;
898 :
899 : /* rest of variable parameters */
900 21 : ptr = va_arg(args, void *);
2118 tgl 901 21 : (void) va_arg(args, long); /* skip args */
4380 902 21 : (void) va_arg(args, long);
903 21 : (void) va_arg(args, long);
904 :
905 : /* variable indicator */
906 21 : (void) va_arg(args, enum ECPGttype);
907 21 : (void) va_arg(args, void *); /* skip args */
908 21 : (void) va_arg(args, long);
909 21 : (void) va_arg(args, long);
910 21 : (void) va_arg(args, long);
911 :
4832 meskes 912 21 : switch (type)
913 : {
914 9 : case ECPGt_descriptor:
915 : {
4790 bruce 916 9 : char *name = ptr;
917 9 : struct descriptor *desc = ecpg_find_desc(line, name);
918 :
919 9 : if (desc == NULL)
4790 bruce 920 UBC 0 : break;
921 :
4832 meskes 922 CBC 9 : res = PQdescribePrepared(con->connection, stmt_name);
923 9 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
4832 meskes 924 UBC 0 : break;
925 :
280 peter 926 GNC 9 : PQclear(desc->result);
4790 bruce 927 ECB :
4790 bruce 928 CBC 9 : desc->result = res;
929 9 : ret = true;
4790 bruce 930 GIC 9 : break;
4790 bruce 931 ECB : }
4790 bruce 932 GIC 12 : case ECPGt_sqlda:
4790 bruce 933 ECB : {
4790 bruce 934 CBC 12 : if (INFORMIX_MODE(compat))
4832 meskes 935 6 : {
4790 bruce 936 GIC 6 : struct sqlda_compat **_sqlda = ptr;
937 : struct sqlda_compat *sqlda;
4790 bruce 938 ECB :
4790 bruce 939 CBC 6 : res = PQdescribePrepared(con->connection, stmt_name);
4790 bruce 940 GBC 6 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
4790 bruce 941 UIC 0 : break;
4832 meskes 942 ECB :
4790 bruce 943 CBC 6 : sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
4790 bruce 944 GIC 6 : if (sqlda)
4832 meskes 945 ECB : {
4790 bruce 946 GIC 6 : struct sqlda_compat *sqlda_old = *_sqlda;
947 : struct sqlda_compat *sqlda_old1;
4790 bruce 948 ECB :
4790 bruce 949 GIC 6 : while (sqlda_old)
4790 bruce 950 EUB : {
4790 bruce 951 UBC 0 : sqlda_old1 = sqlda_old->desc_next;
952 0 : free(sqlda_old);
4790 bruce 953 UIC 0 : sqlda_old = sqlda_old1;
954 : }
4790 bruce 955 ECB :
4790 bruce 956 CBC 6 : *_sqlda = sqlda;
4790 bruce 957 GIC 6 : ret = true;
958 : }
4832 meskes 959 ECB :
4790 bruce 960 GIC 6 : PQclear(res);
961 : }
962 : else
4832 meskes 963 ECB : {
4790 bruce 964 GIC 6 : struct sqlda_struct **_sqlda = ptr;
965 : struct sqlda_struct *sqlda;
4790 bruce 966 ECB :
4790 bruce 967 CBC 6 : res = PQdescribePrepared(con->connection, stmt_name);
4790 bruce 968 GBC 6 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
4790 bruce 969 UIC 0 : break;
4832 meskes 970 ECB :
4790 bruce 971 CBC 6 : sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
4790 bruce 972 GIC 6 : if (sqlda)
4832 meskes 973 ECB : {
4790 bruce 974 GIC 6 : struct sqlda_struct *sqlda_old = *_sqlda;
975 : struct sqlda_struct *sqlda_old1;
4790 bruce 976 ECB :
4790 bruce 977 GIC 6 : while (sqlda_old)
4790 bruce 978 EUB : {
4790 bruce 979 UBC 0 : sqlda_old1 = sqlda_old->desc_next;
980 0 : free(sqlda_old);
4790 bruce 981 UIC 0 : sqlda_old = sqlda_old1;
982 : }
4790 bruce 983 ECB :
4790 bruce 984 CBC 6 : *_sqlda = sqlda;
4790 bruce 985 GIC 6 : ret = true;
986 : }
4832 meskes 987 ECB :
4790 bruce 988 GIC 6 : PQclear(res);
4832 meskes 989 ECB : }
4790 bruce 990 GIC 12 : break;
4832 meskes 991 ECB : }
4832 meskes 992 GIC 21 : default:
993 : /* nothing else may come */
994 : ;
995 : }
996 : }
4832 meskes 997 ECB :
4832 meskes 998 GIC 21 : va_end(args);
4832 meskes 999 ECB :
4832 meskes 1000 GIC 21 : return ret;
1001 : }
|