1 /*-------------------------------------------------------------------------
4 * routines to handle WorkTableScan nodes.
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/executor/nodeWorktablescan.c
13 *-------------------------------------------------------------------------
18 #include "executor/execdebug.h"
19 #include "executor/nodeWorktablescan.h"
21 static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
23 /* ----------------------------------------------------------------
26 * This is a workhorse for ExecWorkTableScan
27 * ----------------------------------------------------------------
29 static TupleTableSlot *
30 WorkTableScanNext(WorkTableScanState *node)
33 Tuplestorestate *tuplestorestate;
36 * get information from the estate and scan state
38 * Note: we intentionally do not support backward scan. Although it would
39 * take only a couple more lines here, it would force nodeRecursiveunion.c
40 * to create the tuplestore with backward scan enabled, which has a
41 * performance cost. In practice backward scan is never useful for a
42 * worktable plan node, since it cannot appear high enough in the plan
43 * tree of a scrollable cursor to be exposed to a backward-scan
44 * requirement. So it's not worth expending effort to support it.
46 * Note: we are also assuming that this node is the only reader of the
47 * worktable. Therefore, we don't need a private read pointer for the
48 * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
50 Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
52 tuplestorestate = node->rustate->working_table;
55 * Get the next tuple from tuplestore. Return NULL if no more tuples.
57 slot = node->ss.ss_ScanTupleSlot;
58 (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
63 * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
66 WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
68 /* nothing to check */
72 /* ----------------------------------------------------------------
73 * ExecWorkTableScan(node)
75 * Scans the worktable sequentially and returns the next qualifying tuple.
76 * We call the ExecScan() routine and pass it the appropriate
77 * access method functions.
78 * ----------------------------------------------------------------
81 ExecWorkTableScan(WorkTableScanState *node)
84 * On the first call, find the ancestor RecursiveUnion's state via the
85 * Param slot reserved for it. (We can't do this during node init because
86 * there are corner cases where we'll get the init call before the
87 * RecursiveUnion does.)
89 if (node->rustate == NULL)
91 WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
92 EState *estate = node->ss.ps.state;
95 param = &(estate->es_param_exec_vals[plan->wtParam]);
96 Assert(param->execPlan == NULL);
97 Assert(!param->isnull);
98 node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
99 Assert(node->rustate);
102 * The scan tuple type (ie, the rowtype we expect to find in the work
103 * table) is the same as the result rowtype of the ancestor
104 * RecursiveUnion node. Note this depends on the assumption that
105 * RecursiveUnion doesn't allow projection.
107 ExecAssignScanType(&node->ss,
108 ExecGetResultType(&node->rustate->ps));
111 * Now we can initialize the projection info. This must be completed
112 * before we can call ExecScan().
114 ExecAssignScanProjectionInfo(&node->ss);
117 return ExecScan(&node->ss,
118 (ExecScanAccessMtd) WorkTableScanNext,
119 (ExecScanRecheckMtd) WorkTableScanRecheck);
123 /* ----------------------------------------------------------------
124 * ExecInitWorkTableScan
125 * ----------------------------------------------------------------
128 ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
130 WorkTableScanState *scanstate;
132 /* check for unsupported flags */
133 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
136 * WorkTableScan should not have any children.
138 Assert(outerPlan(node) == NULL);
139 Assert(innerPlan(node) == NULL);
142 * create new WorkTableScanState for node
144 scanstate = makeNode(WorkTableScanState);
145 scanstate->ss.ps.plan = (Plan *) node;
146 scanstate->ss.ps.state = estate;
147 scanstate->rustate = NULL; /* we'll set this later */
150 * Miscellaneous initialization
152 * create expression context for node
154 ExecAssignExprContext(estate, &scanstate->ss.ps);
157 * initialize child expressions
159 scanstate->ss.ps.targetlist = (List *)
160 ExecInitExpr((Expr *) node->scan.plan.targetlist,
161 (PlanState *) scanstate);
162 scanstate->ss.ps.qual = (List *)
163 ExecInitExpr((Expr *) node->scan.plan.qual,
164 (PlanState *) scanstate);
167 * tuple table initialization
169 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
170 ExecInitScanTupleSlot(estate, &scanstate->ss);
173 * Initialize result tuple type, but not yet projection info.
175 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
180 /* ----------------------------------------------------------------
181 * ExecEndWorkTableScan
183 * frees any storage allocated through C routines.
184 * ----------------------------------------------------------------
187 ExecEndWorkTableScan(WorkTableScanState *node)
192 ExecFreeExprContext(&node->ss.ps);
195 * clean out the tuple table
197 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
198 ExecClearTuple(node->ss.ss_ScanTupleSlot);
201 /* ----------------------------------------------------------------
202 * ExecReScanWorkTableScan
204 * Rescans the relation.
205 * ----------------------------------------------------------------
208 ExecReScanWorkTableScan(WorkTableScanState *node)
210 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
212 ExecScanReScan(&node->ss);
214 /* No need (or way) to rescan if ExecWorkTableScan not called yet */
216 tuplestore_rescan(node->rustate->working_table);