Hi,

I've been working on writeable CTEs during the last couple of months, but right now it looks like I'm going to miss the first commit fest for 9.1. I was trying to make it work by expanding all wCTEs to their own Queries during the rewrite stage (a very crude patch trying to do that for regular CTEs attached), but I don't think that it's a good way of approaching the problem. Consider:

WITH t  AS (SELECT 1),
     t2 AS (SELECT * FROM t2)
VALUES (true);

The first big problem I hit is was that when the query for t2 is planned separately, it doesn't have the CTE information. But even if it had that information (we could easily copy it during the rewrite stage), all RTEs referencing CTEs that were expanded would have the wrong levelsup (this is where the patch fails at regression tests). One could probably come up with ways of fixing even that, but I don't think that's the right direction to be heading.

So what I'm now thinking of is making the planner plan that as a single Query, and make the planner expand it into multiple PlannedStmts if necessary. This would break the existing planner hooks, but I don't think that's a huge problem. Does anyone see any obvious flaws in this?

Any feedback is welcome. I'd also be happy to get some help on this project.


Regards,
Marko Tiikkaja
*** a/src/backend/commands/copy.c
--- b/src/backend/commands/copy.c
***************
*** 1092,1098 **** DoCopy(const CopyStmt *stmt, const char *queryString)
                cstate->queryDesc = CreateQueryDesc(plan, queryString,
                                                                                
        GetActiveSnapshot(),
                                                                                
        InvalidSnapshot,
!                                                                               
        dest, NULL, 0);
  
                /*
                 * Call ExecutorStart to prepare the plan for execution.
--- 1092,1098 ----
                cstate->queryDesc = CreateQueryDesc(plan, queryString,
                                                                                
        GetActiveSnapshot(),
                                                                                
        InvalidSnapshot,
!                                                                               
        dest, NULL, 0, NIL);
  
                /*
                 * Call ExecutorStart to prepare the plan for execution.
*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 367,373 **** ExplainOnePlan(PlannedStmt *plannedstmt, ExplainState *es,
        /* Create a QueryDesc requesting no output */
        queryDesc = CreateQueryDesc(plannedstmt, queryString,
                                                                
GetActiveSnapshot(), InvalidSnapshot,
!                                                               None_Receiver, 
params, instrument_option);
  
        INSTR_TIME_SET_CURRENT(starttime);
  
--- 367,374 ----
        /* Create a QueryDesc requesting no output */
        queryDesc = CreateQueryDesc(plannedstmt, queryString,
                                                                
GetActiveSnapshot(), InvalidSnapshot,
!                                                               None_Receiver, 
params, instrument_option,
!                                                               NIL);
  
        INSTR_TIME_SET_CURRENT(starttime);
  
