Line data Source code
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 *
30 2070 : 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 2070 : Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
51 :
52 2070 : tuplestorestate = node->rustate->working_table;
53 :
54 : /*
55 : * Get the next tuple from tuplestore. Return NULL if no more tuples.
56 : */
57 2070 : slot = node->ss.ss_ScanTupleSlot;
58 2070 : (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
59 2070 : return slot;
60 : }
61 :
62 : /*
63 : * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
64 : */
65 : static bool
66 0 : WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
67 : {
68 : /* nothing to check */
69 0 : 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 *
81 2028 : ExecWorkTableScan(PlanState *pstate)
82 : {
83 2028 : 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 2028 : if (node->rustate == NULL)
92 : {
93 40 : WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
94 40 : EState *estate = node->ss.ps.state;
95 : ParamExecData *param;
96 :
97 40 : param = &(estate->es_param_exec_vals[plan->wtParam]);
98 40 : Assert(param->execPlan == NULL);
99 40 : Assert(!param->isnull);
100 40 : node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
101 40 : 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 40 : ExecAssignScanType(&node->ss,
110 40 : 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 40 : ExecAssignScanProjectionInfo(&node->ss);
117 : }
118 :
119 2028 : return ExecScan(&node->ss,
120 : (ExecScanAccessMtd) WorkTableScanNext,
121 : (ExecScanRecheckMtd) WorkTableScanRecheck);
122 : }
123 :
124 :
125 : /* ----------------------------------------------------------------
126 : * ExecInitWorkTableScan
127 : * ----------------------------------------------------------------
128 : */
129 : WorkTableScanState *
130 40 : ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
131 : {
132 : WorkTableScanState *scanstate;
133 :
134 : /* check for unsupported flags */
135 40 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
136 :
137 : /*
138 : * WorkTableScan should not have any children.
139 : */
140 40 : Assert(outerPlan(node) == NULL);
141 40 : Assert(innerPlan(node) == NULL);
142 :
143 : /*
144 : * create new WorkTableScanState for node
145 : */
146 40 : scanstate = makeNode(WorkTableScanState);
147 40 : scanstate->ss.ps.plan = (Plan *) node;
148 40 : scanstate->ss.ps.state = estate;
149 40 : scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
150 40 : scanstate->rustate = NULL; /* we'll set this later */
151 :
152 : /*
153 : * Miscellaneous initialization
154 : *
155 : * create expression context for node
156 : */
157 40 : ExecAssignExprContext(estate, &scanstate->ss.ps);
158 :
159 : /*
160 : * initialize child expressions
161 : */
162 40 : scanstate->ss.ps.qual =
163 40 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
164 :
165 : /*
166 : * tuple table initialization
167 : */
168 40 : ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
169 40 : ExecInitScanTupleSlot(estate, &scanstate->ss);
170 :
171 : /*
172 : * Initialize result tuple type, but not yet projection info.
173 : */
174 40 : ExecAssignResultTypeFromTL(&scanstate->ss.ps);
175 :
176 40 : return scanstate;
177 : }
178 :
179 : /* ----------------------------------------------------------------
180 : * ExecEndWorkTableScan
181 : *
182 : * frees any storage allocated through C routines.
183 : * ----------------------------------------------------------------
184 : */
185 : void
186 40 : ExecEndWorkTableScan(WorkTableScanState *node)
187 : {
188 : /*
189 : * Free exprcontext
190 : */
191 40 : ExecFreeExprContext(&node->ss.ps);
192 :
193 : /*
194 : * clean out the tuple table
195 : */
196 40 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
197 40 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
198 40 : }
199 :
200 : /* ----------------------------------------------------------------
201 : * ExecReScanWorkTableScan
202 : *
203 : * Rescans the relation.
204 : * ----------------------------------------------------------------
205 : */
206 : void
207 890 : ExecReScanWorkTableScan(WorkTableScanState *node)
208 : {
209 890 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
210 :
211 890 : ExecScanReScan(&node->ss);
212 :
213 : /* No need (or way) to rescan if ExecWorkTableScan not called yet */
214 890 : if (node->rustate)
215 890 : tuplestore_rescan(node->rustate->working_table);
216 890 : }
|