1 /*-------------------------------------------------------------------------
2  *
3  * nodeAppend.c
4  *	  routines to handle append 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/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 
63 static bool exec_append_initialize_next(AppendState *appendstate);
64 
65 
66 /* ----------------------------------------------------------------
67  *		exec_append_initialize_next
68  *
69  *		Sets up the append state node for the "next" scan.
70  *
71  *		Returns t iff there is a "next" scan to process.
72  * ----------------------------------------------------------------
73  */
74 static bool
exec_append_initialize_next(AppendState * appendstate)75 exec_append_initialize_next(AppendState *appendstate)
76 {
77 	int			whichplan;
78 
79 	/*
80 	 * get information from the append node
81 	 */
82 	whichplan = appendstate->as_whichplan;
83 
84 	if (whichplan < 0)
85 	{
86 		/*
87 		 * if scanning in reverse, we start at the last scan in the list and
88 		 * then proceed back to the first.. in any case we inform ExecAppend
89 		 * that we are at the end of the line by returning FALSE
90 		 */
91 		appendstate->as_whichplan = 0;
92 		return FALSE;
93 	}
94 	else if (whichplan >= appendstate->as_nplans)
95 	{
96 		/*
97 		 * as above, end the scan if we go beyond the last scan in our list..
98 		 */
99 		appendstate->as_whichplan = appendstate->as_nplans - 1;
100 		return FALSE;
101 	}
102 	else
103 	{
104 		return TRUE;
105 	}
106 }
107 
108 /* ----------------------------------------------------------------
109  *		ExecInitAppend
110  *
111  *		Begin all of the subscans of the append node.
112  *
113  *	   (This is potentially wasteful, since the entire result of the
114  *		append node may not be scanned, but this way all of the
115  *		structures get allocated in the executor's top level memory
116  *		block instead of that of the call to ExecAppend.)
117  * ----------------------------------------------------------------
118  */
119 AppendState *
ExecInitAppend(Append * node,EState * estate,int eflags)120 ExecInitAppend(Append *node, EState *estate, int eflags)
121 {
122 	AppendState *appendstate = makeNode(AppendState);
123 	PlanState **appendplanstates;
124 	int			nplans;
125 	int			i;
126 	ListCell   *lc;
127 
128 	/* check for unsupported flags */
129 	Assert(!(eflags & EXEC_FLAG_MARK));
130 
131 	/*
132 	 * Set up empty vector of subplan states
133 	 */
134 	nplans = list_length(node->appendplans);
135 
136 	appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
137 
138 	/*
139 	 * create new AppendState for our append node
140 	 */
141 	appendstate->ps.plan = (Plan *) node;
142 	appendstate->ps.state = estate;
143 	appendstate->appendplans = appendplanstates;
144 	appendstate->as_nplans = nplans;
145 
146 	/*
147 	 * Miscellaneous initialization
148 	 *
149 	 * Append plans don't have expression contexts because they never call
150 	 * ExecQual or ExecProject.
151 	 */
152 
153 	/*
154 	 * append nodes still have Result slots, which hold pointers to tuples, so
155 	 * we have to initialize them.
156 	 */
157 	ExecInitResultTupleSlot(estate, &appendstate->ps);
158 
159 	/*
160 	 * call ExecInitNode on each of the plans to be executed and save the
161 	 * results into the array "appendplans".
162 	 */
163 	i = 0;
164 	foreach(lc, node->appendplans)
165 	{
166 		Plan	   *initNode = (Plan *) lfirst(lc);
167 
168 		appendplanstates[i] = ExecInitNode(initNode, estate, eflags);
169 		i++;
170 	}
171 
172 	/*
173 	 * initialize output tuple type
174 	 */
175 	ExecAssignResultTypeFromTL(&appendstate->ps);
176 	appendstate->ps.ps_ProjInfo = NULL;
177 
178 	/*
179 	 * initialize to scan first subplan
180 	 */
181 	appendstate->as_whichplan = 0;
182 	exec_append_initialize_next(appendstate);
183 
184 	return appendstate;
185 }
186 
187 /* ----------------------------------------------------------------
188  *	   ExecAppend
189  *
190  *		Handles iteration over multiple subplans.
191  * ----------------------------------------------------------------
192  */
193 TupleTableSlot *
ExecAppend(AppendState * node)194 ExecAppend(AppendState *node)
195 {
196 	for (;;)
197 	{
198 		PlanState  *subnode;
199 		TupleTableSlot *result;
200 
201 		/*
202 		 * figure out which subplan we are currently processing
203 		 */
204 		subnode = node->appendplans[node->as_whichplan];
205 
206 		/*
207 		 * get a tuple from the subplan
208 		 */
209 		result = ExecProcNode(subnode);
210 
211 		if (!TupIsNull(result))
212 		{
213 			/*
214 			 * If the subplan gave us something then return it as-is. We do
215 			 * NOT make use of the result slot that was set up in
216 			 * ExecInitAppend; there's no need for it.
217 			 */
218 			return result;
219 		}
220 
221 		/*
222 		 * Go on to the "next" subplan in the appropriate direction. If no
223 		 * more subplans, return the empty slot set up for us by
224 		 * ExecInitAppend.
225 		 */
226 		if (ScanDirectionIsForward(node->ps.state->es_direction))
227 			node->as_whichplan++;
228 		else
229 			node->as_whichplan--;
230 		if (!exec_append_initialize_next(node))
231 			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
232 
233 		/* Else loop back and try to get a tuple from the new subplan */
234 	}
235 }
236 
237 /* ----------------------------------------------------------------
238  *		ExecEndAppend
239  *
240  *		Shuts down the subscans of the append node.
241  *
242  *		Returns nothing of interest.
243  * ----------------------------------------------------------------
244  */
245 void
ExecEndAppend(AppendState * node)246 ExecEndAppend(AppendState *node)
247 {
248 	PlanState **appendplans;
249 	int			nplans;
250 	int			i;
251 
252 	/*
253 	 * get information from the node
254 	 */
255 	appendplans = node->appendplans;
256 	nplans = node->as_nplans;
257 
258 	/*
259 	 * shut down each of the subscans
260 	 */
261 	for (i = 0; i < nplans; i++)
262 		ExecEndNode(appendplans[i]);
263 }
264 
265 void
ExecReScanAppend(AppendState * node)266 ExecReScanAppend(AppendState *node)
267 {
268 	int			i;
269 
270 	for (i = 0; i < node->as_nplans; i++)
271 	{
272 		PlanState  *subnode = node->appendplans[i];
273 
274 		/*
275 		 * ExecReScan doesn't know about my subplans, so I have to do
276 		 * changed-parameter signaling myself.
277 		 */
278 		if (node->ps.chgParam != NULL)
279 			UpdateChangedParamSet(subnode, node->ps.chgParam);
280 
281 		/*
282 		 * If chgParam of subnode is not null then plan will be re-scanned by
283 		 * first ExecProcNode.
284 		 */
285 		if (subnode->chgParam == NULL)
286 			ExecReScan(subnode);
287 	}
288 	node->as_whichplan = 0;
289 	exec_append_initialize_next(node);
290 }
291