***************
*** 692,697 **** ExplainNode(Plan *plan, PlanState *planstate,
--- 693,701 ----
                case T_CteScan:
                        pname = sname = "CTE Scan";
                        break;
+               case T_DtScan:
+                       pname = sname = "Derived Table Scan";
+                       break;
                case T_WorkTableScan:
                        pname = sname = "WorkTable Scan";
                        break;
***************
*** 844,849 **** ExplainNode(Plan *plan, PlanState *planstate,
--- 848,854 ----
                case T_ValuesScan:
                case T_CteScan:
                case T_WorkTableScan:
+               case T_DtScan:
                        ExplainScanTarget((Scan *) plan, es);
                        break;
                case T_BitmapIndexScan:
***************
*** 1565,1570 **** ExplainScanTarget(Scan *plan, ExplainState *es)
--- 1570,1581 ----
                        objectname = rte->ctename;
                        objecttag = "CTE Name";
                        break;
+               case T_DtScan:
+                       /* Assert it's on a non-self-reference CTE */
+                       Assert(rte->rtekind == RTE_CTE);
+                       Assert(!rte->self_reference);
+                       objectname = rte->ctename;
+                       objecttag = "Derived Table Name";
                default:
                        break;
        }
*** a/src/backend/executor/Makefile
--- b/src/backend/executor/Makefile
***************
*** 21,27 **** OBJS = execAmi.o execCurrent.o execGrouping.o execJunk.o 
execMain.o \
         nodeMaterial.o nodeMergejoin.o nodeModifyTable.o \
         nodeNestloop.o nodeFunctionscan.o nodeRecursiveunion.o nodeResult.o \
         nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
!        nodeValuesscan.o nodeCtescan.o nodeWorktablescan.o \
         nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o \
         nodeWindowAgg.o tstoreReceiver.o spi.o
  
--- 21,27 ----
         nodeMaterial.o nodeMergejoin.o nodeModifyTable.o \
         nodeNestloop.o nodeFunctionscan.o nodeRecursiveunion.o nodeResult.o \
         nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
!        nodeValuesscan.o nodeCtescan.o nodeWorktablescan.o nodeDtscan.o \
         nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o \
         nodeWindowAgg.o tstoreReceiver.o spi.o
  
*** a/src/backend/executor/execAmi.c
--- b/src/backend/executor/execAmi.c
***************
*** 21,26 ****
--- 21,27 ----
  #include "executor/nodeBitmapIndexscan.h"
  #include "executor/nodeBitmapOr.h"
  #include "executor/nodeCtescan.h"
+ #include "executor/nodeDtscan.h"
  #include "executor/nodeFunctionscan.h"
  #include "executor/nodeGroup.h"
  #include "executor/nodeGroup.h"
***************
*** 189,194 **** ExecReScan(PlanState *node, ExprContext *exprCtxt)
--- 190,199 ----
                        ExecWorkTableScanReScan((WorkTableScanState *) node, 
exprCtxt);
                        break;
  
+               case T_DtScanState:
+                       ExecDtScanReScan((DtScanState *) node, exprCtxt);
+                       break;
+ 
                case T_NestLoopState:
                        ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
                        break;
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***************
*** 146,151 **** standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
--- 146,153 ----
  
        oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
  
+       estate->es_derived = queryDesc->derived;
+ 
        /*
         * Fill in external parameters, if any, from queryDesc; and allocate
         * workspace for internal parameters
*** a/src/backend/executor/execProcnode.c
--- b/src/backend/executor/execProcnode.c
***************
*** 85,90 ****
--- 85,91 ----
  #include "executor/nodeBitmapIndexscan.h"
  #include "executor/nodeBitmapOr.h"
  #include "executor/nodeCtescan.h"
+ #include "executor/nodeDtscan.h"
  #include "executor/nodeFunctionscan.h"
  #include "executor/nodeGroup.h"
  #include "executor/nodeHash.h"
***************
*** 226,231 **** ExecInitNode(Plan *node, EState *estate, int eflags)
--- 227,237 ----
                                                                                
                                 estate, eflags);
                        break;
  
+               case T_DtScan:
+                       result = (PlanState *) ExecInitDtScan((DtScan *) node,
+                                                                               
                  estate, eflags);
+                       break;
+ 
                        /*
                         * join nodes
                         */
***************
*** 412,417 **** ExecProcNode(PlanState *node)
--- 418,427 ----
                        result = ExecWorkTableScan((WorkTableScanState *) node);
                        break;
  
+               case T_DtScanState:
+                       result = ExecDtScan((DtScanState *) node);
+                       break;
+ 
                        /*
                         * join nodes
                         */
***************
*** 635,640 **** ExecEndNode(PlanState *node)
--- 645,653 ----
                case T_WorkTableScanState:
                        ExecEndWorkTableScan((WorkTableScanState *) node);
                        break;
+               case T_DtScanState:
+                       ExecEndDtScan((DtScanState *) node);
+                       break;
  
                        /*
                         * join nodes
*** a/src/backend/executor/execUtils.c
--- b/src/backend/executor/execUtils.c
***************
*** 145,150 **** CreateExecutorState(void)
--- 145,152 ----
  
        estate->es_subplanstates = NIL;
  
+       estate->es_derived = NIL;
+ 
        estate->es_per_tuple_exprcontext = NULL;
  
        estate->es_epqTuple = NULL;
*** a/src/backend/executor/functions.c
--- b/src/backend/executor/functions.c
***************
*** 417,423 **** postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
                                                                 fcache->src,
                                                                 snapshot, 
InvalidSnapshot,
                                                                 dest,
!                                                                
fcache->paramLI, 0);
        else
                es->qd = CreateUtilityQueryDesc(es->stmt,
                                                                                
fcache->src,
--- 417,423 ----
                                                                 fcache->src,
                                                                 snapshot, 
InvalidSnapshot,
                                                                 dest,
!                                                                
fcache->paramLI, 0, NIL);
        else
                es->qd = CreateUtilityQueryDesc(es->stmt,
                                                                                
fcache->src,
*** /dev/null
--- b/src/backend/executor/nodeDtscan.c
***************
*** 0 ****
--- 1,261 ----
+ /*-------------------------------------------------------------------------
+  *
+  * nodeDtscan.c
+  *      routines to handle DtScan nodes.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *      $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "executor/execdebug.h"
+ #include "executor/nodeDtscan.h"
+ #include "miscadmin.h"
+ 
+ static TupleTableSlot *DtScanNext(DtScanState *node);
+ 
+ /* ----------------------------------------------------------------
+  *            DtScanNext
+  *
+  *            This is a workhorse for ExecDtScan
+  * ----------------------------------------------------------------
+  */
+ static TupleTableSlot *
+ DtScanNext(DtScanState *node)
+ {
+       EState     *estate;
+       ScanDirection dir;
+       bool            forward;
+       Tuplestorestate *tuplestorestate;
+       bool            eof_tuplestore;
+       TupleTableSlot *slot;
+ 
+       /*
+        * get state info from node
+        */
+       estate = node->ss.ps.state;
+       dir = estate->es_direction;
+       forward = ScanDirectionIsForward(dir);
+       tuplestorestate = node->tuplestore;
+       tuplestore_select_read_pointer(tuplestorestate, node->readptr);
+       slot = node->ss.ss_ScanTupleSlot;
+ 
+ 
+       Assert(forward);
+ #if 0
+       /*
+        * If we are not at the end of the tuplestore, or are going backwards, 
try
+        * to fetch a tuple from tuplestore.
+        */
+       eof_tuplestore = tuplestore_ateof(tuplestorestate);
+ 
+       if (!forward && eof_tuplestore)
+       {
+               if (!node->leader->eof_cte)
+               {
+                       /*
+                        * When reversing direction at tuplestore EOF, the first
+                        * gettupleslot call will fetch the last-added tuple; 
but we want
+                        * to return the one before that, if possible. So do an 
extra
+                        * fetch.
+                        */
+                       if (!tuplestore_advance(tuplestorestate, forward))
+                               return NULL;    /* the tuplestore must be empty 
*/
+               }
+               eof_tuplestore = false;
+       }
+ #endif
+ 
+       /*
+        * If we can fetch another tuple from the tuplestore, return it.
+        *
+        * Note: we have to use copy=true in the tuplestore_gettupleslot call,
+        * because we are sharing the tuplestore with other nodes that might 
write
+        * into the tuplestore before we get called again.
+        */
+       eof_tuplestore = tuplestore_ateof(tuplestorestate);
+       if (!eof_tuplestore)
+       {
+               if (tuplestore_gettupleslot(tuplestorestate, forward, true, 
slot))
+                       return slot;
+               if (forward)
+                       eof_tuplestore = true;
+       }
+ 
+       /*
+        * Nothing left ...
+        */
+       return ExecClearTuple(slot);
+ }
+ 
+ /*
+  * DtScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
+  */
+ static bool
+ DtScanRecheck(DtScanState *node, TupleTableSlot *slot)
+ {
+       /* nothing to check */
+       return true;
+ }
+ 
+ /* ----------------------------------------------------------------
+  *            ExecDtScan(node)
+  *
+  *            Scans the DT sequentially and returns the next qualifying tuple.
+  *            We call the ExecScan() routine and pass it the appropriate
+  *            access method functions.
+  * ----------------------------------------------------------------
+  */
+ TupleTableSlot *
+ ExecDtScan(DtScanState *node)
+ {
+       return ExecScan(&node->ss,
+                                       (ExecScanAccessMtd) DtScanNext,
+                                       (ExecScanRecheckMtd) DtScanRecheck);
+ }
+ 
+ 
+ /* ----------------------------------------------------------------
+  *            ExecInitDtScan
+  * ----------------------------------------------------------------
+  */
+ DtScanState *
+ ExecInitDtScan(DtScan *node, EState *estate, int eflags)
+ {
+       DtScanState *scanstate;
+ 
+ 
+       /* check for unsupported flags */
+       Assert(!(eflags & EXEC_FLAG_MARK));
+ 
+       /*
+        * For the moment we have to force the tuplestore to allow REWIND, 
because
+        * we might be asked to rescan the CTE even though upper levels didn't
+        * tell us to be prepared to do it efficiently.  Annoying, since this
+        * prevents truncation of the tuplestore.  XXX FIXME
+        */
+       eflags |= EXEC_FLAG_REWIND;
+ 
+       /*
+        * DtScan should not have any children.
+        */
+       Assert(outerPlan(node) == NULL);
+       Assert(innerPlan(node) == NULL);
+ 
+       /*
+        * create new DtScanState for node
+        */
+       scanstate = makeNode(DtScanState);
+       scanstate->ss.ps.plan = (Plan *) node;
+       scanstate->ss.ps.state = estate;
+       scanstate->eflags = eflags;
+ 
+ 
+       /* XXX hack hack */
+       if (true)
+       {
+               /* XXX don't try to alloc a read pointer if this is an EXPLAIN. 
*/
+               if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
+               {
+                       scanstate->tuplestore = (Tuplestorestate *) 
list_nth(estate->es_derived,
+                                                                               
                                                 node->dtTuplestoreId - 1);
+                       scanstate->readptr =
+                               
tuplestore_alloc_read_pointer(scanstate->tuplestore,
+                                                                               
  /* XXX scanstate->eflags*/ 0);
+               }
+               else
+               {
+                       scanstate->tuplestore = NULL;
+                       scanstate->readptr = -1;
+               }
+ 
+ 
+               /*
+                * Miscellaneous initialization
+                *
+                * create expression context for node
+                */
+               ExecAssignExprContext(estate, &scanstate->ss.ps);
+ 
+               /*
+                * initialize child expressions
+                */
+               scanstate->ss.ps.targetlist = (List *)
+                       ExecInitExpr((Expr *) node->scan.plan.targetlist,
+                                                (PlanState *) scanstate);
+               scanstate->ss.ps.qual = (List *)
+                       ExecInitExpr((Expr *) node->scan.plan.qual,
+                                                (PlanState *) scanstate);
+ 
+               /*
+                * tuple table initialization
+                */
+               ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
+               ExecInitScanTupleSlot(estate, &scanstate->ss);
+ 
+               /*
+                * The scan tuple type (ie, the rowtype we expect to find in 
the work
+                * table) is the same as the result rowtype of the CTE query.
+                */
+               ExecAssignScanType(&scanstate->ss,
+                                                  node->dtTupledesc);
+ 
+               /*
+                * Initialize result tuple type and projection info.
+                */
+               ExecAssignResultTypeFromTL(&scanstate->ss.ps);
+               ExecAssignScanProjectionInfo(&scanstate->ss);
+       }
+       else
+       {
+               scanstate->ss.ss_currentRelation = NULL;
+               scanstate->ss.ss_currentScanDesc = NULL;
+               scanstate->ss.ps.ps_TupFromTlist = true;
+               return scanstate;
+       }
+       /* /hack hack */
+ 
+       scanstate->ss.ps.ps_TupFromTlist = false;
+ 
+       return scanstate;
+ }
+ 
+ /* ----------------------------------------------------------------
+  *            ExecEndDtScan
+  *
+  *            frees any storage allocated through C routines.
+  * ----------------------------------------------------------------
+  */
+ void
+ ExecEndDtScan(DtScanState *node)
+ {
+       /*
+        * Free exprcontext
+        */
+       ExecFreeExprContext(&node->ss.ps);
+ 
+       /*
+        * clean out the tuple table
+        */
+       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       ExecClearTuple(node->ss.ss_ScanTupleSlot);
+ }
+ 
+ /* ----------------------------------------------------------------
+  *            ExecDtScanReScan
+  *
+  *            Rescans the relation.
+  * ----------------------------------------------------------------
+  */
+ void
+ ExecDtScanReScan(DtScanState *node, ExprContext *exprCtxt)
+ {
+       /* XXX TODO */
+ }
*** a/src/backend/executor/spi.c
--- b/src/backend/executor/spi.c
***************
*** 1905,1911 **** _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                                                                                
plansource->query_string,
                                                                                
snap, crosscheck_snapshot,
                                                                                
dest,
!                                                                               
paramLI, 0);
                                res = _SPI_pquery(qdesc, fire_triggers,
                                                                  canSetTag ? 
tcount : 0);
                                FreeQueryDesc(qdesc);
