]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/ecpglib/descriptor.c
Initial pgindent run for v12.
[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
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 "ecpglib_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
30 descriptor_destructor(void *arg)
31 {
32         descriptor_deallocate_all(arg);
33 }
34
35 static void
36 descriptor_key_init(void)
37 {
38         pthread_key_create(&descriptor_key, descriptor_destructor);
39 }
40
41 static struct descriptor *
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
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 *
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
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
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
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
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
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
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
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 static void
591 set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
592                           char *tobeinserted)
593 {
594         if (var->type != ECPGt_bytea)
595                 desc_item->is_binary = false;
596
597         else
598         {
599                 struct ECPGgeneric_varchar *variable =
600                 (struct ECPGgeneric_varchar *) (var->value);
601
602                 desc_item->is_binary = true;
603                 desc_item->data_len = variable->len;
604         }
605
606         ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
607         desc_item->data = (char *) tobeinserted;
608 }
609
610
611 bool
612 ECPGset_desc(int lineno, const char *desc_name, int index,...)
613 {
614         va_list         args;
615         struct descriptor *desc;
616         struct descriptor_item *desc_item;
617         struct variable *var;
618
619         desc = ecpg_find_desc(lineno, desc_name);
620         if (desc == NULL)
621                 return false;
622
623         for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
624         {
625                 if (desc_item->num == index)
626                         break;
627         }
628
629         if (desc_item == NULL)
630         {
631                 desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
632                 if (!desc_item)
633                         return false;
634                 desc_item->num = index;
635                 if (desc->count < index)
636                         desc->count = index;
637                 desc_item->next = desc->items;
638                 desc->items = desc_item;
639         }
640
641         if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
642                 return false;
643
644         va_start(args, index);
645
646         for (;;)
647         {
648                 enum ECPGdtype itemtype;
649                 char       *tobeinserted = NULL;
650
651                 itemtype = va_arg(args, enum ECPGdtype);
652
653                 if (itemtype == ECPGd_EODT)
654                         break;
655
656                 var->type = va_arg(args, enum ECPGttype);
657                 var->pointer = va_arg(args, char *);
658
659                 var->varcharsize = va_arg(args, long);
660                 var->arrsize = va_arg(args, long);
661                 var->offset = va_arg(args, long);
662
663                 if (var->arrsize == 0 || var->varcharsize == 0)
664                         var->value = *((char **) (var->pointer));
665                 else
666                         var->value = var->pointer;
667
668                 /*
669                  * negative values are used to indicate an array without given bounds
670                  */
671                 /* reset to zero for us */
672                 if (var->arrsize < 0)
673                         var->arrsize = 0;
674                 if (var->varcharsize < 0)
675                         var->varcharsize = 0;
676
677                 var->next = NULL;
678
679                 switch (itemtype)
680                 {
681                         case ECPGd_data:
682                                 {
683                                         if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
684                                         {
685                                                 ecpg_free(var);
686                                                 va_end(args);
687                                                 return false;
688                                         }
689
690                                         set_desc_attr(desc_item, var, tobeinserted);
691                                         tobeinserted = NULL;
692                                         break;
693                                 }
694
695                         case ECPGd_indicator:
696                                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
697                                 break;
698
699                         case ECPGd_length:
700                                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
701                                 break;
702
703                         case ECPGd_precision:
704                                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
705                                 break;
706
707                         case ECPGd_scale:
708                                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
709                                 break;
710
711                         case ECPGd_type:
712                                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
713                                 break;
714
715                         default:
716                                 {
717                                         char            type_str[20];
718
719                                         snprintf(type_str, sizeof(type_str), "%d", itemtype);
720                                         ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
721                                         ecpg_free(var);
722                                         va_end(args);
723                                         return false;
724                                 }
725                 }
726         }
727         ecpg_free(var);
728         va_end(args);
729
730         return true;
731 }
732
733 /* Free the descriptor and items in it. */
734 static void
735 descriptor_free(struct descriptor *desc)
736 {
737         struct descriptor_item *desc_item;
738
739         for (desc_item = desc->items; desc_item;)
740         {
741                 struct descriptor_item *di;
742
743                 ecpg_free(desc_item->data);
744                 di = desc_item;
745                 desc_item = desc_item->next;
746                 ecpg_free(di);
747         }
748
749         ecpg_free(desc->name);
750         PQclear(desc->result);
751         ecpg_free(desc);
752 }
753
754 bool
755 ECPGdeallocate_desc(int line, const char *name)
756 {
757         struct descriptor *desc;
758         struct descriptor *prev;
759         struct sqlca_t *sqlca = ECPGget_sqlca();
760
761         if (sqlca == NULL)
762         {
763                 ecpg_raise(line, ECPG_OUT_OF_MEMORY,
764                                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
765                 return false;
766         }
767
768         ecpg_init_sqlca(sqlca);
769         for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
770         {
771                 if (strcmp(name, desc->name) == 0)
772                 {
773                         if (prev)
774                                 prev->next = desc->next;
775                         else
776                                 set_descriptors(desc->next);
777                         descriptor_free(desc);
778                         return true;
779                 }
780         }
781         ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
782         return false;
783 }
784
785 #ifdef ENABLE_THREAD_SAFETY
786
787 /* Deallocate all descriptors in the list */
788 static void
789 descriptor_deallocate_all(struct descriptor *list)
790 {
791         while (list)
792         {
793                 struct descriptor *next = list->next;
794
795                 descriptor_free(list);
796                 list = next;
797         }
798 }
799 #endif                                                  /* ENABLE_THREAD_SAFETY */
800
801 bool
802 ECPGallocate_desc(int line, const char *name)
803 {
804         struct descriptor *new;
805         struct sqlca_t *sqlca = ECPGget_sqlca();
806
807         if (sqlca == NULL)
808         {
809                 ecpg_raise(line, ECPG_OUT_OF_MEMORY,
810                                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
811                 return false;
812         }
813
814         ecpg_init_sqlca(sqlca);
815         new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
816         if (!new)
817                 return false;
818         new->next = get_descriptors();
819         new->name = ecpg_alloc(strlen(name) + 1, line);
820         if (!new->name)
821         {
822                 ecpg_free(new);
823                 return false;
824         }
825         new->count = -1;
826         new->items = NULL;
827         new->result = PQmakeEmptyPGresult(NULL, 0);
828         if (!new->result)
829         {
830                 ecpg_free(new->name);
831                 ecpg_free(new);
832                 ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
833                 return false;
834         }
835         strcpy(new->name, name);
836         set_descriptors(new);
837         return true;
838 }
839
840 /* Find descriptor with name in the connection. */
841 struct descriptor *
842 ecpg_find_desc(int line, const char *name)
843 {
844         struct descriptor *desc;
845
846         for (desc = get_descriptors(); desc; desc = desc->next)
847         {
848                 if (strcmp(name, desc->name) == 0)
849                         return desc;
850         }
851
852         ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
853         return NULL;                            /* not found */
854 }
855
856 bool
857 ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
858 {
859         bool            ret = false;
860         struct connection *con;
861         struct prepared_statement *prep;
862         PGresult   *res;
863         va_list         args;
864         const char *real_connection_name = NULL;
865
866         /* DESCRIBE INPUT is not yet supported */
867         if (input)
868         {
869                 ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
870                 return ret;
871         }
872
873         real_connection_name = ecpg_get_con_name_by_declared_name(stmt_name);
874         if (real_connection_name == NULL)
875         {
876                 /*
877                  * If can't get the connection name by declared name then using
878                  * connection name coming from the parameter connection_name
879                  */
880                 real_connection_name = connection_name;
881         }
882
883         con = ecpg_get_connection(real_connection_name);
884         if (!con)
885         {
886                 ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
887                                    real_connection_name ? real_connection_name : ecpg_gettext("NULL"));
888                 return ret;
889         }
890         prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
891         if (!prep)
892         {
893                 ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
894                 return ret;
895         }
896
897         va_start(args, stmt_name);
898
899         for (;;)
900         {
901                 enum ECPGttype type;
902                 void       *ptr;
903
904                 /* variable type */
905                 type = va_arg(args, enum ECPGttype);
906
907                 if (type == ECPGt_EORT)
908                         break;
909
910                 /* rest of variable parameters */
911                 ptr = va_arg(args, void *);
912                 (void) va_arg(args, long);      /* skip args */
913                 (void) va_arg(args, long);
914                 (void) va_arg(args, long);
915
916                 /* variable indicator */
917                 (void) va_arg(args, enum ECPGttype);
918                 (void) va_arg(args, void *);    /* skip args */
919                 (void) va_arg(args, long);
920                 (void) va_arg(args, long);
921                 (void) va_arg(args, long);
922
923                 switch (type)
924                 {
925                         case ECPGt_descriptor:
926                                 {
927                                         char       *name = ptr;
928                                         struct descriptor *desc = ecpg_find_desc(line, name);
929
930                                         if (desc == NULL)
931                                                 break;
932
933                                         res = PQdescribePrepared(con->connection, stmt_name);
934                                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
935                                                 break;
936
937                                         if (desc->result != NULL)
938                                                 PQclear(desc->result);
939
940                                         desc->result = res;
941                                         ret = true;
942                                         break;
943                                 }
944                         case ECPGt_sqlda:
945                                 {
946                                         if (INFORMIX_MODE(compat))
947                                         {
948                                                 struct sqlda_compat **_sqlda = ptr;
949                                                 struct sqlda_compat *sqlda;
950
951                                                 res = PQdescribePrepared(con->connection, stmt_name);
952                                                 if (!ecpg_check_PQresult(res, line, con->connection, compat))
953                                                         break;
954
955                                                 sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
956                                                 if (sqlda)
957                                                 {
958                                                         struct sqlda_compat *sqlda_old = *_sqlda;
959                                                         struct sqlda_compat *sqlda_old1;
960
961                                                         while (sqlda_old)
962                                                         {
963                                                                 sqlda_old1 = sqlda_old->desc_next;
964                                                                 free(sqlda_old);
965                                                                 sqlda_old = sqlda_old1;
966                                                         }
967
968                                                         *_sqlda = sqlda;
969                                                         ret = true;
970                                                 }
971
972                                                 PQclear(res);
973                                         }
974                                         else
975                                         {
976                                                 struct sqlda_struct **_sqlda = ptr;
977                                                 struct sqlda_struct *sqlda;
978
979                                                 res = PQdescribePrepared(con->connection, stmt_name);
980                                                 if (!ecpg_check_PQresult(res, line, con->connection, compat))
981                                                         break;
982
983                                                 sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
984                                                 if (sqlda)
985                                                 {
986                                                         struct sqlda_struct *sqlda_old = *_sqlda;
987                                                         struct sqlda_struct *sqlda_old1;
988
989                                                         while (sqlda_old)
990                                                         {
991                                                                 sqlda_old1 = sqlda_old->desc_next;
992                                                                 free(sqlda_old);
993                                                                 sqlda_old = sqlda_old1;
994                                                         }
995
996                                                         *_sqlda = sqlda;
997                                                         ret = true;
998                                                 }
999
1000                                                 PQclear(res);
1001                                         }
1002                                         break;
1003                                 }
1004                         default:
1005                                 /* nothing else may come */
1006                                 ;
1007                 }
1008         }
1009
1010         va_end(args);
1011
1012         return ret;
1013 }