From e339ed5f5007e37f18d57886ca6414d19cd92ee3 Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Fri, 14 Nov 2008 10:03:33 +0000 Subject: [PATCH] Added files containing changes between gram.y and preproc.y. --- src/interfaces/ecpg/preproc/ecpg.addons | 382 +++++ src/interfaces/ecpg/preproc/ecpg.header | 390 +++++ src/interfaces/ecpg/preproc/ecpg.tokens | 28 + src/interfaces/ecpg/preproc/ecpg.trailer | 2003 ++++++++++++++++++++++ src/interfaces/ecpg/preproc/ecpg.type | 143 ++ 5 files changed, 2946 insertions(+) create mode 100644 src/interfaces/ecpg/preproc/ecpg.addons create mode 100644 src/interfaces/ecpg/preproc/ecpg.header create mode 100644 src/interfaces/ecpg/preproc/ecpg.tokens create mode 100644 src/interfaces/ecpg/preproc/ecpg.trailer create mode 100644 src/interfaces/ecpg/preproc/ecpg.type diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons new file mode 100644 index 0000000000..e060ceb726 --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -0,0 +1,382 @@ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.1 2008/11/14 10:03:33 meskes Exp $ */ + +ECPG: stmtClosePortalStmt block + { + if (INFORMIX_MODE) + { + if (pg_strcasecmp($1+strlen("close "), "database") == 0) + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for close database statement\n"); + + fprintf(yyout, "{ ECPGdisconnect(__LINE__, \"CURRENT\");"); + whenever_action(2); + free($1); + break; + } + } + + output_statement($1, 0, ECPGst_normal); + } +ECPG: stmtDeallocateStmt block + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n"); + + output_deallocate_prepare_statement($1); + } +ECPG: stmtDeclareCursorStmt block + { output_simple_statement($1); } +ECPG: stmtDeleteStmt block +ECPG: stmtDiscardStmt block +ECPG: stmtFetchStmt block +ECPG: stmtInsertStmt block +ECPG: stmtSelectStmt block +ECPG: stmtUpdateStmt block + { output_statement($1, 1, ECPGst_normal); } +ECPG: stmtExecuteStmt block + { output_statement($1, 1, ECPGst_execute); } +ECPG: stmtPrepareStmt block + { + if ($1.type == NULL || strlen($1.type) == 0) + output_prepare_statement($1.name, $1.stmt); + else + output_statement(cat_str(5, make_str("prepare"), $1.name, $1.type, make_str("as"), $1.stmt), 0, ECPGst_normal); + } +ECPG: stmtTransactionStmt block + { + fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); + whenever_action(2); + free($1); + } +ECPG: stmtViewStmt rule + | ECPGAllocateDescr + { + fprintf(yyout,"ECPGallocate_desc(__LINE__, %s);",$1); + whenever_action(0); + free($1); + } + | ECPGConnect + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement\n"); + + fprintf(yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, $1, autocommit); + reset_variables(); + whenever_action(2); + free($1); + } + | ECPGCursorStmt + { + output_simple_statement($1); + } + | ECPGDeallocateDescr + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n"); + fprintf(yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1); + whenever_action(0); + free($1); + } + | ECPGDeclare + { + output_simple_statement($1); + } + | ECPGDescribe + { + fprintf(yyout, "{ ECPGdescribe(__LINE__, %s,", $1); + dump_variables(argsresult, 1); + fputs("ECPGt_EORT);", yyout); + fprintf(yyout, "}"); + output_line_number(); + + free($1); + } + | ECPGDisconnect + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement\n"); + + fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", + $1 ? $1 : "\"CURRENT\""); + whenever_action(2); + free($1); + } + | ECPGExecuteImmediateStmt { output_statement($1, 0, ECPGst_exec_immediate); } + | ECPGFree + { + const char *con = connection ? connection : "NULL"; + if (strcmp($1, "all")) + fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1); + else + fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); + + whenever_action(2); + free($1); + } + | ECPGGetDescriptor + { + lookup_descriptor($1.name, connection); + output_get_descr($1.name, $1.str); + free($1.name); + free($1.str); + } + | ECPGGetDescriptorHeader + { + lookup_descriptor($1, connection); + output_get_descr_header($1); + free($1); + } + | ECPGOpen + { + struct cursor *ptr; + + if ((ptr = add_additional_variables($1, true)) != NULL) + { + connection = ptr->connection ? mm_strdup(ptr->connection) : NULL; + output_statement(mm_strdup(ptr->command), 0, 0); + ptr->opened = true; + } + } + | ECPGSetAutocommit + { + fprintf(yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", $1, connection ? connection : "NULL"); + whenever_action(2); + free($1); + } + | ECPGSetConnection + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement\n"); + + fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1); + whenever_action(2); + free($1); + } + | ECPGSetDescriptor + { + lookup_descriptor($1.name, connection); + output_set_descr($1.name, $1.str); + free($1.name); + free($1.str); + } + | ECPGSetDescriptorHeader + { + lookup_descriptor($1, connection); + output_set_descr_header($1); + free($1); + } + | ECPGTypedef + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement\n"); + + fprintf(yyout, "%s", $1); + free($1); + output_line_number(); + } + | ECPGVar + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for var statement\n"); + + output_simple_statement($1); + } + | ECPGWhenever + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for whenever statement\n"); + + output_simple_statement($1); + } +ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listopt_oidscopy_fromcopy_file_namecopy_delimiteropt_withcopy_opt_list addon + if (strcmp($6, "to") == 0 && strcmp($7, "stdin") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin not possible\n"); + else if (strcmp($6, "from") == 0 && strcmp($7, "stdout") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "copy from stdout not possible\n"); + else if (strcmp($6, "from") == 0 && strcmp($7, "stdin") == 0) + mmerror(PARSE_ERROR, ET_WARNING, "copy from stdin not implemented\n"); +ECPG: CopyStmtCOPYselect_with_parensTOcopy_file_nameopt_withcopy_opt_list addon + if (strcmp($4, "stdin") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin not possible\n"); +ECPG: ConstraintAttributeSpecConstraintDeferrabilitySpecConstraintTimeSpec addon + if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 ) + mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE\n"); +ECPG: ConstraintAttributeSpecConstraintTimeSpecConstraintDeferrabilitySpec addon + if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 ) + mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE\n"); +ECPG: var_valueNumericOnly addon +ECPG: fetch_directionSignedIconst addon + if ($1[1] == '$') + { + free($1); + $1 = make_str("$0"); + } +ECPG: fetch_directionABSOLUTE_PSignedIconst addon +ECPG: fetch_directionRELATIVE_PSignedIconst addon +ECPG: fetch_directionFORWARDSignedIconst addon +ECPG: fetch_directionBACKWARDSignedIconst addon + if ($2[1] == '$') + { + free($2); + $2 = make_str("$0"); + } +ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block + { + $$.name = $2; + $$.type = $3; + $$.stmt = cat_str(3, make_str("\""), $5, make_str("\"")); + } + | PREPARE prepared_name FROM execstring + { + $$.name = $2; + $$.type = NULL; + $$.stmt = $4; + } +ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block + { $$ = $2; } +ECPG: DeclareCursorStmtDECLAREnamecursor_optionsCURSORopt_holdFORSelectStmt block + { + struct cursor *ptr, *this; + + for (ptr = cur; ptr != NULL; ptr = ptr->next) + { + if (strcmp($2, ptr->name) == 0) + mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" already defined\n", $2); + } + + this = (struct cursor *) mm_alloc(sizeof(struct cursor)); + + this->next = cur; + this->name = $2; + this->connection = connection; + this->opened = false; + this->command = cat_str(7, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for"), $7); + this->argsinsert = argsinsert; + this->argsresult = argsresult; + argsinsert = argsresult = NULL; + cur = this; + + if (INFORMIX_MODE) + $$ = cat_str(5, adjust_informix(this->argsinsert), adjust_informix(this->argsresult), make_str("/*"), mm_strdup(this->command), make_str("*/")); + else + $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); + } +ECPG: opt_hold block + { + if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true) + $$ = make_str("with hold"); + else + $$ = EMPTY; + } +ECPG: into_clauseINTOOptTempTableName block + { + FoundInto = 1; + $$= cat2_str(make_str("into"), $2); + } + | ecpg_into { $$ = EMPTY; } +ECPG: table_refselect_with_parens addon + mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias\n"); +ECPG: TypenameSimpleTypenameopt_array_bounds block + { $$ = cat2_str($1, $2.str); } +ECPG: TypenameSETOFSimpleTypenameopt_array_bounds block + { $$ = $$ = cat_str(3, make_str("setof"), $2, $3.str); } +ECPG: opt_array_boundsopt_array_bounds'['']' block + { + $$.index1 = $1.index1; + $$.index2 = $1.index2; + if (strcmp($$.index1, "-1") == 0) + $$.index1 = make_str("0"); + else if (strcmp($1.index2, "-1") == 0) + $$.index2 = make_str("0"); + $$.str = cat_str(2, $1.str, make_str("[]")); + } + | opt_array_bounds '[' Iresult ']' + { + $$.index1 = $1.index1; + $$.index2 = $1.index2; + if (strcmp($1.index1, "-1") == 0) + $$.index1 = strdup($3); + else if (strcmp($1.index2, "-1") == 0) + $$.index2 = strdup($3); + $$.str = cat_str(4, $1.str, make_str("["), $3, make_str("]")); + } +ECPG: opt_array_bounds + { + $$.index1 = make_str("-1"); + $$.index2 = make_str("-1"); + $$.str= EMPTY; + } +ECPG: IconstICONST block + { $$ = make_name(); } +ECPG: AexprConstNULL_P rule + | civar { $$ = $1; } + | civarind { $$ = $1; } +ECPG: ColIdcol_name_keyword rule + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | CHAR_P { $$ = make_str("char"); } + | VALUES { $$ = make_str("values"); } +ECPG: type_function_nametype_func_name_keyword rule + | ECPGKeywords { $$ = $1; } + | ECPGTypeName { $$ = $1; } + | ECPGCKeywords { $$ = $1; } +ECPG: VariableShowStmtSHOWALL block + { + mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL not implemented\n"); + $$ = EMPTY; + } +ECPG: FetchStmtFETCHfetch_directionfrom_inname block + { + add_additional_variables($4, false); + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + } +ECPG: FetchStmtFETCHname block + { + add_additional_variables($2, false); + $$ = cat_str(2, make_str("fetch"), $2); + } +ECPG: FetchStmtMOVEname rule + | FETCH fetch_direction from_in name ecpg_into + { + add_additional_variables($4, false); + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + } + | FETCH fetch_direction name ecpg_into + { + add_additional_variables($3, false); + $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); + } + | FETCH from_in name ecpg_into + { + add_additional_variables($3, false); + $$ = cat_str(3, make_str("fetch"), $2, $3); + } + | FETCH name ecpg_into + { + add_additional_variables($2, false); + $$ = cat2_str(make_str("fetch"), $2); + } + | FETCH fetch_direction name + { + add_additional_variables($3, false); + $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); + } + | FETCH from_in name + { + add_additional_variables($3, false); + $$ = cat_str(3, make_str("fetch"), $2, $3); + } +ECPG: SpecialRuleRelationOLD addon + if (!QueryIsRule) + mmerror(PARSE_ERROR, ET_ERROR, "OLD used in non-rule query\n"); +ECPG: SpecialRuleRelationNEW addon + if (!QueryIsRule) + mmerror(PARSE_ERROR, ET_ERROR, "NEW used in non-rule query\n"); +ECPG: select_limitLIMITselect_limit_value','select_offset_value block + { + mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to backend"); + $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4); + } +ECPG: SignedIconstIconst rule + | civar { $$ = $1; } diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header new file mode 100644 index 0000000000..6e47fa04f9 --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -0,0 +1,390 @@ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.header,v 1.1 2008/11/14 10:03:33 meskes Exp $ */ + +/* Copyright comment */ +%{ +#include "postgres_fe.h" + +#include "extern.h" +#include + +/* Location tracking support --- simpler than bison's default */ +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (N) \ + (Current) = (Rhs)[1]; \ + else \ + (Current) = (Rhs)[0]; \ + } while (0) + +/* + * The %name-prefix option below will make bison call base_yylex, but we + * really want it to call filtered_base_yylex (see parser.c). + */ +#define base_yylex filtered_base_yylex + +/* + * Variables containing simple states. + */ +int struct_level = 0; +int braces_open; /* brace level counter */ +int ecpg_informix_var = 0; +char *connection = NULL; +char *input_filename = NULL; + +static int QueryIsRule = 0, FoundInto = 0; +static int initializer = 0; +static int pacounter = 1; +static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */ +static struct this_type actual_type[STRUCT_DEPTH]; +static char *actual_startline[STRUCT_DEPTH]; + +/* temporarily store struct members while creating the data structure */ +struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; + +/* also store struct type so we can do a sizeof() later */ +static char *ECPGstruct_sizeof = NULL; + +/* for forward declarations we have to store some data as well */ +static char *forward_name = NULL; + +struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, {NULL}, 0}; +struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; + +struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, {NULL}, 0}; + +/* + * Handle parsing errors and warnings + */ +void +mmerror(int error_code, enum errortype type, char * error, ...) +{ + va_list ap; + + /* internationalize the error message string */ + error = _(error); + + fprintf(stderr, "%s:%d: ", input_filename, yylineno); + + switch(type) + { + case ET_WARNING: + fprintf(stderr, _("WARNING: ")); + break; + case ET_ERROR: + case ET_FATAL: + fprintf(stderr, _("ERROR: ")); + break; + } + + va_start(ap, error); + vfprintf(stderr, error, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + switch(type) + { + case ET_WARNING: + break; + case ET_ERROR: + ret_value = error_code; + break; + case ET_FATAL: + if (yyin) + fclose(yyin); + if (yyout) + fclose(yyout); + if (unlink(output_filename) != 0 && *output_filename != '-') + fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); + exit(error_code); + } +} + +/* + * string concatenation + */ + +static char * +cat2_str(char *str1, char *str2) +{ + char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2); + + strcpy(res_str, str1); + strcat(res_str, " "); + strcat(res_str, str2); + free(str1); + free(str2); + return(res_str); +} + +static char * +cat_str(int count, ...) +{ + va_list args; + int i; + char *res_str; + + va_start(args, count); + + res_str = va_arg(args, char *); + + /* now add all other strings */ + for (i = 1; i < count; i++) + res_str = cat2_str(res_str, va_arg(args, char *)); + + va_end(args); + + return(res_str); +} + +char * +make_str(const char *str) +{ + char * res_str = (char *)mm_alloc(strlen(str) + 1); + + strcpy(res_str, str); + return res_str; +} + +static char * +make2_str(char *str1, char *str2) +{ + char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1); + + strcpy(res_str, str1); + strcat(res_str, str2); + free(str1); + free(str2); + return(res_str); +} + +static char * +make3_str(char *str1, char *str2, char *str3) +{ + char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1); + + strcpy(res_str, str1); + strcat(res_str, str2); + strcat(res_str, str3); + free(str1); + free(str2); + free(str3); + return(res_str); +} + +/* and the rest */ +static char * +make_name(void) +{ + char * name = (char *)mm_alloc(yyleng + 1); + + strncpy(name, yytext, yyleng); + name[yyleng] = '\0'; + return(name); +} + +static char * +create_questionmarks(char *name, bool array) +{ + struct variable *p = find_variable(name); + int count; + char *result = EMPTY; + + /* In case we have a struct, we have to print as many "?" as there are attributes in the struct + * An array is only allowed together with an element argument + * This is essantially only used for inserts, but using a struct as input parameter is an error anywhere else + * so we don't have to worry here. */ + + if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct)) + { + struct ECPGstruct_member *m; + + if (p->type->type == ECPGt_struct) + m = p->type->u.members; + else + m = p->type->u.element->u.members; + + for (count = 0; m != NULL; m=m->next, count++); + } + else + count = 1; + + for (; count > 0; count --) + { + sprintf(pacounter_buffer, "$%d", pacounter++); + result = cat_str(3, result, strdup(pacounter_buffer), make_str(" , ")); + } + + /* removed the trailing " ," */ + + result[strlen(result)-3] = '\0'; + return(result); +} + +static char * +adjust_informix(struct arguments *list) +{ + /* Informix accepts DECLARE with variables that are out of scope when OPEN is called. + * for instance you can declare variables in a function, and then subsequently use them + * { + * declare_vars(); + * exec sql ... which uses vars declared in the above function + * + * This breaks standard and leads to some very dangerous programming. + * Since they do, we have to work around and accept their syntax as well. + * But we will do so ONLY in Informix mode. + * We have to change the variables to our own struct and just store the pointer instead of the variable + */ + + struct arguments *ptr; + char *result = make_str(""); + + for (ptr = list; ptr != NULL; ptr = ptr->next) + { + char temp[20]; /* this should be sufficient unless you have 8 byte integers */ + char *original_var; + + /* change variable name to "ECPG_informix_get_var()" */ + original_var = ptr->variable->name; + sprintf(temp, "%d))", ecpg_informix_var); + + if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) + { + ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0); + sprintf(temp, "%d, (", ecpg_informix_var++); + } + else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) + { + ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, (", ecpg_informix_var++); + } + else + { + ptr->variable = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, &(", ecpg_informix_var++); + } + + /* create call to "ECPG_informix_set_var(, . )" */ + result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n")); + + /* now the indicator if there is one */ + if (ptr->indicator->type->type != ECPGt_NO_INDICATOR) + { + /* change variable name to "ECPG_informix_get_var()" */ + original_var = ptr->indicator->name; + sprintf(temp, "%d))", ecpg_informix_var); + + /* create call to "ECPG_informix_set_var(, . )" */ + if (atoi(ptr->indicator->type->size) > 1) + { + ptr->indicator = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, (", ecpg_informix_var++); + } + else + { + ptr->indicator = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, &(", ecpg_informix_var++); + } + result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n")); + } + } + + return result; +} + +static struct cursor * +add_additional_variables(char *name, bool insert) +{ + struct cursor *ptr; + struct arguments *p; + + for (ptr = cur; ptr != NULL; ptr=ptr->next) + { + if (strcmp(ptr->name, name) == 0) + break; + } + + if (ptr == NULL) + { + mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor \"%s\"\n", name); + return NULL; + } + + if (insert) + { + /* add all those input variables that were given earlier + * note that we have to append here but have to keep the existing order */ + for (p = ptr->argsinsert; p; p = p->next) + add_variable_to_tail(&argsinsert, p->variable, p->indicator); + } + + /* add all those output variables that were given earlier */ + for (p = ptr->argsresult; p; p = p->next) + add_variable_to_tail(&argsresult, p->variable, p->indicator); + + return ptr; +} + +static void +add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enum, char *type_dimension, char *type_index, int initializer, int array) +{ + /* add entry to list */ + struct typedefs *ptr, *this; + + if ((type_enum == ECPGt_struct || + type_enum == ECPGt_union) && + initializer == 1) + mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in typedef command"); + else + { + for (ptr = types; ptr != NULL; ptr = ptr->next) + { + if (strcmp(name, ptr->name) == 0) + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "type %s already defined", name); + } + adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true); + + this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); + + /* initial definition */ + this->next = types; + this->name = name; + this->brace_level = braces_open; + this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); + this->type->type_enum = type_enum; + this->type->type_str = mm_strdup(name); + this->type->type_dimension = dimension; /* dimension of array */ + this->type->type_index = length; /* length of string */ + this->type->type_sizeof = ECPGstruct_sizeof; + this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ? + ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; + + if (type_enum != ECPGt_varchar && + type_enum != ECPGt_char && + type_enum != ECPGt_unsigned_char && + atoi(this->type->type_index) >= 0) + mmerror(PARSE_ERROR, ET_ERROR, "no multidimensional array support for simple data types"); + + types = this; + } +} +%} + +%name-prefix="base_yy" +%locations + +%union { + double dval; + char *str; + int ival; + struct when action; + struct index index; + int tagname; + struct this_type type; + enum ECPGttype type_enum; + enum ECPGdtype dtype_enum; + struct fetch_desc descriptor; + struct su_symbol struct_union; + struct prep prep; +} diff --git a/src/interfaces/ecpg/preproc/ecpg.tokens b/src/interfaces/ecpg/preproc/ecpg.tokens new file mode 100644 index 0000000000..9b51975116 --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.tokens @@ -0,0 +1,28 @@ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.tokens,v 1.1 2008/11/14 10:03:33 meskes Exp $ */ +/* special embedded SQL token */ +%token SQL_ALLOCATE SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK + SQL_CALL SQL_CARDINALITY SQL_CONNECT + SQL_COUNT + SQL_DATETIME_INTERVAL_CODE + SQL_DATETIME_INTERVAL_PRECISION SQL_DESCRIBE + SQL_DESCRIPTOR SQL_DISCONNECT SQL_FOUND + SQL_FREE SQL_GET SQL_GO SQL_GOTO SQL_IDENTIFIED + SQL_INDICATOR SQL_KEY_MEMBER SQL_LENGTH + SQL_LONG SQL_NULLABLE SQL_OCTET_LENGTH + SQL_OPEN SQL_OUTPUT SQL_REFERENCE + SQL_RETURNED_LENGTH SQL_RETURNED_OCTET_LENGTH SQL_SCALE + SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL SQL_SQLERROR + SQL_SQLPRINT SQL_SQLWARNING SQL_START SQL_STOP + SQL_STRUCT SQL_UNSIGNED SQL_VAR SQL_WHENEVER + +/* C token */ +%token S_ADD S_AND S_ANYTHING S_AUTO S_CONST S_DEC S_DIV + S_DOTPOINT S_EQUAL S_EXTERN S_INC S_LSHIFT S_MEMPOINT + S_MEMBER S_MOD S_MUL S_NEQUAL S_OR S_REGISTER S_RSHIFT + S_STATIC S_SUB S_VOLATILE + S_TYPEDEF + +%token TYPECAST +%token CSTRING CVARIABLE CPP_LINE IP +%token DOLCONST ECONST NCONST UCONST UIDENT + diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer new file mode 100644 index 0000000000..819c7646bf --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -0,0 +1,2003 @@ +/* $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: :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 [] = "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 + * and Peter Eisentraut + */ + +/* + * 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 = $3.code; + when_error.command = $3.command; + $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */")); + } + | SQL_WHENEVER NOT SQL_FOUND action + { + when_nf.code = $4.code; + when_nf.command = $4.command; + $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */")); + } + | SQL_WHENEVER SQL_SQLWARNING action + { + when_warn.code = $3.code; + when_warn.command = $3.command; + $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */")); + } + ; + +action : CONTINUE_P + { + $$.code = W_NOTHING; + $$.command = NULL; + $$.str = make_str("continue"); + } + | SQL_SQLPRINT + { + $$.code = W_SQLPRINT; + $$.command = NULL; + $$.str = make_str("sqlprint"); + } + | SQL_STOP + { + $$.code = W_STOP; + $$.command = NULL; + $$.str = make_str("stop"); + } + | SQL_GOTO name + { + $$.code = W_GOTO; + $$.command = strdup($2); + $$.str = cat2_str(make_str("goto "), $2); + } + | SQL_GO TO name + { + $$.code = W_GOTO; + $$.command = strdup($3); + $$.str = cat2_str(make_str("goto "), $3); + } + | DO name '(' c_args ')' + { + $$.code = W_DO; + $$.command = cat_str(4, $2, make_str("("), $4, make_str(")")); + $$.str = cat2_str(make_str("do"), mm_strdup($$.command)); + } + | DO SQL_BREAK + { + $$.code = W_BREAK; + $$.command = NULL; + $$.str = make_str("break"); + } + | SQL_CALL name '(' c_args ')' + { + $$.code = W_DO; + $$.command = cat_str(4, $2, make_str("("), $4, make_str(")")); + $$.str = cat2_str(make_str("call"), mm_strdup($$.command)); + } + | SQL_CALL name + { + $$.code = W_DO; + $$.command = cat2_str($2, make_str("()")); + $$.str = cat2_str(make_str("call"), mm_strdup($$.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" diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type new file mode 100644 index 0000000000..11f3d232fc --- /dev/null +++ b/src/interfaces/ecpg/preproc/ecpg.type @@ -0,0 +1,143 @@ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.type,v 1.1 2008/11/14 10:03:33 meskes Exp $ */ +%type ECPGAllocateDescr +%type ECPGCKeywords +%type ECPGColId +%type ECPGColLabel +%type ECPGColLabelCommon +%type ECPGConnect +%type ECPGCursorStmt +%type ECPGDeallocateDescr +%type ECPGDeclaration +%type ECPGDeclare +%type ECPGDescribe +%type ECPGDisconnect +%type ECPGExecuteImmediateStmt +%type ECPGFree +%type ECPGGetDescHeaderItem +%type ECPGGetDescItem +%type ECPGGetDescriptorHeader +%type ECPGKeywords +%type ECPGKeywords_rest +%type ECPGKeywords_vanames +%type ECPGOpen +%type ECPGSetAutocommit +%type ECPGSetConnection +%type ECPGSetDescHeaderItem +%type ECPGSetDescItem +%type ECPGSetDescriptorHeader +%type ECPGTypeName +%type ECPGTypedef +%type ECPGVar +%type ECPGVarDeclaration +%type ECPGWhenever +%type ECPGunreserved +%type ECPGunreserved_con +%type ECPGunreserved_interval +%type UsingConst +%type UsingValue +%type c_anything +%type c_args +%type c_list +%type c_stuff +%type c_stuff_item +%type c_term +%type c_thing +%type char_variable +%type civar +%type civarind +%type ColLabel +%type connect_options +%type connection_object +%type connection_target +%type coutputvariable +%type cvariable +%type db_prefix +%type CreateAsStmt +%type DeallocateStmt +%type dis_name +%type ecpg_bconst +%type ecpg_fconst +%type ecpg_ident +%type ecpg_interval +%type ecpg_into +%type ecpg_param +%type ecpg_sconst +%type ecpg_using +%type ecpg_xconst +%type enum_definition +%type enum_type +%type execstring +%type execute_rest +%type indicator +%type into_descriptor +%type Iresult +%type on_off +%type opt_bit_field +%type opt_connection_name +%type opt_database_name +%type opt_ecpg_using +%type opt_initializer +%type opt_options +%type opt_output +%type opt_pointer +%type opt_port +%type opt_reference +%type opt_scale +%type opt_server +%type opt_user +%type opt_opt_value +%type ora_user +%type precision +%type prepared_name +%type quoted_ident_stringvar +%type RuleStmt +%type s_struct_union +%type server +%type server_name +%type single_vt_declaration +%type storage_clause +%type storage_declaration +%type storage_modifier +%type struct_union_type +%type struct_union_type_with_symbol +%type symbol +%type type_declaration +%type unreserved_keyword +%type user_name +%type using_descriptor +%type var_declaration +%type var_type_declarations +%type variable +%type variable_declarations +%type variable_list +%type vt_declarations + +%type Op +%type IntConstVar +%type AllConstVar +%type CSTRING +%type CPP_LINE +%type CVARIABLE +%type DOLCONST +%type ECONST +%type NCONST +%type SCONST +%type UCONST +%type UIDENT + +%type s_struct_union_symbol + +%type ECPGGetDescriptor +%type ECPGSetDescriptor + +%type simple_type +%type signed_type +%type unsigned_type + +%type descriptor_item +%type desc_header_item + +%type var_type + +%type action + -- 2.40.0