--- /dev/null
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.1 2008/11/14 10:03:33 meskes Exp $ */
+
+statements: /*EMPTY*/
+ | statements statement
+ ;
+
+statement: ecpgstart at stmt ';' { connection = NULL; }
+ | ecpgstart stmt ';'
+ | ecpgstart ECPGVarDeclaration
+ {
+ fprintf(yyout, "%s", $2);
+ free($2);
+ output_line_number();
+ }
+ | ECPGDeclaration
+ | c_thing { fprintf(yyout, "%s", $1); free($1); }
+ | CPP_LINE { fprintf(yyout, "%s", $1); free($1); }
+ | '{' { braces_open++; fputs("{", yyout); }
+ | '}' { remove_typedefs(braces_open); remove_variables(braces_open--); fputs("}", 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 SELECT cannot specify INTO\n");
+
+ $$ = cat_str(6, make_str("create"), $2, make_str("table"), $4, make_str("as"), $7);
+ }
+ ;
+
+RuleStmt: CREATE opt_or_replace RULE name AS
+ {QueryIsRule = 1;}
+ ON event TO qualified_name where_clause
+ DO opt_instead RuleActionList
+ {
+ QueryIsRule=0;
+ $$ = cat_str(12, make_str("create"), $2, make_str("rule"), $4, make_str("as on"), $8, make_str("to"), $10, $11, make_str("do"), $13, $14);
+ }
+ ;
+
+at: AT connection_object
+ {
+ connection = $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, make_str(","), $5, make_str(","), $4); }
+ | SQL_CONNECT TO DEFAULT
+ { $$ = make_str("NULL, NULL, NULL, \"DEFAULT\""); }
+ /* also allow ORACLE syntax */
+ | SQL_CONNECT ora_user
+ { $$ = cat_str(3, make_str("NULL,"), $2, make_str(", NULL")); }
+ | DATABASE connection_target
+ { $$ = cat2_str($2, make_str(", 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(make_str("\""), make3_str($1, $2, $3), make_str("\""));
+ }
+ | 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(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6), $7, make_str("\"")));
+ }
+ | char_variable
+ {
+ $$ = $1;
+ }
+ | ecpg_sconst
+ {
+ /* We can only process double quoted strings not single quotes ones,
+ * so we change the quotes.
+ * Note, that the rule for ecpg_sconst adds these single quotes. */
+ $1[0] = '\"';
+ $1[strlen($1)-1] = '\"';
+ $$ = $1;
+ }
+ ;
+
+opt_database_name: database_name { $$ = $1; }
+ | /*EMPTY*/ { $$ = 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, "illegal connection type %s", $1);
+
+ $$ = make3_str($1, make_str(":"), $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 { $$ = $1; }
+ | /*EMPTY*/ { $$ = EMPTY; }
+ ;
+
+server_name: ColId { $$ = $1; }
+ | ColId '.' server_name { $$ = make3_str($1, make_str("."), $3); }
+ | IP { $$ = make_name(); }
+ ;
+
+opt_port: ':' Iconst { $$ = make2_str(make_str(":"), $2); }
+ | /*EMPTY*/ { $$ = EMPTY; }
+ ;
+
+opt_connection_name: AS connection_object { $$ = $2; }
+ | /*EMPTY*/ { $$ = make_str("NULL"); }
+ ;
+
+opt_user: USER ora_user { $$ = $2; }
+ | /*EMPTY*/ { $$ = make_str("NULL, NULL"); }
+ ;
+
+ora_user: user_name
+ { $$ = cat2_str($1, make_str(", NULL")); }
+ | user_name '/' user_name
+ { $$ = cat_str(3, $1, make_str(","), $3); }
+ | user_name SQL_IDENTIFIED BY user_name
+ { $$ = cat_str(3, $1, make_str(","), $4); }
+ | user_name USING user_name
+ { $$ = cat_str(3, $1, make_str(","), $3); }
+ ;
+
+user_name: RoleId
+ {
+ if ($1[0] == '\"')
+ $$ = $1;
+ else
+ $$ = make3_str(make_str("\""), $1, make_str("\""));
+ }
+ | ecpg_sconst
+ {
+ if ($1[0] == '\"')
+ $$ = $1;
+ else
+ $$ = make3_str(make_str("\""), $1, make_str("\""));
+ }
+ | 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(mm_strdup(argsinsert->variable->name), make_str(".arr"));
+ else
+ $$ = mm_strdup(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 datatype");
+ 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:
+ $$ = $1;
+ break;
+ case ECPGt_varchar:
+ $$ = make2_str($1, make_str(".arr"));
+ break;
+ default:
+ mmerror(PARSE_ERROR, ET_ERROR, "invalid datatype");
+ $$ = $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(make_str("?"), $2);
+ }
+ | /*EMPTY*/ { $$ = 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);
+
+ $$ = cat_str(3, make2_str($1, $2), $3, $4);
+ }
+ ;
+
+opt_opt_value: /*EMPTY*/
+ { $$ = EMPTY; }
+ | '=' Iconst
+ { $$ = make2_str(make_str("="), $2); }
+ | '=' ecpg_ident
+ { $$ = make2_str(make_str("="), $2); }
+ | '=' civar
+ { $$ = make2_str(make_str("="), $2); }
+ ;
+
+prepared_name: name {
+ if ($1[0] == '\"' && $1[strlen($1)-1] == '\"') /* already quoted? */
+ $$ = $1;
+ else /* not quoted => convert to lowercase */
+ {
+ int i;
+
+ for (i = 0; i< strlen($1); i++)
+ $1[i] = tolower((unsigned char) $1[i]);
+
+ $$ = make3_str(make_str("\""), $1, make_str("\""));
+ }
+ }
+ | char_variable { $$ = $1; }
+ ;
+
+/*
+ * Declare a prepared cursor. The syntax is different from the standard
+ * declare statement, so we create a new rule.
+ */
+ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
+ {
+ struct cursor *ptr, *this;
+ struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+ const char *con = connection ? connection : "NULL";
+
+ for (ptr = cur; ptr != NULL; ptr = ptr->next)
+ {
+ if (strcmp($2, ptr->name) == 0)
+ /* re-definition is a bug */
+ mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" already defined", $2);
+ }
+
+ this = (struct cursor *) mm_alloc(sizeof(struct cursor));
+
+ /* initial definition */
+ this->next = cur;
+ this->name = $2;
+ this->connection = connection;
+ this->command = cat_str(6, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for $1"));
+ this->argsresult = 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;
+ add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
+
+ cur = this;
+
+ $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
+ }
+ ;
+
+ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring
+ {
+ /* execute immediate means prepare the statement and
+ * immediately execute it */
+ $$ = $3;
+ };
+/*
+ * variable decalartion outside exec sql declare block
+ */
+ECPGVarDeclaration: single_vt_declaration;
+
+single_vt_declaration: type_declaration { $$ = $1; }
+ | var_declaration { $$ = $1; }
+ ;
+
+precision: NumericOnly { $$ = $1; };
+
+opt_scale: ',' NumericOnly { $$ = $2; }
+ | /* EMPTY */ { $$ = EMPTY; }
+ ;
+
+ecpg_interval: opt_interval { $$ = $1; }
+ | YEAR_P TO MINUTE_P { $$ = make_str("year to minute"); }
+ | YEAR_P TO SECOND_P { $$ = make_str("year to second"); }
+ | DAY_P TO DAY_P { $$ = make_str("day to day"); }
+ | MONTH_P TO MONTH_P { $$ = make_str("month to month"); }
+ ;
+
+/*
+ * variable declaration inside exec sql declare block
+ */
+ECPGDeclaration: sql_startdeclare
+ { fputs("/* exec sql begin declare section */", yyout); }
+ var_type_declarations sql_enddeclare
+ {
+ fprintf(yyout, "%s/* exec sql end declare section */", $3);
+ free($3);
+ output_line_number();
+ }
+ ;
+
+sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' {};
+
+sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' {};
+
+var_type_declarations: /*EMPTY*/ { $$ = EMPTY; }
+ | vt_declarations { $$ = $1; }
+ | CPP_LINE { $$ = $1; }
+ ;
+
+vt_declarations: var_declaration { $$ = $1; }
+ | type_declaration { $$ = $1; }
+ | vt_declarations var_declaration { $$ = cat2_str($1, $2); }
+ | vt_declarations type_declaration { $$ = cat2_str($1, $2); }
+ | vt_declarations CPP_LINE { $$ = cat2_str($1, $2); }
+ ;
+
+variable_declarations: var_declaration { $$ = $1; }
+ | variable_declarations var_declaration { $$ = cat2_str($1, $2); }
+ ;
+
+type_declaration: S_TYPEDEF
+ {
+ /* reset this variable so we see if there was */
+ /* an initializer specified */
+ initializer = 0;
+ }
+ var_type opt_pointer ECPGColLabelCommon opt_array_bounds ';'
+ {
+ add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0);
+
+ fprintf(yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str);
+ output_line_number();
+ $$ = make_str("");
+ };
+
+var_declaration: storage_declaration
+ var_type
+ {
+ actual_type[struct_level].type_enum = $2.type_enum;
+ 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, make_str(";\n"));
+ }
+ | var_type
+ {
+ actual_type[struct_level].type_enum = $1.type_enum;
+ 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, make_str(";\n"));
+ }
+ | struct_union_type_with_symbol ';'
+ {
+ $$ = cat2_str($1, make_str(";"));
+ }
+ ;
+
+opt_bit_field: ':' Iconst { $$ =cat2_str(make_str(":"), $2); }
+ | /* EMPTY */ { $$ = EMPTY; }
+ ;
+
+storage_declaration: storage_clause storage_modifier
+ {$$ = cat2_str ($1, $2); }
+ | storage_clause {$$ = $1; }
+ | storage_modifier {$$ = $1; }
+ ;
+
+storage_clause : S_EXTERN { $$ = make_str("extern"); }
+ | S_STATIC { $$ = make_str("static"); }
+ | S_REGISTER { $$ = make_str("register"); }
+ | S_AUTO { $$ = make_str("auto"); }
+ ;
+
+storage_modifier : S_CONST { $$ = make_str("const"); }
+ | S_VOLATILE { $$ = make_str("volatile"); }
+ ;
+
+var_type: simple_type
+ {
+ $$.type_enum = $1;
+ $$.type_str = mm_strdup(ecpg_type_name($1));
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ | struct_union_type
+ {
+ $$.type_str = $1;
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-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 = $1;
+ $$.type_enum = ECPGt_int;
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ | ECPGColLabelCommon '(' precision opt_scale ')'
+ {
+ if (strcmp($1, "numeric") == 0)
+ {
+ $$.type_enum = ECPGt_numeric;
+ $$.type_str = make_str("numeric");
+ }
+ else if (strcmp($1, "decimal") == 0)
+ {
+ $$.type_enum = ECPGt_decimal;
+ $$.type_str = make_str("decimal");
+ }
+ else
+ {
+ mmerror(PARSE_ERROR, ET_ERROR, "only numeric/decimal have precision/scale argument");
+ $$.type_enum = ECPGt_numeric;
+ $$.type_str = make_str("numeric");
+ }
+
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ | ECPGColLabelCommon ecpg_interval
+ {
+ if (strlen($2) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0)
+ mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here");
+
+ /*
+ * Check for type names that the SQL grammar treats as
+ * unreserved keywords
+ */
+ if (strcmp($1, "varchar") == 0)
+ {
+ $$.type_enum = ECPGt_varchar;
+ $$.type_str = EMPTY; /*make_str("varchar");*/
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "float") == 0)
+ {
+ $$.type_enum = ECPGt_float;
+ $$.type_str = make_str("float");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "double") == 0)
+ {
+ $$.type_enum = ECPGt_double;
+ $$.type_str = make_str("double");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "numeric") == 0)
+ {
+ $$.type_enum = ECPGt_numeric;
+ $$.type_str = make_str("numeric");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "decimal") == 0)
+ {
+ $$.type_enum = ECPGt_decimal;
+ $$.type_str = make_str("decimal");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "date") == 0)
+ {
+ $$.type_enum = ECPGt_date;
+ $$.type_str = make_str("date");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "timestamp") == 0)
+ {
+ $$.type_enum = ECPGt_timestamp;
+ $$.type_str = make_str("timestamp");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "interval") == 0)
+ {
+ $$.type_enum = ECPGt_interval;
+ $$.type_str = make_str("interval");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else if (strcmp($1, "datetime") == 0)
+ {
+ $$.type_enum = ECPGt_timestamp;
+ $$.type_str = make_str("timestamp");
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = NULL;
+ }
+ else
+ {
+ /* this is for typedef'ed types */
+ struct typedefs *this = get_typedef($1);
+
+ $$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : 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, make_str("sizeof("), mm_strdup(this->name), make_str(")"));
+
+ 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);
+ $$.type_str = mm_strdup(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;
+ struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
+ free(name);
+ }
+ else
+ {
+ $$.type_str = name;
+ $$.type_enum = ECPGt_long;
+ $$.type_dimension = make_str("-1");
+ $$.type_index = make_str("-1");
+ $$.type_sizeof = make_str("");
+ struct_member_list[struct_level] = NULL;
+ }
+ }
+ ;
+
+enum_type: ENUM_P symbol enum_definition
+ { $$ = cat_str(3, make_str("enum"), $2, $3); }
+ | ENUM_P enum_definition
+ { $$ = cat2_str(make_str("enum"), $2); }
+ | ENUM_P symbol
+ { $$ = cat2_str(make_str("enum"), $2); }
+ ;
+
+enum_definition: '{' c_list '}'
+ { $$ = cat_str(3, make_str("{"), $2, make_str("}")); };
+
+struct_union_type_with_symbol: s_struct_union_symbol
+ {
+ 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 (strncmp($1.su, "struct", sizeof("struct")-1) == 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 essantially 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\" 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_enum = su_type.type_enum;
+ this->type->type_str = mm_strdup(su_type.type_str);
+ this->type->type_dimension = make_str("-1"); /* dimension of array */
+ this->type->type_index = make_str("-1"); /* length of string */
+ this->type->type_sizeof = ECPGstruct_sizeof;
+ this->struct_member_list = struct_member_list[struct_level];
+
+ types = this;
+ $$ = cat_str(4, su_type.type_str, make_str("{"), $4, make_str("}"));
+ }
+ ;
+
+struct_union_type: struct_union_type_with_symbol { $$ = $1; }
+ | s_struct_union
+ {
+ 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, make_str("{"), $4, make_str("}"));
+ }
+ ;
+
+s_struct_union_symbol: SQL_STRUCT symbol
+ {
+ $$.su = make_str("struct");
+ $$.symbol = $2;
+ ECPGstruct_sizeof = cat_str(3, make_str("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), make_str(")"));
+ }
+ | UNION symbol
+ {
+ $$.su = make_str("union");
+ $$.symbol = $2;
+ }
+ ;
+
+s_struct_union: SQL_STRUCT
+ {
+ ECPGstruct_sizeof = make_str(""); /* This must not be NULL to distinguish from simple types. */
+ $$ = make_str("struct");
+ }
+ | UNION { $$ = make_str("union"); }
+ ;
+
+simple_type: unsigned_type { $$=$1; }
+ | 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
+ {
+#ifdef HAVE_LONG_LONG_INT_64
+ $$ = ECPGt_unsigned_long_long;
+#else
+ $$ = ECPGt_unsigned_long;
+#endif
+ }
+ | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P
+ {
+#ifdef HAVE_LONG_LONG_INT_64
+ $$ = ECPGt_unsigned_long_long;
+#else
+ $$ = ECPGt_unsigned_long;
+#endif
+ }
+ | 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
+ {
+#ifdef HAVE_LONG_LONG_INT_64
+ $$ = ECPGt_long_long;
+#else
+ $$ = ECPGt_long;
+#endif
+ }
+ | SQL_LONG SQL_LONG INT_P
+ {
+#ifdef HAVE_LONG_LONG_INT_64
+ $$ = ECPGt_long_long;
+#else
+ $$ = ECPGt_long;
+#endif
+ }
+ | SQL_BOOL { $$ = ECPGt_bool; }
+ | CHAR_P { $$ = ECPGt_char; }
+ | DOUBLE_P { $$ = ECPGt_double; }
+ ;
+
+opt_signed: SQL_SIGNED
+ | /* EMPTY */
+ ;
+
+variable_list: variable
+ { $$ = $1; }
+ | variable_list ',' variable
+ { $$ = cat_str(3, $1, make_str(","), $3); }
+ ;
+
+variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer
+ {
+ struct ECPGtype * type;
+ char *dimension = $3.index1; /* dimension of array */
+ char *length = $3.index2; /* length of string */
+ char dim[14L];
+ char *vcn;
+
+ 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_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_sizeof), dimension);
+
+ $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
+ break;
+
+ case ECPGt_varchar:
+ if (atoi(dimension) < 0)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, yylineno);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, yylineno), dimension);
+
+ if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1)
+ *dim = '\0';
+ else
+ sprintf(dim, "[%s]", 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, "pointer to varchar are not implemented");
+
+ /* make sure varchar struct name is unique by adding linenumer of its definition */
+ vcn = (char *) mm_alloc(strlen($2) + sizeof(int) * CHAR_BIT * 10 / 3);
+ sprintf(vcn, "%s_%d", $2, yylineno);
+ if (strcmp(dimension, "0") == 0)
+ $$ = cat_str(7, make2_str(make_str(" struct varchar_"), vcn), make_str(" { int len; char arr["), mm_strdup(length), make_str("]; } *"), mm_strdup($2), $4, $5);
+ else
+ $$ = cat_str(8, make2_str(make_str(" struct varchar_"), vcn), make_str(" { int len; char arr["), mm_strdup(length), make_str("]; } "), mm_strdup($2), mm_strdup(dim), $4, $5);
+ break;
+
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ 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 */
+ free(length);
+ length = mm_alloc(i+sizeof("sizeof()"));
+ sprintf(length, "sizeof(%s)", $5+2);
+ }
+ 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, mm_strdup($2), $3.str, $4, $5);
+ break;
+
+ default:
+ if (atoi(dimension) < 0)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, make_str("1"), 0);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, make_str("1"), 0), dimension);
+
+ $$ = cat_str(5, $1, mm_strdup($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]));
+
+ free($2);
+ }
+ ;
+
+opt_initializer: /*EMPTY*/
+ { $$ = EMPTY; }
+ | '=' c_term
+ {
+ initializer = 1;
+ $$ = cat2_str(make_str("="), $2);
+ }
+ ;
+
+opt_pointer: /*EMPTY*/ { $$ = EMPTY; }
+ | '*' { $$ = make_str("*"); }
+ | '*' '*' { $$ = make_str("**"); }
+ ;
+
+/*
+ * 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, make_str("/* declare statement"), $3, make_str("*/"));
+ }
+ ;
+/*
+ * the exec sql disconnect statement: disconnect from the given database
+ */
+ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
+ ;
+
+dis_name: connection_object { $$ = $1; }
+ | CURRENT_P { $$ = make_str("\"CURRENT\""); }
+ | ALL { $$ = make_str("\"ALL\""); }
+ | /* EMPTY */ { $$ = make_str("\"CURRENT\""); }
+ ;
+
+connection_object: database_name { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+ | DEFAULT { $$ = make_str("\"DEFAULT\""); }
+ | char_variable { $$ = $1; }
+ ;
+
+execstring: char_variable
+ { $$ = $1; }
+ | CSTRING
+ { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+ ;
+
+/*
+ * the exec sql free command to deallocate a previously
+ * prepared statement
+ */
+ECPGFree: SQL_FREE name { $$ = $2; }
+ | SQL_FREE ALL { $$ = make_str("all"); }
+ ;
+
+/*
+ * open is an open cursor, at the moment this has to be removed
+ */
+ECPGOpen: SQL_OPEN name opt_ecpg_using { $$ = $2; };
+
+opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; }
+ | ecpg_using { $$ = $1; }
+ ;
+
+ecpg_using: USING using_list { $$ = EMPTY; }
+ | using_descriptor { $$ = $1; }
+ ;
+
+using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
+ {
+ add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
+ $$ = EMPTY;
+ }
+ ;
+
+into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
+ {
+ add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
+ $$ = EMPTY;
+ }
+ ;
+
+opt_sql: /*EMPTY*/ | SQL_SQL;
+
+using_list: UsingValue | UsingValue ',' using_list;
+
+UsingValue: UsingConst
+ {
+ char *length = mm_alloc(32);
+
+ sprintf(length, "%d", (int) strlen($1));
+ add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
+ }
+ | civar { $$ = EMPTY; }
+ | civarind { $$ = EMPTY; }
+ ;
+
+UsingConst: Iconst { $$ = $1; }
+ | ecpg_fconst { $$ = $1; }
+ | ecpg_sconst { $$ = $1; }
+ | ecpg_bconst { $$ = $1; }
+ | ecpg_xconst { $$ = $1; }
+ ;
+
+/*
+ * We accept descibe but do nothing with it so far.
+ */
+ECPGDescribe: SQL_DESCRIBE INPUT_P name using_descriptor
+ {
+ const char *con = connection ? connection : "NULL";
+ mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n");
+ $$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+ sprintf($$, "1, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
+ }
+ | SQL_DESCRIBE opt_output name using_descriptor
+ {
+ const char *con = connection ? connection : "NULL";
+ mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n");
+ $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+ sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
+ }
+ | SQL_DESCRIBE opt_output name into_descriptor
+ {
+ const char *con = connection ? connection : "NULL";
+ mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n");
+ $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+ sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
+ }
+ ;
+
+opt_output: SQL_OUTPUT { $$ = make_str("output"); }
+ | /* EMPTY */ { $$ = EMPTY; }
+ ;
+
+/*
+ * dynamic SQL: descriptor based access
+ * originall 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 = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+
+ sprintf(length, "%d", (int) strlen($1));
+ new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+ $$ = $1;
+ }
+ | cvariable { $$ = $1; }
+ ;
+
+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 = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+
+ sprintf(length, "%d", (int) strlen($1));
+ new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+ $$ = $1;
+ }
+ | IntConstVar { $$ = $1; }
+ | '-' ecpg_fconst
+ {
+ char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+ char *var = cat2_str(make_str("-"), $2);
+
+ sprintf(length, "%d", (int) strlen(var));
+ new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+ $$ = var;
+ }
+ | '-' Iconst
+ {
+ char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+ char *var = cat2_str(make_str("-"), $2);
+
+ sprintf(length, "%d", (int) strlen(var));
+ new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+ $$ = var;
+ }
+ | ecpg_sconst
+ {
+ char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+ char *var = $1 + 1;
+
+ var[strlen(var) - 1] = '\0';
+ sprintf(length, "%d", (int) 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 differnet handling
+ * as the other set commands
+ */
+ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off { $$ = $4; }
+ | SET SQL_AUTOCOMMIT TO on_off { $$ = $4; }
+ ;
+
+on_off: ON { $$ = make_str("on"); }
+ | OFF { $$ = make_str("off"); }
+ ;
+
+/*
+ * set the actual connection, this needs a differnet 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;
+ }
+ ECPGColLabelCommon 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, make_str("/* exec sql type"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/"));
+ else
+ $$ = cat_str(6, make_str("typedef "), mm_strdup($5.type_str), *$7?make_str("*"):make_str(""), mm_strdup($6.str), mm_strdup($3), make_str(";"));
+ }
+ ;
+
+opt_reference: SQL_REFERENCE { $$ = make_str("reference"); }
+ | /*EMPTY*/ { $$ = 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);
+ char *dimension = $6.index1;
+ 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_sizeof);
+ else
+ type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum,$5.type_sizeof), dimension);
+ break;
+
+ case ECPGt_varchar:
+ 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:
+ 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, "no multidimensional array support for simple data types");
+
+ if (atoi(dimension) < 0)
+ type = ECPGmake_simple_type($5.type_enum, make_str("1"), 0);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, make_str("1"), 0), dimension);
+ break;
+ }
+
+ ECPGfree_type(p->type);
+ p->type = type;
+ }
+
+ $$ = cat_str(7, make_str("/* exec sql var"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/"));
+ }
+ ;
+
+/*
+ * 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 = $<action>3.code;
+ when_error.command = $<action>3.command;
+ $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */"));
+ }
+ | SQL_WHENEVER NOT SQL_FOUND action
+ {
+ when_nf.code = $<action>4.code;
+ when_nf.command = $<action>4.command;
+ $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */"));
+ }
+ | SQL_WHENEVER SQL_SQLWARNING action
+ {
+ when_warn.code = $<action>3.code;
+ when_warn.command = $<action>3.command;
+ $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */"));
+ }
+ ;
+
+action : CONTINUE_P
+ {
+ $<action>$.code = W_NOTHING;
+ $<action>$.command = NULL;
+ $<action>$.str = make_str("continue");
+ }
+ | SQL_SQLPRINT
+ {
+ $<action>$.code = W_SQLPRINT;
+ $<action>$.command = NULL;
+ $<action>$.str = make_str("sqlprint");
+ }
+ | SQL_STOP
+ {
+ $<action>$.code = W_STOP;
+ $<action>$.command = NULL;
+ $<action>$.str = make_str("stop");
+ }
+ | SQL_GOTO name
+ {
+ $<action>$.code = W_GOTO;
+ $<action>$.command = strdup($2);
+ $<action>$.str = cat2_str(make_str("goto "), $2);
+ }
+ | SQL_GO TO name
+ {
+ $<action>$.code = W_GOTO;
+ $<action>$.command = strdup($3);
+ $<action>$.str = cat2_str(make_str("goto "), $3);
+ }
+ | DO name '(' c_args ')'
+ {
+ $<action>$.code = W_DO;
+ $<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
+ $<action>$.str = cat2_str(make_str("do"), mm_strdup($<action>$.command));
+ }
+ | DO SQL_BREAK
+ {
+ $<action>$.code = W_BREAK;
+ $<action>$.command = NULL;
+ $<action>$.str = make_str("break");
+ }
+ | SQL_CALL name '(' c_args ')'
+ {
+ $<action>$.code = W_DO;
+ $<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
+ $<action>$.str = cat2_str(make_str("call"), mm_strdup($<action>$.command));
+ }
+ | SQL_CALL name
+ {
+ $<action>$.code = W_DO;
+ $<action>$.command = cat2_str($2, make_str("()"));
+ $<action>$.str = cat2_str(make_str("call"), mm_strdup($<action>$.command));
+ }
+ ;
+
+/* some other stuff for ecpg */
+
+/* additional unreserved keywords */
+ECPGKeywords: ECPGKeywords_vanames { $$ = $1; }
+ | ECPGKeywords_rest { $$ = $1; }
+ ;
+
+ECPGKeywords_vanames: SQL_BREAK { $$ = make_str("break"); }
+ | SQL_CALL { $$ = make_str("call"); }
+ | SQL_CARDINALITY { $$ = make_str("cardinality"); }
+ | SQL_COUNT { $$ = make_str("count"); }
+ | SQL_DATETIME_INTERVAL_CODE { $$ = make_str("datetime_interval_code"); }
+ | SQL_DATETIME_INTERVAL_PRECISION { $$ = make_str("datetime_interval_precision"); }
+ | SQL_FOUND { $$ = make_str("found"); }
+ | SQL_GO { $$ = make_str("go"); }
+ | SQL_GOTO { $$ = make_str("goto"); }
+ | SQL_IDENTIFIED { $$ = make_str("identified"); }
+ | SQL_INDICATOR { $$ = make_str("indicator"); }
+ | SQL_KEY_MEMBER { $$ = make_str("key_member"); }
+ | SQL_LENGTH { $$ = make_str("length"); }
+ | SQL_NULLABLE { $$ = make_str("nullable"); }
+ | SQL_OCTET_LENGTH { $$ = make_str("octet_length"); }
+ | SQL_RETURNED_LENGTH { $$ = make_str("returned_length"); }
+ | SQL_RETURNED_OCTET_LENGTH { $$ = make_str("returned_octet_length"); }
+ | SQL_SCALE { $$ = make_str("scale"); }
+ | SQL_SECTION { $$ = make_str("section"); }
+ | SQL_SQL { $$ = make_str("sql"); }
+ | SQL_SQLERROR { $$ = make_str("sqlerror"); }
+ | SQL_SQLPRINT { $$ = make_str("sqlprint"); }
+ | SQL_SQLWARNING { $$ = make_str("sqlwarning"); }
+ | SQL_STOP { $$ = make_str("stop"); }
+ ;
+
+ECPGKeywords_rest: SQL_CONNECT { $$ = make_str("connect"); }
+ | SQL_DESCRIBE { $$ = make_str("describe"); }
+ | SQL_DISCONNECT { $$ = make_str("disconnect"); }
+ | SQL_OPEN { $$ = make_str("open"); }
+ | SQL_VAR { $$ = make_str("var"); }
+ | SQL_WHENEVER { $$ = make_str("whenever"); }
+ ;
+
+/* additional keywords that can be SQL type names (but not ECPGColLabels) */
+ECPGTypeName: SQL_BOOL { $$ = make_str("bool"); }
+ | SQL_LONG { $$ = make_str("long"); }
+ | SQL_OUTPUT { $$ = make_str("output"); }
+ | SQL_SHORT { $$ = make_str("short"); }
+ | SQL_STRUCT { $$ = make_str("struct"); }
+ | SQL_SIGNED { $$ = make_str("signed"); }
+ | SQL_UNSIGNED { $$ = make_str("unsigned"); }
+ ;
+
+symbol: ColLabel { $$ = $1; }
+ ;
+
+ECPGColId: ecpg_ident { $$ = $1; }
+ | ECPGunreserved_interval { $$ = $1; }
+ | ECPGunreserved_con { $$ = $1; }
+ | col_name_keyword { $$ = $1; }
+ | ECPGKeywords { $$ = $1; }
+ | ECPGCKeywords { $$ = $1; }
+ | CHAR_P { $$ = make_str("char"); }
+ | VALUES { $$ = make_str("values"); }
+ ;
+/* Column label --- allowed labels in "AS" clauses.
+ * This presently includes *all* Postgres keywords.
+ */
+ColLabel: ECPGColLabel { $$ = $1; }
+ | ECPGTypeName { $$ = $1; }
+ | CHAR_P { $$ = make_str("char"); }
+ | INPUT_P { $$ = make_str("input"); }
+ | INT_P { $$ = make_str("int"); }
+ | UNION { $$ = make_str("union"); }
+ | TO { $$ = make_str("to"); }
+ | ECPGCKeywords { $$ = $1; }
+ | ECPGunreserved_interval { $$ = $1; }
+ ;
+
+ECPGColLabelCommon: ecpg_ident { $$ = $1; }
+ | col_name_keyword { $$ = $1; }
+ | type_func_name_keyword { $$ = $1; }
+ | ECPGKeywords_vanames { $$ = $1; }
+ ;
+
+ECPGColLabel: ECPGColLabelCommon { $$ = $1; }
+ | reserved_keyword { $$ = $1; }
+ | ECPGunreserved { $$ = $1; }
+ | ECPGKeywords_rest { $$ = $1; }
+ ;
+
+ECPGCKeywords: S_AUTO { $$ = make_str("auto"); }
+ | S_CONST { $$ = make_str("const"); }
+ | S_EXTERN { $$ = make_str("extern"); }
+ | S_REGISTER { $$ = make_str("register"); }
+ | S_STATIC { $$ = make_str("static"); }
+ | S_TYPEDEF { $$ = make_str("typedef"); }
+ | S_VOLATILE { $$ = make_str("volatile"); }
+ ;
+
+/*
+ * Keyword classification lists. Generally, every keyword present in
+ * the Postgres grammar should appear in exactly one of these lists.
+ *
+ * Put a new keyword into the first list that it can go into without causing
+ * shift or reduce conflicts. The earlier lists define "less reserved"
+ * categories of keywords.
+ */
+
+/* "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
+ */
+unreserved_keyword: ECPGunreserved_interval | ECPGunreserved;
+
+ECPGunreserved_interval: DAY_P { $$ = make_str("day"); }
+ | HOUR_P { $$ = make_str("hour"); }
+ | MINUTE_P { $$ = make_str("minute"); }
+ | MONTH_P { $$ = make_str("month"); }
+ | SECOND_P { $$ = make_str("second"); }
+ | YEAR_P { $$ = make_str("year"); }
+ ;
+
+/* The following symbol must be excluded from var_name but still included in ColId
+ to enable ecpg special postgresql variables with this name: CONNECTION
+ */
+ECPGunreserved: ECPGunreserved_con { $$ = $1; }
+ | CONNECTION { $$ = make_str("connection"); }
+ ;
+
+ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); }
+ | ABSOLUTE_P { $$ = make_str("absolute"); }
+ | ACCESS { $$ = make_str("access"); }
+ | ACTION { $$ = make_str("action"); }
+ | ADD_P { $$ = make_str("add"); }
+ | ADMIN { $$ = make_str("admin"); }
+ | AFTER { $$ = make_str("after"); }
+ | AGGREGATE { $$ = make_str("aggregate"); }
+ | ALSO { $$ = make_str("also"); }
+ | ALTER { $$ = make_str("alter"); }
+ | ALWAYS { $$ = make_str("always"); }
+ | ASSERTION { $$ = make_str("assertion"); }
+ | ASSIGNMENT { $$ = make_str("assignment"); }
+ | AT { $$ = make_str("at"); }
+ | BACKWARD { $$ = make_str("backward"); }
+ | BEFORE { $$ = make_str("before"); }
+ | BEGIN_P { $$ = make_str("begin"); }
+ | BY { $$ = make_str("by"); }
+ | CACHE { $$ = make_str("cache"); }
+ | CASCADE { $$ = make_str("cascade"); }
+ | CASCADED { $$ = make_str("cascaded"); }
+ | CHAIN { $$ = make_str("chain"); }
+ | CHARACTERISTICS { $$ = make_str("characteristics"); }
+ | CHECKPOINT { $$ = make_str("checkpoint"); }
+ | CLASS { $$ = make_str("class"); }
+ | CLOSE { $$ = make_str("close"); }
+ | CLUSTER { $$ = make_str("cluster"); }
+ | COMMENT { $$ = make_str("comment"); }
+ | COMMIT { $$ = make_str("commit"); }
+ | COMMITTED { $$ = make_str("committed"); }
+ | CONCURRENTLY { $$ = make_str("concurrently"); }
+ | CONFIGURATION { $$ = make_str("configuration"); }
+/* | CONNECTION { $$ = make_str("connection"); }*/
+ | CONSTRAINTS { $$ = make_str("constraints"); }
+ | CONTENT_P { $$ = make_str("content"); }
+ | CONTINUE_P { $$ = make_str("continue"); }
+ | CONVERSION_P { $$ = make_str("conversion"); }
+ | COPY { $$ = make_str("copy"); }
+ | COST { $$ = make_str("cost"); }
+ | CREATEDB { $$ = make_str("createdb"); }
+ | CREATEROLE { $$ = make_str("createrole"); }
+ | CREATEUSER { $$ = make_str("createuser"); }
+ | CSV { $$ = make_str("csv"); }
+ | CTYPE { $$ = make_str("ctype"); }
+ | CURSOR { $$ = make_str("cursor"); }
+ | CYCLE { $$ = make_str("cycle"); }
+ | DATA_P { $$ = make_str("data"); }
+ | DATABASE { $$ = make_str("database"); }
+/* | DAY_P { $$ = make_str("day"); }*/
+ | DEALLOCATE { $$ = make_str("deallocate"); }
+ | DECLARE { $$ = make_str("declare"); }
+ | DEFAULTS { $$ = make_str("defaults"); }
+ | DEFERRED { $$ = make_str("deferred"); }
+ | DELETE_P { $$ = make_str("delete"); }
+ | DELIMITER { $$ = make_str("delimiter"); }
+ | DELIMITERS { $$ = make_str("delimiters"); }
+ | DICTIONARY { $$ = make_str("dictionary"); }
+ | DISABLE_P { $$ = make_str("disable"); }
+ | DISCARD { $$ = make_str("discard"); }
+ | DOCUMENT_P { $$ = make_str("document"); }
+ | DOMAIN_P { $$ = make_str("domain"); }
+ | DOUBLE_P { $$ = make_str("double"); }
+ | DROP { $$ = make_str("drop"); }
+ | EACH { $$ = make_str("each"); }
+ | ENABLE_P { $$ = make_str("enable"); }
+ | ENCODING { $$ = make_str("encoding"); }
+ | ENCRYPTED { $$ = make_str("encrypted"); }
+/* | ENUM_P { $$ = make_str("enum"); }*/
+ | ESCAPE { $$ = make_str("escape"); }
+ | EXCLUDING { $$ = make_str("excluding"); }
+ | EXCLUSIVE { $$ = make_str("exclusive"); }
+ | EXECUTE { $$ = make_str("execute"); }
+ | EXPLAIN { $$ = make_str("explain"); }
+ | EXTERNAL { $$ = make_str("external"); }
+ | FAMILY { $$ = make_str("family"); }
+/* | FETCH { $$ = make_str("fetch"); }*/
+ | FIRST_P { $$ = make_str("first"); }
+ | FORCE { $$ = make_str("force"); }
+ | FORWARD { $$ = make_str("forward"); }
+ | FUNCTION { $$ = make_str("function"); }
+ | GLOBAL { $$ = make_str("global"); }
+ | GRANTED { $$ = make_str("granted"); }
+ | HANDLER { $$ = make_str("handler"); }
+ | HEADER_P { $$ = make_str("header"); }
+ | HOLD { $$ = make_str("hold"); }
+/* | HOUR_P { $$ = make_str("hour"); }*/
+ | IDENTITY_P { $$ = make_str("identity"); }
+ | IF_P { $$ = make_str("if"); }
+ | IMMEDIATE { $$ = make_str("immediate"); }
+ | IMMUTABLE { $$ = make_str("immutable"); }
+ | IMPLICIT_P { $$ = make_str("implicit"); }
+ | INCLUDING { $$ = make_str("including"); }
+ | INCREMENT { $$ = make_str("increment"); }
+ | INDEX { $$ = make_str("index"); }
+ | INDEXES { $$ = make_str("indexes"); }
+ | INHERIT { $$ = make_str("inherit"); }
+ | INHERITS { $$ = make_str("inherits"); }
+ | INSENSITIVE { $$ = make_str("insensitive"); }
+ | INSERT { $$ = make_str("insert"); }
+ | INSTEAD { $$ = make_str("instead"); }
+ | ISOLATION { $$ = make_str("isolation"); }
+ | KEY { $$ = make_str("key"); }
+ | LANCOMPILER { $$ = make_str("lancompiler"); }
+ | LANGUAGE { $$ = make_str("language"); }
+ | LARGE_P { $$ = make_str("large"); }
+ | LAST_P { $$ = make_str("last"); }
+ | LEVEL { $$ = make_str("level"); }
+ | LISTEN { $$ = make_str("listen"); }
+ | LOAD { $$ = make_str("load"); }
+ | LOCAL { $$ = make_str("local"); }
+ | LOCATION { $$ = make_str("location"); }
+ | LOCK_P { $$ = make_str("lock"); }
+ | LOGIN_P { $$ = make_str("login"); }
+ | MAPPING { $$ = make_str("mapping"); }
+ | MATCH { $$ = make_str("match"); }
+ | MAXVALUE { $$ = make_str("maxvalue"); }
+/* | MINUTE_P { $$ = make_str("minute"); }*/
+ | MINVALUE { $$ = make_str("minvalue"); }
+ | MODE { $$ = make_str("mode"); }
+/* | MONTH_P { $$ = make_str("month"); }*/
+ | MOVE { $$ = make_str("move"); }
+ | NAME_P { $$ = make_str("name"); }
+ | NAMES { $$ = make_str("names"); }
+ | NEXT { $$ = make_str("next"); }
+ | NO { $$ = make_str("no"); }
+ | NOCREATEDB { $$ = make_str("nocreatedb"); }
+ | NOCREATEROLE { $$ = make_str("nocreaterole"); }
+ | NOCREATEUSER { $$ = make_str("nocreateuser"); }
+ | NOINHERIT { $$ = make_str("noinherit"); }
+ | NOLOGIN_P { $$ = make_str("nologin"); }
+ | NOSUPERUSER { $$ = make_str("nosuperuser"); }
+ | NOTHING { $$ = make_str("nothing"); }
+ | NOTIFY { $$ = make_str("notify"); }
+ | NOWAIT { $$ = make_str("nowait"); }
+ | NULLS_P { $$ = make_str("nulls"); }
+ | OBJECT_P { $$ = make_str("object"); }
+ | OF { $$ = make_str("of"); }
+ | OIDS { $$ = make_str("oids"); }
+ | OPERATOR { $$ = make_str("operator"); }
+ | OPTION { $$ = make_str("option"); }
+ | OWNED { $$ = make_str("owned"); }
+ | OWNER { $$ = make_str("owner"); }
+ | PARSER { $$ = make_str("parser"); }
+ | PARTIAL { $$ = make_str("partial"); }
+ | PASSWORD { $$ = make_str("password"); }
+ | PLANS { $$ = make_str("plans"); }
+ | PREPARE { $$ = make_str("prepare"); }
+ | PREPARED { $$ = make_str("prepared"); }
+ | PRESERVE { $$ = make_str("preserver"); }
+ | PRIOR { $$ = make_str("prior"); }
+ | PRIVILEGES { $$ = make_str("privileges"); }
+ | PROCEDURAL { $$ = make_str("procedural"); }
+ | PROCEDURE { $$ = make_str("procedure"); }
+ | QUOTE { $$ = make_str("quote"); }
+ | READ { $$ = make_str("read"); }
+ | REASSIGN { $$ = make_str("reassign"); }
+ | RECHECK { $$ = make_str("recheck"); }
+ | RECURSIVE { $$ = make_str("recursive"); }
+ | REINDEX { $$ = make_str("reindex"); }
+ | RELATIVE_P { $$ = make_str("relative"); }
+ | RELEASE { $$ = make_str("release"); }
+ | RENAME { $$ = make_str("rename"); }
+ | REPEATABLE { $$ = make_str("repeatable"); }
+ | REPLACE { $$ = make_str("replace"); }
+ | REPLICA { $$ = make_str("replica"); }
+ | RESET { $$ = make_str("reset"); }
+ | RESTART { $$ = make_str("restart"); }
+ | RESTRICT { $$ = make_str("restrict"); }
+ | RETURNS { $$ = make_str("returns"); }
+ | REVOKE { $$ = make_str("revoke"); }
+ | ROLE { $$ = make_str("role"); }
+ | ROLLBACK { $$ = make_str("rollback"); }
+ | ROWS { $$ = make_str("rows"); }
+ | RULE { $$ = make_str("rule"); }
+ | SAVEPOINT { $$ = make_str("savepoint"); }
+ | SCHEMA { $$ = make_str("schema"); }
+ | SCROLL { $$ = make_str("scroll"); }
+ | SEARCH { $$ = make_str("search"); }
+/* | SECOND_P { $$ = make_str("second"); }*/
+ | SEQUENCE { $$ = make_str("sequence"); }
+ | SERIALIZABLE { $$ = make_str("serializable"); }
+ | SESSION { $$ = make_str("session"); }
+ | SET { $$ = make_str("set"); }
+ | SHARE { $$ = make_str("share"); }
+ | SHOW { $$ = make_str("show"); }
+ | SIMPLE { $$ = make_str("simple"); }
+ | STABLE { $$ = make_str("stable"); }
+ | STANDALONE_P { $$ = make_str("standalone"); }
+ | START { $$ = make_str("start"); }
+ | STATEMENT { $$ = make_str("statement"); }
+ | STATISTICS { $$ = make_str("statistics"); }
+ | STDIN { $$ = make_str("stdin"); }
+ | STDOUT { $$ = make_str("stdout"); }
+ | STORAGE { $$ = make_str("storage"); }
+ | STRICT_P { $$ = make_str("strict"); }
+ | STRIP_P { $$ = make_str("strip"); }
+ | SUPERUSER_P { $$ = make_str("superuser"); }
+ | SYSTEM_P { $$ = make_str("system"); }
+ | SYSID { $$ = make_str("sysid"); }
+ | TABLESPACE { $$ = make_str("tablespace"); }
+ | TEMP { $$ = make_str("temp"); }
+ | TEMPLATE { $$ = make_str("template"); }
+ | TEMPORARY { $$ = make_str("temporary"); }
+ | TEXT_P { $$ = make_str("text"); }
+ | TRANSACTION { $$ = make_str("transaction"); }
+ | TRIGGER { $$ = make_str("trigger"); }
+ | TRUNCATE { $$ = make_str("truncate"); }
+ | TRUSTED { $$ = make_str("trusted"); }
+ | TYPE_P { $$ = make_str("type"); }
+ | UNCOMMITTED { $$ = make_str("uncommitted"); }
+ | UNENCRYPTED { $$ = make_str("unencrypted"); }
+ | UNKNOWN { $$ = make_str("unknown"); }
+ | UNLISTEN { $$ = make_str("unlisten"); }
+ | UNTIL { $$ = make_str("until"); }
+ | UPDATE { $$ = make_str("update"); }
+ | VACUUM { $$ = make_str("vacuum"); }
+ | VALID { $$ = make_str("valid"); }
+ | VALIDATOR { $$ = make_str("validator"); }
+ | VALUE_P { $$ = make_str("value"); }
+ | VARYING { $$ = make_str("varying"); }
+ | VERSION_P { $$ = make_str("version"); }
+ | VIEW { $$ = make_str("view"); }
+ | VOLATILE { $$ = make_str("volatile"); }
+ | WHITESPACE_P { $$ = make_str("whitespace"); }
+ | WITHOUT { $$ = make_str("without"); }
+ | WORK { $$ = make_str("work"); }
+ | WRITE { $$ = make_str("write"); }
+ | XML_P { $$ = make_str("xml"); }
+ | YES_P { $$ = make_str("yes"); }
+/* | YEAR_P { $$ = make_str("year"); }*/
+ | ZONE { $$ = make_str("zone"); }
+ ;
+
+into_list : coutputvariable | into_list ',' coutputvariable
+ ;
+
+ecpgstart: SQL_START {
+ reset_variables();
+ pacounter = 1;
+ }
+ ;
+
+c_args: /*EMPTY*/ { $$ = EMPTY; }
+ | c_list { $$ = $1; }
+ ;
+
+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);
+ }
+ ;
+
+civar: cvariable
+ {
+ add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
+ $$ = create_questionmarks($1, false);
+ }
+ ;
+
+indicator: cvariable { check_indicator((find_variable($1))->type); $$ = $1; }
+ | 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 */
+ char *ptr = $1;
+ int brace_open=0, brace = false;
+
+ for (; *ptr; ptr++)
+ {
+ switch (*ptr)
+ {
+ case '[':
+ if (brace)
+ mmerror(PARSE_ERROR, ET_FATAL, "no multidimensional array support for simple data types");
+ 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;
+ }
+ }
+ $$ = $1;
+ }
+ ;
+
+ecpg_param: PARAM { $$ = make_name(); } ;
+
+ecpg_bconst: BCONST { $$ = make_name(); } ;
+
+ecpg_fconst: FCONST { $$ = make_name(); } ;
+
+ecpg_sconst:
+ SCONST
+ {
+ /* could have been input as '' or $$ */
+ $$ = (char *)mm_alloc(strlen($1) + 3);
+ $$[0]='\'';
+ strcpy($$+1, $1);
+ $$[strlen($1)+1]='\'';
+ $$[strlen($1)+2]='\0';
+ free($1);
+ }
+ | ECONST
+ {
+ $$ = (char *)mm_alloc(strlen($1) + 4);
+ $$[0]='E';
+ $$[1]='\'';
+ strcpy($$+2, $1);
+ $$[strlen($1)+2]='\'';
+ $$[strlen($1)+3]='\0';
+ free($1);
+ }
+ | NCONST
+ {
+ $$ = (char *)mm_alloc(strlen($1) + 4);
+ $$[0]='N';
+ $$[1]='\'';
+ strcpy($$+2, $1);
+ $$[strlen($1)+2]='\'';
+ $$[strlen($1)+3]='\0';
+ free($1);
+ }
+ | UCONST { $$ = $1; }
+ | DOLCONST { $$ = $1; }
+ ;
+
+ecpg_xconst: XCONST { $$ = make_name(); } ;
+
+ecpg_ident: IDENT { $$ = make_name(); }
+ | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")) }
+ | UIDENT { $$ = $1; }
+ ;
+
+quoted_ident_stringvar: name
+ { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+ | char_variable
+ { $$ = make3_str(make_str("("), $1, make_str(")")); }
+ ;
+
+/*
+ * C stuff
+ */
+
+c_stuff_item: c_anything { $$ = $1; }
+ | '(' ')' { $$ = make_str("()"); }
+ | '(' c_stuff ')'
+ { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+ ;
+
+c_stuff: c_stuff_item { $$ = $1; }
+ | c_stuff c_stuff_item
+ { $$ = cat2_str($1, $2); }
+ ;
+
+c_list: c_term { $$ = $1; }
+ | c_list ',' c_term { $$ = cat_str(3, $1, make_str(","), $3); }
+ ;
+
+c_term: c_stuff { $$ = $1; }
+ | '{' c_list '}' { $$ = cat_str(3, make_str("{"), $2, make_str("}")); }
+ ;
+
+c_thing: c_anything { $$ = $1; }
+ | '(' { $$ = make_str("("); }
+ | ')' { $$ = make_str(")"); }
+ | ',' { $$ = make_str(","); }
+ | ';' { $$ = make_str(";"); }
+ ;
+
+c_anything: ecpg_ident { $$ = $1; }
+ | Iconst { $$ = $1; }
+ | ecpg_fconst { $$ = $1; }
+ | ecpg_sconst { $$ = $1; }
+ | '*' { $$ = make_str("*"); }
+ | '+' { $$ = make_str("+"); }
+ | '-' { $$ = make_str("-"); }
+ | '/' { $$ = make_str("/"); }
+ | '%' { $$ = make_str("%"); }
+ | NULL_P { $$ = make_str("NULL"); }
+ | S_ADD { $$ = make_str("+="); }
+ | S_AND { $$ = make_str("&&"); }
+ | S_ANYTHING { $$ = make_name(); }
+ | S_AUTO { $$ = make_str("auto"); }
+ | S_CONST { $$ = make_str("const"); }
+ | S_DEC { $$ = make_str("--"); }
+ | S_DIV { $$ = make_str("/="); }
+ | S_DOTPOINT { $$ = make_str(".*"); }
+ | S_EQUAL { $$ = make_str("=="); }
+ | S_EXTERN { $$ = make_str("extern"); }
+ | S_INC { $$ = make_str("++"); }
+ | S_LSHIFT { $$ = make_str("<<"); }
+ | S_MEMBER { $$ = make_str("->"); }
+ | S_MEMPOINT { $$ = make_str("->*"); }
+ | S_MOD { $$ = make_str("%="); }
+ | S_MUL { $$ = make_str("*="); }
+ | S_NEQUAL { $$ = make_str("!="); }
+ | S_OR { $$ = make_str("||"); }
+ | S_REGISTER { $$ = make_str("register"); }
+ | S_RSHIFT { $$ = make_str(">>"); }
+ | S_STATIC { $$ = make_str("static"); }
+ | S_SUB { $$ = make_str("-="); }
+ | S_TYPEDEF { $$ = make_str("typedef"); }
+ | S_VOLATILE { $$ = make_str("volatile"); }
+ | SQL_BOOL { $$ = make_str("bool"); }
+ | ENUM_P { $$ = make_str("enum"); }
+ | HOUR_P { $$ = make_str("hour"); }
+ | INT_P { $$ = make_str("int"); }
+ | SQL_LONG { $$ = make_str("long"); }
+ | MINUTE_P { $$ = make_str("minute"); }
+ | MONTH_P { $$ = make_str("month"); }
+ | SECOND_P { $$ = make_str("second"); }
+ | SQL_SHORT { $$ = make_str("short"); }
+ | SQL_SIGNED { $$ = make_str("signed"); }
+ | SQL_STRUCT { $$ = make_str("struct"); }
+ | SQL_UNSIGNED { $$ = make_str("unsigned"); }
+ | YEAR_P { $$ = make_str("year"); }
+ | CHAR_P { $$ = make_str("char"); }
+ | FLOAT_P { $$ = make_str("float"); }
+ | TO { $$ = make_str("to"); }
+ | UNION { $$ = make_str("union"); }
+ | VARCHAR { $$ = make_str("varchar"); }
+ | '[' { $$ = make_str("["); }
+ | ']' { $$ = make_str("]"); }
+ | '=' { $$ = make_str("="); }
+ | ':' { $$ = make_str(":"); }
+ ;
+
+DeallocateStmt: DEALLOCATE prepared_name { $$ = $2; }
+ | DEALLOCATE PREPARE prepared_name { $$ = $3; }
+ | DEALLOCATE ALL { $$ = make_str("all"); }
+ | DEALLOCATE PREPARE ALL { $$ = make_str("all"); }
+ ;
+
+Iresult: Iconst { $$ = $1; }
+ | '(' Iresult ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+ | Iresult '+' Iresult { $$ = cat_str(3, $1, make_str("+"), $3); }
+ | Iresult '-' Iresult { $$ = cat_str(3, $1, make_str("-"), $3); }
+ | Iresult '*' Iresult { $$ = cat_str(3, $1, make_str("*"), $3); }
+ | Iresult '/' Iresult { $$ = cat_str(3, $1, make_str("/"), $3); }
+ | Iresult '%' Iresult { $$ = cat_str(3, $1, make_str("%"), $3); }
+ | ecpg_sconst { $$ = $1; }
+ | ColId { $$ = $1; }
+ ;
+
+execute_rest: /* EMPTY */ { $$ = EMPTY; }
+ | ecpg_using ecpg_into { $$ = EMPTY; }
+ | ecpg_into ecpg_using { $$ = EMPTY; }
+ | ecpg_using { $$ = EMPTY; }
+ | ecpg_into { $$ = EMPTY; }
+ ;
+
+ecpg_into: INTO into_list { $$ = EMPTY; }
+ | into_descriptor { $$ = $1; }
+ ;
+
+%%
+
+void base_yyerror(const char * error)
+{
+ char buf[1024];
+
+ snprintf(buf,sizeof buf, _("%s at or near \"%s\""), error, token_start ? token_start : yytext);
+ buf[sizeof(buf)-1]=0;
+ mmerror(PARSE_ERROR, ET_ERROR, buf);
+}
+
+void parser_init(void)
+{
+ /* This function is empty. It only exists for compatibility with the backend parser right now. */
+}
+
+/*
+ * Must undefine base_yylex before including pgc.c, since we want it
+ * to create the function base_yylex not filtered_base_yylex.
+ */
+#undef base_yylex
+
+#include "pgc.c"