Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeMaterial.c
4 : * Routines to handle materialization 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/nodeMaterial.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : /*
16 : * INTERFACE ROUTINES
17 : * ExecMaterial - materialize the result of a subplan
18 : * ExecInitMaterial - initialize node and subnodes
19 : * ExecEndMaterial - shutdown node and subnodes
20 : *
21 : */
22 : #include "postgres.h"
23 :
24 : #include "executor/executor.h"
25 : #include "executor/nodeMaterial.h"
26 : #include "miscadmin.h"
27 :
28 : /* ----------------------------------------------------------------
29 : * ExecMaterial
30 : *
31 : * As long as we are at the end of the data collected in the tuplestore,
32 : * we collect one new row from the subplan on each call, and stash it
33 : * aside in the tuplestore before returning it. The tuplestore is
34 : * only read if we are asked to scan backwards, rescan, or mark/restore.
35 : *
36 : * ----------------------------------------------------------------
37 : */
38 : static TupleTableSlot * /* result tuple from subplan */
39 8231671 : ExecMaterial(PlanState *pstate)
40 : {
41 8231671 : MaterialState *node = castNode(MaterialState, pstate);
42 : EState *estate;
43 : ScanDirection dir;
44 : bool forward;
45 : Tuplestorestate *tuplestorestate;
46 : bool eof_tuplestore;
47 : TupleTableSlot *slot;
48 :
49 8231671 : CHECK_FOR_INTERRUPTS();
50 :
51 : /*
52 : * get state info from node
53 : */
54 8231671 : estate = node->ss.ps.state;
55 8231671 : dir = estate->es_direction;
56 8231671 : forward = ScanDirectionIsForward(dir);
57 8231671 : tuplestorestate = node->tuplestorestate;
58 :
59 : /*
60 : * If first time through, and we need a tuplestore, initialize it.
61 : */
62 8231671 : if (tuplestorestate == NULL && node->eflags != 0)
63 : {
64 172 : tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
65 172 : tuplestore_set_eflags(tuplestorestate, node->eflags);
66 172 : if (node->eflags & EXEC_FLAG_MARK)
67 : {
68 : /*
69 : * Allocate a second read pointer to serve as the mark. We know it
70 : * must have index 1, so needn't store that.
71 : */
72 : int ptrno PG_USED_FOR_ASSERTS_ONLY;
73 :
74 12 : ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
75 : node->eflags);
76 12 : Assert(ptrno == 1);
77 : }
78 172 : node->tuplestorestate = tuplestorestate;
79 : }
80 :
81 : /*
82 : * If we are not at the end of the tuplestore, or are going backwards, try
83 : * to fetch a tuple from tuplestore.
84 : */
85 16463342 : eof_tuplestore = (tuplestorestate == NULL) ||
86 8231671 : tuplestore_ateof(tuplestorestate);
87 :
88 8231671 : if (!forward && eof_tuplestore)
89 : {
90 2 : if (!node->eof_underlying)
91 : {
92 : /*
93 : * When reversing direction at tuplestore EOF, the first
94 : * gettupleslot call will fetch the last-added tuple; but we want
95 : * to return the one before that, if possible. So do an extra
96 : * fetch.
97 : */
98 0 : if (!tuplestore_advance(tuplestorestate, forward))
99 0 : return NULL; /* the tuplestore must be empty */
100 : }
101 2 : eof_tuplestore = false;
102 : }
103 :
104 : /*
105 : * If we can fetch another tuple from the tuplestore, return it.
106 : */
107 8231671 : slot = node->ss.ps.ps_ResultTupleSlot;
108 8231671 : if (!eof_tuplestore)
109 : {
110 8219334 : if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
111 8211760 : return slot;
112 7574 : if (forward)
113 7572 : eof_tuplestore = true;
114 : }
115 :
116 : /*
117 : * If necessary, try to fetch another row from the subplan.
118 : *
119 : * Note: the eof_underlying state variable exists to short-circuit further
120 : * subplan calls. It's not optional, unfortunately, because some plan
121 : * node types are not robust about being called again when they've already
122 : * returned NULL.
123 : */
124 19911 : if (eof_tuplestore && !node->eof_underlying)
125 : {
126 : PlanState *outerNode;
127 : TupleTableSlot *outerslot;
128 :
129 : /*
130 : * We can only get here with forward==true, so no need to worry about
131 : * which direction the subplan will go.
132 : */
133 12513 : outerNode = outerPlanState(node);
134 12513 : outerslot = ExecProcNode(outerNode);
135 12513 : if (TupIsNull(outerslot))
136 : {
137 165 : node->eof_underlying = true;
138 165 : return NULL;
139 : }
140 :
141 : /*
142 : * Append a copy of the returned tuple to tuplestore. NOTE: because
143 : * the tuplestore is certainly in EOF state, its read position will
144 : * move forward over the added tuple. This is what we want.
145 : */
146 12348 : if (tuplestorestate)
147 12348 : tuplestore_puttupleslot(tuplestorestate, outerslot);
148 :
149 : /*
150 : * We can just return the subplan's returned tuple, without copying.
151 : */
152 12348 : return outerslot;
153 : }
154 :
155 : /*
156 : * Nothing left ...
157 : */
158 7398 : return ExecClearTuple(slot);
159 : }
160 :
161 : /* ----------------------------------------------------------------
162 : * ExecInitMaterial
163 : * ----------------------------------------------------------------
164 : */
165 : MaterialState *
166 219 : ExecInitMaterial(Material *node, EState *estate, int eflags)
167 : {
168 : MaterialState *matstate;
169 : Plan *outerPlan;
170 :
171 : /*
172 : * create state structure
173 : */
174 219 : matstate = makeNode(MaterialState);
175 219 : matstate->ss.ps.plan = (Plan *) node;
176 219 : matstate->ss.ps.state = estate;
177 219 : matstate->ss.ps.ExecProcNode = ExecMaterial;
178 :
179 : /*
180 : * We must have a tuplestore buffering the subplan output to do backward
181 : * scan or mark/restore. We also prefer to materialize the subplan output
182 : * if we might be called on to rewind and replay it many times. However,
183 : * if none of these cases apply, we can skip storing the data.
184 : */
185 219 : matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
186 : EXEC_FLAG_BACKWARD |
187 : EXEC_FLAG_MARK));
188 :
189 : /*
190 : * Tuplestore's interpretation of the flag bits is subtly different from
191 : * the general executor meaning: it doesn't think BACKWARD necessarily
192 : * means "backwards all the way to start". If told to support BACKWARD we
193 : * must include REWIND in the tuplestore eflags, else tuplestore_trim
194 : * might throw away too much.
195 : */
196 219 : if (eflags & EXEC_FLAG_BACKWARD)
197 2 : matstate->eflags |= EXEC_FLAG_REWIND;
198 :
199 219 : matstate->eof_underlying = false;
200 219 : matstate->tuplestorestate = NULL;
201 :
202 : /*
203 : * Miscellaneous initialization
204 : *
205 : * Materialization nodes don't need ExprContexts because they never call
206 : * ExecQual or ExecProject.
207 : */
208 :
209 : /*
210 : * tuple table initialization
211 : *
212 : * material nodes only return tuples from their materialized relation.
213 : */
214 219 : ExecInitResultTupleSlot(estate, &matstate->ss.ps);
215 219 : ExecInitScanTupleSlot(estate, &matstate->ss);
216 :
217 : /*
218 : * initialize child nodes
219 : *
220 : * We shield the child node from the need to support REWIND, BACKWARD, or
221 : * MARK/RESTORE.
222 : */
223 219 : eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
224 :
225 219 : outerPlan = outerPlan(node);
226 219 : outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
227 :
228 : /*
229 : * initialize tuple type. no need to initialize projection info because
230 : * this node doesn't do projections.
231 : */
232 219 : ExecAssignResultTypeFromTL(&matstate->ss.ps);
233 219 : ExecAssignScanTypeFromOuterPlan(&matstate->ss);
234 219 : matstate->ss.ps.ps_ProjInfo = NULL;
235 :
236 219 : return matstate;
237 : }
238 :
239 : /* ----------------------------------------------------------------
240 : * ExecEndMaterial
241 : * ----------------------------------------------------------------
242 : */
243 : void
244 215 : ExecEndMaterial(MaterialState *node)
245 : {
246 : /*
247 : * clean out the tuple table
248 : */
249 215 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
250 :
251 : /*
252 : * Release tuplestore resources
253 : */
254 215 : if (node->tuplestorestate != NULL)
255 167 : tuplestore_end(node->tuplestorestate);
256 215 : node->tuplestorestate = NULL;
257 :
258 : /*
259 : * shut down the subplan
260 : */
261 215 : ExecEndNode(outerPlanState(node));
262 215 : }
263 :
264 : /* ----------------------------------------------------------------
265 : * ExecMaterialMarkPos
266 : *
267 : * Calls tuplestore to save the current position in the stored file.
268 : * ----------------------------------------------------------------
269 : */
270 : void
271 44 : ExecMaterialMarkPos(MaterialState *node)
272 : {
273 44 : Assert(node->eflags & EXEC_FLAG_MARK);
274 :
275 : /*
276 : * if we haven't materialized yet, just return.
277 : */
278 44 : if (!node->tuplestorestate)
279 44 : return;
280 :
281 : /*
282 : * copy the active read pointer to the mark.
283 : */
284 44 : tuplestore_copy_read_pointer(node->tuplestorestate, 0, 1);
285 :
286 : /*
287 : * since we may have advanced the mark, try to truncate the tuplestore.
288 : */
289 44 : tuplestore_trim(node->tuplestorestate);
290 : }
291 :
292 : /* ----------------------------------------------------------------
293 : * ExecMaterialRestrPos
294 : *
295 : * Calls tuplestore to restore the last saved file position.
296 : * ----------------------------------------------------------------
297 : */
298 : void
299 4 : ExecMaterialRestrPos(MaterialState *node)
300 : {
301 4 : Assert(node->eflags & EXEC_FLAG_MARK);
302 :
303 : /*
304 : * if we haven't materialized yet, just return.
305 : */
306 4 : if (!node->tuplestorestate)
307 4 : return;
308 :
309 : /*
310 : * copy the mark to the active read pointer.
311 : */
312 4 : tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
313 : }
314 :
315 : /* ----------------------------------------------------------------
316 : * ExecReScanMaterial
317 : *
318 : * Rescans the materialized relation.
319 : * ----------------------------------------------------------------
320 : */
321 : void
322 7620 : ExecReScanMaterial(MaterialState *node)
323 : {
324 7620 : PlanState *outerPlan = outerPlanState(node);
325 :
326 7620 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
327 :
328 7620 : if (node->eflags != 0)
329 : {
330 : /*
331 : * If we haven't materialized yet, just return. If outerplan's
332 : * chgParam is not NULL then it will be re-scanned by ExecProcNode,
333 : * else no reason to re-scan it at all.
334 : */
335 7620 : if (!node->tuplestorestate)
336 7777 : return;
337 :
338 : /*
339 : * If subnode is to be rescanned then we forget previous stored
340 : * results; we have to re-read the subplan and re-store. Also, if we
341 : * told tuplestore it needn't support rescan, we lose and must
342 : * re-read. (This last should not happen in common cases; else our
343 : * caller lied by not passing EXEC_FLAG_REWIND to us.)
344 : *
345 : * Otherwise we can just rewind and rescan the stored output. The
346 : * state of the subnode does not change.
347 : */
348 14925 : if (outerPlan->chgParam != NULL ||
349 7462 : (node->eflags & EXEC_FLAG_REWIND) == 0)
350 : {
351 1 : tuplestore_end(node->tuplestorestate);
352 1 : node->tuplestorestate = NULL;
353 1 : if (outerPlan->chgParam == NULL)
354 0 : ExecReScan(outerPlan);
355 1 : node->eof_underlying = false;
356 : }
357 : else
358 7462 : tuplestore_rescan(node->tuplestorestate);
359 : }
360 : else
361 : {
362 : /* In this case we are just passing on the subquery's output */
363 :
364 : /*
365 : * if chgParam of subnode is not null then plan will be re-scanned by
366 : * first ExecProcNode.
367 : */
368 0 : if (outerPlan->chgParam == NULL)
369 0 : ExecReScan(outerPlan);
370 0 : node->eof_underlying = false;
371 : }
372 : }
|