wcte.patch
text/plain
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 1 | 0 |
| src/backend/commands/explain.c | 12 | 0 |
| src/backend/executor/execAmi.c | 5 | 0 |
| src/backend/executor/execMain.c | 2 | 0 |
| src/backend/executor/execProcnode.c | 13 | 0 |
| src/backend/executor/execUtils.c | 2 | 0 |
| src/backend/executor/functions.c | 1 | 0 |
| src/backend/executor/Makefile | 1 | 0 |
| src/backend/executor/nodeDtscan.c | 261 | 0 |
| src/backend/executor/spi.c | 1 | 0 |
| src/backend/optimizer/path/allpaths.c | 13 | 0 |
| src/backend/optimizer/path/costsize.c | 29 | 0 |
| src/backend/optimizer/plan/createplan.c | 134 | 0 |
| src/backend/optimizer/plan/setrefs.c | 12 | 0 |
| src/backend/optimizer/plan/subselect.c | 8 | 0 |
| src/backend/optimizer/util/pathnode.c | 18 | 0 |
| src/backend/rewrite/rewriteHandler.c | 42 | 0 |
| src/backend/tcop/pquery.c | 34 | 0 |
| src/backend/utils/mmgr/portalmem.c | 1 | 0 |
| src/include/executor/execdesc.h | 3 | 0 |
| src/include/executor/nodeDtscan.h | 24 | 0 |
| src/include/nodes/execnodes.h | 19 | 0 |
| src/include/nodes/nodes.h | 2 | 0 |
| src/include/nodes/parsenodes.h | 6 | 0 |
| src/include/nodes/plannodes.h | 13 | 0 |
| src/include/nodes/relation.h | 2 | 0 |
| src/include/optimizer/cost.h | 1 | 0 |
| src/include/optimizer/pathnode.h | 1 | 0 |
| src/include/utils/portal.h | 2 | 0 |
*** 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;
/*