Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeCtescan.c
4 : * routines to handle CteScan 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/nodeCtescan.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include "executor/execdebug.h"
19 : #include "executor/nodeCtescan.h"
20 : #include "miscadmin.h"
21 :
22 : static TupleTableSlot *CteScanNext(CteScanState *node);
23 :
24 : /* ----------------------------------------------------------------
25 : * CteScanNext
26 : *
27 : * This is a workhorse for ExecCteScan
28 : * ----------------------------------------------------------------
29 : */
30 : static TupleTableSlot *
31 4815 : CteScanNext(CteScanState *node)
32 : {
33 : EState *estate;
34 : ScanDirection dir;
35 : bool forward;
36 : Tuplestorestate *tuplestorestate;
37 : bool eof_tuplestore;
38 : TupleTableSlot *slot;
39 :
40 : /*
41 : * get state info from node
42 : */
43 4815 : estate = node->ss.ps.state;
44 4815 : dir = estate->es_direction;
45 4815 : forward = ScanDirectionIsForward(dir);
46 4815 : tuplestorestate = node->leader->cte_table;
47 4815 : tuplestore_select_read_pointer(tuplestorestate, node->readptr);
48 4815 : slot = node->ss.ss_ScanTupleSlot;
49 :
50 : /*
51 : * If we are not at the end of the tuplestore, or are going backwards, try
52 : * to fetch a tuple from tuplestore.
53 : */
54 4815 : eof_tuplestore = tuplestore_ateof(tuplestorestate);
55 :
56 4815 : if (!forward && eof_tuplestore)
57 : {
58 0 : if (!node->leader->eof_cte)
59 : {
60 : /*
61 : * When reversing direction at tuplestore EOF, the first
62 : * gettupleslot call will fetch the last-added tuple; but we want
63 : * to return the one before that, if possible. So do an extra
64 : * fetch.
65 : */
66 0 : if (!tuplestore_advance(tuplestorestate, forward))
67 0 : return NULL; /* the tuplestore must be empty */
68 : }
69 0 : eof_tuplestore = false;
70 : }
71 :
72 : /*
73 : * If we can fetch another tuple from the tuplestore, return it.
74 : *
75 : * Note: we have to use copy=true in the tuplestore_gettupleslot call,
76 : * because we are sharing the tuplestore with other nodes that might write
77 : * into the tuplestore before we get called again.
78 : */
79 4815 : if (!eof_tuplestore)
80 : {
81 530 : if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot))
82 322 : return slot;
83 208 : if (forward)
84 208 : eof_tuplestore = true;
85 : }
86 :
87 : /*
88 : * If necessary, try to fetch another row from the CTE query.
89 : *
90 : * Note: the eof_cte state variable exists to short-circuit further calls
91 : * of the CTE plan. It's not optional, unfortunately, because some plan
92 : * node types are not robust about being called again when they've already
93 : * returned NULL.
94 : */
95 4493 : if (eof_tuplestore && !node->leader->eof_cte)
96 : {
97 : TupleTableSlot *cteslot;
98 :
99 : /*
100 : * We can only get here with forward==true, so no need to worry about
101 : * which direction the subplan will go.
102 : */
103 4455 : cteslot = ExecProcNode(node->cteplanstate);
104 4452 : if (TupIsNull(cteslot))
105 : {
106 152 : node->leader->eof_cte = true;
107 152 : return NULL;
108 : }
109 :
110 : /*
111 : * Append a copy of the returned tuple to tuplestore. NOTE: because
112 : * our read pointer is certainly in EOF state, its read position will
113 : * move forward over the added tuple. This is what we want. Also,
114 : * any other readers will *not* move past the new tuple, which is what
115 : * they want.
116 : */
117 4300 : tuplestore_puttupleslot(tuplestorestate, cteslot);
118 :
119 : /*
120 : * We MUST copy the CTE query's output tuple into our own slot. This
121 : * is because other CteScan nodes might advance the CTE query before
122 : * we are called again, and our output tuple must stay stable over
123 : * that.
124 : */
125 4300 : return ExecCopySlot(slot, cteslot);
126 : }
127 :
128 : /*
129 : * Nothing left ...
130 : */
131 38 : return ExecClearTuple(slot);
132 : }
133 :
134 : /*
135 : * CteScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
136 : */
137 : static bool
138 0 : CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
139 : {
140 : /* nothing to check */
141 0 : return true;
142 : }
143 :
144 : /* ----------------------------------------------------------------
145 : * ExecCteScan(node)
146 : *
147 : * Scans the CTE sequentially and returns the next qualifying tuple.
148 : * We call the ExecScan() routine and pass it the appropriate
149 : * access method functions.
150 : * ----------------------------------------------------------------
151 : */
152 : static TupleTableSlot *
153 2674 : ExecCteScan(PlanState *pstate)
154 : {
155 2674 : CteScanState *node = castNode(CteScanState, pstate);
156 :
157 2674 : return ExecScan(&node->ss,
158 : (ExecScanAccessMtd) CteScanNext,
159 : (ExecScanRecheckMtd) CteScanRecheck);
160 : }
161 :
162 :
163 : /* ----------------------------------------------------------------
164 : * ExecInitCteScan
165 : * ----------------------------------------------------------------
166 : */
167 : CteScanState *
168 162 : ExecInitCteScan(CteScan *node, EState *estate, int eflags)
169 : {
170 : CteScanState *scanstate;
171 : ParamExecData *prmdata;
172 :
173 : /* check for unsupported flags */
174 162 : Assert(!(eflags & EXEC_FLAG_MARK));
175 :
176 : /*
177 : * For the moment we have to force the tuplestore to allow REWIND, because
178 : * we might be asked to rescan the CTE even though upper levels didn't
179 : * tell us to be prepared to do it efficiently. Annoying, since this
180 : * prevents truncation of the tuplestore. XXX FIXME
181 : */
182 162 : eflags |= EXEC_FLAG_REWIND;
183 :
184 : /*
185 : * CteScan should not have any children.
186 : */
187 162 : Assert(outerPlan(node) == NULL);
188 162 : Assert(innerPlan(node) == NULL);
189 :
190 : /*
191 : * create new CteScanState for node
192 : */
193 162 : scanstate = makeNode(CteScanState);
194 162 : scanstate->ss.ps.plan = (Plan *) node;
195 162 : scanstate->ss.ps.state = estate;
196 162 : scanstate->ss.ps.ExecProcNode = ExecCteScan;
197 162 : scanstate->eflags = eflags;
198 162 : scanstate->cte_table = NULL;
199 162 : scanstate->eof_cte = false;
200 :
201 : /*
202 : * Find the already-initialized plan for the CTE query.
203 : */
204 162 : scanstate->cteplanstate = (PlanState *) list_nth(estate->es_subplanstates,
205 162 : node->ctePlanId - 1);
206 :
207 : /*
208 : * The Param slot associated with the CTE query is used to hold a pointer
209 : * to the CteState of the first CteScan node that initializes for this
210 : * CTE. This node will be the one that holds the shared state for all the
211 : * CTEs, particularly the shared tuplestore.
212 : */
213 162 : prmdata = &(estate->es_param_exec_vals[node->cteParam]);
214 162 : Assert(prmdata->execPlan == NULL);
215 162 : Assert(!prmdata->isnull);
216 162 : scanstate->leader = castNode(CteScanState, DatumGetPointer(prmdata->value));
217 162 : if (scanstate->leader == NULL)
218 : {
219 : /* I am the leader */
220 133 : prmdata->value = PointerGetDatum(scanstate);
221 133 : scanstate->leader = scanstate;
222 133 : scanstate->cte_table = tuplestore_begin_heap(true, false, work_mem);
223 133 : tuplestore_set_eflags(scanstate->cte_table, scanstate->eflags);
224 133 : scanstate->readptr = 0;
225 : }
226 : else
227 : {
228 : /* Not the leader */
229 : /* Create my own read pointer, and ensure it is at start */
230 29 : scanstate->readptr =
231 29 : tuplestore_alloc_read_pointer(scanstate->leader->cte_table,
232 : scanstate->eflags);
233 29 : tuplestore_select_read_pointer(scanstate->leader->cte_table,
234 : scanstate->readptr);
235 29 : tuplestore_rescan(scanstate->leader->cte_table);
236 : }
237 :
238 : /*
239 : * Miscellaneous initialization
240 : *
241 : * create expression context for node
242 : */
243 162 : ExecAssignExprContext(estate, &scanstate->ss.ps);
244 :
245 : /*
246 : * initialize child expressions
247 : */
248 162 : scanstate->ss.ps.qual =
249 162 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
250 :
251 : /*
252 : * tuple table initialization
253 : */
254 162 : ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
255 162 : ExecInitScanTupleSlot(estate, &scanstate->ss);
256 :
257 : /*
258 : * The scan tuple type (ie, the rowtype we expect to find in the work
259 : * table) is the same as the result rowtype of the CTE query.
260 : */
261 162 : ExecAssignScanType(&scanstate->ss,
262 : ExecGetResultType(scanstate->cteplanstate));
263 :
264 : /*
265 : * Initialize result tuple type and projection info.
266 : */
267 162 : ExecAssignResultTypeFromTL(&scanstate->ss.ps);
268 162 : ExecAssignScanProjectionInfo(&scanstate->ss);
269 :
270 162 : return scanstate;
271 : }
272 :
273 : /* ----------------------------------------------------------------
274 : * ExecEndCteScan
275 : *
276 : * frees any storage allocated through C routines.
277 : * ----------------------------------------------------------------
278 : */
279 : void
280 159 : ExecEndCteScan(CteScanState *node)
281 : {
282 : /*
283 : * Free exprcontext
284 : */
285 159 : ExecFreeExprContext(&node->ss.ps);
286 :
287 : /*
288 : * clean out the tuple table
289 : */
290 159 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
291 159 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
292 :
293 : /*
294 : * If I am the leader, free the tuplestore.
295 : */
296 159 : if (node->leader == node)
297 : {
298 130 : tuplestore_end(node->cte_table);
299 130 : node->cte_table = NULL;
300 : }
301 159 : }
302 :
303 : /* ----------------------------------------------------------------
304 : * ExecReScanCteScan
305 : *
306 : * Rescans the relation.
307 : * ----------------------------------------------------------------
308 : */
309 : void
310 80 : ExecReScanCteScan(CteScanState *node)
311 : {
312 80 : Tuplestorestate *tuplestorestate = node->leader->cte_table;
313 :
314 80 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
315 :
316 80 : ExecScanReScan(&node->ss);
317 :
318 : /*
319 : * Clear the tuplestore if a new scan of the underlying CTE is required.
320 : * This implicitly resets all the tuplestore's read pointers. Note that
321 : * multiple CTE nodes might redundantly clear the tuplestore; that's OK,
322 : * and not unduly expensive. We'll stop taking this path as soon as
323 : * somebody has attempted to read something from the underlying CTE
324 : * (thereby causing its chgParam to be cleared).
325 : */
326 80 : if (node->leader->cteplanstate->chgParam != NULL)
327 : {
328 47 : tuplestore_clear(tuplestorestate);
329 47 : node->leader->eof_cte = false;
330 : }
331 : else
332 : {
333 : /*
334 : * Else, just rewind my own pointer. Either the underlying CTE
335 : * doesn't need a rescan (and we can re-read what's in the tuplestore
336 : * now), or somebody else already took care of it.
337 : */
338 33 : tuplestore_select_read_pointer(tuplestorestate, node->readptr);
339 33 : tuplestore_rescan(tuplestorestate);
340 : }
341 80 : }
|