LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - descriptor.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 57.8 % 524 303
Test Date: 2026-02-17 17:20:33 Functions: 90.0 % 20 18
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* dynamic SQL support routines
       2              :  *
       3              :  * src/interfaces/ecpg/ecpglib/descriptor.c
       4              :  */
       5              : 
       6              : #define POSTGRES_ECPG_INTERNAL
       7              : #include "postgres_fe.h"
       8              : 
       9              : #include "catalog/pg_type_d.h"
      10              : #include "ecpg-pthread-win32.h"
      11              : #include "ecpgerrno.h"
      12              : #include "ecpglib.h"
      13              : #include "ecpglib_extern.h"
      14              : #include "ecpgtype.h"
      15              : #include "sql3types.h"
      16              : #include "sqlca.h"
      17              : #include "sqlda.h"
      18              : 
      19              : static void descriptor_free(struct descriptor *desc);
      20              : 
      21              : /* We manage descriptors separately for each thread. */
      22              : static pthread_key_t descriptor_key;
      23              : static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
      24              : 
      25              : static void descriptor_deallocate_all(struct descriptor *list);
      26              : 
      27              : static void
      28            0 : descriptor_destructor(void *arg)
      29              : {
      30            0 :     descriptor_deallocate_all(arg);
      31            0 : }
      32              : 
      33              : static void
      34           18 : descriptor_key_init(void)
      35              : {
      36           18 :     pthread_key_create(&descriptor_key, descriptor_destructor);
      37           18 : }
      38              : 
      39              : static struct descriptor *
      40      3200292 : get_descriptors(void)
      41              : {
      42      3200292 :     pthread_once(&descriptor_once, descriptor_key_init);
      43      3200292 :     return (struct descriptor *) pthread_getspecific(descriptor_key);
      44              : }
      45              : 
      46              : static void
      47      3200054 : set_descriptors(struct descriptor *value)
      48              : {
      49      3200054 :     pthread_setspecific(descriptor_key, value);
      50      3200054 : }
      51              : 
      52              : /* old internal convenience function that might go away later */
      53              : static PGresult *
      54          146 : ecpg_result_by_descriptor(int line, const char *name)
      55              : {
      56          146 :     struct descriptor *desc = ecpg_find_desc(line, name);
      57              : 
      58          146 :     if (desc == NULL)
      59            0 :         return NULL;
      60          146 :     return desc->result;
      61              : }
      62              : 
      63              : static unsigned int
      64           16 : ecpg_dynamic_type_DDT(Oid type)
      65              : {
      66           16 :     switch (type)
      67              :     {
      68           16 :         case DATEOID:
      69           16 :             return SQL3_DDT_DATE;
      70            0 :         case TIMEOID:
      71            0 :             return SQL3_DDT_TIME;
      72            0 :         case TIMESTAMPOID:
      73            0 :             return SQL3_DDT_TIMESTAMP;
      74            0 :         case TIMESTAMPTZOID:
      75            0 :             return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
      76            0 :         case TIMETZOID:
      77            0 :             return SQL3_DDT_TIME_WITH_TIME_ZONE;
      78            0 :         default:
      79            0 :             return SQL3_DDT_ILLEGAL;
      80              :     }
      81              : }
      82              : 
      83              : bool
      84           24 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
      85              : {
      86              :     PGresult   *ECPGresult;
      87           24 :     struct sqlca_t *sqlca = ECPGget_sqlca();
      88              : 
      89           24 :     if (sqlca == NULL)
      90              :     {
      91            0 :         ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
      92              :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
      93            0 :         return false;
      94              :     }
      95              : 
      96           24 :     ecpg_init_sqlca(sqlca);
      97           24 :     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
      98           24 :     if (!ECPGresult)
      99            0 :         return false;
     100              : 
     101           24 :     *count = PQnfields(ECPGresult);
     102           24 :     sqlca->sqlerrd[2] = 1;
     103           24 :     ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
     104           24 :     return true;
     105              : }
     106              : 
     107              : static bool
     108          206 : get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
     109              : {
     110          206 :     switch (vartype)
     111              :     {
     112            0 :         case ECPGt_short:
     113            0 :             *(short *) var = (short) value;
     114            0 :             break;
     115          206 :         case ECPGt_int:
     116          206 :             *(int *) var = value;
     117          206 :             break;
     118            0 :         case ECPGt_long:
     119            0 :             *(long *) var = (long) value;
     120            0 :             break;
     121            0 :         case ECPGt_unsigned_short:
     122            0 :             *(unsigned short *) var = (unsigned short) value;
     123            0 :             break;
     124            0 :         case ECPGt_unsigned_int:
     125            0 :             *(unsigned int *) var = (unsigned int) value;
     126            0 :             break;
     127            0 :         case ECPGt_unsigned_long:
     128            0 :             *(unsigned long *) var = (unsigned long) value;
     129            0 :             break;
     130            0 :         case ECPGt_long_long:
     131            0 :             *(long long int *) var = (long long int) value;
     132            0 :             break;
     133            0 :         case ECPGt_unsigned_long_long:
     134            0 :             *(unsigned long long int *) var = (unsigned long long int) value;
     135            0 :             break;
     136            0 :         case ECPGt_float:
     137            0 :             *(float *) var = (float) value;
     138            0 :             break;
     139            0 :         case ECPGt_double:
     140            0 :             *(double *) var = (double) value;
     141            0 :             break;
     142            0 :         default:
     143            0 :             ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
     144            0 :             return false;
     145              :     }
     146              : 
     147          206 :     return true;
     148              : }
     149              : 
     150              : static bool
     151            8 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
     152              : {
     153            8 :     switch (vartype)
     154              :     {
     155            0 :         case ECPGt_short:
     156            0 :             *target = *(const short *) var;
     157            0 :             break;
     158            8 :         case ECPGt_int:
     159            8 :             *target = *(const int *) var;
     160            8 :             break;
     161            0 :         case ECPGt_long:
     162            0 :             *target = *(const long *) var;
     163            0 :             break;
     164            0 :         case ECPGt_unsigned_short:
     165            0 :             *target = *(const unsigned short *) var;
     166            0 :             break;
     167            0 :         case ECPGt_unsigned_int:
     168            0 :             *target = *(const unsigned int *) var;
     169            0 :             break;
     170            0 :         case ECPGt_unsigned_long:
     171            0 :             *target = *(const unsigned long *) var;
     172            0 :             break;
     173            0 :         case ECPGt_long_long:
     174            0 :             *target = *(const long long int *) var;
     175            0 :             break;
     176            0 :         case ECPGt_unsigned_long_long:
     177            0 :             *target = *(const unsigned long long int *) var;
     178            0 :             break;
     179            0 :         case ECPGt_float:
     180            0 :             *target = *(const float *) var;
     181            0 :             break;
     182            0 :         case ECPGt_double:
     183            0 :             *target = *(const double *) var;
     184            0 :             break;
     185            0 :         default:
     186            0 :             ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
     187            0 :             return false;
     188              :     }
     189              : 
     190            8 :     return true;
     191              : }
     192              : 
     193              : static bool
     194           60 : get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
     195              : {
     196           60 :     switch (vartype)
     197              :     {
     198           60 :         case ECPGt_char:
     199              :         case ECPGt_unsigned_char:
     200              :         case ECPGt_string:
     201           60 :             strncpy(var, value, varcharsize);
     202           60 :             break;
     203            0 :         case ECPGt_varchar:
     204              :             {
     205            0 :                 struct ECPGgeneric_varchar *variable =
     206              :                     (struct ECPGgeneric_varchar *) var;
     207              : 
     208            0 :                 if (varcharsize == 0)
     209            0 :                     memcpy(variable->arr, value, strlen(value));
     210              :                 else
     211            0 :                     strncpy(variable->arr, value, varcharsize);
     212              : 
     213            0 :                 variable->len = strlen(value);
     214            0 :                 if (varcharsize > 0 && variable->len > varcharsize)
     215            0 :                     variable->len = varcharsize;
     216              :             }
     217            0 :             break;
     218            0 :         default:
     219            0 :             ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
     220            0 :             return false;
     221              :     }
     222              : 
     223           60 :     return true;
     224              : }
     225              : 
     226              : #define RETURN_IF_NO_DATA   if (ntuples < 1) \
     227              :                 { \
     228              :                     va_end(args); \
     229              :                     ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
     230              :                     return false; \
     231              :                 }
     232              : 
     233              : bool
     234          122 : ECPGget_desc(int lineno, const char *desc_name, int index,...)
     235              : {
     236              :     va_list     args;
     237              :     PGresult   *ECPGresult;
     238              :     enum ECPGdtype type;
     239              :     int         ntuples,
     240              :                 act_tuple;
     241              :     struct variable data_var;
     242          122 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     243          122 :     bool        alloc_failed = (sqlca == NULL);
     244              : 
     245          122 :     if (alloc_failed)
     246              :     {
     247            0 :         ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
     248              :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     249            0 :         return false;
     250              :     }
     251              : 
     252          122 :     va_start(args, index);
     253          122 :     ecpg_init_sqlca(sqlca);
     254          122 :     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
     255          122 :     if (!ECPGresult)
     256              :     {
     257            0 :         va_end(args);
     258            0 :         return false;
     259              :     }
     260              : 
     261          122 :     ntuples = PQntuples(ECPGresult);
     262              : 
     263          122 :     if (index < 1 || index > PQnfields(ECPGresult))
     264              :     {
     265            0 :         ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
     266            0 :         va_end(args);
     267            0 :         return false;
     268              :     }
     269              : 
     270          122 :     ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
     271          122 :     --index;
     272              : 
     273          122 :     type = va_arg(args, enum ECPGdtype);
     274              : 
     275          122 :     memset(&data_var, 0, sizeof data_var);
     276          122 :     data_var.type = ECPGt_EORT;
     277          122 :     data_var.ind_type = ECPGt_NO_INDICATOR;
     278              : 
     279          468 :     while (type != ECPGd_EODT)
     280              :     {
     281              :         char        type_str[20];
     282              :         long        varcharsize;
     283              :         long        offset;
     284              :         long        arrsize;
     285              :         enum ECPGttype vartype;
     286              :         void       *var;
     287              : 
     288          346 :         vartype = va_arg(args, enum ECPGttype);
     289          346 :         var = va_arg(args, void *);
     290          346 :         varcharsize = va_arg(args, long);
     291          346 :         arrsize = va_arg(args, long);
     292          346 :         offset = va_arg(args, long);
     293              : 
     294          346 :         switch (type)
     295              :         {
     296           52 :             case (ECPGd_indicator):
     297           52 :                 RETURN_IF_NO_DATA;
     298           52 :                 data_var.ind_type = vartype;
     299           52 :                 data_var.ind_pointer = var;
     300           52 :                 data_var.ind_varcharsize = varcharsize;
     301           52 :                 data_var.ind_arrsize = arrsize;
     302           52 :                 data_var.ind_offset = offset;
     303           52 :                 if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
     304           20 :                     data_var.ind_value = *((void **) (data_var.ind_pointer));
     305              :                 else
     306           32 :                     data_var.ind_value = data_var.ind_pointer;
     307           52 :                 break;
     308              : 
     309           56 :             case ECPGd_data:
     310           56 :                 RETURN_IF_NO_DATA;
     311           56 :                 data_var.type = vartype;
     312           56 :                 data_var.pointer = var;
     313           56 :                 data_var.varcharsize = varcharsize;
     314           56 :                 data_var.arrsize = arrsize;
     315           56 :                 data_var.offset = offset;
     316           56 :                 if (data_var.arrsize == 0 || data_var.varcharsize == 0)
     317           20 :                     data_var.value = *((void **) (data_var.pointer));
     318              :                 else
     319           36 :                     data_var.value = data_var.pointer;
     320           56 :                 break;
     321              : 
     322           60 :             case ECPGd_name:
     323           60 :                 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
     324              :                 {
     325            0 :                     va_end(args);
     326            0 :                     return false;
     327              :                 }
     328              : 
     329           60 :                 ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
     330           60 :                 break;
     331              : 
     332            0 :             case ECPGd_nullable:
     333            0 :                 if (!get_int_item(lineno, var, vartype, 1))
     334              :                 {
     335            0 :                     va_end(args);
     336            0 :                     return false;
     337              :                 }
     338              : 
     339            0 :                 break;
     340              : 
     341            0 :             case ECPGd_key_member:
     342            0 :                 if (!get_int_item(lineno, var, vartype, 0))
     343              :                 {
     344            0 :                     va_end(args);
     345            0 :                     return false;
     346              :                 }
     347              : 
     348            0 :                 break;
     349              : 
     350           28 :             case ECPGd_scale:
     351           28 :                 if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
     352              :                 {
     353            0 :                     va_end(args);
     354            0 :                     return false;
     355              :                 }
     356              : 
     357           28 :                 ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
     358           28 :                 break;
     359              : 
     360           28 :             case ECPGd_precision:
     361           28 :                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
     362              :                 {
     363            0 :                     va_end(args);
     364            0 :                     return false;
     365              :                 }
     366              : 
     367           28 :                 ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
     368           28 :                 break;
     369              : 
     370           28 :             case ECPGd_octet:
     371           28 :                 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
     372              :                 {
     373            0 :                     va_end(args);
     374            0 :                     return false;
     375              :                 }
     376              : 
     377           28 :                 ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
     378           28 :                 break;
     379              : 
     380           30 :             case ECPGd_length:
     381           30 :                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
     382              :                 {
     383            0 :                     va_end(args);
     384            0 :                     return false;
     385              :                 }
     386              : 
     387           30 :                 ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
     388           30 :                 break;
     389              : 
     390           28 :             case ECPGd_type:
     391           28 :                 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
     392              :                 {
     393            0 :                     va_end(args);
     394            0 :                     return false;
     395              :                 }
     396              : 
     397           28 :                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
     398           28 :                 break;
     399              : 
     400            8 :             case ECPGd_di_code:
     401            8 :                 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
     402              :                 {
     403            0 :                     va_end(args);
     404            0 :                     return false;
     405              :                 }
     406              : 
     407            8 :                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
     408            8 :                 break;
     409              : 
     410            0 :             case ECPGd_cardinality:
     411            0 :                 if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
     412              :                 {
     413            0 :                     va_end(args);
     414            0 :                     return false;
     415              :                 }
     416              : 
     417            0 :                 ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
     418            0 :                 break;
     419              : 
     420           28 :             case ECPGd_ret_length:
     421              :             case ECPGd_ret_octet:
     422              : 
     423           28 :                 RETURN_IF_NO_DATA;
     424              : 
     425              :                 /*
     426              :                  * this is like ECPGstore_result
     427              :                  */
     428           28 :                 if (arrsize > 0 && ntuples > arrsize)
     429              :                 {
     430            0 :                     ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
     431              :                              lineno, ntuples, arrsize);
     432            0 :                     ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
     433            0 :                     va_end(args);
     434            0 :                     return false;
     435              :                 }
     436              :                 /* allocate storage if needed */
     437           28 :                 if (arrsize == 0 && *(void **) var == NULL)
     438              :                 {
     439            0 :                     void       *mem = ecpg_auto_alloc(offset * ntuples, lineno);
     440              : 
     441            0 :                     if (!mem)
     442              :                     {
     443            0 :                         va_end(args);
     444            0 :                         return false;
     445              :                     }
     446            0 :                     *(void **) var = mem;
     447            0 :                     var = mem;
     448              :                 }
     449              : 
     450           56 :                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     451              :                 {
     452           28 :                     if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
     453              :                     {
     454            0 :                         va_end(args);
     455            0 :                         return false;
     456              :                     }
     457           28 :                     var = (char *) var + offset;
     458           28 :                     ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
     459              :                 }
     460           28 :                 break;
     461              : 
     462            0 :             default:
     463            0 :                 snprintf(type_str, sizeof(type_str), "%d", type);
     464            0 :                 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
     465            0 :                 va_end(args);
     466            0 :                 return false;
     467              :         }
     468              : 
     469          346 :         type = va_arg(args, enum ECPGdtype);
     470              :     }
     471              : 
     472          122 :     if (data_var.type != ECPGt_EORT)
     473              :     {
     474              :         struct statement stmt;
     475              : 
     476           56 :         memset(&stmt, 0, sizeof stmt);
     477           56 :         stmt.lineno = lineno;
     478              : 
     479              :         /* Make sure we do NOT honor the locale for numeric input */
     480              :         /* since the database gives the standard decimal point */
     481              :         /* (see comments in execute.c) */
     482              : #ifdef HAVE_USELOCALE
     483              : 
     484              :         /*
     485              :          * To get here, the above PQnfields() test must have found nonzero
     486              :          * fields.  One needs a connection to create such a descriptor.  (EXEC
     487              :          * SQL SET DESCRIPTOR can populate the descriptor's "items", but it
     488              :          * can't change the descriptor's PQnfields().)  Any successful
     489              :          * connection initializes ecpg_clocale.
     490              :          */
     491              :         Assert(ecpg_clocale);
     492           56 :         stmt.oldlocale = uselocale(ecpg_clocale);
     493              : #else
     494              : #ifdef WIN32
     495              :         stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
     496              : #endif
     497              :         stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL),
     498              :                                      lineno, &alloc_failed);
     499              :         if (alloc_failed)
     500              :         {
     501              :             va_end(args);
     502              :             return false;
     503              :         }
     504              : 
     505              :         setlocale(LC_NUMERIC, "C");
     506              : #endif
     507              : 
     508              :         /* desperate try to guess something sensible */
     509           56 :         stmt.connection = ecpg_get_connection(NULL);
     510           56 :         ecpg_store_result(ECPGresult, index, &stmt, &data_var);
     511              : 
     512              : #ifdef HAVE_USELOCALE
     513           56 :         if (stmt.oldlocale != (locale_t) 0)
     514           56 :             uselocale(stmt.oldlocale);
     515              : #else
     516              :         if (stmt.oldlocale)
     517              :         {
     518              :             setlocale(LC_NUMERIC, stmt.oldlocale);
     519              :             ecpg_free(stmt.oldlocale);
     520              :         }
     521              : #ifdef WIN32
     522              :         if (stmt.oldthreadlocale != -1)
     523              :             _configthreadlocale(stmt.oldthreadlocale);
     524              : #endif
     525              : #endif
     526              :     }
     527           66 :     else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
     528              : 
     529              :         /*
     530              :          * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
     531              :          * since this might be changed manually in the .c file let's play it
     532              :          * safe
     533              :          */
     534              :     {
     535              :         /*
     536              :          * this is like ECPGstore_result but since we don't have a data
     537              :          * variable at hand, we can't call it
     538              :          */
     539           28 :         if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
     540              :         {
     541            0 :             ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
     542              :                      lineno, ntuples, data_var.ind_arrsize);
     543            0 :             ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
     544            0 :             va_end(args);
     545            0 :             return false;
     546              :         }
     547              : 
     548              :         /* allocate storage if needed */
     549           28 :         if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
     550              :         {
     551            0 :             void       *mem = ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
     552              : 
     553            0 :             if (!mem)
     554              :             {
     555            0 :                 va_end(args);
     556            0 :                 return false;
     557              :             }
     558            0 :             *(void **) data_var.ind_pointer = mem;
     559            0 :             data_var.ind_value = mem;
     560              :         }
     561              : 
     562           56 :         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     563              :         {
     564           28 :             if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
     565              :             {
     566            0 :                 va_end(args);
     567            0 :                 return false;
     568              :             }
     569           28 :             data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
     570           28 :             ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
     571              :         }
     572              :     }
     573          122 :     sqlca->sqlerrd[2] = ntuples;
     574          122 :     va_end(args);
     575          122 :     return true;
     576              : }
     577              : 
     578              : #undef RETURN_IF_NO_DATA
     579              : 
     580              : bool
     581            2 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
     582              : {
     583            2 :     struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
     584              : 
     585            2 :     if (desc == NULL)
     586            0 :         return false;
     587            2 :     desc->count = count;
     588            2 :     return true;
     589              : }
     590              : 
     591              : static void
     592           22 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
     593              :               char *tobeinserted)
     594              : {
     595           22 :     if (var->type != ECPGt_bytea)
     596           18 :         desc_item->is_binary = false;
     597              : 
     598              :     else
     599              :     {
     600            4 :         struct ECPGgeneric_bytea *variable =
     601              :             (struct ECPGgeneric_bytea *) (var->value);
     602              : 
     603            4 :         desc_item->is_binary = true;
     604            4 :         desc_item->data_len = variable->len;
     605              :     }
     606              : 
     607           22 :     ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
     608           22 :     desc_item->data = tobeinserted;
     609           22 : }
     610              : 
     611              : 
     612              : bool
     613           22 : ECPGset_desc(int lineno, const char *desc_name, int index,...)
     614              : {
     615              :     va_list     args;
     616              :     struct descriptor *desc;
     617              :     struct descriptor_item *desc_item;
     618              :     struct variable *var;
     619              : 
     620           22 :     desc = ecpg_find_desc(lineno, desc_name);
     621           22 :     if (desc == NULL)
     622            0 :         return false;
     623              : 
     624           34 :     for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
     625              :     {
     626           26 :         if (desc_item->num == index)
     627           14 :             break;
     628              :     }
     629              : 
     630           22 :     if (desc_item == NULL)
     631              :     {
     632            8 :         desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
     633            8 :         if (!desc_item)
     634            0 :             return false;
     635            8 :         desc_item->num = index;
     636            8 :         if (desc->count < index)
     637            8 :             desc->count = index;
     638            8 :         desc_item->next = desc->items;
     639            8 :         desc->items = desc_item;
     640              :     }
     641              : 
     642           22 :     if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
     643            0 :         return false;
     644              : 
     645           22 :     va_start(args, index);
     646              : 
     647              :     for (;;)
     648           30 :     {
     649              :         enum ECPGdtype itemtype;
     650           52 :         char       *tobeinserted = NULL;
     651              : 
     652           52 :         itemtype = va_arg(args, enum ECPGdtype);
     653              : 
     654           52 :         if (itemtype == ECPGd_EODT)
     655           22 :             break;
     656              : 
     657           30 :         var->type = va_arg(args, enum ECPGttype);
     658           30 :         var->pointer = va_arg(args, char *);
     659              : 
     660           30 :         var->varcharsize = va_arg(args, long);
     661           30 :         var->arrsize = va_arg(args, long);
     662           30 :         var->offset = va_arg(args, long);
     663              : 
     664           30 :         if (var->arrsize == 0 || var->varcharsize == 0)
     665            0 :             var->value = *((char **) (var->pointer));
     666              :         else
     667           30 :             var->value = var->pointer;
     668              : 
     669              :         /*
     670              :          * negative values are used to indicate an array without given bounds
     671              :          */
     672              :         /* reset to zero for us */
     673           30 :         if (var->arrsize < 0)
     674            0 :             var->arrsize = 0;
     675           30 :         if (var->varcharsize < 0)
     676            0 :             var->varcharsize = 0;
     677              : 
     678           30 :         var->next = NULL;
     679              : 
     680           30 :         switch (itemtype)
     681              :         {
     682           22 :             case ECPGd_data:
     683              :                 {
     684           22 :                     if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
     685              :                     {
     686            0 :                         ecpg_free(var);
     687            0 :                         va_end(args);
     688            0 :                         return false;
     689              :                     }
     690              : 
     691           22 :                     set_desc_attr(desc_item, var, tobeinserted);
     692           22 :                     tobeinserted = NULL;
     693           22 :                     break;
     694              :                 }
     695              : 
     696            8 :             case ECPGd_indicator:
     697            8 :                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
     698            8 :                 break;
     699              : 
     700            0 :             case ECPGd_length:
     701            0 :                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
     702            0 :                 break;
     703              : 
     704            0 :             case ECPGd_precision:
     705            0 :                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
     706            0 :                 break;
     707              : 
     708            0 :             case ECPGd_scale:
     709            0 :                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
     710            0 :                 break;
     711              : 
     712            0 :             case ECPGd_type:
     713            0 :                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
     714            0 :                 break;
     715              : 
     716            0 :             default:
     717              :                 {
     718              :                     char        type_str[20];
     719              : 
     720            0 :                     snprintf(type_str, sizeof(type_str), "%d", itemtype);
     721            0 :                     ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
     722            0 :                     ecpg_free(var);
     723            0 :                     va_end(args);
     724            0 :                     return false;
     725              :                 }
     726              :         }
     727              :     }
     728           22 :     ecpg_free(var);
     729           22 :     va_end(args);
     730              : 
     731           22 :     return true;
     732              : }
     733              : 
     734              : /* Free the descriptor and items in it. */
     735              : static void
     736      1600030 : descriptor_free(struct descriptor *desc)
     737              : {
     738              :     struct descriptor_item *desc_item;
     739              : 
     740      1600034 :     for (desc_item = desc->items; desc_item;)
     741              :     {
     742              :         struct descriptor_item *di;
     743              : 
     744            4 :         ecpg_free(desc_item->data);
     745            4 :         di = desc_item;
     746            4 :         desc_item = desc_item->next;
     747            4 :         ecpg_free(di);
     748              :     }
     749              : 
     750      1600030 :     ecpg_free(desc->name);
     751      1600030 :     PQclear(desc->result);
     752      1600030 :     ecpg_free(desc);
     753      1600030 : }
     754              : 
     755              : bool
     756      1600030 : ECPGdeallocate_desc(int line, const char *name)
     757              : {
     758              :     struct descriptor *desc;
     759              :     struct descriptor *prev;
     760      1600030 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     761              : 
     762      1600030 :     if (sqlca == NULL)
     763              :     {
     764            0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY,
     765              :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     766            0 :         return false;
     767              :     }
     768              : 
     769      1600030 :     ecpg_init_sqlca(sqlca);
     770      1600040 :     for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
     771              :     {
     772      1600040 :         if (strcmp(name, desc->name) == 0)
     773              :         {
     774      1600030 :             if (prev)
     775           10 :                 prev->next = desc->next;
     776              :             else
     777      1600020 :                 set_descriptors(desc->next);
     778      1600030 :             descriptor_free(desc);
     779      1600030 :             return true;
     780              :         }
     781              :     }
     782            0 :     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
     783            0 :     return false;
     784              : }
     785              : 
     786              : /* Deallocate all descriptors in the list */
     787              : static void
     788            0 : descriptor_deallocate_all(struct descriptor *list)
     789              : {
     790            0 :     while (list)
     791              :     {
     792            0 :         struct descriptor *next = list->next;
     793              : 
     794            0 :         descriptor_free(list);
     795            0 :         list = next;
     796              :     }
     797            0 : }
     798              : 
     799              : bool
     800      1600034 : ECPGallocate_desc(int line, const char *name)
     801              : {
     802              :     struct descriptor *new;
     803      1600034 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     804              : 
     805      1600034 :     if (sqlca == NULL)
     806              :     {
     807            0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY,
     808              :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     809            0 :         return false;
     810              :     }
     811              : 
     812      1600034 :     ecpg_init_sqlca(sqlca);
     813      1600034 :     new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
     814      1600034 :     if (!new)
     815            0 :         return false;
     816      1600034 :     new->next = get_descriptors();
     817      1600034 :     new->name = ecpg_alloc(strlen(name) + 1, line);
     818      1600034 :     if (!new->name)
     819              :     {
     820            0 :         ecpg_free(new);
     821            0 :         return false;
     822              :     }
     823      1600034 :     new->count = -1;
     824      1600034 :     new->items = NULL;
     825      1600034 :     new->result = PQmakeEmptyPGresult(NULL, 0);
     826      1600034 :     if (!new->result)
     827              :     {
     828            0 :         ecpg_free(new->name);
     829            0 :         ecpg_free(new);
     830            0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     831            0 :         return false;
     832              :     }
     833      1600034 :     strcpy(new->name, name);
     834      1600034 :     set_descriptors(new);
     835      1600034 :     return true;
     836              : }
     837              : 
     838              : /* Find descriptor with name in the connection. */
     839              : struct descriptor *
     840          228 : ecpg_find_desc(int line, const char *name)
     841              : {
     842              :     struct descriptor *desc;
     843              : 
     844          318 :     for (desc = get_descriptors(); desc; desc = desc->next)
     845              :     {
     846          318 :         if (strcmp(name, desc->name) == 0)
     847          228 :             return desc;
     848              :     }
     849              : 
     850            0 :     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
     851            0 :     return NULL;                /* not found */
     852              : }
     853              : 
     854              : bool
     855           42 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
     856              : {
     857           42 :     bool        ret = false;
     858              :     struct connection *con;
     859              :     struct prepared_statement *prep;
     860              :     PGresult   *res;
     861              :     va_list     args;
     862              : 
     863              :     /* DESCRIBE INPUT is not yet supported */
     864           42 :     if (input)
     865              :     {
     866            0 :         ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
     867            0 :         return ret;
     868              :     }
     869              : 
     870           42 :     con = ecpg_get_connection(connection_name);
     871           42 :     if (!con)
     872              :     {
     873            0 :         ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
     874            0 :                    connection_name ? connection_name : ecpg_gettext("NULL"));
     875            0 :         return ret;
     876              :     }
     877           42 :     prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
     878           42 :     if (!prep)
     879              :     {
     880            0 :         ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
     881            0 :         return ret;
     882              :     }
     883              : 
     884           42 :     va_start(args, stmt_name);
     885              : 
     886              :     for (;;)
     887           42 :     {
     888              :         enum ECPGttype type;
     889              :         void       *ptr;
     890              : 
     891              :         /* variable type */
     892           84 :         type = va_arg(args, enum ECPGttype);
     893              : 
     894           84 :         if (type == ECPGt_EORT)
     895           42 :             break;
     896              : 
     897              :         /* rest of variable parameters */
     898           42 :         ptr = va_arg(args, void *);
     899           42 :         (void) va_arg(args, long);  /* skip args */
     900           42 :         (void) va_arg(args, long);
     901           42 :         (void) va_arg(args, long);
     902              : 
     903              :         /* variable indicator */
     904           42 :         (void) va_arg(args, enum ECPGttype);
     905           42 :         (void) va_arg(args, void *);    /* skip args */
     906           42 :         (void) va_arg(args, long);
     907           42 :         (void) va_arg(args, long);
     908           42 :         (void) va_arg(args, long);
     909              : 
     910           42 :         switch (type)
     911              :         {
     912           18 :             case ECPGt_descriptor:
     913              :                 {
     914           18 :                     char       *name = ptr;
     915           18 :                     struct descriptor *desc = ecpg_find_desc(line, name);
     916              : 
     917           18 :                     if (desc == NULL)
     918            0 :                         break;
     919              : 
     920           18 :                     res = PQdescribePrepared(con->connection, stmt_name);
     921           18 :                     if (!ecpg_check_PQresult(res, line, con->connection, compat))
     922            0 :                         break;
     923              : 
     924           18 :                     PQclear(desc->result);
     925              : 
     926           18 :                     desc->result = res;
     927           18 :                     ret = true;
     928           18 :                     break;
     929              :                 }
     930           24 :             case ECPGt_sqlda:
     931              :                 {
     932           24 :                     if (INFORMIX_MODE(compat))
     933           12 :                     {
     934           12 :                         struct sqlda_compat **_sqlda = ptr;
     935              :                         struct sqlda_compat *sqlda;
     936              : 
     937           12 :                         res = PQdescribePrepared(con->connection, stmt_name);
     938           12 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     939            0 :                             break;
     940              : 
     941           12 :                         sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
     942           12 :                         if (sqlda)
     943              :                         {
     944           12 :                             struct sqlda_compat *sqlda_old = *_sqlda;
     945              :                             struct sqlda_compat *sqlda_old1;
     946              : 
     947           12 :                             while (sqlda_old)
     948              :                             {
     949            0 :                                 sqlda_old1 = sqlda_old->desc_next;
     950            0 :                                 free(sqlda_old);
     951            0 :                                 sqlda_old = sqlda_old1;
     952              :                             }
     953              : 
     954           12 :                             *_sqlda = sqlda;
     955           12 :                             ret = true;
     956              :                         }
     957              : 
     958           12 :                         PQclear(res);
     959              :                     }
     960              :                     else
     961              :                     {
     962           12 :                         struct sqlda_struct **_sqlda = ptr;
     963              :                         struct sqlda_struct *sqlda;
     964              : 
     965           12 :                         res = PQdescribePrepared(con->connection, stmt_name);
     966           12 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     967            0 :                             break;
     968              : 
     969           12 :                         sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
     970           12 :                         if (sqlda)
     971              :                         {
     972           12 :                             struct sqlda_struct *sqlda_old = *_sqlda;
     973              :                             struct sqlda_struct *sqlda_old1;
     974              : 
     975           12 :                             while (sqlda_old)
     976              :                             {
     977            0 :                                 sqlda_old1 = sqlda_old->desc_next;
     978            0 :                                 free(sqlda_old);
     979            0 :                                 sqlda_old = sqlda_old1;
     980              :                             }
     981              : 
     982           12 :                             *_sqlda = sqlda;
     983           12 :                             ret = true;
     984              :                         }
     985              : 
     986           12 :                         PQclear(res);
     987              :                     }
     988           24 :                     break;
     989              :                 }
     990           42 :             default:
     991              :                 /* nothing else may come */
     992              :                 ;
     993              :         }
     994              :     }
     995              : 
     996           42 :     va_end(args);
     997              : 
     998           42 :     return ret;
     999              : }
        

Generated by: LCOV version 2.0-1