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

Generated by: LCOV version 1.13