LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/preproc - variable.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 204 289 70.6 %
Date: 2024-11-21 09:14:53 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(const 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(const 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(const 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(const 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           0 :                     case '\0':
     220           0 :                         mmfatal(PARSE_ERROR, "unmatched brace in variable \"%s\"", name);
     221             :                         break;
     222         200 :                     default:
     223         200 :                         break;
     224             :                 }
     225             :             }
     226         200 :             if (*end == '.')
     227           0 :                 p = find_struct(name, next, end);
     228             :             else
     229             :             {
     230         200 :                 char        c = *next;
     231             : 
     232         200 :                 *next = '\0';
     233         200 :                 p = find_simple(name);
     234         200 :                 if (p == NULL)
     235           0 :                     mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
     236         200 :                 if (p->type->type != ECPGt_array)
     237           0 :                     mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
     238         200 :                 *next = c;
     239         200 :                 switch (p->type->u.element->type)
     240             :                 {
     241           0 :                     case ECPGt_array:
     242           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);
     243           6 :                     case ECPGt_struct:
     244             :                     case ECPGt_union:
     245           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);
     246         194 :                     default:
     247         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);
     248             :                 }
     249             :             }
     250             :         }
     251             :         else
     252          58 :             p = find_struct(name, next, next);
     253             :     }
     254             :     else
     255        2524 :         p = find_simple(name);
     256             : 
     257        2582 :     if (p == NULL)
     258           0 :         mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
     259             : 
     260        2582 :     return p;
     261             : }
     262             : 
     263             : void
     264         660 : remove_typedefs(int brace_level)
     265             : {
     266             :     struct typedefs *p,
     267             :                *prev;
     268             : 
     269         966 :     for (p = prev = types; p;)
     270             :     {
     271         306 :         if (p->brace_level >= brace_level)
     272             :         {
     273             :             /* remove it */
     274          26 :             if (p == types)
     275          26 :                 prev = types = p->next;
     276             :             else
     277           0 :                 prev->next = p->next;
     278             : 
     279          26 :             if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
     280          24 :                 free(p->struct_member_list);
     281          26 :             free(p->type);
     282          26 :             free(p->name);
     283          26 :             free(p);
     284          26 :             if (prev == types)
     285          26 :                 p = types;
     286             :             else
     287           0 :                 p = prev ? prev->next : NULL;
     288             :         }
     289             :         else
     290             :         {
     291         280 :             prev = p;
     292         280 :             p = prev->next;
     293             :         }
     294             :     }
     295         660 : }
     296             : 
     297             : void
     298         660 : remove_variables(int brace_level)
     299             : {
     300             :     struct variable *p,
     301             :                *prev;
     302             : 
     303        3116 :     for (p = prev = allvariables; p;)
     304             :     {
     305        2456 :         if (p->brace_level >= brace_level)
     306             :         {
     307             :             /* is it still referenced by a cursor? */
     308             :             struct cursor *ptr;
     309             : 
     310        1506 :             for (ptr = cur; ptr != NULL; ptr = ptr->next)
     311             :             {
     312             :                 struct arguments *varptr,
     313             :                            *prevvar;
     314             : 
     315        1236 :                 for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
     316             :                 {
     317         514 :                     if (p == varptr->variable)
     318             :                     {
     319             :                         /* remove from list */
     320          20 :                         if (varptr == ptr->argsinsert)
     321          14 :                             ptr->argsinsert = varptr->next;
     322             :                         else
     323           6 :                             prevvar->next = varptr->next;
     324             :                     }
     325             :                 }
     326         732 :                 for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
     327             :                 {
     328          10 :                     if (p == varptr->variable)
     329             :                     {
     330             :                         /* remove from list */
     331           6 :                         if (varptr == ptr->argsresult)
     332           6 :                             ptr->argsresult = varptr->next;
     333             :                         else
     334           0 :                             prevvar->next = varptr->next;
     335             :                     }
     336             :                 }
     337             :             }
     338             : 
     339             :             /* remove it */
     340         784 :             if (p == allvariables)
     341         462 :                 prev = allvariables = p->next;
     342             :             else
     343         322 :                 prev->next = p->next;
     344             : 
     345         784 :             ECPGfree_type(p->type);
     346         784 :             free(p->name);
     347         784 :             free(p);
     348         784 :             if (prev == allvariables)
     349         518 :                 p = allvariables;
     350             :             else
     351         266 :                 p = prev ? prev->next : NULL;
     352             :         }
     353             :         else
     354             :         {
     355        1672 :             prev = p;
     356        1672 :             p = prev->next;
     357             :         }
     358             :     }
     359         660 : }
     360             : 
     361             : 
     362             : /*
     363             :  * Here are the variables that need to be handled on every request.
     364             :  * These are of two kinds: input and output.
     365             :  * I will make two lists for them.
     366             :  */
     367             : 
     368             : struct arguments *argsinsert = NULL;
     369             : struct arguments *argsresult = NULL;
     370             : 
     371             : void
     372        3974 : reset_variables(void)
     373             : {
     374        3974 :     argsinsert = NULL;
     375        3974 :     argsresult = NULL;
     376        3974 : }
     377             : 
     378             : /* Insert a new variable into our request list.
     379             :  * Note: The list is dumped from the end,
     380             :  * so we have to add new entries at the beginning */
     381             : void
     382        1010 : add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
     383             : {
     384        1010 :     struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
     385             : 
     386        1010 :     p->variable = var;
     387        1010 :     p->indicator = ind;
     388        1010 :     p->next = *list;
     389        1010 :     *list = p;
     390        1010 : }
     391             : 
     392             : /* Append a new variable to our request list. */
     393             : void
     394         190 : add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
     395             : {
     396             :     struct arguments *p,
     397         190 :                *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
     398             : 
     399         204 :     for (p = *list; p && p->next; p = p->next);
     400             : 
     401         190 :     new->variable = var;
     402         190 :     new->indicator = ind;
     403         190 :     new->next = NULL;
     404             : 
     405         190 :     if (p)
     406          52 :         p->next = new;
     407             :     else
     408         138 :         *list = new;
     409         190 : }
     410             : 
     411             : void
     412          34 : remove_variable_from_list(struct arguments **list, struct variable *var)
     413             : {
     414             :     struct arguments *p,
     415          34 :                *prev = NULL;
     416          34 :     bool        found = false;
     417             : 
     418          34 :     for (p = *list; p; p = p->next)
     419             :     {
     420          34 :         if (p->variable == var)
     421             :         {
     422          34 :             found = true;
     423          34 :             break;
     424             :         }
     425           0 :         prev = p;
     426             :     }
     427          34 :     if (found)
     428             :     {
     429          34 :         if (prev)
     430           0 :             prev->next = p->next;
     431             :         else
     432          34 :             *list = p->next;
     433             :     }
     434          34 : }
     435             : 
     436             : /* Dump out a list of all the variable on this list.
     437             :    This is a recursive function that works from the end of the list and
     438             :    deletes the list as we go on.
     439             :  */
     440             : void
     441        3284 : dump_variables(struct arguments *list, int mode)
     442             : {
     443             :     char       *str_zero;
     444             : 
     445        3284 :     if (list == NULL)
     446        2254 :         return;
     447             : 
     448        1030 :     str_zero = mm_strdup("0");
     449             : 
     450             :     /*
     451             :      * The list is build up from the beginning so lets first dump the end of
     452             :      * the list:
     453             :      */
     454             : 
     455        1030 :     dump_variables(list->next, mode);
     456             : 
     457             :     /* Then the current element and its indicator */
     458        1030 :     ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
     459        1030 :                     list->indicator->name, list->indicator->type, list->indicator->brace_level,
     460             :                     NULL, NULL, str_zero, NULL, NULL);
     461             : 
     462             :     /* Then release the list element. */
     463        1030 :     if (mode != 0)
     464        1030 :         free(list);
     465             : 
     466        1030 :     free(str_zero);
     467             : }
     468             : 
     469             : void
     470         134 : check_indicator(struct ECPGtype *var)
     471             : {
     472             :     /* make sure this is a valid indicator variable */
     473         134 :     switch (var->type)
     474             :     {
     475             :             struct ECPGstruct_member *p;
     476             : 
     477          90 :         case ECPGt_short:
     478             :         case ECPGt_int:
     479             :         case ECPGt_long:
     480             :         case ECPGt_long_long:
     481             :         case ECPGt_unsigned_short:
     482             :         case ECPGt_unsigned_int:
     483             :         case ECPGt_unsigned_long:
     484             :         case ECPGt_unsigned_long_long:
     485          90 :             break;
     486             : 
     487          22 :         case ECPGt_struct:
     488             :         case ECPGt_union:
     489          72 :             for (p = var->u.members; p; p = p->next)
     490          50 :                 check_indicator(p->type);
     491          22 :             break;
     492             : 
     493          22 :         case ECPGt_array:
     494          22 :             check_indicator(var->u.element);
     495          22 :             break;
     496           0 :         default:
     497           0 :             mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
     498           0 :             break;
     499             :     }
     500         134 : }
     501             : 
     502             : struct typedefs *
     503       11144 : get_typedef(const char *name, bool noerror)
     504             : {
     505             :     struct typedefs *this;
     506             : 
     507       17938 :     for (this = types; this != NULL; this = this->next)
     508             :     {
     509        6854 :         if (strcmp(this->name, name) == 0)
     510          60 :             return this;
     511             :     }
     512             : 
     513       11084 :     if (!noerror)
     514           0 :         mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
     515             : 
     516       11084 :     return NULL;
     517             : }
     518             : 
     519             : void
     520         748 : adjust_array(enum ECPGttype type_enum,
     521             :              const char **dimension, const char **length,
     522             :              const char *type_dimension, const char *type_index,
     523             :              int pointer_len, bool type_definition)
     524             : {
     525         748 :     if (atoi(type_index) >= 0)
     526             :     {
     527          12 :         if (atoi(*length) >= 0)
     528           0 :             mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     529             : 
     530          12 :         *length = type_index;
     531             :     }
     532             : 
     533         748 :     if (atoi(type_dimension) >= 0)
     534             :     {
     535           2 :         if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
     536           0 :             mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     537             : 
     538           2 :         if (atoi(*dimension) >= 0)
     539           0 :             *length = *dimension;
     540             : 
     541           2 :         *dimension = type_dimension;
     542             :     }
     543             : 
     544         748 :     if (pointer_len > 2)
     545           0 :         mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
     546             :                                       "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
     547             :                 pointer_len);
     548             : 
     549         748 :     if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
     550           0 :         mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
     551             : 
     552         748 :     if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
     553           0 :         mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     554             : 
     555         748 :     if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
     556           0 :         mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
     557             : 
     558         748 :     switch (type_enum)
     559             :     {
     560          68 :         case ECPGt_struct:
     561             :         case ECPGt_union:
     562             :             /* pointer has to get dimension 0 */
     563          68 :             if (pointer_len)
     564             :             {
     565          18 :                 *length = *dimension;
     566          18 :                 *dimension = "0";
     567             :             }
     568             : 
     569          68 :             if (atoi(*length) >= 0)
     570           0 :                 mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
     571             : 
     572          68 :             break;
     573          46 :         case ECPGt_varchar:
     574             :         case ECPGt_bytea:
     575             :             /* pointer has to get dimension 0 */
     576          46 :             if (pointer_len)
     577           0 :                 *dimension = "0";
     578             : 
     579             :             /* one index is the string length */
     580          46 :             if (atoi(*length) < 0)
     581             :             {
     582          30 :                 *length = *dimension;
     583          30 :                 *dimension = "-1";
     584             :             }
     585             : 
     586          46 :             break;
     587         238 :         case ECPGt_char:
     588             :         case ECPGt_unsigned_char:
     589             :         case ECPGt_string:
     590             :             /* char ** */
     591         238 :             if (pointer_len == 2)
     592             :             {
     593          16 :                 *length = *dimension = "0";
     594          16 :                 break;
     595             :             }
     596             : 
     597             :             /* pointer has to get length 0 */
     598         222 :             if (pointer_len == 1)
     599          72 :                 *length = "0";
     600             : 
     601             :             /* one index is the string length */
     602         222 :             if (atoi(*length) < 0)
     603             :             {
     604             :                 /*
     605             :                  * make sure we return length = -1 for arrays without given
     606             :                  * bounds
     607             :                  */
     608         130 :                 if (atoi(*dimension) < 0 && !type_definition)
     609             : 
     610             :                     /*
     611             :                      * do not change this for typedefs since it will be
     612             :                      * changed later on when the variable is defined
     613             :                      */
     614          10 :                     *length = "1";
     615         120 :                 else if (strcmp(*dimension, "0") == 0)
     616           4 :                     *length = "-1";
     617             :                 else
     618         116 :                     *length = *dimension;
     619             : 
     620         130 :                 *dimension = "-1";
     621             :             }
     622         222 :             break;
     623         396 :         default:
     624             :             /* a pointer has dimension = 0 */
     625         396 :             if (pointer_len)
     626             :             {
     627          40 :                 *length = *dimension;
     628          40 :                 *dimension = "0";
     629             :             }
     630             : 
     631         396 :             if (atoi(*length) >= 0)
     632           0 :                 mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
     633             : 
     634         396 :             break;
     635             :     }
     636         748 : }

Generated by: LCOV version 1.14