Header And Logo

PostgreSQL
| The world's most advanced open source database.

nodeAppend.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeAppend.c
00004  *    routines to handle append nodes.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/executor/nodeAppend.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 /* INTERFACE ROUTINES
00016  *      ExecInitAppend  - initialize the append node
00017  *      ExecAppend      - retrieve the next tuple from the node
00018  *      ExecEndAppend   - shut down the append node
00019  *      ExecReScanAppend - rescan the append node
00020  *
00021  *   NOTES
00022  *      Each append node contains a list of one or more subplans which
00023  *      must be iteratively processed (forwards or backwards).
00024  *      Tuples are retrieved by executing the 'whichplan'th subplan
00025  *      until the subplan stops returning tuples, at which point that
00026  *      plan is shut down and the next started up.
00027  *
00028  *      Append nodes don't make use of their left and right
00029  *      subtrees, rather they maintain a list of subplans so
00030  *      a typical append node looks like this in the plan tree:
00031  *
00032  *                 ...
00033  *                 /
00034  *              Append -------+------+------+--- nil
00035  *              /   \         |      |      |
00036  *            nil   nil      ...    ...    ...
00037  *                               subplans
00038  *
00039  *      Append nodes are currently used for unions, and to support
00040  *      inheritance queries, where several relations need to be scanned.
00041  *      For example, in our standard person/student/employee/student-emp
00042  *      example, where student and employee inherit from person
00043  *      and student-emp inherits from student and employee, the
00044  *      query:
00045  *
00046  *              select name from person
00047  *
00048  *      generates the plan:
00049  *
00050  *                |
00051  *              Append -------+-------+--------+--------+
00052  *              /   \         |       |        |        |
00053  *            nil   nil      Scan    Scan     Scan     Scan
00054  *                            |       |        |        |
00055  *                          person employee student student-emp
00056  */
00057 
00058 #include "postgres.h"
00059 
00060 #include "executor/execdebug.h"
00061 #include "executor/nodeAppend.h"
00062 
00063 static bool exec_append_initialize_next(AppendState *appendstate);
00064 
00065 
00066 /* ----------------------------------------------------------------
00067  *      exec_append_initialize_next
00068  *
00069  *      Sets up the append state node for the "next" scan.
00070  *
00071  *      Returns t iff there is a "next" scan to process.
00072  * ----------------------------------------------------------------
00073  */
00074 static bool
00075 exec_append_initialize_next(AppendState *appendstate)
00076 {
00077     int         whichplan;
00078 
00079     /*
00080      * get information from the append node
00081      */
00082     whichplan = appendstate->as_whichplan;
00083 
00084     if (whichplan < 0)
00085     {
00086         /*
00087          * if scanning in reverse, we start at the last scan in the list and
00088          * then proceed back to the first.. in any case we inform ExecAppend
00089          * that we are at the end of the line by returning FALSE
00090          */
00091         appendstate->as_whichplan = 0;
00092         return FALSE;
00093     }
00094     else if (whichplan >= appendstate->as_nplans)
00095     {
00096         /*
00097          * as above, end the scan if we go beyond the last scan in our list..
00098          */
00099         appendstate->as_whichplan = appendstate->as_nplans - 1;
00100         return FALSE;
00101     }
00102     else
00103     {
00104         return TRUE;
00105     }
00106 }
00107 
00108 /* ----------------------------------------------------------------
00109  *      ExecInitAppend
00110  *
00111  *      Begin all of the subscans of the append node.
00112  *
00113  *     (This is potentially wasteful, since the entire result of the
00114  *      append node may not be scanned, but this way all of the
00115  *      structures get allocated in the executor's top level memory
00116  *      block instead of that of the call to ExecAppend.)
00117  * ----------------------------------------------------------------
00118  */
00119 AppendState *
00120 ExecInitAppend(Append *node, EState *estate, int eflags)
00121 {
00122     AppendState *appendstate = makeNode(AppendState);
00123     PlanState **appendplanstates;
00124     int         nplans;
00125     int         i;
00126     ListCell   *lc;
00127 
00128     /* check for unsupported flags */
00129     Assert(!(eflags & EXEC_FLAG_MARK));
00130 
00131     /*
00132      * Set up empty vector of subplan states
00133      */
00134     nplans = list_length(node->appendplans);
00135 
00136     appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
00137 
00138     /*
00139      * create new AppendState for our append node
00140      */
00141     appendstate->ps.plan = (Plan *) node;
00142     appendstate->ps.state = estate;
00143     appendstate->appendplans = appendplanstates;
00144     appendstate->as_nplans = nplans;
00145 
00146     /*
00147      * Miscellaneous initialization
00148      *
00149      * Append plans don't have expression contexts because they never call
00150      * ExecQual or ExecProject.
00151      */
00152 
00153     /*
00154      * append nodes still have Result slots, which hold pointers to tuples, so
00155      * we have to initialize them.
00156      */
00157     ExecInitResultTupleSlot(estate, &appendstate->ps);
00158 
00159     /*
00160      * call ExecInitNode on each of the plans to be executed and save the
00161      * results into the array "appendplans".
00162      */
00163     i = 0;
00164     foreach(lc, node->appendplans)
00165     {
00166         Plan       *initNode = (Plan *) lfirst(lc);
00167 
00168         appendplanstates[i] = ExecInitNode(initNode, estate, eflags);
00169         i++;
00170     }
00171 
00172     /*
00173      * initialize output tuple type
00174      */
00175     ExecAssignResultTypeFromTL(&appendstate->ps);
00176     appendstate->ps.ps_ProjInfo = NULL;
00177 
00178     /*
00179      * initialize to scan first subplan
00180      */
00181     appendstate->as_whichplan = 0;
00182     exec_append_initialize_next(appendstate);
00183 
00184     return appendstate;
00185 }
00186 
00187 /* ----------------------------------------------------------------
00188  *     ExecAppend
00189  *
00190  *      Handles iteration over multiple subplans.
00191  * ----------------------------------------------------------------
00192  */
00193 TupleTableSlot *
00194 ExecAppend(AppendState *node)
00195 {
00196     for (;;)
00197     {
00198         PlanState  *subnode;
00199         TupleTableSlot *result;
00200 
00201         /*
00202          * figure out which subplan we are currently processing
00203          */
00204         subnode = node->appendplans[node->as_whichplan];
00205 
00206         /*
00207          * get a tuple from the subplan
00208          */
00209         result = ExecProcNode(subnode);
00210 
00211         if (!TupIsNull(result))
00212         {
00213             /*
00214              * If the subplan gave us something then return it as-is. We do
00215              * NOT make use of the result slot that was set up in
00216              * ExecInitAppend; there's no need for it.
00217              */
00218             return result;
00219         }
00220 
00221         /*
00222          * Go on to the "next" subplan in the appropriate direction. If no
00223          * more subplans, return the empty slot set up for us by
00224          * ExecInitAppend.
00225          */
00226         if (ScanDirectionIsForward(node->ps.state->es_direction))
00227             node->as_whichplan++;
00228         else
00229             node->as_whichplan--;
00230         if (!exec_append_initialize_next(node))
00231             return ExecClearTuple(node->ps.ps_ResultTupleSlot);
00232 
00233         /* Else loop back and try to get a tuple from the new subplan */
00234     }
00235 }
00236 
00237 /* ----------------------------------------------------------------
00238  *      ExecEndAppend
00239  *
00240  *      Shuts down the subscans of the append node.
00241  *
00242  *      Returns nothing of interest.
00243  * ----------------------------------------------------------------
00244  */
00245 void
00246 ExecEndAppend(AppendState *node)
00247 {
00248     PlanState **appendplans;
00249     int         nplans;
00250     int         i;
00251 
00252     /*
00253      * get information from the node
00254      */
00255     appendplans = node->appendplans;
00256     nplans = node->as_nplans;
00257 
00258     /*
00259      * shut down each of the subscans
00260      */
00261     for (i = 0; i < nplans; i++)
00262         ExecEndNode(appendplans[i]);
00263 }
00264 
00265 void
00266 ExecReScanAppend(AppendState *node)
00267 {
00268     int         i;
00269 
00270     for (i = 0; i < node->as_nplans; i++)
00271     {
00272         PlanState  *subnode = node->appendplans[i];
00273 
00274         /*
00275          * ExecReScan doesn't know about my subplans, so I have to do
00276          * changed-parameter signaling myself.
00277          */
00278         if (node->ps.chgParam != NULL)
00279             UpdateChangedParamSet(subnode, node->ps.chgParam);
00280 
00281         /*
00282          * If chgParam of subnode is not null then plan will be re-scanned by
00283          * first ExecProcNode.
00284          */
00285         if (subnode->chgParam == NULL)
00286             ExecReScan(subnode);
00287     }
00288     node->as_whichplan = 0;
00289     exec_append_initialize_next(node);
00290 }