]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/ecpglib/descriptor.c
Phase 2 of pgindent updates.
[postgresql] / src / interfaces / ecpg / ecpglib / descriptor.c
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
29 descriptor_destructor(void *arg)
30 {
31         descriptor_deallocate_all(arg);
32 }
33
34 static void
35 descriptor_key_init(void)
36 {
37         pthread_key_create(&descriptor_key, descriptor_destructor);
38 }
39
40 static struct descriptor *
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
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 *
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
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
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
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
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
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                                         strncpy(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
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                 char       *oldlocale;
486
487                 /* Make sure we do NOT honor the locale for numeric input */
488                 /* since the database gives the standard decimal point */
489                 oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
490                 setlocale(LC_NUMERIC, "C");
491
492                 memset(&stmt, 0, sizeof stmt);
493                 stmt.lineno = lineno;
494
495                 /* desperate try to guess something sensible */
496                 stmt.connection = ecpg_get_connection(NULL);
497                 ecpg_store_result(ECPGresult, index, &stmt, &data_var);
498
499                 setlocale(LC_NUMERIC, oldlocale);
500                 ecpg_free(oldlocale);
501         }
502         else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
503
504                 /*
505                  * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
506                  * since this might be changed manually in the .c file let's play it
507                  * safe
508                  */
509         {
510                 /*
511                  * this is like ECPGstore_result but since we don't have a data
512                  * variable at hand, we can't call it
513                  */
514                 if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
515                 {
516                         ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
517                                          lineno, ntuples, data_var.ind_arrsize);
518                         ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
519                         va_end(args);
520                         return false;
521                 }
522
523                 /* allocate storage if needed */
524                 if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
525                 {
526                         void       *mem = (void *) ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
527
528                         if (!mem)
529                         {
530                                 va_end(args);
531                                 return false;
532                         }
533                         *(void **) data_var.ind_pointer = mem;
534                         data_var.ind_value = mem;
535                 }
536
537                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
538                 {
539                         if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
540                         {
541                                 va_end(args);
542                                 return (false);
543                         }
544                         data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
545                         ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
546                 }
547         }
548         sqlca->sqlerrd[2] = ntuples;
549         va_end(args);
550         return (true);
551 }
552
553 #undef RETURN_IF_NO_DATA
554
555 bool
556 ECPGset_desc_header(int lineno, const char *desc_name, int count)
557 {
558         struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
559
560         if (desc == NULL)
561                 return false;
562         desc->count = count;
563         return true;
564 }
565
566 bool
567 ECPGset_desc(int lineno, const char *desc_name, int index,...)
568 {
569         va_list         args;
570         struct descriptor *desc;
571         struct descriptor_item *desc_item;
572         struct variable *var;
573
574         desc = ecpg_find_desc(lineno, desc_name);
575         if (desc == NULL)
576                 return false;
577
578         for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
579         {
580                 if (desc_item->num == index)
581                         break;
582         }
583
584         if (desc_item == NULL)
585         {
586                 desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
587                 if (!desc_item)
588                         return false;
589                 desc_item->num = index;
590                 if (desc->count < index)
591                         desc->count = index;
592                 desc_item->next = desc->items;
593                 desc->items = desc_item;
594         }
595
596         if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
597                 return false;
598
599         va_start(args, index);
600
601         for (;;)
602         {
603                 enum ECPGdtype itemtype;
604                 char       *tobeinserted = NULL;
605
606                 itemtype = va_arg(args, enum ECPGdtype);
607
608                 if (itemtype == ECPGd_EODT)
609                         break;
610
611                 var->type = va_arg(args, enum ECPGttype);
612                 var->pointer = va_arg(args, char *);
613
614                 var->varcharsize = va_arg(args, long);
615                 var->arrsize = va_arg(args, long);
616                 var->offset = va_arg(args, long);
617
618                 if (var->arrsize == 0 || var->varcharsize == 0)
619                         var->value = *((char **) (var->pointer));
620                 else
621                         var->value = var->pointer;
622
623                 /*
624                  * negative values are used to indicate an array without given bounds
625                  */
626                 /* reset to zero for us */
627                 if (var->arrsize < 0)
628                         var->arrsize = 0;
629                 if (var->varcharsize < 0)
630                         var->varcharsize = 0;
631
632                 var->next = NULL;
633
634                 switch (itemtype)
635                 {
636                         case ECPGd_data:
637                                 {
638                                         if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
639                                         {
640                                                 ecpg_free(var);
641                                                 va_end(args);
642                                                 return false;
643                                         }
644
645                                         ecpg_free(desc_item->data); /* free() takes care of a
646                                                                                                  * potential NULL value */
647                                         desc_item->data = (char *) tobeinserted;
648                                         tobeinserted = NULL;
649                                         break;
650                                 }
651
652                         case ECPGd_indicator:
653                                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
654                                 break;
655
656                         case ECPGd_length:
657                                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
658                                 break;
659
660                         case ECPGd_precision:
661                                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
662                                 break;
663
664                         case ECPGd_scale:
665                                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
666                                 break;
667
668                         case ECPGd_type:
669                                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
670                                 break;
671
672                         default:
673                                 {
674                                         char            type_str[20];
675
676                                         snprintf(type_str, sizeof(type_str), "%d", itemtype);
677                                         ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
678                                         ecpg_free(var);
679                                         va_end(args);
680                                         return false;
681                                 }
682                 }
683         }
684         ecpg_free(var);
685         va_end(args);
686
687         return true;
688 }
689
690 /* Free the descriptor and items in it. */
691 static void
692 descriptor_free(struct descriptor *desc)
693 {
694         struct descriptor_item *desc_item;
695
696         for (desc_item = desc->items; desc_item;)
697         {
698                 struct descriptor_item *di;
699
700                 ecpg_free(desc_item->data);
701                 di = desc_item;
702                 desc_item = desc_item->next;
703                 ecpg_free(di);
704         }
705
706         ecpg_free(desc->name);
707         PQclear(desc->result);
708         ecpg_free(desc);
709 }
710
711 bool
712 ECPGdeallocate_desc(int line, const char *name)
713 {
714         struct descriptor *desc;
715         struct descriptor *prev;
716         struct sqlca_t *sqlca = ECPGget_sqlca();
717
718         if (sqlca == NULL)
719         {
720                 ecpg_raise(line, ECPG_OUT_OF_MEMORY,
721                                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
722                 return false;
723         }
724
725         ecpg_init_sqlca(sqlca);
726         for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
727         {
728                 if (strcmp(name, desc->name) == 0)
729                 {
730                         if (prev)
731                                 prev->next = desc->next;
732                         else
733                                 set_descriptors(desc->next);
734                         descriptor_free(desc);
735                         return true;
736                 }
737         }
738         ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
739         return false;
740 }
741
742 #ifdef ENABLE_THREAD_SAFETY
743
744 /* Deallocate all descriptors in the list */
745 static void
746 descriptor_deallocate_all(struct descriptor *list)
747 {
748         while (list)
749         {
750                 struct descriptor *next = list->next;
751
752                 descriptor_free(list);
753                 list = next;
754         }
755 }
756 #endif                                                  /* ENABLE_THREAD_SAFETY */
757
758 bool
759 ECPGallocate_desc(int line, const char *name)
760 {
761         struct descriptor *new;
762         struct sqlca_t *sqlca = ECPGget_sqlca();
763
764         if (sqlca == NULL)
765         {
766                 ecpg_raise(line, ECPG_OUT_OF_MEMORY,
767                                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
768                 return false;
769         }
770
771         ecpg_init_sqlca(sqlca);
772         new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
773         if (!new)
774                 return false;
775         new->next = get_descriptors();
776         new->name = ecpg_alloc(strlen(name) + 1, line);
777         if (!new->name)
778         {
779                 ecpg_free(new);
780                 return false;
781         }
782         new->count = -1;
783         new->items = NULL;
784         new->result = PQmakeEmptyPGresult(NULL, 0);
785         if (!new->result)
786         {
787                 ecpg_free(new->name);
788                 ecpg_free(new);
789                 ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
790                 return false;
791         }
792         strcpy(new->name, name);
793         set_descriptors(new);
794         return true;
795 }
796
797 /* Find descriptor with name in the connection. */
798 struct descriptor *
799 ecpg_find_desc(int line, const char *name)
800 {
801         struct descriptor *desc;
802
803         for (desc = get_descriptors(); desc; desc = desc->next)
804         {
805                 if (strcmp(name, desc->name) == 0)
806                         return desc;
807         }
808
809         ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
810         return NULL;                            /* not found */
811 }
812
813 bool
814 ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
815 {
816         bool            ret = false;
817         struct connection *con;
818         struct prepared_statement *prep;
819         PGresult   *res;
820         va_list         args;
821
822         /* DESCRIBE INPUT is not yet supported */
823         if (input)
824         {
825                 ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
826                 return ret;
827         }
828
829         con = ecpg_get_connection(connection_name);
830         if (!con)
831         {
832                 ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
833                                    connection_name ? connection_name : ecpg_gettext("NULL"));
834                 return ret;
835         }
836         prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
837         if (!prep)
838         {
839                 ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
840                 return ret;
841         }
842
843         va_start(args, stmt_name);
844
845         for (;;)
846         {
847                 enum ECPGttype type;
848                 void       *ptr;
849
850                 /* variable type */
851                 type = va_arg(args, enum ECPGttype);
852
853                 if (type == ECPGt_EORT)
854                         break;
855
856                 /* rest of variable parameters */
857                 ptr = va_arg(args, void *);
858                 (void) va_arg(args, long);      /* skip args */
859                 (void) va_arg(args, long);
860                 (void) va_arg(args, long);
861
862                 /* variable indicator */
863                 (void) va_arg(args, enum ECPGttype);
864                 (void) va_arg(args, void *);    /* skip args */
865                 (void) va_arg(args, long);
866                 (void) va_arg(args, long);
867                 (void) va_arg(args, long);
868
869                 switch (type)
870                 {
871                         case ECPGt_descriptor:
872                                 {
873                                         char       *name = ptr;
874                                         struct descriptor *desc = ecpg_find_desc(line, name);
875
876                                         if (desc == NULL)
877                                                 break;
878
879                                         res = PQdescribePrepared(con->connection, stmt_name);
880                                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
881                                                 break;
882
883                                         if (desc->result != NULL)
884                                                 PQclear(desc->result);
885
886                                         desc->result = res;
887                                         ret = true;
888                                         break;
889                                 }
890                         case ECPGt_sqlda:
891                                 {
892                                         if (INFORMIX_MODE(compat))
893                                         {
894                                                 struct sqlda_compat **_sqlda = ptr;
895                                                 struct sqlda_compat *sqlda;
896
897                                                 res = PQdescribePrepared(con->connection, stmt_name);
898                                                 if (!ecpg_check_PQresult(res, line, con->connection, compat))
899                                                         break;
900
901                                                 sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
902                                                 if (sqlda)
903                                                 {
904                                                         struct sqlda_compat *sqlda_old = *_sqlda;
905                                                         struct sqlda_compat *sqlda_old1;
906
907                                                         while (sqlda_old)
908                                                         {
909                                                                 sqlda_old1 = sqlda_old->desc_next;
910                                                                 free(sqlda_old);
911                                                                 sqlda_old = sqlda_old1;
912                                                         }
913
914                                                         *_sqlda = sqlda;
915                                                         ret = true;
916                                                 }
917
918                                                 PQclear(res);
919                                         }
920                                         else
921                                         {
922                                                 struct sqlda_struct **_sqlda = ptr;
923                                                 struct sqlda_struct *sqlda;
924
925                                                 res = PQdescribePrepared(con->connection, stmt_name);
926                                                 if (!ecpg_check_PQresult(res, line, con->connection, compat))
927                                                         break;
928
929                                                 sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
930                                                 if (sqlda)
931                                                 {
932                                                         struct sqlda_struct *sqlda_old = *_sqlda;
933                                                         struct sqlda_struct *sqlda_old1;
934
935                                                         while (sqlda_old)
936                                                         {
937                                                                 sqlda_old1 = sqlda_old->desc_next;
938                                                                 free(sqlda_old);
939                                                                 sqlda_old = sqlda_old1;
940                                                         }
941
942                                                         *_sqlda = sqlda;
943                                                         ret = true;
944                                                 }
945
946                                                 PQclear(res);
947                                         }
948                                         break;
949                                 }
950                         default:
951                                 /* nothing else may come */
952                                 ;
953                 }
954         }
955
956         va_end(args);
957
958         return ret;
959 }