aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/preproc
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/preproc')
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.addons90
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c9
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.header25
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.trailer45
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.type1
-rw-r--r--src/interfaces/ecpg/preproc/preproc_extern.h1
-rw-r--r--src/interfaces/ecpg/preproc/type.h7
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;