1 /* dynamic SQL support routines
3 * src/interfaces/ecpg/ecpglib/descriptor.c
6 #define POSTGRES_ECPG_INTERNAL
7 #include "postgres_fe.h"
9 #include "catalog/pg_type_d.h"
11 #include "ecpg-pthread-win32.h"
14 #include "ecpgerrno.h"
15 #include "ecpglib_extern.h"
18 #include "sql3types.h"
20 static void descriptor_free(struct descriptor *desc);
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;
27 static void descriptor_deallocate_all(struct descriptor *list);
30 descriptor_destructor(void *arg)
32 descriptor_deallocate_all(arg);
36 descriptor_key_init(void)
38 pthread_key_create(&descriptor_key, descriptor_destructor);
41 static struct descriptor *
44 pthread_once(&descriptor_once, descriptor_key_init);
45 return (struct descriptor *) pthread_getspecific(descriptor_key);
49 set_descriptors(struct descriptor *value)
51 pthread_setspecific(descriptor_key, value);
54 static struct descriptor *all_descriptors = NULL;
56 #define get_descriptors() (all_descriptors)
57 #define set_descriptors(value) do { all_descriptors = (value); } while(0)
60 /* old internal convenience function that might go away later */
62 ecpg_result_by_descriptor(int line, const char *name)
64 struct descriptor *desc = ecpg_find_desc(line, name);
72 ecpg_dynamic_type_DDT(Oid type)
81 return SQL3_DDT_TIMESTAMP;
83 return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
85 return SQL3_DDT_TIME_WITH_TIME_ZONE;
87 return SQL3_DDT_ILLEGAL;
92 ECPGget_desc_header(int lineno, const char *desc_name, int *count)
95 struct sqlca_t *sqlca = ECPGget_sqlca();
99 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
100 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
104 ecpg_init_sqlca(sqlca);
105 ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
109 *count = PQnfields(ECPGresult);
110 sqlca->sqlerrd[2] = 1;
111 ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
116 get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
121 *(short *) var = (short) value;
124 *(int *) var = (int) value;
127 *(long *) var = (long) value;
129 case ECPGt_unsigned_short:
130 *(unsigned short *) var = (unsigned short) value;
132 case ECPGt_unsigned_int:
133 *(unsigned int *) var = (unsigned int) value;
135 case ECPGt_unsigned_long:
136 *(unsigned long *) var = (unsigned long) value;
138 #ifdef HAVE_LONG_LONG_INT
139 case ECPGt_long_long:
140 *(long long int *) var = (long long int) value;
142 case ECPGt_unsigned_long_long:
143 *(unsigned long long int *) var = (unsigned long long int) value;
145 #endif /* HAVE_LONG_LONG_INT */
147 *(float *) var = (float) value;
150 *(double *) var = (double) value;
153 ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
161 set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
166 *target = *(const short *) var;
169 *target = *(const int *) var;
172 *target = *(const long *) var;
174 case ECPGt_unsigned_short:
175 *target = *(const unsigned short *) var;
177 case ECPGt_unsigned_int:
178 *target = *(const unsigned int *) var;
180 case ECPGt_unsigned_long:
181 *target = *(const unsigned long *) var;
183 #ifdef HAVE_LONG_LONG_INT
184 case ECPGt_long_long:
185 *target = *(const long long int *) var;
187 case ECPGt_unsigned_long_long:
188 *target = *(const unsigned long long int *) var;
190 #endif /* HAVE_LONG_LONG_INT */
192 *target = *(const float *) var;
195 *target = *(const double *) var;
198 ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
206 get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
211 case ECPGt_unsigned_char:
213 strncpy((char *) var, value, varcharsize);
217 struct ECPGgeneric_varchar *variable =
218 (struct ECPGgeneric_varchar *) var;
220 if (varcharsize == 0)
221 memcpy(variable->arr, value, strlen(value));
223 strncpy(variable->arr, value, varcharsize);
225 variable->len = strlen(value);
226 if (varcharsize > 0 && variable->len > varcharsize)
227 variable->len = varcharsize;
231 ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
238 #define RETURN_IF_NO_DATA if (ntuples < 1) \
241 ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
246 ECPGget_desc(int lineno, const char *desc_name, int index,...)
249 PGresult *ECPGresult;
253 struct variable data_var;
254 struct sqlca_t *sqlca = ECPGget_sqlca();
258 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
259 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
263 va_start(args, index);
264 ecpg_init_sqlca(sqlca);
265 ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
272 ntuples = PQntuples(ECPGresult);
274 if (index < 1 || index > PQnfields(ECPGresult))
276 ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
281 ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
284 type = va_arg(args, enum ECPGdtype);
286 memset(&data_var, 0, sizeof data_var);
287 data_var.type = ECPGt_EORT;
288 data_var.ind_type = ECPGt_NO_INDICATOR;
290 while (type != ECPGd_EODT)
296 enum ECPGttype vartype;
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);
307 case (ECPGd_indicator):
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));
317 data_var.ind_value = data_var.ind_pointer;
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));
330 data_var.value = data_var.pointer;
334 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
340 ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
344 if (!get_int_item(lineno, var, vartype, 1))
352 case ECPGd_key_member:
353 if (!get_int_item(lineno, var, vartype, 0))
362 if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
368 ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
371 case ECPGd_precision:
372 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
378 ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
382 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
388 ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
392 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
398 ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
402 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
408 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
412 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
418 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
421 case ECPGd_cardinality:
422 if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
428 ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
431 case ECPGd_ret_length:
432 case ECPGd_ret_octet:
437 * this is like ECPGstore_result
439 if (arrsize > 0 && ntuples > arrsize)
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);
447 /* allocate storage if needed */
448 if (arrsize == 0 && *(void **) var == NULL)
450 void *mem = (void *) ecpg_auto_alloc(offset * ntuples, lineno);
457 *(void **) var = mem;
461 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
463 if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
468 var = (char *) var + offset;
469 ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
474 snprintf(type_str, sizeof(type_str), "%d", type);
475 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
480 type = va_arg(args, enum ECPGdtype);
483 if (data_var.type != ECPGt_EORT)
485 struct statement stmt;
487 memset(&stmt, 0, sizeof stmt);
488 stmt.lineno = lineno;
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);
498 #ifdef HAVE__CONFIGTHREADLOCALE
499 stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
501 stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
502 setlocale(LC_NUMERIC, "C");
505 /* desperate try to guess something sensible */
506 stmt.connection = ecpg_get_connection(NULL);
507 ecpg_store_result(ECPGresult, index, &stmt, &data_var);
509 #ifdef HAVE_USELOCALE
510 if (stmt.oldlocale != (locale_t) 0)
511 uselocale(stmt.oldlocale);
513 freelocale(stmt.clocale);
517 setlocale(LC_NUMERIC, stmt.oldlocale);
518 ecpg_free(stmt.oldlocale);
520 #ifdef HAVE__CONFIGTHREADLOCALE
521 if (stmt.oldthreadlocale != -1)
522 (void) _configthreadlocale(stmt.oldthreadlocale);
526 else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
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
535 * this is like ECPGstore_result but since we don't have a data
536 * variable at hand, we can't call it
538 if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
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);
547 /* allocate storage if needed */
548 if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
550 void *mem = (void *) ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
557 *(void **) data_var.ind_pointer = mem;
558 data_var.ind_value = mem;
561 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
563 if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
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));
572 sqlca->sqlerrd[2] = ntuples;
577 #undef RETURN_IF_NO_DATA
580 ECPGset_desc_header(int lineno, const char *desc_name, int count)
582 struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
591 set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
594 if (var->type != ECPGt_bytea)
595 desc_item->is_binary = false;
599 struct ECPGgeneric_varchar *variable =
600 (struct ECPGgeneric_varchar *) (var->value);
602 desc_item->is_binary = true;
603 desc_item->data_len = variable->len;
606 ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
607 desc_item->data = (char *) tobeinserted;
612 ECPGset_desc(int lineno, const char *desc_name, int index,...)
615 struct descriptor *desc;
616 struct descriptor_item *desc_item;
617 struct variable *var;
619 desc = ecpg_find_desc(lineno, desc_name);
623 for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
625 if (desc_item->num == index)
629 if (desc_item == NULL)
631 desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
634 desc_item->num = index;
635 if (desc->count < index)
637 desc_item->next = desc->items;
638 desc->items = desc_item;
641 if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
644 va_start(args, index);
648 enum ECPGdtype itemtype;
649 char *tobeinserted = NULL;
651 itemtype = va_arg(args, enum ECPGdtype);
653 if (itemtype == ECPGd_EODT)
656 var->type = va_arg(args, enum ECPGttype);
657 var->pointer = va_arg(args, char *);
659 var->varcharsize = va_arg(args, long);
660 var->arrsize = va_arg(args, long);
661 var->offset = va_arg(args, long);
663 if (var->arrsize == 0 || var->varcharsize == 0)
664 var->value = *((char **) (var->pointer));
666 var->value = var->pointer;
669 * negative values are used to indicate an array without given bounds
671 /* reset to zero for us */
672 if (var->arrsize < 0)
674 if (var->varcharsize < 0)
675 var->varcharsize = 0;
683 if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
690 set_desc_attr(desc_item, var, tobeinserted);
695 case ECPGd_indicator:
696 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
700 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
703 case ECPGd_precision:
704 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
708 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
712 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
719 snprintf(type_str, sizeof(type_str), "%d", itemtype);
720 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
733 /* Free the descriptor and items in it. */
735 descriptor_free(struct descriptor *desc)
737 struct descriptor_item *desc_item;
739 for (desc_item = desc->items; desc_item;)
741 struct descriptor_item *di;
743 ecpg_free(desc_item->data);
745 desc_item = desc_item->next;
749 ecpg_free(desc->name);
750 PQclear(desc->result);
755 ECPGdeallocate_desc(int line, const char *name)
757 struct descriptor *desc;
758 struct descriptor *prev;
759 struct sqlca_t *sqlca = ECPGget_sqlca();
763 ecpg_raise(line, ECPG_OUT_OF_MEMORY,
764 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
768 ecpg_init_sqlca(sqlca);
769 for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
771 if (strcmp(name, desc->name) == 0)
774 prev->next = desc->next;
776 set_descriptors(desc->next);
777 descriptor_free(desc);
781 ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
785 #ifdef ENABLE_THREAD_SAFETY
787 /* Deallocate all descriptors in the list */
789 descriptor_deallocate_all(struct descriptor *list)
793 struct descriptor *next = list->next;
795 descriptor_free(list);
799 #endif /* ENABLE_THREAD_SAFETY */
802 ECPGallocate_desc(int line, const char *name)
804 struct descriptor *new;
805 struct sqlca_t *sqlca = ECPGget_sqlca();
809 ecpg_raise(line, ECPG_OUT_OF_MEMORY,
810 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
814 ecpg_init_sqlca(sqlca);
815 new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
818 new->next = get_descriptors();
819 new->name = ecpg_alloc(strlen(name) + 1, line);
827 new->result = PQmakeEmptyPGresult(NULL, 0);
830 ecpg_free(new->name);
832 ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
835 strcpy(new->name, name);
836 set_descriptors(new);
840 /* Find descriptor with name in the connection. */
842 ecpg_find_desc(int line, const char *name)
844 struct descriptor *desc;
846 for (desc = get_descriptors(); desc; desc = desc->next)
848 if (strcmp(name, desc->name) == 0)
852 ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
853 return NULL; /* not found */
857 ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
860 struct connection *con;
861 struct prepared_statement *prep;
864 const char *real_connection_name = NULL;
866 /* DESCRIBE INPUT is not yet supported */
869 ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
873 real_connection_name = ecpg_get_con_name_by_declared_name(stmt_name);
874 if (real_connection_name == NULL)
877 * If can't get the connection name by declared name then using
878 * connection name coming from the parameter connection_name
880 real_connection_name = connection_name;
883 con = ecpg_get_connection(real_connection_name);
886 ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
887 real_connection_name ? real_connection_name : ecpg_gettext("NULL"));
890 prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
893 ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
897 va_start(args, stmt_name);
905 type = va_arg(args, enum ECPGttype);
907 if (type == ECPGt_EORT)
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);
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);
925 case ECPGt_descriptor:
928 struct descriptor *desc = ecpg_find_desc(line, name);
933 res = PQdescribePrepared(con->connection, stmt_name);
934 if (!ecpg_check_PQresult(res, line, con->connection, compat))
937 if (desc->result != NULL)
938 PQclear(desc->result);
946 if (INFORMIX_MODE(compat))
948 struct sqlda_compat **_sqlda = ptr;
949 struct sqlda_compat *sqlda;
951 res = PQdescribePrepared(con->connection, stmt_name);
952 if (!ecpg_check_PQresult(res, line, con->connection, compat))
955 sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
958 struct sqlda_compat *sqlda_old = *_sqlda;
959 struct sqlda_compat *sqlda_old1;
963 sqlda_old1 = sqlda_old->desc_next;
965 sqlda_old = sqlda_old1;
976 struct sqlda_struct **_sqlda = ptr;
977 struct sqlda_struct *sqlda;
979 res = PQdescribePrepared(con->connection, stmt_name);
980 if (!ecpg_check_PQresult(res, line, con->connection, compat))
983 sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
986 struct sqlda_struct *sqlda_old = *_sqlda;
987 struct sqlda_struct *sqlda_old1;
991 sqlda_old1 = sqlda_old->desc_next;
993 sqlda_old = sqlda_old1;
1005 /* nothing else may come */