--- 1905,1911 ----
                                                                                
plansource->query_string,
                                                                                
snap, crosscheck_snapshot,
                                                                                
dest,
!                                                                               
paramLI, 0, NIL);
                                res = _SPI_pquery(qdesc, fire_triggers,
                                                                  canSetTag ? 
tcount : 0);
                                FreeQueryDesc(qdesc);
*** a/src/backend/optimizer/path/allpaths.c
--- b/src/backend/optimizer/path/allpaths.c
***************
*** 697,705 **** set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, 
RangeTblEntry *rte)
        int                     ndx;
        ListCell   *lc;
        int                     plan_id;
  
        /*
!        * Find the referenced CTE, and locate the plan previously made for it.
         */
        levelsup = rte->ctelevelsup;
        cteroot = root;
--- 697,707 ----
        int                     ndx;
        ListCell   *lc;
        int                     plan_id;
+       CommonTableExpr *cte;
+ 
  
        /*
!        * XXX Find the referenced CTE, and locate the plan previously made for 
it.
         */
        levelsup = rte->ctelevelsup;
        cteroot = root;
***************
*** 718,724 **** set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, 
RangeTblEntry *rte)
        ndx = 0;
        foreach(lc, cteroot->parse->cteList)
        {
!               CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
  
                if (strcmp(cte->ctename, rte->ctename) == 0)
                        break;
--- 720,726 ----
        ndx = 0;
        foreach(lc, cteroot->parse->cteList)
        {
!               cte = (CommonTableExpr *) lfirst(lc);
  
                if (strcmp(cte->ctename, rte->ctename) == 0)
                        break;
***************
*** 726,731 **** set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, 
RangeTblEntry *rte)
--- 728,742 ----
        }
        if (lc == NULL)                         /* shouldn't happen */
                elog(ERROR, "could not find CTE \"%s\"", rte->ctename);
