]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/ecpglib/descriptor.c
ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp> added thread-safe
[postgresql] / src / interfaces / ecpg / ecpglib / descriptor.c
1 /* dynamic SQL support routines
2  *
3  * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.24 2007/10/02 09:49:59 meskes Exp $
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 "sql3types.h"
17
18 static void descriptor_free(struct descriptor *desc);
19 static void descriptor_deallocate_all(struct descriptor *list);
20
21 /* We manage descriptors separately for each thread. */
22 #ifdef ENABLE_THREAD_SAFETY
23 static pthread_key_t    descriptor_key;
24 #ifndef WIN32
25 static pthread_once_t   descriptor_once = PTHREAD_ONCE_INIT;
26 #endif
27
28 static void
29 descriptor_destructor(void *arg)
30 {
31         descriptor_deallocate_all(arg);
32 }
33
34 NON_EXEC_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
53 #else
54 static struct descriptor                *all_descriptors = NULL;
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 ECPGresultByDescriptor(int line, const char *name)
62 {
63         struct descriptor *desc = ECPGfind_desc(line, name);
64         if (desc == NULL)
65                 return NULL;
66         return desc->result;
67 }
68
69 static unsigned int
70 ECPGDynamicType_DDT(Oid type)
71 {
72         switch (type)
73         {
74                 case DATEOID:
75                         return SQL3_DDT_DATE;
76                 case TIMEOID:
77                         return SQL3_DDT_TIME;
78                 case TIMESTAMPOID:
79                         return SQL3_DDT_TIMESTAMP;
80                 case TIMESTAMPTZOID:
81                         return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
82                 case TIMETZOID:
83                         return SQL3_DDT_TIME_WITH_TIME_ZONE;
84                 default:
85                         return SQL3_DDT_ILLEGAL;
86         }
87 }
88
89 bool
90 ECPGget_desc_header(int lineno, const char *desc_name, int *count)
91 {
92         PGresult   *ECPGresult;
93         struct sqlca_t *sqlca = ECPGget_sqlca();
94
95         ECPGinit_sqlca(sqlca);
96         ECPGresult = ECPGresultByDescriptor(lineno, desc_name);
97         if (!ECPGresult)
98                 return false;
99
100         *count = PQnfields(ECPGresult);
101         sqlca->sqlerrd[2] = 1;
102         ECPGlog("ECPGget_desc_header: found %d attributes.\n", *count);
103         return true;
104 }
105
106 static bool
107 get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
108 {
109         switch (vartype)
110         {
111                 case ECPGt_short:
112                         *(short *) var = (short) value;
113                         break;
114                 case ECPGt_int:
115                         *(int *) var = (int) value;
116                         break;
117                 case ECPGt_long:
118                         *(long *) var = (long) value;
119                         break;
120                 case ECPGt_unsigned_short:
121                         *(unsigned short *) var = (unsigned short) value;
122                         break;
123                 case ECPGt_unsigned_int:
124                         *(unsigned int *) var = (unsigned int) value;
125                         break;
126                 case ECPGt_unsigned_long:
127                         *(unsigned long *) var = (unsigned long) value;
128                         break;
129 #ifdef HAVE_LONG_LONG_INT_64
130                 case ECPGt_long_long:
131                         *(long long int *) var = (long long int) value;
132                         break;
133                 case ECPGt_unsigned_long_long:
134                         *(unsigned long long int *) var = (unsigned long long int) value;
135                         break;
136 #endif   /* HAVE_LONG_LONG_INT_64 */
137                 case ECPGt_float:
138                         *(float *) var = (float) value;
139                         break;
140                 case ECPGt_double:
141                         *(double *) var = (double) value;
142                         break;
143                 default:
144                         ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
145                         return (false);
146         }
147
148         return (true);
149 }
150
151 static bool
152 set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
153 {
154         switch (vartype)
155         {
156                 case ECPGt_short:
157                         *target = *(short *) var;
158                         break;
159                 case ECPGt_int:
160                         *target = *(int *) var;
161                         break;
162                 case ECPGt_long:
163                         *target = *(long *) var;
164                         break;
165                 case ECPGt_unsigned_short:
166                         *target = *(unsigned short *) var;
167                         break;
168                 case ECPGt_unsigned_int:
169                         *target = *(unsigned int *) var;
170                         break;
171                 case ECPGt_unsigned_long:
172                         *target = *(unsigned long *) var;
173                         break;
174 #ifdef HAVE_LONG_LONG_INT_64
175                 case ECPGt_long_long:
176                         *target = *(long long int *) var;
177                         break;
178                 case ECPGt_unsigned_long_long:
179                         *target = *(unsigned long long int *) var;
180                         break;
181 #endif   /* HAVE_LONG_LONG_INT_64 */
182                 case ECPGt_float:
183                         *target = *(float *) var;
184                         break;
185                 case ECPGt_double:
186                         *target = *(double *) var;
187                         break;
188                 default:
189                         ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
190                         return (false);
191         }
192
193         return true;
194 }
195
196 static bool
197 get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
198 {
199         switch (vartype)
200         {
201                 case ECPGt_char:
202                 case ECPGt_unsigned_char:
203                         strncpy((char *) var, value, varcharsize);
204                         break;
205                 case ECPGt_varchar:
206                         {
207                                 struct ECPGgeneric_varchar *variable =
208                                 (struct ECPGgeneric_varchar *) var;
209
210                                 if (varcharsize == 0)
211                                         strncpy(variable->arr, value, strlen(value));
212                                 else
213                                         strncpy(variable->arr, value, varcharsize);
214
215                                 variable->len = strlen(value);
216                                 if (varcharsize > 0 && variable->len > varcharsize)
217                                         variable->len = varcharsize;
218                         }
219                         break;
220                 default:
221                         ECPGraise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
222                         return (false);
223         }
224
225         return (true);
226 }
227
228 bool
229 ECPGget_desc(int lineno, const char *desc_name, int index,...)
230 {
231         va_list         args;
232         PGresult   *ECPGresult;
233         enum ECPGdtype type;
234         int                     ntuples,
235                                 act_tuple;
236         struct variable data_var;
237         struct sqlca_t *sqlca = ECPGget_sqlca();
238
239         va_start(args, index);
240         ECPGinit_sqlca(sqlca);
241         ECPGresult = ECPGresultByDescriptor(lineno, desc_name);
242         if (!ECPGresult)
243                 return (false);
244
245         ntuples = PQntuples(ECPGresult);
246         if (ntuples < 1)
247         {
248                 ECPGraise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
249                 return (false);
250         }
251
252         if (index < 1 || index > PQnfields(ECPGresult))
253         {
254                 ECPGraise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
255                 return (false);
256         }
257
258         ECPGlog("ECPGget_desc: reading items for tuple %d\n", index);
259         --index;
260
261         type = va_arg(args, enum ECPGdtype);
262
263         memset(&data_var, 0, sizeof data_var);
264         data_var.type = ECPGt_EORT;
265         data_var.ind_type = ECPGt_NO_INDICATOR;
266
267         while (type != ECPGd_EODT)
268         {
269                 char            type_str[20];
270                 long            varcharsize;
271                 long            offset;
272                 long            arrsize;
273                 enum ECPGttype vartype;
274                 void       *var;
275
276                 vartype = va_arg(args, enum ECPGttype);
277                 var = va_arg(args, void *);
278                 varcharsize = va_arg(args, long);
279                 arrsize = va_arg(args, long);
280                 offset = va_arg(args, long);
281
282                 switch (type)
283                 {
284                         case (ECPGd_indicator):
285                                 data_var.ind_type = vartype;
286                                 data_var.ind_pointer = var;
287                                 data_var.ind_varcharsize = varcharsize;
288                                 data_var.ind_arrsize = arrsize;
289                                 data_var.ind_offset = offset;
290                                 if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
291                                         data_var.ind_value = *((void **) (data_var.ind_pointer));
292                                 else
293                                         data_var.ind_value = data_var.ind_pointer;
294                                 break;
295
296                         case ECPGd_data:
297                                 data_var.type = vartype;
298                                 data_var.pointer = var;
299                                 data_var.varcharsize = varcharsize;
300                                 data_var.arrsize = arrsize;
301                                 data_var.offset = offset;
302                                 if (data_var.arrsize == 0 || data_var.varcharsize == 0)
303                                         data_var.value = *((void **) (data_var.pointer));
304                                 else
305                                         data_var.value = data_var.pointer;
306                                 break;
307
308                         case ECPGd_name:
309                                 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
310                                         return (false);
311
312                                 ECPGlog("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
313                                 break;
314
315                         case ECPGd_nullable:
316                                 if (!get_int_item(lineno, var, vartype, 1))
317                                         return (false);
318
319                                 break;
320
321                         case ECPGd_key_member:
322                                 if (!get_int_item(lineno, var, vartype, 0))
323                                         return (false);
324
325                                 break;
326
327                         case ECPGd_scale:
328                                 if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
329                                         return (false);
330
331                                 ECPGlog("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
332                                 break;
333
334                         case ECPGd_precision:
335                                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
336                                         return (false);
337
338                                 ECPGlog("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
339                                 break;
340
341                         case ECPGd_octet:
342                                 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
343                                         return (false);
344
345                                 ECPGlog("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
346                                 break;
347
348                         case ECPGd_length:
349                                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
350                                         return (false);
351
352                                 ECPGlog("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
353                                 break;
354
355                         case ECPGd_type:
356                                 if (!get_int_item(lineno, var, vartype, ECPGDynamicType(PQftype(ECPGresult, index))))
357                                         return (false);
358
359                                 ECPGlog("ECPGget_desc: TYPE = %d\n", ECPGDynamicType(PQftype(ECPGresult, index)));
360                                 break;
361
362                         case ECPGd_di_code:
363                                 if (!get_int_item(lineno, var, vartype, ECPGDynamicType_DDT(PQftype(ECPGresult, index))))
364                                         return (false);
365
366                                 ECPGlog("ECPGget_desc: TYPE = %d\n", ECPGDynamicType_DDT(PQftype(ECPGresult, index)));
367                                 break;
368
369                         case ECPGd_cardinality:
370                                 if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
371                                         return (false);
372
373                                 ECPGlog("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
374                                 break;
375
376                         case ECPGd_ret_length:
377                         case ECPGd_ret_octet:
378
379                                 /*
380                                  * this is like ECPGstore_result
381                                  */
382                                 if (arrsize > 0 && ntuples > arrsize)
383                                 {
384                                         ECPGlog("ECPGget_desc line %d: Incorrect number of matches: %d don't fit into array of %d\n",
385                                                         lineno, ntuples, arrsize);
386                                         ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
387                                         return false;
388                                 }
389                                 /* allocate storage if needed */
390                                 if (arrsize == 0 && *(void **) var == NULL)
391                                 {
392                                         void       *mem = (void *) ECPGalloc(offset * ntuples, lineno);
393
394                                         if (!mem)
395                                                 return false;
396                                         *(void **) var = mem;
397                                         ECPGadd_mem(mem, lineno);
398                                         var = mem;
399                                 }
400
401                                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
402                                 {
403                                         if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
404                                                 return (false);
405                                         var = (char *) var + offset;
406                                         ECPGlog("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
407                                 }
408                                 break;
409
410                         default:
411                                 snprintf(type_str, sizeof(type_str), "%d", type);
412                                 ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
413                                 return (false);
414                 }
415
416                 type = va_arg(args, enum ECPGdtype);
417         }
418
419         if (data_var.type != ECPGt_EORT)
420         {
421                 struct statement stmt;
422                 char       *oldlocale;
423
424                 /* Make sure we do NOT honor the locale for numeric input */
425                 /* since the database gives the standard decimal point */
426                 oldlocale = ECPGstrdup(setlocale(LC_NUMERIC, NULL), lineno);
427                 setlocale(LC_NUMERIC, "C");
428
429                 memset(&stmt, 0, sizeof stmt);
430                 stmt.lineno = lineno;
431
432                 /* desparate try to guess something sensible */
433                 stmt.connection = ECPGget_connection(NULL);
434                 ECPGstore_result(ECPGresult, index, &stmt, &data_var);
435
436                 setlocale(LC_NUMERIC, oldlocale);
437                 ECPGfree(oldlocale);
438         }
439         else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
440
441                 /*
442                  * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
443                  * since this might be changed manually in the .c file let's play it
444                  * safe
445                  */
446         {
447                 /*
448                  * this is like ECPGstore_result but since we don't have a data
449                  * variable at hand, we can't call it
450                  */
451                 if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
452                 {
453                         ECPGlog("ECPGget_desc line %d: Incorrect number of matches (indicator): %d don't fit into array of %d\n",
454                                         lineno, ntuples, data_var.ind_arrsize);
455                         ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
456                         return false;
457                 }
458
459                 /* allocate storage if needed */
460                 if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
461                 {
462                         void       *mem = (void *) ECPGalloc(data_var.ind_offset * ntuples, lineno);
463
464                         if (!mem)
465                                 return false;
466                         *(void **) data_var.ind_pointer = mem;
467                         ECPGadd_mem(mem, lineno);
468                         data_var.ind_value = mem;
469                 }
470
471                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
472                 {
473                         if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
474                                 return (false);
475                         data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
476                         ECPGlog("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
477                 }
478         }
479         sqlca->sqlerrd[2] = ntuples;
480         return (true);
481 }
482
483 bool
484 ECPGset_desc_header(int lineno, const char *desc_name, int count)
485 {
486         struct descriptor *desc = ECPGfind_desc(lineno, desc_name);
487         if (desc == NULL)
488                 return false;
489         desc->count = count;
490         return true;
491 }
492
493 bool
494 ECPGset_desc(int lineno, const char *desc_name, int index,...)
495 {
496         va_list         args;
497         struct descriptor *desc;
498         struct descriptor_item *desc_item;
499         struct variable *var;
500
501         desc = ECPGfind_desc(lineno, desc_name);
502         if (desc == NULL)
503                 return false;
504
505         for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
506         {
507                 if (desc_item->num == index)
508                         break;
509         }
510
511         if (desc_item == NULL)
512         {
513                 desc_item = (struct descriptor_item *) ECPGalloc(sizeof(*desc_item), lineno);
514                 if (!desc_item)
515                         return false;
516                 desc_item->num = index;
517                 if (desc->count < index)
518                         desc->count = index;
519                 desc_item->next = desc->items;
520                 desc->items = desc_item;
521         }
522
523         if (!(var = (struct variable *) ECPGalloc(sizeof(struct variable), lineno)))
524                 return false;
525
526         va_start(args, index);
527
528         for (;;)
529         {
530                 enum ECPGdtype itemtype;
531                 const char *tobeinserted = NULL;
532
533                 itemtype = va_arg(args, enum ECPGdtype);
534
535                 if (itemtype == ECPGd_EODT)
536                         break;
537
538                 var->type = va_arg(args, enum ECPGttype);
539                 var->pointer = va_arg(args, char *);
540
541                 var->varcharsize = va_arg(args, long);
542                 var->arrsize = va_arg(args, long);
543                 var->offset = va_arg(args, long);
544
545                 if (var->arrsize == 0 || var->varcharsize == 0)
546                         var->value = *((char **) (var->pointer));
547                 else
548                         var->value = var->pointer;
549
550                 /*
551                  * negative values are used to indicate an array without given bounds
552                  */
553                 /* reset to zero for us */
554                 if (var->arrsize < 0)
555                         var->arrsize = 0;
556                 if (var->varcharsize < 0)
557                         var->varcharsize = 0;
558
559                 var->next = NULL;
560                 
561                 switch (itemtype)
562                 {
563                         case ECPGd_data:
564                                 {
565                                         if (!ECPGstore_input(lineno, true, var, &tobeinserted, false))
566                                         {
567                                                 ECPGfree(var);
568                                                 return false;
569                                         }
570
571                                         ECPGfree(desc_item->data); /* free() takes care of a potential NULL value */
572                                         desc_item->data = (char *) tobeinserted;
573                                         tobeinserted = NULL;
574                                         break;
575                                 }
576
577                         case ECPGd_indicator:
578                                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
579                                 break;
580
581                         case ECPGd_length:
582                                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
583                                 break;
584
585                         case ECPGd_precision:
586                                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
587                                 break;
588
589                         case ECPGd_scale:
590                                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
591                                 break;
592
593                         case ECPGd_type:
594                                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
595                                 break;
596
597                         default:
598                                 {
599                                         char            type_str[20];
600
601                                         snprintf(type_str, sizeof(type_str), "%d", itemtype);
602                                         ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
603                                         ECPGfree(var);
604                                         return false;
605                                 }
606                 }
607         }
608         ECPGfree(var);
609
610         return true;
611 }
612
613 /* Free the descriptor and items in it. */
614 static void
615 descriptor_free(struct descriptor *desc)
616 {
617         struct descriptor_item *desc_item;
618
619         for (desc_item = desc->items; desc_item;)
620         {
621                 struct descriptor_item *di;
622
623                 ECPGfree(desc_item->data);
624                 di = desc_item;
625                 desc_item = desc_item->next;
626                 ECPGfree(di);
627         }
628
629         ECPGfree(desc->name);
630         PQclear(desc->result);
631         ECPGfree(desc);
632 }
633
634 bool
635 ECPGdeallocate_desc(int line, const char *name)
636 {
637         struct descriptor *desc;
638         struct descriptor *prev;
639         struct sqlca_t *sqlca = ECPGget_sqlca();
640
641         ECPGinit_sqlca(sqlca);
642         for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
643         {
644                 if (!strcmp(name, desc->name))
645                 {
646                         if (prev)
647                                 prev->next = desc->next;
648                         else
649                                 set_descriptors(desc->next);
650                         descriptor_free(desc);
651                         return true;
652                 }
653         }
654         ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
655         return false;
656 }
657
658 /* Deallocate all descriptors in the list */
659 static void
660 descriptor_deallocate_all(struct descriptor *list)
661 {
662         while (list)
663         {
664                 struct descriptor *next = list->next;
665                 descriptor_free(list);
666                 list = next;
667         }
668 }
669
670 bool
671 ECPGallocate_desc(int line, const char *name)
672 {
673         struct descriptor *new;
674         struct sqlca_t *sqlca = ECPGget_sqlca();
675
676         ECPGinit_sqlca(sqlca);
677         new = (struct descriptor *) ECPGalloc(sizeof(struct descriptor), line);
678         if (!new)
679                 return false;
680         new->next = get_descriptors();
681         new->name = ECPGalloc(strlen(name) + 1, line);
682         if (!new->name)
683         {
684                 ECPGfree(new);
685                 return false;
686         }
687         new->count = -1;
688         new->items = NULL;
689         new->result = PQmakeEmptyPGresult(NULL, 0);
690         if (!new->result)
691         {
692                 ECPGfree(new->name);
693                 ECPGfree(new);
694                 ECPGraise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
695                 return false;
696         }
697         strcpy(new->name, name);
698         set_descriptors(new);
699         return true;
700 }
701
702 /* Find descriptor with name in the connection. */
703 struct descriptor *
704 ECPGfind_desc(int line, const char *name)
705 {
706         struct descriptor *desc;
707
708         for (desc = get_descriptors(); desc; desc = desc->next)
709         {
710                 if (strcmp(name, desc->name) == 0)
711                         return desc;
712         }
713
714         ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
715         return NULL;    /* not found */
716 }
717
718 bool
719 ECPGdescribe(int line, bool input, const char *statement,...)
720 {
721         ECPGlog("ECPGdescribe called on line %d for %s in %s\n", line, (input) ? "input" : "output", statement);
722         return false;
723 }