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

Generated by: LCOV version 1.13