+ 
+       if (cte->derived)
+       {
+               /* XXX */
+               add_path(rel, create_dtscan_path(root, rel));
+               set_cheapest(rel);
+               return;
+       }
+ 
        if (ndx >= list_length(cteroot->cte_plan_ids))
                elog(ERROR, "could not find plan for CTE \"%s\"", rte->ctename);
        plan_id = list_nth_int(cteroot->cte_plan_ids, ndx);
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
***************
*** 1067,1072 **** cost_recursive_union(Plan *runion, Plan *nrterm, Plan *rterm)
--- 1067,1101 ----
  }
  
  /*
+  * cost_dtscan
+  *      Determines and returns the cost of scanning a derived table.
+  */
+ void
+ cost_dtscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
+ {
+       Cost            startup_cost = 0;
+       Cost            run_cost = 0;
+       Cost            cpu_per_tuple;
+ 
+       /* XXX only allowed in CTEs for now */
+       Assert(baserel->relid > 0);
+       Assert(baserel->rtekind == RTE_CTE);
+ 
+       /* XXX CTE comment says: "Charge one CPU tuple cost per
+        * row for tuplestore manipulation."  We don't modify
+        * anything, so should this be 0? */
+       cpu_per_tuple = 0;
+ 
+       /* Add scanning CPU costs */
+       startup_cost += baserel->baserestrictcost.startup;
+       cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
+       run_cost += cpu_per_tuple * baserel->tuples;
+ 
+       path->startup_cost = startup_cost;
+       path->total_cost = startup_cost + run_cost;
+ }
+ 
+ /*
   * cost_sort
   *      Determines and returns the cost of sorting a relation, including
   *      the cost of reading the input data.
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
***************
*** 66,71 **** static CteScan *create_ctescan_plan(PlannerInfo *root, Path 
*best_path,
--- 66,73 ----
                                        List *tlist, List *scan_clauses);
  static WorkTableScan *create_worktablescan_plan(PlannerInfo *root, Path 
*best_path,
                                                  List *tlist, List 
*scan_clauses);
+ static DtScan *create_dtscan_plan(PlannerInfo *root, Path *best_path,
+                                       List *tlist, List *scan_clauses);
  static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path,
                                         Plan *outer_plan, Plan *inner_plan);
  static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath 
*best_path,
***************
*** 100,105 **** static CteScan *make_ctescan(List *qptlist, List *qpqual,
--- 102,109 ----
                         Index scanrelid, int ctePlanId, int cteParam);
  static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
                                   Index scanrelid, int wtParam);
+ static DtScan *make_dtscan(List *qptlist, List *qpqual,
+                        Index scanrelid, int qwrid, TupleDesc td /*XXX */);
  static BitmapAnd *make_bitmap_and(List *bitmapplans);
  static BitmapOr *make_bitmap_or(List *bitmapplans);
  static NestLoop *make_nestloop(List *tlist,
***************
*** 162,167 **** create_plan(PlannerInfo *root, Path *best_path)
--- 166,172 ----
                case T_ValuesScan:
                case T_CteScan:
                case T_WorkTableScan:
+               case T_DtScan:
                        plan = create_scan_plan(root, best_path);
                        break;
                case T_HashJoin:
***************
*** 298,303 **** create_scan_plan(PlannerInfo *root, Path *best_path)
--- 303,315 ----
                                                                                
                          scan_clauses);
                        break;
  
+               case T_DtScan:
+                       plan = (Plan *) create_dtscan_plan(root,
+                                                                               
           best_path,
+                                                                               
           tlist,
+                                                                               
           scan_clauses);
+                       break;
+ 
                default:
                        elog(ERROR, "unrecognized node type: %d",
                                 (int) best_path->pathtype);
***************
*** 1560,1565 **** create_worktablescan_plan(PlannerInfo *root, Path *best_path,
--- 1572,1672 ----
  }
  
  
