(Oops, this didn't go to -HACKERS)

On 2010-10-04 2:46 PM +0300, Erik Rijkers wrote:
(HEAD from git://git.postgresql.org/git/postgresql.git)

The patch applies only with error.
If that error is ignored, the regression 'with' test failes.
If that is also ignored, it runs.

This patch conflicted with Tom's WITH .. INSERT change.  I tweaked the
patch just a bit and it now passes all regression tests so I can review
it.  New version attached for documentation purposes.


Regards,
Marko Tiikkaja
*** a/doc/src/sgml/ref/delete.sgml
--- b/doc/src/sgml/ref/delete.sgml
***************
*** 21,26 **** PostgreSQL documentation
--- 21,27 ----
  
   <refsynopsisdiv>
  <synopsis>
+ [ WITH [ RECURSIVE ] with_query ]
  DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ 
AS ] <replaceable class="parameter">alias</replaceable> ]
      [ USING <replaceable class="PARAMETER">using_list</replaceable> ]
      [ WHERE <replaceable class="PARAMETER">condition</replaceable> | WHERE 
CURRENT OF <replaceable class="PARAMETER">cursor_name</replaceable> ]
***************
*** 84,89 **** DELETE FROM [ ONLY ] <replaceable 
class="PARAMETER">table</replaceable> [ [ AS ]
--- 85,102 ----
  
    <variablelist>
     <varlistentry>
+     <term><replaceable class="PARAMETER">with_query</replaceable></term>
+     <listitem>
+      <para>
+       The <literal>WITH</literal> clause allows you to specify one or more
+       subqueries that can be referenced by name in the primary query.
+       See <xref linkend="queries-with"> and <xref linkend="sql-select">
+       for details.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <term><literal>ONLY</></term>
      <listitem>
       <para>
*** a/doc/src/sgml/ref/insert.sgml
--- b/doc/src/sgml/ref/insert.sgml
***************
*** 21,26 **** PostgreSQL documentation
--- 21,27 ----
  
   <refsynopsisdiv>
  <synopsis>
+ [ WITH [ RECURSIVE ] with_query ]
  INSERT INTO <replaceable class="PARAMETER">table</replaceable> [ ( 
<replaceable class="PARAMETER">column</replaceable> [, ...] ) ]
      { DEFAULT VALUES | VALUES ( { <replaceable 
class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) [, ...] | 
<replaceable class="PARAMETER">query</replaceable> }
      [ RETURNING * | <replaceable 
class="parameter">output_expression</replaceable> [ [ AS ] <replaceable 
class="parameter">output_name</replaceable> ] [, ...] ]
***************
*** 85,90 **** INSERT INTO <replaceable class="PARAMETER">table</replaceable> [ 
( <replaceable
--- 86,109 ----
  
    <variablelist>
     <varlistentry>
+     <term><replaceable class="PARAMETER">with_query</replaceable></term>
+     <listitem>
+      <para>
+       The <literal>WITH</literal> clause allows you to specify one or more
+       subqueries that can be referenced by name in the primary query.
+       See <xref linkend="queries-with"> and <xref linkend="sql-select">
+       for details.
+      </para>
+      <para>
+       It is possible that <literal>SELECT</literal> query also has
+       <literal>WITH</literal>.  In this case the two
+       <replaceable>with_query</replaceable> can be referred from
+       the <literal>SELECT</literal> query.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <term><replaceable class="PARAMETER">table</replaceable></term>
      <listitem>
       <para>
***************
*** 129,135 **** INSERT INTO <replaceable class="PARAMETER">table</replaceable> 
[ ( <replaceable
      <listitem>
       <para>
        The corresponding <replaceable>column</replaceable> will be filled with
!       its default value.
       </para>
      </listitem>
     </varlistentry>
--- 148,155 ----
      <listitem>
       <para>
        The corresponding <replaceable>column</replaceable> will be filled with
!       its default value. This clause is allowed in a simple VALUES list
!       without additional (LIMIT, etc.) clauses.
       </para>
      </listitem>
     </varlistentry>
*** a/doc/src/sgml/ref/update.sgml
--- b/doc/src/sgml/ref/update.sgml
***************
*** 21,26 **** PostgreSQL documentation
--- 21,27 ----
  
   <refsynopsisdiv>
  <synopsis>
+ [ WITH [ RECURSIVE ] with_query ]
  UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] 
<replaceable class="parameter">alias</replaceable> ]
      SET { <replaceable class="PARAMETER">column</replaceable> = { 
<replaceable class="PARAMETER">expression</replaceable> | DEFAULT } |
            ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( 
{ <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) 
} [, ...]
***************
*** 80,85 **** UPDATE [ ONLY ] <replaceable 
class="PARAMETER">table</replaceable> [ [ AS ] <rep
--- 81,98 ----
  
    <variablelist>
     <varlistentry>
+     <term><replaceable class="PARAMETER">with_query</replaceable></term>
+     <listitem>
+      <para>
+       The <literal>WITH</literal> clause allows you to specify one or more
+       subqueries that can be referenced by name in the primary query.
+       See <xref linkend="queries-with"> and <xref linkend="sql-select">
+       for details.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <term><replaceable class="PARAMETER">table</replaceable></term>
      <listitem>
       <para>
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 2288,2293 **** _copyInsertStmt(InsertStmt *from)
--- 2288,2294 ----
        COPY_NODE_FIELD(cols);
        COPY_NODE_FIELD(selectStmt);
        COPY_NODE_FIELD(returningList);
+       COPY_NODE_FIELD(withClause);
  
        return newnode;
  }
***************
*** 2301,2306 **** _copyDeleteStmt(DeleteStmt *from)
--- 2302,2308 ----
        COPY_NODE_FIELD(usingClause);
        COPY_NODE_FIELD(whereClause);
        COPY_NODE_FIELD(returningList);
+       COPY_NODE_FIELD(withClause);
  
        return newnode;
  }
***************
*** 2315,2320 **** _copyUpdateStmt(UpdateStmt *from)
--- 2317,2323 ----
        COPY_NODE_FIELD(whereClause);
        COPY_NODE_FIELD(fromClause);
        COPY_NODE_FIELD(returningList);
+       COPY_NODE_FIELD(withClause);
  
        return newnode;
  }
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 890,895 **** _equalInsertStmt(InsertStmt *a, InsertStmt *b)
--- 890,896 ----
        COMPARE_NODE_FIELD(cols);
        COMPARE_NODE_FIELD(selectStmt);
        COMPARE_NODE_FIELD(returningList);
+       COMPARE_NODE_FIELD(withClause);
  
        return true;
  }
***************
*** 901,906 **** _equalDeleteStmt(DeleteStmt *a, DeleteStmt *b)
--- 902,908 ----
        COMPARE_NODE_FIELD(usingClause);
        COMPARE_NODE_FIELD(whereClause);
        COMPARE_NODE_FIELD(returningList);
+       COMPARE_NODE_FIELD(withClause);
  
        return true;
  }
***************
*** 913,918 **** _equalUpdateStmt(UpdateStmt *a, UpdateStmt *b)
--- 915,921 ----
        COMPARE_NODE_FIELD(whereClause);
        COMPARE_NODE_FIELD(fromClause);
        COMPARE_NODE_FIELD(returningList);
+       COMPARE_NODE_FIELD(withClause);
  
        return true;
  }
