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