+ /*
+  * create_dtscan_plan
+  *     Returns a ctescan plan for the base relation scanned by 'best_path'
+  *     with restriction clauses 'scan_clauses' and targetlist 'tlist'.
+  */
+ static DtScan *
+ create_dtscan_plan(PlannerInfo *root, Path *best_path,
+                                       List *tlist, List *scan_clauses)
+ {
+       DtScan    *scan_plan;
+       Index           scan_relid = best_path->parent->relid;
+       RangeTblEntry *rte;
+       SubPlan    *ctesplan = NULL;
+       int                     plan_id;
+       int                     cte_param_id;
+       PlannerInfo *cteroot;
+       Index           levelsup;
+       int                     ndx;
+       ListCell   *lc;
+       CommonTableExpr *cte;
+       TupleDesc tupledesc;
+ 
+       Assert(scan_relid > 0);
+       rte = planner_rt_fetch(scan_relid, root);
+       Assert(rte->rtekind == RTE_CTE);
+       Assert(!rte->self_reference);
+ 
+       /*
+        * Find the referenced CTE, and locate the SubPlan previously made for 
it.
+        */
+       levelsup = rte->ctelevelsup;
+       cteroot = root;
+       while (levelsup-- > 0)
+       {
+               cteroot = cteroot->parent_root;
+               if (!cteroot)                   /* shouldn't happen */
+                       elog(ERROR, "bad levelsup for CTE \"%s\"", 
rte->ctename);
+       }
+ 
+       /*
+        * Note: cte_plan_ids can be shorter than cteList, if we are still 
working
+        * on planning the CTEs (ie, this is a side-reference from another CTE).
+        * So we mustn't use forboth here.
+        */
+       ndx = 1;
+       foreach(lc, cteroot->parse->cteList)
+       {
+               cte = (CommonTableExpr *) lfirst(lc);
+ 
+               if (strcmp(cte->ctename, rte->ctename) == 0)
+                       break;
+ 
+               if (cte->derived)
+                       ndx++;
+       }
+       if (lc == NULL)                         /* shouldn't happen */
+               elog(ERROR, "could not find CTE \"%s\"", rte->ctename);
+ 
+       tupledesc = CreateTemplateTupleDesc(list_length(cte->ctecolnames), 
false /* XXX oids? */);
+       {
+               int resno = 1;
+               ListCell *namelc,
+                                *typelc,
+                                *typmodlc;
+ 
+               Assert(list_length(cte->ctecoltypes) == 
list_length(cte->ctecolnames));
+               Assert(list_length(cte->ctecoltypmods) == 
list_length(cte->ctecolnames));
+ 
+               typelc = list_head(cte->ctecoltypes);
+               typmodlc = list_head(cte->ctecoltypmods);
+               foreach(namelc, cte->ctecolnames)
+               {
+                       TupleDescInitEntry(tupledesc,
+                                                          resno++,
+                                                          
strVal(lfirst(namelc)),
+                                                          lfirst_oid(typelc),
+                                                          lfirst_int(typmodlc),
+                                                          0);
+ 
+                       typelc = lnext(typelc);
+                       typmodlc = lnext(typmodlc);
+               }
+       }
+ 
+       scan_clauses = order_qual_clauses(root, scan_clauses);
+       scan_clauses = extract_actual_clauses(scan_clauses, false);
+ 
+       scan_plan = make_dtscan(tlist, scan_clauses, scan_relid,
+                                                       ndx, tupledesc /* XXX 
hack hack pass real id */);
+ 
+       copy_path_costsize(&scan_plan->scan.plan, best_path);
+ 
+       return scan_plan;
+ }
+ 
  /*****************************************************************************
   *
   *    JOIN METHODS
***************
*** 2634,2639 **** make_worktablescan(List *qptlist,
--- 2741,2773 ----
        return node;
  }
  
+ static DtScan *
+ make_dtscan(List *qptlist,
+                       List *qpqual,
+                       Index scanrelid,
+                       int qwrid /*XXX */,
+                       TupleDesc td)
+ {
+       DtScan     *node = makeNode(DtScan);
+       Plan       *plan = &node->scan.plan;
+ 
+       /* cost should be inserted by caller */
+       plan->targetlist = qptlist;
+       plan->qual = qpqual;
+       plan->lefttree = NULL;
+       plan->righttree = NULL;
+       node->scan.scanrelid = scanrelid;
+       /* hack hack */
+       node->dtTuplestoreId = qwrid;
+       node->dtTupledesc = td;
+       /* /hack hack */
+ 
+       //node->cteParam = cteParam;
+       //XXX tuplestorestate id
+ 
+       return node;
+ }
+ 
  Append *
  make_append(List *appendplans, List *tlist)
  {
*** a/src/backend/optimizer/plan/setrefs.c
--- b/src/backend/optimizer/plan/setrefs.c
***************
*** 398,403 **** set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
--- 398,415 ----
                                        fix_scan_list(glob, 
splan->scan.plan.qual, rtoffset);
                        }
                        break;
+               case T_DtScan:
+                       /* XXX TODO XXX */
+                       {
+                               DtScan *splan = (DtScan *) plan;
+ 
+                               splan->scan.scanrelid += rtoffset;
+                               splan->scan.plan.targetlist =
+                                       fix_scan_list(glob, 
splan->scan.plan.targetlist, rtoffset);
+                               splan->scan.plan.qual =
+                                       fix_scan_list(glob, 
splan->scan.plan.qual, rtoffset);
+                       }
+                       break;
                case T_NestLoop:
                case T_MergeJoin:
                case T_HashJoin:
*** a/src/backend/optimizer/plan/subselect.c
--- b/src/backend/optimizer/plan/subselect.c
***************
*** 875,883 **** SS_process_ctes(PlannerInfo *root)
                Param      *prm;
  
                /*
                 * Ignore CTEs that are not actually referenced anywhere.
                 */
