Boszormenyi Zoltan írta: > Tom Lane írta: > >> Boszormenyi Zoltan <z...@cybertec.at> 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers