]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeGroup.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeGroup.c
index 6d824421d3305b8a527b4e8a847e2bb500e1221b..655084d7b564858b1a447b79be6905acd9352bf6 100644 (file)
@@ -3,7 +3,7 @@
  * nodeGroup.c
  *       Routines to handle group nodes (used for queries with GROUP BY clause).
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  *       locate group boundaries.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.64 2006/03/05 15:58:26 momjian Exp $
+ *       src/backend/executor/nodeGroup.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
-#include "access/heapam.h"
 #include "executor/executor.h"
 #include "executor/nodeGroup.h"
+#include "miscadmin.h"
+#include "utils/memutils.h"
 
 
 /*
  *
  *             Return one tuple for each group of matching input tuples.
  */
-TupleTableSlot *
-ExecGroup(GroupState *node)
+static TupleTableSlot *
+ExecGroup(PlanState *pstate)
 {
+       GroupState *node = castNode(GroupState, pstate);
        ExprContext *econtext;
-       int                     numCols;
-       AttrNumber *grpColIdx;
        TupleTableSlot *firsttupleslot;
        TupleTableSlot *outerslot;
 
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * get state info from node
         */
        if (node->grp_done)
                return NULL;
        econtext = node->ss.ps.ps_ExprContext;
-       numCols = ((Group *) node->ss.ps.plan)->numCols;
-       grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
 
        /*
         * The ScanTupleSlot holds the (copied) first tuple of each group.
@@ -56,7 +56,7 @@ ExecGroup(GroupState *node)
        firsttupleslot = node->ss.ss_ScanTupleSlot;
 
        /*
-        * We need not call ResetExprContext here because execTuplesMatch will
+        * We need not call ResetExprContext here because ExecQualAndReset() will
         * reset the per-tuple memory context once per input tuple.
         */
 
@@ -70,24 +70,31 @@ ExecGroup(GroupState *node)
                if (TupIsNull(outerslot))
                {
                        /* empty input, so return nothing */
-                       node->grp_done = TRUE;
+                       node->grp_done = true;
                        return NULL;
                }
-               /* Copy tuple, set up as input for qual test and projection */
+               /* Copy tuple into firsttupleslot */
                ExecCopySlot(firsttupleslot, outerslot);
-               econtext->ecxt_scantuple = firsttupleslot;
+
+               /*
+                * Set it up as input for qual test and projection.  The expressions
+                * will access the input tuple as varno OUTER.
+                */
+               econtext->ecxt_outertuple = firsttupleslot;
 
                /*
                 * Check the qual (HAVING clause); if the group does not match, ignore
                 * it and fall into scan loop.
                 */
-               if (ExecQual(node->ss.ps.qual, econtext, false))
+               if (ExecQual(node->ss.ps.qual, econtext))
                {
                        /*
                         * Form and return a projection tuple using the first input tuple.
                         */
-                       return ExecProject(node->ss.ps.ps_ProjInfo, NULL);
+                       return ExecProject(node->ss.ps.ps_ProjInfo);
                }
+               else
+                       InstrCountFiltered1(node, 1);
        }
 
        /*
@@ -106,7 +113,7 @@ ExecGroup(GroupState *node)
                        if (TupIsNull(outerslot))
                        {
                                /* no more groups, so we're done */
-                               node->grp_done = TRUE;
+                               node->grp_done = true;
                                return NULL;
                        }
 
@@ -114,10 +121,9 @@ ExecGroup(GroupState *node)
                         * Compare with first tuple and see if this tuple is of the same
                         * group.  If so, ignore it and keep scanning.
                         */
-                       if (!execTuplesMatch(firsttupleslot, outerslot,
-                                                                numCols, grpColIdx,
-                                                                node->eqfunctions,
-                                                                econtext->ecxt_per_tuple_memory))
+                       econtext->ecxt_innertuple = firsttupleslot;
+                       econtext->ecxt_outertuple = outerslot;
+                       if (!ExecQualAndReset(node->eqfunction, econtext))
                                break;
                }
 
@@ -127,23 +133,22 @@ ExecGroup(GroupState *node)
                 */
                /* Copy tuple, set up as input for qual test and projection */
                ExecCopySlot(firsttupleslot, outerslot);
