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 */
ExecMaterial(PlanState * pstate)39 ExecMaterial(PlanState *pstate)
40 {
41 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 CHECK_FOR_INTERRUPTS();
50
51 /*
52 * get state info from node
53 */
54 estate = node->ss.ps.state;
55 dir = estate->es_direction;
56 forward = ScanDirectionIsForward(dir);
57 tuplestorestate = node->tuplestorestate;
58
59 /*
60 * If first time through, and we need a tuplestore, initialize it.
61 */
62 if (tuplestorestate == NULL && node->eflags != 0)
63 {
64 tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
65 tuplestore_set_eflags(tuplestorestate, node->eflags);
66 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 ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
75 node->eflags);
76 Assert(ptrno == 1);
77 }
78 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 eof_tuplestore = (tuplestorestate == NULL) ||
86 tuplestore_ateof(tuplestorestate);
87
88 if (!forward && eof_tuplestore)
89 {
90 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 if (!tuplestore_advance(tuplestorestate, forward))
99 return NULL; /* the tuplestore must be empty */
100 }
101 eof_tuplestore = false;
102 }
103
104 /*
105 * If we can fetch another tuple from the tuplestore, return it.
106 */
107 slot = node->ss.ps.ps_ResultTupleSlot;
108 if (!eof_tuplestore)
109 {
110 if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
111 return slot;
112 if (forward)
113 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 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 outerNode = outerPlanState(node);
134 outerslot = ExecProcNode(outerNode);
135 if (TupIsNull(outerslot))
136 {
137 node->eof_underlying = true;
138 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 if (tuplestorestate)
147 tuplestore_puttupleslot(tuplestorestate, outerslot);
148
149 /*
150 * We can just return the subplan's returned tuple, without copying.
151 */
152 return outerslot;
153 }
154
155 /*
156 * Nothing left ...
157 */
158 return ExecClearTuple(slot);
159 }
160
161 /* ----------------------------------------------------------------
162 * ExecInitMaterial
163 * ----------------------------------------------------------------
164 */
165 MaterialState *
ExecInitMaterial(Material * node,EState * estate,int eflags)166 ExecInitMaterial(Material *node, EState *estate, int eflags)
167 {
168 MaterialState *matstate;
169 Plan *outerPlan;
170
171 /*
172 * create state structure
173 */
174 matstate = makeNode(MaterialState);
175 matstate->ss.ps.plan = (Plan *) node;
176 matstate->ss.ps.state = estate;
177 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 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 if (eflags & EXEC_FLAG_BACKWARD)
197 matstate->eflags |= EXEC_FLAG_REWIND;
198
199 matstate->eof_underlying = false;
200 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 ExecInitResultTupleSlot(estate, &matstate->ss.ps);
215 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 eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
224
225 outerPlan = outerPlan(node);
226 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 ExecAssignResultTypeFromTL(&matstate->ss.ps);
233 ExecAssignScanTypeFromOuterPlan(&matstate->ss);
234 matstate->ss.ps.ps_ProjInfo = NULL;
235
236 return matstate;
237 }
238
239 /* ----------------------------------------------------------------
240 * ExecEndMaterial
241 * ----------------------------------------------------------------
242 */
243 void
ExecEndMaterial(MaterialState * node)244 ExecEndMaterial(MaterialState *node)
245 {
246 /*
247 * clean out the tuple table
248 */
249 ExecClearTuple(node->ss.ss_ScanTupleSlot);
250
251 /*
252 * Release tuplestore resources
253 */
254 if (node->tuplestorestate != NULL)
255 tuplestore_end(node->tuplestorestate);
256 node->tuplestorestate = NULL;
257
258 /*
259 * shut down the subplan
260 */
261 ExecEndNode(outerPlanState(node));
262 }
263
264 /* ----------------------------------------------------------------
265 * ExecMaterialMarkPos
266 *
267 * Calls tuplestore to save the current position in the stored file.
268 * ----------------------------------------------------------------
269 */
270 void
ExecMaterialMarkPos(MaterialState * node)271 ExecMaterialMarkPos(MaterialState *node)
272 {
273 Assert(node->eflags & EXEC_FLAG_MARK);
274
275 /*
276 * if we haven't materialized yet, just return.
277 */
278 if (!node->tuplestorestate)
279 return;
280
281 /*
282 * copy the active read pointer to the mark.
283 */
284 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 tuplestore_trim(node->tuplestorestate);
290 }
291
292 /* ----------------------------------------------------------------
293 * ExecMaterialRestrPos
294 *
295 * Calls tuplestore to restore the last saved file position.
296 * ----------------------------------------------------------------
297 */
298 void
ExecMaterialRestrPos(MaterialState * node)299 ExecMaterialRestrPos(MaterialState *node)
300 {
301 Assert(node->eflags & EXEC_FLAG_MARK);
302
303 /*
304 * if we haven't materialized yet, just return.
305 */
306 if (!node->tuplestorestate)
307 return;
308
309 /*
310 * copy the mark to the active read pointer.
311 */
312 tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
313 }
314
315 /* ----------------------------------------------------------------
316 * ExecReScanMaterial
317 *
318 * Rescans the materialized relation.
319 * ----------------------------------------------------------------
320 */
321 void
ExecReScanMaterial(MaterialState * node)322 ExecReScanMaterial(MaterialState *node)
323 {
324 PlanState *outerPlan = outerPlanState(node);
325
326 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
327
328 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 if (!node->tuplestorestate)
336 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 if (outerPlan->chgParam != NULL ||
349 (node->eflags & EXEC_FLAG_REWIND) == 0)
350 {
351 tuplestore_end(node->tuplestorestate);
352 node->tuplestorestate = NULL;
353 if (outerPlan->chgParam == NULL)
354 ExecReScan(outerPlan);
355 node->eof_underlying = false;
356 }
357 else
358 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 if (outerPlan->chgParam == NULL)
369 ExecReScan(outerPlan);
370 node->eof_underlying = false;
371 }
372 }
373