Header And Logo

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

nodeGroup.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeGroup.c
00004  *    Routines to handle group nodes (used for queries with GROUP BY clause).
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  * DESCRIPTION
00011  *    The Group node is designed for handling queries with a GROUP BY clause.
00012  *    Its outer plan must deliver tuples that are sorted in the order
00013  *    specified by the grouping columns (ie. tuples from the same group are
00014  *    consecutive).  That way, we just have to compare adjacent tuples to
00015  *    locate group boundaries.
00016  *
00017  * IDENTIFICATION
00018  *    src/backend/executor/nodeGroup.c
00019  *
00020  *-------------------------------------------------------------------------
00021  */
00022 
00023 #include "postgres.h"
00024 
00025 #include "executor/executor.h"
00026 #include "executor/nodeGroup.h"
00027 
00028 
00029 /*
00030  *   ExecGroup -
00031  *
00032  *      Return one tuple for each group of matching input tuples.
00033  */
00034 TupleTableSlot *
00035 ExecGroup(GroupState *node)
00036 {
00037     ExprContext *econtext;
00038     int         numCols;
00039     AttrNumber *grpColIdx;
00040     TupleTableSlot *firsttupleslot;
00041     TupleTableSlot *outerslot;
00042 
00043     /*
00044      * get state info from node
00045      */
00046     if (node->grp_done)
00047         return NULL;
00048     econtext = node->ss.ps.ps_ExprContext;
00049     numCols = ((Group *) node->ss.ps.plan)->numCols;
00050     grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
00051 
00052     /*
00053      * Check to see if we're still projecting out tuples from a previous group
00054      * tuple (because there is a function-returning-set in the projection
00055      * expressions).  If so, try to project another one.
00056      */
00057     if (node->ss.ps.ps_TupFromTlist)
00058     {
00059         TupleTableSlot *result;
00060         ExprDoneCond isDone;
00061 
00062         result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
00063         if (isDone == ExprMultipleResult)
00064             return result;
00065         /* Done with that source tuple... */
00066         node->ss.ps.ps_TupFromTlist = false;
00067     }
00068 
00069     /*
00070      * The ScanTupleSlot holds the (copied) first tuple of each group.
00071      */
00072     firsttupleslot = node->ss.ss_ScanTupleSlot;
00073 
00074     /*
00075      * We need not call ResetExprContext here because execTuplesMatch will
00076      * reset the per-tuple memory context once per input tuple.
00077      */
00078 
00079     /*
00080      * If first time through, acquire first input tuple and determine whether
00081      * to return it or not.
00082      */
00083     if (TupIsNull(firsttupleslot))
00084     {
00085         outerslot = ExecProcNode(outerPlanState(node));
00086         if (TupIsNull(outerslot))
00087         {
00088             /* empty input, so return nothing */
00089             node->grp_done = TRUE;
00090             return NULL;
00091         }
00092         /* Copy tuple into firsttupleslot */
00093         ExecCopySlot(firsttupleslot, outerslot);
00094 
00095         /*
00096          * Set it up as input for qual test and projection.  The expressions
00097          * will access the input tuple as varno OUTER.
00098          */
00099         econtext->ecxt_outertuple = firsttupleslot;
00100 
00101         /*
00102          * Check the qual (HAVING clause); if the group does not match, ignore
00103          * it and fall into scan loop.
00104          */
00105         if (ExecQual(node->ss.ps.qual, econtext, false))
00106         {
00107             /*
00108              * Form and return a projection tuple using the first input tuple.
00109              */
00110             TupleTableSlot *result;
00111             ExprDoneCond isDone;
00112 
00113             result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
00114 
00115             if (isDone != ExprEndResult)
00116             {
00117                 node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
00118                 return result;
00119             }
00120         }
00121         else
00122             InstrCountFiltered1(node, 1);
00123     }
00124 
00125     /*
00126      * This loop iterates once per input tuple group.  At the head of the
00127      * loop, we have finished processing the first tuple of the group and now
00128      * need to scan over all the other group members.
00129      */
00130     for (;;)
00131     {
00132         /*
00133          * Scan over all remaining tuples that belong to this group
00134          */
00135         for (;;)
00136         {
00137             outerslot = ExecProcNode(outerPlanState(node));
00138             if (TupIsNull(outerslot))
00139             {
00140                 /* no more groups, so we're done */
00141                 node->grp_done = TRUE;
00142                 return NULL;
00143             }
00144 
00145             /*
00146              * Compare with first tuple and see if this tuple is of the same
00147              * group.  If so, ignore it and keep scanning.
00148              */
00149             if (!execTuplesMatch(firsttupleslot, outerslot,
00150                                  numCols, grpColIdx,
00151                                  node->eqfunctions,
00152                                  econtext->ecxt_per_tuple_memory))
00153                 break;
00154         }
00155 
00156         /*
00157          * We have the first tuple of the next input group.  See if we want to
00158          * return it.
00159          */
00160         /* Copy tuple, set up as input for qual test and projection */
00161         ExecCopySlot(firsttupleslot, outerslot);
00162         econtext->ecxt_outertuple = firsttupleslot;
00163 
00164         /*
00165          * Check the qual (HAVING clause); if the group does not match, ignore
00166          * it and loop back to scan the rest of the group.
00167          */
00168         if (ExecQual(node->ss.ps.qual, econtext, false))
00169         {
00170             /*
00171              * Form and return a projection tuple using the first input tuple.
00172              */
00173             TupleTableSlot *result;
00174             ExprDoneCond isDone;
00175 
00176             result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
00177 
00178             if (isDone != ExprEndResult)
00179             {
00180                 node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
00181                 return result;
00182             }
00183         }
00184         else
00185             InstrCountFiltered1(node, 1);
00186     }
00187 }
00188 
00189 /* -----------------
00190  * ExecInitGroup
00191  *
00192  *  Creates the run-time information for the group node produced by the
00193  *  planner and initializes its outer subtree
00194  * -----------------
00195  */
00196 GroupState *
00197 ExecInitGroup(Group *node, EState *estate, int eflags)
00198 {
00199     GroupState *grpstate;
00200 
00201     /* check for unsupported flags */
00202     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
00203 
00204     /*
00205      * create state structure
00206      */
00207     grpstate = makeNode(GroupState);
00208     grpstate->ss.ps.plan = (Plan *) node;
00209     grpstate->ss.ps.state = estate;
00210     grpstate->grp_done = FALSE;
00211 
00212     /*
00213      * create expression context
00214      */
00215     ExecAssignExprContext(estate, &grpstate->ss.ps);
00216 
00217     /*
00218      * tuple table initialization
00219      */
00220     ExecInitScanTupleSlot(estate, &grpstate->ss);
00221     ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
00222 
00223     /*
00224      * initialize child expressions
00225      */
00226     grpstate->ss.ps.targetlist = (List *)
00227         ExecInitExpr((Expr *) node->plan.targetlist,
00228                      (PlanState *) grpstate);
00229     grpstate->ss.ps.qual = (List *)
00230         ExecInitExpr((Expr *) node->plan.qual,
00231                      (PlanState *) grpstate);
00232 
00233     /*
00234      * initialize child nodes
00235      */
00236     outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
00237 
00238     /*
00239      * initialize tuple type.
00240      */
00241     ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
00242 
00243     /*
00244      * Initialize result tuple type and projection info.
00245      */
00246     ExecAssignResultTypeFromTL(&grpstate->ss.ps);
00247     ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
00248 
00249     grpstate->ss.ps.ps_TupFromTlist = false;
00250 
00251     /*
00252      * Precompute fmgr lookup data for inner loop
00253      */
00254     grpstate->eqfunctions =
00255         execTuplesMatchPrepare(node->numCols,
00256                                node->grpOperators);
00257 
00258     return grpstate;
00259 }
00260 
00261 /* ------------------------
00262  *      ExecEndGroup(node)
00263  *
00264  * -----------------------
00265  */
00266 void
00267 ExecEndGroup(GroupState *node)
00268 {
00269     PlanState  *outerPlan;
00270 
00271     ExecFreeExprContext(&node->ss.ps);
00272 
00273     /* clean up tuple table */
00274     ExecClearTuple(node->ss.ss_ScanTupleSlot);
00275 
00276     outerPlan = outerPlanState(node);
00277     ExecEndNode(outerPlan);
00278 }
00279 
00280 void
00281 ExecReScanGroup(GroupState *node)
00282 {
00283     node->grp_done = FALSE;
00284     node->ss.ps.ps_TupFromTlist = false;
00285     /* must clear first tuple */
00286     ExecClearTuple(node->ss.ss_ScanTupleSlot);
00287 
00288     /*
00289      * if chgParam of subnode is not null then plan will be re-scanned by
00290      * first ExecProcNode.
00291      */
00292     if (node->ss.ps.lefttree &&
00293         node->ss.ps.lefttree->chgParam == NULL)
00294         ExecReScan(node->ss.ps.lefttree);
00295 }