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