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

Generated by: LCOV version 1.13