From 2ea179f36102edc8df6be9e728b24bcb264ec52e Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvherre@alvh.no-ip.org> Date: Wed, 11 Nov 2009 19:25:42 +0000 Subject: [PATCH] Support optional FROM/IN in FETCH and MOVE The main motivation for this is that it's required for Informix compatibility in ECPG. This patch makes the ECPG and core grammars a bit closer to one another for these productions. Author: Zoltan Boszormenyi --- src/backend/parser/gram.y | 78 ++++++++++--------- src/interfaces/ecpg/preproc/ecpg.addons | 76 ++++++++---------- .../expected/compat_informix-test_informix.c | 2 +- .../compat_informix-test_informix.stderr | 6 +- 4 files changed, 77 insertions(+), 85 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4325e4d0ed..38d9764b55 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.690 2009/11/09 18:38:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.691 2009/11/11 19:25:40 alvherre Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -332,7 +332,7 @@ static TypeName *TableFuncTypeName(List *columns); %type <ival> opt_column event cursor_options opt_hold opt_set_data %type <objtype> reindex_type drop_type comment_type -%type <node> fetch_direction limit_clause select_limit_value +%type <node> fetch_args limit_clause select_limit_value offset_clause select_offset_value select_offset_value2 opt_select_fetch_first_value %type <ival> row_or_rows first_or_next @@ -4180,142 +4180,144 @@ comment_text: * *****************************************************************************/ -FetchStmt: FETCH fetch_direction from_in name +FetchStmt: FETCH fetch_args { FetchStmt *n = (FetchStmt *) $2; - n->portalname = $4; - n->ismove = FALSE; - $$ = (Node *)n; - } - | FETCH name - { - FetchStmt *n = makeNode(FetchStmt); - n->direction = FETCH_FORWARD; - n->howMany = 1; - n->portalname = $2; n->ismove = FALSE; $$ = (Node *)n; } - | MOVE fetch_direction from_in name + | MOVE fetch_args { FetchStmt *n = (FetchStmt *) $2; - n->portalname = $4; n->ismove = TRUE; $$ = (Node *)n; } - | MOVE name + ; + +fetch_args: name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $1; n->direction = FETCH_FORWARD; n->howMany = 1; - n->portalname = $2; - n->ismove = TRUE; $$ = (Node *)n; } - ; - -fetch_direction: - /*EMPTY*/ + | from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $2; n->direction = FETCH_FORWARD; n->howMany = 1; $$ = (Node *)n; } - | NEXT + | NEXT opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_FORWARD; n->howMany = 1; $$ = (Node *)n; } - | PRIOR + | PRIOR opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_BACKWARD; n->howMany = 1; $$ = (Node *)n; } - | FIRST_P + | FIRST_P opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_ABSOLUTE; n->howMany = 1; $$ = (Node *)n; } - | LAST_P + | LAST_P opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_ABSOLUTE; n->howMany = -1; $$ = (Node *)n; } - | ABSOLUTE_P SignedIconst + | ABSOLUTE_P SignedIconst opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $4; n->direction = FETCH_ABSOLUTE; n->howMany = $2; $$ = (Node *)n; } - | RELATIVE_P SignedIconst + | RELATIVE_P SignedIconst opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $4; n->direction = FETCH_RELATIVE; n->howMany = $2; $$ = (Node *)n; } - | SignedIconst + | SignedIconst opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_FORWARD; n->howMany = $1; $$ = (Node *)n; } - | ALL + | ALL opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_FORWARD; n->howMany = FETCH_ALL; $$ = (Node *)n; } - | FORWARD + | FORWARD opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_FORWARD; n->howMany = 1; $$ = (Node *)n; } - | FORWARD SignedIconst + | FORWARD SignedIconst opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $4; n->direction = FETCH_FORWARD; n->howMany = $2; $$ = (Node *)n; } - | FORWARD ALL + | FORWARD ALL opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $4; n->direction = FETCH_FORWARD; n->howMany = FETCH_ALL; $$ = (Node *)n; } - | BACKWARD + | BACKWARD opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $3; n->direction = FETCH_BACKWARD; n->howMany = 1; $$ = (Node *)n; } - | BACKWARD SignedIconst + | BACKWARD SignedIconst opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $4; n->direction = FETCH_BACKWARD; n->howMany = $2; $$ = (Node *)n; } - | BACKWARD ALL + | BACKWARD ALL opt_from_in name { FetchStmt *n = makeNode(FetchStmt); + n->portalname = $4; n->direction = FETCH_BACKWARD; n->howMany = FETCH_ALL; $$ = (Node *)n; @@ -4326,6 +4328,10 @@ from_in: FROM {} | IN_P {} ; +opt_from_in: from_in {} + | /* EMPTY */ {} + ; + /***************************************************************************** * diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index 7550616170..9ef3d19100 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.6 2009/11/05 23:24:27 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.7 2009/11/11 19:25:40 alvherre Exp $ */ ECPG: stmtClosePortalStmt block { @@ -206,16 +206,38 @@ ECPG: ConstraintAttributeSpecConstraintTimeSpecConstraintDeferrabilitySpec addon if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 ) mmerror(PARSE_ERROR, ET_ERROR, "constraint declared INITIALLY DEFERRED must be DEFERRABLE"); ECPG: var_valueNumericOnly addon -ECPG: fetch_directionSignedIconst addon if ($1[0] == '$') { free($1); $1 = make_str("$0"); } -ECPG: fetch_directionABSOLUTE_PSignedIconst addon -ECPG: fetch_directionRELATIVE_PSignedIconst addon -ECPG: fetch_directionFORWARDSignedIconst addon -ECPG: fetch_directionBACKWARDSignedIconst addon +ECPG: fetch_argsname addon + add_additional_variables($1, false); +ECPG: fetch_argsfrom_inname addon + add_additional_variables($2, false); +ECPG: fetch_argsNEXTopt_from_inname addon +ECPG: fetch_argsPRIORopt_from_inname addon +ECPG: fetch_argsFIRST_Popt_from_inname addon +ECPG: fetch_argsLAST_Popt_from_inname addon +ECPG: fetch_argsALLopt_from_inname addon +ECPG: fetch_argsFORWARDopt_from_inname addon +ECPG: fetch_argsBACKWARDopt_from_inname addon + add_additional_variables($3, false); +ECPG: fetch_argsSignedIconstopt_from_inname addon + add_additional_variables($3, false); + if ($1[0] == '$') + { + free($1); + $1 = make_str("$0"); + } +ECPG: fetch_argsFORWARDALLopt_from_inname addon +ECPG: fetch_argsBACKWARDALLopt_from_inname addon + add_additional_variables($4, false); +ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_inname addon +ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_inname addon +ECPG: fetch_argsFORWARDSignedIconstopt_from_inname addon +ECPG: fetch_argsBACKWARDSignedIconstopt_from_inname addon + add_additional_variables($4, false); if ($2[0] == '$') { free($2); @@ -336,47 +358,11 @@ ECPG: VariableShowStmtSHOWALL block mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); $$ = EMPTY; } -ECPG: FetchStmtFETCHfetch_directionfrom_inname block - { - add_additional_variables($4, false); - $$ = cat_str(4, make_str("fetch"), $2, $3, $4); - } -ECPG: FetchStmtFETCHname block +ECPG: FetchStmtMOVEfetch_args rule + | FETCH fetch_args ecpg_into { - add_additional_variables($2, false); - $$ = cat_str(2, make_str("fetch"), $2); + $$ = cat2_str(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: select_limitLIMITselect_limit_value','select_offset_value block { mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to server"); diff --git a/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c b/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c index 3d48a3a273..0dc8c7f08a 100644 --- a/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c +++ b/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c @@ -158,7 +158,7 @@ if (sqlca.sqlcode < 0) dosqlprint ( );} while (1) { - { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch forward from c", ECPGt_EOIT, + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch forward c", ECPGt_EOIT, ECPGt_int,&(i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_decimal,&(j),(long)1,(long)1,sizeof(decimal), diff --git a/src/interfaces/ecpg/test/expected/compat_informix-test_informix.stderr b/src/interfaces/ecpg/test/expected/compat_informix-test_informix.stderr index 89e9483ffb..d678788640 100644 --- a/src/interfaces/ecpg/test/expected/compat_informix-test_informix.stderr +++ b/src/interfaces/ecpg/test/expected/compat_informix-test_informix.stderr @@ -63,7 +63,7 @@ DETAIL: Key (i)=(7) already exists. [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_execute on line 95: OK: DECLARE CURSOR [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 57: query: fetch forward from c; with 0 parameter(s) on connection regress1 +[NO_PID]: ecpg_execute on line 57: query: fetch forward c; with 0 parameter(s) on connection regress1 [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_execute on line 57: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 @@ -75,7 +75,7 @@ DETAIL: Key (i)=(7) already exists. [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_get_data on line 57: RESULT: test offset: -1; array: yes [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 57: query: fetch forward from c; with 0 parameter(s) on connection regress1 +[NO_PID]: ecpg_execute on line 57: query: fetch forward c; with 0 parameter(s) on connection regress1 [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_execute on line 57: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 @@ -87,7 +87,7 @@ DETAIL: Key (i)=(7) already exists. [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_get_data on line 57: RESULT: a offset: -1; array: yes [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 57: query: fetch forward from c; with 0 parameter(s) on connection regress1 +[NO_PID]: ecpg_execute on line 57: query: fetch forward c; with 0 parameter(s) on connection regress1 [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_execute on line 57: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -- 2.40.0