LCOV - code coverage report
Current view: top level - src/backend/executor - nodeAppend.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 57 60 95.0 %
Date: 2017-09-29 15:12:54 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.11