!               if (cte->cterefcount == 0)
                {
                        /* Make a dummy entry in cte_plan_ids */
                        root->cte_plan_ids = lappend_int(root->cte_plan_ids, 
-1);
--- 875,884 ----
                Param      *prm;
  
                /*
+                * XXX
                 * Ignore CTEs that are not actually referenced anywhere.
                 */
!               if (cte->cterefcount == 0 || (!cte->cterecursive && 
cte->derived))
                {
                        /* Make a dummy entry in cte_plan_ids */
                        root->cte_plan_ids = lappend_int(root->cte_plan_ids, 
-1);
***************
*** 1982,1987 **** finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset 
*valid_params,
--- 1983,1994 ----
                        context.paramids = bms_add_members(context.paramids, 
scan_params);
                        break;
  
+               case T_DtScan:
+                       /* XXX TODO */
+                               context.paramids = 
bms_add_members(context.paramids,
+                                                                               
                   scan_params);
+                       break;
+ 
                case T_ModifyTable:
                        {
                                ModifyTable *mtplan = (ModifyTable *) plan;
*** a/src/backend/optimizer/util/pathnode.c
--- b/src/backend/optimizer/util/pathnode.c
***************
*** 1311,1316 **** create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel)
--- 1311,1334 ----
  }
  
  /*
+  * create_dtscan_path
+  *      Creates a path corresponding to a scan of derived table.
+  */
+ Path *
+ create_dtscan_path(PlannerInfo *root, RelOptInfo *rel)
+ {
+       Path       *pathnode = makeNode(Path);
+ 
+       pathnode->pathtype = T_DtScan;
+       pathnode->parent = rel;
+       pathnode->pathkeys = NIL;       /* XXX for now, result is always 
unordered */
+ 
+       cost_dtscan(pathnode, root, rel);
+ 
+       return pathnode;
+ }
+ 
+ /*
   * create_nestloop_path
   *      Creates a pathnode corresponding to a nestloop join between two
   *      relations.
*** a/src/backend/rewrite/rewriteHandler.c
--- b/src/backend/rewrite/rewriteHandler.c
***************
*** 1616,1621 **** fireRules(Query *parsetree,
--- 1616,1658 ----
        return results;
  }
  
+ static List *
+ RewriteQuery(Query *parsetree, List *rewrite_events);
+ 
+ static List *
+ RewriteCteList(Query *parse)
+ {
+       /* XXX */
+       List* rewritten = NIL;
+       ListCell *lc;
+       CommonTableExpr *cte;
+       Query *query;
+       List* ctelist;
+ 
+       parse->derivedList = NIL;
+ 
+       ctelist = NIL;
+       foreach(lc, parse->cteList)
+       {
+               cte = (CommonTableExpr *) lfirst(lc);
+ 
+               if (!cte->cterecursive)
+               {
+                       cte->derived = true;
+ 
+                       query = (Query *) cte->ctequery;
+                       query->querySource = QSRC_DERIVED;
+                       query->canSetTag = false;
+ 
+                       rewritten = lappend(rewritten, query);
+               }
+               else
+                       ctelist = lappend(ctelist, cte);
+       }
+ 
+       return rewritten;
+ }
+ 
  
  /*
   * RewriteQuery -
***************
*** 1633,1638 **** RewriteQuery(Query *parsetree, List *rewrite_events)
--- 1670,1680 ----
        Query      *qual_product = NULL;
        List       *rewritten = NIL;
  
+       /* XXX */
+       if (parsetree->cteList != NIL)
+               rewritten = RewriteCteList(parsetree);
+ 
+ 
        /*
         * If the statement is an update, insert or delete - fire rules on it.
         *
*** a/src/backend/tcop/pquery.c
--- b/src/backend/tcop/pquery.c
***************
*** 38,43 **** Portal           ActivePortal = NULL;
--- 38,44 ----
  static void ProcessQuery(PlannedStmt *plan,
                         const char *sourceText,
                         ParamListInfo params,
+                        List *derived,
                         DestReceiver *dest,
                         char *completionTag);
  static void FillPortalStore(Portal portal, bool isTopLevel);
***************
*** 67,73 **** CreateQueryDesc(PlannedStmt *plannedstmt,
                                Snapshot crosscheck_snapshot,
                                DestReceiver *dest,
                                ParamListInfo params,
!                               int instrument_options)
  {
        QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
  
--- 68,75 ----
                                Snapshot crosscheck_snapshot,
                                DestReceiver *dest,
                                ParamListInfo params,
!                               int instrument_options,
!                               List *derived)
  {
        QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
  
***************
*** 82,87 **** CreateQueryDesc(PlannedStmt *plannedstmt,
--- 84,90 ----
        qd->params = params;            /* parameter values passed into query */
        qd->instrument_options = instrument_options;            /* 
instrumentation
                                                                                
                                 * wanted? */
+       qd->derived = derived;
  
        /* null these fields until set by ExecutorStart */
        qd->tupDesc = NULL;
