| /* src/interfaces/ecpg/preproc/ecpg.trailer */ |
| |
| statements: /*EMPTY*/ |
| | statements statement |
| ; |
| |
| statement: ecpgstart at toplevel_stmt ';' |
| { |
| if (connection) |
| free(connection); |
| connection = NULL; |
| } |
| | ecpgstart toplevel_stmt ';' |
| { |
| if (connection) |
| free(connection); |
| connection = NULL; |
| } |
| | ecpgstart ECPGVarDeclaration |
| { |
| fprintf(base_yyout, "%s", $2); |
| free($2); |
| output_line_number(); |
| } |
| | ECPGDeclaration |
| | c_thing { fprintf(base_yyout, "%s", $1); free($1); } |
| | CPP_LINE { fprintf(base_yyout, "%s", $1); free($1); } |
| | '{' { braces_open++; fputs("{", base_yyout); } |
| | '}' |
| { |
| remove_typedefs(braces_open); |
| remove_variables(braces_open--); |
| if (braces_open == 0) |
| { |
| free(current_function); |
| current_function = NULL; |
| } |
| fputs("}", base_yyout); |
| } |
| ; |
| |
| CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data OptDistributedBy OptFirstPartitionSpec |
| { |
| if (FoundInto == 1) |
| mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); |
| |
| $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as"), $7, $8); |
| } |
| | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data |
| { |
| if (FoundInto == 1) |
| mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); |
| |
| $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as"), $10, $11); |
| } |
| ; |
| |
| 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, mm_strdup(","), $5, mm_strdup(","), $4); } |
| | SQL_CONNECT TO DEFAULT |
| { $$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); } |
| /* also allow ORACLE syntax */ |
| | SQL_CONNECT ora_user |
| { $$ = cat_str(3, mm_strdup("NULL,"), $2, mm_strdup(", NULL")); } |
| | DATABASE connection_target |
| { $$ = cat2_str($2, mm_strdup(", 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(mm_strdup("\""), make3_str($1, $2, $3), mm_strdup("\"")); |
| } |
| | 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(mm_strdup("\""), $1, mm_strdup(":")), $3, make3_str(make3_str($4, mm_strdup("/"), $6), $7, mm_strdup("\""))); |
| } |
| | 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: 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, "invalid connection type: %s", $1); |
| |
| $$ = make3_str($1, mm_strdup(":"), $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, mm_strdup("."), $3); } |
| | IP { $$ = make_name(); } |
| ; |
| |
| opt_port: ':' Iconst { $$ = make2_str(mm_strdup(":"), $2); } |
| | /*EMPTY*/ { $$ = EMPTY; } |
| ; |
| |
| opt_connection_name: AS connection_object { $$ = $2; } |
| | /*EMPTY*/ { $$ = mm_strdup("NULL"); } |
| ; |
| |
| opt_user: USER ora_user { $$ = $2; } |
| | /*EMPTY*/ { $$ = mm_strdup("NULL, NULL"); } |
| ; |
| |
| ora_user: user_name |
| { $$ = cat2_str($1, mm_strdup(", NULL")); } |
| | user_name '/' user_name |
| { $$ = cat_str(3, $1, mm_strdup(","), $3); } |
| | user_name SQL_IDENTIFIED BY user_name |
| { $$ = cat_str(3, $1, mm_strdup(","), $4); } |
| | user_name USING user_name |
| { $$ = cat_str(3, $1, mm_strdup(","), $3); } |
| ; |
| |
| user_name: RoleId |
| { |
| if ($1[0] == '\"') |
| $$ = $1; |
| else |
| $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); |
| } |
| | ecpg_sconst |
| { |
| if ($1[0] == '\"') |
| $$ = $1; |
| else |
| $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); |
| } |
| | 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), mm_strdup(".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 data type"); |
| else |
| { |
| /* if array see what's inside */ |
| if (type == ECPGt_array) |
| type = p->type->u.element->type; |
| |
| switch (type) |
| { |
| case ECPGt_char: |
| case ECPGt_unsigned_char: |
| case ECPGt_string: |
| $$ = $1; |
| break; |
| case ECPGt_varchar: |
| $$ = make2_str($1, mm_strdup(".arr")); |
| break; |
| default: |
| mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); |
| $$ = $1; |
| break; |
| } |
| } |
| } |
| ; |
| |
| opt_options: Op connect_options |
| { |
| if (strlen($1) == 0) |
| mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); |
| |
| if (strcmp($1, "?") != 0) |
| mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1); |
| |
| $$ = make2_str(mm_strdup("?"), $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(mm_strdup("="), $2); } |
| | '=' ecpg_ident |
| { $$ = make2_str(mm_strdup("="), $2); } |
| | '=' civar |
| { $$ = make2_str(mm_strdup("="), $2); } |
| ; |
| |
| prepared_name: name |
| { |
| if ($1[0] == '\"' && $1[strlen($1)-1] == '\"') /* already quoted? */ |
| $$ = $1; |
| else /* not quoted => convert to lowercase */ |
| { |
| size_t i; |
| |
| for (i = 0; i< strlen($1); i++) |
| $1[i] = tolower((unsigned char) $1[i]); |
| |
| $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); |
| } |
| } |
| | char_variable { $$ = $1; } |
| ; |
| |
| /* |
| * Declare Statement |
| */ |
| ECPGDeclareStmt: DECLARE prepared_name STATEMENT |
| { |
| struct declared_list *ptr = NULL; |
| /* Check whether the declared name has been defined or not */ |
| for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next) |
| { |
| if (strcmp($2, ptr->name) == 0) |
| { |
| /* re-definition is not allowed */ |
| mmerror(PARSE_ERROR, ET_ERROR, "name \"%s\" is already declared", ptr->name); |
| } |
| } |
| |
| /* Add a new declared name into the g_declared_list */ |
| ptr = NULL; |
| ptr = (struct declared_list *)mm_alloc(sizeof(struct declared_list)); |
| if (ptr) |
| { |
| /* initial definition */ |
| ptr -> name = $2; |
| if (connection) |
| ptr -> connection = mm_strdup(connection); |
| else |
| ptr -> connection = NULL; |
| |
| ptr -> next = g_declared_list; |
| g_declared_list = ptr; |
| } |
| |
| $$ = cat_str(3 , mm_strdup("/* declare "), mm_strdup($2), mm_strdup(" as an SQL identifier */")); |
| } |
| ; |
| |
| /* |
| * Declare a prepared cursor. The syntax is different from the standard |
| * declare statement, so we create a new rule. |
| */ |
| ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name |
| { |
| struct cursor *ptr, *this; |
| char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); |
| int (* strcmp_fn)(const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); |
| struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); |
| char *comment; |
| char *con; |
| |
| if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) |
| mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); |
| |
| check_declared_list($7); |
| con = connection ? connection : "NULL"; |
| for (ptr = cur; ptr != NULL; ptr = ptr->next) |
| { |
| if (strcmp_fn($2, ptr->name) == 0) |
| { |
| /* re-definition is a bug */ |
| if ($2[0] == ':') |
| mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported", $2+1); |
| else |
| mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2); |
| } |
| } |
| |
| this = (struct cursor *) mm_alloc(sizeof(struct cursor)); |
| |
| /* initial definition */ |
| this->next = cur; |
| this->name = $2; |
| this->function = (current_function ? mm_strdup(current_function) : NULL); |
| this->connection = connection ? mm_strdup(connection) : NULL; |
| this->command = cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for $1")); |
| this->argsresult = NULL; |
| this->argsresult_oos = NULL; |
| |
| thisquery->type = &ecpg_query; |
| thisquery->brace_level = 0; |
| thisquery->next = NULL; |
| thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7)); |
| sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); |
| |
| this->argsinsert = NULL; |
| this->argsinsert_oos = NULL; |
| if ($2[0] == ':') |
| { |
| struct variable *var = find_variable($2 + 1); |
| remove_variable_from_list(&argsinsert, var); |
| add_variable_to_head(&(this->argsinsert), var, &no_indicator); |
| } |
| add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); |
| |
| cur = this; |
| |
| comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/")); |
| |
| $$ = cat_str(2, adjust_outofscope_cursor_vars(this), |
| comment); |
| } |
| ; |
| |
| ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring |
| { |
| /* execute immediate means prepare the statement and |
| * immediately execute it */ |
| $$ = $3; |
| }; |
| /* |
| * variable declaration outside exec sql declare block |
| */ |
| ECPGVarDeclaration: single_vt_declaration; |
| |
| single_vt_declaration: type_declaration { $$ = $1; } |
| | var_declaration { $$ = $1; } |
| ; |
| |
| precision: NumericOnly { $$ = $1; }; |
| |
| opt_scale: ',' NumericOnly { $$ = $2; } |
| | /* EMPTY */ { $$ = EMPTY; } |
| ; |
| |
| ecpg_interval: opt_interval { $$ = $1; } |
| | YEAR_P TO MINUTE_P { $$ = mm_strdup("year to minute"); } |
| | YEAR_P TO SECOND_P { $$ = mm_strdup("year to second"); } |
| | DAY_P TO DAY_P { $$ = mm_strdup("day to day"); } |
| | MONTH_P TO MONTH_P { $$ = mm_strdup("month to month"); } |
| ; |
| |
| /* |
| * variable declaration inside exec sql declare block |
| */ |
| ECPGDeclaration: sql_startdeclare |
| { fputs("/* exec sql begin declare section */", base_yyout); } |
| var_type_declarations sql_enddeclare |
| { |
| fprintf(base_yyout, "%s/* exec sql end declare section */", $3); |
| 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; } |
| ; |
| |
| vt_declarations: single_vt_declaration { $$ = $1; } |
| | CPP_LINE { $$ = $1; } |
| | vt_declarations single_vt_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(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str); |
| output_line_number(); |
| $$ = mm_strdup(""); |
| }; |
| |
| var_declaration: storage_declaration |
| var_type |
| { |
| actual_type[struct_level].type_enum = $2.type_enum; |
| actual_type[struct_level].type_str = $2.type_str; |
| actual_type[struct_level].type_dimension = $2.type_dimension; |
| actual_type[struct_level].type_index = $2.type_index; |
| actual_type[struct_level].type_sizeof = $2.type_sizeof; |
| |
| actual_startline[struct_level] = hashline_number(); |
| } |
| variable_list ';' |
| { |
| $$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, mm_strdup(";\n")); |
| } |
| | var_type |
| { |
| actual_type[struct_level].type_enum = $1.type_enum; |
| actual_type[struct_level].type_str = $1.type_str; |
| actual_type[struct_level].type_dimension = $1.type_dimension; |
| actual_type[struct_level].type_index = $1.type_index; |
| actual_type[struct_level].type_sizeof = $1.type_sizeof; |
| |
| actual_startline[struct_level] = hashline_number(); |
| } |
| variable_list ';' |
| { |
| $$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, mm_strdup(";\n")); |
| } |
| | struct_union_type_with_symbol ';' |
| { |
| $$ = cat2_str($1, mm_strdup(";")); |
| } |
| ; |
| |
| opt_bit_field: ':' Iconst { $$ =cat2_str(mm_strdup(":"), $2); } |
| | /* EMPTY */ { $$ = EMPTY; } |
| ; |
| |
| storage_declaration: storage_clause storage_modifier |
| {$$ = cat2_str ($1, $2); } |
| | storage_clause {$$ = $1; } |
| | storage_modifier {$$ = $1; } |
| ; |
| |
| storage_clause : S_EXTERN { $$ = mm_strdup("extern"); } |
| | S_STATIC { $$ = mm_strdup("static"); } |
| | S_REGISTER { $$ = mm_strdup("register"); } |
| | S_AUTO { $$ = mm_strdup("auto"); } |
| ; |
| |
| storage_modifier : S_CONST { $$ = mm_strdup("const"); } |
| | S_VOLATILE { $$ = mm_strdup("volatile"); } |
| ; |
| |
| var_type: simple_type |
| { |
| $$.type_enum = $1; |
| $$.type_str = mm_strdup(ecpg_type_name($1)); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| | struct_union_type |
| { |
| $$.type_str = $1; |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-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 = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| | ECPGColLabelCommon '(' precision opt_scale ')' |
| { |
| if (strcmp($1, "numeric") == 0) |
| { |
| $$.type_enum = ECPGt_numeric; |
| $$.type_str = mm_strdup("numeric"); |
| } |
| else if (strcmp($1, "decimal") == 0) |
| { |
| $$.type_enum = ECPGt_decimal; |
| $$.type_str = mm_strdup("decimal"); |
| } |
| else |
| { |
| mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument"); |
| $$.type_enum = ECPGt_numeric; |
| $$.type_str = mm_strdup("numeric"); |
| } |
| |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-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; /*mm_strdup("varchar");*/ |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "bytea") == 0) |
| { |
| $$.type_enum = ECPGt_bytea; |
| $$.type_str = EMPTY; |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "float") == 0) |
| { |
| $$.type_enum = ECPGt_float; |
| $$.type_str = mm_strdup("float"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "double") == 0) |
| { |
| $$.type_enum = ECPGt_double; |
| $$.type_str = mm_strdup("double"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "numeric") == 0) |
| { |
| $$.type_enum = ECPGt_numeric; |
| $$.type_str = mm_strdup("numeric"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "decimal") == 0) |
| { |
| $$.type_enum = ECPGt_decimal; |
| $$.type_str = mm_strdup("decimal"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "date") == 0) |
| { |
| $$.type_enum = ECPGt_date; |
| $$.type_str = mm_strdup("date"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "timestamp") == 0) |
| { |
| $$.type_enum = ECPGt_timestamp; |
| $$.type_str = mm_strdup("timestamp"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "interval") == 0) |
| { |
| $$.type_enum = ECPGt_interval; |
| $$.type_str = mm_strdup("interval"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if (strcmp($1, "datetime") == 0) |
| { |
| $$.type_enum = ECPGt_timestamp; |
| $$.type_str = mm_strdup("timestamp"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = NULL; |
| } |
| else if ((strcmp($1, "string") == 0) && INFORMIX_MODE) |
| { |
| $$.type_enum = ECPGt_string; |
| $$.type_str = mm_strdup("char"); |
| $$.type_dimension = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-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 || this->type->type_enum == ECPGt_bytea) ? 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, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); |
| |
| 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 = mm_strdup("-1"); |
| $$.type_index = mm_strdup("-1"); |
| $$.type_sizeof = mm_strdup(""); |
| struct_member_list[struct_level] = NULL; |
| } |
| } |
| ; |
| |
| enum_type: ENUM_P symbol enum_definition |
| { $$ = cat_str(3, mm_strdup("enum"), $2, $3); } |
| | ENUM_P enum_definition |
| { $$ = cat2_str(mm_strdup("enum"), $2); } |
| | ENUM_P symbol |
| { $$ = cat2_str(mm_strdup("enum"), $2); } |
| ; |
| |
| enum_definition: '{' c_list '}' |
| { $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); }; |
| |
| 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 essentially a typedef but needs the keyword struct/union as well. |
| * So we create the typedef for each struct definition with symbol */ |
| for (ptr = types; ptr != NULL; ptr = ptr->next) |
| { |
| if (strcmp(su_type.type_str, ptr->name) == 0) |
| /* re-definition is a bug */ |
| mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", su_type.type_str); |
| } |
| |
| this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); |
| |
| /* initial definition */ |
| this->next = types; |
| this->name = mm_strdup(su_type.type_str); |
| this->brace_level = braces_open; |
| this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); |
| this->type->type_enum = su_type.type_enum; |
| this->type->type_str = mm_strdup(su_type.type_str); |
| this->type->type_dimension = mm_strdup("-1"); /* dimension of array */ |
| this->type->type_index = mm_strdup("-1"); /* length of string */ |
| this->type->type_sizeof = ECPGstruct_sizeof; |
| this->struct_member_list = struct_member_list[struct_level]; |
| |
| types = this; |
| $$ = cat_str(4, su_type.type_str, mm_strdup("{"), $4, mm_strdup("}")); |
| } |
| ; |
| |
| 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, mm_strdup("{"), $4, mm_strdup("}")); |
| } |
| ; |
| |
| s_struct_union_symbol: SQL_STRUCT symbol |
| { |
| $$.su = mm_strdup("struct"); |
| $$.symbol = $2; |
| ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")")); |
| } |
| | UNION symbol |
| { |
| $$.su = mm_strdup("union"); |
| $$.symbol = $2; |
| } |
| ; |
| |
| s_struct_union: SQL_STRUCT |
| { |
| ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to distinguish from simple types. */ |
| $$ = mm_strdup("struct"); |
| } |
| | UNION |
| { |
| $$ = mm_strdup("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 { $$ = ECPGt_unsigned_long_long; } |
| | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P { $$ = ECPGt_unsigned_long_long; } |
| | SQL_UNSIGNED CHAR_P { $$ = ECPGt_unsigned_char; } |
| ; |
| |
| signed_type: SQL_SHORT { $$ = ECPGt_short; } |
| | SQL_SHORT INT_P { $$ = ECPGt_short; } |
| | INT_P { $$ = ECPGt_int; } |
| | SQL_LONG { $$ = ECPGt_long; } |
| | SQL_LONG INT_P { $$ = ECPGt_long; } |
| | SQL_LONG SQL_LONG { $$ = ECPGt_long_long; } |
| | SQL_LONG SQL_LONG INT_P { $$ = ECPGt_long_long; } |
| | SQL_BOOL { $$ = ECPGt_bool; } |
| | CHAR_P { $$ = ECPGt_char; } |
| | DOUBLE_P { $$ = ECPGt_double; } |
| ; |
| |
| opt_signed: SQL_SIGNED |
| | /* EMPTY */ |
| ; |
| |
| variable_list: variable |
| { $$ = $1; } |
| | variable_list ',' variable |
| { |
| if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea) |
| $$ = cat_str(3, $1, mm_strdup(";"), $3); |
| else |
| $$ = cat_str(3, $1, mm_strdup(","), $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_str; |
| char *vcn; |
| int *varlen_type_counter; |
| char *struct_name; |
| |
| adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1), false); |
| switch (actual_type[struct_level].type_enum) |
| { |
| case ECPGt_struct: |
| case ECPGt_union: |
| if (atoi(dimension) < 0) |
| type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof); |
| else |
| type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension); |
| |
| $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); |
| break; |
| |
| case ECPGt_varchar: |
| case ECPGt_bytea: |
| if (actual_type[struct_level].type_enum == ECPGt_varchar) |
| { |
| varlen_type_counter = &varchar_counter; |
| struct_name = " struct varchar_"; |
| } |
| else |
| { |
| varlen_type_counter = &bytea_counter; |
| struct_name = " struct bytea_"; |
| } |
| if (atoi(dimension) < 0) |
| type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter); |
| else |
| type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter), dimension); |
| |
| if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1) |
| dim_str=mm_strdup(""); |
| else |
| dim_str=cat_str(3, mm_strdup("["), mm_strdup(dimension), mm_strdup("]")); |
| /* cannot check for atoi <= 0 because a defined constant will yield 0 here as well */ |
| if (atoi(length) < 0 || strcmp(length, "0") == 0) |
| mmerror(PARSE_ERROR, ET_ERROR, "pointers to varchar are not implemented"); |
| |
| /* make sure varchar struct name is unique by adding a unique counter to its definition */ |
| vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); |
| sprintf(vcn, "%d", *varlen_type_counter); |
| if (strcmp(dimension, "0") == 0) |
| $$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } *"), mm_strdup($2), $4, $5); |
| else |
| $$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5); |
| (*varlen_type_counter)++; |
| break; |
| |
| case ECPGt_char: |
| case ECPGt_unsigned_char: |
| case ECPGt_string: |
| if (atoi(dimension) == -1) |
| { |
| int i = strlen($5); |
| |
| if (atoi(length) == -1 && i > 0) /* char <var>[] = "string" */ |
| { |
| /* if we have an initializer but no string size set, let's use the initializer's length */ |
| 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, mm_strdup("1"), 0); |
| else |
| type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("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(mm_strdup("="), $2); |
| } |
| ; |
| |
| opt_pointer: /*EMPTY*/ { $$ = EMPTY; } |
| | '*' { $$ = mm_strdup("*"); } |
| | '*' '*' { $$ = mm_strdup("**"); } |
| ; |
| |
| /* |
| * 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, mm_strdup("/* declare statement"), $3, mm_strdup("*/")); |
| } |
| ; |
| /* |
| * the exec sql disconnect statement: disconnect from the given database |
| */ |
| ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; } |
| ; |
| |
| dis_name: connection_object { $$ = $1; } |
| | CURRENT_P { $$ = mm_strdup("\"CURRENT\""); } |
| | ALL { $$ = mm_strdup("\"ALL\""); } |
| | /* EMPTY */ { $$ = mm_strdup("\"CURRENT\""); } |
| ; |
| |
| connection_object: name { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } |
| | DEFAULT { $$ = mm_strdup("\"DEFAULT\""); } |
| | char_variable { $$ = $1; } |
| ; |
| |
| execstring: char_variable |
| { $$ = $1; } |
| | CSTRING |
| { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } |
| ; |
| |
| /* |
| * the exec sql free command to deallocate a previously |
| * prepared statement |
| */ |
| ECPGFree: SQL_FREE cursor_name { $$ = $2; } |
| | SQL_FREE ALL { $$ = mm_strdup("all"); } |
| ; |
| |
| /* |
| * open is an open cursor, at the moment this has to be removed |
| */ |
| ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using |
| { |
| if ($2[0] == ':') |
| remove_variable_from_list(&argsinsert, find_variable($2 + 1)); |
| $$ = $2; |
| } |
| ; |
| |
| opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } |
| | ecpg_using { $$ = $1; } |
| ; |
| |
| ecpg_using: USING using_list { $$ = EMPTY; } |
| | using_descriptor { $$ = $1; } |
| ; |
| |
| using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar |
| { |
| add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); |
| $$ = EMPTY; |
| } |
| | USING SQL_DESCRIPTOR name |
| { |
| add_variable_to_head(&argsinsert, sqlda_variable($3), &no_indicator); |
| $$ = EMPTY; |
| } |
| ; |
| |
| into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar |
| { |
| add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); |
| $$ = EMPTY; |
| } |
| | INTO SQL_DESCRIPTOR name |
| { |
| add_variable_to_head(&argsresult, sqlda_variable($3), &no_indicator); |
| $$ = EMPTY; |
| } |
| ; |
| |
| into_sqlda: INTO name |
| { |
| add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator); |
| $$ = EMPTY; |
| } |
| ; |
| |
| using_list: UsingValue | UsingValue ',' using_list; |
| |
| UsingValue: UsingConst |
| { |
| char *length = mm_alloc(32); |
| |
| sprintf(length, "%zu", 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; } |
| | '+' Iconst { $$ = cat_str(2, mm_strdup("+"), $2); } |
| | '-' Iconst { $$ = cat_str(2, mm_strdup("-"), $2); } |
| | ecpg_fconst { $$ = $1; } |
| | '+' ecpg_fconst { $$ = cat_str(2, mm_strdup("+"), $2); } |
| | '-' ecpg_fconst { $$ = cat_str(2, mm_strdup("-"), $2); } |
| | ecpg_sconst { $$ = $1; } |
| | ecpg_bconst { $$ = $1; } |
| | ecpg_xconst { $$ = $1; } |
| ; |
| |
| /* |
| * We accept DESCRIBE [OUTPUT] but do nothing with DESCRIBE INPUT so far. |
| */ |
| ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor |
| { |
| $$.input = 1; |
| $$.stmt_name = $3; |
| } |
| | SQL_DESCRIBE opt_output prepared_name using_descriptor |
| { |
| struct variable *var; |
| var = argsinsert->variable; |
| remove_variable_from_list(&argsinsert, var); |
| add_variable_to_head(&argsresult, var, &no_indicator); |
| |
| $$.input = 0; |
| $$.stmt_name = $3; |
| } |
| | SQL_DESCRIBE opt_output prepared_name into_descriptor |
| { |
| $$.input = 0; |
| $$.stmt_name = $3; |
| } |
| | SQL_DESCRIBE INPUT_P prepared_name into_sqlda |
| { |
| $$.input = 1; |
| $$.stmt_name = $3; |
| } |
| | SQL_DESCRIBE opt_output prepared_name into_sqlda |
| { |
| $$.input = 0; |
| $$.stmt_name = $3; |
| } |
| ; |
| |
| opt_output: SQL_OUTPUT { $$ = mm_strdup("output"); } |
| | /* EMPTY */ { $$ = EMPTY; } |
| ; |
| |
| /* |
| * dynamic SQL: descriptor based access |
| * originally written by Christof Petig <christof.petig@wtal.de> |
| * and Peter Eisentraut <peter.eisentraut@credativ.de> |
| */ |
| |
| /* |
| * allocate a descriptor |
| */ |
| ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar |
| { |
| add_descriptor($3,connection); |
| $$ = $3; |
| } |
| ; |
| |
| |
| /* |
| * deallocate a descriptor |
| */ |
| ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar |
| { |
| drop_descriptor($3,connection); |
| $$ = $3; |
| } |
| ; |
| |
| /* |
| * manipulate a descriptor header |
| */ |
| |
| ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems |
| { $$ = $3; } |
| ; |
| |
| ECPGGetDescHeaderItems: ECPGGetDescHeaderItem |
| | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem |
| ; |
| |
| ECPGGetDescHeaderItem: cvariable '=' desc_header_item |
| { push_assignment($1, $3); } |
| ; |
| |
| |
| ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems |
| { $$ = $3; } |
| ; |
| |
| ECPGSetDescHeaderItems: ECPGSetDescHeaderItem |
| | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem |
| ; |
| |
| ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar |
| { |
| push_assignment($3, $1); |
| } |
| ; |
| |
| IntConstVar: Iconst |
| { |
| char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); |
| |
| sprintf(length, "%zu", 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, "%zu", 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(mm_strdup("-"), $2); |
| |
| sprintf(length, "%zu", 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(mm_strdup("-"), $2); |
| |
| sprintf(length, "%zu", 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, "%zu", strlen(var)); |
| new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); |
| $$ = var; |
| } |
| ; |
| |
| descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } |
| | DATA_P { $$ = ECPGd_data; } |
| | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } |
| | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } |
| | SQL_INDICATOR { $$ = ECPGd_indicator; } |
| | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } |
| | SQL_LENGTH { $$ = ECPGd_length; } |
| | NAME_P { $$ = ECPGd_name; } |
| | SQL_NULLABLE { $$ = ECPGd_nullable; } |
| | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } |
| | PRECISION { $$ = ECPGd_precision; } |
| | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } |
| | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } |
| | SQL_SCALE { $$ = ECPGd_scale; } |
| | TYPE_P { $$ = ECPGd_type; } |
| ; |
| |
| /* |
| * set/reset the automatic transaction mode, this needs a different handling |
| * as the other set commands |
| */ |
| ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off { $$ = $4; } |
| | SET SQL_AUTOCOMMIT TO on_off { $$ = $4; } |
| ; |
| |
| on_off: ON { $$ = mm_strdup("on"); } |
| | OFF { $$ = mm_strdup("off"); } |
| ; |
| |
| /* |
| * set the actual connection, this needs a different handling as the other |
| * set commands |
| */ |
| ECPGSetConnection: SET CONNECTION TO connection_object { $$ = $4; } |
| | SET CONNECTION '=' connection_object { $$ = $4; } |
| | SET CONNECTION connection_object { $$ = $3; } |
| ; |
| |
| /* |
| * define a new type for embedded SQL |
| */ |
| ECPGTypedef: TYPE_P |
| { |
| /* reset this variable so we see if there was */ |
| /* an initializer specified */ |
| initializer = 0; |
| } |
| 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, mm_strdup("/* exec sql type"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, mm_strdup("*/")); |
| else |
| $$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *$7?mm_strdup("*"):mm_strdup(""), mm_strdup($3), mm_strdup($6.str), mm_strdup(";")); |
| } |
| ; |
| |
| opt_reference: SQL_REFERENCE { $$ = mm_strdup("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_str, $5.type_sizeof); |
| else |
| type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof), dimension); |
| break; |
| |
| case ECPGt_varchar: |
| case ECPGt_bytea: |
| if (atoi(dimension) == -1) |
| type = ECPGmake_simple_type($5.type_enum, length, 0); |
| else |
| type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); |
| break; |
| |
| case ECPGt_char: |
| case ECPGt_unsigned_char: |
| case ECPGt_string: |
| if (atoi(dimension) == -1) |
| type = ECPGmake_simple_type($5.type_enum, length, 0); |
| else |
| type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); |
| break; |
| |
| default: |
| if (atoi(length) >= 0) |
| mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); |
| |
| if (atoi(dimension) < 0) |
| type = ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0); |
| else |
| type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0), dimension); |
| break; |
| } |
| |
| ECPGfree_type(p->type); |
| p->type = type; |
| } |
| |
| $$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, mm_strdup("*/")); |
| } |
| ; |
| |
| /* |
| * 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, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); |
| } |
| | SQL_WHENEVER NOT SQL_FOUND action |
| { |
| when_nf.code = $<action>4.code; |
| when_nf.command = $<action>4.command; |
| $$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); |
| } |
| | SQL_WHENEVER SQL_SQLWARNING action |
| { |
| when_warn.code = $<action>3.code; |
| when_warn.command = $<action>3.command; |
| $$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); |
| } |
| ; |
| |
| action : CONTINUE_P |
| { |
| $<action>$.code = W_NOTHING; |
| $<action>$.command = NULL; |
| $<action>$.str = mm_strdup("continue"); |
| } |
| | SQL_SQLPRINT |
| { |
| $<action>$.code = W_SQLPRINT; |
| $<action>$.command = NULL; |
| $<action>$.str = mm_strdup("sqlprint"); |
| } |
| | SQL_STOP |
| { |
| $<action>$.code = W_STOP; |
| $<action>$.command = NULL; |
| $<action>$.str = mm_strdup("stop"); |
| } |
| | SQL_GOTO name |
| { |
| $<action>$.code = W_GOTO; |
| $<action>$.command = mm_strdup($2); |
| $<action>$.str = cat2_str(mm_strdup("goto "), $2); |
| } |
| | SQL_GO TO name |
| { |
| $<action>$.code = W_GOTO; |
| $<action>$.command = mm_strdup($3); |
| $<action>$.str = cat2_str(mm_strdup("goto "), $3); |
| } |
| | DO name '(' c_args ')' |
| { |
| $<action>$.code = W_DO; |
| $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); |
| $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command)); |
| } |
| | DO SQL_BREAK |
| { |
| $<action>$.code = W_BREAK; |
| $<action>$.command = NULL; |
| $<action>$.str = mm_strdup("break"); |
| } |
| | DO CONTINUE_P |
| { |
| $<action>$.code = W_CONTINUE; |
| $<action>$.command = NULL; |
| $<action>$.str = mm_strdup("continue"); |
| } |
| | CALL name '(' c_args ')' |
| { |
| $<action>$.code = W_DO; |
| $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); |
| $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); |
| } |
| | CALL name |
| { |
| $<action>$.code = W_DO; |
| $<action>$.command = cat2_str($2, mm_strdup("()")); |
| $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); |
| } |
| ; |
| |
| /* some other stuff for ecpg */ |
| |
| /* additional unreserved keywords */ |
| ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } |
| | ECPGKeywords_rest { $$ = $1; } |
| ; |
| |
| ECPGKeywords_vanames: SQL_BREAK { $$ = mm_strdup("break"); } |
| | SQL_CARDINALITY { $$ = mm_strdup("cardinality"); } |
| | SQL_COUNT { $$ = mm_strdup("count"); } |
| | SQL_DATETIME_INTERVAL_CODE { $$ = mm_strdup("datetime_interval_code"); } |
| | SQL_DATETIME_INTERVAL_PRECISION { $$ = mm_strdup("datetime_interval_precision"); } |
| | SQL_FOUND { $$ = mm_strdup("found"); } |
| | SQL_GO { $$ = mm_strdup("go"); } |
| | SQL_GOTO { $$ = mm_strdup("goto"); } |
| | SQL_IDENTIFIED { $$ = mm_strdup("identified"); } |
| | SQL_INDICATOR { $$ = mm_strdup("indicator"); } |
| | SQL_KEY_MEMBER { $$ = mm_strdup("key_member"); } |
| | SQL_LENGTH { $$ = mm_strdup("length"); } |
| | SQL_NULLABLE { $$ = mm_strdup("nullable"); } |
| | SQL_OCTET_LENGTH { $$ = mm_strdup("octet_length"); } |
| | SQL_RETURNED_LENGTH { $$ = mm_strdup("returned_length"); } |
| | SQL_RETURNED_OCTET_LENGTH { $$ = mm_strdup("returned_octet_length"); } |
| | SQL_SCALE { $$ = mm_strdup("scale"); } |
| | SQL_SECTION { $$ = mm_strdup("section"); } |
| | SQL_SQLERROR { $$ = mm_strdup("sqlerror"); } |
| | SQL_SQLPRINT { $$ = mm_strdup("sqlprint"); } |
| | SQL_SQLWARNING { $$ = mm_strdup("sqlwarning"); } |
| | SQL_STOP { $$ = mm_strdup("stop"); } |
| ; |
| |
| ECPGKeywords_rest: SQL_CONNECT { $$ = mm_strdup("connect"); } |
| | SQL_DESCRIBE { $$ = mm_strdup("describe"); } |
| | SQL_DISCONNECT { $$ = mm_strdup("disconnect"); } |
| | SQL_OPEN { $$ = mm_strdup("open"); } |
| | SQL_VAR { $$ = mm_strdup("var"); } |
| | SQL_WHENEVER { $$ = mm_strdup("whenever"); } |
| ; |
| |
| /* additional keywords that can be SQL type names (but not ECPGColLabels) */ |
| ECPGTypeName: SQL_BOOL { $$ = mm_strdup("bool"); } |
| | SQL_LONG { $$ = mm_strdup("long"); } |
| | SQL_OUTPUT { $$ = mm_strdup("output"); } |
| | SQL_SHORT { $$ = mm_strdup("short"); } |
| | SQL_STRUCT { $$ = mm_strdup("struct"); } |
| | SQL_SIGNED { $$ = mm_strdup("signed"); } |
| | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } |
| ; |
| |
| symbol: ColLabel { $$ = $1; } |
| ; |
| |
| ECPGColId: ecpg_ident { $$ = $1; } |
| | unreserved_keyword { $$ = $1; } |
| | col_name_keyword { $$ = $1; } |
| | ECPGunreserved_interval { $$ = $1; } |
| | ECPGKeywords { $$ = $1; } |
| | ECPGCKeywords { $$ = $1; } |
| | CHAR_P { $$ = mm_strdup("char"); } |
| | VALUES { $$ = mm_strdup("values"); } |
| ; |
| |
| /* |
| * Name classification hierarchy. |
| * |
| * These productions should match those in the core grammar, except that |
| * we use all_unreserved_keyword instead of unreserved_keyword, and |
| * where possible include ECPG keywords as well as core keywords. |
| */ |
| |
| /* Column identifier --- names that can be column, table, etc names. |
| */ |
| ColId: ecpg_ident { $$ = $1; } |
| | all_unreserved_keyword { $$ = $1; } |
| | col_name_keyword { $$ = $1; } |
| | ECPGKeywords { $$ = $1; } |
| | ECPGCKeywords { $$ = $1; } |
| | CHAR_P { $$ = mm_strdup("char"); } |
| | VALUES { $$ = mm_strdup("values"); } |
| ; |
| |
| /* Type/function identifier --- names that can be type or function names. |
| */ |
| type_function_name: ecpg_ident { $$ = $1; } |
| | all_unreserved_keyword { $$ = $1; } |
| | type_func_name_keyword { $$ = $1; } |
| | ECPGKeywords { $$ = $1; } |
| | ECPGCKeywords { $$ = $1; } |
| | ECPGTypeName { $$ = $1; } |
| ; |
| |
| /* Column label --- allowed labels in "AS" clauses. |
| * This presently includes *all* Postgres keywords. |
| */ |
| ColLabel: ECPGColLabel { $$ = $1; } |
| | ECPGTypeName { $$ = $1; } |
| | CHAR_P { $$ = mm_strdup("char"); } |
| | CURRENT_P { $$ = mm_strdup("current"); } |
| | INPUT_P { $$ = mm_strdup("input"); } |
| | INT_P { $$ = mm_strdup("int"); } |
| | TO { $$ = mm_strdup("to"); } |
| | UNION { $$ = mm_strdup("union"); } |
| | VALUES { $$ = mm_strdup("values"); } |
| | ECPGCKeywords { $$ = $1; } |
| | ECPGunreserved_interval { $$ = $1; } |
| ; |
| |
| ECPGColLabel: ECPGColLabelCommon { $$ = $1; } |
| | unreserved_keyword { $$ = $1; } |
| | reserved_keyword { $$ = $1; } |
| | ECPGKeywords_rest { $$ = $1; } |
| | CONNECTION { $$ = mm_strdup("connection"); } |
| ; |
| |
| ECPGColLabelCommon: ecpg_ident { $$ = $1; } |
| | col_name_keyword { $$ = $1; } |
| | type_func_name_keyword { $$ = $1; } |
| | ECPGKeywords_vanames { $$ = $1; } |
| ; |
| |
| ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } |
| | S_CONST { $$ = mm_strdup("const"); } |
| | S_EXTERN { $$ = mm_strdup("extern"); } |
| | S_REGISTER { $$ = mm_strdup("register"); } |
| | S_STATIC { $$ = mm_strdup("static"); } |
| | S_TYPEDEF { $$ = mm_strdup("typedef"); } |
| | S_VOLATILE { $$ = mm_strdup("volatile"); } |
| ; |
| |
| /* "Unreserved" keywords --- available for use as any kind of name. |
| */ |
| |
| /* |
| * The following symbols must be excluded from ECPGColLabel and directly |
| * included into ColLabel to enable C variables to get names from ECPGColLabel: |
| * DAY_P, HOUR_P, MINUTE_P, MONTH_P, SECOND_P, YEAR_P. |
| * |
| * We also have to exclude CONNECTION, CURRENT, and INPUT for various reasons. |
| * CONNECTION can be added back in all_unreserved_keyword, but CURRENT and |
| * INPUT are reserved for ecpg purposes. |
| * |
| * The mentioned exclusions are done by $replace_line settings in parse.pl. |
| */ |
| all_unreserved_keyword: unreserved_keyword { $$ = $1; } |
| | ECPGunreserved_interval { $$ = $1; } |
| | CONNECTION { $$ = mm_strdup("connection"); } |
| ; |
| |
| ECPGunreserved_interval: DAY_P { $$ = mm_strdup("day"); } |
| | HOUR_P { $$ = mm_strdup("hour"); } |
| | MINUTE_P { $$ = mm_strdup("minute"); } |
| | MONTH_P { $$ = mm_strdup("month"); } |
| | SECOND_P { $$ = mm_strdup("second"); } |
| | YEAR_P { $$ = mm_strdup("year"); } |
| ; |
| |
| |
| 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); |
| } |
| ; |
| |
| char_civar: char_variable |
| { |
| char *ptr = strstr($1, ".arr"); |
| |
| if (ptr) /* varchar, we need the struct name here, not the struct element */ |
| *ptr = '\0'; |
| add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); |
| $$ = $1; |
| } |
| ; |
| |
| 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) |
| mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported"); |
| brace_open++; |
| break; |
| case ']': |
| brace_open--; |
| if (brace_open == 0) |
| brace = true; |
| break; |
| case '\t': |
| case ' ': |
| break; |
| default: |
| if (brace_open == 0) |
| brace = false; |
| break; |
| } |
| } |
| $$ = $1; |
| } |
| ; |
| |
| ecpg_param: PARAM { $$ = make_name(); } ; |
| |
| ecpg_bconst: BCONST { $$ = $1; } ; |
| |
| ecpg_fconst: FCONST { $$ = make_name(); } ; |
| |
| ecpg_sconst: SCONST { $$ = $1; } ; |
| |
| ecpg_xconst: XCONST { $$ = $1; } ; |
| |
| ecpg_ident: IDENT { $$ = $1; } |
| | CSTRING { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } |
| ; |
| |
| quoted_ident_stringvar: name |
| { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } |
| | char_variable |
| { $$ = make3_str(mm_strdup("("), $1, mm_strdup(")")); } |
| ; |
| |
| /* |
| * C stuff |
| */ |
| |
| c_stuff_item: c_anything { $$ = $1; } |
| | '(' ')' { $$ = mm_strdup("()"); } |
| | '(' c_stuff ')' |
| { $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); } |
| ; |
| |
| 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, mm_strdup(","), $3); } |
| ; |
| |
| c_term: c_stuff { $$ = $1; } |
| | '{' c_list '}' { $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); } |
| ; |
| |
| c_thing: c_anything { $$ = $1; } |
| | '(' { $$ = mm_strdup("("); } |
| | ')' { $$ = mm_strdup(")"); } |
| | ',' { $$ = mm_strdup(","); } |
| | ';' { $$ = mm_strdup(";"); } |
| ; |
| |
| c_anything: ecpg_ident { $$ = $1; } |
| | Iconst { $$ = $1; } |
| | ecpg_fconst { $$ = $1; } |
| | ecpg_sconst { $$ = $1; } |
| | '*' { $$ = mm_strdup("*"); } |
| | '+' { $$ = mm_strdup("+"); } |
| | '-' { $$ = mm_strdup("-"); } |
| | '/' { $$ = mm_strdup("/"); } |
| | '%' { $$ = mm_strdup("%"); } |
| | NULL_P { $$ = mm_strdup("NULL"); } |
| | S_ADD { $$ = mm_strdup("+="); } |
| | S_AND { $$ = mm_strdup("&&"); } |
| | S_ANYTHING { $$ = make_name(); } |
| | S_AUTO { $$ = mm_strdup("auto"); } |
| | S_CONST { $$ = mm_strdup("const"); } |
| | S_DEC { $$ = mm_strdup("--"); } |
| | S_DIV { $$ = mm_strdup("/="); } |
| | S_DOTPOINT { $$ = mm_strdup(".*"); } |
| | S_EQUAL { $$ = mm_strdup("=="); } |
| | S_EXTERN { $$ = mm_strdup("extern"); } |
| | S_INC { $$ = mm_strdup("++"); } |
| | S_LSHIFT { $$ = mm_strdup("<<"); } |
| | S_MEMBER { $$ = mm_strdup("->"); } |
| | S_MEMPOINT { $$ = mm_strdup("->*"); } |
| | S_MOD { $$ = mm_strdup("%="); } |
| | S_MUL { $$ = mm_strdup("*="); } |
| | S_NEQUAL { $$ = mm_strdup("!="); } |
| | S_OR { $$ = mm_strdup("||"); } |
| | S_REGISTER { $$ = mm_strdup("register"); } |
| | S_RSHIFT { $$ = mm_strdup(">>"); } |
| | S_STATIC { $$ = mm_strdup("static"); } |
| | S_SUB { $$ = mm_strdup("-="); } |
| | S_TYPEDEF { $$ = mm_strdup("typedef"); } |
| | S_VOLATILE { $$ = mm_strdup("volatile"); } |
| | SQL_BOOL { $$ = mm_strdup("bool"); } |
| | ENUM_P { $$ = mm_strdup("enum"); } |
| | HOUR_P { $$ = mm_strdup("hour"); } |
| | INT_P { $$ = mm_strdup("int"); } |
| | SQL_LONG { $$ = mm_strdup("long"); } |
| | MINUTE_P { $$ = mm_strdup("minute"); } |
| | MONTH_P { $$ = mm_strdup("month"); } |
| | SECOND_P { $$ = mm_strdup("second"); } |
| | SQL_SHORT { $$ = mm_strdup("short"); } |
| | SQL_SIGNED { $$ = mm_strdup("signed"); } |
| | SQL_STRUCT { $$ = mm_strdup("struct"); } |
| | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } |
| | YEAR_P { $$ = mm_strdup("year"); } |
| | CHAR_P { $$ = mm_strdup("char"); } |
| | FLOAT_P { $$ = mm_strdup("float"); } |
| | TO { $$ = mm_strdup("to"); } |
| | UNION { $$ = mm_strdup("union"); } |
| | VARCHAR { $$ = mm_strdup("varchar"); } |
| | '[' { $$ = mm_strdup("["); } |
| | ']' { $$ = mm_strdup("]"); } |
| | '=' { $$ = mm_strdup("="); } |
| | ':' { $$ = mm_strdup(":"); } |
| ; |
| |
| DeallocateStmt: DEALLOCATE prepared_name { check_declared_list($2); $$ = $2; } |
| | DEALLOCATE PREPARE prepared_name { check_declared_list($3); $$ = $3; } |
| | DEALLOCATE ALL { $$ = mm_strdup("all"); } |
| | DEALLOCATE PREPARE ALL { $$ = mm_strdup("all"); } |
| ; |
| |
| Iresult: Iconst { $$ = $1; } |
| | '(' Iresult ')' { $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); } |
| | Iresult '+' Iresult { $$ = cat_str(3, $1, mm_strdup("+"), $3); } |
| | Iresult '-' Iresult { $$ = cat_str(3, $1, mm_strdup("-"), $3); } |
| | Iresult '*' Iresult { $$ = cat_str(3, $1, mm_strdup("*"), $3); } |
| | Iresult '/' Iresult { $$ = cat_str(3, $1, mm_strdup("/"), $3); } |
| | Iresult '%' Iresult { $$ = cat_str(3, $1, mm_strdup("%"), $3); } |
| | ecpg_sconst { $$ = $1; } |
| | ColId { $$ = $1; } |
| | ColId '(' var_type ')' { if (pg_strcasecmp($1, "sizeof") != 0) |
| mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition"); |
| else |
| $$ = cat_str(4, $1, mm_strdup("("), $3.type_str, mm_strdup(")")); |
| } |
| ; |
| |
| execute_rest: /* EMPTY */ { $$ = EMPTY; } |
| | ecpg_using opt_ecpg_into { $$ = EMPTY; } |
| | ecpg_into ecpg_using { $$ = EMPTY; } |
| | ecpg_into { $$ = EMPTY; } |
| ; |
| |
| ecpg_into: INTO into_list { $$ = EMPTY; } |
| | into_descriptor { $$ = $1; } |
| ; |
| |
| opt_ecpg_into: /* EMPTY */ { $$ = EMPTY; } |
| | ecpg_into { $$ = $1; } |
| ; |
| |
| ecpg_fetch_into: ecpg_into { $$ = $1; } |
| | using_descriptor |
| { |
| struct variable *var; |
| |
| var = argsinsert->variable; |
| remove_variable_from_list(&argsinsert, var); |
| add_variable_to_head(&argsresult, var, &no_indicator); |
| $$ = $1; |
| } |
| ; |
| |
| opt_ecpg_fetch_into: /* EMPTY */ { $$ = EMPTY; } |
| | ecpg_fetch_into { $$ = $1; } |
| ; |
| |
| %% |
| |
| void base_yyerror(const char *error) |
| { |
| /* translator: %s is typically the translation of "syntax error" */ |
| mmerror(PARSE_ERROR, ET_ERROR, "%s at or near \"%s\"", |
| _(error), token_start ? token_start : base_yytext); |
| } |
| |
| void parser_init(void) |
| { |
| /* This function is empty. It only exists for compatibility with the backend parser right now. */ |
| } |