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