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
29 UBC 0 : descriptor_destructor(void *arg)
30 : {
31 0 : descriptor_deallocate_all(arg);
32 0 : }
33 :
34 : static void
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
48 1600027 : set_descriptors(struct descriptor *value)
49 : {
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 *
61 73 : ecpg_result_by_descriptor(int line, const char *name)
62 : {
63 73 : struct descriptor *desc = ecpg_find_desc(line, name);
64 :
65 73 : if (desc == NULL)
66 UBC 0 : return NULL;
67 CBC 73 : return desc->result;
68 : }
69 :
70 : static unsigned int
71 8 : ecpg_dynamic_type_DDT(Oid type)
72 : {
73 8 : switch (type)
74 : {
75 8 : case DATEOID:
76 8 : return SQL3_DDT_DATE;
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
91 CBC 12 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
92 : {
93 : PGresult *ECPGresult;
94 12 : struct sqlca_t *sqlca = ECPGget_sqlca();
95 :
96 12 : if (sqlca == NULL)
97 : {
98 UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
99 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
100 0 : return false;
101 : }
102 :
103 CBC 12 : ecpg_init_sqlca(sqlca);
104 12 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
105 12 : if (!ECPGresult)
106 UBC 0 : return false;
107 :
108 CBC 12 : *count = PQnfields(ECPGresult);
109 12 : sqlca->sqlerrd[2] = 1;
110 12 : ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
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 : {
119 UBC 0 : case ECPGt_short:
120 0 : *(short *) var = (short) value;
121 0 : break;
122 CBC 103 : case ECPGt_int:
123 103 : *(int *) var = (int) value;
124 103 : break;
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:
150 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
151 0 : return false;
152 : }
153 :
154 CBC 103 : return true;
155 : }
156 :
157 : static bool
158 4 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
159 : {
160 4 : switch (vartype)
161 : {
162 UBC 0 : case ECPGt_short:
163 0 : *target = *(const short *) var;
164 0 : break;
165 CBC 4 : case ECPGt_int:
166 4 : *target = *(const int *) var;
167 4 : break;
168 UBC 0 : case ECPGt_long:
169 0 : *target = *(const long *) var;
170 0 : break;
171 0 : case ECPGt_unsigned_short:
172 0 : *target = *(const unsigned short *) var;
173 0 : break;
174 0 : case ECPGt_unsigned_int:
175 0 : *target = *(const unsigned int *) var;
176 0 : break;
177 0 : case ECPGt_unsigned_long:
178 0 : *target = *(const unsigned long *) var;
179 0 : break;
180 0 : case ECPGt_long_long:
181 0 : *target = *(const long long int *) var;
182 0 : break;
183 0 : case ECPGt_unsigned_long_long:
184 0 : *target = *(const unsigned long long int *) var;
185 0 : break;
186 0 : case ECPGt_float:
187 0 : *target = *(const float *) var;
188 0 : break;
189 0 : case ECPGt_double:
190 0 : *target = *(const double *) var;
191 0 : break;
192 0 : default:
193 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
194 0 : return false;
195 : }
196 :
197 CBC 4 : return true;
198 : }
199 :
200 : static bool
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;
210 UBC 0 : case ECPGt_varchar:
211 : {
212 0 : struct ECPGgeneric_varchar *variable =
213 : (struct ECPGgeneric_varchar *) var;
214 :
215 0 : if (varcharsize == 0)
216 0 : memcpy(variable->arr, value, strlen(value));
217 : else
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:
226 0 : ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
227 0 : return false;
228 : }
229 :
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
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;
249 61 : struct sqlca_t *sqlca = ECPGget_sqlca();
250 :
251 61 : if (sqlca == NULL)
252 : {
253 UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
254 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
255 0 : return false;
256 : }
257 :
258 CBC 61 : va_start(args, index);
259 61 : ecpg_init_sqlca(sqlca);
260 61 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
261 61 : if (!ECPGresult)
262 : {
263 UBC 0 : va_end(args);
264 0 : return false;
265 : }
266 :
267 CBC 61 : ntuples = PQntuples(ECPGresult);
268 :
269 61 : if (index < 1 || index > PQnfields(ECPGresult))
270 : {
271 UBC 0 : ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
272 0 : va_end(args);
273 0 : return false;
274 : }
275 :
276 CBC 61 : ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
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):
303 26 : RETURN_IF_NO_DATA;
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;
309 26 : if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
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:
316 28 : RETURN_IF_NO_DATA;
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 : {
331 UBC 0 : va_end(args);
332 0 : return false;
333 : }
334 :
335 CBC 30 : ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
336 30 : break;
337 :
338 UBC 0 : case ECPGd_nullable:
339 0 : if (!get_int_item(lineno, var, vartype, 1))
340 : {
341 0 : va_end(args);
342 0 : return false;
343 : }
344 :
345 0 : break;
346 :
347 0 : case ECPGd_key_member:
348 0 : if (!get_int_item(lineno, var, vartype, 0))
349 : {
350 0 : va_end(args);
351 0 : return false;
352 : }
353 :
354 0 : break;
355 :
356 CBC 14 : case ECPGd_scale:
357 14 : if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
358 : {
359 UBC 0 : va_end(args);
360 0 : return false;
361 : }
362 :
363 CBC 14 : ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
364 14 : break;
365 :
366 14 : case ECPGd_precision:
367 14 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
368 : {
369 UBC 0 : va_end(args);
370 0 : return false;
371 : }
372 :
373 CBC 14 : ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
374 14 : break;
375 :
376 14 : case ECPGd_octet:
377 14 : if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
378 : {
379 UBC 0 : va_end(args);
380 0 : return false;
381 : }
382 :
383 CBC 14 : ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
384 14 : break;
385 :
386 15 : case ECPGd_length:
387 15 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
388 : {
389 UBC 0 : va_end(args);
390 0 : return false;
391 : }
392 :
393 CBC 15 : ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
394 15 : break;
395 :
396 14 : case ECPGd_type:
397 14 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
398 : {
399 UBC 0 : va_end(args);
400 0 : return false;
401 : }
402 :
403 CBC 14 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
404 14 : break;
405 :
406 4 : case ECPGd_di_code:
407 4 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
408 : {
409 UBC 0 : va_end(args);
410 0 : return false;
411 : }
412 :
413 CBC 4 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
414 4 : break;
415 :
416 UBC 0 : case ECPGd_cardinality:
417 0 : if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
418 : {
419 0 : va_end(args);
420 0 : return false;
421 : }
422 :
423 0 : ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
424 0 : break;
425 :
426 CBC 14 : case ECPGd_ret_length:
427 : case ECPGd_ret_octet:
428 :
429 14 : RETURN_IF_NO_DATA;
430 :
431 : /*
432 : * this is like ECPGstore_result
433 : */
434 14 : if (arrsize > 0 && ntuples > arrsize)
435 : {
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);
438 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
439 0 : va_end(args);
440 0 : return false;
441 : }
442 : /* allocate storage if needed */
443 CBC 14 : if (arrsize == 0 && *(void **) var == NULL)
444 : {
445 UBC 0 : void *mem = (void *) ecpg_auto_alloc(offset * ntuples, lineno);
446 :
447 0 : if (!mem)
448 : {
449 0 : va_end(args);
450 0 : return false;
451 : }
452 0 : *(void **) var = mem;
453 0 : var = mem;
454 : }
455 :
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 : {
460 UBC 0 : va_end(args);
461 0 : return false;
462 : }
463 CBC 14 : var = (char *) var + offset;
464 14 : ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
465 : }
466 14 : break;
467 :
468 UBC 0 : default:
469 0 : snprintf(type_str, sizeof(type_str), "%d", type);
470 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
471 0 : va_end(args);
472 0 : return false;
473 : }
474 :
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 :
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 : */
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 */
508 28 : stmt.connection = ecpg_get_connection(NULL);
509 28 : ecpg_store_result(ECPGresult, index, &stmt, &data_var);
510 :
511 : #ifdef HAVE_USELOCALE
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 : }
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 : */
538 14 : if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
539 : {
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);
542 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
543 0 : va_end(args);
544 0 : return false;
545 : }
546 :
547 : /* allocate storage if needed */
548 CBC 14 : if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
549 : {
550 UBC 0 : void *mem = (void *) ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
551 :
552 0 : if (!mem)
553 : {
554 0 : va_end(args);
555 0 : return false;
556 : }
557 0 : *(void **) data_var.ind_pointer = mem;
558 0 : data_var.ind_value = mem;
559 : }
560 :
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 : {
565 UBC 0 : va_end(args);
566 0 : return false;
567 : }
568 CBC 14 : data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
569 14 : ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
570 : }
571 : }
572 61 : sqlca->sqlerrd[2] = ntuples;
573 61 : va_end(args);
574 61 : return true;
575 : }
576 :
577 : #undef RETURN_IF_NO_DATA
578 :
579 : bool
580 1 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
581 : {
582 1 : struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
583 :
584 1 : if (desc == NULL)
585 UBC 0 : return false;
586 CBC 1 : desc->count = count;
587 1 : return true;
588 : }
589 :
590 : static void
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 : {
599 2 : struct ECPGgeneric_bytea *variable =
600 : (struct ECPGgeneric_bytea *) (var->value);
601 :
602 2 : desc_item->is_binary = true;
603 2 : desc_item->data_len = variable->len;
604 : }
605 :
606 11 : ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
607 11 : desc_item->data = (char *) tobeinserted;
608 11 : }
609 :
610 :
611 : bool
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 :
619 11 : desc = ecpg_find_desc(lineno, desc_name);
620 11 : if (desc == NULL)
621 UBC 0 : return false;
622 :
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 : {
631 4 : desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
632 4 : if (!desc_item)
633 UBC 0 : return false;
634 CBC 4 : desc_item->num = index;
635 4 : if (desc->count < index)
636 4 : desc->count = index;
637 4 : desc_item->next = desc->items;
638 4 : desc->items = desc_item;
639 : }
640 :
641 11 : if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
642 UBC 0 : return false;
643 :
644 CBC 11 : va_start(args, index);
645 :
646 : for (;;)
647 15 : {
648 : enum ECPGdtype itemtype;
649 26 : char *tobeinserted = NULL;
650 :
651 26 : itemtype = va_arg(args, enum ECPGdtype);
652 :
653 26 : if (itemtype == ECPGd_EODT)
654 11 : break;
655 :
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)
664 UBC 0 : var->value = *((char **) (var->pointer));
665 : else
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)
673 UBC 0 : var->arrsize = 0;
674 CBC 15 : if (var->varcharsize < 0)
675 UBC 0 : var->varcharsize = 0;
676 :
677 CBC 15 : var->next = NULL;
678 :
679 15 : switch (itemtype)
680 : {
681 11 : case ECPGd_data:
682 : {
683 11 : if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
684 : {
685 UBC 0 : ecpg_free(var);
686 0 : va_end(args);
687 0 : return false;
688 : }
689 :
690 CBC 11 : set_desc_attr(desc_item, var, tobeinserted);
691 11 : tobeinserted = NULL;
692 11 : break;
693 : }
694 :
695 4 : case ECPGd_indicator:
696 4 : set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
697 4 : break;
698 :
699 UBC 0 : case ECPGd_length:
700 0 : set_int_item(lineno, &desc_item->length, var->pointer, var->type);
701 0 : break;
702 :
703 0 : case ECPGd_precision:
704 0 : set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
705 0 : break;
706 :
707 0 : case ECPGd_scale:
708 0 : set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
709 0 : break;
710 :
711 0 : case ECPGd_type:
712 0 : set_int_item(lineno, &desc_item->type, var->pointer, var->type);
713 0 : break;
714 :
715 0 : default:
716 : {
717 : char type_str[20];
718 :
719 0 : snprintf(type_str, sizeof(type_str), "%d", itemtype);
720 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
721 0 : ecpg_free(var);
722 0 : va_end(args);
723 0 : return false;
724 : }
725 : }
726 : }
727 CBC 11 : ecpg_free(var);
728 11 : va_end(args);
729 :
730 11 : return true;
731 : }
732 :
733 : /* Free the descriptor and items in it. */
734 : static void
735 800015 : descriptor_free(struct descriptor *desc)
736 : {
737 : struct descriptor_item *desc_item;
738 :
739 800017 : for (desc_item = desc->items; desc_item;)
740 : {
741 : struct descriptor_item *di;
742 :
743 2 : ecpg_free(desc_item->data);
744 2 : di = desc_item;
745 2 : desc_item = desc_item->next;
746 2 : ecpg_free(di);
747 : }
748 :
749 800015 : ecpg_free(desc->name);
750 800015 : PQclear(desc->result);
751 800015 : ecpg_free(desc);
752 800015 : }
753 :
754 : bool
755 800015 : ECPGdeallocate_desc(int line, const char *name)
756 : {
757 : struct descriptor *desc;
758 : struct descriptor *prev;
759 800015 : struct sqlca_t *sqlca = ECPGget_sqlca();
760 :
761 800015 : if (sqlca == NULL)
762 : {
763 UBC 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
764 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
765 0 : return false;
766 : }
767 :
768 CBC 800015 : ecpg_init_sqlca(sqlca);
769 800020 : for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
770 : {
771 800020 : if (strcmp(name, desc->name) == 0)
772 : {
773 800015 : if (prev)
774 5 : prev->next = desc->next;
775 : else
776 800010 : set_descriptors(desc->next);
777 800015 : descriptor_free(desc);
778 800015 : return true;
779 : }
780 : }
781 UBC 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
782 0 : return false;
783 : }
784 :
785 : #ifdef ENABLE_THREAD_SAFETY
786 :
787 : /* Deallocate all descriptors in the list */
788 : static void
789 0 : descriptor_deallocate_all(struct descriptor *list)
790 : {
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
802 CBC 800017 : ECPGallocate_desc(int line, const char *name)
803 : {
804 : struct descriptor *new;
805 800017 : struct sqlca_t *sqlca = ECPGget_sqlca();
806 :
807 800017 : if (sqlca == NULL)
808 : {
809 UBC 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
810 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
811 0 : return false;
812 : }
813 :
814 CBC 800017 : ecpg_init_sqlca(sqlca);
815 800017 : new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
816 800017 : if (!new)
817 UBC 0 : return false;
818 CBC 800017 : new->next = get_descriptors();
819 800017 : new->name = ecpg_alloc(strlen(name) + 1, line);
820 800017 : if (!new->name)
821 : {
822 UBC 0 : ecpg_free(new);
823 0 : return false;
824 : }
825 CBC 800017 : new->count = -1;
826 800017 : new->items = NULL;
827 800017 : new->result = PQmakeEmptyPGresult(NULL, 0);
828 800017 : if (!new->result)
829 : {
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);
833 0 : return false;
834 : }
835 CBC 800017 : strcpy(new->name, name);
836 800017 : set_descriptors(new);
837 800017 : return true;
838 : }
839 :
840 : /* Find descriptor with name in the connection. */
841 : struct descriptor *
842 114 : ecpg_find_desc(int line, const char *name)
843 : {
844 : struct descriptor *desc;
845 :
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 :
852 UBC 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
853 0 : return NULL; /* not found */
854 : }
855 :
856 : bool
857 CBC 21 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
858 : {
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 : {
868 UBC 0 : ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
869 0 : return ret;
870 : }
871 :
872 CBC 21 : con = ecpg_get_connection(connection_name);
873 21 : if (!con)
874 : {
875 UBC 0 : ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
876 0 : connection_name ? connection_name : ecpg_gettext("NULL"));
877 0 : return ret;
878 : }
879 CBC 21 : prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
880 21 : if (!prep)
881 : {
882 UBC 0 : ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
883 0 : return ret;
884 : }
885 :
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 *);
901 21 : (void) va_arg(args, long); /* skip args */
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 :
912 21 : switch (type)
913 : {
914 9 : case ECPGt_descriptor:
915 : {
916 9 : char *name = ptr;
917 9 : struct descriptor *desc = ecpg_find_desc(line, name);
918 :
919 9 : if (desc == NULL)
920 UBC 0 : break;
921 :
922 CBC 9 : res = PQdescribePrepared(con->connection, stmt_name);
923 9 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
924 UBC 0 : break;
925 :
926 GNC 9 : PQclear(desc->result);
927 ECB :
928 CBC 9 : desc->result = res;
929 9 : ret = true;
930 GIC 9 : break;
931 ECB : }
932 GIC 12 : case ECPGt_sqlda:
933 ECB : {
934 CBC 12 : if (INFORMIX_MODE(compat))
935 6 : {
936 GIC 6 : struct sqlda_compat **_sqlda = ptr;
937 : struct sqlda_compat *sqlda;
938 ECB :
939 CBC 6 : res = PQdescribePrepared(con->connection, stmt_name);
940 GBC 6 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
941 UIC 0 : break;
942 ECB :
943 CBC 6 : sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
944 GIC 6 : if (sqlda)
945 ECB : {
946 GIC 6 : struct sqlda_compat *sqlda_old = *_sqlda;
947 : struct sqlda_compat *sqlda_old1;
948 ECB :
949 GIC 6 : while (sqlda_old)
950 EUB : {
951 UBC 0 : sqlda_old1 = sqlda_old->desc_next;
952 0 : free(sqlda_old);
953 UIC 0 : sqlda_old = sqlda_old1;
954 : }
955 ECB :
956 CBC 6 : *_sqlda = sqlda;
957 GIC 6 : ret = true;
958 : }
959 ECB :
960 GIC 6 : PQclear(res);
961 : }
962 : else
963 ECB : {
964 GIC 6 : struct sqlda_struct **_sqlda = ptr;
965 : struct sqlda_struct *sqlda;
966 ECB :
967 CBC 6 : res = PQdescribePrepared(con->connection, stmt_name);
968 GBC 6 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
969 UIC 0 : break;
970 ECB :
971 CBC 6 : sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
972 GIC 6 : if (sqlda)
973 ECB : {
974 GIC 6 : struct sqlda_struct *sqlda_old = *_sqlda;
975 : struct sqlda_struct *sqlda_old1;
976 ECB :
977 GIC 6 : while (sqlda_old)
978 EUB : {
979 UBC 0 : sqlda_old1 = sqlda_old->desc_next;
980 0 : free(sqlda_old);
981 UIC 0 : sqlda_old = sqlda_old1;
982 : }
983 ECB :
984 CBC 6 : *_sqlda = sqlda;
985 GIC 6 : ret = true;
986 : }
987 ECB :
988 GIC 6 : PQclear(res);
989 ECB : }
990 GIC 12 : break;
991 ECB : }
992 GIC 21 : default:
993 : /* nothing else may come */
994 : ;
995 : }
996 : }
997 ECB :
998 GIC 21 : va_end(args);
999 ECB :
1000 GIC 21 : return ret;
1001 : }
|