***************
*** 162,167 **** static void
--- 165,171 ----
  ProcessQuery(PlannedStmt *plan,
                         const char *sourceText,
                         ParamListInfo params,
+                        List *derived,
                         DestReceiver *dest,
                         char *completionTag)
  {
***************
*** 179,185 **** ProcessQuery(PlannedStmt *plan,
         */
        queryDesc = CreateQueryDesc(plan, sourceText,
                                                                
GetActiveSnapshot(), InvalidSnapshot,
!                                                               dest, params, 
0);
  
        /*
         * Set up to collect AFTER triggers
--- 183,189 ----
         */
        queryDesc = CreateQueryDesc(plan, sourceText,
                                                                
GetActiveSnapshot(), InvalidSnapshot,
!                                                               dest, params, 
0, derived);
  
        /*
         * Set up to collect AFTER triggers
***************
*** 517,523 **** PortalStart(Portal portal, ParamListInfo params, Snapshot 
snapshot)
                                                                                
        InvalidSnapshot,
                                                                                
        None_Receiver,
                                                                                
        params,
!                                                                               
        0);
  
                                /*
                                 * We do *not* call AfterTriggerBeginQuery() 
here.      We assume
--- 521,528 ----
                                                                                
        InvalidSnapshot,
                                                                                
        None_Receiver,
                                                                                
        params,
!                                                                               
        0,
!                                                                               
        NIL);
  
                                /*
                                 * We do *not* call AfterTriggerBeginQuery() 
here.      We assume
***************
*** 1220,1225 **** PortalRunMulti(Portal portal, bool isTopLevel,
--- 1225,1231 ----
                           char *completionTag)
  {
        ListCell   *stmtlist_item;
+       DestReceiver* ddtreceiver;
  
        /*
         * If the destination is DestRemoteExecute, change to DestNone.  The
***************
*** 1236,1241 **** PortalRunMulti(Portal portal, bool isTopLevel,
--- 1242,1249 ----
        if (altdest->mydest == DestRemoteExecute)
                altdest = None_Receiver;
  
+       ddtreceiver = CreateDestReceiver(DestTuplestore);
+ 
        /*
         * Loop to handle the individual queries generated from a single 
parsetree
         * by analysis and rewrite.
***************
*** 1268,1281 **** PortalRunMulti(Portal portal, bool isTopLevel,
--- 1276,1310 ----
                                ProcessQuery(pstmt,
                                                         portal->sourceText,
                                                         portal->portalParams,
+                                                        portal->ddts,
                                                         dest, completionTag);
                        }
+                       else if (true || /* XXX */stmt == 
linitial(portal->stmts))
+                       {
+                               Tuplestorestate *st;
+ 
+                               st = tuplestore_begin_heap(true, false, 124124);
+                               tuplestore_set_eflags(st, 0);
+                               SetTuplestoreDestReceiverParams(ddtreceiver,
+                                                                               
                st,
+                                                                               
                portal->heap,
+                                                                               
                true);
+ 
+                               ProcessQuery(pstmt,
+                                                        portal->sourceText,
+                                                        portal->portalParams,
+                                                        portal->ddts,
+                                                        ddtreceiver, NULL);
+ 
+                               portal->ddts = lappend(portal->ddts, st);
+                       }
                        else
                        {
                                /* stmt added by rewrite cannot set tag */
                                ProcessQuery(pstmt,
                                                         portal->sourceText,
                                                         portal->portalParams,
+                                                        portal->ddts,
                                                         altdest, NULL);
                        }
  
***************
*** 1313,1318 **** PortalRunMulti(Portal portal, bool isTopLevel,
--- 1342,1349 ----
                MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
        }
  
+       (*ddtreceiver->rDestroy) (ddtreceiver);
+ 
        /*
         * If a command completion tag was supplied, use it.  Otherwise use the
         * portal's commandTag as the default completion tag.
*** a/src/backend/utils/mmgr/portalmem.c
--- b/src/backend/utils/mmgr/portalmem.c
***************
*** 237,242 **** CreatePortal(const char *name, bool allowDup, bool dupSilent)
--- 237,243 ----
        portal->atEnd = true;           /* disallow fetches until query is set 
*/
        portal->visible = true;
        portal->creation_time = GetCurrentStatementStartTimestamp();
+       portal->ddts = NIL;
  
        /* put portal in table (sets portal->name) */
        PortalHashTableInsert(portal, name);
*** a/src/include/executor/execdesc.h
--- b/src/include/executor/execdesc.h
***************
*** 43,48 **** typedef struct QueryDesc
--- 43,49 ----
        DestReceiver *dest;                     /* the destination for tuple 
output */
        ParamListInfo params;           /* param values being passed in */
        int                     instrument_options;             /* OR of 
InstrumentOption flags */
+       List       *derived;            /* XXX */
  
        /* These fields are set by ExecutorStart */
        TupleDesc       tupDesc;                /* descriptor for result tuples 
*/
***************
*** 60,66 **** extern QueryDesc *CreateQueryDesc(PlannedStmt *plannedstmt,
                                Snapshot crosscheck_snapshot,
                                DestReceiver *dest,
                                ParamListInfo params,
!                               int instrument_options);
  
  extern QueryDesc *CreateUtilityQueryDesc(Node *utilitystmt,
                                           const char *sourceText,
--- 61,68 ----
                                Snapshot crosscheck_snapshot,
                                DestReceiver *dest,
                                ParamListInfo params,
!                               int instrument_options,
!                               List *derived);
  
  extern QueryDesc *CreateUtilityQueryDesc(Node *utilitystmt,
                                           const char *sourceText,
*** /dev/null
--- b/src/include/executor/nodeDtscan.h
***************
*** 0 ****
--- 1,24 ----
+ /*-------------------------------------------------------------------------
+  *
+  * nodeDtscan.h
+  *
+  *
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef NODEDTSCAN_H
+ #define NODEDTSCAN_H
+ 
+ #include "nodes/execnodes.h"
+ 
+ extern DtScanState *ExecInitDtScan(DtScan *node, EState *estate, int eflags);
+ extern TupleTableSlot *ExecDtScan(DtScanState *node);
+ extern void ExecEndDtScan(DtScanState *node);
+ extern void ExecDtScanReScan(DtScanState *node, ExprContext *exprCtxt);
+ 
+ #endif   /* NODEDTSCAN_H */
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 363,368 **** typedef struct EState
--- 363,370 ----
        /* Other working state: */
        MemoryContext es_query_cxt; /* per-query context in which EState lives 
*/
  
+       List       *es_derived; /* XXX */
+ 
        List       *es_tupleTable;      /* List of TupleTableSlots */
  
        List       *es_rowMarks;        /* List of ExecRowMarks */
***************
*** 1355,1360 **** typedef struct WorkTableScanState
--- 1357,1379 ----
        RecursiveUnionState *rustate;
  } WorkTableScanState;
  
+ 
+ /* ----------------
+  *     DtScanState information
+  *
+  *            DtScan nodes are used to scan a derived table (XXX 
DerivedSomethingHere?)
+  *
+  * Multiple DtScan nodes can read out from the same derived tables.
+  * ----------------
+  */
+ typedef struct DtScanState
+ {
+       ScanState       ss;                             /* its first field is 
NodeTag */
+       int                     eflags;                 /* capability flags to 
pass to tuplestore */
+       Tuplestorestate *tuplestore; /* XXX */
+       int                     readptr;                /* index of my 
tuplestore read pointer */
+ } DtScanState;
+ 
  /* ----------------------------------------------------------------
   *                             Join State Information
   * ----------------------------------------------------------------
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 59,64 **** typedef enum NodeTag
--- 59,65 ----
        T_ValuesScan,
        T_CteScan,
        T_WorkTableScan,
+       T_DtScan,
        T_Join,
        T_NestLoop,
        T_MergeJoin,
***************
*** 100,105 **** typedef enum NodeTag
--- 101,107 ----
        T_ValuesScanState,
        T_CteScanState,
        T_WorkTableScanState,
+       T_DtScanState,
        T_JoinState,
        T_NestLoopState,
        T_MergeJoinState,
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 31,37 **** typedef enum QuerySource
        QSRC_PARSER,                            /* added by parse analysis (now 
unused) */
        QSRC_INSTEAD_RULE,                      /* added by unconditional 
INSTEAD rule */
        QSRC_QUAL_INSTEAD_RULE,         /* added by conditional INSTEAD rule */
!       QSRC_NON_INSTEAD_RULE           /* added by non-INSTEAD rule */
  } QuerySource;
  
  /* Sort ordering options for ORDER BY and CREATE INDEX */
