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