Boszormenyi Zoltan írta:
> Tom Lane írta:
>
>> Boszormenyi Zoltan <[email protected]> writes:
>>
>>
>>> Tom Lane írta:
>>>
>>>
>>>> I'd look at requiring from_in as being the least-bad alternative.
>>>>
>>>>
>>
>>
>>> Hm. "FETCH FORWARD variable" can only be a rowcount var
>>> only if there's something afterwards, no? With the proposed
>>> change in fetch_direction (moving FORWARD and BACKWARD
>>> without the rowcount upper to the parent rules) now the parser is
>>> able to look behind "FORWARD variable"...
>>>
>>>
>> The fundamental reason that there's a problem here is that ecpg has
>> decided to accept a syntax that the backend doesn't (ie, FETCH with a
>> fetch direction but no FROM/IN). I think that that's basically a bad
>> idea: it's not helpful to users to be inconsistent, and it requires ugly
>> hacks in ecpg, and now ugly hacks in the core grammar as well. We
>> should resolve it either by taking out that syntax from ecpg, or by
>> making the backend accept it too. Not by uglifying the grammars some
>> more in order to keep them inconsistent.
>>
>> If we were going to allow it in the core, I think moving the cursor
>> name into the fetch_direction production might work, ie, change
>> fetch_direction to fetch_args and make it cover everything that
>> FETCH and MOVE share. Probably from_in could become opt_from_in,
>> since the alternatives for it are fully reserved words already, and we
>> wouldn't need to double up any of the fetch_direction productions.
>>
>> regards, tom lane
>>
>>
>
> Your guess about making from_in into opt_from_in
> seems good, mostly. I tried doing exactly that and simply
> adding an empty match into from_in, I got shift/reduce conflicts
> only in "opt_from_in cursor_name". So, this rule has to be
> unrolled into 3 rules, or keeping a separate "from_in" just for
> having a separate "cursor_name" and "from_in cursor_name".
> I decided that I use the second method, it's shorter.
>
OK, here's the WIP patch for the unified core/ecpg grammar,
with opt_from_in. But I am still getting the 2 shift/reduce
conflicts exactly for the FORWARD and BACKWARD rules
that I was getting originally. Can you look at this patch and
point me to the right direction in solving it? Thanks in advance.
> Best regards,
> Zoltán Böszörményi
>
>
--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics
----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/
diff -dcrpN pgsql.orig/src/backend/parser/gram.y pgsql/src/backend/parser/gram.y
*** pgsql.orig/src/backend/parser/gram.y 2009-08-03 10:38:28.000000000 +0200
--- pgsql/src/backend/parser/gram.y 2009-08-09 17:48:36.000000000 +0200
*************** static TypeName *TableFuncTypeName(List
*** 253,259 ****
%type <str> relation_name copy_file_name
database_name access_method_clause access_method attr_name
! index_name name file_name cluster_index_specification
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
opt_class opt_validator validator_clause
--- 253,259 ----
%type <str> relation_name copy_file_name
database_name access_method_clause access_method attr_name
! index_name name cursor_name file_name cluster_index_specification
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
opt_class opt_validator validator_clause
*************** static TypeName *TableFuncTypeName(List
*** 331,337 ****
%type <ival> opt_column event cursor_options opt_hold opt_set_data
%type <objtype> reindex_type drop_type comment_type
! %type <node> fetch_direction select_limit_value select_offset_value
select_offset_value2 opt_select_fetch_first_value
%type <ival> row_or_rows first_or_next
--- 331,337 ----
%type <ival> opt_column event cursor_options opt_hold opt_set_data
%type <objtype> reindex_type drop_type comment_type
! %type <node> fetch_args select_limit_value select_offset_value
select_offset_value2 opt_select_fetch_first_value
%type <ival> row_or_rows first_or_next
*************** reloption_elem:
*** 1915,1921 ****
*****************************************************************************/
ClosePortalStmt:
! CLOSE name
{
ClosePortalStmt *n = makeNode(ClosePortalStmt);
n->portalname = $2;
--- 1915,1921 ----
*****************************************************************************/
ClosePortalStmt:
! CLOSE cursor_name
{
ClosePortalStmt *n = makeNode(ClosePortalStmt);
n->portalname = $2;
*************** comment_text:
*** 4082,4223 ****
*
*****************************************************************************/
! FetchStmt: FETCH fetch_direction from_in name
{
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
{
FetchStmt *n = (FetchStmt *) $2;
- n->portalname = $4;
n->ismove = TRUE;
$$ = (Node *)n;
}
! | MOVE name
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = 1;
- n->portalname = $2;
- n->ismove = TRUE;
$$ = (Node *)n;
}
! ;
!
! fetch_direction:
! /*EMPTY*/
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | NEXT
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | PRIOR
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_BACKWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | FIRST_P
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_ABSOLUTE;
n->howMany = 1;
$$ = (Node *)n;
}
! | LAST_P
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_ABSOLUTE;
n->howMany = -1;
$$ = (Node *)n;
}
! | ABSOLUTE_P SignedIconst
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_ABSOLUTE;
n->howMany = $2;
$$ = (Node *)n;
}
! | RELATIVE_P SignedIconst
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_RELATIVE;
n->howMany = $2;
$$ = (Node *)n;
}
! | SignedIconst
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = $1;
$$ = (Node *)n;
}
! | ALL
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
}
! | FORWARD
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | FORWARD SignedIconst
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = $2;
$$ = (Node *)n;
}
! | FORWARD ALL
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
}
! | BACKWARD
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_BACKWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | BACKWARD SignedIconst
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_BACKWARD;
n->howMany = $2;
$$ = (Node *)n;
}
! | BACKWARD ALL
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_BACKWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
--- 4082,4226 ----
*
*****************************************************************************/
! FetchStmt: FETCH fetch_args
{
FetchStmt *n = (FetchStmt *) $2;
n->ismove = FALSE;
$$ = (Node *)n;
}
! | MOVE fetch_args
{
FetchStmt *n = (FetchStmt *) $2;
n->ismove = TRUE;
$$ = (Node *)n;
}
! ;
!
! fetch_args:
! cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $1;
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $2;
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | NEXT opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | PRIOR opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_BACKWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | FIRST_P opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_ABSOLUTE;
n->howMany = 1;
$$ = (Node *)n;
}
! | LAST_P opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_ABSOLUTE;
n->howMany = -1;
$$ = (Node *)n;
}
! | ABSOLUTE_P SignedIconst opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
n->direction = FETCH_ABSOLUTE;
n->howMany = $2;
$$ = (Node *)n;
}
! | RELATIVE_P SignedIconst opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
n->direction = FETCH_RELATIVE;
n->howMany = $2;
$$ = (Node *)n;
}
! | SignedIconst opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_FORWARD;
n->howMany = $1;
$$ = (Node *)n;
}
! | ALL opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_FORWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
}
! | FORWARD opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | FORWARD SignedIconst opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
n->direction = FETCH_FORWARD;
n->howMany = $2;
$$ = (Node *)n;
}
! | FORWARD ALL opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
n->direction = FETCH_FORWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
}
! | BACKWARD opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
n->direction = FETCH_BACKWARD;
n->howMany = 1;
$$ = (Node *)n;
}
! | BACKWARD SignedIconst opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
n->direction = FETCH_BACKWARD;
n->howMany = $2;
$$ = (Node *)n;
}
! | BACKWARD ALL opt_from_in cursor_name
{
FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
n->direction = FETCH_BACKWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
*************** from_in: FROM {}
*** 4228,4233 ****
--- 4231,4241 ----
| IN_P {}
;
+ opt_from_in: FROM {}
+ | IN_P {}
+ | /* EMPTY */ {}
+ ;
+
/*****************************************************************************
*
*************** set_target_list:
*** 6847,6853 ****
* CURSOR STATEMENTS
*
*****************************************************************************/
! DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
{
DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
n->portalname = $2;
--- 6855,6861 ----
* CURSOR STATEMENTS
*
*****************************************************************************/
! DeclareCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR SelectStmt
{
DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
n->portalname = $2;
*************** DeclareCursorStmt: DECLARE name cursor_o
*** 6858,6863 ****
--- 6866,6874 ----
}
;
+ cursor_name: name { $$ = $1; }
+ ;
+
cursor_options: /*EMPTY*/ { $$ = 0; }
| cursor_options NO SCROLL { $$ = $1 | CURSOR_OPT_NO_SCROLL; }
| cursor_options SCROLL { $$ = $1 | CURSOR_OPT_SCROLL; }
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons pgsql/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons 2009-01-30 17:28:46.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/ecpg.addons 2009-08-09 19:50:07.000000000 +0200
*************** ECPG: ConstraintAttributeSpecConstraintT
*** 206,226 ****
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
if ($2[0] == '$')
{
free($2);
$2 = make_str("$0");
}
ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
{
$$.name = $2;
--- 206,287 ----
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
if ($1[0] == '$')
{
free($1);
$1 = make_str("$0");
}
! ECPG: fetch_argscursor_name addon
! current_cursor = mm_strdup($1);
! if ($1[0] == ':')
! {
! free($1);
! $1 = make_str("$0");
! }
! ECPG: fetch_argsfrom_incursor_name addon
! current_cursor = mm_strdup($2);
! if ($2[0] == ':')
! {
! free($2);
! $2 = make_str("$0");
! }
! ECPG: fetch_argsNEXTopt_from_incursor_name addon
! 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
! ECPG: fetch_argsFORWARDopt_from_incursor_name addon
! ECPG: fetch_argsBACKWARDopt_from_incursor_name addon
! current_cursor = mm_strdup($3);
! if ($3[0] == ':')
! {
! free($3);
! $3 = make_str("$0");
! }
! ECPG: fetch_argsSignedIconstopt_from_incursor_name addon
! if ($1[0] == '$')
! {
! free($1);
! $1 = make_str("$0");
! }
! current_cursor = mm_strdup($3);
! if ($3[0] == ':')
! {
! free($3);
! $3 = make_str("$0");
! }
! ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon
! ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon
! current_cursor = mm_strdup($4);
! if ($4[0] == ':')
! {
! free($4);
! $4 = make_str("$0");
! }
! 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
if ($2[0] == '$')
{
free($2);
$2 = make_str("$0");
}
+ current_cursor = mm_strdup($4);
+ if ($4[0] == ':')
+ {
+ free($4);
+ $4 = make_str("$0");
+ }
+ ECPG: cursor_namename rule
+ | char_civar
+ {
+ char *curname = mm_alloc(strlen($1) + 2);
+ sprintf(curname, ":%s", $1);
+ free($1);
+ $1 = curname;
+ $$ = $1;
+ }
ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
{
$$.name = $2;
*************** ECPG: PrepareStmtPREPAREprepared_namepre
*** 235,243 ****
}
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)
{
--- 296,305 ----
}
ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
{ $$ = $2; }
! ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block
{
struct cursor *ptr, *this;
+ char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2);
for (ptr = cur; ptr != NULL; ptr = ptr->next)
{
*************** ECPG: DeclareCursorStmtDECLAREnamecursor
*** 251,257 ****
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;
--- 313,319 ----
this->name = $2;
this->connection = connection;
this->opened = false;
! this->command = cat_str(7, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for"), $7);
this->argsinsert = argsinsert;
this->argsresult = argsresult;
argsinsert = argsresult = NULL;
*************** ECPG: DeclareCursorStmtDECLAREnamecursor
*** 262,267 ****
--- 324,334 ----
else
$$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
}
+ ECPG: ClosePortalStmtCLOSEcursor_name block
+ {
+ char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2;
+ $$ = cat2_str(make_str("close"), cursor_marker);
+ }
ECPG: opt_hold block
{
if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true)
*************** ECPG: VariableShowStmtSHOWALL block
*** 326,372 ****
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
{
! 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 query that is not in a rule");
--- 393,412 ----
mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented");
$$ = EMPTY;
}
! ECPG: FetchStmtFETCHfetch_args block
{
! add_additional_variables(current_cursor, false);
! free(current_cursor);
! current_cursor = NULL;
! $$ = cat2_str(2, make_str("fetch"), $2);
}
! ECPG: FetchStmtMOVEfetch_args block
{
! add_additional_variables(current_cursor, false);
! free(current_cursor);
! current_cursor = NULL;
! $$ = cat2_str(2, make_str("move"), $2);
}
ECPG: SpecialRuleRelationOLD addon
if (!QueryIsRule)
mmerror(PARSE_ERROR, ET_ERROR, "OLD used in query that is not in a rule");
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.c pgsql/src/interfaces/ecpg/preproc/ecpg.c
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.c 2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/ecpg.c 2009-08-09 18:13:08.000000000 +0200
*************** enum COMPAT_MODE compat = ECPG_COMPAT_PG
*** 26,31 ****
--- 26,32 ----
struct _include_path *include_paths = NULL;
struct cursor *cur = NULL;
+ char *current_cursor = NULL;
struct typedefs *types = NULL;
struct _defines *defines = NULL;
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.trailer pgsql/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-09 15:42:06.000000000 +0200
*************** prepared_name: name {
*** 285,293 ****
* 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";
--- 285,294 ----
* Declare a prepared cursor. The syntax is different from the standard
* declare statement, so we create a new rule.
*/
! ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name
{
struct cursor *ptr, *this;
+ char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2);
struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
const char *con = connection ? connection : "NULL";
*************** ECPGCursorStmt: DECLARE name cursor_opt
*** 304,310 ****
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;
--- 305,311 ----
this->next = cur;
this->name = $2;
this->connection = connection;
! this->command = cat_str(6, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for $1"));
this->argsresult = NULL;
thisquery->type = &ecpg_query;
*************** ECPGCursorStmt: DECLARE name cursor_opt
*** 314,319 ****
--- 315,326 ----
sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
this->argsinsert = NULL;
+ if ($2[0] == ':')
+ {
+ struct variable *var = find_variable($2 + 1);
+ remove_variable_from_list(&argsinsert, var);
+ add_variable_to_head(&(this->argsinsert), var, &no_indicator);
+ }
add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
cur = this;
*************** ECPGFree: SQL_FREE name { $$ = $2; }
*** 954,960 ****
/*
* 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; }
--- 961,976 ----
/*
* open is an open cursor, at the moment this has to be removed
*/
! ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using
! {
! if ($2[0] == ':')
! {
! struct variable *var = find_variable($2 + 1);
! remove_variable_from_list(&argsinsert, var);
! }
! $$ = $2;
! }
! ;
opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; }
| ecpg_using { $$ = $1; }
*************** civarind: cvariable indicator
*** 1779,1784 ****
--- 1795,1807 ----
}
;
+ char_civar: char_variable
+ {
+ add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
+ $$ = $1;
+ }
+ ;
+
civar: cvariable
{
add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.type pgsql/src/interfaces/ecpg/preproc/ecpg.type
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.type 2008-11-14 11:03:33.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/ecpg.type 2009-08-09 15:42:06.000000000 +0200
***************
*** 43,48 ****
--- 43,49 ----
%type <str> c_term
%type <str> c_thing
%type <str> char_variable
+ %type <str> char_civar
%type <str> civar
%type <str> civarind
%type <str> ColLabel
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/extern.h pgsql/src/interfaces/ecpg/preproc/extern.h
*** pgsql.orig/src/interfaces/ecpg/preproc/extern.h 2009-07-17 07:50:56.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/extern.h 2009-08-09 18:13:31.000000000 +0200
*************** extern char *output_filename;
*** 47,52 ****
--- 47,53 ----
extern struct _include_path *include_paths;
extern struct cursor *cur;
+ extern char *current_cursor;
extern struct typedefs *types;
extern struct _defines *defines;
extern struct ECPGtype ecpg_no_indicator;
*************** extern struct descriptor *lookup_descrip
*** 91,96 ****
--- 92,98 ----
extern struct variable *descriptor_variable(const char *name, int input);
extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *);
extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *);
+ extern void remove_variable_from_list(struct arguments ** list, struct variable * var);
extern void dump_variables(struct arguments *, int);
extern struct typedefs *get_typedef(char *);
extern void adjust_array(enum ECPGttype, char **, char **, char *, char *, int, bool);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/parse.pl pgsql/src/interfaces/ecpg/preproc/parse.pl
*** pgsql.orig/src/interfaces/ecpg/preproc/parse.pl 2009-01-30 17:28:46.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/parse.pl 2009-08-09 17:53:11.000000000 +0200
*************** $replace_types{'unreserved_keyword'} = '
*** 57,63 ****
$replace_types{'Sconst'} = 'ignore';
# some production rules have to be ignored or replaced
! $replace_line{'fetch_direction'} = 'ignore';
$replace_line{"opt_array_boundsopt_array_bounds'['Iconst']'"} = 'ignore';
$replace_line{'col_name_keywordCHAR_P'} = 'ignore';
$replace_line{'col_name_keywordINT_P'} = 'ignore';
--- 57,63 ----
$replace_types{'Sconst'} = 'ignore';
# some production rules have to be ignored or replaced
! $replace_line{'fetch_args'} = 'ignore';
$replace_line{"opt_array_boundsopt_array_bounds'['Iconst']'"} = 'ignore';
$replace_line{'col_name_keywordCHAR_P'} = 'ignore';
$replace_line{'col_name_keywordINT_P'} = 'ignore';
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/variable.c pgsql/src/interfaces/ecpg/preproc/variable.c
*** pgsql.orig/src/interfaces/ecpg/preproc/variable.c 2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/variable.c 2009-08-09 15:42:06.000000000 +0200
*************** add_variable_to_tail(struct arguments **
*** 401,406 ****
--- 401,430 ----
*list = new;
}
+ void
+ remove_variable_from_list(struct arguments ** list, struct variable * var)
+ {
+ struct arguments *p, *prev = NULL;
+ bool found = false;
+
+ for (p = *list; p; p = p->next)
+ {
+ if (p->variable == var)
+ {
+ found = true;
+ break;
+ }
+ prev = p;
+ }
+ if (found)
+ {
+ if (prev)
+ prev->next = p->next;
+ else
+ *list = p->next;
+ }
+ }
+
/* Dump out a list of all the variable on this list.
This is a recursive function that works from the end of the list and
deletes the list as we go on.
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers