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