*** 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; /*