mirror of
https://github.com/postgres/postgres.git
synced 2025-08-31 17:02:12 +03:00
2004 lines
62 KiB
Plaintext
2004 lines
62 KiB
Plaintext
/* $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"
|