LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - descriptor.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 58.2 % 529 308
Test Date: 2026-05-20 23:16:39 Functions: 90.0 % 20 18
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1