]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeGroup.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeGroup.c
index ff992e1e8b8b6c091a75498bb9987e2f75e831f2..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-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -15,7 +15,7 @@
  *       locate group boundaries.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.74 2009/04/02 19:14:33 momjian Exp $
+ *       src/backend/executor/nodeGroup.c
  *
  *-------------------------------------------------------------------------
  */
@@ -24,7 +24,8 @@
 
 #include "executor/executor.h"
 #include "executor/nodeGroup.h"
-#include "pg_trace.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;
-
-       TRACE_POSTGRESQL_EXECUTOR_GROUP((uintptr_t)node, numCols);
-
-       /*
-        * Check to see if we're still projecting out tuples from a previous group
-        * tuple (because there is a function-returning-set in the projection
-        * expressions).  If so, try to project another one.
-        */
-       if (node->ss.ps.ps_TupFromTlist)
-       {
-               TupleTableSlot *result;
-               ExprDoneCond isDone;
-
-               result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-               if (isDone == ExprMultipleResult)
-                       return result;
-               /* Done with that source tuple... */
-               node->ss.ps.ps_TupFromTlist = false;
-       }
 
        /*
         * The ScanTupleSlot holds the (copied) first tuple of each group.
@@ -75,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.
         */
 
@@ -89,7 +70,7 @@ ExecGroup(GroupState *node)
                if (TupIsNull(outerslot))
                {
                        /* empty input, so return nothing */
-                       node->grp_done = TRUE;
+                       node->grp_done = true;
                        return NULL;
                }
                /* Copy tuple into firsttupleslot */
@@ -105,22 +86,15 @@ ExecGroup(GroupState *node)
                 * 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.
                         */
-                       TupleTableSlot *result;
-                       ExprDoneCond isDone;
-
-                       result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-
-                       if (isDone != ExprEndResult)
-                       {
-                               node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-                               return result;
-                       }
+                       return ExecProject(node->ss.ps.ps_ProjInfo);
                }
+               else
+                       InstrCountFiltered1(node, 1);
        }
 
        /*
@@ -139,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;
                        }
 
@@ -147,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;
                }
 
@@ -166,26 +139,16 @@ ExecGroup(GroupState *node)
                 * 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.
                         */
-                       TupleTableSlot *result;
-                       ExprDoneCond isDone;
-
-                       result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-
-                       if (isDone != ExprEndResult)
-                       {
-                               node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-                               return result;
-                       }
+                       return ExecProject(node->ss.ps.ps_ProjInfo);
                }
+               else
+                       InstrCountFiltered1(node, 1);
        }
-
-       /* NOTREACHED */
-       return NULL;
 }
 
 /* -----------------
@@ -199,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)));
@@ -209,65 +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
-        */
-       grpstate->ss.ps.targetlist = (List *)
-               ExecInitExpr((Expr *) node->plan.targetlist,
-                                        (PlanState *) grpstate);
-       grpstate->ss.ps.qual = (List *)
-               ExecInitExpr((Expr *) node->plan.qual,
-                                        (PlanState *) grpstate);
-
        /*
         * initialize child nodes
         */
        outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
 
        /*
-        * initialize tuple type.
+        * Initialize scan slot and type.
         */
-       ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
+       tts_ops = ExecGetResultSlotOps(outerPlanState(&grpstate->ss), NULL);
+       ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss, tts_ops);
 
        /*
-        * Initialize result tuple type and projection info.
+        * Initialize result slot, type and projection.
         */
-       ExecAssignResultTypeFromTL(&grpstate->ss.ps);
+       ExecInitResultTupleSlotTL(&grpstate->ss.ps, &TTSOpsVirtual);
        ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
 
-       grpstate->ss.ps.ps_TupFromTlist = false;
+       /*
+        * initialize child expressions
+        */
+       grpstate->ss.ps.qual =
+               ExecInitQual(node->plan.qual, (PlanState *) grpstate);
 
        /*
         * Precompute fmgr lookup data for inner loop
         */
-       grpstate->eqfunctions =
-               execTuplesMatchPrepare(node->numCols,
-                                                          node->grpOperators);
+       grpstate->eqfunction =
+               execTuplesMatchPrepare(ExecGetResultType(outerPlanState(grpstate)),
+                                                          node->numCols,
+                                                          node->grpColIdx,
+                                                          node->grpOperators,
+                                                          &grpstate->ss.ps);
 
        return grpstate;
 }
 
-int
-ExecCountSlotsGroup(Group *node)
-{
-       return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
-}
-
 /* ------------------------
  *             ExecEndGroup(node)
  *
@@ -288,14 +237,18 @@ ExecEndGroup(GroupState *node)
 }
 
 void
-ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
+ExecReScanGroup(GroupState *node)
 {
-       node->grp_done = FALSE;
-       node->ss.ps.ps_TupFromTlist = 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);
 }