PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2016, 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 
28 
29 /*
30  * ExecGroup -
31  *
32  * Return one tuple for each group of matching input tuples.
33  */
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  * Check to see if we're still projecting out tuples from a previous group
54  * tuple (because there is a function-returning-set in the projection
55  * expressions). If so, try to project another one.
56  */
57  if (node->ss.ps.ps_TupFromTlist)
58  {
59  TupleTableSlot *result;
60  ExprDoneCond isDone;
61 
62  result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
63  if (isDone == ExprMultipleResult)
64  return result;
65  /* Done with that source tuple... */
66  node->ss.ps.ps_TupFromTlist = false;
67  }
68 
69  /*
70  * The ScanTupleSlot holds the (copied) first tuple of each group.
71  */
72  firsttupleslot = node->ss.ss_ScanTupleSlot;
73 
74  /*
75  * We need not call ResetExprContext here because execTuplesMatch will
76  * reset the per-tuple memory context once per input tuple.
77  */
78 
79  /*
80  * If first time through, acquire first input tuple and determine whether
81  * to return it or not.
82  */
83  if (TupIsNull(firsttupleslot))
84  {
85  outerslot = ExecProcNode(outerPlanState(node));
86  if (TupIsNull(outerslot))
87  {
88  /* empty input, so return nothing */
89  node->grp_done = TRUE;
90  return NULL;
91  }
92  /* Copy tuple into firsttupleslot */
93  ExecCopySlot(firsttupleslot, outerslot);
94 
95  /*
96  * Set it up as input for qual test and projection. The expressions
97  * will access the input tuple as varno OUTER.
98  */
99  econtext->ecxt_outertuple = firsttupleslot;
100 
101  /*
102  * Check the qual (HAVING clause); if the group does not match, ignore
103  * it and fall into scan loop.
104  */
105  if (ExecQual(node->ss.ps.qual, econtext, false))
106  {
107  /*
108  * Form and return a projection tuple using the first input tuple.
109  */
110  TupleTableSlot *result;
111  ExprDoneCond isDone;
112 
113  result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
114 
115  if (isDone != ExprEndResult)
116  {
117  node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
118  return result;
119  }
120  }
121  else
122  InstrCountFiltered1(node, 1);
123  }
124 
125  /*
126  * This loop iterates once per input tuple group. At the head of the
127  * loop, we have finished processing the first tuple of the group and now
128  * need to scan over all the other group members.
129  */
130  for (;;)
131  {
132  /*
133  * Scan over all remaining tuples that belong to this group
134  */
135  for (;;)
136  {
137  outerslot = ExecProcNode(outerPlanState(node));
138  if (TupIsNull(outerslot))
139  {
140  /* no more groups, so we're done */
141  node->grp_done = TRUE;
142  return NULL;
143  }
144 
145  /*
146  * Compare with first tuple and see if this tuple is of the same
147  * group. If so, ignore it and keep scanning.
148  */
149  if (!execTuplesMatch(firsttupleslot, outerslot,
150  numCols, grpColIdx,
151  node->eqfunctions,
152  econtext->ecxt_per_tuple_memory))
153  break;
154  }
155 
156  /*
157  * We have the first tuple of the next input group. See if we want to
158  * return it.
159  */
160  /* Copy tuple, set up as input for qual test and projection */
161  ExecCopySlot(firsttupleslot, outerslot);
162  econtext->ecxt_outertuple = firsttupleslot;
163 
164  /*
165  * Check the qual (HAVING clause); if the group does not match, ignore
166  * it and loop back to scan the rest of the group.
167  */
168  if (ExecQual(node->ss.ps.qual, econtext, false))
169  {
170  /*
171  * Form and return a projection tuple using the first input tuple.
172  */
173  TupleTableSlot *result;
174  ExprDoneCond isDone;
175 
176  result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
177 
178  if (isDone != ExprEndResult)
179  {
180  node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
181  return result;
182  }
183  }
184  else
185  InstrCountFiltered1(node, 1);
186  }
187 }
188 
189 /* -----------------
190  * ExecInitGroup
191  *
192  * Creates the run-time information for the group node produced by the
193  * planner and initializes its outer subtree
194  * -----------------
195  */
196 GroupState *
197 ExecInitGroup(Group *node, EState *estate, int eflags)
198 {
199  GroupState *grpstate;
200 
201  /* check for unsupported flags */
202  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
203 
204  /*
205  * create state structure
206  */
207  grpstate = makeNode(GroupState);
208  grpstate->ss.ps.plan = (Plan *) node;
209  grpstate->ss.ps.state = estate;
210  grpstate->grp_done = FALSE;
211 
212  /*
213  * create expression context
214  */
215  ExecAssignExprContext(estate, &grpstate->ss.ps);
216 
217  /*
218  * tuple table initialization
219  */
220  ExecInitScanTupleSlot(estate, &grpstate->ss);
221  ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
222 
223  /*
224  * initialize child expressions
225  */
226  grpstate->ss.ps.targetlist = (List *)
227  ExecInitExpr((Expr *) node->plan.targetlist,
228  (PlanState *) grpstate);
229  grpstate->ss.ps.qual = (List *)
230  ExecInitExpr((Expr *) node->plan.qual,
231  (PlanState *) grpstate);
232 
233  /*
234  * initialize child nodes
235  */
236  outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
237 
238  /*
239  * initialize tuple type.
240  */
242 
243  /*
244  * Initialize result tuple type and projection info.
245  */
246  ExecAssignResultTypeFromTL(&grpstate->ss.ps);
247  ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
248 
249  grpstate->ss.ps.ps_TupFromTlist = false;
250 
251  /*
252  * Precompute fmgr lookup data for inner loop
253  */
254  grpstate->eqfunctions =
256  node->grpOperators);
257 
258  return grpstate;
259 }
260 
261 /* ------------------------
262  * ExecEndGroup(node)
263  *
264  * -----------------------
265  */
266 void
268 {
270 
271  ExecFreeExprContext(&node->ss.ps);
272 
273  /* clean up tuple table */
275 
276  outerPlan = outerPlanState(node);
277  ExecEndNode(outerPlan);
278 }
279 
280 void
282 {
284 
285  node->grp_done = FALSE;
286  node->ss.ps.ps_TupFromTlist = false;
287  /* must clear first tuple */
289 
290  /*
291  * if chgParam of subnode is not null then plan will be re-scanned by
292  * first ExecProcNode.
293  */
294  if (outerPlan->chgParam == NULL)
295  ExecReScan(outerPlan);
296 }
void ExecEndGroup(GroupState *node)
Definition: nodeGroup.c:267
List * qual
Definition: plannodes.h:122
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:374
void ExecReScanGroup(GroupState *node)
Definition: nodeGroup.c:281
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:845
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1059
TupleTableSlot * ExecGroup(GroupState *node)
Definition: nodeGroup.c:35
GroupState * ExecInitGroup(Group *node, EState *estate, int eflags)
Definition: nodeGroup.c:197
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:614
Definition: plannodes.h:96
ExprContext * ps_ExprContext
Definition: execnodes.h:1058
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:128
void ExecReScan(PlanState *node)
Definition: execAmi.c:73
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:442
List * qual
Definition: execnodes.h:1042
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:54
List * targetlist
Definition: execnodes.h:1041
TupleTableSlot * ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
Definition: execQual.c:5520
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1251
EState * state
Definition: execnodes.h:1029
bool grp_done
Definition: execnodes.h:1799
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:696
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:435
ScanState ss
Definition: execnodes.h:1797
PlanState ps
Definition: execnodes.h:1248
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4452
#define FALSE
Definition: c.h:218
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:835
#define EXEC_FLAG_BACKWARD
Definition: executor.h:59
#define outerPlanState(node)
Definition: execnodes.h:1072
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:668
bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
Definition: execQual.c:5246
#define TupIsNull(slot)
Definition: tuptable.h:138
int numCols
Definition: plannodes.h:690
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1075
Bitmapset * chgParam
Definition: execnodes.h:1052
#define outerPlan(node)
Definition: plannodes.h:151
ExprDoneCond
Definition: execnodes.h:159
Plan * plan
Definition: execnodes.h:1027
TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: execTuples.c:798
#define makeNode(_type_)
Definition: nodes.h:539
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:124
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define EXEC_FLAG_MARK
Definition: executor.h:60
Plan plan
Definition: plannodes.h:689
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:413
List * targetlist
Definition: plannodes.h:121
void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
Definition: execUtils.c:732
FmgrInfo * eqfunctions
Definition: execnodes.h:1798
#define TRUE
Definition: c.h:214
FmgrInfo * execTuplesMatchPrepare(int numCols, Oid *eqOperators)
Definition: execGrouping.c:189
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:136
bool ps_TupFromTlist
Definition: execnodes.h:1060
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
Oid * grpOperators
Definition: plannodes.h:692