LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - descriptor.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 58.2 % 529 308
Test Date: 2026-05-10 04:16:29 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           20 : descriptor_key_init(void)
      35              : {
      36           20 :     pthread_key_create(&descriptor_key, descriptor_destructor);
      37           20 : }
      38              : 
      39              : static struct descriptor *
      40      3200308 : get_descriptors(void)
      41              : {
      42      3200308 :     pthread_once(&descriptor_once, descriptor_key_init);
      43      3200308 :     return (struct descriptor *) pthread_getspecific(descriptor_key);
      44              : }
      45              : 
      46              : static void
      47      3200058 : set_descriptors(struct descriptor *value)
      48              : {
      49      3200058 :     pthread_setspecific(descriptor_key, value);
      50      3200058 : }
      51              : 
      52              : /* old internal convenience function that might go away later */
      53              : static PGresult *
      54          148 : ecpg_result_by_descriptor(int line, const char *name)
      55              : {
      56          148 :     struct descriptor *desc = ecpg_find_desc(line, name);
      57              : 
      58          148 :     if (desc == NULL)
      59            0 :         return NULL;
      60          148 :     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          124 : 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          124 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     243          124 :     bool        alloc_failed = (sqlca == NULL);
     244              : 
     245          124 :     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          124 :     va_start(args, index);
     253          124 :     ecpg_init_sqlca(sqlca);
     254          124 :     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
     255          124 :     if (!ECPGresult)
     256              :     {
     257            0 :         va_end(args);
     258            0 :         return false;
     259              :     }
     260              : 
     261          124 :     ntuples = PQntuples(ECPGresult);
     262              : 
     263          124 :     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          124 :     ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
     271          124 :     --index;
     272              : 
     273          124 :     type = va_arg(args, enum ECPGdtype);
     274              : 
     275          124 :     memset(&data_var, 0, sizeof data_var);
     276          124 :     data_var.type = ECPGt_EORT;
     277          124 :     data_var.ind_type = ECPGt_NO_INDICATOR;
     278              : 
     279          472 :     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          348 :         vartype = va_arg(args, enum ECPGttype);
     289          348 :         var = va_arg(args, void *);
     290          348 :         varcharsize = va_arg(args, long);
     291          348 :         arrsize = va_arg(args, long);
     292          348 :         offset = va_arg(args, long);
     293              : 
     294          348 :         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           58 :             case ECPGd_data:
     310           58 :                 RETURN_IF_NO_DATA;
     311           58 :                 data_var.type = vartype;
     312           58 :                 data_var.pointer = var;
     313           58 :                 data_var.varcharsize = varcharsize;
     314           58 :                 data_var.arrsize = arrsize;
     315           58 :                 data_var.offset = offset;
     316           58 :                 if (data_var.arrsize == 0 || data_var.varcharsize == 0)
     317           20 :                     data_var.value = *((void **) (data_var.pointer));
     318              :                 else
     319           38 :                     data_var.value = data_var.pointer;
     320           58 :                 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          348 :         type = va_arg(args, enum ECPGdtype);
     470              :     }
     471              : 
     472          124 :     if (data_var.type != ECPGt_EORT)
     473              :     {
     474              :         struct statement stmt;
     475              : 
     476           58 :         memset(&stmt, 0, sizeof stmt);
     477           58 :         stmt.lineno = lineno;
     478              : 
     479              :         /* desperate try to guess something sensible */
     480           58 :         stmt.connection = ecpg_get_connection(NULL);
     481           58 :         if (stmt.connection == NULL)
     482              :         {
     483            2 :             ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
     484            2 :                        ecpg_gettext("NULL"));
     485            2 :             va_end(args);
     486            2 :             return false;
     487              :         }
     488              : 
     489              :         /* Make sure we do NOT honor the locale for numeric input */
     490              :         /* since the database gives the standard decimal point */
     491              :         /* (see comments in execute.c) */
     492              : #ifdef HAVE_USELOCALE
     493              : 
     494              :         /*
     495              :          * To get here, the above PQnfields() test must have found nonzero
     496              :          * fields.  One needs a connection to create such a descriptor.  (EXEC
     497              :          * SQL SET DESCRIPTOR can populate the descriptor's "items", but it
     498              :          * can't change the descriptor's PQnfields().)  Any successful
     499              :          * connection initializes ecpg_clocale.
     500              :          */
     501              :         Assert(ecpg_clocale);
     502           56 :         stmt.oldlocale = uselocale(ecpg_clocale);
     503              : #else
     504              : #ifdef WIN32
     505              :         stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
     506              : #endif
     507              :         stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL),
     508              :                                      lineno, &alloc_failed);
     509              :         if (alloc_failed)
     510              :         {
     511              :             va_end(args);
     512              :             return false;
     513              :         }
     514              : 
     515              :         setlocale(LC_NUMERIC, "C");
     516              : #endif
     517              : 
     518           56 :         ecpg_store_result(ECPGresult, index, &stmt, &data_var);
     519              : 
     520              : #ifdef HAVE_USELOCALE
     521           56 :         if (stmt.oldlocale != (locale_t) 0)
     522           56 :             uselocale(stmt.oldlocale);
     523              : #else
     524              :         if (stmt.oldlocale)
     525              :         {
     526              :             setlocale(LC_NUMERIC, stmt.oldlocale);
     527              :             ecpg_free(stmt.oldlocale);
     528              :         }
     529              : #ifdef WIN32
     530              :         if (stmt.oldthreadlocale != -1)
     531              :             _configthreadlocale(stmt.oldthreadlocale);
     532              : #endif
     533              : #endif
     534              :     }
     535           66 :     else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
     536              : 
     537              :         /*
     538              :          * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
     539              :          * since this might be changed manually in the .c file let's play it
     540              :          * safe
     541              :          */
     542              :     {
     543              :         /*
     544              :          * this is like ECPGstore_result but since we don't have a data
     545              :          * variable at hand, we can't call it
     546              :          */
     547           28 :         if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
     548              :         {
     549            0 :             ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
     550              :                      lineno, ntuples, data_var.ind_arrsize);
     551            0 :             ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
     552            0 :             va_end(args);
     553            0 :             return false;
     554              :         }
     555              : 
     556              :         /* allocate storage if needed */
     557           28 :         if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
     558              :         {
     559            0 :             void       *mem = ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
     560              : 
     561            0 :             if (!mem)
     562              :             {
     563            0 :                 va_end(args);
     564            0 :                 return false;
     565              :             }
     566            0 :             *(void **) data_var.ind_pointer = mem;
     567            0 :             data_var.ind_value = mem;
     568              :         }
     569              : 
     570           56 :         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     571              :         {
     572           28 :             if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
     573              :             {
     574            0 :                 va_end(args);
     575            0 :                 return false;
     576              :             }
     577           28 :             data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
     578           28 :             ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
     579              :         }
     580              :     }
     581          122 :     sqlca->sqlerrd[2] = ntuples;
     582          122 :     va_end(args);
     583          122 :     return true;
     584              : }
     585              : 
     586              : #undef RETURN_IF_NO_DATA
     587              : 
     588              : bool
     589            2 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
     590              : {
     591            2 :     struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
     592              : 
     593            2 :     if (desc == NULL)
     594            0 :         return false;
     595            2 :     desc->count = count;
     596            2 :     return true;
     597              : }
     598              : 
     599              : static void
     600           26 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
     601              :               char *tobeinserted)
     602              : {
     603           26 :     if (var->type != ECPGt_bytea)
     604           22 :         desc_item->is_binary = false;
     605              : 
     606              :     else
     607              :     {
     608            4 :         struct ECPGgeneric_bytea *variable =
     609              :             (struct ECPGgeneric_bytea *) (var->value);
     610              : 
     611            4 :         desc_item->is_binary = true;
     612            4 :         desc_item->data_len = variable->len;
     613              :     }
     614              : 
     615           26 :     ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
     616           26 :     desc_item->data = tobeinserted;
     617           26 : }
     618              : 
     619              : 
     620              : bool
     621           26 : ECPGset_desc(int lineno, const char *desc_name, int index,...)
     622              : {
     623              :     va_list     args;
     624              :     struct descriptor *desc;
     625              :     struct descriptor_item *desc_item;
     626              :     struct variable *var;
     627              : 
     628           26 :     desc = ecpg_find_desc(lineno, desc_name);
     629           26 :     if (desc == NULL)
     630            0 :         return false;
     631              : 
     632           40 :     for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
     633              :     {
     634           28 :         if (desc_item->num == index)
     635           14 :             break;
     636              :     }
     637              : 
     638           26 :     if (desc_item == NULL)
     639              :     {
     640           12 :         desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
     641           12 :         if (!desc_item)
     642            0 :             return false;
     643           12 :         desc_item->num = index;
     644           12 :         if (desc->count < index)
     645           12 :             desc->count = index;
     646           12 :         desc_item->next = desc->items;
     647           12 :         desc->items = desc_item;
     648              :     }
     649              : 
     650           26 :     if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
     651            0 :         return false;
     652              : 
     653           26 :     va_start(args, index);
     654              : 
     655              :     for (;;)
     656           34 :     {
     657              :         enum ECPGdtype itemtype;
     658           60 :         char       *tobeinserted = NULL;
     659              : 
     660           60 :         itemtype = va_arg(args, enum ECPGdtype);
     661              : 
     662           60 :         if (itemtype == ECPGd_EODT)
     663           26 :             break;
     664              : 
     665           34 :         var->type = va_arg(args, enum ECPGttype);
     666           34 :         var->pointer = va_arg(args, char *);
     667              : 
     668           34 :         var->varcharsize = va_arg(args, long);
     669           34 :         var->arrsize = va_arg(args, long);
     670           34 :         var->offset = va_arg(args, long);
     671              : 
     672           34 :         if (var->arrsize == 0 || var->varcharsize == 0)
     673            0 :             var->value = *((char **) (var->pointer));
     674              :         else
     675           34 :             var->value = var->pointer;
     676              : 
     677              :         /*
     678              :          * negative values are used to indicate an array without given bounds
     679              :          */
     680              :         /* reset to zero for us */
     681           34 :         if (var->arrsize < 0)
     682            0 :             var->arrsize = 0;
     683           34 :         if (var->varcharsize < 0)
     684            0 :             var->varcharsize = 0;
     685              : 
     686           34 :         var->next = NULL;
     687              : 
     688           34 :         switch (itemtype)
     689              :         {
     690           26 :             case ECPGd_data:
     691              :                 {
     692           26 :                     if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
     693              :                     {
     694            0 :                         ecpg_free(var);
     695            0 :                         va_end(args);
     696            0 :                         return false;
     697              :                     }
     698              : 
     699           26 :                     set_desc_attr(desc_item, var, tobeinserted);
     700           26 :                     tobeinserted = NULL;
     701           26 :                     break;
     702              :                 }
     703              : 
     704            8 :             case ECPGd_indicator:
     705            8 :                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
     706            8 :                 break;
     707              : 
     708            0 :             case ECPGd_length:
     709            0 :                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
     710            0 :                 break;
     711              : 
     712            0 :             case ECPGd_precision:
     713            0 :                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
     714            0 :                 break;
     715              : 
     716            0 :             case ECPGd_scale:
     717            0 :                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
     718            0 :                 break;
     719              : 
     720            0 :             case ECPGd_type:
     721            0 :                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
     722            0 :                 break;
     723              : 
     724            0 :             default:
     725              :                 {
     726              :                     char        type_str[20];
     727              : 
     728            0 :                     snprintf(type_str, sizeof(type_str), "%d", itemtype);
     729            0 :                     ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
     730            0 :                     ecpg_free(var);
     731            0 :                     va_end(args);
     732            0 :                     return false;
     733              :                 }
     734              :         }
     735              :     }
     736           26 :     ecpg_free(var);
     737           26 :     va_end(args);
     738              : 
     739           26 :     return true;
     740              : }
     741              : 
     742              : /* Free the descriptor and items in it. */
     743              : static void
     744      1600030 : descriptor_free(struct descriptor *desc)
     745              : {
     746              :     struct descriptor_item *desc_item;
     747              : 
     748      1600034 :     for (desc_item = desc->items; desc_item;)
     749              :     {
     750              :         struct descriptor_item *di;
     751              : 
     752            4 :         ecpg_free(desc_item->data);
     753            4 :         di = desc_item;
     754            4 :         desc_item = desc_item->next;
     755            4 :         ecpg_free(di);
     756              :     }
     757              : 
     758      1600030 :     ecpg_free(desc->name);
     759      1600030 :     PQclear(desc->result);
     760      1600030 :     ecpg_free(desc);
     761      1600030 : }
     762              : 
     763              : bool
     764      1600030 : ECPGdeallocate_desc(int line, const char *name)
     765              : {
     766              :     struct descriptor *desc;
     767              :     struct descriptor *prev;
     768      1600030 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     769              : 
     770      1600030 :     if (sqlca == NULL)
     771              :     {
     772            0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY,
     773              :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     774            0 :         return false;
     775              :     }
     776              : 
     777      1600030 :     ecpg_init_sqlca(sqlca);
     778      1600040 :     for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
     779              :     {
     780      1600040 :         if (strcmp(name, desc->name) == 0)
     781              :         {
     782      1600030 :             if (prev)
     783           10 :                 prev->next = desc->next;
     784              :             else
     785      1600020 :                 set_descriptors(desc->next);
     786      1600030 :             descriptor_free(desc);
     787      1600030 :             return true;
     788              :         }
     789              :     }
     790            0 :     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
     791            0 :     return false;
     792              : }
     793              : 
     794              : /* Deallocate all descriptors in the list */
     795              : static void
     796            0 : descriptor_deallocate_all(struct descriptor *list)
     797              : {
     798            0 :     while (list)
     799              :     {
     800            0 :         struct descriptor *next = list->next;
     801              : 
     802            0 :         descriptor_free(list);
     803            0 :         list = next;
     804              :     }
     805            0 : }
     806              : 
     807              : bool
     808      1600038 : ECPGallocate_desc(int line, const char *name)
     809              : {
     810              :     struct descriptor *new;
     811      1600038 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     812              : 
     813      1600038 :     if (sqlca == NULL)
     814              :     {
     815            0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY,
     816              :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     817            0 :         return false;
     818              :     }
     819              : 
     820      1600038 :     ecpg_init_sqlca(sqlca);
     821      1600038 :     new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
     822      1600038 :     if (!new)
     823            0 :         return false;
     824      1600038 :     new->next = get_descriptors();
     825      1600038 :     new->name = ecpg_alloc(strlen(name) + 1, line);
     826      1600038 :     if (!new->name)
     827              :     {
     828            0 :         ecpg_free(new);
     829            0 :         return false;
     830              :     }
     831      1600038 :     new->count = -1;
     832      1600038 :     new->items = NULL;
     833      1600038 :     new->result = PQmakeEmptyPGresult(NULL, 0);
     834      1600038 :     if (!new->result)
     835              :     {
     836            0 :         ecpg_free(new->name);
     837            0 :         ecpg_free(new);
     838            0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     839            0 :         return false;
     840              :     }
     841      1600038 :     strcpy(new->name, name);
     842      1600038 :     set_descriptors(new);
     843      1600038 :     return true;
     844              : }
     845              : 
     846              : /* Find descriptor with name in the connection. */
     847              : struct descriptor *
     848          240 : ecpg_find_desc(int line, const char *name)
     849              : {
     850              :     struct descriptor *desc;
     851              : 
     852          338 :     for (desc = get_descriptors(); desc; desc = desc->next)
     853              :     {
     854          338 :         if (strcmp(name, desc->name) == 0)
     855          240 :             return desc;
     856              :     }
     857              : 
     858            0 :     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
     859            0 :     return NULL;                /* not found */
     860              : }
     861              : 
     862              : bool
     863           42 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
     864              : {
     865           42 :     bool        ret = false;
     866              :     struct connection *con;
     867              :     struct prepared_statement *prep;
     868              :     PGresult   *res;
     869              :     va_list     args;
     870              : 
     871              :     /* DESCRIBE INPUT is not yet supported */
     872           42 :     if (input)
     873              :     {
     874            0 :         ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
     875            0 :         return ret;
     876              :     }
     877              : 
     878           42 :     con = ecpg_get_connection(connection_name);
     879           42 :     if (!con)
     880              :     {
     881            0 :         ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
     882            0 :                    connection_name ? connection_name : ecpg_gettext("NULL"));
     883            0 :         return ret;
     884              :     }
     885           42 :     prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
     886           42 :     if (!prep)
     887              :     {
     888            0 :         ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
     889            0 :         return ret;
     890              :     }
     891              : 
     892           42 :     va_start(args, stmt_name);
     893              : 
     894              :     for (;;)
     895           42 :     {
     896              :         enum ECPGttype type;
     897              :         void       *ptr;
     898              : 
     899              :         /* variable type */
     900           84 :         type = va_arg(args, enum ECPGttype);
     901              : 
     902           84 :         if (type == ECPGt_EORT)
     903           42 :             break;
     904              : 
     905              :         /* rest of variable parameters */
     906           42 :         ptr = va_arg(args, void *);
     907           42 :         (void) va_arg(args, long);  /* skip args */
     908           42 :         (void) va_arg(args, long);
     909           42 :         (void) va_arg(args, long);
     910              : 
     911              :         /* variable indicator */
     912           42 :         (void) va_arg(args, enum ECPGttype);
     913           42 :         (void) va_arg(args, void *);    /* skip args */
     914           42 :         (void) va_arg(args, long);
     915           42 :         (void) va_arg(args, long);
     916           42 :         (void) va_arg(args, long);
     917              : 
     918           42 :         switch (type)
     919              :         {
     920           18 :             case ECPGt_descriptor:
     921              :                 {
     922           18 :                     char       *name = ptr;
     923           18 :                     struct descriptor *desc = ecpg_find_desc(line, name);
     924              : 
     925           18 :                     if (desc == NULL)
     926            0 :                         break;
     927              : 
     928           18 :                     res = PQdescribePrepared(con->connection, stmt_name);
     929           18 :                     if (!ecpg_check_PQresult(res, line, con->connection, compat))
     930            0 :                         break;
     931              : 
     932           18 :                     PQclear(desc->result);
     933              : 
     934           18 :                     desc->result = res;
     935           18 :                     ret = true;
     936           18 :                     break;
     937              :                 }
     938           24 :             case ECPGt_sqlda:
     939              :                 {
     940           24 :                     if (INFORMIX_MODE(compat))
     941           12 :                     {
     942           12 :                         struct sqlda_compat **_sqlda = ptr;
     943              :                         struct sqlda_compat *sqlda;
     944              : 
     945           12 :                         res = PQdescribePrepared(con->connection, stmt_name);
     946           12 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     947            0 :                             break;
     948              : 
     949           12 :                         sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
     950           12 :                         if (sqlda)
     951              :                         {
     952           12 :                             struct sqlda_compat *sqlda_old = *_sqlda;
     953              :                             struct sqlda_compat *sqlda_old1;
     954              : 
     955           12 :                             while (sqlda_old)
     956              :                             {
     957            0 :                                 sqlda_old1 = sqlda_old->desc_next;
     958            0 :                                 free(sqlda_old);
     959            0 :                                 sqlda_old = sqlda_old1;
     960              :                             }
     961              : 
     962           12 :                             *_sqlda = sqlda;
     963           12 :                             ret = true;
     964              :                         }
     965              : 
     966           12 :                         PQclear(res);
     967              :                     }
     968              :                     else
     969              :                     {
     970           12 :                         struct sqlda_struct **_sqlda = ptr;
     971              :                         struct sqlda_struct *sqlda;
     972              : 
     973           12 :                         res = PQdescribePrepared(con->connection, stmt_name);
     974           12 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     975            0 :                             break;
     976              : 
     977           12 :                         sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
     978           12 :                         if (sqlda)
     979              :                         {
     980           12 :                             struct sqlda_struct *sqlda_old = *_sqlda;
     981              :                             struct sqlda_struct *sqlda_old1;
     982              : 
     983           12 :                             while (sqlda_old)
     984              :                             {
     985            0 :                                 sqlda_old1 = sqlda_old->desc_next;
     986            0 :                                 free(sqlda_old);
     987            0 :                                 sqlda_old = sqlda_old1;
     988              :                             }
     989              : 
     990           12 :                             *_sqlda = sqlda;
     991           12 :                             ret = true;
     992              :                         }
     993              : 
     994           12 :                         PQclear(res);
     995              :                     }
     996           24 :                     break;
     997              :                 }
     998           42 :             default:
     999              :                 /* nothing else may come */
    1000              :                 ;
    1001              :         }
    1002              :     }
    1003              : 
    1004           42 :     va_end(args);
    1005              : 
    1006           42 :     return ret;
    1007              : }
        

Generated by: LCOV version 2.0-1