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

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeGroup.c
       4             :  *    Routines to handle group nodes (used for queries with GROUP BY clause).
       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             :  * DESCRIPTION
      11             :  *    The Group node is designed for handling queries with a GROUP BY clause.
      12             :  *    Its outer plan must deliver tuples that are sorted in the order
      13             :  *    specified by the grouping columns (ie. tuples from the same group are
      14             :  *    consecutive).  That way, we just have to compare adjacent tuples to
      15             :  *    locate group boundaries.
      16             :  *
      17             :  * IDENTIFICATION
      18             :  *    src/backend/executor/nodeGroup.c
      19             :  *
      20             :  *-------------------------------------------------------------------------
      21             :  */
      22             : 
      23             : #include "postgres.h"
      24             : 
      25             : #include "executor/executor.h"
      26             : #include "executor/nodeGroup.h"
      27             : #include "miscadmin.h"
      28             : 
      29             : 
      30             : /*
      31             :  *   ExecGroup -
      32             :  *
      33             :  *      Return one tuple for each group of matching input tuples.
      34             :  */
      35             : static TupleTableSlot *
      36         914 : ExecGroup(PlanState *pstate)
      37             : {
      38         914 :     GroupState *node = castNode(GroupState, pstate);
      39             :     ExprContext *econtext;
      40             :     int         numCols;
      41             :     AttrNumber *grpColIdx;
      42             :     TupleTableSlot *firsttupleslot;
      43             :     TupleTableSlot *outerslot;
      44             : 
      45         914 :     CHECK_FOR_INTERRUPTS();
      46             : 
      47             :     /*
      48             :      * get state info from node
      49             :      */
      50         914 :     if (node->grp_done)
      51           0 :         return NULL;
      52         914 :     econtext = node->ss.ps.ps_ExprContext;
      53         914 :     numCols = ((Group *) node->ss.ps.plan)->numCols;
      54         914 :     grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
      55             : 
      56             :     /*
      57             :      * The ScanTupleSlot holds the (copied) first tuple of each group.
      58             :      */
      59         914 :     firsttupleslot = node->ss.ss_ScanTupleSlot;
      60             : 
      61             :     /*
      62             :      * We need not call ResetExprContext here because execTuplesMatch will
      63             :      * reset the per-tuple memory context once per input tuple.
      64             :      */
      65             : 
      66             :     /*
      67             :      * If first time through, acquire first input tuple and determine whether
      68             :      * to return it or not.
      69             :      */
      70         914 :     if (TupIsNull(firsttupleslot))
      71             :     {
      72          11 :         outerslot = ExecProcNode(outerPlanState(node));
      73          11 :         if (TupIsNull(outerslot))
      74             :         {
      75             :             /* empty input, so return nothing */
      76           3 :             node->grp_done = TRUE;
      77           3 :             return NULL;
      78             :         }
      79             :         /* Copy tuple into firsttupleslot */
      80           8 :         ExecCopySlot(firsttupleslot, outerslot);
      81             : 
      82             :         /*
      83             :          * Set it up as input for qual test and projection.  The expressions
      84             :          * will access the input tuple as varno OUTER.
      85             :          */
      86           8 :         econtext->ecxt_outertuple = firsttupleslot;
      87             : 
      88             :         /*
      89             :          * Check the qual (HAVING clause); if the group does not match, ignore
      90             :          * it and fall into scan loop.
      91             :          */
      92           8 :         if (ExecQual(node->ss.ps.qual, econtext))
      93             :         {
      94             :             /*
      95             :              * Form and return a projection tuple using the first input tuple.
      96             :              */
      97           8 :             return ExecProject(node->ss.ps.ps_ProjInfo);
      98             :         }
      99             :         else
     100           0 :             InstrCountFiltered1(node, 1);
     101             :     }
     102             : 
     103             :     /*
     104             :      * This loop iterates once per input tuple group.  At the head of the
     105             :      * loop, we have finished processing the first tuple of the group and now
     106             :      * need to scan over all the other group members.
     107             :      */
     108             :     for (;;)
     109             :     {
     110             :         /*
     111             :          * Scan over all remaining tuples that belong to this group
     112             :          */
     113             :         for (;;)
     114             :         {
     115        2034 :             outerslot = ExecProcNode(outerPlanState(node));
     116        2034 :             if (TupIsNull(outerslot))
     117             :             {
     118             :                 /* no more groups, so we're done */
     119           8 :                 node->grp_done = TRUE;
     120           8 :                 return NULL;
     121             :             }
     122             : 
     123             :             /*
     124             :              * Compare with first tuple and see if this tuple is of the same
     125             :              * group.  If so, ignore it and keep scanning.
     126             :              */
     127        2026 :             if (!execTuplesMatch(firsttupleslot, outerslot,
     128             :                                  numCols, grpColIdx,
     129             :                                  node->eqfunctions,
     130             :                                  econtext->ecxt_per_tuple_memory))
     131         895 :                 break;
     132        1131 :         }
     133             : 
     134             :         /*
     135             :          * We have the first tuple of the next input group.  See if we want to
     136             :          * return it.
     137             :          */
     138             :         /* Copy tuple, set up as input for qual test and projection */
     139         895 :         ExecCopySlot(firsttupleslot, outerslot);
     140         895 :         econtext->ecxt_outertuple = firsttupleslot;
     141             : 
     142             :         /*
     143             :          * Check the qual (HAVING clause); if the group does not match, ignore
     144             :          * it and loop back to scan the rest of the group.
     145             :          */
     146         895 :         if (ExecQual(node->ss.ps.qual, econtext))
     147             :         {
     148             :             /*
     149             :              * Form and return a projection tuple using the first input tuple.
     150             :              */
     151         895 :             return ExecProject(node->ss.ps.ps_ProjInfo);
     152             :         }
     153             :         else
     154           0 :             InstrCountFiltered1(node, 1);
     155           0 :     }
     156             : }
     157             : 
     158             : /* -----------------
     159             :  * ExecInitGroup
     160             :  *
     161             :  *  Creates the run-time information for the group node produced by the
     162             :  *  planner and initializes its outer subtree
     163             :  * -----------------
     164             :  */
     165             : GroupState *
     166          11 : ExecInitGroup(Group *node, EState *estate, int eflags)
     167             : {
     168             :     GroupState *grpstate;
     169             : 
     170             :     /* check for unsupported flags */
     171          11 :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     172             : 
     173             :     /*
     174             :      * create state structure
     175             :      */
     176          11 :     grpstate = makeNode(GroupState);
     177          11 :     grpstate->ss.ps.plan = (Plan *) node;
     178          11 :     grpstate->ss.ps.state = estate;
     179          11 :     grpstate->ss.ps.ExecProcNode = ExecGroup;
     180          11 :     grpstate->grp_done = FALSE;
     181             : 
     182             :     /*
     183             :      * create expression context
     184             :      */
     185          11 :     ExecAssignExprContext(estate, &grpstate->ss.ps);
     186             : 
     187             :     /*
     188             :      * tuple table initialization
     189             :      */
     190          11 :     ExecInitScanTupleSlot(estate, &grpstate->ss);
     191          11 :     ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
     192             : 
     193             :     /*
     194             :      * initialize child expressions
     195             :      */
     196          11 :     grpstate->ss.ps.qual =
     197          11 :         ExecInitQual(node->plan.qual, (PlanState *) grpstate);
     198             : 
     199             :     /*
     200             :      * initialize child nodes
     201             :      */
     202          11 :     outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
     203             : 
     204             :     /*
     205             :      * initialize tuple type.
     206             :      */
     207          11 :     ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
     208             : 
     209             :     /*
     210             :      * Initialize result tuple type and projection info.
     211             :      */
     212          11 :     ExecAssignResultTypeFromTL(&grpstate->ss.ps);
     213          11 :     ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
     214             : 
     215             :     /*
     216             :      * Precompute fmgr lookup data for inner loop
     217             :      */
     218          11 :     grpstate->eqfunctions =
     219          11 :         execTuplesMatchPrepare(node->numCols,
     220             :                                node->grpOperators);
     221             : 
     222          11 :     return grpstate;
     223             : }
     224             : 
     225             : /* ------------------------
     226             :  *      ExecEndGroup(node)
     227             :  *
     228             :  * -----------------------
     229             :  */
     230             : void
     231          11 : ExecEndGroup(GroupState *node)
     232             : {
     233             :     PlanState  *outerPlan;
     234             : 
     235          11 :     ExecFreeExprContext(&node->ss.ps);
     236             : 
     237             :     /* clean up tuple table */
     238          11 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     239             : 
     240          11 :     outerPlan = outerPlanState(node);
     241          11 :     ExecEndNode(outerPlan);
     242          11 : }
     243             : 
     244             : void
     245           3 : ExecReScanGroup(GroupState *node)
     246             : {
     247           3 :     PlanState  *outerPlan = outerPlanState(node);
     248             : 
     249           3 :     node->grp_done = FALSE;
     250             :     /* must clear first tuple */
     251           3 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     252             : 
     253             :     /*
     254             :      * if chgParam of subnode is not null then plan will be re-scanned by
     255             :      * first ExecProcNode.
     256             :      */
     257           3 :     if (outerPlan->chgParam == NULL)
     258           3 :         ExecReScan(outerPlan);
     259           3 : }

Generated by: LCOV version 1.11