LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - descriptor.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 303 524 57.8 %
Date: 2025-08-09 08:18:06 Functions: 18 20 90.0 %
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          36 : descriptor_key_init(void)
      35             : {
      36          36 :     pthread_key_create(&descriptor_key, descriptor_destructor);
      37          36 : }
      38             : 
      39             : static struct descriptor *
      40     6400584 : get_descriptors(void)
      41             : {
      42     6400584 :     pthread_once(&descriptor_once, descriptor_key_init);
      43     6400584 :     return (struct descriptor *) pthread_getspecific(descriptor_key);
      44             : }
      45             : 
      46             : static void
      47     6400108 : set_descriptors(struct descriptor *value)
      48             : {
      49     6400108 :     pthread_setspecific(descriptor_key, value);
      50     6400108 : }
      51             : 
      52             : /* old internal convenience function that might go away later */
      53             : static PGresult *
      54         292 : ecpg_result_by_descriptor(int line, const char *name)
      55             : {
      56         292 :     struct descriptor *desc = ecpg_find_desc(line, name);
      57             : 
      58         292 :     if (desc == NULL)
      59           0 :         return NULL;
      60         292 :     return desc->result;
      61             : }
      62             : 
      63             : static unsigned int
      64          32 : ecpg_dynamic_type_DDT(Oid type)
      65             : {
      66          32 :     switch (type)
      67             :     {
      68          32 :         case DATEOID:
      69          32 :             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          48 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
      85             : {
      86             :     PGresult   *ECPGresult;
      87          48 :     struct sqlca_t *sqlca = ECPGget_sqlca();
      88             : 
      89          48 :     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          48 :     ecpg_init_sqlca(sqlca);
      97          48 :     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
      98          48 :     if (!ECPGresult)
      99           0 :         return false;
     100             : 
     101          48 :     *count = PQnfields(ECPGresult);
     102          48 :     sqlca->sqlerrd[2] = 1;
     103          48 :     ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
     104          48 :     return true;
     105             : }
     106             : 
     107             : static bool
     108         412 : get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
     109             : {
     110         412 :     switch (vartype)
     111             :     {
     112           0 :         case ECPGt_short:
     113           0 :             *(short *) var = (short) value;
     114           0 :             break;
     115         412 :         case ECPGt_int:
     116         412 :             *(int *) var = (int) value;
     117         412 :             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         412 :     return true;
     148             : }
     149             : 
     150             : static bool
     151          16 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
     152             : {
     153          16 :     switch (vartype)
     154             :     {
     155           0 :         case ECPGt_short:
     156           0 :             *target = *(const short *) var;
     157           0 :             break;
     158          16 :         case ECPGt_int:
     159          16 :             *target = *(const int *) var;
     160          16 :             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          16 :     return true;
     191             : }
     192             : 
     193             : static bool
     194         120 : get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
     195             : {
     196         120 :     switch (vartype)
     197             :     {
     198         120 :         case ECPGt_char:
     199             :         case ECPGt_unsigned_char:
     200             :         case ECPGt_string:
     201         120 :             strncpy(var, value, varcharsize);
     202         120 :             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         120 :     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         244 : 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         244 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     243         244 :     bool        alloc_failed = (sqlca == NULL);
     244             : 
     245         244 :     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         244 :     va_start(args, index);
     253         244 :     ecpg_init_sqlca(sqlca);
     254         244 :     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
     255         244 :     if (!ECPGresult)
     256             :     {
     257           0 :         va_end(args);
     258           0 :         return false;
     259             :     }
     260             : 
     261         244 :     ntuples = PQntuples(ECPGresult);
     262             : 
     263         244 :     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         244 :     ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
     271         244 :     --index;
     272             : 
     273         244 :     type = va_arg(args, enum ECPGdtype);
     274             : 
     275         244 :     memset(&data_var, 0, sizeof data_var);
     276         244 :     data_var.type = ECPGt_EORT;
     277         244 :     data_var.ind_type = ECPGt_NO_INDICATOR;
     278             : 
     279         936 :     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         692 :         vartype = va_arg(args, enum ECPGttype);
     289         692 :         var = va_arg(args, void *);
     290         692 :         varcharsize = va_arg(args, long);
     291         692 :         arrsize = va_arg(args, long);
     292         692 :         offset = va_arg(args, long);
     293             : 
     294         692 :         switch (type)
     295             :         {
     296         104 :             case (ECPGd_indicator):
     297         104 :                 RETURN_IF_NO_DATA;
     298         104 :                 data_var.ind_type = vartype;
     299         104 :                 data_var.ind_pointer = var;
     300         104 :                 data_var.ind_varcharsize = varcharsize;
     301         104 :                 data_var.ind_arrsize = arrsize;
     302         104 :                 data_var.ind_offset = offset;
     303         104 :                 if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
     304          40 :                     data_var.ind_value = *((void **) (data_var.ind_pointer));
     305             :                 else
     306          64 :                     data_var.ind_value = data_var.ind_pointer;
     307         104 :                 break;
     308             : 
     309         112 :             case ECPGd_data:
     310         112 :                 RETURN_IF_NO_DATA;
     311         112 :                 data_var.type = vartype;
     312         112 :                 data_var.pointer = var;
     313         112 :                 data_var.varcharsize = varcharsize;
     314         112 :                 data_var.arrsize = arrsize;
     315         112 :                 data_var.offset = offset;
     316         112 :                 if (data_var.arrsize == 0 || data_var.varcharsize == 0)
     317          40 :                     data_var.value = *((void **) (data_var.pointer));
     318             :                 else
     319          72 :                     data_var.value = data_var.pointer;
     320         112 :                 break;
     321             : 
     322         120 :             case ECPGd_name:
     323         120 :                 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
     324             :                 {
     325           0 :                     va_end(args);
     326           0 :                     return false;
     327             :                 }
     328             : 
     329         120 :                 ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
     330         120 :                 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          56 :             case ECPGd_scale:
     351          56 :                 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          56 :                 ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
     358          56 :                 break;
     359             : 
     360          56 :             case ECPGd_precision:
     361          56 :                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
     362             :                 {
     363           0 :                     va_end(args);
     364           0 :                     return false;
     365             :                 }
     366             : 
     367          56 :                 ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
     368          56 :                 break;
     369             : 
     370          56 :             case ECPGd_octet:
     371          56 :                 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
     372             :                 {
     373           0 :                     va_end(args);
     374           0 :                     return false;
     375             :                 }
     376             : 
     377          56 :                 ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
     378          56 :                 break;
     379             : 
     380          60 :             case ECPGd_length:
     381          60 :                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
     382             :                 {
     383           0 :                     va_end(args);
     384           0 :                     return false;
     385             :                 }
     386             : 
     387          60 :                 ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
     388          60 :                 break;
     389             : 
     390          56 :             case ECPGd_type:
     391          56 :                 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          56 :                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
     398          56 :                 break;
     399             : 
     400          16 :             case ECPGd_di_code:
     401          16 :                 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          16 :                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
     408          16 :                 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          56 :             case ECPGd_ret_length:
     421             :             case ECPGd_ret_octet:
     422             : 
     423          56 :                 RETURN_IF_NO_DATA;
     424             : 
     425             :                 /*
     426             :                  * this is like ECPGstore_result
     427             :                  */
     428          56 :                 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          56 :                 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         112 :                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     451             :                 {
     452          56 :                     if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
     453             :                     {
     454           0 :                         va_end(args);
     455           0 :                         return false;
     456             :                     }
     457          56 :                     var = (char *) var + offset;
     458          56 :                     ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
     459             :                 }
     460          56 :                 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         692 :         type = va_arg(args, enum ECPGdtype);
     470             :     }
     471             : 
     472         244 :     if (data_var.type != ECPGt_EORT)
     473             :     {
     474             :         struct statement stmt;
     475             : 
     476         112 :         memset(&stmt, 0, sizeof stmt);
     477         112 :         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         112 :         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         112 :         stmt.connection = ecpg_get_connection(NULL);
     510         112 :         ecpg_store_result(ECPGresult, index, &stmt, &data_var);
     511             : 
     512             : #ifdef HAVE_USELOCALE
     513         112 :         if (stmt.oldlocale != (locale_t) 0)
     514         112 :             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         132 :     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          56 :         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          56 :         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         112 :         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     563             :         {
     564          56 :             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          56 :             data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
     570          56 :             ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
     571             :         }
     572             :     }
     573         244 :     sqlca->sqlerrd[2] = ntuples;
     574         244 :     va_end(args);
     575         244 :     return true;
     576             : }
     577             : 
     578             : #undef RETURN_IF_NO_DATA
     579             : 
     580             : bool
     581           4 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
     582             : {
     583           4 :     struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
     584             : 
     585           4 :     if (desc == NULL)
     586           0 :         return false;
     587           4 :     desc->count = count;
     588           4 :     return true;
     589             : }
     590             : 
     591             : static void
     592          44 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
     593             :               char *tobeinserted)
     594             : {
     595          44 :     if (var->type != ECPGt_bytea)
     596          36 :         desc_item->is_binary = false;
     597             : 
     598             :     else
     599             :     {
     600           8 :         struct ECPGgeneric_bytea *variable =
     601             :             (struct ECPGgeneric_bytea *) (var->value);
     602             : 
     603           8 :         desc_item->is_binary = true;
     604           8 :         desc_item->data_len = variable->len;
     605             :     }
     606             : 
     607          44 :     ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
     608          44 :     desc_item->data = tobeinserted;
     609          44 : }
     610             : 
     611             : 
     612             : bool
     613          44 : 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          44 :     desc = ecpg_find_desc(lineno, desc_name);
     621          44 :     if (desc == NULL)
     622           0 :         return false;
     623             : 
     624          68 :     for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
     625             :     {
     626          52 :         if (desc_item->num == index)
     627          28 :             break;
     628             :     }
     629             : 
     630          44 :     if (desc_item == NULL)
     631             :     {
     632          16 :         desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
     633          16 :         if (!desc_item)
     634           0 :             return false;
     635          16 :         desc_item->num = index;
     636          16 :         if (desc->count < index)
     637          16 :             desc->count = index;
     638          16 :         desc_item->next = desc->items;
     639          16 :         desc->items = desc_item;
     640             :     }
     641             : 
     642          44 :     if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
     643           0 :         return false;
     644             : 
     645          44 :     va_start(args, index);
     646             : 
     647             :     for (;;)
     648          60 :     {
     649             :         enum ECPGdtype itemtype;
     650         104 :         char       *tobeinserted = NULL;
     651             : 
     652         104 :         itemtype = va_arg(args, enum ECPGdtype);
     653             : 
     654         104 :         if (itemtype == ECPGd_EODT)
     655          44 :             break;
     656             : 
     657          60 :         var->type = va_arg(args, enum ECPGttype);
     658          60 :         var->pointer = va_arg(args, char *);
     659             : 
     660          60 :         var->varcharsize = va_arg(args, long);
     661          60 :         var->arrsize = va_arg(args, long);
     662          60 :         var->offset = va_arg(args, long);
     663             : 
     664          60 :         if (var->arrsize == 0 || var->varcharsize == 0)
     665           0 :             var->value = *((char **) (var->pointer));
     666             :         else
     667          60 :             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          60 :         if (var->arrsize < 0)
     674           0 :             var->arrsize = 0;
     675          60 :         if (var->varcharsize < 0)
     676           0 :             var->varcharsize = 0;
     677             : 
     678          60 :         var->next = NULL;
     679             : 
     680          60 :         switch (itemtype)
     681             :         {
     682          44 :             case ECPGd_data:
     683             :                 {
     684          44 :                     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          44 :                     set_desc_attr(desc_item, var, tobeinserted);
     692          44 :                     tobeinserted = NULL;
     693          44 :                     break;
     694             :                 }
     695             : 
     696          16 :             case ECPGd_indicator:
     697          16 :                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
     698          16 :                 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          44 :     ecpg_free(var);
     729          44 :     va_end(args);
     730             : 
     731          44 :     return true;
     732             : }
     733             : 
     734             : /* Free the descriptor and items in it. */
     735             : static void
     736     3200060 : descriptor_free(struct descriptor *desc)
     737             : {
     738             :     struct descriptor_item *desc_item;
     739             : 
     740     3200068 :     for (desc_item = desc->items; desc_item;)
     741             :     {
     742             :         struct descriptor_item *di;
     743             : 
     744           8 :         ecpg_free(desc_item->data);
     745           8 :         di = desc_item;
     746           8 :         desc_item = desc_item->next;
     747           8 :         ecpg_free(di);
     748             :     }
     749             : 
     750     3200060 :     ecpg_free(desc->name);
     751     3200060 :     PQclear(desc->result);
     752     3200060 :     ecpg_free(desc);
     753     3200060 : }
     754             : 
     755             : bool
     756     3200060 : ECPGdeallocate_desc(int line, const char *name)
     757             : {
     758             :     struct descriptor *desc;
     759             :     struct descriptor *prev;
     760     3200060 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     761             : 
     762     3200060 :     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     3200060 :     ecpg_init_sqlca(sqlca);
     770     3200080 :     for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
     771             :     {
     772     3200080 :         if (strcmp(name, desc->name) == 0)
     773             :         {
     774     3200060 :             if (prev)
     775          20 :                 prev->next = desc->next;
     776             :             else
     777     3200040 :                 set_descriptors(desc->next);
     778     3200060 :             descriptor_free(desc);
     779     3200060 :             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     3200068 : ECPGallocate_desc(int line, const char *name)
     801             : {
     802             :     struct descriptor *new;
     803     3200068 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     804             : 
     805     3200068 :     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     3200068 :     ecpg_init_sqlca(sqlca);
     813     3200068 :     new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
     814     3200068 :     if (!new)
     815           0 :         return false;
     816     3200068 :     new->next = get_descriptors();
     817     3200068 :     new->name = ecpg_alloc(strlen(name) + 1, line);
     818     3200068 :     if (!new->name)
     819             :     {
     820           0 :         ecpg_free(new);
     821           0 :         return false;
     822             :     }
     823     3200068 :     new->count = -1;
     824     3200068 :     new->items = NULL;
     825     3200068 :     new->result = PQmakeEmptyPGresult(NULL, 0);
     826     3200068 :     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     3200068 :     strcpy(new->name, name);
     834     3200068 :     set_descriptors(new);
     835     3200068 :     return true;
     836             : }
     837             : 
     838             : /* Find descriptor with name in the connection. */
     839             : struct descriptor *
     840         456 : ecpg_find_desc(int line, const char *name)
     841             : {
     842             :     struct descriptor *desc;
     843             : 
     844         636 :     for (desc = get_descriptors(); desc; desc = desc->next)
     845             :     {
     846         636 :         if (strcmp(name, desc->name) == 0)
     847         456 :             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          84 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
     856             : {
     857          84 :     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          84 :     if (input)
     865             :     {
     866           0 :         ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
     867           0 :         return ret;
     868             :     }
     869             : 
     870          84 :     con = ecpg_get_connection(connection_name);
     871          84 :     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          84 :     prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
     878          84 :     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          84 :     va_start(args, stmt_name);
     885             : 
     886             :     for (;;)
     887          84 :     {
     888             :         enum ECPGttype type;
     889             :         void       *ptr;
     890             : 
     891             :         /* variable type */
     892         168 :         type = va_arg(args, enum ECPGttype);
     893             : 
     894         168 :         if (type == ECPGt_EORT)
     895          84 :             break;
     896             : 
     897             :         /* rest of variable parameters */
     898          84 :         ptr = va_arg(args, void *);
     899          84 :         (void) va_arg(args, long);  /* skip args */
     900          84 :         (void) va_arg(args, long);
     901          84 :         (void) va_arg(args, long);
     902             : 
     903             :         /* variable indicator */
     904          84 :         (void) va_arg(args, enum ECPGttype);
     905          84 :         (void) va_arg(args, void *);    /* skip args */
     906          84 :         (void) va_arg(args, long);
     907          84 :         (void) va_arg(args, long);
     908          84 :         (void) va_arg(args, long);
     909             : 
     910          84 :         switch (type)
     911             :         {
     912          36 :             case ECPGt_descriptor:
     913             :                 {
     914          36 :                     char       *name = ptr;
     915          36 :                     struct descriptor *desc = ecpg_find_desc(line, name);
     916             : 
     917          36 :                     if (desc == NULL)
     918           0 :                         break;
     919             : 
     920          36 :                     res = PQdescribePrepared(con->connection, stmt_name);
     921          36 :                     if (!ecpg_check_PQresult(res, line, con->connection, compat))
     922           0 :                         break;
     923             : 
     924          36 :                     PQclear(desc->result);
     925             : 
     926          36 :                     desc->result = res;
     927          36 :                     ret = true;
     928          36 :                     break;
     929             :                 }
     930          48 :             case ECPGt_sqlda:
     931             :                 {
     932          48 :                     if (INFORMIX_MODE(compat))
     933          24 :                     {
     934          24 :                         struct sqlda_compat **_sqlda = ptr;
     935             :                         struct sqlda_compat *sqlda;
     936             : 
     937          24 :                         res = PQdescribePrepared(con->connection, stmt_name);
     938          24 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     939           0 :                             break;
     940             : 
     941          24 :                         sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
     942          24 :                         if (sqlda)
     943             :                         {
     944          24 :                             struct sqlda_compat *sqlda_old = *_sqlda;
     945             :                             struct sqlda_compat *sqlda_old1;
     946             : 
     947          24 :                             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          24 :                             *_sqlda = sqlda;
     955          24 :                             ret = true;
     956             :                         }
     957             : 
     958          24 :                         PQclear(res);
     959             :                     }
     960             :                     else
     961             :                     {
     962          24 :                         struct sqlda_struct **_sqlda = ptr;
     963             :                         struct sqlda_struct *sqlda;
     964             : 
     965          24 :                         res = PQdescribePrepared(con->connection, stmt_name);
     966          24 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     967           0 :                             break;
     968             : 
     969          24 :                         sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
     970          24 :                         if (sqlda)
     971             :                         {
     972          24 :                             struct sqlda_struct *sqlda_old = *_sqlda;
     973             :                             struct sqlda_struct *sqlda_old1;
     974             : 
     975          24 :                             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          24 :                             *_sqlda = sqlda;
     983          24 :                             ret = true;
     984             :                         }
     985             : 
     986          24 :                         PQclear(res);
     987             :                     }
     988          48 :                     break;
     989             :                 }
     990          84 :             default:
     991             :                 /* nothing else may come */
     992             :                 ;
     993             :         }
     994             :     }
     995             : 
     996          84 :     va_end(args);
     997             : 
     998          84 :     return ret;
     999             : }

Generated by: LCOV version 1.16