|
|
|
|
Quelle ecpg.trailer
Sprache: unbekannt
|
|
Spracherkennung für: .trailer vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
/* src/interfaces/ecpg/preproc/ecpg.trailer */
statements: /* EMPTY */
| statements statement
{
/* Reclaim local storage used while processing statement */
reclaim_local_storage();
/* Clean up now-dangling location pointer */
@$ = "";
}
;
statement: ecpgstart at toplevel_stmt ';'
{
if (connection)
free(connection);
connection = NULL;
}
| ecpgstart toplevel_stmt ';'
{
if (connection)
free(connection);
connection = NULL;
}
| ecpgstart ECPGVarDeclaration
{
fprintf(base_yyout, "%s", @$);
output_line_number();
}
| ECPGDeclaration
| c_thing
{
fprintf(base_yyout, "%s", @$);
}
| CPP_LINE
{
fprintf(base_yyout, "%s", @$);
}
| '{'
{
braces_open++;
fputs("{", base_yyout);
}
| '}'
{
if (braces_open > 0)
{
remove_typedefs(braces_open);
remove_variables(braces_open);
if (--braces_open == 0)
{
free(current_function);
current_function = NULL;
}
}
fputs("}", base_yyout);
}
;
CreateAsStmt: CREATE OptTemp TABLE create_as_target AS
{
FoundInto = 0;
} SelectStmt opt_with_data
{
if (FoundInto == 1)
mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO");
}
| CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS
{
FoundInto = 0;
} SelectStmt opt_with_data
{
if (FoundInto == 1)
mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO");
}
;
at: AT connection_object
{
if (connection)
free(connection);
connection = mm_strdup(@2);
/*
* Do we have a variable as connection target? Remove the variable
* from the variable list or else it will be used twice.
*/
if (argsinsert != NULL)
argsinsert = NULL;
}
;
/*
* the exec sql connect statement: connect to the given database
*/
ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
{
@$ = cat_str(5, @3, ",", @5, ",", @4);
}
| SQL_CONNECT TO DEFAULT
{
@$ = "NULL, NULL, NULL, \"DEFAULT\"";
}
/* also allow ORACLE syntax */
| SQL_CONNECT ora_user
{
@$ = cat_str(3, "NULL,", @2, ", NULL");
}
| DATABASE connection_target
{
@$ = cat2_str(@2, ", NULL, NULL, NULL");
}
;
connection_target: opt_database_name opt_server opt_port
{
/* old style: dbname[@server][:port] */
if (strlen(@2) > 0 && *(@2) != '@')
mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", @2);
/* C strings need to be handled differently */
if (@1[0] == '\"')
@$ = @1;
else
@$ = make3_str("\"", make3_str(@1, @2, @3), "\"");
}
| db_prefix ':' server opt_port '/' opt_database_name opt_options
{
/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
if (strncmp(@1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp(@1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported");
if (strncmp(@3, "//", strlen("//")) != 0)
mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", @3);
if (strncmp(@1, "unix", strlen("unix")) == 0 &&
strncmp(@3 + strlen("//"), "localhost", strlen("localhost")) != 0 &&
strncmp(@3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", @3 + strlen("//"));
@$ = make3_str(make3_str("\"", @1, ":"), @3, make3_str(make3_str(@4, "/", @6), @7, "\""));
}
| char_variable
| ecpg_sconst
{
/*
* We can only process double quoted strings not single quoted ones,
* so we change the quotes. Note that the rule for ecpg_sconst adds
* these single quotes.
*/
char *str = loc_strdup(@1);
str[0] = '\"';
str[strlen(str) - 1] = '\"';
@$ = str;
}
;
opt_database_name: name
| /* EMPTY */
;
db_prefix: ecpg_ident cvariable
{
if (strcmp(@2, "postgresql") != 0 && strcmp(@2, "postgres") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", @2);
if (strcmp(@1, "tcp") != 0 && strcmp(@1, "unix") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", @1);
@$ = make3_str(@1, ":", @2);
}
;
server: Op server_name
{
if (strcmp(@1, "@") != 0 && strcmp(@1, "//") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", @1);
@$ = make2_str(@1, @2);
}
;
opt_server: server
| /* EMPTY */
;
server_name: ColId
| ColId '.' server_name
| IP
;
opt_port: ':' Iconst
{
@$ = make2_str(":", @2);
}
| /* EMPTY */
;
opt_connection_name: AS connection_object
{
@$ = @2;
}
| /* EMPTY */
{
@$ = "NULL";
}
;
opt_user: USER ora_user
{
@$ = @2;
}
| /* EMPTY */
{
@$ = "NULL, NULL";
}
;
ora_user: user_name
{
@$ = cat2_str(@1, ", NULL");
}
| user_name '/' user_name
{
@$ = cat_str(3, @1, ",", @3);
}
| user_name SQL_IDENTIFIED BY user_name
{
@$ = cat_str(3, @1, ",", @4);
}
| user_name USING user_name
{
@$ = cat_str(3, @1, ",", @3);
}
;
user_name: RoleId
{
if (@1[0] == '\"')
@$ = @1;
else
@$ = make3_str("\"", @1, "\"");
}
| ecpg_sconst
{
if (@1[0] == '\"')
@$ = @1;
else
@$ = make3_str("\"", @1, "\"");
}
| civar
{
enum ECPGttype type = argsinsert->variable->type->type;
/* if array see what's inside */
if (type == ECPGt_array)
type = argsinsert->variable->type->u.element->type;
/* handle varchars */
if (type == ECPGt_varchar)
@$ = make2_str(argsinsert->variable->name, ".arr");
else
@$ = argsinsert->variable->name;
}
;
char_variable: cvariable
{
/* check if we have a string variable */
struct variable *p = find_variable(@1);
enum ECPGttype type = p->type->type;
/* If we have just one character this is not a string */
if (atol(p->type->size) == 1)
mmerror(PARSE_ERROR, ET_ERROR, "invalid data type");
else
{
/* if array see what's inside */
if (type == ECPGt_array)
type = p->type->u.element->type;
switch (type)
{
case ECPGt_char:
case ECPGt_unsigned_char:
case ECPGt_string:
@$ = @1;
break;
case ECPGt_varchar:
@$ = make2_str(@1, ".arr");
break;
default:
mmerror(PARSE_ERROR, ET_ERROR, "invalid data type");
@$ = @1;
break;
}
}
}
;
opt_options: Op connect_options
{
if (strlen(@1) == 0)
mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
if (strcmp(@1, "?") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @1);
@$ = make2_str("?", @2);
}
| /* EMPTY */
;
connect_options: ColId opt_opt_value
{
@$ = make2_str(@1, @2);
}
| ColId opt_opt_value Op connect_options
{
if (strlen(@3) == 0)
mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
if (strcmp(@3, "&") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @3);
@$ = make3_str(make2_str(@1, @2), @3, @4);
}
;
opt_opt_value: /* EMPTY */
| '=' Iconst
{
@$ = make2_str("=", @2);
}
| '=' ecpg_ident
{
@$ = make2_str("=", @2);
}
| '=' civar
{
@$ = make2_str("=", @2);
}
;
prepared_name: name
{
size_t slen = strlen(@1);
if (@1[0] == '\"' && @1[slen - 1] == '\"') /* already quoted? */
@$ = @1;
else /* not quoted => convert to lowercase */
{
char *str = loc_alloc(slen + 3);
str[0] = '\"';
for (size_t i = 0; i < slen; i++)
str[i + 1] = tolower((unsigned char) @1[i]);
str[slen + 1] = '\"';
str[slen + 2] = '\0';
@$ = str;
}
}
| char_variable
;
/*
* Declare Statement
*/
ECPGDeclareStmt: DECLARE prepared_name STATEMENT
{
struct declared_list *ptr;
/* Check whether the declared name has been defined or not */
for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next)
{
if (strcmp(@2, ptr->name) == 0)
{
/* re-definition is not allowed */
mmerror(PARSE_ERROR, ET_ERROR, "name \"%s\" is already declared", ptr->name);
}
}
/* Add a new declared name into the g_declared_list */
ptr = (struct declared_list *) mm_alloc(sizeof(struct declared_list));
if (ptr)
{
/* initial definition */
ptr->name = mm_strdup(@2);
if (connection)
ptr->connection = mm_strdup(connection);
else
ptr->connection = NULL;
ptr->next = g_declared_list;
g_declared_list = ptr;
}
@$ = cat_str(3, "/* declare ", @2, " as an SQL identifier */");
}
;
/*
* Declare a prepared cursor. The syntax is different from the standard
* declare statement, so we create a new rule.
*/
ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name
{
struct cursor *ptr,
*this;
const char *cursor_marker = @2[0] == ':' ? "$0" : @2;
int (*strcmp_fn) (const char *, const char *) = ((@2[0] == ':' || @2[0] == '"') ? strcmp : pg_strcasecmp);
struct variable *thisquery = (struct variable *) mm_alloc(sizeof(struct variable));
char *comment;
char *con;
if (INFORMIX_MODE && pg_strcasecmp(@2, "database") == 0)
mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode");
check_declared_list(@7);
con = connection ? connection : "NULL";
for (ptr = cur; ptr != NULL; ptr = ptr->next)
{
if (strcmp_fn(@2, ptr->name) == 0)
{
/* re-definition is a bug */
if (@2[0] == ':')
mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported", @2 + 1);
else
mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", @2);
}
}
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
/* initial definition */
this->next = cur;
this->name = mm_strdup(@2);
this->function = (current_function ? mm_strdup(current_function) : NULL);
this->connection = connection ? mm_strdup(connection) : NULL;
this->opened = false;
this->command = mm_strdup(cat_str(6, "declare", cursor_marker, @3, "cursor", @5, "for $1"));
this->argsresult = NULL;
this->argsresult_oos = NULL;
thisquery->type = &ecpg_query;
thisquery->brace_level = 0;
thisquery->next = NULL;
thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen(@7));
sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, @7);
this->argsinsert = NULL;
this->argsinsert_oos = NULL;
if (@2[0] == ':')
{
struct variable *var = find_variable(@2 + 1);
remove_variable_from_list(&argsinsert, var);
add_variable_to_head(&(this->argsinsert), var, &no_indicator);
}
add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
cur = this;
comment = cat_str(3, "/*", this->command, "*/");
@$ = cat_str(2, adjust_outofscope_cursor_vars(this),
comment);
}
;
ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring
{
/*
* execute immediate means prepare the statement and immediately
* execute it
*/
@$ = @3;
}
;
/*
* variable declaration outside exec sql declare block
*/
ECPGVarDeclaration: single_vt_declaration;
single_vt_declaration: type_declaration
| var_declaration
;
precision: NumericOnly
;
opt_scale: ',' NumericOnly
{
@$ = @2;
}
| /* EMPTY */
;
ecpg_interval: opt_interval
| YEAR_P TO MINUTE_P
| YEAR_P TO SECOND_P
| DAY_P TO DAY_P
| MONTH_P TO MONTH_P
;
/*
* variable declaration inside exec sql declare block
*/
ECPGDeclaration: sql_startdeclare
{
fputs("/* exec sql begin declare section */", base_yyout);
}
var_type_declarations sql_enddeclare
{
fprintf(base_yyout, "%s/* exec sql end declare section */", @3);
output_line_number();
}
;
sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';'
{
}
;
sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';'
{
}
;
var_type_declarations: /* EMPTY */
| vt_declarations
;
vt_declarations: single_vt_declaration
| CPP_LINE
| vt_declarations single_vt_declaration
| vt_declarations CPP_LINE
;
variable_declarations: var_declaration
| variable_declarations var_declaration
;
type_declaration: S_TYPEDEF
{
/* reset this variable so we see if there was */
/* an initializer specified */
initializer = 0;
}
var_type opt_pointer ECPGColLabel opt_array_bounds ';'
{
add_typedef(@5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *@4 ? 1 : 0);
fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *@4 ? "*" : "", @5, $6.str);
output_line_number();
@$ = "";
}
;
var_declaration:
storage_declaration var_type
{
actual_type[struct_level].type_storage = loc_strdup(@1);
actual_type[struct_level].type_enum = $2.type_enum;
actual_type[struct_level].type_str = $2.type_str;
actual_type[struct_level].type_dimension = $2.type_dimension;
actual_type[struct_level].type_index = $2.type_index;
actual_type[struct_level].type_sizeof = $2.type_sizeof;
actual_startline[struct_level] = hashline_number();
}
variable_list ';'
{
@$ = cat_str(5, actual_startline[struct_level], @1, $2.type_str, @4, ";\n");
}
| var_type
{
actual_type[struct_level].type_storage = loc_strdup("");
actual_type[struct_level].type_enum = $1.type_enum;
actual_type[struct_level].type_str = $1.type_str;
actual_type[struct_level].type_dimension = $1.type_dimension;
actual_type[struct_level].type_index = $1.type_index;
actual_type[struct_level].type_sizeof = $1.type_sizeof;
actual_startline[struct_level] = hashline_number();
}
variable_list ';'
{
@$ = cat_str(4, actual_startline[struct_level], $1.type_str, @3, ";\n");
}
| struct_union_type_with_symbol ';'
;
opt_bit_field: ':' Iconst
| /* EMPTY */
;
storage_declaration: storage_clause storage_modifier
| storage_clause
| storage_modifier
;
storage_clause: S_EXTERN
| S_STATIC
| S_REGISTER
| S_AUTO
;
storage_modifier: S_CONST
| S_VOLATILE
;
var_type: simple_type
{
$$.type_enum = $1;
$$.type_str = loc_strdup(ecpg_type_name($1));
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| struct_union_type
{
$$.type_str = loc_strdup(@1);
$$.type_dimension = "-1";
$$.type_index = "-1";
if (strncmp(@1, "struct", sizeof("struct") - 1) == 0)
{
$$.type_enum = ECPGt_struct;
$$.type_sizeof = ECPGstruct_sizeof;
}
else
{
$$.type_enum = ECPGt_union;
$$.type_sizeof = NULL;
}
}
| enum_type
{
$$.type_str = loc_strdup(@1);
$$.type_enum = ECPGt_int;
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| NUMERIC '(' precision opt_scale ')'
{
$$.type_enum = ECPGt_numeric;
$$.type_str = "numeric";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| DECIMAL_P '(' precision opt_scale ')'
{
$$.type_enum = ECPGt_decimal;
$$.type_str = "decimal";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| IDENT '(' precision opt_scale ')'
{
/*
* In C parsing mode, NUMERIC and DECIMAL are not keywords, so they
* will show up here as a plain identifier, and we need this duplicate
* code to recognize them.
*/
if (strcmp(@1, "numeric") == 0)
{
$$.type_enum = ECPGt_numeric;
$$.type_str = "numeric";
}
else if (strcmp(@1, "decimal") == 0)
{
$$.type_enum = ECPGt_decimal;
$$.type_str = "decimal";
}
else
{
mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = "numeric";
}
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| VARCHAR
{
$$.type_enum = ECPGt_varchar;
$$.type_str = ""; /* "varchar"; */
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| FLOAT_P
{
/* Note: DOUBLE is handled in simple_type */
$$.type_enum = ECPGt_float;
$$.type_str = "float";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| NUMERIC
{
$$.type_enum = ECPGt_numeric;
$$.type_str = "numeric";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| DECIMAL_P
{
$$.type_enum = ECPGt_decimal;
$$.type_str = "decimal";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| TIMESTAMP
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = "timestamp";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| STRING_P
{
if (INFORMIX_MODE)
{
/* In Informix mode, "string" is automatically a typedef */
$$.type_enum = ECPGt_string;
$$.type_str = "char";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else
{
/* Otherwise, legal only if user typedef'ed it */
struct typedefs *this = get_typedef("string", false);
$$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? mm_strdup("") : mm_strdup(this->name);
$$.type_enum = this->type->type_enum;
$$.type_dimension = this->type->type_dimension;
$$.type_index = this->type->type_index;
if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
$$.type_sizeof = this->type->type_sizeof;
else
$$.type_sizeof = cat_str(3, "sizeof(", this->name, ")");
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
}
| INTERVAL ecpg_interval
{
$$.type_enum = ECPGt_interval;
$$.type_str = "interval";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
| IDENT ecpg_interval
{
/*
* In C parsing mode, the above SQL type names are not keywords, so
* they will show up here as a plain identifier, and we need this
* duplicate code to recognize them.
*
* Note that we also handle the type names bytea, date, and datetime
* here, but not above because those are not currently SQL keywords.
* If they ever become so, they must gain duplicate productions above.
*/
if (strlen(@2) != 0 && strcmp(@1, "datetime") != 0 && strcmp(@1, "interval") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "interval specification not allowed here");
if (strcmp(@1, "varchar") == 0)
{
$$.type_enum = ECPGt_varchar;
$$.type_str = ""; /* "varchar"; */
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "bytea") == 0)
{
$$.type_enum = ECPGt_bytea;
$$.type_str = "";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "float") == 0)
{
$$.type_enum = ECPGt_float;
$$.type_str = "float";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "double") == 0)
{
$$.type_enum = ECPGt_double;
$$.type_str = "double";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "numeric") == 0)
{
$$.type_enum = ECPGt_numeric;
$$.type_str = "numeric";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "decimal") == 0)
{
$$.type_enum = ECPGt_decimal;
$$.type_str = "decimal";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "date") == 0)
{
$$.type_enum = ECPGt_date;
$$.type_str = "date";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "timestamp") == 0)
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = "timestamp";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "interval") == 0)
{
$$.type_enum = ECPGt_interval;
$$.type_str = "interval";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if (strcmp(@1, "datetime") == 0)
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = "timestamp";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else if ((strcmp(@1, "string") == 0) && INFORMIX_MODE)
{
$$.type_enum = ECPGt_string;
$$.type_str = "char";
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = NULL;
}
else
{
/* Otherwise, it must be a user-defined typedef name */
struct typedefs *this = get_typedef(@1, false);
$$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? "" : this->name;
$$.type_enum = this->type->type_enum;
$$.type_dimension = this->type->type_dimension;
$$.type_index = this->type->type_index;
if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
$$.type_sizeof = this->type->type_sizeof;
else
$$.type_sizeof = cat_str(3, "sizeof(", this->name, ")");
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
}
| s_struct_union_symbol
{
/* this is for named structs/unions */
char *name;
struct typedefs *this;
bool forward = (forward_name != NULL && strcmp($1.symbol, forward_name) == 0 && strcmp($1.su, "struct") == 0);
name = cat2_str($1.su, $1.symbol);
/* Do we have a forward definition? */
if (!forward)
{
/* No */
this = get_typedef(name, false);
$$.type_str = this->name;
$$.type_enum = this->type->type_enum;
$$.type_dimension = this->type->type_dimension;
$$.type_index = this->type->type_index;
$$.type_sizeof = this->type->type_sizeof;
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
else
{
$$.type_str = name;
$$.type_enum = ECPGt_long;
$$.type_dimension = "-1";
$$.type_index = "-1";
$$.type_sizeof = "";
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level] = NULL;
}
}
;
enum_type: ENUM_P symbol enum_definition
| ENUM_P enum_definition
| ENUM_P symbol
;
enum_definition: '{' c_list '}'
;
struct_union_type_with_symbol: s_struct_union_symbol
{
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
forward_name = mm_strdup($1.symbol);
}
'{' variable_declarations '}'
{
struct typedefs *ptr,
*this;
struct this_type su_type;
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level] = NULL;
struct_level--;
if (strcmp($1.su, "struct") == 0)
su_type.type_enum = ECPGt_struct;
else
su_type.type_enum = ECPGt_union;
su_type.type_str = cat2_str($1.su, $1.symbol);
free(forward_name);
forward_name = NULL;
/*
* This is essentially a typedef but needs the keyword struct/union as
* well. So we create the typedef for each struct definition with
* symbol
*/
for (ptr = types; ptr != NULL; ptr = ptr->next)
{
if (strcmp(su_type.type_str, ptr->name) == 0)
/* re-definition is a bug */
mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", su_type.type_str);
}
this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
/* initial definition */
this->next = types;
this->name = mm_strdup(su_type.type_str);
this->brace_level = braces_open;
this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
this->type->type_storage = NULL;
this->type->type_enum = su_type.type_enum;
this->type->type_str = mm_strdup(su_type.type_str);
this->type->type_dimension = mm_strdup("-1"); /* dimension of array */
this->type->type_index = mm_strdup("-1"); /* length of string */
this->type->type_sizeof = ECPGstruct_sizeof ? mm_strdup(ECPGstruct_sizeof) : NULL;
this->struct_member_list = ECPGstruct_member_dup(struct_member_list[struct_level]);
types = this;
@$ = cat_str(4, su_type.type_str, "{", @4, "}");
}
;
struct_union_type: struct_union_type_with_symbol
| s_struct_union
{
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
}
'{' variable_declarations '}'
{
ECPGfree_struct_member(struct_member_list[struct_level]);
struct_member_list[struct_level] = NULL;
struct_level--;
@$ = cat_str(4, @1, "{", @4, "}");
}
;
s_struct_union_symbol: SQL_STRUCT symbol
{
$$.su = "struct";
$$.symbol = @2;
free(ECPGstruct_sizeof);
ECPGstruct_sizeof = mm_strdup(cat_str(3, "sizeof(",
cat2_str($$.su, $$.symbol),
")"));
}
| UNION symbol
{
$$.su = "union";
$$.symbol = @2;
}
;
s_struct_union: SQL_STRUCT
{
free(ECPGstruct_sizeof);
ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to
* distinguish from simple types. */
@$ = "struct";
}
| UNION
{
@$ = "union";
}
;
simple_type: unsigned_type
| opt_signed signed_type { $$ = $2; }
;
unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; }
| SQL_UNSIGNED SQL_SHORT INT_P { $$ = ECPGt_unsigned_short; }
| SQL_UNSIGNED { $$ = ECPGt_unsigned_int; }
| SQL_UNSIGNED INT_P { $$ = ECPGt_unsigned_int; }
| SQL_UNSIGNED SQL_LONG { $$ = ECPGt_unsigned_long; }
| SQL_UNSIGNED SQL_LONG INT_P { $$ = ECPGt_unsigned_long; }
| SQL_UNSIGNED SQL_LONG SQL_LONG { $$ = ECPGt_unsigned_long_long; }
| SQL_UNSIGNED SQL_LONG SQL_LONG INT_P { $$ = ECPGt_unsigned_long_long; }
| SQL_UNSIGNED CHAR_P { $$ = ECPGt_unsigned_char; }
;
signed_type: SQL_SHORT { $$ = ECPGt_short; }
| SQL_SHORT INT_P { $$ = ECPGt_short; }
| INT_P { $$ = ECPGt_int; }
| SQL_LONG { $$ = ECPGt_long; }
| SQL_LONG INT_P { $$ = ECPGt_long; }
| SQL_LONG SQL_LONG { $$ = ECPGt_long_long; }
| SQL_LONG SQL_LONG INT_P { $$ = ECPGt_long_long; }
| SQL_BOOL { $$ = ECPGt_bool; }
| CHAR_P { $$ = ECPGt_char; }
| DOUBLE_P { $$ = ECPGt_double; }
;
opt_signed: SQL_SIGNED
| /* EMPTY */
;
variable_list: variable
| variable_list ',' variable
{
if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea)
@$ = cat_str(4, @1, ";", actual_type[struct_level].type_storage, @3);
else
@$ = cat_str(3, @1, ",", @3);
}
;
variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer
{
struct ECPGtype *type;
const char *dimension = $3.index1; /* dimension of array */
const char *length = $3.index2; /* length of string */
char *dim_str;
char vcn[32];
int *varlen_type_counter;
char *struct_name;
adjust_array(actual_type[struct_level].type_enum,
&dimension, &length,
actual_type[struct_level].type_dimension,
actual_type[struct_level].type_index,
strlen(@1), false);
switch (actual_type[struct_level].type_enum)
{
case ECPGt_struct:
case ECPGt_union:
if (atoi(dimension) < 0)
type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof);
else
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension);
@$ = cat_str(5, @1, @2, $3.str, @4, @5);
break;
case ECPGt_varchar:
case ECPGt_bytea:
if (actual_type[struct_level].type_enum == ECPGt_varchar)
{
varlen_type_counter = &varchar_counter;
struct_name = " struct varchar_";
}
else
{
varlen_type_counter = &bytea_counter;
struct_name = " struct bytea_";
}
if (atoi(dimension) < 0)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter), dimension);
if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1)
dim_str = "";
else
dim_str = cat_str(3, "[", dimension, "]");
/*
* cannot check for atoi <= 0 because a defined constant will
* yield 0 here as well
*/
if (atoi(length) < 0 || strcmp(length, "0") == 0)
mmerror(PARSE_ERROR, ET_ERROR, "pointers to varchar are not implemented");
/*
* make sure varchar struct name is unique by adding a unique
* counter to its definition
*/
snprintf(vcn, sizeof(vcn), "%d", *varlen_type_counter);
if (strcmp(dimension, "0") == 0)
@$ = cat_str(7, make2_str(struct_name, vcn), " { int len; char arr[", length, "]; } *", @2, @4, @5);
else
@$ = cat_str(8, make2_str(struct_name, vcn), " { int len; char arr[", length, "]; } ", @2, dim_str, @4, @5);
(*varlen_type_counter)++;
break;
case ECPGt_char:
case ECPGt_unsigned_char:
case ECPGt_string:
if (atoi(dimension) == -1)
{
int i = strlen(@5);
if (atoi(length) == -1 && i > 0) /* char <var>[] =
* "string" */
{
/*
* if we have an initializer but no string size set,
* let's use the initializer's length
*/
char *buf = loc_alloc(32);
snprintf(buf, 32, "sizeof(%s)", @5 + 2);
length = buf;
}
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0);
}
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension);
@$ = cat_str(5, @1, @2, $3.str, @4, @5);
break;
default:
if (atoi(dimension) < 0)
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, "1", 0);
else
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, "1", 0), dimension);
@$ = cat_str(5, @1, @2, $3.str, @4, @5);
break;
}
if (struct_level == 0)
new_variable(@2, type, braces_open);
else
ECPGmake_struct_member(@2, type, &(struct_member_list[struct_level - 1]));
}
;
opt_initializer: /* EMPTY */
| '=' c_term
{
initializer = 1;
}
;
opt_pointer: /* EMPTY */
| '*'
| '*' '*'
{
@$ = "**";
}
;
/*
* We try to simulate the correct DECLARE syntax here so we get dynamic SQL
*/
ECPGDeclare: DECLARE STATEMENT ecpg_ident
{
/* this is only supported for compatibility */
@$ = cat_str(3, "/* declare statement", @3, "*/");
}
;
/*
* the exec sql disconnect statement: disconnect from the given database
*/
ECPGDisconnect: SQL_DISCONNECT dis_name
{
@$ = @2;
}
;
dis_name: connection_object
| CURRENT_P
{
@$ = "\"CURRENT\"";
}
| ALL
{
@$ = "\"ALL\"";
}
| /* EMPTY */
{
@$ = "\"CURRENT\"";
}
;
connection_object: name
{
@$ = make3_str("\"", @1, "\"");
}
| DEFAULT
{
@$ = "\"DEFAULT\"";
}
| char_variable
;
execstring: char_variable
| CSTRING
{
@$ = make3_str("\"", @1, "\"");
}
;
/*
* the exec sql free command to deallocate a previously
* prepared statement
*/
ECPGFree: SQL_FREE cursor_name
{
@$ = @2;
}
| SQL_FREE ALL
{
@$ = "all";
}
;
/*
* open is an open cursor, at the moment this has to be removed
*/
ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using
{
if (@2[0] == ':')
remove_variable_from_list(&argsinsert, find_variable(@2 + 1));
@$ = @2;
}
;
opt_ecpg_using: /* EMPTY */
| ecpg_using
;
ecpg_using: USING using_list
{
@$ = "";
}
| using_descriptor
;
using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar
{
add_variable_to_head(&argsinsert, descriptor_variable(@4, 0), &no_indicator);
@$ = "";
}
| USING SQL_DESCRIPTOR name
{
add_variable_to_head(&argsinsert, sqlda_variable(@3), &no_indicator);
@$ = "";
}
;
into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar
{
add_variable_to_head(&argsresult, descriptor_variable(@4, 1), &no_indicator);
@$ = "";
}
| INTO SQL_DESCRIPTOR name
{
add_variable_to_head(&argsresult, sqlda_variable(@3), &no_indicator);
@$ = "";
}
;
into_sqlda: INTO name
{
add_variable_to_head(&argsresult, sqlda_variable(@2), &no_indicator);
@$ = "";
}
;
using_list: UsingValue | UsingValue ',' using_list
;
UsingValue: UsingConst
{
char length[32];
snprintf(length, sizeof(length), "%zu", strlen(@1));
add_variable_to_head(&argsinsert, new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
}
| civar
{
@$ = "";
}
| civarind
{
@$ = "";
}
;
UsingConst: Iconst
| '+' Iconst
| '-' Iconst
| ecpg_fconst
| '+' ecpg_fconst
| '-' ecpg_fconst
| ecpg_sconst
| ecpg_bconst
| ecpg_xconst
;
/*
* We accept DESCRIBE [OUTPUT] but do nothing with DESCRIBE INPUT so far.
*/
ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor
{
$$.input = 1;
$$.stmt_name = @3;
}
| SQL_DESCRIBE opt_output prepared_name using_descriptor
{
struct variable *var;
var = argsinsert->variable;
remove_variable_from_list(&argsinsert, var);
add_variable_to_head(&argsresult, var, &no_indicator);
$$.input = 0;
$$.stmt_name = @3;
}
| SQL_DESCRIBE opt_output prepared_name into_descriptor
{
$$.input = 0;
$$.stmt_name = @3;
}
| SQL_DESCRIBE INPUT_P prepared_name into_sqlda
{
$$.input = 1;
$$.stmt_name = @3;
}
| SQL_DESCRIBE opt_output prepared_name into_sqlda
{
$$.input = 0;
$$.stmt_name = @3;
}
;
opt_output: SQL_OUTPUT
| /* EMPTY */
;
/*
* dynamic SQL: descriptor based access
* originally written by Christof Petig <christof.petig@wtal.de>
* and Peter Eisentraut <peter.eisentraut@credativ.de>
*/
/*
* allocate a descriptor
*/
ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
{
add_descriptor(@3, connection);
@$ = @3;
}
;
/*
* deallocate a descriptor
*/
ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
{
drop_descriptor(@3, connection);
@$ = @3;
}
;
/*
* manipulate a descriptor header
*/
ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
{
@$ = @3;
}
;
ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
;
ECPGGetDescHeaderItem: cvariable '=' desc_header_item
{
push_assignment(@1, $3);
}
;
ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems
{
@$ = @3;
}
;
ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
| ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
;
ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar
{
push_assignment(@3, $1);
}
;
IntConstVar: Iconst
{
char length[32];
snprintf(length, sizeof(length), "%zu", strlen(@1));
new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
}
| cvariable
;
desc_header_item: SQL_COUNT
{
$$ = ECPGd_count;
}
;
/*
* manipulate a descriptor
*/
ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems
{
$$.str = @5;
$$.name = @3;
}
;
ECPGGetDescItems: ECPGGetDescItem
| ECPGGetDescItems ',' ECPGGetDescItem
;
ECPGGetDescItem: cvariable '=' descriptor_item
{
push_assignment(@1, $3);
}
;
ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems
{
$$.str = @5;
$$.name = @3;
}
;
ECPGSetDescItems: ECPGSetDescItem
| ECPGSetDescItems ',' ECPGSetDescItem
;
ECPGSetDescItem: descriptor_item '=' AllConstVar
{
push_assignment(@3, $1);
}
;
AllConstVar: ecpg_fconst
{
char length[32];
snprintf(length, sizeof(length), "%zu", strlen(@1));
new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
}
| IntConstVar
| '-' ecpg_fconst
{
char length[32];
char *var = cat2_str("-", @2);
snprintf(length, sizeof(length), "%zu", strlen(var));
new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
@$ = var;
}
| '-' Iconst
{
char length[32];
char *var = cat2_str("-", @2);
snprintf(length, sizeof(length), "%zu", strlen(var));
new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
@$ = var;
}
| ecpg_sconst
{
char length[32];
char *var;
/* Strip single quotes from ecpg_sconst */
var = loc_strdup(@1 + 1);
var[strlen(var) - 1] = '\0';
snprintf(length, sizeof(length), "%zu", strlen(var));
new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
@$ = var;
}
;
descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; }
| DATA_P { $$ = ECPGd_data; }
| SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; }
| SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; }
| SQL_INDICATOR { $$ = ECPGd_indicator; }
| SQL_KEY_MEMBER { $$ = ECPGd_key_member; }
| SQL_LENGTH { $$ = ECPGd_length; }
| NAME_P { $$ = ECPGd_name; }
| SQL_NULLABLE { $$ = ECPGd_nullable; }
| SQL_OCTET_LENGTH { $$ = ECPGd_octet; }
| PRECISION { $$ = ECPGd_precision; }
| SQL_RETURNED_LENGTH { $$ = ECPGd_length; }
| SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; }
| SQL_SCALE { $$ = ECPGd_scale; }
| TYPE_P { $$ = ECPGd_type; }
;
/*
* set/reset the automatic transaction mode, this needs a different handling
* as the other set commands
*/
ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off
{
@$ = @4;
}
| SET SQL_AUTOCOMMIT TO on_off
{
@$ = @4;
}
;
on_off: ON
| OFF
;
/*
* set the actual connection, this needs a different handling as the other
* set commands
*/
ECPGSetConnection: SET CONNECTION TO connection_object
{
@$ = @4;
}
| SET CONNECTION '=' connection_object
{
@$ = @4;
}
| SET CONNECTION connection_object
{
@$ = @3;
}
;
/*
* define a new type for embedded SQL
*/
ECPGTypedef: TYPE_P
{
/* reset this variable so we see if there was */
/* an initializer specified */
initializer = 0;
}
ECPGColLabel IS var_type opt_array_bounds opt_reference
{
add_typedef(@3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *@7 ? 1 : 0);
if (auto_create_c == false)
@$ = cat_str(7, "/* exec sql type", @3, "is", $5.type_str, $6.str, @7, "*/");
else
@$ = cat_str(6, "typedef ", $5.type_str, *@7 ? "*" : "", @3, $6.str, ";");
}
;
opt_reference: SQL_REFERENCE
| /* EMPTY */
;
/*
* define the type of one variable for embedded SQL
*/
ECPGVar: SQL_VAR
{
/* reset this variable so we see if there was */
/* an initializer specified */
initializer = 0;
}
ColLabel IS var_type opt_array_bounds opt_reference
{
struct variable *p = find_variable(@3);
const char *dimension = $6.index1;
const char *length = $6.index2;
struct ECPGtype *type;
if (($5.type_enum == ECPGt_struct ||
$5.type_enum == ECPGt_union) &&
initializer == 1)
mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command");
else
{
adjust_array($5.type_enum, &dimension, &length,
$5.type_dimension, $5.type_index, *@7 ? 1 : 0, false);
switch ($5.type_enum)
{
case ECPGt_struct:
case ECPGt_union:
if (atoi(dimension) < 0)
type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof);
else
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof), dimension);
break;
case ECPGt_varchar:
case ECPGt_bytea:
if (atoi(dimension) == -1)
type = ECPGmake_simple_type($5.type_enum, length, 0);
else
type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
break;
case ECPGt_char:
case ECPGt_unsigned_char:
case ECPGt_string:
if (atoi(dimension) == -1)
type = ECPGmake_simple_type($5.type_enum, length, 0);
else
type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
break;
default:
if (atoi(length) >= 0)
mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
if (atoi(dimension) < 0)
type = ECPGmake_simple_type($5.type_enum, "1", 0);
else
type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, "1", 0), dimension);
break;
}
ECPGfree_type(p->type);
p->type = type;
}
@$ = cat_str(7, "/* exec sql var", @3, "is", $5.type_str, $6.str, @7, "*/");
}
;
/*
* whenever statement: decide what to do in case of error/no data found
* according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
*/
ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action
{
when_error.code = $3.code;
free(when_error.command);
when_error.command = $3.command ? mm_strdup($3.command) : NULL;
@$ = cat_str(3, "/* exec sql whenever sqlerror ", $3.str, "; */");
}
| SQL_WHENEVER NOT SQL_FOUND action
{
when_nf.code = $4.code;
free(when_nf.command);
when_nf.command = $4.command ? mm_strdup($4.command) : NULL;
@$ = cat_str(3, "/* exec sql whenever not found ", $4.str, "; */");
}
| SQL_WHENEVER SQL_SQLWARNING action
{
when_warn.code = $3.code;
free(when_warn.command);
when_warn.command = $3.command ? mm_strdup($3.command) : NULL;
@$ = cat_str(3, "/* exec sql whenever sql_warning ", $3.str, "; */");
}
;
action: CONTINUE_P
{
$$.code = W_NOTHING;
$$.command = NULL;
$$.str = "continue";
}
| SQL_SQLPRINT
{
$$.code = W_SQLPRINT;
$$.command = NULL;
$$.str = "sqlprint";
}
| SQL_STOP
{
$$.code = W_STOP;
$$.command = NULL;
$$.str = "stop";
}
| SQL_GOTO name
{
$$.code = W_GOTO;
$$.command = loc_strdup(@2);
$$.str = cat2_str("goto ", @2);
}
| SQL_GO TO name
{
$$.code = W_GOTO;
$$.command = loc_strdup(@3);
$$.str = cat2_str("goto ", @3);
}
| DO name '(' c_args ')'
{
$$.code = W_DO;
$$.command = cat_str(4, @2, "(", @4, ")");
$$.str = cat2_str("do", $$.command);
}
| DO SQL_BREAK
{
$$.code = W_BREAK;
$$.command = NULL;
$$.str = "break";
}
| DO CONTINUE_P
{
$$.code = W_CONTINUE;
$$.command = NULL;
$$.str = "continue";
}
| CALL name '(' c_args ')'
{
$$.code = W_DO;
$$.command = cat_str(4, @2, "(", @4, ")");
$$.str = cat2_str("call", $$.command);
}
| CALL name
{
$$.code = W_DO;
$$.command = cat2_str(@2, "()");
$$.str = cat2_str("call", $$.command);
}
;
/* some other stuff for ecpg */
/* additional unreserved keywords */
ECPGKeywords: ECPGKeywords_vanames
| ECPGKeywords_rest
;
ECPGKeywords_vanames: SQL_BREAK
| SQL_CARDINALITY
| SQL_COUNT
| SQL_DATETIME_INTERVAL_CODE
| SQL_DATETIME_INTERVAL_PRECISION
| SQL_FOUND
| SQL_GO
| SQL_GOTO
| SQL_IDENTIFIED
| SQL_INDICATOR
| SQL_KEY_MEMBER
| SQL_LENGTH
| SQL_NULLABLE
| SQL_OCTET_LENGTH
| SQL_RETURNED_LENGTH
| SQL_RETURNED_OCTET_LENGTH
| SQL_SCALE
| SQL_SECTION
| SQL_SQLERROR
| SQL_SQLPRINT
| SQL_SQLWARNING
| SQL_STOP
;
ECPGKeywords_rest: SQL_CONNECT
| SQL_DESCRIBE
| SQL_DISCONNECT
| SQL_OPEN
| SQL_VAR
| SQL_WHENEVER
;
/* additional keywords that can be SQL type names (but not ECPGColLabels) */
ECPGTypeName: SQL_BOOL
| SQL_LONG
| SQL_OUTPUT
| SQL_SHORT
| SQL_STRUCT
| SQL_SIGNED
| SQL_UNSIGNED
;
symbol: ColLabel
;
ECPGColId: ecpg_ident
| unreserved_keyword
| col_name_keyword
| ECPGunreserved_interval
| ECPGKeywords
| ECPGCKeywords
| CHAR_P
| VALUES
;
/*
* Name classification hierarchy.
*
* These productions should match those in the core grammar, except that
* we use all_unreserved_keyword instead of unreserved_keyword, and
* where possible include ECPG keywords as well as core keywords.
*/
/* Column identifier --- names that can be column, table, etc names.
*/
ColId: ecpg_ident
| all_unreserved_keyword
| col_name_keyword
| ECPGKeywords
| ECPGCKeywords
| CHAR_P
| VALUES
;
/* Type/function identifier --- names that can be type or function names.
*/
type_function_name: ecpg_ident
| all_unreserved_keyword
| type_func_name_keyword
| ECPGKeywords
| ECPGCKeywords
| ECPGTypeName
;
/* Column label --- allowed labels in "AS" clauses.
* This presently includes *all* Postgres keywords.
*/
ColLabel: ECPGColLabel
| ECPGTypeName
| CHAR_P
| CURRENT_P
| INPUT_P
| INT_P
| TO
| UNION
| VALUES
| ECPGCKeywords
| ECPGunreserved_interval
;
ECPGColLabel: ecpg_ident
| unreserved_keyword
| col_name_keyword
| type_func_name_keyword
| reserved_keyword
| ECPGKeywords_vanames
| ECPGKeywords_rest
| CONNECTION
;
ECPGCKeywords: S_AUTO
| S_CONST
| S_EXTERN
| S_REGISTER
| S_STATIC
| S_TYPEDEF
| S_VOLATILE
;
/* "Unreserved" keywords --- available for use as any kind of name.
*/
/*
* The following symbols must be excluded from ECPGColLabel and directly
* included into ColLabel to enable C variables to get names from ECPGColLabel:
* DAY_P, HOUR_P, MINUTE_P, MONTH_P, SECOND_P, YEAR_P.
*
* We also have to exclude CONNECTION, CURRENT, and INPUT for various reasons.
* CONNECTION can be added back in all_unreserved_keyword, but CURRENT and
* INPUT are reserved for ecpg purposes.
*
* The mentioned exclusions are done by $replace_line settings in parse.pl.
*/
all_unreserved_keyword: unreserved_keyword
| ECPGunreserved_interval
| CONNECTION
;
ECPGunreserved_interval: DAY_P
| HOUR_P
| MINUTE_P
| MONTH_P
| SECOND_P
| YEAR_P
;
into_list: coutputvariable | into_list ',' coutputvariable
;
ecpgstart: SQL_START
{
reset_variables();
pacounter = 1;
@$ = "";
}
;
c_args: /* EMPTY */
| c_list
;
coutputvariable: cvariable indicator
{
add_variable_to_head(&argsresult, find_variable(@1), find_variable(@2));
}
| cvariable
{
add_variable_to_head(&argsresult, find_variable(@1), &no_indicator);
}
;
civarind: cvariable indicator
{
if (find_variable(@2)->type->type == ECPGt_array)
mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
add_variable_to_head(&argsinsert, find_variable(@1), find_variable(@2));
@$ = create_questionmarks(@1, false);
}
;
char_civar: char_variable
{
char *ptr = (char *) strstr(@1, ".arr");
if (ptr) /* varchar, we need the struct name here, not
* the struct element */
*ptr = '\0';
add_variable_to_head(&argsinsert, find_variable(@1), &no_indicator);
}
;
civar: cvariable
{
add_variable_to_head(&argsinsert, find_variable(@1), &no_indicator);
@$ = create_questionmarks(@1, false);
}
;
indicator: cvariable
{
check_indicator((find_variable(@1))->type);
}
| SQL_INDICATOR cvariable
{
check_indicator((find_variable(@2))->type);
@$ = @2;
}
| SQL_INDICATOR name
{
check_indicator((find_variable(@2))->type);
@$ = @2;
}
;
cvariable: CVARIABLE
{
/*
* As long as multidimensional arrays are not implemented we have to
* check for those here
*/
const char *ptr = @1;
int brace_open = 0,
brace = false;
for (; *ptr; ptr++)
{
switch (*ptr)
{
case '[':
if (brace)
mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
brace_open++;
break;
case ']':
brace_open--;
if (brace_open == 0)
brace = true;
break;
case '\t':
case ' ':
break;
default:
if (brace_open == 0)
brace = false;
break;
}
}
}
;
ecpg_param: PARAM
;
ecpg_bconst: BCONST
;
ecpg_fconst: FCONST
;
ecpg_sconst: SCONST
;
ecpg_xconst: XCONST
;
ecpg_ident: IDENT
| CSTRING
{
@$ = make3_str("\"", @1, "\"");
}
;
quoted_ident_stringvar: name
{
@$ = make3_str("\"", @1, "\"");
}
| char_variable
{
@$ = make3_str("(", @1, ")");
}
;
/*
* C stuff
*/
c_stuff_item: c_anything
| '(' ')'
{
@$ = "()";
}
| '(' c_stuff ')'
;
c_stuff: c_stuff_item
| c_stuff c_stuff_item
;
c_list: c_term
| c_list ',' c_term
;
c_term: c_stuff
| '{' c_list '}'
;
c_thing: c_anything
| '('
| ')'
| ','
| ';'
;
/*
* Note: NULL_P is treated specially to force it to be output in upper case,
* since it's likely meant as a reference to the standard C macro NULL.
*/
c_anything: ecpg_ident
| Iconst
| ecpg_fconst
| ecpg_sconst
| '*'
| '+'
| '-'
| '/'
| '%'
| NULL_P { @$ = "NULL"; }
| S_ADD
| S_AND
| S_ANYTHING
| S_AUTO
| S_CONST
| S_DEC
| S_DIV
| S_DOTPOINT
| S_EQUAL
| S_EXTERN
| S_INC
| S_LSHIFT
| S_MEMBER
| S_MEMPOINT
| S_MOD
| S_MUL
| S_NEQUAL
| S_OR
| S_REGISTER
| S_RSHIFT
| S_STATIC
| S_SUB
| S_TYPEDEF
| S_VOLATILE
| SQL_BOOL
| ENUM_P
| HOUR_P
| INT_P
| SQL_LONG
| MINUTE_P
| MONTH_P
| SECOND_P
| SQL_SHORT
| SQL_SIGNED
| SQL_STRUCT
| SQL_UNSIGNED
| YEAR_P
| CHAR_P
| FLOAT_P
| TO
| UNION
| VARCHAR
| '['
| ']'
| '='
| ':'
;
DeallocateStmt: DEALLOCATE prepared_name
{
check_declared_list(@2);
@$ = @2;
}
| DEALLOCATE PREPARE prepared_name
{
check_declared_list(@3);
@$ = @3;
}
| DEALLOCATE ALL
{
@$ = "all";
}
| DEALLOCATE PREPARE ALL
{
@$ = "all";
}
;
Iresult: Iconst
| '(' Iresult ')'
| Iresult '+' Iresult
| Iresult '-' Iresult
| Iresult '*' Iresult
| Iresult '/' Iresult
| Iresult '%' Iresult
| ecpg_sconst
| ColId
| ColId '(' var_type ')'
{
if (pg_strcasecmp(@1, "sizeof") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition");
else
@$ = cat_str(4, @1, "(", $3.type_str, ")");
}
;
execute_rest: /* EMPTY */
| ecpg_using opt_ecpg_into
| ecpg_into ecpg_using
| ecpg_into
;
ecpg_into: INTO into_list
{
/* always suppress this from the constructed string */
@$ = "";
}
| into_descriptor
;
opt_ecpg_into: /* EMPTY */
| ecpg_into
;
ecpg_fetch_into: ecpg_into
| using_descriptor
{
struct variable *var;
var = argsinsert->variable;
remove_variable_from_list(&argsinsert, var);
add_variable_to_head(&argsresult, var, &no_indicator);
}
;
opt_ecpg_fetch_into: /* EMPTY */
| ecpg_fetch_into
;
%%
void
base_yyerror(const char *error)
{
/* translator: %s is typically the translation of "syntax error" */
mmerror(PARSE_ERROR, ET_ERROR, "%s at or near \"%s\"",
_(error), token_start ? token_start : base_yytext);
}
void
parser_init(void)
{
/*
* This function is empty. It only exists for compatibility with the
* backend parser right now.
*/
}
[Dauer der Verarbeitung: 0.110 Sekunden, vorverarbeitet 2026-08-08]
|
2026-08-25
|
|
|
|
|
Neuigkeiten |
| Aktuelles |
| Motto des Tages |
|
Open Source Software |
|
|
|
Jenseits des Üblichen ....
|
|
Besucherstatistik |
|
|
| Statistik |
| #Sources=277311 |
| #Domains=752002 |
|
|