LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/preproc - descriptor.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 66.1 % 180 119
Test Date: 2026-03-03 13:15:30 Functions: 92.3 % 13 12
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * functions needed for descriptor handling
       3              :  *
       4              :  * src/interfaces/ecpg/preproc/descriptor.c
       5              :  *
       6              :  * since descriptor might be either a string constant or a string var
       7              :  * we need to check for a constant if we expect a constant
       8              :  */
       9              : 
      10              : #include "postgres_fe.h"
      11              : 
      12              : #include "preproc_extern.h"
      13              : 
      14              : /*
      15              :  * assignment handling function (descriptor)
      16              :  */
      17              : 
      18              : static struct assignment *assignments;
      19              : 
      20              : void
      21           78 : push_assignment(const char *var, enum ECPGdtype value)
      22              : {
      23           78 :     struct assignment *new = (struct assignment *) mm_alloc(sizeof(struct assignment));
      24              : 
      25           78 :     new->next = assignments;
      26           78 :     new->variable = mm_strdup(var);
      27           78 :     new->value = value;
      28           78 :     assignments = new;
      29           78 : }
      30              : 
      31              : static void
      32           54 : drop_assignments(void)
      33              : {
      34          132 :     while (assignments)
      35              :     {
      36           78 :         struct assignment *old_head = assignments;
      37              : 
      38           78 :         assignments = old_head->next;
      39           78 :         free(old_head->variable);
      40           78 :         free(old_head);
      41              :     }
      42           54 : }
      43              : 
      44              : static void
      45           12 : ECPGnumeric_lvalue(char *name)
      46              : {
      47           12 :     const struct variable *v = find_variable(name);
      48              : 
      49           12 :     switch (v->type->type)
      50              :     {
      51           12 :         case ECPGt_short:
      52              :         case ECPGt_int:
      53              :         case ECPGt_long:
      54              :         case ECPGt_long_long:
      55              :         case ECPGt_unsigned_short:
      56              :         case ECPGt_unsigned_int:
      57              :         case ECPGt_unsigned_long:
      58              :         case ECPGt_unsigned_long_long:
      59              :         case ECPGt_const:
      60           12 :             fputs(name, base_yyout);
      61           12 :             break;
      62            0 :         default:
      63            0 :             mmerror(PARSE_ERROR, ET_ERROR, "variable \"%s\" must have a numeric type", name);
      64            0 :             break;
      65              :     }
      66           12 : }
      67              : 
      68              : /*
      69              :  * descriptor name lookup
      70              :  */
      71              : 
      72              : static struct descriptor *descriptors;
      73              : 
      74              : void
      75           18 : add_descriptor(const char *name, const char *connection)
      76              : {
      77              :     struct descriptor *new;
      78              : 
      79           18 :     if (name[0] != '"')
      80            1 :         return;
      81              : 
      82           17 :     new = (struct descriptor *) mm_alloc(sizeof(struct descriptor));
      83              : 
      84           17 :     new->next = descriptors;
      85           17 :     new->name = mm_strdup(name);
      86           17 :     if (connection)
      87            2 :         new->connection = mm_strdup(connection);
      88              :     else
      89           15 :         new->connection = NULL;
      90           17 :     descriptors = new;
      91              : }
      92              : 
      93              : void
      94           16 : drop_descriptor(const char *name, const char *connection)
      95              : {
      96              :     struct descriptor *i;
      97           16 :     struct descriptor **lastptr = &descriptors;
      98              : 
      99           16 :     if (name[0] != '"')
     100            1 :         return;
     101              : 
     102           19 :     for (i = descriptors; i; lastptr = &i->next, i = i->next)
     103              :     {
     104           19 :         if (strcmp(name, i->name) == 0)
     105              :         {
     106           15 :             if ((!connection && !i->connection)
     107            2 :                 || (connection && i->connection
     108            2 :                     && strcmp(connection, i->connection) == 0))
     109              :             {
     110           15 :                 *lastptr = i->next;
     111           15 :                 free(i->connection);
     112           15 :                 free(i->name);
     113           15 :                 free(i);
     114           15 :                 return;
     115              :             }
     116              :         }
     117              :     }
     118            0 :     if (connection)
     119            0 :         mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to connection %s does not exist", name, connection);
     120              :     else
     121            0 :         mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name);
     122              : }
     123              : 
     124              : struct descriptor *
     125           54 : lookup_descriptor(const char *name, const char *connection)
     126              : {
     127              :     struct descriptor *i;
     128              : 
     129           54 :     if (name[0] != '"')
     130            1 :         return NULL;
     131              : 
     132           67 :     for (i = descriptors; i; i = i->next)
     133              :     {
     134           67 :         if (strcmp(name, i->name) == 0)
     135              :         {
     136           53 :             if ((!connection && !i->connection)
     137            3 :                 || (connection && i->connection
     138            3 :                     && strcmp(connection, i->connection) == 0))
     139           53 :                 return i;
     140            0 :             if (connection && !i->connection)
     141              :             {
     142              :                 /* overwrite descriptor's connection */
     143            0 :                 i->connection = mm_strdup(connection);
     144            0 :                 return i;
     145              :             }
     146              :         }
     147              :     }
     148            0 :     if (connection)
     149            0 :         mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to connection %s does not exist", name, connection);
     150              :     else
     151            0 :         mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name);
     152            0 :     return NULL;
     153              : }
     154              : 
     155              : void
     156           11 : output_get_descr_header(const char *desc_name)
     157              : {
     158              :     struct assignment *results;
     159              : 
     160           11 :     fprintf(base_yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name);
     161           22 :     for (results = assignments; results != NULL; results = results->next)
     162              :     {
     163           11 :         if (results->value == ECPGd_count)
     164           11 :             ECPGnumeric_lvalue(results->variable);
     165              :         else
     166            0 :             mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value);
     167              :     }
     168              : 
     169           11 :     drop_assignments();
     170           11 :     fprintf(base_yyout, "));\n");
     171           11 :     whenever_action(3);
     172           11 : }
     173              : 
     174              : void
     175           31 : output_get_descr(const char *desc_name, const char *index)
     176              : {
     177              :     struct assignment *results;
     178              : 
     179           31 :     fprintf(base_yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index);
     180           82 :     for (results = assignments; results != NULL; results = results->next)
     181              :     {
     182           51 :         const struct variable *v = find_variable(results->variable);
     183           51 :         char       *str_zero = mm_strdup("0");
     184              : 
     185           51 :         switch (results->value)
     186              :         {
     187            0 :             case ECPGd_nullable:
     188            0 :                 mmerror(PARSE_ERROR, ET_WARNING, "nullable is always 1");
     189            0 :                 break;
     190            0 :             case ECPGd_key_member:
     191            0 :                 mmerror(PARSE_ERROR, ET_WARNING, "key_member is always 0");
     192            0 :                 break;
     193           51 :             default:
     194           51 :                 break;
     195              :         }
     196           51 :         fprintf(base_yyout, "%s,", get_dtype(results->value));
     197           51 :         ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level,
     198              :                         NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL);
     199           51 :         free(str_zero);
     200              :     }
     201           31 :     drop_assignments();
     202           31 :     fputs("ECPGd_EODT);\n", base_yyout);
     203              : 
     204           31 :     whenever_action(2 | 1);
     205           31 : }
     206              : 
     207              : void
     208            1 : output_set_descr_header(const char *desc_name)
     209              : {
     210              :     struct assignment *results;
     211              : 
     212            1 :     fprintf(base_yyout, "{ ECPGset_desc_header(__LINE__, %s, (int)(", desc_name);
     213            2 :     for (results = assignments; results != NULL; results = results->next)
     214              :     {
     215            1 :         if (results->value == ECPGd_count)
     216            1 :             ECPGnumeric_lvalue(results->variable);
     217              :         else
     218            0 :             mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value);
     219              :     }
     220              : 
     221            1 :     drop_assignments();
     222            1 :     fprintf(base_yyout, "));\n");
     223            1 :     whenever_action(3);
     224            1 : }
     225              : 
     226              : static const char *
     227            0 : descriptor_item_name(enum ECPGdtype itemcode)
     228              : {
     229            0 :     switch (itemcode)
     230              :     {
     231            0 :         case ECPGd_cardinality:
     232            0 :             return "CARDINALITY";
     233            0 :         case ECPGd_count:
     234            0 :             return "COUNT";
     235            0 :         case ECPGd_data:
     236            0 :             return "DATA";
     237            0 :         case ECPGd_di_code:
     238            0 :             return "DATETIME_INTERVAL_CODE";
     239            0 :         case ECPGd_di_precision:
     240            0 :             return "DATETIME_INTERVAL_PRECISION";
     241            0 :         case ECPGd_indicator:
     242            0 :             return "INDICATOR";
     243            0 :         case ECPGd_key_member:
     244            0 :             return "KEY_MEMBER";
     245            0 :         case ECPGd_length:
     246            0 :             return "LENGTH";
     247            0 :         case ECPGd_name:
     248            0 :             return "NAME";
     249            0 :         case ECPGd_nullable:
     250            0 :             return "NULLABLE";
     251            0 :         case ECPGd_octet:
     252            0 :             return "OCTET_LENGTH";
     253            0 :         case ECPGd_precision:
     254            0 :             return "PRECISION";
     255            0 :         case ECPGd_ret_length:
     256            0 :             return "RETURNED_LENGTH";
     257            0 :         case ECPGd_ret_octet:
     258            0 :             return "RETURNED_OCTET_LENGTH";
     259            0 :         case ECPGd_scale:
     260            0 :             return "SCALE";
     261            0 :         case ECPGd_type:
     262            0 :             return "TYPE";
     263            0 :         default:
     264            0 :             return NULL;
     265              :     }
     266              : }
     267              : 
     268              : void
     269           11 : output_set_descr(const char *desc_name, const char *index)
     270              : {
     271              :     struct assignment *results;
     272              : 
     273           11 :     fprintf(base_yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index);
     274           26 :     for (results = assignments; results != NULL; results = results->next)
     275              :     {
     276           15 :         const struct variable *v = find_variable(results->variable);
     277              : 
     278           15 :         switch (results->value)
     279              :         {
     280            0 :             case ECPGd_cardinality:
     281              :             case ECPGd_di_code:
     282              :             case ECPGd_di_precision:
     283              :             case ECPGd_precision:
     284              :             case ECPGd_scale:
     285            0 :                 mmfatal(PARSE_ERROR, "descriptor item \"%s\" is not implemented",
     286              :                         descriptor_item_name(results->value));
     287              :                 break;
     288              : 
     289            0 :             case ECPGd_key_member:
     290              :             case ECPGd_name:
     291              :             case ECPGd_nullable:
     292              :             case ECPGd_octet:
     293              :             case ECPGd_ret_length:
     294              :             case ECPGd_ret_octet:
     295            0 :                 mmfatal(PARSE_ERROR, "descriptor item \"%s\" cannot be set",
     296              :                         descriptor_item_name(results->value));
     297              :                 break;
     298              : 
     299           15 :             case ECPGd_data:
     300              :             case ECPGd_indicator:
     301              :             case ECPGd_length:
     302              :             case ECPGd_type:
     303              :                 {
     304           15 :                     char       *str_zero = mm_strdup("0");
     305              : 
     306           15 :                     fprintf(base_yyout, "%s,", get_dtype(results->value));
     307           15 :                     ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level,
     308              :                                     NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL);
     309           15 :                     free(str_zero);
     310              :                 }
     311           15 :                 break;
     312              : 
     313           15 :             default:
     314              :                 ;
     315              :         }
     316              :     }
     317           11 :     drop_assignments();
     318           11 :     fputs("ECPGd_EODT);\n", base_yyout);
     319              : 
     320           11 :     whenever_action(2 | 1);
     321           11 : }
     322              : 
     323              : /* I consider dynamic allocation overkill since at most two descriptor
     324              :    variables are possible per statement. (input and output descriptor)
     325              :    And descriptors are no normal variables, so they don't belong into
     326              :    the variable list.
     327              : */
     328              : 
     329              : #define MAX_DESCRIPTOR_NAMELEN 128
     330              : struct variable *
     331           22 : descriptor_variable(const char *name, int input)
     332              : {
     333              :     static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
     334              :     static struct ECPGtype descriptor_type = {ECPGt_descriptor, NULL, NULL, NULL, {NULL}, 0};
     335              :     static struct variable varspace[2] = {
     336              :         {descriptor_names[0], &descriptor_type, 0, NULL},
     337              :         {descriptor_names[1], &descriptor_type, 0, NULL}
     338              :     };
     339              : 
     340           22 :     strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input]));
     341           22 :     return &varspace[input];
     342              : }
     343              : 
     344              : struct variable *
     345           25 : sqlda_variable(const char *name)
     346              : {
     347              :     /*
     348              :      * Presently, sqlda variables are only needed for the duration of the
     349              :      * current statement.  Rather than add infrastructure to manage them,
     350              :      * let's just loc_alloc them.
     351              :      */
     352           25 :     struct variable *p = (struct variable *) loc_alloc(sizeof(struct variable));
     353              : 
     354           25 :     p->name = loc_strdup(name);
     355           25 :     p->type = (struct ECPGtype *) loc_alloc(sizeof(struct ECPGtype));
     356           25 :     p->type->type = ECPGt_sqlda;
     357           25 :     p->type->type_name = NULL;
     358           25 :     p->type->size = NULL;
     359           25 :     p->type->struct_sizeof = NULL;
     360           25 :     p->type->u.element = NULL;
     361           25 :     p->type->counter = 0;
     362           25 :     p->brace_level = 0;
     363           25 :     p->next = NULL;
     364              : 
     365           25 :     return p;
     366              : }
        

Generated by: LCOV version 2.0-1