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-2023, 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 #include "utils/memutils.h"
29 
30 
31 /*
32  * ExecGroup -
33  *
34  * Return one tuple for each group of matching input tuples.
35  */
36 static TupleTableSlot *
38 {
39  GroupState *node = castNode(GroupState, pstate);
40  ExprContext *econtext;
41  TupleTableSlot *firsttupleslot;
42  TupleTableSlot *outerslot;
43 
45 
46  /*
47  * get state info from node
48  */
49  if (node->grp_done)
50  return NULL;
51  econtext = node->ss.ps.ps_ExprContext;
52 
53  /*
54  * The ScanTupleSlot holds the (copied) first tuple of each group.
55  */
56  firsttupleslot = node->ss.ss_ScanTupleSlot;
57 
58  /*
59  * We need not call ResetExprContext here because ExecQualAndReset() will
60  * reset the per-tuple memory context once per input tuple.
61  */
62 
63  /*
64  * If first time through, acquire first input tuple and determine whether
65  * to return it or not.
66  */
67  if (TupIsNull(firsttupleslot))
68  {
69  outerslot = ExecProcNode(outerPlanState(node));
70  if (TupIsNull(outerslot))
71  {
72  /* empty input, so return nothing */
73  node->grp_done = true;
74  return NULL;
75  }
76  /* Copy tuple into firsttupleslot */
77  ExecCopySlot(firsttupleslot, outerslot);
78 
79  /*
80  * Set it up as input for qual test and projection. The expressions
81  * will access the input tuple as varno OUTER.
82  */
83  econtext->ecxt_outertuple = firsttupleslot;
84 
85  /*
86  * Check the qual (HAVING clause); if the group does not match, ignore
87  * it and fall into scan loop.
88  */
89  if (ExecQual(node->ss.ps.qual, econtext))
90  {
91  /*
92  * Form and return a projection tuple using the first input tuple.
93  */
94  return ExecProject(node->ss.ps.ps_ProjInfo);
95  }
96  else
97  InstrCountFiltered1(node, 1);
98  }
99 
100  /*
101  * This loop iterates once per input tuple group. At the head of the
102  * loop, we have finished processing the first tuple of the group and now
103  * need to scan over all the other group members.
104  */
105  for (;;)
106  {
107  /*
108  * Scan over all remaining tuples that belong to this group
109  */
110  for (;;)
111  {
112  outerslot = ExecProcNode(outerPlanState(node));
113  if (TupIsNull(outerslot))
114  {
115  /* no more groups, so we're done */
116  node->grp_done = true;
117  return NULL;
118  }
119 
120  /*
121  * Compare with first tuple and see if this tuple is of the same
122  * group. If so, ignore it and keep scanning.
123  */
124  econtext->ecxt_innertuple = firsttupleslot;
125  econtext->ecxt_outertuple = outerslot;
126  if (!ExecQualAndReset(node->eqfunction, econtext))
127  break;
128  }
129 
130  /*
131  * We have the first tuple of the next input group. See if we want to
132  * return it.
133  */
134  /* Copy tuple, set up as input for qual test and projection */
135  ExecCopySlot(firsttupleslot, outerslot);
136  econtext->ecxt_outertuple = firsttupleslot;
137 
138  /*
139  * Check the qual (HAVING clause); if the group does not match, ignore
140  * it and loop back to scan the rest of the group.
141  */
142  if (ExecQual(node->ss.ps.qual, econtext))
143  {
144  /*
145  * Form and return a projection tuple using the first input tuple.
146  */
147  return ExecProject(node->ss.ps.ps_ProjInfo);
148  }
149  else
150  InstrCountFiltered1(node, 1);
151  }
152 }
153 
154 /* -----------------
155  * ExecInitGroup
156  *
157  * Creates the run-time information for the group node produced by the
158  * planner and initializes its outer subtree
159  * -----------------
160  */
161 GroupState *
162 ExecInitGroup(Group *node, EState *estate, int eflags)
163 {
164  GroupState *grpstate;
165  const TupleTableSlotOps *tts_ops;
166 
167  /* check for unsupported flags */
168  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
169 
170  /*
171  * create state structure
172  */
173  grpstate = makeNode(GroupState);
174  grpstate->ss.ps.plan = (Plan *) node;
175  grpstate->ss.ps.state = estate;
176  grpstate->ss.ps.ExecProcNode = ExecGroup;
177  grpstate->grp_done = false;
178 
179  /*
180  * create expression context
181  */
182  ExecAssignExprContext(estate, &grpstate->ss.ps);
183 
184  /*
185  * initialize child nodes
186  */
187  outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
188 
189  /*
190  * Initialize scan slot and type.
191  */
192  tts_ops = ExecGetResultSlotOps(outerPlanState(&grpstate->ss), NULL);
193  ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss, tts_ops);
194 
195  /*
196  * Initialize result slot, type and projection.
197  */
199  ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
200 
201  /*
202  * initialize child expressions
203  */
204  grpstate->ss.ps.qual =
205  ExecInitQual(node->plan.qual, (PlanState *) grpstate);
206 
207  /*
208  * Precompute fmgr lookup data for inner loop
209  */
210  grpstate->eqfunction =
212  node->numCols,
213  node->grpColIdx,
214  node->grpOperators,
215  node->grpCollations,
216  &grpstate->ss.ps);
217 
218  return grpstate;
219 }
220 
221 /* ------------------------
222  * ExecEndGroup(node)
223  *
224  * -----------------------
225  */
226 void
228 {
230 
231  ExecFreeExprContext(&node->ss.ps);
232 
233  /* clean up tuple table */
235 
236  outerPlan = outerPlanState(node);
238 }
239 
240 void
242 {
244 
245  node->grp_done = false;
246  /* must clear first tuple */
248 
249  /*
250  * if chgParam of subnode is not null then plan will be re-scanned by
251  * first ExecProcNode.
252  */
253  if (outerPlan->chgParam == NULL)
255 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:213
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1800
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:498
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:507
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:690
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:488
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:543
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:658
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1141
#define outerPlanState(node)
Definition: execnodes.h:1133
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:375
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:412
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:439
#define EXEC_FLAG_MARK
Definition: executor.h:69
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:268
Assert(fmt[strlen(fmt) - 1] !='\n')
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
static TupleTableSlot * ExecGroup(PlanState *pstate)
Definition: nodeGroup.c:37
void ExecReScanGroup(GroupState *node)
Definition: nodeGroup.c:241
GroupState * ExecInitGroup(Group *node, EState *estate, int eflags)
Definition: nodeGroup.c:162
void ExecEndGroup(GroupState *node)
Definition: nodeGroup.c:227
#define makeNode(_type_)
Definition: nodes.h:176
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
#define outerPlan(node)
Definition: plannodes.h:183
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:251
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:253
ExprState * eqfunction
Definition: execnodes.h:2333
ScanState ss
Definition: execnodes.h:2332
bool grp_done
Definition: execnodes.h:2334
int numCols
Definition: plannodes.h:970
Plan plan
Definition: plannodes.h:967
ExprState * qual
Definition: execnodes.h:1058
Plan * plan
Definition: execnodes.h:1037
EState * state
Definition: execnodes.h:1039
ExprContext * ps_ExprContext
Definition: execnodes.h:1076
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1077
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1043
List * qual
Definition: plannodes.h:154
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1477
PlanState ps
Definition: execnodes.h:1474
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:433
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:483
#define TupIsNull(slot)
Definition: tuptable.h:300