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