--- 31,38 ----
        QSRC_PARSER,                            /* added by parse analysis (now 
unused) */
        QSRC_INSTEAD_RULE,                      /* added by unconditional 
INSTEAD rule */
        QSRC_QUAL_INSTEAD_RULE,         /* added by conditional INSTEAD rule */
!       QSRC_NON_INSTEAD_RULE,          /* added by non-INSTEAD rule */
!       QSRC_DERIVED                            /* XXX */
  } QuerySource;
  
  /* Sort ordering options for ORDER BY and CREATE INDEX */
***************
*** 121,126 **** typedef struct Query
--- 122,128 ----
        bool            hasForUpdate;   /* FOR UPDATE or FOR SHARE was 
specified */
  
        List       *cteList;            /* WITH list (of CommonTableExpr's) */
+       List       *derivedList;        /* list of derived tables XXX */
  
        List       *rtable;                     /* list of range table entries 
*/
        FromExpr   *jointree;           /* table join tree (FROM and WHERE 
clauses) */
***************
*** 872,877 **** typedef struct CommonTableExpr
--- 874,882 ----
        List       *ctecolnames;        /* list of output column names */
        List       *ctecoltypes;        /* OID list of output column type OIDs 
*/
        List       *ctecoltypmods;      /* integer list of output column 
typmods */
+ 
+       /* XXX rename this, at least to cteSOMETHING */
+       bool            derived;                /* was this CTE rewritten to a 
derived table? */
  } CommonTableExpr;
  
  /*****************************************************************************
*** a/src/include/nodes/plannodes.h
--- b/src/include/nodes/plannodes.h
***************
*** 15,20 ****
--- 15,21 ----
  #define PLANNODES_H
  
  #include "access/sdir.h"
+ #include "access/tupdesc.h"
  #include "nodes/bitmapset.h"
  #include "nodes/primnodes.h"
  #include "storage/itemptr.h"
***************
*** 400,405 **** typedef struct WorkTableScan
--- 401,418 ----
        int                     wtParam;                /* ID of Param 
representing work table */
  } WorkTableScan;
  
+ /* ----------------
+  *            DtScan node
+  * ----------------
+  */
+ typedef struct DtScan
+ {
+       Scan            scan;
+       int                     dtTuplestoreId;
+       TupleDesc       dtTupledesc;
+       /* XXX paramid? */
+ } DtScan;
+ 
  
  /*
   * ==========
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 83,88 **** typedef struct PlannerGlobal
--- 83,90 ----
        Index           lastPHId;               /* highest PlaceHolderVar ID 
assigned */
  
        bool            transientPlan;  /* redo plan when TransactionXmin 
changes? */
+ 
+       List       *derivedTables;      /* plans for derived tables */
  } PlannerGlobal;
  
  /* macro for fetching the Plan associated with a SubPlan node */
*** a/src/include/optimizer/cost.h
--- b/src/include/optimizer/cost.h
***************
*** 81,86 **** extern void cost_functionscan(Path *path, PlannerInfo *root,
--- 81,87 ----
  extern void cost_valuesscan(Path *path, PlannerInfo *root,
                                RelOptInfo *baserel);
  extern void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel);
+ extern void cost_dtscan(Path *path, PlannerInfo *root, RelOptInfo *baserel);
  extern void cost_recursive_union(Plan *runion, Plan *nrterm, Plan *rterm);
  extern void cost_sort(Path *path, PlannerInfo *root,
                  List *pathkeys, Cost input_cost, double tuples, int width,
*** a/src/include/optimizer/pathnode.h
--- b/src/include/optimizer/pathnode.h
***************
*** 56,61 **** extern Path *create_functionscan_path(PlannerInfo *root, 
RelOptInfo *rel);
--- 56,62 ----
  extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel);
+ extern Path *create_dtscan_path(PlannerInfo *root, RelOptInfo *rel);
  
  extern NestPath *create_nestloop_path(PlannerInfo *root,
                                         RelOptInfo *joinrel,
*** a/src/include/utils/portal.h
--- b/src/include/utils/portal.h
***************
*** 168,173 **** typedef struct PortalData
--- 168,175 ----
        /* Presentation data, primarily used by the pg_cursors system view */
        TimestampTz creation_time;      /* time at which this portal was 
defined */
        bool            visible;                /* include this portal in 
pg_cursors? */
+ 
+       List       *ddts;
  } PortalData;
  
  /*
-- 
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