LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - descriptor.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 302 523 57.7 %
Date: 2024-04-23 20:11:10 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((char *) 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         244 :     if (sqlca == NULL)
     245             :     {
     246           0 :         ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
     247             :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     248           0 :         return false;
     249             :     }
     250             : 
     251         244 :     va_start(args, index);
     252         244 :     ecpg_init_sqlca(sqlca);
     253         244 :     ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
     254         244 :     if (!ECPGresult)
     255             :     {
     256           0 :         va_end(args);
     257           0 :         return false;
     258             :     }
     259             : 
     260         244 :     ntuples = PQntuples(ECPGresult);
     261             : 
     262         244 :     if (index < 1 || index > PQnfields(ECPGresult))
     263             :     {
     264           0 :         ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
     265           0 :         va_end(args);
     266           0 :         return false;
     267             :     }
     268             : 
     269         244 :     ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
     270         244 :     --index;
     271             : 
     272         244 :     type = va_arg(args, enum ECPGdtype);
     273             : 
     274         244 :     memset(&data_var, 0, sizeof data_var);
     275         244 :     data_var.type = ECPGt_EORT;
     276         244 :     data_var.ind_type = ECPGt_NO_INDICATOR;
     277             : 
     278         936 :     while (type != ECPGd_EODT)
     279             :     {
     280             :         char        type_str[20];
     281             :         long        varcharsize;
     282             :         long        offset;
     283             :         long        arrsize;
     284             :         enum ECPGttype vartype;
     285             :         void       *var;
     286             : 
     287         692 :         vartype = va_arg(args, enum ECPGttype);
     288         692 :         var = va_arg(args, void *);
     289         692 :         varcharsize = va_arg(args, long);
     290         692 :         arrsize = va_arg(args, long);
     291         692 :         offset = va_arg(args, long);
     292             : 
     293         692 :         switch (type)
     294             :         {
     295         104 :             case (ECPGd_indicator):
     296         104 :                 RETURN_IF_NO_DATA;
     297         104 :                 data_var.ind_type = vartype;
     298         104 :                 data_var.ind_pointer = var;
     299         104 :                 data_var.ind_varcharsize = varcharsize;
     300         104 :                 data_var.ind_arrsize = arrsize;
     301         104 :                 data_var.ind_offset = offset;
     302         104 :                 if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
     303          40 :                     data_var.ind_value = *((void **) (data_var.ind_pointer));
     304             :                 else
     305          64 :                     data_var.ind_value = data_var.ind_pointer;
     306         104 :                 break;
     307             : 
     308         112 :             case ECPGd_data:
     309         112 :                 RETURN_IF_NO_DATA;
     310         112 :                 data_var.type = vartype;
     311         112 :                 data_var.pointer = var;
     312         112 :                 data_var.varcharsize = varcharsize;
     313         112 :                 data_var.arrsize = arrsize;
     314         112 :                 data_var.offset = offset;
     315         112 :                 if (data_var.arrsize == 0 || data_var.varcharsize == 0)
     316          40 :                     data_var.value = *((void **) (data_var.pointer));
     317             :                 else
     318          72 :                     data_var.value = data_var.pointer;
     319         112 :                 break;
     320             : 
     321         120 :             case ECPGd_name:
     322         120 :                 if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
     323             :                 {
     324           0 :                     va_end(args);
     325           0 :                     return false;
     326             :                 }
     327             : 
     328         120 :                 ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
     329         120 :                 break;
     330             : 
     331           0 :             case ECPGd_nullable:
     332           0 :                 if (!get_int_item(lineno, var, vartype, 1))
     333             :                 {
     334           0 :                     va_end(args);
     335           0 :                     return false;
     336             :                 }
     337             : 
     338           0 :                 break;
     339             : 
     340           0 :             case ECPGd_key_member:
     341           0 :                 if (!get_int_item(lineno, var, vartype, 0))
     342             :                 {
     343           0 :                     va_end(args);
     344           0 :                     return false;
     345             :                 }
     346             : 
     347           0 :                 break;
     348             : 
     349          56 :             case ECPGd_scale:
     350          56 :                 if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
     351             :                 {
     352           0 :                     va_end(args);
     353           0 :                     return false;
     354             :                 }
     355             : 
     356          56 :                 ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
     357          56 :                 break;
     358             : 
     359          56 :             case ECPGd_precision:
     360          56 :                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
     361             :                 {
     362           0 :                     va_end(args);
     363           0 :                     return false;
     364             :                 }
     365             : 
     366          56 :                 ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
     367          56 :                 break;
     368             : 
     369          56 :             case ECPGd_octet:
     370          56 :                 if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
     371             :                 {
     372           0 :                     va_end(args);
     373           0 :                     return false;
     374             :                 }
     375             : 
     376          56 :                 ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
     377          56 :                 break;
     378             : 
     379          60 :             case ECPGd_length:
     380          60 :                 if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
     381             :                 {
     382           0 :                     va_end(args);
     383           0 :                     return false;
     384             :                 }
     385             : 
     386          60 :                 ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
     387          60 :                 break;
     388             : 
     389          56 :             case ECPGd_type:
     390          56 :                 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
     391             :                 {
     392           0 :                     va_end(args);
     393           0 :                     return false;
     394             :                 }
     395             : 
     396          56 :                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
     397          56 :                 break;
     398             : 
     399          16 :             case ECPGd_di_code:
     400          16 :                 if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
     401             :                 {
     402           0 :                     va_end(args);
     403           0 :                     return false;
     404             :                 }
     405             : 
     406          16 :                 ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
     407          16 :                 break;
     408             : 
     409           0 :             case ECPGd_cardinality:
     410           0 :                 if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
     411             :                 {
     412           0 :                     va_end(args);
     413           0 :                     return false;
     414             :                 }
     415             : 
     416           0 :                 ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
     417           0 :                 break;
     418             : 
     419          56 :             case ECPGd_ret_length:
     420             :             case ECPGd_ret_octet:
     421             : 
     422          56 :                 RETURN_IF_NO_DATA;
     423             : 
     424             :                 /*
     425             :                  * this is like ECPGstore_result
     426             :                  */
     427          56 :                 if (arrsize > 0 && ntuples > arrsize)
     428             :                 {
     429           0 :                     ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
     430             :                              lineno, ntuples, arrsize);
     431           0 :                     ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
     432           0 :                     va_end(args);
     433           0 :                     return false;
     434             :                 }
     435             :                 /* allocate storage if needed */
     436          56 :                 if (arrsize == 0 && *(void **) var == NULL)
     437             :                 {
     438           0 :                     void       *mem = (void *) ecpg_auto_alloc(offset * ntuples, lineno);
     439             : 
     440           0 :                     if (!mem)
     441             :                     {
     442           0 :                         va_end(args);
     443           0 :                         return false;
     444             :                     }
     445           0 :                     *(void **) var = mem;
     446           0 :                     var = mem;
     447             :                 }
     448             : 
     449         112 :                 for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     450             :                 {
     451          56 :                     if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
     452             :                     {
     453           0 :                         va_end(args);
     454           0 :                         return false;
     455             :                     }
     456          56 :                     var = (char *) var + offset;
     457          56 :                     ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
     458             :                 }
     459          56 :                 break;
     460             : 
     461           0 :             default:
     462           0 :                 snprintf(type_str, sizeof(type_str), "%d", type);
     463           0 :                 ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
     464           0 :                 va_end(args);
     465           0 :                 return false;
     466             :         }
     467             : 
     468         692 :         type = va_arg(args, enum ECPGdtype);
     469             :     }
     470             : 
     471         244 :     if (data_var.type != ECPGt_EORT)
     472             :     {
     473             :         struct statement stmt;
     474             : 
     475         112 :         memset(&stmt, 0, sizeof stmt);
     476         112 :         stmt.lineno = lineno;
     477             : 
     478             :         /* Make sure we do NOT honor the locale for numeric input */
     479             :         /* since the database gives the standard decimal point */
     480             :         /* (see comments in execute.c) */
     481             : #ifdef HAVE_USELOCALE
     482             : 
     483             :         /*
     484             :          * To get here, the above PQnfields() test must have found nonzero
     485             :          * fields.  One needs a connection to create such a descriptor.  (EXEC
     486             :          * SQL SET DESCRIPTOR can populate the descriptor's "items", but it
     487             :          * can't change the descriptor's PQnfields().)  Any successful
     488             :          * connection initializes ecpg_clocale.
     489             :          */
     490             :         Assert(ecpg_clocale);
     491         112 :         stmt.oldlocale = uselocale(ecpg_clocale);
     492             : #else
     493             : #ifdef HAVE__CONFIGTHREADLOCALE
     494             :         stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
     495             : #endif
     496             :         stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
     497             :         setlocale(LC_NUMERIC, "C");
     498             : #endif
     499             : 
     500             :         /* desperate try to guess something sensible */
     501         112 :         stmt.connection = ecpg_get_connection(NULL);
     502         112 :         ecpg_store_result(ECPGresult, index, &stmt, &data_var);
     503             : 
     504             : #ifdef HAVE_USELOCALE
     505         112 :         if (stmt.oldlocale != (locale_t) 0)
     506         112 :             uselocale(stmt.oldlocale);
     507             : #else
     508             :         if (stmt.oldlocale)
     509             :         {
     510             :             setlocale(LC_NUMERIC, stmt.oldlocale);
     511             :             ecpg_free(stmt.oldlocale);
     512             :         }
     513             : #ifdef HAVE__CONFIGTHREADLOCALE
     514             :         if (stmt.oldthreadlocale != -1)
     515             :             (void) _configthreadlocale(stmt.oldthreadlocale);
     516             : #endif
     517             : #endif
     518             :     }
     519         132 :     else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
     520             : 
     521             :         /*
     522             :          * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
     523             :          * since this might be changed manually in the .c file let's play it
     524             :          * safe
     525             :          */
     526             :     {
     527             :         /*
     528             :          * this is like ECPGstore_result but since we don't have a data
     529             :          * variable at hand, we can't call it
     530             :          */
     531          56 :         if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
     532             :         {
     533           0 :             ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
     534             :                      lineno, ntuples, data_var.ind_arrsize);
     535           0 :             ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
     536           0 :             va_end(args);
     537           0 :             return false;
     538             :         }
     539             : 
     540             :         /* allocate storage if needed */
     541          56 :         if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
     542             :         {
     543           0 :             void       *mem = (void *) ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
     544             : 
     545           0 :             if (!mem)
     546             :             {
     547           0 :                 va_end(args);
     548           0 :                 return false;
     549             :             }
     550           0 :             *(void **) data_var.ind_pointer = mem;
     551           0 :             data_var.ind_value = mem;
     552             :         }
     553             : 
     554         112 :         for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
     555             :         {
     556          56 :             if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
     557             :             {
     558           0 :                 va_end(args);
     559           0 :                 return false;
     560             :             }
     561          56 :             data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
     562          56 :             ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
     563             :         }
     564             :     }
     565         244 :     sqlca->sqlerrd[2] = ntuples;
     566         244 :     va_end(args);
     567         244 :     return true;
     568             : }
     569             : 
     570             : #undef RETURN_IF_NO_DATA
     571             : 
     572             : bool
     573           4 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
     574             : {
     575           4 :     struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
     576             : 
     577           4 :     if (desc == NULL)
     578           0 :         return false;
     579           4 :     desc->count = count;
     580           4 :     return true;
     581             : }
     582             : 
     583             : static void
     584          44 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
     585             :               char *tobeinserted)
     586             : {
     587          44 :     if (var->type != ECPGt_bytea)
     588          36 :         desc_item->is_binary = false;
     589             : 
     590             :     else
     591             :     {
     592           8 :         struct ECPGgeneric_bytea *variable =
     593             :             (struct ECPGgeneric_bytea *) (var->value);
     594             : 
     595           8 :         desc_item->is_binary = true;
     596           8 :         desc_item->data_len = variable->len;
     597             :     }
     598             : 
     599          44 :     ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
     600          44 :     desc_item->data = (char *) tobeinserted;
     601          44 : }
     602             : 
     603             : 
     604             : bool
     605          44 : ECPGset_desc(int lineno, const char *desc_name, int index,...)
     606             : {
     607             :     va_list     args;
     608             :     struct descriptor *desc;
     609             :     struct descriptor_item *desc_item;
     610             :     struct variable *var;
     611             : 
     612          44 :     desc = ecpg_find_desc(lineno, desc_name);
     613          44 :     if (desc == NULL)
     614           0 :         return false;
     615             : 
     616          68 :     for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
     617             :     {
     618          52 :         if (desc_item->num == index)
     619          28 :             break;
     620             :     }
     621             : 
     622          44 :     if (desc_item == NULL)
     623             :     {
     624          16 :         desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
     625          16 :         if (!desc_item)
     626           0 :             return false;
     627          16 :         desc_item->num = index;
     628          16 :         if (desc->count < index)
     629          16 :             desc->count = index;
     630          16 :         desc_item->next = desc->items;
     631          16 :         desc->items = desc_item;
     632             :     }
     633             : 
     634          44 :     if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
     635           0 :         return false;
     636             : 
     637          44 :     va_start(args, index);
     638             : 
     639             :     for (;;)
     640          60 :     {
     641             :         enum ECPGdtype itemtype;
     642         104 :         char       *tobeinserted = NULL;
     643             : 
     644         104 :         itemtype = va_arg(args, enum ECPGdtype);
     645             : 
     646         104 :         if (itemtype == ECPGd_EODT)
     647          44 :             break;
     648             : 
     649          60 :         var->type = va_arg(args, enum ECPGttype);
     650          60 :         var->pointer = va_arg(args, char *);
     651             : 
     652          60 :         var->varcharsize = va_arg(args, long);
     653          60 :         var->arrsize = va_arg(args, long);
     654          60 :         var->offset = va_arg(args, long);
     655             : 
     656          60 :         if (var->arrsize == 0 || var->varcharsize == 0)
     657           0 :             var->value = *((char **) (var->pointer));
     658             :         else
     659          60 :             var->value = var->pointer;
     660             : 
     661             :         /*
     662             :          * negative values are used to indicate an array without given bounds
     663             :          */
     664             :         /* reset to zero for us */
     665          60 :         if (var->arrsize < 0)
     666           0 :             var->arrsize = 0;
     667          60 :         if (var->varcharsize < 0)
     668           0 :             var->varcharsize = 0;
     669             : 
     670          60 :         var->next = NULL;
     671             : 
     672          60 :         switch (itemtype)
     673             :         {
     674          44 :             case ECPGd_data:
     675             :                 {
     676          44 :                     if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
     677             :                     {
     678           0 :                         ecpg_free(var);
     679           0 :                         va_end(args);
     680           0 :                         return false;
     681             :                     }
     682             : 
     683          44 :                     set_desc_attr(desc_item, var, tobeinserted);
     684          44 :                     tobeinserted = NULL;
     685          44 :                     break;
     686             :                 }
     687             : 
     688          16 :             case ECPGd_indicator:
     689          16 :                 set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
     690          16 :                 break;
     691             : 
     692           0 :             case ECPGd_length:
     693           0 :                 set_int_item(lineno, &desc_item->length, var->pointer, var->type);
     694           0 :                 break;
     695             : 
     696           0 :             case ECPGd_precision:
     697           0 :                 set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
     698           0 :                 break;
     699             : 
     700           0 :             case ECPGd_scale:
     701           0 :                 set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
     702           0 :                 break;
     703             : 
     704           0 :             case ECPGd_type:
     705           0 :                 set_int_item(lineno, &desc_item->type, var->pointer, var->type);
     706           0 :                 break;
     707             : 
     708           0 :             default:
     709             :                 {
     710             :                     char        type_str[20];
     711             : 
     712           0 :                     snprintf(type_str, sizeof(type_str), "%d", itemtype);
     713           0 :                     ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
     714           0 :                     ecpg_free(var);
     715           0 :                     va_end(args);
     716           0 :                     return false;
     717             :                 }
     718             :         }
     719             :     }
     720          44 :     ecpg_free(var);
     721          44 :     va_end(args);
     722             : 
     723          44 :     return true;
     724             : }
     725             : 
     726             : /* Free the descriptor and items in it. */
     727             : static void
     728     3200060 : descriptor_free(struct descriptor *desc)
     729             : {
     730             :     struct descriptor_item *desc_item;
     731             : 
     732     3200068 :     for (desc_item = desc->items; desc_item;)
     733             :     {
     734             :         struct descriptor_item *di;
     735             : 
     736           8 :         ecpg_free(desc_item->data);
     737           8 :         di = desc_item;
     738           8 :         desc_item = desc_item->next;
     739           8 :         ecpg_free(di);
     740             :     }
     741             : 
     742     3200060 :     ecpg_free(desc->name);
     743     3200060 :     PQclear(desc->result);
     744     3200060 :     ecpg_free(desc);
     745     3200060 : }
     746             : 
     747             : bool
     748     3200060 : ECPGdeallocate_desc(int line, const char *name)
     749             : {
     750             :     struct descriptor *desc;
     751             :     struct descriptor *prev;
     752     3200060 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     753             : 
     754     3200060 :     if (sqlca == NULL)
     755             :     {
     756           0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY,
     757             :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     758           0 :         return false;
     759             :     }
     760             : 
     761     3200060 :     ecpg_init_sqlca(sqlca);
     762     3200080 :     for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
     763             :     {
     764     3200080 :         if (strcmp(name, desc->name) == 0)
     765             :         {
     766     3200060 :             if (prev)
     767          20 :                 prev->next = desc->next;
     768             :             else
     769     3200040 :                 set_descriptors(desc->next);
     770     3200060 :             descriptor_free(desc);
     771     3200060 :             return true;
     772             :         }
     773             :     }
     774           0 :     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
     775           0 :     return false;
     776             : }
     777             : 
     778             : /* Deallocate all descriptors in the list */
     779             : static void
     780           0 : descriptor_deallocate_all(struct descriptor *list)
     781             : {
     782           0 :     while (list)
     783             :     {
     784           0 :         struct descriptor *next = list->next;
     785             : 
     786           0 :         descriptor_free(list);
     787           0 :         list = next;
     788             :     }
     789           0 : }
     790             : 
     791             : bool
     792     3200068 : ECPGallocate_desc(int line, const char *name)
     793             : {
     794             :     struct descriptor *new;
     795     3200068 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     796             : 
     797     3200068 :     if (sqlca == NULL)
     798             :     {
     799           0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY,
     800             :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     801           0 :         return false;
     802             :     }
     803             : 
     804     3200068 :     ecpg_init_sqlca(sqlca);
     805     3200068 :     new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
     806     3200068 :     if (!new)
     807           0 :         return false;
     808     3200068 :     new->next = get_descriptors();
     809     3200068 :     new->name = ecpg_alloc(strlen(name) + 1, line);
     810     3200068 :     if (!new->name)
     811             :     {
     812           0 :         ecpg_free(new);
     813           0 :         return false;
     814             :     }
     815     3200068 :     new->count = -1;
     816     3200068 :     new->items = NULL;
     817     3200068 :     new->result = PQmakeEmptyPGresult(NULL, 0);
     818     3200068 :     if (!new->result)
     819             :     {
     820           0 :         ecpg_free(new->name);
     821           0 :         ecpg_free(new);
     822           0 :         ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     823           0 :         return false;
     824             :     }
     825     3200068 :     strcpy(new->name, name);
     826     3200068 :     set_descriptors(new);
     827     3200068 :     return true;
     828             : }
     829             : 
     830             : /* Find descriptor with name in the connection. */
     831             : struct descriptor *
     832         456 : ecpg_find_desc(int line, const char *name)
     833             : {
     834             :     struct descriptor *desc;
     835             : 
     836         636 :     for (desc = get_descriptors(); desc; desc = desc->next)
     837             :     {
     838         636 :         if (strcmp(name, desc->name) == 0)
     839         456 :             return desc;
     840             :     }
     841             : 
     842           0 :     ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
     843           0 :     return NULL;                /* not found */
     844             : }
     845             : 
     846             : bool
     847          84 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
     848             : {
     849          84 :     bool        ret = false;
     850             :     struct connection *con;
     851             :     struct prepared_statement *prep;
     852             :     PGresult   *res;
     853             :     va_list     args;
     854             : 
     855             :     /* DESCRIBE INPUT is not yet supported */
     856          84 :     if (input)
     857             :     {
     858           0 :         ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
     859           0 :         return ret;
     860             :     }
     861             : 
     862          84 :     con = ecpg_get_connection(connection_name);
     863          84 :     if (!con)
     864             :     {
     865           0 :         ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
     866           0 :                    connection_name ? connection_name : ecpg_gettext("NULL"));
     867           0 :         return ret;
     868             :     }
     869          84 :     prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
     870          84 :     if (!prep)
     871             :     {
     872           0 :         ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
     873           0 :         return ret;
     874             :     }
     875             : 
     876          84 :     va_start(args, stmt_name);
     877             : 
     878             :     for (;;)
     879          84 :     {
     880             :         enum ECPGttype type;
     881             :         void       *ptr;
     882             : 
     883             :         /* variable type */
     884         168 :         type = va_arg(args, enum ECPGttype);
     885             : 
     886         168 :         if (type == ECPGt_EORT)
     887          84 :             break;
     888             : 
     889             :         /* rest of variable parameters */
     890          84 :         ptr = va_arg(args, void *);
     891          84 :         (void) va_arg(args, long);  /* skip args */
     892          84 :         (void) va_arg(args, long);
     893          84 :         (void) va_arg(args, long);
     894             : 
     895             :         /* variable indicator */
     896          84 :         (void) va_arg(args, enum ECPGttype);
     897          84 :         (void) va_arg(args, void *);    /* skip args */
     898          84 :         (void) va_arg(args, long);
     899          84 :         (void) va_arg(args, long);
     900          84 :         (void) va_arg(args, long);
     901             : 
     902          84 :         switch (type)
     903             :         {
     904          36 :             case ECPGt_descriptor:
     905             :                 {
     906          36 :                     char       *name = ptr;
     907          36 :                     struct descriptor *desc = ecpg_find_desc(line, name);
     908             : 
     909          36 :                     if (desc == NULL)
     910           0 :                         break;
     911             : 
     912          36 :                     res = PQdescribePrepared(con->connection, stmt_name);
     913          36 :                     if (!ecpg_check_PQresult(res, line, con->connection, compat))
     914           0 :                         break;
     915             : 
     916          36 :                     PQclear(desc->result);
     917             : 
     918          36 :                     desc->result = res;
     919          36 :                     ret = true;
     920          36 :                     break;
     921             :                 }
     922          48 :             case ECPGt_sqlda:
     923             :                 {
     924          48 :                     if (INFORMIX_MODE(compat))
     925          24 :                     {
     926          24 :                         struct sqlda_compat **_sqlda = ptr;
     927             :                         struct sqlda_compat *sqlda;
     928             : 
     929          24 :                         res = PQdescribePrepared(con->connection, stmt_name);
     930          24 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     931           0 :                             break;
     932             : 
     933          24 :                         sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
     934          24 :                         if (sqlda)
     935             :                         {
     936          24 :                             struct sqlda_compat *sqlda_old = *_sqlda;
     937             :                             struct sqlda_compat *sqlda_old1;
     938             : 
     939          24 :                             while (sqlda_old)
     940             :                             {
     941           0 :                                 sqlda_old1 = sqlda_old->desc_next;
     942           0 :                                 free(sqlda_old);
     943           0 :                                 sqlda_old = sqlda_old1;
     944             :                             }
     945             : 
     946          24 :                             *_sqlda = sqlda;
     947          24 :                             ret = true;
     948             :                         }
     949             : 
     950          24 :                         PQclear(res);
     951             :                     }
     952             :                     else
     953             :                     {
     954          24 :                         struct sqlda_struct **_sqlda = ptr;
     955             :                         struct sqlda_struct *sqlda;
     956             : 
     957          24 :                         res = PQdescribePrepared(con->connection, stmt_name);
     958          24 :                         if (!ecpg_check_PQresult(res, line, con->connection, compat))
     959           0 :                             break;
     960             : 
     961          24 :                         sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
     962          24 :                         if (sqlda)
     963             :                         {
     964          24 :                             struct sqlda_struct *sqlda_old = *_sqlda;
     965             :                             struct sqlda_struct *sqlda_old1;
     966             : 
     967          24 :                             while (sqlda_old)
     968             :                             {
     969           0 :                                 sqlda_old1 = sqlda_old->desc_next;
     970           0 :                                 free(sqlda_old);
     971           0 :                                 sqlda_old = sqlda_old1;
     972             :                             }
     973             : 
     974          24 :                             *_sqlda = sqlda;
     975          24 :                             ret = true;
     976             :                         }
     977             : 
     978          24 :                         PQclear(res);
     979             :                     }
     980          48 :                     break;
     981             :                 }
     982          84 :             default:
     983             :                 /* nothing else may come */
     984             :                 ;
     985             :         }
     986             :     }
     987             : 
     988          84 :     va_end(args);
     989             : 
     990          84 :     return ret;
     991             : }

Generated by: LCOV version 1.14