1 /*-------------------------------------------------------------------------
2 *
3 * nodeWorktablescan.c
4 * routines to handle WorkTableScan nodes.
5 *
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/executor/nodeWorktablescan.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16 #include "postgres.h"
17
18 #include "executor/execdebug.h"
19 #include "executor/nodeWorktablescan.h"
20
21 static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
22
23 /* ----------------------------------------------------------------
24 * WorkTableScanNext
25 *
26 * This is a workhorse for ExecWorkTableScan
27 * ----------------------------------------------------------------
28 */
29 static TupleTableSlot *
WorkTableScanNext(WorkTableScanState * node)30 WorkTableScanNext(WorkTableScanState *node)
31 {
32 TupleTableSlot *slot;
33 Tuplestorestate *tuplestorestate;
34
35 /*
36 * get information from the estate and scan state
37 *
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.
45 *
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.
49 */
50 Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
51
52 tuplestorestate = node->rustate->working_table;
53
54 /*
55 * Get the next tuple from tuplestore. Return NULL if no more tuples.
56 */
57 slot = node->ss.ss_ScanTupleSlot;
58 (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
59 return slot;
60 }
61
62 /*
63 * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
64 */
65 static bool
WorkTableScanRecheck(WorkTableScanState * node,TupleTableSlot * slot)66 WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
67 {
68 /* nothing to check */
69 return true;
70 }
71
72 /* ----------------------------------------------------------------
73 * ExecWorkTableScan(node)
74 *
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 * ----------------------------------------------------------------
79 */
80 static TupleTableSlot *
ExecWorkTableScan(PlanState * pstate)81 ExecWorkTableScan(PlanState *pstate)
82 {
83 WorkTableScanState *node = castNode(WorkTableScanState, pstate);
84
85 /*
86 * On the first call, find the ancestor RecursiveUnion's state via the
87 * Param slot reserved for it. (We can't do this during node init because
88 * there are corner cases where we'll get the init call before the
89 * RecursiveUnion does.)
90 */
91 if (node->rustate == NULL)
92 {
93 WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
94 EState *estate = node->ss.ps.state;
95 ParamExecData *param;
96
97 param = &(estate->es_param_exec_vals[plan->wtParam]);
98 Assert(param->execPlan == NULL);
99 Assert(!param->isnull);
100 node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
101 Assert(node->rustate);
102
103 /*
104 * The scan tuple type (ie, the rowtype we expect to find in the work
105 * table) is the same as the result rowtype of the ancestor
106 * RecursiveUnion node. Note this depends on the assumption that
107 * RecursiveUnion doesn't allow projection.
108 */
109 ExecAssignScanType(&node->ss,
110 ExecGetResultType(&node->rustate->ps));
111
112 /*
113 * Now we can initialize the projection info. This must be completed
114 * before we can call ExecScan().
115 */
116 ExecAssignScanProjectionInfo(&node->ss);
117 }
118
119 return ExecScan(&node->ss,
120 (ExecScanAccessMtd) WorkTableScanNext,
121 (ExecScanRecheckMtd) WorkTableScanRecheck);
122 }
123
124
125 /* ----------------------------------------------------------------
126 * ExecInitWorkTableScan
127 * ----------------------------------------------------------------
128 */
129 WorkTableScanState *
ExecInitWorkTableScan(WorkTableScan * node,EState * estate,int eflags)130 ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
131 {
132 WorkTableScanState *scanstate;
133
134 /* check for unsupported flags */
135 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
136
137 /*
138 * WorkTableScan should not have any children.
139 */
140 Assert(outerPlan(node) == NULL);
141 Assert(innerPlan(node) == NULL);
142
143 /*
144 * create new WorkTableScanState for node
145 */
146 scanstate = makeNode(WorkTableScanState);
147 scanstate->ss.ps.plan = (Plan *) node;
148 scanstate->ss.ps.state = estate;
149 scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
150 scanstate->rustate = NULL; /* we'll set this later */
151
152 /*
153 * Miscellaneous initialization
154 *
155 * create expression context for node
156 */
157 ExecAssignExprContext(estate, &scanstate->ss.ps);
158
159 /*
160 * initialize child expressions
161 */
162 scanstate->ss.ps.qual =
163 ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
164
165 /*
166 * tuple table initialization
167 */
168 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
169 ExecInitScanTupleSlot(estate, &scanstate->ss);
170
171 /*
172 * Initialize result tuple type, but not yet projection info.
173 */
174 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
175
176 return scanstate;
177 }
178
179 /* ----------------------------------------------------------------
180 * ExecEndWorkTableScan
181 *
182 * frees any storage allocated through C routines.
183 * ----------------------------------------------------------------
184 */
185 void
ExecEndWorkTableScan(WorkTableScanState * node)186 ExecEndWorkTableScan(WorkTableScanState *node)
187 {
188 /*
189 * Free exprcontext
190 */
191 ExecFreeExprContext(&node->ss.ps);
192
193 /*
194 * clean out the tuple table
195 */
196 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
197 ExecClearTuple(node->ss.ss_ScanTupleSlot);
198 }
199
200 /* ----------------------------------------------------------------
201 * ExecReScanWorkTableScan
202 *
203 * Rescans the relation.
204 * ----------------------------------------------------------------
205 */
206 void
ExecReScanWorkTableScan(WorkTableScanState * node)207 ExecReScanWorkTableScan(WorkTableScanState *node)
208 {
209 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
210
211 ExecScanReScan(&node->ss);
212
213 /* No need (or way) to rescan if ExecWorkTableScan not called yet */
214 if (node->rustate)
215 tuplestore_rescan(node->rustate->working_table);
216 }
217