*** a/src/backend/parser/analyze.c
--- b/src/backend/parser/analyze.c
***************
*** 283,288 **** transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
--- 283,295 ----
  
        qry->commandType = CMD_DELETE;
  
+       /* process the WITH clause independently of all else */
+       if (stmt->withClause)
+       {
+               qry->hasRecursive = stmt->withClause->recursive;
+               qry->cteList = transformWithClause(pstate, stmt->withClause);
+       }
+ 
        /* set up range table with just the result rel */
        qry->resultRelation = setTargetTable(pstate, stmt->relation,
                                                                  
interpretInhOption(stmt->relation->inhOpt),
***************
*** 343,348 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
--- 350,362 ----
        qry->commandType = CMD_INSERT;
        pstate->p_is_insert = true;
  
+       /* process the WITH clause independently of all else */
+       if (stmt->withClause)
+       {
+               qry->hasRecursive = stmt->withClause->recursive;
+               qry->cteList = transformWithClause(pstate, stmt->withClause);
+       }
+ 
        /*
         * We have three cases to deal with: DEFAULT VALUES (selectStmt == 
NULL),
         * VALUES list, or general SELECT input.  We special-case VALUES, both 
for
***************
*** 376,383 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
                pstate->p_relnamespace = NIL;
                sub_varnamespace = pstate->p_varnamespace;
                pstate->p_varnamespace = NIL;
-               /* There can't be any outer WITH to worry about */
-               Assert(pstate->p_ctenamespace == NIL);
        }
        else
        {
--- 390,395 ----
***************
*** 518,530 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
                List       *exprsLists = NIL;
                int                     sublist_length = -1;
  
-               /* process the WITH clause */
-               if (selectStmt->withClause)
-               {
-                       qry->hasRecursive = selectStmt->withClause->recursive;
-                       qry->cteList = transformWithClause(pstate, 
selectStmt->withClause);
-               }
- 
                foreach(lc, selectStmt->valuesLists)
                {
                        List       *sublist = (List *) lfirst(lc);
--- 530,535 ----
***************
*** 618,630 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
  
                Assert(list_length(valuesLists) == 1);
  
-               /* process the WITH clause */
-               if (selectStmt->withClause)
-               {
-                       qry->hasRecursive = selectStmt->withClause->recursive;
-                       qry->cteList = transformWithClause(pstate, 
selectStmt->withClause);
-               }
- 
                /* Do basic expression transformation (same as a ROW() expr) */
                exprList = transformExpressionList(pstate,
                                                                                
   (List *) linitial(valuesLists));
--- 623,628 ----
***************
*** 1045,1051 **** transformValuesClause(ParseState *pstate, SelectStmt *stmt)
                        if (IsA(col, SetToDefault))
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
!                                                errmsg("DEFAULT can only 
appear in a VALUES list within INSERT"),
                                                 parser_errposition(pstate, 
exprLocation(col))));
                        colexprs[i] = lappend(colexprs[i], col);
                        i++;
--- 1043,1050 ----
                        if (IsA(col, SetToDefault))
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
!                                                errmsg("DEFAULT can only 
appear in a simple VALUES list within INSERT"),
!                                                errhint("A simple VALUES list 
means it isn't modified by any of ORDER BY, OFFSET, LIMIT or WITH"),
                                                 parser_errposition(pstate, 
exprLocation(col))));
                        colexprs[i] = lappend(colexprs[i], col);
                        i++;
***************
*** 1794,1799 **** transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
--- 1793,1805 ----
        qry->commandType = CMD_UPDATE;
        pstate->p_is_update = true;
  
+       /* process the WITH clause independently of all else */
+       if (stmt->withClause)
+       {
+               qry->hasRecursive = stmt->withClause->recursive;
+               qry->cteList = transformWithClause(pstate, stmt->withClause);
+       }
+ 
        qry->resultRelation = setTargetTable(pstate, stmt->relation,
                                                                  
interpretInhOption(stmt->relation->inhOpt),
                                                                                
 true,
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 433,439 **** static RangeVar *makeRangeVarFromAnyName(List *names, int 
position, core_yyscan_
  %type <boolean> xml_whitespace_option
  
  %type <node>  common_table_expr
! %type <with>  with_clause
  %type <list>  cte_list
  
  %type <list>  window_clause window_definition_list opt_partition_clause
--- 433,439 ----
  %type <boolean> xml_whitespace_option
  
  %type <node>  common_table_expr
! %type <with>  with_clause opt_with_clause
  %type <list>  cte_list
  
  %type <list>  window_clause window_definition_list opt_partition_clause
***************
*** 7268,7278 **** DeallocateStmt: DEALLOCATE name
   
*****************************************************************************/
  
  InsertStmt:
!                       INSERT INTO qualified_name insert_rest returning_clause
                                {
!                                       $4->relation = $3;
!                                       $4->returningList = $5;
!                                       $$ = (Node *) $4;
                                }
                ;
  
--- 7268,7279 ----
   
*****************************************************************************/
  
  InsertStmt:
!                       opt_with_clause INSERT INTO qualified_name insert_rest 
returning_clause
                                {
!                                       $5->relation = $4;
!                                       $5->returningList = $6;
!                                       $5->withClause = $1;
!                                       $$ = (Node *) $5;
                                }
                ;
  
***************
*** 7328,7341 **** returning_clause:
   *
   
*****************************************************************************/
  
! DeleteStmt: DELETE_P FROM relation_expr_opt_alias
                        using_clause where_or_current_clause returning_clause
                                {
                                        DeleteStmt *n = makeNode(DeleteStmt);
!                                       n->relation = $3;
!                                       n->usingClause = $4;
!                                       n->whereClause = $5;
!                                       n->returningList = $6;
                                        $$ = (Node *)n;
                                }
                ;
--- 7329,7343 ----
   *
   
*****************************************************************************/
  
! DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias
                        using_clause where_or_current_clause returning_clause
                                {
                                        DeleteStmt *n = makeNode(DeleteStmt);
!                                       n->relation = $4;
!                                       n->usingClause = $5;
!                                       n->whereClause = $6;
!                                       n->returningList = $7;
!                                       n->withClause = $1;
                                        $$ = (Node *)n;
                                }
                ;
***************
*** 7390,7407 **** opt_nowait:  NOWAIT                                          
        { $$ = TRUE; }
   *
   
*****************************************************************************/
  
! UpdateStmt: UPDATE relation_expr_opt_alias
                        SET set_clause_list
                        from_clause
                        where_or_current_clause
                        returning_clause
                                {
                                        UpdateStmt *n = makeNode(UpdateStmt);
!                                       n->relation = $2;
!                                       n->targetList = $4;
!                                       n->fromClause = $5;
!                                       n->whereClause = $6;
!                                       n->returningList = $7;
                                        $$ = (Node *)n;
                                }
                ;
--- 7392,7410 ----
   *
   
*****************************************************************************/
  
! UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias
                        SET set_clause_list
                        from_clause
                        where_or_current_clause
                        returning_clause
                                {
                                        UpdateStmt *n = makeNode(UpdateStmt);
!                                       n->relation = $3;
!                                       n->targetList = $5;
!                                       n->fromClause = $6;
!                                       n->whereClause = $7;
!                                       n->returningList = $8;
!                                       n->withClause = $1;
                                        $$ = (Node *)n;
                                }
                ;
***************
*** 7743,7748 **** common_table_expr:  name opt_name_list AS select_with_parens
--- 7746,7757 ----
                        }
                ;
  
+ opt_with_clause:
+               with_clause                                                     
        { $$ = $1; }
+               | /*EMPTY*/                                                     
        { $$ = NULL; }
+               ;
+ 
+ 
  into_clause:
                        INTO OptTempTableName
                                {
*** a/src/backend/parser/parse_utilcmd.c
--- b/src/backend/parser/parse_utilcmd.c
***************
*** 1868,1873 **** transformRuleStmt(RuleStmt *stmt, const char *queryString,
--- 1868,1881 ----
                        }
  
                        /*
+                        * OLD/NEW is not allowed in CTE queries.
+                        */
+                       if (checkCTEHasOldNew(sub_qry))
+                               ereport(ERROR,
+                                               
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("cannot refer to 
OLD/NEW in CTE query")));
+ 
+                       /*
                         * For efficiency's sake, add OLD to the rule action's 
jointree
                         * only if it was actually referenced in the statement 
or qual.
                         *
*** a/src/backend/rewrite/rewriteManip.c
--- b/src/backend/rewrite/rewriteManip.c
***************
*** 291,296 **** checkExprHasSubLink_walker(Node *node, void *context)
--- 291,320 ----
        return expression_tree_walker(node, checkExprHasSubLink_walker, 
context);
  }
  
+ /*
+  * checkCTEHasOldNew - check if OLD/NEW is referred in CTE queries.
+  */
+ bool
+ checkCTEHasOldNew(Query *node)
+ {
+       ListCell   *l;
+ 
+       foreach (l, node->cteList)
+       {
+               CommonTableExpr    *cte = (CommonTableExpr *) lfirst(l);
+               int             new_varno = PRS2_NEW_VARNO;
+               int             old_varno = PRS2_OLD_VARNO;
+ 
+               /* 1 == the top CTE */
+               if (rangeTableEntry_used(cte->ctequery, new_varno, 1))
+                       return true;
+ 
+               if (rangeTableEntry_used(cte->ctequery, old_varno, 1))
+                       return true;
+       }
+ 
+       return false;
+ }
  
  /*
   * OffsetVarNodes - adjust Vars when appending one query's RT to another
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 3345,3350 **** get_insert_query_def(Query *query, deparse_context *context)
--- 3345,3353 ----
        ListCell   *l;
        List       *strippedexprs;
  
+       /* Insert the WITH clause if given */
+       get_with_clause(query, context);
+ 
        /*
         * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will 
be
         * a single RTE for the SELECT or VALUES.
***************
*** 3482,3487 **** get_update_query_def(Query *query, deparse_context *context)
--- 3485,3493 ----
        RangeTblEntry *rte;
        ListCell   *l;
  
+       /* Insert the WITH clause if given */
+       get_with_clause(query, context);
+ 
        /*
         * Start the query with UPDATE relname SET
         */
***************
*** 3563,3568 **** get_delete_query_def(Query *query, deparse_context *context)
--- 3569,3577 ----
        StringInfo      buf = context->buf;
        RangeTblEntry *rte;
  
+       /* Insert the WITH clause if given */
+       get_with_clause(query, context);
+ 
        /*
         * Start the query with DELETE FROM relname
         */
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 896,901 **** typedef struct InsertStmt
--- 896,902 ----
        List       *cols;                       /* optional: names of the 
target columns */
        Node       *selectStmt;         /* the source SELECT/VALUES, or NULL */
        List       *returningList;      /* list of expressions to return */
+       WithClause *withClause;         /* WITH clause */
  } InsertStmt;
  
  /* ----------------------
***************
*** 909,914 **** typedef struct DeleteStmt
--- 910,916 ----
        List       *usingClause;        /* optional using clause for more 
tables */
        Node       *whereClause;        /* qualifications */
        List       *returningList;      /* list of expressions to return */
+       WithClause *withClause;         /* WITH clause */
  } DeleteStmt;
  
  /* ----------------------
***************
*** 923,928 **** typedef struct UpdateStmt
--- 925,931 ----
        Node       *whereClause;        /* qualifications */
        List       *fromClause;         /* optional from clause for more tables 
*/
        List       *returningList;      /* list of expressions to return */
+       WithClause *withClause;         /* WITH clause */
  } UpdateStmt;
  
  /* ----------------------
*** a/src/include/rewrite/rewriteManip.h
--- b/src/include/rewrite/rewriteManip.h
***************
*** 56,61 **** extern int       locate_windowfunc(Node *node);
--- 56,62 ----
  extern bool checkExprHasAggs(Node *node);
  extern bool checkExprHasWindowFuncs(Node *node);
  extern bool checkExprHasSubLink(Node *node);
+ extern bool checkCTEHasOldNew(Query *node);
  
  extern Node *replace_rte_variables(Node *node,
                                          int target_varno, int sublevels_up,
*** a/src/test/regress/expected/with.out
--- b/src/test/regress/expected/with.out
***************
*** 738,743 **** WITH RECURSIVE
--- 738,820 ----
  (54 rows)
  
  --
+ -- WITH on top of a DML statement
+ --
+ CREATE TEMPORARY TABLE y (a INTEGER);
+ INSERT INTO y SELECT generate_series(1, 10);
+ WITH t AS (
+       SELECT a FROM y
+ )
+ INSERT INTO y
+ SELECT a+20 FROM t RETURNING *;
+  a  
+ ----
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+ (10 rows)
+ 
+ WITH t AS (
+       SELECT a FROM y
+ )
+ UPDATE y SET a = y.a-10 FROM t WHERE y.a > 20 AND t.a = y.a RETURNING y.a;
+  a  
+ ----
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+ (10 rows)
+ 
+ WITH RECURSIVE t(a) AS (
+       SELECT 11
+       UNION ALL
+       SELECT a+1 FROM t WHERE a < 50
+ )
+ DELETE FROM y USING t WHERE t.a = y.a RETURNING y.a;
+  a  
+ ----
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+ (10 rows)
+ 
+ SELECT * FROM y;
+  a  
+ ----
+   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+ (10 rows)
+ 
+ --
  -- error cases
  --
  -- INTERSECT
***************
*** 774,781 **** WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
  ERROR:  recursive reference to query "x" must not appear within its 
non-recursive term
  LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
                                                ^
- CREATE TEMPORARY TABLE y (a INTEGER);
- INSERT INTO y SELECT generate_series(1, 10);
  -- LEFT JOIN
  WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
        UNION ALL
--- 851,856 ----
***************
*** 912,917 **** ERROR:  recursive query "foo" column 1 has type numeric(3,0) 
in non-recursive te
--- 987,997 ----
  LINE 2:    (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
                     ^
  HINT:  Cast the output of the non-recursive term to the correct type.
+ -- disallow OLD/NEW reference in CTE
+ CREATE TEMPORARY TABLE x (n integer);
+ CREATE RULE r2 AS ON UPDATE TO x DO INSTEAD
+     WITH t AS (SELECT OLD.*) UPDATE y SET a = t.n FROM t;
+ ERROR:  cannot refer to OLD/NEW in CTE query
  --
  -- test for bug #4902
  --
*** a/src/test/regress/sql/with.sql
--- b/src/test/regress/sql/with.sql
***************
*** 339,344 **** WITH RECURSIVE
--- 339,371 ----
   SELECT * FROM z;
  
  --
+ -- WITH on top of a DML statement
+ --
+ 
+ CREATE TEMPORARY TABLE y (a INTEGER);
+ INSERT INTO y SELECT generate_series(1, 10);
+ 
+ WITH t AS (
+       SELECT a FROM y
+ )
+ INSERT INTO y
+ SELECT a+20 FROM t RETURNING *;
+ 
+ WITH t AS (
+       SELECT a FROM y
+ )
+ UPDATE y SET a = y.a-10 FROM t WHERE y.a > 20 AND t.a = y.a RETURNING y.a;
+ 
+ WITH RECURSIVE t(a) AS (
+       SELECT 11
+       UNION ALL
+       SELECT a+1 FROM t WHERE a < 50
+ )
+ DELETE FROM y USING t WHERE t.a = y.a RETURNING y.a;
+ 
+ SELECT * FROM y;
+ 
+ --
  -- error cases
  --
  
***************
*** 364,372 **** WITH RECURSIVE x(n) AS (SELECT n FROM x)
  WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
        SELECT * FROM x;
  
- CREATE TEMPORARY TABLE y (a INTEGER);
- INSERT INTO y SELECT generate_series(1, 10);
- 
  -- LEFT JOIN
  
  WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
--- 391,396 ----
***************
*** 470,475 **** WITH RECURSIVE foo(i) AS
--- 494,504 ----
     SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
  SELECT * FROM foo;
  
+ -- disallow OLD/NEW reference in CTE
+ CREATE TEMPORARY TABLE x (n integer);
+ CREATE RULE r2 AS ON UPDATE TO x DO INSTEAD
+     WITH t AS (SELECT OLD.*) UPDATE y SET a = t.n FROM t;
+ 
  --
  -- test for bug #4902
  --

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to