2010-09-20 22:08:53 +02:00
|
|
|
/* src/interfaces/ecpg/preproc/variable.c */
|
2006-07-30 12:24:10 +02:00
|
|
|
|
2001-02-10 03:31:31 +01:00
|
|
|
#include "postgres_fe.h"
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2018-12-01 22:34:00 +01:00
|
|
|
#include "preproc_extern.h"
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2007-12-21 15:33:20 +01:00
|
|
|
static struct variable *allvariables = NULL;
|
2000-02-17 20:48:58 +01:00
|
|
|
|
|
|
|
struct variable *
|
2002-01-13 09:52:09 +01:00
|
|
|
new_variable(const char *name, struct ECPGtype *type, int brace_level)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
|
|
|
|
|
|
|
|
p->name = mm_strdup(name);
|
|
|
|
p->type = type;
|
2002-01-13 09:52:09 +01:00
|
|
|
p->brace_level = brace_level;
|
2000-02-17 20:48:58 +01:00
|
|
|
|
|
|
|
p->next = allvariables;
|
|
|
|
allvariables = p;
|
|
|
|
|
2017-08-17 18:39:20 +02:00
|
|
|
return p;
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct variable *
|
2010-04-01 12:30:53 +02:00
|
|
|
find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int brace_level)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
2003-05-29 15:59:26 +02:00
|
|
|
char *next = strpbrk(++str, ".-["),
|
|
|
|
*end,
|
|
|
|
c = '\0';
|
2000-02-17 20:48:58 +01:00
|
|
|
|
|
|
|
if (next != NULL)
|
|
|
|
{
|
|
|
|
c = *next;
|
|
|
|
*next = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; members; members = members->next)
|
|
|
|
{
|
|
|
|
if (strcmp(members->name, str) == 0)
|
|
|
|
{
|
2003-05-29 15:59:26 +02:00
|
|
|
if (next == NULL)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
/* found the end */
|
2001-12-23 13:17:41 +01:00
|
|
|
switch (members->type->type)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-02-17 20:48:58 +01:00
|
|
|
case ECPGt_array:
|
2017-08-17 18:39:20 +02:00
|
|
|
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);
|
2000-02-17 20:48:58 +01:00
|
|
|
case ECPGt_struct:
|
|
|
|
case ECPGt_union:
|
2017-08-17 18:39:20 +02:00
|
|
|
return new_variable(name, ECPGmake_struct_type(members->type->u.members, members->type->type, members->type->type_name, members->type->struct_sizeof), brace_level);
|
2000-02-17 20:48:58 +01:00
|
|
|
default:
|
2017-08-17 18:39:20 +02:00
|
|
|
return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*next = c;
|
2003-05-29 15:59:26 +02:00
|
|
|
if (c == '[')
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2003-05-29 15:59:26 +02:00
|
|
|
int count;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't care about what's inside the array braces so
|
|
|
|
* just eat up the character
|
|
|
|
*/
|
|
|
|
for (count = 1, end = next + 1; count; end++)
|
|
|
|
{
|
|
|
|
switch (*end)
|
|
|
|
{
|
|
|
|
case '[':
|
|
|
|
count++;
|
|
|
|
break;
|
|
|
|
case ']':
|
|
|
|
count--;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
end = next;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-05-29 15:59:26 +02:00
|
|
|
switch (*end)
|
|
|
|
{
|
|
|
|
case '\0': /* found the end, but this time it has to be
|
|
|
|
* an array element */
|
|
|
|
if (members->type->type != ECPGt_array)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-05-29 15:59:26 +02:00
|
|
|
switch (members->type->u.element->type)
|
2003-08-04 02:43:34 +02:00
|
|
|
{
|
2003-05-29 15:59:26 +02:00
|
|
|
case ECPGt_array:
|
2017-08-17 18:39:20 +02:00
|
|
|
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);
|
2003-05-29 15:59:26 +02:00
|
|
|
case ECPGt_struct:
|
|
|
|
case ECPGt_union:
|
2017-08-17 18:39:20 +02:00
|
|
|
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);
|
2003-08-04 02:43:34 +02:00
|
|
|
default:
|
2017-08-17 18:39:20 +02:00
|
|
|
return new_variable(name, ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), brace_level);
|
2003-08-04 02:43:34 +02:00
|
|
|
}
|
2003-05-29 15:59:26 +02:00
|
|
|
break;
|
|
|
|
case '-':
|
2012-11-29 17:12:00 +01:00
|
|
|
if (members->type->type == ECPGt_array)
|
2017-08-17 18:39:20 +02:00
|
|
|
return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
|
2012-11-29 17:12:00 +01:00
|
|
|
else
|
2017-08-17 18:39:20 +02:00
|
|
|
return find_struct_member(name, ++end, members->type->u.members, brace_level);
|
2012-11-29 17:12:00 +01:00
|
|
|
break;
|
2003-05-29 15:59:26 +02:00
|
|
|
case '.':
|
2004-01-28 10:52:14 +01:00
|
|
|
if (members->type->type == ECPGt_array)
|
2017-08-17 18:39:20 +02:00
|
|
|
return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
|
2003-08-04 02:43:34 +02:00
|
|
|
else
|
2017-08-17 18:39:20 +02:00
|
|
|
return find_struct_member(name, end, members->type->u.members, brace_level);
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
|
|
|
default:
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-17 18:39:20 +02:00
|
|
|
return NULL;
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct variable *
|
2003-05-29 14:00:22 +02:00
|
|
|
find_struct(char *name, char *next, char *end)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
struct variable *p;
|
|
|
|
char c = *next;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* first get the mother structure entry */
|
|
|
|
*next = '\0';
|
|
|
|
p = find_variable(name);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
if (c == '-')
|
|
|
|
{
|
2001-12-23 13:17:41 +01:00
|
|
|
if (p->type->type != ECPGt_array)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2001-12-23 13:17:41 +01:00
|
|
|
if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-05-29 14:00:22 +02:00
|
|
|
/* restore the name, we will need it later */
|
2000-02-17 20:48:58 +01:00
|
|
|
*next = c;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-06-11 08:39:13 +02:00
|
|
|
return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
else
|
|
|
|
{
|
2003-05-29 14:00:22 +02:00
|
|
|
if (next == end)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2003-05-29 14:00:22 +02:00
|
|
|
if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", name);
|
2003-05-29 14:00:22 +02:00
|
|
|
|
|
|
|
/* restore the name, we will need it later */
|
|
|
|
*next = c;
|
|
|
|
|
|
|
|
return find_struct_member(name, end, p->type->u.members, p->brace_level);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
2003-05-29 14:00:22 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (p->type->type != ECPGt_array)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", name);
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2003-05-29 14:00:22 +02:00
|
|
|
if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
|
2003-05-29 14:00:22 +02:00
|
|
|
|
|
|
|
/* restore the name, we will need it later */
|
|
|
|
*next = c;
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2003-05-29 14:00:22 +02:00
|
|
|
return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
|
|
|
|
}
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct variable *
|
|
|
|
find_simple(char *name)
|
|
|
|
{
|
|
|
|
struct variable *p;
|
|
|
|
|
|
|
|
for (p = allvariables; p; p = p->next)
|
|
|
|
{
|
|
|
|
if (strcmp(p->name, name) == 0)
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2017-08-17 18:39:20 +02:00
|
|
|
return NULL;
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Note that this function will end the program in case of an unknown */
|
|
|
|
/* variable */
|
|
|
|
struct variable *
|
|
|
|
find_variable(char *name)
|
|
|
|
{
|
2003-05-29 14:00:22 +02:00
|
|
|
char *next,
|
|
|
|
*end;
|
2000-02-17 20:48:58 +01:00
|
|
|
struct variable *p;
|
2003-05-29 14:00:22 +02:00
|
|
|
int count;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-05-29 14:00:22 +02:00
|
|
|
next = strpbrk(name, ".[-");
|
|
|
|
if (next)
|
|
|
|
{
|
|
|
|
if (*next == '[')
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We don't care about what's inside the array braces so just eat
|
2004-03-04 08:32:02 +01:00
|
|
|
* up the characters
|
2003-05-29 14:00:22 +02:00
|
|
|
*/
|
|
|
|
for (count = 1, end = next + 1; count; end++)
|
|
|
|
{
|
|
|
|
switch (*end)
|
|
|
|
{
|
|
|
|
case '[':
|
|
|
|
count++;
|
|
|
|
break;
|
|
|
|
case ']':
|
|
|
|
count--;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*end == '.')
|
|
|
|
p = find_struct(name, next, end);
|
|
|
|
else
|
|
|
|
{
|
2003-05-29 15:59:26 +02:00
|
|
|
char c = *next;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-05-29 15:59:26 +02:00
|
|
|
*next = '\0';
|
|
|
|
p = find_simple(name);
|
2004-03-04 08:32:02 +01:00
|
|
|
if (p == NULL)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
|
2004-06-30 17:01:58 +02:00
|
|
|
|
2003-05-29 15:59:26 +02:00
|
|
|
*next = c;
|
|
|
|
switch (p->type->u.element->type)
|
|
|
|
{
|
|
|
|
case ECPGt_array:
|
2017-08-17 18:39:20 +02:00
|
|
|
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);
|
2003-05-29 15:59:26 +02:00
|
|
|
case ECPGt_struct:
|
|
|
|
case ECPGt_union:
|
2017-08-17 18:39:20 +02:00
|
|
|
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);
|
2003-05-29 15:59:26 +02:00
|
|
|
default:
|
2017-08-17 18:39:20 +02:00
|
|
|
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);
|
2003-05-29 15:59:26 +02:00
|
|
|
}
|
2003-05-29 14:00:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
p = find_struct(name, next, next);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
p = find_simple(name);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
if (p == NULL)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2017-08-17 18:39:20 +02:00
|
|
|
return p;
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
|
2004-06-27 14:28:42 +02:00
|
|
|
void
|
|
|
|
remove_typedefs(int brace_level)
|
|
|
|
{
|
|
|
|
struct typedefs *p,
|
|
|
|
*prev;
|
|
|
|
|
|
|
|
for (p = prev = types; p;)
|
|
|
|
{
|
|
|
|
if (p->brace_level >= brace_level)
|
|
|
|
{
|
|
|
|
/* remove it */
|
|
|
|
if (p == types)
|
|
|
|
prev = types = p->next;
|
|
|
|
else
|
|
|
|
prev->next = p->next;
|
|
|
|
|
|
|
|
if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
|
|
|
|
free(p->struct_member_list);
|
|
|
|
free(p->type);
|
|
|
|
free(p->name);
|
|
|
|
free(p);
|
|
|
|
if (prev == types)
|
|
|
|
p = types;
|
|
|
|
else
|
|
|
|
p = prev ? prev->next : NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prev = p;
|
|
|
|
p = prev->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
void
|
|
|
|
remove_variables(int brace_level)
|
|
|
|
{
|
|
|
|
struct variable *p,
|
|
|
|
*prev;
|
|
|
|
|
2004-06-27 14:28:42 +02:00
|
|
|
for (p = prev = allvariables; p;)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
if (p->brace_level >= brace_level)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2003-06-11 08:39:13 +02:00
|
|
|
/* is it still referenced by a cursor? */
|
|
|
|
struct cursor *ptr;
|
|
|
|
|
|
|
|
for (ptr = cur; ptr != NULL; ptr = ptr->next)
|
|
|
|
{
|
|
|
|
struct arguments *varptr,
|
|
|
|
*prevvar;
|
|
|
|
|
|
|
|
for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
|
|
|
|
{
|
|
|
|
if (p == varptr->variable)
|
|
|
|
{
|
|
|
|
/* remove from list */
|
|
|
|
if (varptr == ptr->argsinsert)
|
|
|
|
ptr->argsinsert = varptr->next;
|
|
|
|
else
|
|
|
|
prevvar->next = varptr->next;
|
|
|
|
}
|
|
|
|
}
|
2003-12-17 16:23:45 +01:00
|
|
|
for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
|
2003-06-11 08:39:13 +02:00
|
|
|
{
|
|
|
|
if (p == varptr->variable)
|
|
|
|
{
|
|
|
|
/* remove from list */
|
|
|
|
if (varptr == ptr->argsresult)
|
|
|
|
ptr->argsresult = varptr->next;
|
|
|
|
else
|
|
|
|
prevvar->next = varptr->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* remove it */
|
|
|
|
if (p == allvariables)
|
|
|
|
prev = allvariables = p->next;
|
|
|
|
else
|
|
|
|
prev->next = p->next;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
ECPGfree_type(p->type);
|
|
|
|
free(p->name);
|
|
|
|
free(p);
|
2004-06-27 14:28:42 +02:00
|
|
|
if (prev == allvariables)
|
|
|
|
p = allvariables;
|
|
|
|
else
|
|
|
|
p = prev ? prev->next : NULL;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
2004-06-27 14:28:42 +02:00
|
|
|
{
|
2000-02-17 20:48:58 +01:00
|
|
|
prev = p;
|
2004-06-27 14:28:42 +02:00
|
|
|
p = prev->next;
|
|
|
|
}
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Here are the variables that need to be handled on every request.
|
|
|
|
* These are of two kinds: input and output.
|
|
|
|
* I will make two lists for them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct arguments *argsinsert = NULL;
|
|
|
|
struct arguments *argsresult = NULL;
|
|
|
|
|
|
|
|
void
|
|
|
|
reset_variables(void)
|
|
|
|
{
|
|
|
|
argsinsert = NULL;
|
|
|
|
argsresult = NULL;
|
|
|
|
}
|
|
|
|
|
2003-09-22 15:19:39 +02:00
|
|
|
/* Insert a new variable into our request list.
|
|
|
|
* Note: The list is dumped from the end,
|
|
|
|
* so we have to add new entries at the beginning */
|
2000-02-17 20:48:58 +01:00
|
|
|
void
|
2003-12-17 16:23:45 +01:00
|
|
|
add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
2000-03-09 10:17:16 +01:00
|
|
|
struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
p->variable = var;
|
|
|
|
p->indicator = ind;
|
|
|
|
p->next = *list;
|
|
|
|
*list = p;
|
|
|
|
}
|
|
|
|
|
2000-03-09 10:17:16 +01:00
|
|
|
/* Append a new variable to our request list. */
|
|
|
|
void
|
2003-12-17 16:23:45 +01:00
|
|
|
add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
|
2000-03-09 10:17:16 +01:00
|
|
|
{
|
|
|
|
struct arguments *p,
|
|
|
|
*new = (struct arguments *) mm_alloc(sizeof(struct arguments));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-03-09 10:17:16 +01:00
|
|
|
for (p = *list; p && p->next; p = p->next);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-03-09 10:17:16 +01:00
|
|
|
new->variable = var;
|
|
|
|
new->indicator = ind;
|
|
|
|
new->next = NULL;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-03-09 10:17:16 +01:00
|
|
|
if (p)
|
|
|
|
p->next = new;
|
|
|
|
else
|
|
|
|
*list = new;
|
|
|
|
}
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2009-11-26 16:06:47 +01:00
|
|
|
void
|
|
|
|
remove_variable_from_list(struct arguments **list, struct variable *var)
|
|
|
|
{
|
|
|
|
struct arguments *p,
|
|
|
|
*prev = NULL;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
for (p = *list; p; p = p->next)
|
|
|
|
{
|
|
|
|
if (p->variable == var)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = p;
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
if (prev)
|
|
|
|
prev->next = p->next;
|
|
|
|
else
|
|
|
|
*list = p->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* Dump out a list of all the variable on this list.
|
|
|
|
This is a recursive function that works from the end of the list and
|
|
|
|
deletes the list as we go on.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dump_variables(struct arguments *list, int mode)
|
|
|
|
{
|
2015-06-12 14:52:55 +02:00
|
|
|
char *str_zero;
|
2014-05-06 18:12:18 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
if (list == NULL)
|
|
|
|
return;
|
|
|
|
|
2015-06-12 14:52:55 +02:00
|
|
|
str_zero = mm_strdup("0");
|
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/*
|
|
|
|
* The list is build up from the beginning so lets first dump the end of
|
|
|
|
* the list:
|
|
|
|
*/
|
|
|
|
|
|
|
|
dump_variables(list->next, mode);
|
|
|
|
|
|
|
|
/* Then the current element and its indicator */
|
2016-12-11 20:54:25 +01:00
|
|
|
ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
|
2010-04-01 12:30:53 +02:00
|
|
|
list->indicator->name, list->indicator->type, list->indicator->brace_level,
|
2014-03-02 04:14:14 +01:00
|
|
|
NULL, NULL, str_zero, NULL, NULL);
|
2000-02-17 20:48:58 +01:00
|
|
|
|
|
|
|
/* Then release the list element. */
|
|
|
|
if (mode != 0)
|
|
|
|
free(list);
|
2014-03-03 20:05:33 +01:00
|
|
|
|
2014-03-02 04:14:14 +01:00
|
|
|
free(str_zero);
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
check_indicator(struct ECPGtype *var)
|
|
|
|
{
|
|
|
|
/* make sure this is a valid indicator variable */
|
2001-12-23 13:17:41 +01:00
|
|
|
switch (var->type)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
struct ECPGstruct_member *p;
|
|
|
|
|
|
|
|
case ECPGt_short:
|
|
|
|
case ECPGt_int:
|
|
|
|
case ECPGt_long:
|
2000-09-19 13:47:16 +02:00
|
|
|
case ECPGt_long_long:
|
2000-02-17 20:48:58 +01:00
|
|
|
case ECPGt_unsigned_short:
|
|
|
|
case ECPGt_unsigned_int:
|
|
|
|
case ECPGt_unsigned_long:
|
2000-09-19 13:47:16 +02:00
|
|
|
case ECPGt_unsigned_long_long:
|
2000-02-17 20:48:58 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ECPGt_struct:
|
|
|
|
case ECPGt_union:
|
|
|
|
for (p = var->u.members; p; p = p->next)
|
2001-12-23 13:17:41 +01:00
|
|
|
check_indicator(p->type);
|
2000-02-17 20:48:58 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ECPGt_array:
|
|
|
|
check_indicator(var->u.element);
|
|
|
|
break;
|
|
|
|
default:
|
2009-01-23 13:43:32 +01:00
|
|
|
mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
|
2000-02-17 20:48:58 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct typedefs *
|
Fix ECPG's handling of type names that match SQL keywords.
Previously, ECPG could only cope with variable declarations whose
type names either weren't any SQL keyword, or were at least partially
reserved. If you tried to use something in the unreserved_keyword
category, you got a syntax error.
This is pretty awful, not only because it says right on the tin that
those words are not reserved, but because the set of such keywords
tends to grow over time. Thus, an ECPG program that was just fine
last year could fail when recompiled with a newer SQL grammar.
We had to work around this recently when STRING became a keyword,
but it's time for an actual fix instead of a band-aid.
To fix, borrow a trick from C parsers and make the lexer's behavior
change when it sees a word that is known as a typedef. This is not
free of downsides: if you try to use such a name as a SQL keyword
in EXEC SQL later in the program, it won't be recognized as a SQL
keyword, leading to a syntax error there instead. So in a real
sense this is just trading one hazard for another. But there is an
important difference: with this, whether your ECPG program works
depends only on what typedef names and SQL commands are used in the
program text. If it compiles today it'll still compile next year,
even if more words have become SQL keywords.
Discussion: https://postgr.es/m/3661437.1653855582@sss.pgh.pa.us
2022-07-12 23:05:46 +02:00
|
|
|
get_typedef(const char *name, bool noerror)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
struct typedefs *this;
|
|
|
|
|
Fix ECPG's handling of type names that match SQL keywords.
Previously, ECPG could only cope with variable declarations whose
type names either weren't any SQL keyword, or were at least partially
reserved. If you tried to use something in the unreserved_keyword
category, you got a syntax error.
This is pretty awful, not only because it says right on the tin that
those words are not reserved, but because the set of such keywords
tends to grow over time. Thus, an ECPG program that was just fine
last year could fail when recompiled with a newer SQL grammar.
We had to work around this recently when STRING became a keyword,
but it's time for an actual fix instead of a band-aid.
To fix, borrow a trick from C parsers and make the lexer's behavior
change when it sees a word that is known as a typedef. This is not
free of downsides: if you try to use such a name as a SQL keyword
in EXEC SQL later in the program, it won't be recognized as a SQL
keyword, leading to a syntax error there instead. So in a real
sense this is just trading one hazard for another. But there is an
important difference: with this, whether your ECPG program works
depends only on what typedef names and SQL commands are used in the
program text. If it compiles today it'll still compile next year,
even if more words have become SQL keywords.
Discussion: https://postgr.es/m/3661437.1653855582@sss.pgh.pa.us
2022-07-12 23:05:46 +02:00
|
|
|
for (this = types; this != NULL; this = this->next)
|
|
|
|
{
|
|
|
|
if (strcmp(this->name, name) == 0)
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!noerror)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
|
2000-02-17 20:48:58 +01:00
|
|
|
|
Fix ECPG's handling of type names that match SQL keywords.
Previously, ECPG could only cope with variable declarations whose
type names either weren't any SQL keyword, or were at least partially
reserved. If you tried to use something in the unreserved_keyword
category, you got a syntax error.
This is pretty awful, not only because it says right on the tin that
those words are not reserved, but because the set of such keywords
tends to grow over time. Thus, an ECPG program that was just fine
last year could fail when recompiled with a newer SQL grammar.
We had to work around this recently when STRING became a keyword,
but it's time for an actual fix instead of a band-aid.
To fix, borrow a trick from C parsers and make the lexer's behavior
change when it sees a word that is known as a typedef. This is not
free of downsides: if you try to use such a name as a SQL keyword
in EXEC SQL later in the program, it won't be recognized as a SQL
keyword, leading to a syntax error there instead. So in a real
sense this is just trading one hazard for another. But there is an
important difference: with this, whether your ECPG program works
depends only on what typedef names and SQL commands are used in the
program text. If it compiles today it'll still compile next year,
even if more words have become SQL keywords.
Discussion: https://postgr.es/m/3661437.1653855582@sss.pgh.pa.us
2022-07-12 23:05:46 +02:00
|
|
|
return NULL;
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-05-07 15:42:49 +02:00
|
|
|
adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(type_index) >= 0)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*length) >= 0)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
|
2000-02-17 20:48:58 +01:00
|
|
|
|
|
|
|
*length = type_index;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(type_dimension) >= 0)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*dimension) >= 0)
|
2000-02-17 20:48:58 +01:00
|
|
|
*length = *dimension;
|
|
|
|
|
|
|
|
*dimension = type_dimension;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2001-11-16 09:36:37 +01:00
|
|
|
if (pointer_len > 2)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
|
2009-03-26 23:26:08 +01:00
|
|
|
"multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
|
|
|
|
pointer_len);
|
2003-05-29 14:00:22 +02:00
|
|
|
|
2009-08-07 12:51:21 +02:00
|
|
|
if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
|
2001-11-16 09:36:37 +01:00
|
|
|
|
2003-05-14 16:37:36 +02:00
|
|
|
if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
|
2000-02-17 20:48:58 +01:00
|
|
|
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
|
2000-02-17 20:48:58 +01:00
|
|
|
|
|
|
|
switch (type_enum)
|
|
|
|
{
|
|
|
|
case ECPGt_struct:
|
|
|
|
case ECPGt_union:
|
|
|
|
/* pointer has to get dimension 0 */
|
2001-11-16 09:36:37 +01:00
|
|
|
if (pointer_len)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
*length = *dimension;
|
2011-01-09 02:45:56 +01:00
|
|
|
*dimension = mm_strdup("0");
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*length) >= 0)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
break;
|
|
|
|
case ECPGt_varchar:
|
2019-02-18 10:20:31 +01:00
|
|
|
case ECPGt_bytea:
|
2000-02-17 20:48:58 +01:00
|
|
|
/* pointer has to get dimension 0 */
|
2001-11-16 09:36:37 +01:00
|
|
|
if (pointer_len)
|
2011-01-09 02:45:56 +01:00
|
|
|
*dimension = mm_strdup("0");
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* one index is the string length */
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*length) < 0)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
*length = *dimension;
|
2011-01-09 02:45:56 +01:00
|
|
|
*dimension = mm_strdup("-1");
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
break;
|
|
|
|
case ECPGt_char:
|
|
|
|
case ECPGt_unsigned_char:
|
2009-08-07 12:51:21 +02:00
|
|
|
case ECPGt_string:
|
2001-11-16 09:36:37 +01:00
|
|
|
/* char ** */
|
|
|
|
if (pointer_len == 2)
|
|
|
|
{
|
2011-01-09 02:45:56 +01:00
|
|
|
*length = *dimension = mm_strdup("0");
|
2001-11-16 09:36:37 +01:00
|
|
|
break;
|
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* pointer has to get length 0 */
|
2001-11-16 09:36:37 +01:00
|
|
|
if (pointer_len == 1)
|
2011-01-09 02:45:56 +01:00
|
|
|
*length = mm_strdup("0");
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* one index is the string length */
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*length) < 0)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
2003-07-07 14:15:33 +02:00
|
|
|
/*
|
|
|
|
* make sure we return length = -1 for arrays without given
|
|
|
|
* bounds
|
|
|
|
*/
|
2004-05-07 15:42:49 +02:00
|
|
|
if (atoi(*dimension) < 0 && !type_definition)
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-05-07 15:42:49 +02:00
|
|
|
/*
|
|
|
|
* do not change this for typedefs since it will be
|
|
|
|
* changed later on when the variable is defined
|
|
|
|
*/
|
2011-01-09 02:45:56 +01:00
|
|
|
*length = mm_strdup("1");
|
2004-12-06 21:35:35 +01:00
|
|
|
else if (strcmp(*dimension, "0") == 0)
|
2011-01-09 02:45:56 +01:00
|
|
|
*length = mm_strdup("-1");
|
2003-07-07 14:15:33 +02:00
|
|
|
else
|
|
|
|
*length = *dimension;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2011-01-09 02:45:56 +01:00
|
|
|
*dimension = mm_strdup("-1");
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* a pointer has dimension = 0 */
|
2001-11-16 09:36:37 +01:00
|
|
|
if (pointer_len)
|
2000-02-17 20:48:58 +01:00
|
|
|
{
|
|
|
|
*length = *dimension;
|
2011-01-09 02:45:56 +01:00
|
|
|
*dimension = mm_strdup("0");
|
2000-02-17 20:48:58 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-05-14 16:37:36 +02:00
|
|
|
if (atoi(*length) >= 0)
|
2013-11-13 04:12:08 +01:00
|
|
|
mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|