diff options
Diffstat (limited to 'src/interfaces/ecpg/preproc')
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.addons | 90 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.c | 9 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.header | 25 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.trailer | 45 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.type | 1 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/preproc_extern.h | 1 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/type.h | 7 |
7 files changed, 162 insertions, 16 deletions
diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index 300381eaad5..974ce05664f 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -33,6 +33,7 @@ ECPG: stmtUpdateStmt block { output_statement($1, 1, ECPGst_prepnormal); } ECPG: stmtExecuteStmt block { + check_declared_list($1.name); if ($1.type == NULL || strlen($1.type) == 0) output_statement($1.name, 1, ECPGst_execute); else @@ -56,6 +57,7 @@ ECPG: stmtExecuteStmt block } ECPG: stmtPrepareStmt block { + check_declared_list($1.name); if ($1.type == NULL) output_prepare_statement($1.name, $1.stmt); else if (strlen($1.type) == 0) @@ -104,6 +106,10 @@ ECPG: stmtViewStmt rule whenever_action(2); free($1); } + | ECPGDeclareStmt + { + output_simple_statement($1, 0); + } | ECPGCursorStmt { output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); @@ -244,14 +250,20 @@ ECPG: var_valueNumericOnly addon $1 = mm_strdup("$0"); } ECPG: fetch_argscursor_name addon - add_additional_variables($1, false); + struct cursor *ptr = add_additional_variables($1, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + if ($1[0] == ':') { free($1); $1 = mm_strdup("$0"); } ECPG: fetch_argsfrom_incursor_name addon - add_additional_variables($2, false); + struct cursor *ptr = add_additional_variables($2, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + if ($2[0] == ':') { free($2); @@ -262,14 +274,20 @@ ECPG: fetch_argsPRIORopt_from_incursor_name addon ECPG: fetch_argsFIRST_Popt_from_incursor_name addon ECPG: fetch_argsLAST_Popt_from_incursor_name addon ECPG: fetch_argsALLopt_from_incursor_name addon - add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables($3, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + if ($3[0] == ':') { free($3); $3 = mm_strdup("$0"); } ECPG: fetch_argsSignedIconstopt_from_incursor_name addon - add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables($3, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + if ($3[0] == ':') { free($3); @@ -282,7 +300,10 @@ ECPG: fetch_argsSignedIconstopt_from_incursor_name addon } ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon - add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables($4, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + if ($4[0] == ':') { free($4); @@ -292,7 +313,10 @@ ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon - add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables($4, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + if ($4[0] == ':') { free($4); @@ -348,6 +372,9 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt char *comment, *c1, *c2; int (* strcmp_fn)(const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); + if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) + mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); + for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp_fn($2, ptr->name) == 0) @@ -388,6 +415,17 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt ECPG: ClosePortalStmtCLOSEcursor_name block { char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : $2; + struct cursor *ptr = NULL; + for (ptr = cur; ptr != NULL; ptr = ptr -> next) + { + if (strcmp($2, ptr -> name) == 0) + { + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + + break; + } + } $$ = cat2_str(mm_strdup("close"), cursor_marker); } ECPG: opt_hold block @@ -466,49 +504,73 @@ ECPG: FetchStmtMOVEfetch_args rule | FETCH FORWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables($3, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker); } | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables($4, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker); } | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables($3, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker); } | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables($4, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker); } | MOVE FORWARD cursor_name { char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables($3, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("move forward"), cursor_marker); } | MOVE FORWARD from_in cursor_name { char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables($4, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("move forward from"), cursor_marker); } | MOVE BACKWARD cursor_name { char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables($3, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("move backward"), cursor_marker); } | MOVE BACKWARD from_in cursor_name { char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables($4, false); + if (ptr -> connection) + connection = mm_strdup(ptr -> connection); + $$ = cat_str(2, mm_strdup("move backward from"), cursor_marker); } ECPG: limit_clauseLIMITselect_limit_value','select_offset_value block diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index f362664fdc1..3c6506017d8 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -28,6 +28,7 @@ struct _include_path *include_paths = NULL; struct cursor *cur = NULL; struct typedefs *types = NULL; struct _defines *defines = NULL; +struct declared_list *g_declared_list = NULL; static void help(const char *progname) @@ -347,6 +348,7 @@ main(int argc, char *const argv[]) struct cursor *ptr; struct _defines *defptr; struct typedefs *typeptr; + struct declared_list *list; /* remove old cursor definitions if any are still there */ for (ptr = cur; ptr != NULL;) @@ -373,6 +375,13 @@ main(int argc, char *const argv[]) } cur = NULL; + /* remove old delared statements if any are still there */ + for (list = g_declared_list; list != NULL;) + { + struct declared_list *this = list; + free(this); + } + /* remove non-pertinent old defines as well */ while (defines && !defines->pertinent) { diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index f37112dd4dc..5263df2b6e0 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -64,6 +64,8 @@ static struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NUL static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0); +static bool check_declared_list(const char*); + /* * Handle parsing errors and warnings */ @@ -576,6 +578,29 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, types = this; } } + +/* + * check an SQL identifier is declared or not. + * If it is already declared, the global variable + * connection will be changed to the related connection. + */ +static bool +check_declared_list(const char *name) +{ + struct declared_list *ptr = NULL; + for (ptr = g_declared_list; ptr != NULL; ptr = ptr -> next) + { + if (strcmp(name, ptr -> name) == 0) + { + if (ptr -> connection) + { + connection = mm_strdup(ptr -> connection); + return true; + } + } + } + return false; +} %} %expect 0 diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index 0e4a0413930..d699e0abbfc 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -291,6 +291,42 @@ prepared_name: name ; /* + * 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, "declared name %s is already defined", 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. */ @@ -300,9 +336,14 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared 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)); - const char *con = connection ? connection : "NULL"; 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) @@ -321,7 +362,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared this->next = cur; this->name = $2; this->function = (current_function ? mm_strdup(current_function) : NULL); - this->connection = connection; + 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; diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type index eca298bdb80..e8c36119ed0 100644 --- a/src/interfaces/ecpg/preproc/ecpg.type +++ b/src/interfaces/ecpg/preproc/ecpg.type @@ -9,6 +9,7 @@ %type <str> ECPGDeallocateDescr %type <str> ECPGDeclaration %type <str> ECPGDeclare +%type <str> ECPGDeclareStmt %type <str> ECPGDescribe %type <str> ECPGDisconnect %type <str> ECPGExecuteImmediateStmt diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h index 51d5f94f07f..992797b8bb1 100644 --- a/src/interfaces/ecpg/preproc/preproc_extern.h +++ b/src/interfaces/ecpg/preproc/preproc_extern.h @@ -47,6 +47,7 @@ extern struct _include_path *include_paths; extern struct cursor *cur; extern struct typedefs *types; extern struct _defines *defines; +extern struct declared_list *g_declared_list; extern struct ECPGtype ecpg_no_indicator; extern struct variable no_indicator; extern struct arguments *argsinsert; diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h index 20b279001b2..01ccb74fdc6 100644 --- a/src/interfaces/ecpg/preproc/type.h +++ b/src/interfaces/ecpg/preproc/type.h @@ -141,6 +141,13 @@ struct cursor struct cursor *next; }; +struct declared_list +{ + char *name; + char *connection; + struct declared_list *next; +}; + struct typedefs { char *name; |