PostgreSQL Source Code  git master
nodeGroup.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeGroup.c
4  * Routines to handle group nodes (used for queries with GROUP BY clause).
5  *
6  * Portions Copyright (c) 1996-2017, 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 *
37 {
38  GroupState *node = castNode(GroupState, pstate);
39  ExprContext *econtext;
40  int numCols;
41  AttrNumber *grpColIdx;
42  TupleTableSlot *firsttupleslot;
43  TupleTableSlot *outerslot;
44 
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 =
220  node->grpOperators);
221 
222  return grpstate;
223 }
224 
225 /* ------------------------
226  * ExecEndGroup(node)
227  *
228  * -----------------------
229  */
230 void
232 {
234 
235  ExecFreeExprContext(&node->ss.ps);
236 
237  /* clean up tuple table */
239 
240  outerPlan = outerPlanState(node);
241  ExecEndNode(outerPlan);
242 }
243 
244 void
246 {
248 
249  node->grp_done = false;
250  /* must clear first tuple */
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 }
void ExecEndGroup(GroupState *node)
Definition: nodeGroup.c:231
List * qual
Definition: plannodes.h:145
void ExecReScanGroup(GroupState *node)
Definition: nodeGroup.c:245
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:842
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:885
GroupState * ExecInitGroup(Group *node, EState *estate, int eflags)
Definition: nodeGroup.c:166
#define castNode(_type_, nodeptr)
Definition: nodes.h:581
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:539
ExprContext * ps_ExprContext
Definition: execnodes.h:884
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:204
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1116
EState * state
Definition: execnodes.h:852
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:357
bool grp_done
Definition: execnodes.h:1792
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:603
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:448
ScanState ss
Definition: execnodes.h:1790
PlanState ps
Definition: execnodes.h:1113
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:896
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:495
#define TupIsNull(slot)
Definition: tuptable.h:138
int numCols
Definition: plannodes.h:762
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:899
Bitmapset * chgParam
Definition: execnodes.h:878
#define outerPlan(node)
Definition: plannodes.h:174
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:856
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:237
Plan * plan
Definition: execnodes.h:850
TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: execTuples.c:795
#define makeNode(_type_)
Definition: nodes.h:560
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:200
#define Assert(condition)
Definition: c.h:680
#define EXEC_FLAG_MARK
Definition: executor.h:61
Plan plan
Definition: plannodes.h:761
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:426
ExprState * qual
Definition: execnodes.h:868
static TupleTableSlot * ExecGroup(PlanState *pstate)
Definition: nodeGroup.c:36
void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
Definition: execUtils.c:639
FmgrInfo * eqfunctions
Definition: execnodes.h:1791
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
FmgrInfo * execTuplesMatchPrepare(int numCols, Oid *eqOperators)
Definition: execGrouping.c:204
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
int16 AttrNumber
Definition: attnum.h:21
Oid * grpOperators
Definition: plannodes.h:764
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:320