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