LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/preproc - variable.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 203 285 71.2 %
Date: 2024-04-26 07:11:03 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* src/interfaces/ecpg/preproc/variable.c */
       2             : 
       3             : #include "postgres_fe.h"
       4             : 
       5             : #include "preproc_extern.h"
       6             : 
       7             : static struct variable *allvariables = NULL;
       8             : 
       9             : struct variable *
      10         964 : new_variable(const char *name, struct ECPGtype *type, int brace_level)
      11             : {
      12         964 :     struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
      13             : 
      14         964 :     p->name = mm_strdup(name);
      15         964 :     p->type = type;
      16         964 :     p->brace_level = brace_level;
      17             : 
      18         964 :     p->next = allvariables;
      19         964 :     allvariables = p;
      20             : 
      21         964 :     return p;
      22             : }
      23             : 
      24             : static struct variable *
      25          58 : find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int brace_level)
      26             : {
      27          58 :     char       *next = strpbrk(++str, ".-["),
      28             :                *end,
      29          58 :                 c = '\0';
      30             : 
      31          58 :     if (next != NULL)
      32             :     {
      33           0 :         c = *next;
      34           0 :         *next = '\0';
      35             :     }
      36             : 
      37         112 :     for (; members; members = members->next)
      38             :     {
      39         112 :         if (strcmp(members->name, str) == 0)
      40             :         {
      41          58 :             if (next == NULL)
      42             :             {
      43             :                 /* found the end */
      44          58 :                 switch (members->type->type)
      45             :                 {
      46           0 :                     case ECPGt_array:
      47           0 :                         return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), members->type->size), brace_level);
      48           0 :                     case ECPGt_struct:
      49             :                     case ECPGt_union:
      50           0 :                         return new_variable(name, ECPGmake_struct_type(members->type->u.members, members->type->type, members->type->type_name, members->type->struct_sizeof), brace_level);
      51          58 :                     default:
      52          58 :                         return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
      53             :                 }
      54             :             }
      55             :             else
      56             :             {
      57           0 :                 *next = c;
      58           0 :                 if (c == '[')
      59             :                 {
      60             :                     int         count;
      61             : 
      62             :                     /*
      63             :                      * We don't care about what's inside the array braces so
      64             :                      * just eat up the character
      65             :                      */
      66           0 :                     for (count = 1, end = next + 1; count; end++)
      67             :                     {
      68           0 :                         switch (*end)
      69             :                         {
      70           0 :                             case '[':
      71           0 :                                 count++;
      72           0 :                                 break;
      73           0 :                             case ']':
      74           0 :                                 count--;
      75           0 :                                 break;
      76           0 :                             default:
      77           0 :                                 break;
      78             :                         }
      79             :                     }
      80             :                 }
      81             :                 else
      82           0 :                     end = next;
      83             : 
      84           0 :                 switch (*end)
      85             :                 {
      86           0 :                     case '\0':  /* found the end, but this time it has to be
      87             :                                  * an array element */
      88           0 :                         if (members->type->type != ECPGt_array)
      89           0 :                             mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
      90             : 
      91           0 :                         switch (members->type->u.element->type)
      92             :                         {
      93           0 :                             case ECPGt_array:
      94           0 :                                 return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->u.element->type, members->type->u.element->u.element->size, members->type->u.element->u.element->counter), members->type->u.element->size), brace_level);
      95           0 :                             case ECPGt_struct:
      96             :                             case ECPGt_union:
      97           0 :                                 return new_variable(name, ECPGmake_struct_type(members->type->u.element->u.members, members->type->u.element->type, members->type->u.element->type_name, members->type->u.element->struct_sizeof), brace_level);
      98           0 :                             default:
      99           0 :                                 return new_variable(name, ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), brace_level);
     100             :                         }
     101             :                         break;
     102           0 :                     case '-':
     103           0 :                         if (members->type->type == ECPGt_array)
     104           0 :                             return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
     105             :                         else
     106           0 :                             return find_struct_member(name, ++end, members->type->u.members, brace_level);
     107             :                         break;
     108           0 :                     case '.':
     109           0 :                         if (members->type->type == ECPGt_array)
     110           0 :                             return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
     111             :                         else
     112           0 :                             return find_struct_member(name, end, members->type->u.members, brace_level);
     113             :                         break;
     114           0 :                     default:
     115           0 :                         mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
     116             :                         break;
     117             :                 }
     118             :             }
     119             :         }
     120             :     }
     121             : 
     122           0 :     return NULL;
     123             : }
     124             : 
     125             : static struct variable *
     126          58 : find_struct(char *name, char *next, char *end)
     127             : {
     128             :     struct variable *p;
     129          58 :     char        c = *next;
     130             : 
     131             :     /* first get the mother structure entry */
     132          58 :     *next = '\0';
     133          58 :     p = find_variable(name);
     134             : 
     135          58 :     if (c == '-')
     136             :     {
     137           0 :         if (p->type->type != ECPGt_array)
     138           0 :             mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
     139             : 
     140           0 :         if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
     141           0 :             mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
     142             : 
     143             :         /* restore the name, we will need it later */
     144           0 :         *next = c;
     145             : 
     146           0 :         return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
     147             :     }
     148             :     else
     149             :     {
     150          58 :         if (next == end)
     151             :         {
     152          58 :             if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
     153           0 :                 mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", name);
     154             : 
     155             :             /* restore the name, we will need it later */
     156          58 :             *next = c;
     157             : 
     158          58 :             return find_struct_member(name, end, p->type->u.members, p->brace_level);
     159             :         }
     160             :         else
     161             :         {
     162           0 :             if (p->type->type != ECPGt_array)
     163           0 :                 mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", name);
     164             : 
     165           0 :             if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
     166           0 :                 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
     167             : 
     168             :             /* restore the name, we will need it later */
     169           0 :             *next = c;
     170             : 
     171           0 :             return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
     172             :         }
     173             :     }
     174             : }
     175             : 
     176             : static struct variable *
     177        2724 : find_simple(char *name)
     178             : {
     179             :     struct variable *p;
     180             : 
     181       21320 :     for (p = allvariables; p; p = p->next)
     182             :     {
     183       21320 :         if (strcmp(p->name, name) == 0)
     184        2724 :             return p;
     185             :     }
     186             : 
     187           0 :     return NULL;
     188             : }
     189             : 
     190             : /* Note that this function will end the program in case of an unknown */
     191             : /* variable */
     192             : struct variable *
     193        2782 : find_variable(char *name)
     194             : {
     195             :     char       *next,
     196             :                *end;
     197             :     struct variable *p;
     198             :     int         count;
     199             : 
     200        2782 :     next = strpbrk(name, ".[-");
     201        2782 :     if (next)
     202             :     {
     203         258 :         if (*next == '[')
     204             :         {
     205             :             /*
     206             :              * We don't care about what's inside the array braces so just eat
     207             :              * up the characters
     208             :              */
     209         600 :             for (count = 1, end = next + 1; count; end++)
     210             :             {
     211         400 :                 switch (*end)
     212             :                 {
     213           0 :                     case '[':
     214           0 :                         count++;
     215           0 :                         break;
     216         200 :                     case ']':
     217         200 :                         count--;
     218         200 :                         break;
     219         200 :                     default:
     220         200 :                         break;
     221             :                 }
     222             :             }
     223         200 :             if (*end == '.')
     224           0 :                 p = find_struct(name, next, end);
     225             :             else
     226             :             {
     227         200 :                 char        c = *next;
     228             : 
     229         200 :                 *next = '\0';
     230         200 :                 p = find_simple(name);
     231         200 :                 if (p == NULL)
     232           0 :                     mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
     233             : 
     234         200 :                 *next = c;
     235         200 :                 switch (p->type->u.element->type)
     236             :                 {
     237           0 :                     case ECPGt_array:
     238           0 :                         return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(p->type->u.element->u.element->type, p->type->u.element->u.element->size, p->type->u.element->u.element->counter), p->type->u.element->size), p->brace_level);
     239           6 :                     case ECPGt_struct:
     240             :                     case ECPGt_union:
     241           6 :                         return new_variable(name, ECPGmake_struct_type(p->type->u.element->u.members, p->type->u.element->type, p->type->u.element->type_name, p->type->u.element->struct_sizeof), p->brace_level);
     242         194 :                     default:
     243         194 :                         return new_variable(name, ECPGmake_simple_type(p->type->u.element->type, p->type->u.element->size, p->type->u.element->counter), p->brace_level);
     244             :                 }
     245             :             }
     246             :         }
     247             :         else
     248          58 :             p = find_struct(name, next, next);
     249             :     }
     250             :     else
     251        2524 :         p = find_simple(name);
     252             : 
     253        2582 :     if (p == NULL)
     254           0 :         mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
     255             : 
     256        2582 :     return p;
     257             : }
     258             : 
     259             : void
     260         656 : remove_typedefs(int brace_level)
     261             : {
     262             :     struct typedefs *p,
     263             :                *prev;
     264             : 
     265         962 :     for (p = prev = types; p;)
     266             :     {
     267         306 :         if (p->brace_level >= brace_level)
     268             :         {
     269             :             /* remove it */
     270          26 :             if (p == types)
     271          26 :                 prev = types = p->next;
     272             :             else
     273           0 :                 prev->next = p->next;
     274             : 
     275          26 :             if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
     276          24 :                 free(p->struct_member_list);
     277          26 :             free(p->type);
     278          26 :             free(p->name);
     279          26 :             free(p);
     280          26 :             if (prev == types)
     281          26 :                 p = types;
     282             :             else
     283           0 :                 p = prev ? prev->next : NULL;
     284             :         }
     285             :         else
     286             :         {
     287         280 :             prev = p;
     288         280 :             p = prev->next;
     289             :         }
     290             :     }
     291         656 : }
     292             : 
     293             : void
     294         656 : remove_variables(int brace_level)
     295             : {
     296             :     struct variable *p,
     297             :                *prev;
     298             : 
     299        3112 :     for (p = prev = allvariables; p;)
     300             :     {
     301        2456 :         if (p->brace_level >= brace_level)
     302             :         {
     303             :             /* is it still referenced by a cursor? */
     304             :             struct cursor *ptr;
     305             : 
     306        1506 :             for (ptr = cur; ptr != NULL; ptr = ptr->next)
     307             :             {
     308             :                 struct arguments *varptr,
     309             :                            *prevvar;
     310             : 
     311        1236 :                 for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
     312             :                 {
     313         514 :                     if (p == varptr->variable)
     314             :                     {
     315             :                         /* remove from list */
     316          20 :                         if (varptr == ptr->argsinsert)
     317          14 :                             ptr->argsinsert = varptr->next;
     318             :                         else
     319           6 :                             prevvar->next = varptr->next;
     320             :                     }
     321             :                 }
     322         732 :                 for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
     323             :                 {
     324          10 :                     if (p == varptr->variable)
     325             :                     {
     326             :                         /* remove from list */
     327           6 :                         if (varptr == ptr->argsresult)
     328           6 :                             ptr->argsresult = varptr->next;
     329             :                         else
     330           0 :                             prevvar->next = varptr->next;
     331             :                     }
     332             :                 }
     333             :             }
     334             : 
     335             :             /* remove it */
     336         784 :             if (p == allvariables)
     337         462 :                 prev = allvariables = p->next;
     338             :             else
     339         322 :                 prev->next = p->next;
     340             : 
     341         784 :             ECPGfree_type(p->type);
     342         784 :             free(p->name);
     343         784 :             free(p);
     344         784 :             if (prev == allvariables)
     345         518 :                 p = allvariables;
     346             :             else
     347         266 :                 p = prev ? prev->next : NULL;
     348             :         }
     349             :         else
     350             :         {
     351        1672 :             prev = p;
     352        1672 :             p = prev->next;
     353             :         }
     354             :     }
     355         656 : }
     356             : 
     357             : 
     358             : /*
     359             :  * Here are the variables that need to be handled on every request.
     360             :  * These are of two kinds: input and output.
     361             :  * I will make two lists for them.
     362             :  */
     363             : 
     364             : struct arguments *argsinsert = NULL;
     365             : struct arguments *argsresult = NULL;
     366             : 
     367             : void
     368        3974 : reset_variables(void)
     369             : {
     370        3974 :     argsinsert = NULL;
     371        3974 :     argsresult = NULL;
     372        3974 : }
     373             : 
     374             : /* Insert a new variable into our request list.
     375             :  * Note: The list is dumped from the end,
     376             :  * so we have to add new entries at the beginning */
     377             : void
     378        1010 : add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
     379             : {
     380        1010 :     struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
     381             : 
     382        1010 :     p->variable = var;
     383        1010 :     p->indicator = ind;
     384        1010 :     p->next = *list;
     385        1010 :     *list = p;
     386        1010 : }
     387             : 
     388             : /* Append a new variable to our request list. */
     389             : void
     390         190 : add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
     391             : {
     392             :     struct arguments *p,
     393         190 :                *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
     394             : 
     395         204 :     for (p = *list; p && p->next; p = p->next);
     396             : 
     397         190 :     new->variable = var;
     398         190 :     new->indicator = ind;
     399         190 :     new->next = NULL;
     400             : 
     401         190 :     if (p)
     402          52 :         p->next = new;
     403             :     else
     404         138 :         *list = new;
     405         190 : }
     406             : 
     407             : void
     408          34 : remove_variable_from_list(struct arguments **list, struct variable *var)
     409             : {
     410             :     struct arguments *p,
     411          34 :                *prev = NULL;
     412          34 :     bool        found = false;
     413             : 
     414          34 :     for (p = *list; p; p = p->next)
     415             :     {
     416          34 :         if (p->variable == var)
     417             :         {
     418          34 :             found = true;
     419          34 :             break;
     420             :         }
     421           0 :         prev = p;
     422             :     }
     423          34 :     if (found)
     424             :     {
     425          34 :         if (prev)
     426           0 :             prev->next = p->next;
     427             :         else
     428          34 :             *list = p->next;
     429             :     }
     430          34 : }
     431             : 
     432             : /* Dump out a list of all the variable on this list.
     433             :    This is a recursive function that works from the end of the list and
     434             :    deletes the list as we go on.
     435             :  */
     436             : void
     437        3284 : dump_variables(struct arguments *list, int mode)
     438             : {
     439             :     char       *str_zero;
     440             : 
     441        3284 :     if (list == NULL)
     442        2254 :         return;
     443             : 
     444        1030 :     str_zero = mm_strdup("0");
     445             : 
     446             :     /*
     447             :      * The list is build up from the beginning so lets first dump the end of
     448             :      * the list:
     449             :      */
     450             : 
     451        1030 :     dump_variables(list->next, mode);
     452             : 
     453             :     /* Then the current element and its indicator */
     454        1030 :     ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
     455        1030 :                     list->indicator->name, list->indicator->type, list->indicator->brace_level,
     456             :                     NULL, NULL, str_zero, NULL, NULL);
     457             : 
     458             :     /* Then release the list element. */
     459        1030 :     if (mode != 0)
     460        1030 :         free(list);
     461             : 
     462        1030 :     free(str_zero);
     463             : }
     464             : 
     465             : void
     466         134 : check_indicator(struct ECPGtype *var)
     467             : {
     468             :     /* make sure this is a valid indicator variable */
     469         134 :     switch (var->type)
     470             :     {
     471             :             struct ECPGstruct_member *p;
     472             : 
     473          90 :         case ECPGt_short:
     474             :         case ECPGt_int:
     475             :         case ECPGt_long:
     476             :         case ECPGt_long_long:
     477             :         case ECPGt_unsigned_short:
     478             :         case ECPGt_unsigned_int:
     479             :         case ECPGt_unsigned_long:
     480             :         case ECPGt_unsigned_long_long:
     481          90 :             break;
     482             : 
     483          22 :         case ECPGt_struct:
     484             :         case ECPGt_union:
     485          72 :             for (p = var->u.members; p; p = p->next)
     486          50 :                 check_indicator(p->type);
     487          22 :             break;
     488             : 
     489          22 :         case ECPGt_array:
     490          22 :             check_indicator(var->u.element);
     491          22 :             break;
     492           0 :         default:
     493           0 :             mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
     494           0 :             break;
     495             :     }
     496         134 : }
     497             : 
     498             : struct typedefs *
     499       11144 : get_typedef(const char *name, bool noerror)
     500             : {
     501             :     struct typedefs *this;
     502             : 
     503       17938 :     for (this = types; this != NULL; this = this->next)
     504             :     {
     505        6854 :         if (strcmp(this->name, name) == 0)
     506          60 :             return this;
     507             :     }
     508             : 
     509       11084 :     if (!noerror)
     510           0 :         mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
     511             : 
     512       11084 :     return NULL;
     513             : }
     514             : 
     515             : void
     516         748 : adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
     517             : {
     518         748 :     if (atoi(type_index) >= 0)
     519             :     {
     520          12 :         if (atoi(*length) >= 0)
     521           0 :             mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     522             : 
     523          12 :         *length = type_index;
     524             :     }
     525             : 
     526         748 :     if (atoi(type_dimension) >= 0)
     527             :     {
     528           2 :         if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
     529           0 :             mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     530             : 
     531           2 :         if (atoi(*dimension) >= 0)
     532           0 :             *length = *dimension;
     533             : 
     534           2 :         *dimension = type_dimension;
     535             :     }
     536             : 
     537         748 :     if (pointer_len > 2)
     538           0 :         mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
     539             :                                       "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
     540             :                 pointer_len);
     541             : 
     542         748 :     if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
     543           0 :         mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
     544             : 
     545         748 :     if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
     546           0 :         mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     547             : 
     548         748 :     if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
     549           0 :         mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     550             : 
     551         748 :     switch (type_enum)
     552             :     {
     553          68 :         case ECPGt_struct:
     554             :         case ECPGt_union:
     555             :             /* pointer has to get dimension 0 */
     556          68 :             if (pointer_len)
     557             :             {
     558          18 :                 *length = *dimension;
     559          18 :                 *dimension = mm_strdup("0");
     560             :             }
     561             : 
     562          68 :             if (atoi(*length) >= 0)
     563           0 :                 mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
     564             : 
     565          68 :             break;
     566          46 :         case ECPGt_varchar:
     567             :         case ECPGt_bytea:
     568             :             /* pointer has to get dimension 0 */
     569          46 :             if (pointer_len)
     570           0 :                 *dimension = mm_strdup("0");
     571             : 
     572             :             /* one index is the string length */
     573          46 :             if (atoi(*length) < 0)
     574             :             {
     575          30 :                 *length = *dimension;
     576          30 :                 *dimension = mm_strdup("-1");
     577             :             }
     578             : 
     579          46 :             break;
     580         238 :         case ECPGt_char:
     581             :         case ECPGt_unsigned_char:
     582             :         case ECPGt_string:
     583             :             /* char ** */
     584         238 :             if (pointer_len == 2)
     585             :             {
     586          16 :                 *length = *dimension = mm_strdup("0");
     587          16 :                 break;
     588             :             }
     589             : 
     590             :             /* pointer has to get length 0 */
     591         222 :             if (pointer_len == 1)
     592          72 :                 *length = mm_strdup("0");
     593             : 
     594             :             /* one index is the string length */
     595         222 :             if (atoi(*length) < 0)
     596             :             {
     597             :                 /*
     598             :                  * make sure we return length = -1 for arrays without given
     599             :                  * bounds
     600             :                  */
     601         130 :                 if (atoi(*dimension) < 0 && !type_definition)
     602             : 
     603             :                     /*
     604             :                      * do not change this for typedefs since it will be
     605             :                      * changed later on when the variable is defined
     606             :                      */
     607          10 :                     *length = mm_strdup("1");
     608         120 :                 else if (strcmp(*dimension, "0") == 0)
     609           4 :                     *length = mm_strdup("-1");
     610             :                 else
     611         116 :                     *length = *dimension;
     612             : 
     613         130 :                 *dimension = mm_strdup("-1");
     614             :             }
     615         222 :             break;
     616         396 :         default:
     617             :             /* a pointer has dimension = 0 */
     618         396 :             if (pointer_len)
     619             :             {
     620          40 :                 *length = *dimension;
     621          40 :                 *dimension = mm_strdup("0");
     622             :             }
     623             : 
     624         396 :             if (atoi(*length) >= 0)
     625           0 :                 mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
     626             : 
     627         396 :             break;
     628             :     }
     629         748 : }

Generated by: LCOV version 1.14