]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeAppend.c
OK, folks, here is the pgindent output.
[postgresql] / src / backend / executor / nodeAppend.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeAppend.c--
4  *        routines to handle append nodes.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.15 1998/09/01 04:28:26 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /* INTERFACE ROUTINES
15  *              ExecInitAppend  - initialize the append node
16  *              ExecProcAppend  - retrieve the next tuple from the node
17  *              ExecEndAppend   - shut down the append node
18  *              ExecReScanAppend - rescan the append node
19  *
20  *       NOTES
21  *              Each append node contains a list of one or more subplans which
22  *              must be iteratively processed (forwards or backwards).
23  *              Tuples are retrieved by executing the 'whichplan'th subplan
24  *              until the subplan stops returning tuples, at which point that
25  *              plan is shut down and the next started up.
26  *
27  *              Append nodes don't make use of their left and right
28  *              subtrees, rather they maintain a list of subplans so
29  *              a typical append node looks like this in the plan tree:
30  *
31  *                                 ...
32  *                                 /
33  *                              Append -------+------+------+--- nil
34  *                              /       \                 |              |              |
35  *                        nil   nil              ...    ...    ...
36  *                                                               subplans
37  *
38  *              Append nodes are currently used for unions, and to support inheritance
39  *              queries, where several relations need to be scanned.
40  *              For example, in our standard person/student/employee/student-emp
41  *              example, where student and employee inherit from person
42  *              and student-emp inherits from student and employee, the
43  *              query:
44  *
45  *                              retrieve (e.name) from e in person*
46  *
47  *              generates the plan:
48  *
49  *                                |
50  *                              Append -------+-------+--------+--------+
51  *                              /       \                 |               |                |            |
52  *                        nil   nil              Scan    Scan     Scan     Scan
53  *                                                        |               |                |            |
54  *                                                      person employee student student-emp
55  */
56 #include "postgres.h"
57
58
59 #include "access/heapam.h"
60 #include "executor/executor.h"
61 #include "executor/execdebug.h"
62 #include "executor/nodeAppend.h"
63 #include "executor/nodeIndexscan.h"
64 #include "utils/palloc.h"
65 #include "utils/mcxt.h"
66 #include "parser/parsetree.h"   /* for rt_store() macro */
67
68 static bool exec_append_initialize_next(Append *node);
69
70 /* ----------------------------------------------------------------
71  *              exec-append-initialize-next
72  *
73  *              Sets up the append node state (i.e. the append state node)
74  *              for the "next" scan.
75  *
76  *              Returns t iff there is a "next" scan to process.
77  * ----------------------------------------------------------------
78  */
79 static bool
80 exec_append_initialize_next(Append *node)
81 {
82         EState     *estate;
83         AppendState *appendstate;
84         TupleTableSlot *result_slot;
85         List       *rangeTable;
86
87         int                     whichplan;
88         int                     nplans;
89         List       *rtables;
90         List       *rtable;
91         ResTarget  *rtentry;
92
93         /* ----------------
94          *      get information from the append node
95          * ----------------
96          */
97         estate = node->plan.state;
98         appendstate = node->appendstate;
99         result_slot = appendstate->cstate.cs_ResultTupleSlot;
100         rangeTable = estate->es_range_table;
101
102         whichplan = appendstate->as_whichplan;
103         nplans = appendstate->as_nplans;
104         rtables = node->unionrtables;
105         rtable = node->inheritrtable;
106
107         if (whichplan < 0)
108         {
109                 /* ----------------
110                  *              if scanning in reverse, we start at
111                  *              the last scan in the list and then
112                  *              proceed back to the first.. in any case
113                  *              we inform ExecProcAppend that we are
114                  *              at the end of the line by returning FALSE
115                  * ----------------
116                  */
117                 appendstate->as_whichplan = 0;
118                 return FALSE;
119
120         }
121         else if (whichplan >= nplans)
122         {
123                 /* ----------------
124                  *              as above, end the scan if we go beyond
125                  *              the last scan in our list..
126                  * ----------------
127                  */
128                 appendstate->as_whichplan = nplans - 1;
129                 return FALSE;
130
131         }
132         else
133         {
134                 /* ----------------
135                  *              initialize the scan
136                  *              (and update the range table appropriately)
137                  *                (doesn't this leave the range table hosed for anybody upstream
138                  *                 of the Append node??? - jolly )
139                  * ----------------
140                  */
141                 if (node->inheritrelid > 0)
142                 {
143                         rtentry = nth(whichplan, rtable);
144                         Assert(rtentry != NULL);
145
146                         rt_store(node->inheritrelid, rangeTable, rtentry);
147                 }
148                 else
149                         estate->es_range_table = nth(whichplan, rtables);
150
151                 if (appendstate->as_junkFilter_list)
152                 {
153                         estate->es_junkFilter =
154                                 (JunkFilter *) nth(whichplan,
155                                                                    appendstate->as_junkFilter_list);
156                 }
157                 if (appendstate->as_result_relation_info_list)
158                 {
159                         estate->es_result_relation_info =
160                                 (RelationInfo *) nth(whichplan,
161                                                           appendstate->as_result_relation_info_list);
162                 }
163                 result_slot->ttc_whichplan = whichplan;
164
165                 return TRUE;
166         }
167 }
168
169 /* ----------------------------------------------------------------
170  *              ExecInitAppend
171  *
172  *              Begins all of the subscans of the append node, storing the
173  *              scan structures in the 'initialized' vector of the append-state
174  *              structure.
175  *
176  *         (This is potentially wasteful, since the entire result of the
177  *              append node may not be scanned, but this way all of the
178  *              structures get allocated in the executor's top level memory
179  *              block instead of that of the call to ExecProcAppend.)
180  *
181  *              Returns the scan result of the first scan.
182  * ----------------------------------------------------------------
183  */
184 bool
185 ExecInitAppend(Append *node, EState *estate, Plan *parent)
186 {
187         AppendState *appendstate;
188         int                     nplans;
189         List       *resultList = NULL;
190         List       *rtable;
191         List       *appendplans;
192         bool       *initialized;
193         int                     i;
194         Plan       *initNode;
195         List       *junkList;
196         RelationInfo *es_rri = estate->es_result_relation_info;
197
198         /* ----------------
199          *      assign execution state to node and get information
200          *      for append state
201          * ----------------
202          */
203         node->plan.state = estate;
204
205         appendplans = node->appendplans;
206         nplans = length(appendplans);
207         rtable = node->inheritrtable;
208
209         CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
210         initialized = (bool *) palloc(nplans * sizeof(bool));
211
212         /* ----------------
213          *      create new AppendState for our append node
214          * ----------------
215          */
216         appendstate = makeNode(AppendState);
217         appendstate->as_whichplan = 0;
218         appendstate->as_nplans = nplans;
219         appendstate->as_initialized = initialized;
220         appendstate->as_rtentries = rtable;
221
222         node->appendstate = appendstate;
223
224         /* ----------------
225          *      Miscellanious initialization
226          *
227          *               +      assign node's base_id
228          *               +      assign debugging hooks
229          *
230          *      Append plans don't have expression contexts because they
231          *      never call ExecQual or ExecTargetList.
232          * ----------------
233          */
234         ExecAssignNodeBaseInfo(estate, &appendstate->cstate, parent);
235
236 #define APPEND_NSLOTS 1
237         /* ----------------
238          *      append nodes still have Result slots, which hold pointers
239          *      to tuples, so we have to initialize them..
240          * ----------------
241          */
242         ExecInitResultTupleSlot(estate, &appendstate->cstate);
243
244         /*
245          * If the inherits rtentry is the result relation, we have to make a
246          * result relation info list for all inheritors so we can update their
247          * indices and put the result tuples in the right place etc.
248          *
249          * e.g. replace p (age = p.age + 1) from p in person*
250          */
251         if ((es_rri != (RelationInfo *) NULL) &&
252                 (node->inheritrelid == es_rri->ri_RangeTableIndex))
253         {
254                 RelationInfo *rri;
255                 List       *rtentryP;
256
257                 foreach(rtentryP, rtable)
258                 {
259                         Oid                     reloid;
260                         RangeTblEntry *rtentry = lfirst(rtentryP);
261
262                         reloid = rtentry->relid;
263                         rri = makeNode(RelationInfo);
264                         rri->ri_RangeTableIndex = es_rri->ri_RangeTableIndex;
265                         rri->ri_RelationDesc = heap_open(reloid);
266                         rri->ri_NumIndices = 0;
267                         rri->ri_IndexRelationDescs = NULL;      /* index descs */
268                         rri->ri_IndexRelationInfo = NULL;       /* index key info */
269
270                         resultList = lcons(rri, resultList);
271                         ExecOpenIndices(reloid, rri);
272                 }
273                 appendstate->as_result_relation_info_list = resultList;
274         }
275         /* ----------------
276          *      call ExecInitNode on each of the plans in our list
277          *      and save the results into the array "initialized"
278          * ----------------
279          */
280         junkList = NIL;
281
282         for (i = 0; i < nplans; i++)
283         {
284                 JunkFilter *j;
285                 List       *targetList;
286
287                 /* ----------------
288                  *      NOTE: we first modify range table in
289                  *                exec_append_initialize_next() and
290                  *                then initialize the subnode,
291                  *                since it may use the range table.
292                  * ----------------
293                  */
294                 appendstate->as_whichplan = i;
295                 exec_append_initialize_next(node);
296
297                 initNode = (Plan *) nth(i, appendplans);
298                 initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
299
300                 /* ---------------
301                  *      Each targetlist in the subplan may need its own junk filter
302                  *
303                  *      This is true only when the reln being replaced/deleted is
304                  *      the one that we're looking at the subclasses of
305                  * ---------------
306                  */
307                 if ((es_rri != (RelationInfo *) NULL) &&
308                         (node->inheritrelid == es_rri->ri_RangeTableIndex))
309                 {
310
311                         targetList = initNode->targetlist;
312                         j = (JunkFilter *) ExecInitJunkFilter(targetList);
313                         junkList = lappend(junkList, j);
314                 }
315
316         }
317         appendstate->as_junkFilter_list = junkList;
318         if (junkList != NIL)
319                 estate->es_junkFilter = (JunkFilter *) lfirst(junkList);
320
321         /* ----------------
322          *      initialize the return type from the appropriate subplan.
323          * ----------------
324          */
325         initNode = (Plan *) nth(0, appendplans);
326         ExecAssignResultType(&appendstate->cstate,
327 /*                                               ExecGetExecTupDesc(initNode), */
328                                                  ExecGetTupType(initNode));
329         appendstate->cstate.cs_ProjInfo = NULL;
330
331         /* ----------------
332          *      return the result from the first subplan's initialization
333          * ----------------
334          */
335         appendstate->as_whichplan = 0;
336         exec_append_initialize_next(node);
337 #if 0
338         result = (List *) initialized[0];
339 #endif
340         return TRUE;
341 }
342
343 int
344 ExecCountSlotsAppend(Append *node)
345 {
346         List       *plan;
347         List       *appendplans = node->appendplans;
348         int                     nSlots = 0;
349
350         foreach(plan, appendplans)
351                 nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
352         return nSlots + APPEND_NSLOTS;
353 }
354
355 /* ----------------------------------------------------------------
356  *         ExecProcAppend
357  *
358  *              Handles the iteration over the multiple scans.
359  *
360  *         NOTE: Can't call this ExecAppend, that name is used in execMain.l
361  * ----------------------------------------------------------------
362  */
363 TupleTableSlot *
364 ExecProcAppend(Append *node)
365 {
366         EState     *estate;
367         AppendState *appendstate;
368
369         int                     whichplan;
370         List       *appendplans;
371         Plan       *subnode;
372         TupleTableSlot *result;
373         TupleTableSlot *result_slot;
374         ScanDirection direction;
375
376         /* ----------------
377          *      get information from the node
378          * ----------------
379          */
380         appendstate = node->appendstate;
381         estate = node->plan.state;
382         direction = estate->es_direction;
383
384         appendplans = node->appendplans;
385         whichplan = appendstate->as_whichplan;
386         result_slot = appendstate->cstate.cs_ResultTupleSlot;
387
388         /* ----------------
389          *      figure out which subplan we are currently processing
390          * ----------------
391          */
392         subnode = (Plan *) nth(whichplan, appendplans);
393
394         if (subnode == NULL)
395                 elog(DEBUG, "ExecProcAppend: subnode is NULL");
396
397         /* ----------------
398          *      get a tuple from the subplan
399          * ----------------
400          */
401         result = ExecProcNode(subnode, (Plan *) node);
402
403         if (!TupIsNull(result))
404         {
405                 /* ----------------
406                  *      if the subplan gave us something then place a copy of
407                  *      whatever we get into our result slot and return it, else..
408                  * ----------------
409                  */
410                 return ExecStoreTuple(result->val,
411                                                           result_slot, result->ttc_buffer, false);
412
413         }
414         else
415         {
416                 /* ----------------
417                  *      .. go on to the "next" subplan in the appropriate
418                  *      direction and try processing again (recursively)
419                  * ----------------
420                  */
421                 whichplan = appendstate->as_whichplan;
422
423                 if (ScanDirectionIsForward(direction))
424                         appendstate->as_whichplan = whichplan + 1;
425                 else
426                         appendstate->as_whichplan = whichplan - 1;
427
428                 /* ----------------
429                  *      return something from next node or an empty slot
430                  *      all of our subplans have been exhausted.
431                  * ----------------
432                  */
433                 if (exec_append_initialize_next(node))
434                 {
435                         ExecSetSlotDescriptorIsNew(result_slot, true);
436                         return ExecProcAppend(node);
437                 }
438                 else
439                         return ExecClearTuple(result_slot);
440         }
441 }
442
443 /* ----------------------------------------------------------------
444  *              ExecEndAppend
445  *
446  *              Shuts down the subscans of the append node.
447  *
448  *              Returns nothing of interest.
449  * ----------------------------------------------------------------
450  */
451 void
452 ExecEndAppend(Append *node)
453 {
454         AppendState *appendstate;
455         int                     nplans;
456         List       *appendplans;
457         bool       *initialized;
458         int                     i;
459         List       *resultRelationInfoList;
460         RelationInfo *resultRelationInfo;
461
462         /* ----------------
463          *      get information from the node
464          * ----------------
465          */
466         appendstate = node->appendstate;
467         appendplans = node->appendplans;
468         nplans = appendstate->as_nplans;
469         initialized = appendstate->as_initialized;
470
471         /* ----------------
472          *      shut down each of the subscans
473          * ----------------
474          */
475         for (i = 0; i < nplans; i++)
476         {
477                 if (initialized[i] == TRUE)
478                         ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
479         }
480
481         /* ----------------
482          *      close out the different result relations
483          * ----------------
484          */
485         resultRelationInfoList = appendstate->as_result_relation_info_list;
486         while (resultRelationInfoList != NIL)
487         {
488                 Relation        resultRelationDesc;
489
490                 resultRelationInfo = (RelationInfo *) lfirst(resultRelationInfoList);
491                 resultRelationDesc = resultRelationInfo->ri_RelationDesc;
492                 heap_close(resultRelationDesc);
493                 pfree(resultRelationInfo);
494                 resultRelationInfoList = lnext(resultRelationInfoList);
495         }
496         if (appendstate->as_result_relation_info_list)
497                 pfree(appendstate->as_result_relation_info_list);
498
499         /*
500          * XXX should free appendstate->as_rtentries  and
501          * appendstate->as_junkfilter_list here
502          */
503 }
504 void
505 ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
506 {
507         AppendState *appendstate = node->appendstate;
508         int                     nplans = length(node->appendplans);
509         int                     i;
510
511         for (i = 0; i < nplans; i++)
512         {
513                 Plan       *rescanNode;
514
515                 appendstate->as_whichplan = i;
516                 rescanNode = (Plan *) nth(i, node->appendplans);
517                 if (rescanNode->chgParam == NULL)
518                 {
519                         exec_append_initialize_next(node);
520                         ExecReScan((Plan *) rescanNode, exprCtxt, (Plan *) node);
521                 }
522         }
523         appendstate->as_whichplan = 0;
524         exec_append_initialize_next(node);
525 }