Fix obsolete comment regarding FSM truncation.
[PostgreSQL.git] / src / interfaces / ecpg / ecpglib / descriptor.c
blobeb3fd9a226dc1466c1b09157f528eaa43b67f433
1 /* dynamic SQL support routines
3 * $PostgreSQL$
4 */
6 #define POSTGRES_ECPG_INTERNAL
7 #include "postgres_fe.h"
8 #include "pg_type.h"
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"
18 static void descriptor_free(struct descriptor * desc);
20 /* We manage descriptors separately for each thread. */
21 #ifdef ENABLE_THREAD_SAFETY
22 static pthread_key_t descriptor_key;
23 static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
25 static void descriptor_deallocate_all(struct descriptor * list);
27 static void
28 descriptor_destructor(void *arg)
30 descriptor_deallocate_all(arg);
33 static void
34 descriptor_key_init(void)
36 pthread_key_create(&descriptor_key, descriptor_destructor);
39 static struct descriptor *
40 get_descriptors(void)
42 pthread_once(&descriptor_once, descriptor_key_init);
43 return (struct descriptor *) pthread_getspecific(descriptor_key);
46 static void
47 set_descriptors(struct descriptor * value)
49 pthread_setspecific(descriptor_key, value);
51 #else
52 static struct descriptor *all_descriptors = NULL;
54 #define get_descriptors() (all_descriptors)
55 #define set_descriptors(value) do { all_descriptors = (value); } while(0)
56 #endif
58 /* old internal convenience function that might go away later */
59 static PGresult *
60 ecpg_result_by_descriptor(int line, const char *name)
62 struct descriptor *desc = ecpg_find_desc(line, name);
64 if (desc == NULL)
65 return NULL;
66 return desc->result;
69 static unsigned int
70 ecpg_dynamic_type_DDT(Oid type)
72 switch (type)
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;
89 bool
90 ECPGget_desc_header(int lineno, const char *desc_name, int *count)
92 PGresult *ECPGresult;
93 struct sqlca_t *sqlca = ECPGget_sqlca();
95 ecpg_init_sqlca(sqlca);
96 ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
97 if (!ECPGresult)
98 return false;
100 *count = PQnfields(ECPGresult);
101 sqlca->sqlerrd[2] = 1;
102 ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
103 return true;
106 static bool
107 get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
109 switch (vartype)
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 ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
145 return (false);
148 return (true);
151 static bool
152 set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
154 switch (vartype)
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 ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
190 return (false);
193 return true;
196 static bool
197 get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
199 switch (vartype)
201 case ECPGt_char:
202 case ECPGt_unsigned_char:
203 strncpy((char *) var, value, varcharsize);
204 break;
205 case ECPGt_varchar:
207 struct ECPGgeneric_varchar *variable =
208 (struct ECPGgeneric_varchar *) var;
210 if (varcharsize == 0)
211 strncpy(variable->arr, value, strlen(value));
212 else
213 strncpy(variable->arr, value, varcharsize);
215 variable->len = strlen(value);
216 if (varcharsize > 0 && variable->len > varcharsize)
217 variable->len = varcharsize;
219 break;
220 default:
221 ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
222 return (false);
225 return (true);
228 bool
229 ECPGget_desc(int lineno, const char *desc_name, int index,...)
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();
239 va_start(args, index);
240 ecpg_init_sqlca(sqlca);
241 ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
242 if (!ECPGresult)
243 return (false);
245 ntuples = PQntuples(ECPGresult);
246 if (ntuples < 1)
248 ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
249 return (false);
252 if (index < 1 || index > PQnfields(ECPGresult))
254 ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
255 return (false);
258 ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
259 --index;
261 type = va_arg(args, enum ECPGdtype);
263 memset(&data_var, 0, sizeof data_var);
264 data_var.type = ECPGt_EORT;
265 data_var.ind_type = ECPGt_NO_INDICATOR;
267 while (type != ECPGd_EODT)
269 char type_str[20];
270 long varcharsize;
271 long offset;
272 long arrsize;
273 enum ECPGttype vartype;
274 void *var;
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);
282 switch (type)
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;
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;
308 case ECPGd_name:
309 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
310 return (false);
312 ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
313 break;
315 case ECPGd_nullable:
316 if (!get_int_item(lineno, var, vartype, 1))
317 return (false);
319 break;
321 case ECPGd_key_member:
322 if (!get_int_item(lineno, var, vartype, 0))
323 return (false);
325 break;
327 case ECPGd_scale:
328 if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
329 return (false);
331 ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
332 break;
334 case ECPGd_precision:
335 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
336 return (false);
338 ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
339 break;
341 case ECPGd_octet:
342 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
343 return (false);
345 ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
346 break;
348 case ECPGd_length:
349 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
350 return (false);
352 ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
353 break;
355 case ECPGd_type:
356 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
357 return (false);
359 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
360 break;
362 case ECPGd_di_code:
363 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
364 return (false);
366 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
367 break;
369 case ECPGd_cardinality:
370 if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
371 return (false);
373 ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
374 break;
376 case ECPGd_ret_length:
377 case ECPGd_ret_octet:
380 * this is like ECPGstore_result
382 if (arrsize > 0 && ntuples > arrsize)
384 ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %d\n",
385 lineno, ntuples, arrsize);
386 ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
387 return false;
389 /* allocate storage if needed */
390 if (arrsize == 0 && *(void **) var == NULL)
392 void *mem = (void *) ecpg_alloc(offset * ntuples, lineno);
394 if (!mem)
395 return false;
396 *(void **) var = mem;
397 ecpg_add_mem(mem, lineno);
398 var = mem;
401 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
403 if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
404 return (false);
405 var = (char *) var + offset;
406 ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
408 break;
410 default:
411 snprintf(type_str, sizeof(type_str), "%d", type);
412 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
413 return (false);
416 type = va_arg(args, enum ECPGdtype);
419 if (data_var.type != ECPGt_EORT)
421 struct statement stmt;
422 char *oldlocale;
424 /* Make sure we do NOT honor the locale for numeric input */
425 /* since the database gives the standard decimal point */
426 oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
427 setlocale(LC_NUMERIC, "C");
429 memset(&stmt, 0, sizeof stmt);
430 stmt.lineno = lineno;
432 /* desparate try to guess something sensible */
433 stmt.connection = ecpg_get_connection(NULL);
434 ecpg_store_result(ECPGresult, index, &stmt, &data_var);
436 setlocale(LC_NUMERIC, oldlocale);
437 ecpg_free(oldlocale);
439 else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
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
448 * this is like ECPGstore_result but since we don't have a data
449 * variable at hand, we can't call it
451 if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
453 ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %d\n",
454 lineno, ntuples, data_var.ind_arrsize);
455 ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
456 return false;
459 /* allocate storage if needed */
460 if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
462 void *mem = (void *) ecpg_alloc(data_var.ind_offset * ntuples, lineno);
464 if (!mem)
465 return false;
466 *(void **) data_var.ind_pointer = mem;
467 ecpg_add_mem(mem, lineno);
468 data_var.ind_value = mem;
471 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
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 ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
479 sqlca->sqlerrd[2] = ntuples;
480 return (true);
483 bool
484 ECPGset_desc_header(int lineno, const char *desc_name, int count)
486 struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
488 if (desc == NULL)
489 return false;
490 desc->count = count;
491 return true;
494 bool
495 ECPGset_desc(int lineno, const char *desc_name, int index,...)
497 va_list args;
498 struct descriptor *desc;
499 struct descriptor_item *desc_item;
500 struct variable *var;
502 desc = ecpg_find_desc(lineno, desc_name);
503 if (desc == NULL)
504 return false;
506 for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
508 if (desc_item->num == index)
509 break;
512 if (desc_item == NULL)
514 desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
515 if (!desc_item)
516 return false;
517 desc_item->num = index;
518 if (desc->count < index)
519 desc->count = index;
520 desc_item->next = desc->items;
521 desc->items = desc_item;
524 if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
525 return false;
527 va_start(args, index);
529 for (;;)
531 enum ECPGdtype itemtype;
532 char *tobeinserted = NULL;
534 itemtype = va_arg(args, enum ECPGdtype);
536 if (itemtype == ECPGd_EODT)
537 break;
539 var->type = va_arg(args, enum ECPGttype);
540 var->pointer = va_arg(args, char *);
542 var->varcharsize = va_arg(args, long);
543 var->arrsize = va_arg(args, long);
544 var->offset = va_arg(args, long);
546 if (var->arrsize == 0 || var->varcharsize == 0)
547 var->value = *((char **) (var->pointer));
548 else
549 var->value = var->pointer;
552 * negative values are used to indicate an array without given bounds
554 /* reset to zero for us */
555 if (var->arrsize < 0)
556 var->arrsize = 0;
557 if (var->varcharsize < 0)
558 var->varcharsize = 0;
560 var->next = NULL;
562 switch (itemtype)
564 case ECPGd_data:
566 if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
568 ecpg_free(var);
569 return false;
572 ecpg_free(desc_item->data); /* free() takes care of a
573 * potential NULL value */
574 desc_item->data = (char *) tobeinserted;
575 tobeinserted = NULL;
576 break;
579 case ECPGd_indicator:
580 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
581 break;
583 case ECPGd_length:
584 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
585 break;
587 case ECPGd_precision:
588 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
589 break;
591 case ECPGd_scale:
592 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
593 break;
595 case ECPGd_type:
596 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
597 break;
599 default:
601 char type_str[20];
603 snprintf(type_str, sizeof(type_str), "%d", itemtype);
604 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
605 ecpg_free(var);
606 return false;
610 ecpg_free(var);
612 return true;
615 /* Free the descriptor and items in it. */
616 static void
617 descriptor_free(struct descriptor * desc)
619 struct descriptor_item *desc_item;
621 for (desc_item = desc->items; desc_item;)
623 struct descriptor_item *di;
625 ecpg_free(desc_item->data);
626 di = desc_item;
627 desc_item = desc_item->next;
628 ecpg_free(di);
631 ecpg_free(desc->name);
632 PQclear(desc->result);
633 ecpg_free(desc);
636 bool
637 ECPGdeallocate_desc(int line, const char *name)
639 struct descriptor *desc;
640 struct descriptor *prev;
641 struct sqlca_t *sqlca = ECPGget_sqlca();
643 ecpg_init_sqlca(sqlca);
644 for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
646 if (!strcmp(name, desc->name))
648 if (prev)
649 prev->next = desc->next;
650 else
651 set_descriptors(desc->next);
652 descriptor_free(desc);
653 return true;
656 ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
657 return false;
660 #ifdef ENABLE_THREAD_SAFETY
662 /* Deallocate all descriptors in the list */
663 static void
664 descriptor_deallocate_all(struct descriptor * list)
666 while (list)
668 struct descriptor *next = list->next;
670 descriptor_free(list);
671 list = next;
674 #endif /* ENABLE_THREAD_SAFETY */
676 bool
677 ECPGallocate_desc(int line, const char *name)
679 struct descriptor *new;
680 struct sqlca_t *sqlca = ECPGget_sqlca();
682 ecpg_init_sqlca(sqlca);
683 new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
684 if (!new)
685 return false;
686 new->next = get_descriptors();
687 new->name = ecpg_alloc(strlen(name) + 1, line);
688 if (!new->name)
690 ecpg_free(new);
691 return false;
693 new->count = -1;
694 new->items = NULL;
695 new->result = PQmakeEmptyPGresult(NULL, 0);
696 if (!new->result)
698 ecpg_free(new->name);
699 ecpg_free(new);
700 ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
701 return false;
703 strcpy(new->name, name);
704 set_descriptors(new);
705 return true;
708 /* Find descriptor with name in the connection. */
709 struct descriptor *
710 ecpg_find_desc(int line, const char *name)
712 struct descriptor *desc;
714 for (desc = get_descriptors(); desc; desc = desc->next)
716 if (strcmp(name, desc->name) == 0)
717 return desc;
720 ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
721 return NULL; /* not found */
724 bool
725 ECPGdescribe(int line, bool input, const char *statement,...)
727 ecpg_log("ECPGdescribe called on line %d for %s: %s\n", line, (input) ? _("input") : _("output"), statement);
728 return false;