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

Generated by: LCOV version 1.14