Header And Logo

PostgreSQL
| The world's most advanced open source database.

descriptor.c

Go to the documentation of this file.
00001 /* dynamic SQL support routines
00002  *
00003  * src/interfaces/ecpg/ecpglib/descriptor.c
00004  */
00005 
00006 #define POSTGRES_ECPG_INTERNAL
00007 #include "postgres_fe.h"
00008 #include "pg_type.h"
00009 
00010 #include "ecpg-pthread-win32.h"
00011 #include "ecpgtype.h"
00012 #include "ecpglib.h"
00013 #include "ecpgerrno.h"
00014 #include "extern.h"
00015 #include "sqlca.h"
00016 #include "sqlda.h"
00017 #include "sql3types.h"
00018 
00019 static void descriptor_free(struct descriptor * desc);
00020 
00021 /* We manage descriptors separately for each thread. */
00022 #ifdef ENABLE_THREAD_SAFETY
00023 static pthread_key_t descriptor_key;
00024 static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
00025 
00026 static void descriptor_deallocate_all(struct descriptor * list);
00027 
00028 static void
00029 descriptor_destructor(void *arg)
00030 {
00031     descriptor_deallocate_all(arg);
00032 }
00033 
00034 static void
00035 descriptor_key_init(void)
00036 {
00037     pthread_key_create(&descriptor_key, descriptor_destructor);
00038 }
00039 
00040 static struct descriptor *
00041 get_descriptors(void)
00042 {
00043     pthread_once(&descriptor_once, descriptor_key_init);
00044     return (struct descriptor *) pthread_getspecific(descriptor_key);
00045 }
00046 
00047 static void
00048 set_descriptors(struct descriptor * value)
00049 {
00050     pthread_setspecific(descriptor_key, value);
00051 }
00052 #else
00053 static struct descriptor *all_descriptors = NULL;
00054 
00055 #define get_descriptors()       (all_descriptors)
00056 #define set_descriptors(value)  do { all_descriptors = (value); } while(0)
00057 #endif
00058 
00059 /* old internal convenience function that might go away later */
00060 static PGresult *
00061 ecpg_result_by_descriptor(int line, const char *name)
00062 {
00063     struct descriptor *desc = ecpg_find_desc(line, name);
00064 
00065     if (desc == NULL)
00066         return NULL;
00067     return desc->result;
00068 }
00069 
00070 static unsigned int
00071 ecpg_dynamic_type_DDT(Oid type)
00072 {
00073     switch (type)
00074     {
00075         case DATEOID:
00076             return SQL3_DDT_DATE;
00077         case TIMEOID:
00078             return SQL3_DDT_TIME;
00079         case TIMESTAMPOID:
00080             return SQL3_DDT_TIMESTAMP;
00081         case TIMESTAMPTZOID:
00082             return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
00083         case TIMETZOID:
00084             return SQL3_DDT_TIME_WITH_TIME_ZONE;
00085         default:
00086             return SQL3_DDT_ILLEGAL;
00087     }
00088 }
00089 
00090 bool
00091 ECPGget_desc_header(int lineno, const char *desc_name, int *count)
00092 {
00093     PGresult   *ECPGresult;
00094     struct sqlca_t *sqlca = ECPGget_sqlca();
00095 
00096     ecpg_init_sqlca(sqlca);
00097     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
00098     if (!ECPGresult)
00099         return false;
00100 
00101     *count = PQnfields(ECPGresult);
00102     sqlca->sqlerrd[2] = 1;
00103     ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
00104     return true;
00105 }
00106 
00107 static bool
00108 get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
00109 {
00110     switch (vartype)
00111     {
00112         case ECPGt_short:
00113             *(short *) var = (short) value;
00114             break;
00115         case ECPGt_int:
00116             *(int *) var = (int) value;
00117             break;
00118         case ECPGt_long:
00119             *(long *) var = (long) value;
00120             break;
00121         case ECPGt_unsigned_short:
00122             *(unsigned short *) var = (unsigned short) value;
00123             break;
00124         case ECPGt_unsigned_int:
00125             *(unsigned int *) var = (unsigned int) value;
00126             break;
00127         case ECPGt_unsigned_long:
00128             *(unsigned long *) var = (unsigned long) value;
00129             break;
00130 #ifdef HAVE_LONG_LONG_INT
00131         case ECPGt_long_long:
00132             *(long long int *) var = (long long int) value;
00133             break;
00134         case ECPGt_unsigned_long_long:
00135             *(unsigned long long int *) var = (unsigned long long int) value;
00136             break;
00137 #endif   /* HAVE_LONG_LONG_INT */
00138         case ECPGt_float:
00139             *(float *) var = (float) value;
00140             break;
00141         case ECPGt_double:
00142             *(double *) var = (double) value;
00143             break;
00144         default:
00145             ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
00146             return (false);
00147     }
00148 
00149     return (true);
00150 }
00151 
00152 static bool
00153 set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
00154 {
00155     switch (vartype)
00156     {
00157         case ECPGt_short:
00158             *target = *(const short *) var;
00159             break;
00160         case ECPGt_int:
00161             *target = *(const int *) var;
00162             break;
00163         case ECPGt_long:
00164             *target = *(const long *) var;
00165             break;
00166         case ECPGt_unsigned_short:
00167             *target = *(const unsigned short *) var;
00168             break;
00169         case ECPGt_unsigned_int:
00170             *target = *(const unsigned int *) var;
00171             break;
00172         case ECPGt_unsigned_long:
00173             *target = *(const unsigned long *) var;
00174             break;
00175 #ifdef HAVE_LONG_LONG_INT
00176         case ECPGt_long_long:
00177             *target = *(const long long int *) var;
00178             break;
00179         case ECPGt_unsigned_long_long:
00180             *target = *(const unsigned long long int *) var;
00181             break;
00182 #endif   /* HAVE_LONG_LONG_INT */
00183         case ECPGt_float:
00184             *target = *(const float *) var;
00185             break;
00186         case ECPGt_double:
00187             *target = *(const double *) var;
00188             break;
00189         default:
00190             ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
00191             return (false);
00192     }
00193 
00194     return true;
00195 }
00196 
00197 static bool
00198 get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
00199 {
00200     switch (vartype)
00201     {
00202         case ECPGt_char:
00203         case ECPGt_unsigned_char:
00204         case ECPGt_string:
00205             strncpy((char *) var, value, varcharsize);
00206             break;
00207         case ECPGt_varchar:
00208             {
00209                 struct ECPGgeneric_varchar *variable =
00210                 (struct ECPGgeneric_varchar *) var;
00211 
00212                 if (varcharsize == 0)
00213                     strncpy(variable->arr, value, strlen(value));
00214                 else
00215                     strncpy(variable->arr, value, varcharsize);
00216 
00217                 variable->len = strlen(value);
00218                 if (varcharsize > 0 && variable->len > varcharsize)
00219                     variable->len = varcharsize;
00220             }
00221             break;
00222         default:
00223             ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
00224             return (false);
00225     }
00226 
00227     return (true);
00228 }
00229 
00230 #define RETURN_IF_NO_DATA   if (ntuples < 1) \
00231                 { \
00232                     va_end(args); \
00233                     ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
00234                     return (false); \
00235                 }
00236 
00237 bool
00238 ECPGget_desc(int lineno, const char *desc_name, int index,...)
00239 {
00240     va_list     args;
00241     PGresult   *ECPGresult;
00242     enum ECPGdtype type;
00243     int         ntuples,
00244                 act_tuple;
00245     struct variable data_var;
00246     struct sqlca_t *sqlca = ECPGget_sqlca();
00247 
00248     va_start(args, index);
00249     ecpg_init_sqlca(sqlca);
00250     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
00251     if (!ECPGresult)
00252     {
00253         va_end(args);
00254         return (false);
00255     }
00256 
00257     ntuples = PQntuples(ECPGresult);
00258 
00259     if (index < 1 || index > PQnfields(ECPGresult))
00260     {
00261         ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
00262         va_end(args);
00263         return (false);
00264     }
00265 
00266     ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
00267     --index;
00268 
00269     type = va_arg(args, enum ECPGdtype);
00270 
00271     memset(&data_var, 0, sizeof data_var);
00272     data_var.type = ECPGt_EORT;
00273     data_var.ind_type = ECPGt_NO_INDICATOR;
00274 
00275     while (type != ECPGd_EODT)
00276     {
00277         char        type_str[20];
00278         long        varcharsize;
00279         long        offset;
00280         long        arrsize;
00281         enum ECPGttype vartype;
00282         void       *var;
00283 
00284         vartype = va_arg(args, enum ECPGttype);
00285         var = va_arg(args, void *);
00286         varcharsize = va_arg(args, long);
00287         arrsize = va_arg(args, long);
00288         offset = va_arg(args, long);
00289 
00290         switch (type)
00291         {
00292             case (ECPGd_indicator):
00293                 RETURN_IF_NO_DATA;
00294                 data_var.ind_type = vartype;
00295                 data_var.ind_pointer = var;
00296                 data_var.ind_varcharsize = varcharsize;
00297                 data_var.ind_arrsize = arrsize;
00298                 data_var.ind_offset = offset;
00299                 if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
00300                     data_var.ind_value = *((void **) (data_var.ind_pointer));
00301                 else
00302                     data_var.ind_value = data_var.ind_pointer;
00303                 break;
00304 
00305             case ECPGd_data:
00306                 RETURN_IF_NO_DATA;
00307                 data_var.type = vartype;
00308                 data_var.pointer = var;
00309                 data_var.varcharsize = varcharsize;
00310                 data_var.arrsize = arrsize;
00311                 data_var.offset = offset;
00312                 if (data_var.arrsize == 0 || data_var.varcharsize == 0)
00313                     data_var.value = *((void **) (data_var.pointer));
00314                 else
00315                     data_var.value = data_var.pointer;
00316                 break;
00317 
00318             case ECPGd_name:
00319                 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
00320                 {
00321                     va_end(args);
00322                     return (false);
00323                 }
00324 
00325                 ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
00326                 break;
00327 
00328             case ECPGd_nullable:
00329                 if (!get_int_item(lineno, var, vartype, 1))
00330                 {
00331                     va_end(args);
00332                     return (false);
00333                 }
00334 
00335                 break;
00336 
00337             case ECPGd_key_member:
00338                 if (!get_int_item(lineno, var, vartype, 0))
00339                 {
00340                     va_end(args);
00341                     return (false);
00342                 }
00343 
00344                 break;
00345 
00346             case ECPGd_scale:
00347                 if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
00348                 {
00349                     va_end(args);
00350                     return (false);
00351                 }
00352 
00353                 ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
00354                 break;
00355 
00356             case ECPGd_precision:
00357                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
00358                 {
00359                     va_end(args);
00360                     return (false);
00361                 }
00362 
00363                 ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
00364                 break;
00365 
00366             case ECPGd_octet:
00367                 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
00368                 {
00369                     va_end(args);
00370                     return (false);
00371                 }
00372 
00373                 ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
00374                 break;
00375 
00376             case ECPGd_length:
00377                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
00378                 {
00379                     va_end(args);
00380                     return (false);
00381                 }
00382 
00383                 ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
00384                 break;
00385 
00386             case ECPGd_type:
00387                 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
00388                 {
00389                     va_end(args);
00390                     return (false);
00391                 }
00392 
00393                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
00394                 break;
00395 
00396             case ECPGd_di_code:
00397                 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
00398                 {
00399                     va_end(args);
00400                     return (false);
00401                 }
00402 
00403                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
00404                 break;
00405 
00406             case ECPGd_cardinality:
00407                 if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
00408                 {
00409                     va_end(args);
00410                     return (false);
00411                 }
00412 
00413                 ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
00414                 break;
00415 
00416             case ECPGd_ret_length:
00417             case ECPGd_ret_octet:
00418 
00419                 RETURN_IF_NO_DATA;
00420 
00421                 /*
00422                  * this is like ECPGstore_result
00423                  */
00424                 if (arrsize > 0 && ntuples > arrsize)
00425                 {
00426                     ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
00427                              lineno, ntuples, arrsize);
00428                     ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
00429                     va_end(args);
00430                     return false;
00431                 }
00432                 /* allocate storage if needed */
00433                 if (arrsize == 0 && *(void **) var == NULL)
00434                 {
00435                     void       *mem = (void *) ecpg_alloc(offset * ntuples, lineno);
00436 
00437                     if (!mem)
00438                     {
00439                         va_end(args);
00440                         return false;
00441                     }
00442                     *(void **) var = mem;
00443                     ecpg_add_mem(mem, lineno);
00444                     var = mem;
00445                 }
00446 
00447                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
00448                 {
00449                     if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
00450                     {
00451                         va_end(args);
00452                         return (false);
00453                     }
00454                     var = (char *) var + offset;
00455                     ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
00456                 }
00457                 break;
00458 
00459             default:
00460                 snprintf(type_str, sizeof(type_str), "%d", type);
00461                 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
00462                 va_end(args);
00463                 return (false);
00464         }
00465 
00466         type = va_arg(args, enum ECPGdtype);
00467     }
00468 
00469     if (data_var.type != ECPGt_EORT)
00470     {
00471         struct statement stmt;
00472         char       *oldlocale;
00473 
00474         /* Make sure we do NOT honor the locale for numeric input */
00475         /* since the database gives the standard decimal point */
00476         oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
00477         setlocale(LC_NUMERIC, "C");
00478 
00479         memset(&stmt, 0, sizeof stmt);
00480         stmt.lineno = lineno;
00481 
00482         /* desperate try to guess something sensible */
00483         stmt.connection = ecpg_get_connection(NULL);
00484         ecpg_store_result(ECPGresult, index, &stmt, &data_var);
00485 
00486         setlocale(LC_NUMERIC, oldlocale);
00487         ecpg_free(oldlocale);
00488     }
00489     else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
00490 
00491         /*
00492          * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
00493          * since this might be changed manually in the .c file let's play it
00494          * safe
00495          */
00496     {
00497         /*
00498          * this is like ECPGstore_result but since we don't have a data
00499          * variable at hand, we can't call it
00500          */
00501         if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
00502         {
00503             ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
00504                      lineno, ntuples, data_var.ind_arrsize);
00505             ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
00506             va_end(args);
00507             return false;
00508         }
00509 
00510         /* allocate storage if needed */
00511         if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
00512         {
00513             void       *mem = (void *) ecpg_alloc(data_var.ind_offset * ntuples, lineno);
00514 
00515             if (!mem)
00516             {
00517                 va_end(args);
00518                 return false;
00519             }
00520             *(void **) data_var.ind_pointer = mem;
00521             ecpg_add_mem(mem, lineno);
00522             data_var.ind_value = mem;
00523         }
00524 
00525         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
00526         {
00527             if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
00528             {
00529                 va_end(args);
00530                 return (false);
00531             }
00532             data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
00533             ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
00534         }
00535     }
00536     sqlca->sqlerrd[2] = ntuples;
00537     va_end(args);
00538     return (true);
00539 }
00540 
00541 #undef RETURN_IF_NO_DATA
00542 
00543 bool
00544 ECPGset_desc_header(int lineno, const char *desc_name, int count)
00545 {
00546     struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
00547 
00548     if (desc == NULL)
00549         return false;
00550     desc->count = count;
00551     return true;
00552 }
00553 
00554 bool
00555 ECPGset_desc(int lineno, const char *desc_name, int index,...)
00556 {
00557     va_list     args;
00558     struct descriptor *desc;
00559     struct descriptor_item *desc_item;
00560     struct variable *var;
00561 
00562     desc = ecpg_find_desc(lineno, desc_name);
00563     if (desc == NULL)
00564         return false;
00565 
00566     for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
00567     {
00568         if (desc_item->num == index)
00569             break;
00570     }
00571 
00572     if (desc_item == NULL)
00573     {
00574         desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
00575         if (!desc_item)
00576             return false;
00577         desc_item->num = index;
00578         if (desc->count < index)
00579             desc->count = index;
00580         desc_item->next = desc->items;
00581         desc->items = desc_item;
00582     }
00583 
00584     if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
00585         return false;
00586 
00587     va_start(args, index);
00588 
00589     for (;;)
00590     {
00591         enum ECPGdtype itemtype;
00592         char       *tobeinserted = NULL;
00593 
00594         itemtype = va_arg(args, enum ECPGdtype);
00595 
00596         if (itemtype == ECPGd_EODT)
00597             break;
00598 
00599         var->type = va_arg(args, enum ECPGttype);
00600         var->pointer = va_arg(args, char *);
00601 
00602         var->varcharsize = va_arg(args, long);
00603         var->arrsize = va_arg(args, long);
00604         var->offset = va_arg(args, long);
00605 
00606         if (var->arrsize == 0 || var->varcharsize == 0)
00607             var->value = *((char **) (var->pointer));
00608         else
00609             var->value = var->pointer;
00610 
00611         /*
00612          * negative values are used to indicate an array without given bounds
00613          */
00614         /* reset to zero for us */
00615         if (var->arrsize < 0)
00616             var->arrsize = 0;
00617         if (var->varcharsize < 0)
00618             var->varcharsize = 0;
00619 
00620         var->next = NULL;
00621 
00622         switch (itemtype)
00623         {
00624             case ECPGd_data:
00625                 {
00626                     if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
00627                     {
00628                         ecpg_free(var);
00629                         va_end(args);
00630                         return false;
00631                     }
00632 
00633                     ecpg_free(desc_item->data); /* free() takes care of a
00634                                                  * potential NULL value */
00635                     desc_item->data = (char *) tobeinserted;
00636                     tobeinserted = NULL;
00637                     break;
00638                 }
00639 
00640             case ECPGd_indicator:
00641                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
00642                 break;
00643 
00644             case ECPGd_length:
00645                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
00646                 break;
00647 
00648             case ECPGd_precision:
00649                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
00650                 break;
00651 
00652             case ECPGd_scale:
00653                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
00654                 break;
00655 
00656             case ECPGd_type:
00657                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
00658                 break;
00659 
00660             default:
00661                 {
00662                     char        type_str[20];
00663 
00664                     snprintf(type_str, sizeof(type_str), "%d", itemtype);
00665                     ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
00666                     ecpg_free(var);
00667                     va_end(args);
00668                     return false;
00669                 }
00670         }
00671     }
00672     ecpg_free(var);
00673     va_end(args);
00674 
00675     return true;
00676 }
00677 
00678 /* Free the descriptor and items in it. */
00679 static void
00680 descriptor_free(struct descriptor * desc)
00681 {
00682     struct descriptor_item *desc_item;
00683 
00684     for (desc_item = desc->items; desc_item;)
00685     {
00686         struct descriptor_item *di;
00687 
00688         ecpg_free(desc_item->data);
00689         di = desc_item;
00690         desc_item = desc_item->next;
00691         ecpg_free(di);
00692     }
00693 
00694     ecpg_free(desc->name);
00695     PQclear(desc->result);
00696     ecpg_free(desc);
00697 }
00698 
00699 bool
00700 ECPGdeallocate_desc(int line, const char *name)
00701 {
00702     struct descriptor *desc;
00703     struct descriptor *prev;
00704     struct sqlca_t *sqlca = ECPGget_sqlca();
00705 
00706     ecpg_init_sqlca(sqlca);
00707     for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
00708     {
00709         if (strcmp(name, desc->name) == 0)
00710         {
00711             if (prev)
00712                 prev->next = desc->next;
00713             else
00714                 set_descriptors(desc->next);
00715             descriptor_free(desc);
00716             return true;
00717         }
00718     }
00719     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
00720     return false;
00721 }
00722 
00723 #ifdef ENABLE_THREAD_SAFETY
00724 
00725 /* Deallocate all descriptors in the list */
00726 static void
00727 descriptor_deallocate_all(struct descriptor * list)
00728 {
00729     while (list)
00730     {
00731         struct descriptor *next = list->next;
00732 
00733         descriptor_free(list);
00734         list = next;
00735     }
00736 }
00737 #endif   /* ENABLE_THREAD_SAFETY */
00738 
00739 bool
00740 ECPGallocate_desc(int line, const char *name)
00741 {
00742     struct descriptor *new;
00743     struct sqlca_t *sqlca = ECPGget_sqlca();
00744 
00745     ecpg_init_sqlca(sqlca);
00746     new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
00747     if (!new)
00748         return false;
00749     new->next = get_descriptors();
00750     new->name = ecpg_alloc(strlen(name) + 1, line);
00751     if (!new->name)
00752     {
00753         ecpg_free(new);
00754         return false;
00755     }
00756     new->count = -1;
00757     new->items = NULL;
00758     new->result = PQmakeEmptyPGresult(NULL, 0);
00759     if (!new->result)
00760     {
00761         ecpg_free(new->name);
00762         ecpg_free(new);
00763         ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
00764         return false;
00765     }
00766     strcpy(new->name, name);
00767     set_descriptors(new);
00768     return true;
00769 }
00770 
00771 /* Find descriptor with name in the connection. */
00772 struct descriptor *
00773 ecpg_find_desc(int line, const char *name)
00774 {
00775     struct descriptor *desc;
00776 
00777     for (desc = get_descriptors(); desc; desc = desc->next)
00778     {
00779         if (strcmp(name, desc->name) == 0)
00780             return desc;
00781     }
00782 
00783     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
00784     return NULL;                /* not found */
00785 }
00786 
00787 bool
00788 ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
00789 {
00790     bool        ret = false;
00791     struct connection *con;
00792     struct prepared_statement *prep;
00793     PGresult   *res;
00794     va_list     args;
00795 
00796     /* DESCRIBE INPUT is not yet supported */
00797     if (input)
00798     {
00799         ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
00800         return ret;
00801     }
00802 
00803     con = ecpg_get_connection(connection_name);
00804     if (!con)
00805     {
00806         ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
00807                    connection_name ? connection_name : ecpg_gettext("NULL"));
00808         return ret;
00809     }
00810     prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
00811     if (!prep)
00812     {
00813         ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
00814         return ret;
00815     }
00816 
00817     va_start(args, stmt_name);
00818 
00819     for (;;)
00820     {
00821         enum ECPGttype type;
00822         void       *ptr;
00823 
00824         /* variable type */
00825         type = va_arg(args, enum ECPGttype);
00826 
00827         if (type == ECPGt_EORT)
00828             break;
00829 
00830         /* rest of variable parameters */
00831         ptr = va_arg(args, void *);
00832         (void) va_arg(args, long);      /* skip args */
00833         (void) va_arg(args, long);
00834         (void) va_arg(args, long);
00835 
00836         /* variable indicator */
00837         (void) va_arg(args, enum ECPGttype);
00838         (void) va_arg(args, void *);    /* skip args */
00839         (void) va_arg(args, long);
00840         (void) va_arg(args, long);
00841         (void) va_arg(args, long);
00842 
00843         switch (type)
00844         {
00845             case ECPGt_descriptor:
00846                 {
00847                     char       *name = ptr;
00848                     struct descriptor *desc = ecpg_find_desc(line, name);
00849 
00850                     if (desc == NULL)
00851                         break;
00852 
00853                     res = PQdescribePrepared(con->connection, stmt_name);
00854                     if (!ecpg_check_PQresult(res, line, con->connection, compat))
00855                         break;
00856 
00857                     if (desc->result != NULL)
00858                         PQclear(desc->result);
00859 
00860                     desc->result = res;
00861                     ret = true;
00862                     break;
00863                 }
00864             case ECPGt_sqlda:
00865                 {
00866                     if (INFORMIX_MODE(compat))
00867                     {
00868                         struct sqlda_compat **_sqlda = ptr;
00869                         struct sqlda_compat *sqlda;
00870 
00871                         res = PQdescribePrepared(con->connection, stmt_name);
00872                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
00873                             break;
00874 
00875                         sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
00876                         if (sqlda)
00877                         {
00878                             struct sqlda_compat *sqlda_old = *_sqlda;
00879                             struct sqlda_compat *sqlda_old1;
00880 
00881                             while (sqlda_old)
00882                             {
00883                                 sqlda_old1 = sqlda_old->desc_next;
00884                                 free(sqlda_old);
00885                                 sqlda_old = sqlda_old1;
00886                             }
00887 
00888                             *_sqlda = sqlda;
00889                             ret = true;
00890                         }
00891 
00892                         PQclear(res);
00893                     }
00894                     else
00895                     {
00896                         struct sqlda_struct **_sqlda = ptr;
00897                         struct sqlda_struct *sqlda;
00898 
00899                         res = PQdescribePrepared(con->connection, stmt_name);
00900                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
00901                             break;
00902 
00903                         sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
00904                         if (sqlda)
00905                         {
00906                             struct sqlda_struct *sqlda_old = *_sqlda;
00907                             struct sqlda_struct *sqlda_old1;
00908 
00909                             while (sqlda_old)
00910                             {
00911                                 sqlda_old1 = sqlda_old->desc_next;
00912                                 free(sqlda_old);
00913                                 sqlda_old = sqlda_old1;
00914                             }
00915 
00916                             *_sqlda = sqlda;
00917                             ret = true;
00918                         }
00919 
00920                         PQclear(res);
00921                     }
00922                     break;
00923                 }
00924             default:
00925                 /* nothing else may come */
00926                 ;
00927         }
00928     }
00929 
00930     va_end(args);
00931 
00932     return ret;
00933 }