1 /*-------------------------------------------------------------------------
4 * Routines to handle group nodes (used for queries with GROUP BY clause).
6 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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.
18 * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.58 2004/08/29 04:12:31 momjian Exp $
20 *-------------------------------------------------------------------------
25 #include "access/heapam.h"
26 #include "executor/executor.h"
27 #include "executor/nodeGroup.h"
33 * Return one tuple for each group of matching input tuples.
36 ExecGroup(GroupState *node)
39 ExprContext *econtext;
42 AttrNumber *grpColIdx;
43 HeapTuple outerTuple = NULL;
45 TupleTableSlot *outerslot;
46 ProjectionInfo *projInfo;
47 TupleTableSlot *resultSlot;
50 * get state info from node
54 estate = node->ss.ps.state;
55 econtext = node->ss.ps.ps_ExprContext;
56 tupdesc = ExecGetScanType(&node->ss);
57 numCols = ((Group *) node->ss.ps.plan)->numCols;
58 grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
61 * We need not call ResetExprContext here because execTuplesMatch will
62 * reset the per-tuple memory context once per input tuple.
65 /* If we don't already have first tuple of group, fetch it */
66 /* this should occur on the first call only */
67 firsttuple = node->grp_firstTuple;
68 if (firsttuple == NULL)
70 outerslot = ExecProcNode(outerPlanState(node));
71 if (TupIsNull(outerslot))
73 node->grp_done = TRUE;
76 node->grp_firstTuple = firsttuple =
77 heap_copytuple(outerslot->val);
81 * Scan over all tuples that belong to this group
85 outerslot = ExecProcNode(outerPlanState(node));
86 if (TupIsNull(outerslot))
88 node->grp_done = TRUE;
92 outerTuple = outerslot->val;
95 * Compare with first tuple and see if this tuple is of the same
98 if (!execTuplesMatch(firsttuple, outerTuple,
102 econtext->ecxt_per_tuple_memory))
107 * form a projection tuple based on the (copied) first tuple of the
108 * group, and store it in the result tuple slot.
110 ExecStoreTuple(firsttuple,
111 node->ss.ss_ScanTupleSlot,
114 econtext->ecxt_scantuple = node->ss.ss_ScanTupleSlot;
115 projInfo = node->ss.ps.ps_ProjInfo;
116 resultSlot = ExecProject(projInfo, NULL);
118 /* save first tuple of next group, if we are not done yet */
121 heap_freetuple(firsttuple);
122 node->grp_firstTuple = heap_copytuple(outerTuple);
131 * Creates the run-time information for the group node produced by the
132 * planner and initializes its outer subtree
136 ExecInitGroup(Group *node, EState *estate)
138 GroupState *grpstate;
141 * create state structure
143 grpstate = makeNode(GroupState);
144 grpstate->ss.ps.plan = (Plan *) node;
145 grpstate->ss.ps.state = estate;
146 grpstate->grp_firstTuple = NULL;
147 grpstate->grp_done = FALSE;
150 * create expression context
152 ExecAssignExprContext(estate, &grpstate->ss.ps);
154 #define GROUP_NSLOTS 2
157 * tuple table initialization
159 ExecInitScanTupleSlot(estate, &grpstate->ss);
160 ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
163 * initialize child expressions
165 grpstate->ss.ps.targetlist = (List *)
166 ExecInitExpr((Expr *) node->plan.targetlist,
167 (PlanState *) grpstate);
168 grpstate->ss.ps.qual = (List *)
169 ExecInitExpr((Expr *) node->plan.qual,
170 (PlanState *) grpstate);
173 * initialize child nodes
175 outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate);
178 * initialize tuple type.
180 ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
183 * Initialize result tuple type and projection info.
185 ExecAssignResultTypeFromTL(&grpstate->ss.ps);
186 ExecAssignProjectionInfo(&grpstate->ss.ps);
189 * Precompute fmgr lookup data for inner loop
191 grpstate->eqfunctions =
192 execTuplesMatchPrepare(ExecGetScanType(&grpstate->ss),
200 ExecCountSlotsGroup(Group *node)
202 return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
205 /* ------------------------
208 * -----------------------
211 ExecEndGroup(GroupState *node)
213 PlanState *outerPlan;
215 ExecFreeExprContext(&node->ss.ps);
217 /* clean up tuple table */
218 ExecClearTuple(node->ss.ss_ScanTupleSlot);
220 outerPlan = outerPlanState(node);
221 ExecEndNode(outerPlan);
225 ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
227 node->grp_done = FALSE;
228 if (node->grp_firstTuple != NULL)
230 heap_freetuple(node->grp_firstTuple);
231 node->grp_firstTuple = NULL;
234 if (((PlanState *) node)->lefttree &&
235 ((PlanState *) node)->lefttree->chgParam == NULL)
236 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);