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