-               econtext->ecxt_scantuple = firsttupleslot;
+               econtext->ecxt_outertuple = firsttupleslot;
 
                /*
                 * Check the qual (HAVING clause); if the group does not match, ignore
                 * it and loop back to scan the rest of the group.
                 */
-               if (ExecQual(node->ss.ps.qual, econtext, false))
+               if (ExecQual(node->ss.ps.qual, econtext))
                {
                        /*
                         * Form and return a projection tuple using the first input tuple.
                         */
-                       return ExecProject(node->ss.ps.ps_ProjInfo, NULL);
+                       return ExecProject(node->ss.ps.ps_ProjInfo);
                }
+               else
+                       InstrCountFiltered1(node, 1);
        }
-
-       /* NOTREACHED */
-       return NULL;
 }
 
 /* -----------------
@@ -157,6 +162,7 @@ GroupState *
 ExecInitGroup(Group *node, EState *estate, int eflags)
 {
        GroupState *grpstate;
+       const TupleTableSlotOps *tts_ops;
 
        /* check for unsupported flags */
        Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -167,64 +173,50 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
        grpstate = makeNode(GroupState);
        grpstate->ss.ps.plan = (Plan *) node;
        grpstate->ss.ps.state = estate;
-       grpstate->grp_done = FALSE;
+       grpstate->ss.ps.ExecProcNode = ExecGroup;
+       grpstate->grp_done = false;
 
        /*
         * create expression context
         */
        ExecAssignExprContext(estate, &grpstate->ss.ps);
 
-#define GROUP_NSLOTS 2
-
        /*
-        * tuple table initialization
-        */
-       ExecInitScanTupleSlot(estate, &grpstate->ss);
-       ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
-
-       /*
-        * initialize child expressions
+        * initialize child nodes
         */
-       grpstate->ss.ps.targetlist = (List *)
-               ExecInitExpr((Expr *) node->plan.targetlist,
-                                        (PlanState *) grpstate);
-       grpstate->ss.ps.qual = (List *)
-               ExecInitExpr((Expr *) node->plan.qual,
-                                        (PlanState *) grpstate);
+       outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
 
        /*
-        * initialize child nodes
+        * Initialize scan slot and type.
         */
-       outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
+       tts_ops = ExecGetResultSlotOps(outerPlanState(&grpstate->ss), NULL);
+       ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss, tts_ops);
 
        /*
-        * initialize tuple type.
+        * Initialize result slot, type and projection.
         */
-       ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
+       ExecInitResultTupleSlotTL(&grpstate->ss.ps, &TTSOpsVirtual);
+       ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
 
        /*
-        * Initialize result tuple type and projection info.
+        * initialize child expressions
         */
-       ExecAssignResultTypeFromTL(&grpstate->ss.ps);
-       ExecAssignProjectionInfo(&grpstate->ss.ps);
+       grpstate->ss.ps.qual =
+               ExecInitQual(node->plan.qual, (PlanState *) grpstate);
 
        /*
         * Precompute fmgr lookup data for inner loop
         */
-       grpstate->eqfunctions =
-               execTuplesMatchPrepare(ExecGetScanType(&grpstate->ss),
+       grpstate->eqfunction =
+               execTuplesMatchPrepare(ExecGetResultType(outerPlanState(grpstate)),
                                                           node->numCols,
-                                                          node->grpColIdx);
+                                                          node->grpColIdx,
+                                                          node->grpOperators,
+                                                          &grpstate->ss.ps);
 
        return grpstate;
 }
 
-int
-ExecCountSlotsGroup(Group *node)
-{
-       return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
-}
-
 /* ------------------------
  *             ExecEndGroup(node)
  *
@@ -245,13 +237,18 @@ ExecEndGroup(GroupState *node)
 }
 
 void
-ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
+ExecReScanGroup(GroupState *node)
 {
-       node->grp_done = FALSE;
+       PlanState  *outerPlan = outerPlanState(node);
+
+       node->grp_done = false;
        /* must clear first tuple */
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
-       if (((PlanState *) node)->lefttree &&
-               ((PlanState *) node)->lefttree->chgParam == NULL)
-               ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+       /*
+        * if chgParam of subnode is not null then plan will be re-scanned by
+        * first ExecProcNode.
+        */
+       if (outerPlan->chgParam == NULL)
+               ExecReScan(outerPlan);
 }