Line data Source code
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
77 2634 : exec_append_initialize_next(AppendState *appendstate)
78 : {
79 : int whichplan;
80 :
81 : /*
82 : * get information from the append node
83 : */
84 2634 : whichplan = appendstate->as_whichplan;
85 :
86 2634 : 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 0 : appendstate->as_whichplan = 0;
94 0 : return FALSE;
95 : }
96 2634 : 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 746 : appendstate->as_whichplan = appendstate->as_nplans - 1;
102 746 : return FALSE;
103 : }
104 : else
105 : {
106 1888 : 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 *
122 602 : ExecInitAppend(Append *node, EState *estate, int eflags)
123 : {
124 602 : AppendState *appendstate = makeNode(AppendState);
125 : PlanState **appendplanstates;
126 : int nplans;
127 : int i;
128 : ListCell *lc;
129 :
130 : /* check for unsupported flags */
131 602 : 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 602 : ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
138 :
139 : /*
140 : * Set up empty vector of subplan states
141 : */
142 602 : nplans = list_length(node->appendplans);
143 :
144 602 : appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
145 :
146 : /*
147 : * create new AppendState for our append node
148 : */
149 602 : appendstate->ps.plan = (Plan *) node;
150 602 : appendstate->ps.state = estate;
151 602 : appendstate->ps.ExecProcNode = ExecAppend;
152 602 : appendstate->appendplans = appendplanstates;
153 602 : 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 602 : 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 602 : i = 0;
173 2103 : foreach(lc, node->appendplans)
174 : {
175 1501 : Plan *initNode = (Plan *) lfirst(lc);
176 :
177 1501 : appendplanstates[i] = ExecInitNode(initNode, estate, eflags);
178 1501 : i++;
179 : }
180 :
181 : /*
182 : * initialize output tuple type
183 : */
184 602 : ExecAssignResultTypeFromTL(&appendstate->ps);
185 602 : appendstate->ps.ps_ProjInfo = NULL;
186 :
187 : /*
188 : * initialize to scan first subplan
189 : */
190 602 : appendstate->as_whichplan = 0;
191 602 : exec_append_initialize_next(appendstate);
192 :
193 602 : return appendstate;
194 : }
195 :
196 : /* ----------------------------------------------------------------
197 : * ExecAppend
198 : *
199 : * Handles iteration over multiple subplans.
200 : * ----------------------------------------------------------------
201 : */
202 : static TupleTableSlot *
203 105535 : ExecAppend(PlanState *pstate)
204 : {
205 105535 : AppendState *node = castNode(AppendState, pstate);
206 :
207 : for (;;)
208 : {
209 : PlanState *subnode;
210 : TupleTableSlot *result;
211 :
212 106498 : CHECK_FOR_INTERRUPTS();
213 :
214 : /*
215 : * figure out which subplan we are currently processing
216 : */
217 106498 : subnode = node->appendplans[node->as_whichplan];
218 :
219 : /*
220 : * get a tuple from the subplan
221 : */
222 106498 : result = ExecProcNode(subnode);
223 :
224 106498 : 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 104789 : 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 1709 : if (ScanDirectionIsForward(node->ps.state->es_direction))
240 1709 : node->as_whichplan++;
241 : else
242 0 : node->as_whichplan--;
243 1709 : if (!exec_append_initialize_next(node))
244 746 : return ExecClearTuple(node->ps.ps_ResultTupleSlot);
245 :
246 : /* Else loop back and try to get a tuple from the new subplan */
247 963 : }
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
259 591 : ExecEndAppend(AppendState *node)
260 : {
261 : PlanState **appendplans;
262 : int nplans;
263 : int i;
264 :
265 : /*
266 : * get information from the node
267 : */
268 591 : appendplans = node->appendplans;
269 591 : nplans = node->as_nplans;
270 :
271 : /*
272 : * shut down each of the subscans
273 : */
274 2070 : for (i = 0; i < nplans; i++)
275 1479 : ExecEndNode(appendplans[i]);
276 591 : }
277 :
278 : void
279 323 : ExecReScanAppend(AppendState *node)
280 : {
281 : int i;
282 :
283 980 : for (i = 0; i < node->as_nplans; i++)
284 : {
285 657 : 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 657 : if (node->ps.chgParam != NULL)
292 632 : 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 657 : if (subnode->chgParam == NULL)
299 137 : ExecReScan(subnode);
300 : }
301 323 : node->as_whichplan = 0;
302 323 : exec_append_initialize_next(node);
303 323 : }
|