1 /*-------------------------------------------------------------------------
2  *
3  * nodeAppend.c
4  *	  routines to handle append 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/nodeAppend.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /* INTERFACE ROUTINES
16  *		ExecInitAppend	- initialize the append node
17  *		ExecAppend		- retrieve the next tuple from the node
18  *		ExecEndAppend	- shut down the append node
19  *		ExecReScanAppend - rescan the append node
20  *
21  *	 NOTES
22  *		Each append node contains a list of one or more subplans which
23  *		must be iteratively processed (forwards or backwards).
24  *		Tuples are retrieved by executing the 'whichplan'th subplan
25  *		until the subplan stops returning tuples, at which point that
26  *		plan is shut down and the next started up.
27  *
28  *		Append nodes don't make use of their left and right
29  *		subtrees, rather they maintain a list of subplans so
30  *		a typical append node looks like this in the plan tree:
31  *
32  *				   ...
33  *				   /
34  *				Append -------+------+------+--- nil
35  *				/	\		  |		 |		|
36  *			  nil	nil		 ...    ...    ...
37  *								 subplans
38  *
39  *		Append nodes are currently used for unions, and to support
40  *		inheritance queries, where several relations need to be scanned.
41  *		For example, in our standard person/student/employee/student-emp
42  *		example, where student and employee inherit from person
43  *		and student-emp inherits from student and employee, the
44  *		query:
45  *
46  *				select name from person
47  *
48  *		generates the plan:
49  *
50  *				  |
51  *				Append -------+-------+--------+--------+
52  *				/	\		  |		  |		   |		|
53  *			  nil	nil		 Scan	 Scan	  Scan	   Scan
54  *							  |		  |		   |		|
55  *							person employee student student-emp
56  */
57 
58 #include "postgres.h"
59 
60 #include "executor/execdebug.h"
61 #include "executor/nodeAppend.h"
62 #include "miscadmin.h"
63 
64 static TupleTableSlot *ExecAppend(PlanState *pstate);
65 static bool exec_append_initialize_next(AppendState *appendstate);
66 
67 
68 /* ----------------------------------------------------------------
69  *		exec_append_initialize_next
70  *
71  *		Sets up the append state node for the "next" scan.
72  *
73  *		Returns t iff there is a "next" scan to process.
74  * ----------------------------------------------------------------
75  */
76 static bool
exec_append_initialize_next(AppendState * appendstate)77 exec_append_initialize_next(AppendState *appendstate)
78 {
79 	int			whichplan;
80 
81 	/*
82 	 * get information from the append node
83 	 */
84 	whichplan = appendstate->as_whichplan;
85 
86 	if (whichplan < 0)
87 	{
88 		/*
89 		 * if scanning in reverse, we start at the last scan in the list and
90 		 * then proceed back to the first.. in any case we inform ExecAppend
91 		 * that we are at the end of the line by returning FALSE
92 		 */
93 		appendstate->as_whichplan = 0;
94 		return FALSE;
95 	}
96 	else if (whichplan >= appendstate->as_nplans)
97 	{
98 		/*
99 		 * as above, end the scan if we go beyond the last scan in our list..
100 		 */
101 		appendstate->as_whichplan = appendstate->as_nplans - 1;
102 		return FALSE;
103 	}
104 	else
105 	{
106 		return TRUE;
107 	}
108 }
109 
110 /* ----------------------------------------------------------------
111  *		ExecInitAppend
112  *
113  *		Begin all of the subscans of the append node.
114  *
115  *	   (This is potentially wasteful, since the entire result of the
116  *		append node may not be scanned, but this way all of the
117  *		structures get allocated in the executor's top level memory
118  *		block instead of that of the call to ExecAppend.)
119  * ----------------------------------------------------------------
120  */
121 AppendState *
ExecInitAppend(Append * node,EState * estate,int eflags)122 ExecInitAppend(Append *node, EState *estate, int eflags)
123 {
124 	AppendState *appendstate = makeNode(AppendState);
125 	PlanState **appendplanstates;
126 	int			nplans;
127 	int			i;
128 	ListCell   *lc;
129 
130 	/* check for unsupported flags */
131 	Assert(!(eflags & EXEC_FLAG_MARK));
132 
133 	/*
134 	 * Lock the non-leaf tables in the partition tree controlled by this node.
135 	 * It's a no-op for non-partitioned parent tables.
136 	 */
137 	ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
138 
139 	/*
140 	 * Set up empty vector of subplan states
141 	 */
142 	nplans = list_length(node->appendplans);
143 
144 	appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
145 
146 	/*
147 	 * create new AppendState for our append node
148 	 */
149 	appendstate->ps.plan = (Plan *) node;
150 	appendstate->ps.state = estate;
151 	appendstate->ps.ExecProcNode = ExecAppend;
152 	appendstate->appendplans = appendplanstates;
153 	appendstate->as_nplans = nplans;
154 
155 	/*
156 	 * Miscellaneous initialization
157 	 *
158 	 * Append plans don't have expression contexts because they never call
159 	 * ExecQual or ExecProject.
160 	 */
161 
162 	/*
163 	 * append nodes still have Result slots, which hold pointers to tuples, so
164 	 * we have to initialize them.
165 	 */
166 	ExecInitResultTupleSlot(estate, &appendstate->ps);
167 
168 	/*
169 	 * call ExecInitNode on each of the plans to be executed and save the
170 	 * results into the array "appendplans".
171 	 */
172 	i = 0;
173 	foreach(lc, node->appendplans)
174 	{
175 		Plan	   *initNode = (Plan *) lfirst(lc);
176 
177 		appendplanstates[i] = ExecInitNode(initNode, estate, eflags);
178 		i++;
179 	}
180 
181 	/*
182 	 * initialize output tuple type
183 	 */
184 	ExecAssignResultTypeFromTL(&appendstate->ps);
185 	appendstate->ps.ps_ProjInfo = NULL;
186 
187 	/*
188 	 * initialize to scan first subplan
189 	 */
190 	appendstate->as_whichplan = 0;
191 	exec_append_initialize_next(appendstate);
192 
193 	return appendstate;
194 }
195 
196 /* ----------------------------------------------------------------
197  *	   ExecAppend
198  *
199  *		Handles iteration over multiple subplans.
200  * ----------------------------------------------------------------
201  */
202 static TupleTableSlot *
ExecAppend(PlanState * pstate)203 ExecAppend(PlanState *pstate)
204 {
205 	AppendState *node = castNode(AppendState, pstate);
206 
207 	for (;;)
208 	{
209 		PlanState  *subnode;
210 		TupleTableSlot *result;
211 
212 		CHECK_FOR_INTERRUPTS();
213 
214 		/*
215 		 * figure out which subplan we are currently processing
216 		 */
217 		subnode = node->appendplans[node->as_whichplan];
218 
219 		/*
220 		 * get a tuple from the subplan
221 		 */
222 		result = ExecProcNode(subnode);
223 
224 		if (!TupIsNull(result))
225 		{
226 			/*
227 			 * If the subplan gave us something then return it as-is. We do
228 			 * NOT make use of the result slot that was set up in
229 			 * ExecInitAppend; there's no need for it.
230 			 */
231 			return result;
232 		}
233 
234 		/*
235 		 * Go on to the "next" subplan in the appropriate direction. If no
236 		 * more subplans, return the empty slot set up for us by
237 		 * ExecInitAppend.
238 		 */
239 		if (ScanDirectionIsForward(node->ps.state->es_direction))
240 			node->as_whichplan++;
241 		else
242 			node->as_whichplan--;
243 		if (!exec_append_initialize_next(node))
244 			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
245 
246 		/* Else loop back and try to get a tuple from the new subplan */
247 	}
248 }
249 
250 /* ----------------------------------------------------------------
251  *		ExecEndAppend
252  *
253  *		Shuts down the subscans of the append node.
254  *
255  *		Returns nothing of interest.
256  * ----------------------------------------------------------------
257  */
258 void
ExecEndAppend(AppendState * node)259 ExecEndAppend(AppendState *node)
260 {
261 	PlanState **appendplans;
262 	int			nplans;
263 	int			i;
264 
265 	/*
266 	 * get information from the node
267 	 */
268 	appendplans = node->appendplans;
269 	nplans = node->as_nplans;
270 
271 	/*
272 	 * shut down each of the subscans
273 	 */
274 	for (i = 0; i < nplans; i++)
275 		ExecEndNode(appendplans[i]);
276 }
277 
278 void
ExecReScanAppend(AppendState * node)279 ExecReScanAppend(AppendState *node)
280 {
281 	int			i;
282 
283 	for (i = 0; i < node->as_nplans; i++)
284 	{
285 		PlanState  *subnode = node->appendplans[i];
286 
287 		/*
288 		 * ExecReScan doesn't know about my subplans, so I have to do
289 		 * changed-parameter signaling myself.
290 		 */
291 		if (node->ps.chgParam != NULL)
292 			UpdateChangedParamSet(subnode, node->ps.chgParam);
293 
294 		/*
295 		 * If chgParam of subnode is not null then plan will be re-scanned by
296 		 * first ExecProcNode.
297 		 */
298 		if (subnode->chgParam == NULL)
299 			ExecReScan(subnode);
300 	}
301 	node->as_whichplan = 0;
302 	exec_append_initialize_next(node);
303 }
304