Re: Split-up ECPG patches - Mailing list pgsql-hackers

From Boszormenyi Zoltan
Subject Re: Split-up ECPG patches
Date
Msg-id 4A7F0DCE.2050508@cybertec.at
Whole thread Raw
In response to Re: Split-up ECPG patches  (Boszormenyi Zoltan <zb@cybertec.at>)
Responses Re: Split-up ECPG patches  (Boszormenyi Zoltan <zb@cybertec.at>)
List pgsql-hackers
Boszormenyi Zoltan írta:
> Tom Lane írta:
>
>> Boszormenyi Zoltan <zb@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.

pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: mixed, named notation support
Next
From: Peter Eisentraut
Date:
Subject: Re: a short trip in the wayback machine