]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeGroup.c
Revert "Do execGrouping.c via expression eval machinery."
[postgresql] / 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-2018, 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 ExecGroup(PlanState *pstate)
37 {
38         GroupState *node = castNode(GroupState, pstate);
39         ExprContext *econtext;
40         int                     numCols;
41         AttrNumber *grpColIdx;
42         TupleTableSlot *firsttupleslot;
43         TupleTableSlot *outerslot;
44
45         CHECK_FOR_INTERRUPTS();
46
47         /*
48          * get state info from node
49          */
50         if (node->grp_done)
51                 return NULL;
52         econtext = node->ss.ps.ps_ExprContext;
53         numCols = ((Group *) node->ss.ps.plan)->numCols;
54         grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
55
56         /*
57          * The ScanTupleSlot holds the (copied) first tuple of each group.
58          */
59         firsttupleslot = node->ss.ss_ScanTupleSlot;
60
61         /*
62          * We need not call ResetExprContext here because execTuplesMatch will
63          * reset the per-tuple memory context once per input tuple.
64          */
65
66         /*
67          * If first time through, acquire first input tuple and determine whether
68          * to return it or not.
69          */
70         if (TupIsNull(firsttupleslot))
71         {
72                 outerslot = ExecProcNode(outerPlanState(node));
73                 if (TupIsNull(outerslot))
74                 {
75                         /* empty input, so return nothing */
76                         node->grp_done = true;
77                         return NULL;
78                 }
79                 /* Copy tuple into firsttupleslot */
80                 ExecCopySlot(firsttupleslot, outerslot);
81
82                 /*
83                  * Set it up as input for qual test and projection.  The expressions
84                  * will access the input tuple as varno OUTER.
85                  */
86                 econtext->ecxt_outertuple = firsttupleslot;
87
88                 /*
89                  * Check the qual (HAVING clause); if the group does not match, ignore
90                  * it and fall into scan loop.
91                  */
92                 if (ExecQual(node->ss.ps.qual, econtext))
93                 {
94                         /*
95                          * Form and return a projection tuple using the first input tuple.
96                          */
97                         return ExecProject(node->ss.ps.ps_ProjInfo);
98                 }
99                 else
100                         InstrCountFiltered1(node, 1);
101         }
102
103         /*
104          * This loop iterates once per input tuple group.  At the head of the
105          * loop, we have finished processing the first tuple of the group and now
106          * need to scan over all the other group members.
107          */
108         for (;;)
109         {
110                 /*
111                  * Scan over all remaining tuples that belong to this group
112                  */
113                 for (;;)
114                 {
115                         outerslot = ExecProcNode(outerPlanState(node));
116                         if (TupIsNull(outerslot))
117                         {
118                                 /* no more groups, so we're done */
119                                 node->grp_done = true;
120                                 return NULL;
121                         }
122
123                         /*
124                          * Compare with first tuple and see if this tuple is of the same
125                          * group.  If so, ignore it and keep scanning.
126                          */
127                         if (!execTuplesMatch(firsttupleslot, outerslot,
128                                                                  numCols, grpColIdx,
129                                                                  node->eqfunctions,
130                                                                  econtext->ecxt_per_tuple_memory))
131                                 break;
132                 }
133
134                 /*
135                  * We have the first tuple of the next input group.  See if we want to
136                  * return it.
137                  */
138                 /* Copy tuple, set up as input for qual test and projection */
139                 ExecCopySlot(firsttupleslot, outerslot);
140                 econtext->ecxt_outertuple = firsttupleslot;
141
142                 /*
143                  * Check the qual (HAVING clause); if the group does not match, ignore
144                  * it and loop back to scan the rest of the group.
145                  */
146                 if (ExecQual(node->ss.ps.qual, econtext))
147                 {
148                         /*
149                          * Form and return a projection tuple using the first input tuple.
150                          */
151                         return ExecProject(node->ss.ps.ps_ProjInfo);
152                 }
153                 else
154                         InstrCountFiltered1(node, 1);
155         }
156 }
157
158 /* -----------------
159  * ExecInitGroup
160  *
161  *      Creates the run-time information for the group node produced by the
162  *      planner and initializes its outer subtree
163  * -----------------
164  */
165 GroupState *
166 ExecInitGroup(Group *node, EState *estate, int eflags)
167 {
168         GroupState *grpstate;
169
170         /* check for unsupported flags */
171         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
172
173         /*
174          * create state structure
175          */
176         grpstate = makeNode(GroupState);
177         grpstate->ss.ps.plan = (Plan *) node;
178         grpstate->ss.ps.state = estate;
179         grpstate->ss.ps.ExecProcNode = ExecGroup;
180         grpstate->grp_done = false;
181
182         /*
183          * create expression context
184          */
185         ExecAssignExprContext(estate, &grpstate->ss.ps);
186
187         /*
188          * tuple table initialization
189          */
190         ExecInitScanTupleSlot(estate, &grpstate->ss);
191         ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
192
193         /*
194          * initialize child expressions
195          */
196         grpstate->ss.ps.qual =
197                 ExecInitQual(node->plan.qual, (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 /* ------------------------
226  *              ExecEndGroup(node)
227  *
228  * -----------------------
229  */
230 void
231 ExecEndGroup(GroupState *node)
232 {
233         PlanState  *outerPlan;
234
235         ExecFreeExprContext(&node->ss.ps);
236
237         /* clean up tuple table */
238         ExecClearTuple(node->ss.ss_ScanTupleSlot);
239
240         outerPlan = outerPlanState(node);
241         ExecEndNode(outerPlan);
242 }
243
244 void
245 ExecReScanGroup(GroupState *node)
246 {
247         PlanState  *outerPlan = outerPlanState(node);
248
249         node->grp_done = false;
250         /* must clear first tuple */
251         ExecClearTuple(node->ss.ss_ScanTupleSlot);
252
253         /*
254          * if chgParam of subnode is not null then plan will be re-scanned by
255          * first ExecProcNode.
256          */
257         if (outerPlan->chgParam == NULL)
258                 ExecReScan(outerPlan);
259 }