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

Generated by: LCOV version 1.13