OSDN Git Service

pgindent run for 8.3.
[pg-rex/syncrep.git] / src / backend / executor / nodeGroup.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeGroup.c
4  *        Routines to handle group nodes (used for queries with GROUP BY clause).
5  *
6  * Portions Copyright (c) 1996-2007, 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  *        $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.69 2007/02/22 23:44:24 tgl Exp $
19  *
20  *-------------------------------------------------------------------------
21  */
22
23 #include "postgres.h"
24
25 #include "executor/executor.h"
26 #include "executor/nodeGroup.h"
27
28
29 /*
30  *       ExecGroup -
31  *
32  *              Return one tuple for each group of matching input tuples.
33  */
34 TupleTableSlot *
35 ExecGroup(GroupState *node)
36 {
37         ExprContext *econtext;
38         int                     numCols;
39         AttrNumber *grpColIdx;
40         TupleTableSlot *firsttupleslot;
41         TupleTableSlot *outerslot;
42
43         /*
44          * get state info from node
45          */
46         if (node->grp_done)
47                 return NULL;
48         econtext = node->ss.ps.ps_ExprContext;
49         numCols = ((Group *) node->ss.ps.plan)->numCols;
50         grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
51
52         /*
53          * The ScanTupleSlot holds the (copied) first tuple of each group.
54          */
55         firsttupleslot = node->ss.ss_ScanTupleSlot;
56
57         /*
58          * We need not call ResetExprContext here because execTuplesMatch 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         if (TupIsNull(firsttupleslot))
67         {
68                 outerslot = ExecProcNode(outerPlanState(node));
69                 if (TupIsNull(outerslot))
70                 {
71                         /* empty input, so return nothing */
72                         node->grp_done = TRUE;
73                         return NULL;
74                 }
75                 /* Copy tuple into firsttupleslot */
76                 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                 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                 if (ExecQual(node->ss.ps.qual, econtext, false))
89                 {
90                         /*
91                          * Form and return a projection tuple using the first input tuple.
92                          */
93                         return ExecProject(node->ss.ps.ps_ProjInfo, NULL);
94                 }
95         }
96
97         /*
98          * This loop iterates once per input tuple group.  At the head of the
99          * loop, we have finished processing the first tuple of the group and now
100          * need to scan over all the other group members.
101          */
102         for (;;)
103         {
104                 /*
105                  * Scan over all remaining tuples that belong to this group
106                  */
107                 for (;;)
108                 {
109                         outerslot = ExecProcNode(outerPlanState(node));
110                         if (TupIsNull(outerslot))
111                         {
112                                 /* no more groups, so we're done */
113                                 node->grp_done = TRUE;
114                                 return NULL;
115                         }
116
117                         /*
118                          * Compare with first tuple and see if this tuple is of the same
119                          * group.  If so, ignore it and keep scanning.
120                          */
121                         if (!execTuplesMatch(firsttupleslot, outerslot,
122                                                                  numCols, grpColIdx,
123                                                                  node->eqfunctions,
124                                                                  econtext->ecxt_per_tuple_memory))
125                                 break;
126                 }
127
128                 /*
129                  * We have the first tuple of the next input group.  See if we want to
130                  * return it.
131                  */
132                 /* Copy tuple, set up as input for qual test and projection */
133                 ExecCopySlot(firsttupleslot, outerslot);
134                 econtext->ecxt_outertuple = firsttupleslot;
135
136                 /*
137                  * Check the qual (HAVING clause); if the group does not match, ignore
138                  * it and loop back to scan the rest of the group.
139                  */
140                 if (ExecQual(node->ss.ps.qual, econtext, false))
141                 {
142                         /*
143                          * Form and return a projection tuple using the first input tuple.
144                          */
145                         return ExecProject(node->ss.ps.ps_ProjInfo, NULL);
146                 }
147         }
148
149         /* NOTREACHED */
150         return NULL;
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 ExecInitGroup(Group *node, EState *estate, int eflags)
162 {
163         GroupState *grpstate;
164
165         /* check for unsupported flags */
166         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
167
168         /*
169          * create state structure
170          */
171         grpstate = makeNode(GroupState);
172         grpstate->ss.ps.plan = (Plan *) node;
173         grpstate->ss.ps.state = estate;
174         grpstate->grp_done = FALSE;
175
176         /*
177          * create expression context
178          */
179         ExecAssignExprContext(estate, &grpstate->ss.ps);
180
181 #define GROUP_NSLOTS 2
182
183         /*
184          * tuple table initialization
185          */
186         ExecInitScanTupleSlot(estate, &grpstate->ss);
187         ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
188
189         /*
190          * initialize child expressions
191          */
192         grpstate->ss.ps.targetlist = (List *)
193                 ExecInitExpr((Expr *) node->plan.targetlist,
194                                          (PlanState *) grpstate);
195         grpstate->ss.ps.qual = (List *)
196                 ExecInitExpr((Expr *) node->plan.qual,
197                                          (PlanState *) grpstate);
198
199         /*
200          * initialize child nodes
201          */
202         outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
203
204         /*
205          * initialize tuple type.
206          */
207         ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
208
209         /*
210          * Initialize result tuple type and projection info.
211          */
212         ExecAssignResultTypeFromTL(&grpstate->ss.ps);
213         ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
214
215         /*
216          * Precompute fmgr lookup data for inner loop
217          */
218         grpstate->eqfunctions =
219                 execTuplesMatchPrepare(node->numCols,
220                                                            node->grpOperators);
221
222         return grpstate;
223 }
224
225 int
226 ExecCountSlotsGroup(Group *node)
227 {
228         return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
229 }
230
231 /* ------------------------
232  *              ExecEndGroup(node)
233  *
234  * -----------------------
235  */
236 void
237 ExecEndGroup(GroupState *node)
238 {
239         PlanState  *outerPlan;
240
241         ExecFreeExprContext(&node->ss.ps);
242
243         /* clean up tuple table */
244         ExecClearTuple(node->ss.ss_ScanTupleSlot);
245
246         outerPlan = outerPlanState(node);
247         ExecEndNode(outerPlan);
248 }
249
250 void
251 ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
252 {
253         node->grp_done = FALSE;
254         /* must clear first tuple */
255         ExecClearTuple(node->ss.ss_ScanTupleSlot);
256
257         if (((PlanState *) node)->lefttree &&
258                 ((PlanState *) node)->lefttree->chgParam == NULL)
259                 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
260 }