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-2024, 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  TupleTableSlot *firsttupleslot;
41  TupleTableSlot *outerslot;
42 
44 
45  /*
46  * get state info from node
47  */
48  if (node->grp_done)
49  return NULL;
50  econtext = node->ss.ps.ps_ExprContext;
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 ExecQualAndReset() 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))
89  {
90  /*
91  * Form and return a projection tuple using the first input tuple.
92  */
93  return ExecProject(node->ss.ps.ps_ProjInfo);
94  }
95  else
96  InstrCountFiltered1(node, 1);
97  }
98 
99  /*
100  * This loop iterates once per input tuple group. At the head of the
101  * loop, we have finished processing the first tuple of the group and now
102  * need to scan over all the other group members.
103  */
104  for (;;)
105  {
106  /*
107  * Scan over all remaining tuples that belong to this group
108  */
109  for (;;)
110  {
111  outerslot = ExecProcNode(outerPlanState(node));
112  if (TupIsNull(outerslot))
113  {
114  /* no more groups, so we're done */
115  node->grp_done = true;
116  return NULL;
117  }
118 
119  /*
120  * Compare with first tuple and see if this tuple is of the same
121  * group. If so, ignore it and keep scanning.
122  */
123  econtext->ecxt_innertuple = firsttupleslot;
124  econtext->ecxt_outertuple = outerslot;
125  if (!ExecQualAndReset(node->eqfunction, econtext))
126  break;
127  }
128 
129  /*
130  * We have the first tuple of the next input group. See if we want to
131  * return it.
132  */
133  /* Copy tuple, set up as input for qual test and projection */
134  ExecCopySlot(firsttupleslot, outerslot);
135  econtext->ecxt_outertuple = firsttupleslot;
136 
137  /*
138  * Check the qual (HAVING clause); if the group does not match, ignore
139  * it and loop back to scan the rest of the group.
140  */
141  if (ExecQual(node->ss.ps.qual, econtext))
142  {
143  /*
144  * Form and return a projection tuple using the first input tuple.
145  */
146  return ExecProject(node->ss.ps.ps_ProjInfo);
147  }
148  else
149  InstrCountFiltered1(node, 1);
150  }
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  const TupleTableSlotOps *tts_ops;
165 
166  /* check for unsupported flags */
167  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
168 
169  /*
170  * create state structure
171  */
172  grpstate = makeNode(GroupState);
173  grpstate->ss.ps.plan = (Plan *) node;
174  grpstate->ss.ps.state = estate;
175  grpstate->ss.ps.ExecProcNode = ExecGroup;
176  grpstate->grp_done = false;
177 
178  /*
179  * create expression context
180  */
181  ExecAssignExprContext(estate, &grpstate->ss.ps);
182 
183  /*
184  * initialize child nodes
185  */
186  outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate, eflags);
187 
188  /*
189  * Initialize scan slot and type.
190  */
191  tts_ops = ExecGetResultSlotOps(outerPlanState(&grpstate->ss), NULL);
192  ExecCreateScanSlotFromOuterPlan(estate, &grpstate->ss, tts_ops);
193 
194  /*
195  * Initialize result slot, type and projection.
196  */
198  ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
199 
200  /*
201  * initialize child expressions
202  */
203  grpstate->ss.ps.qual =
204  ExecInitQual(node->plan.qual, (PlanState *) grpstate);
205 
206  /*
207  * Precompute fmgr lookup data for inner loop
208  */
209  grpstate->eqfunction =
211  node->numCols,
212  node->grpColIdx,
213  node->grpOperators,
214  node->grpCollations,
215  &grpstate->ss.ps);
216 
217  return grpstate;
218 }
219 
220 /* ------------------------
221  * ExecEndGroup(node)
222  *
223  * -----------------------
224  */
225 void
227 {
229 
230  outerPlan = outerPlanState(node);
232 }
233 
234 void
236 {
238 
239  node->grp_done = false;
240  /* must clear first tuple */
242 
243  /*
244  * if chgParam of subnode is not null then plan will be re-scanned by
245  * first ExecProcNode.
246  */
247  if (outerPlan->chgParam == NULL)
249 }
#define Assert(condition)
Definition: c.h:858
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:220
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:58
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:84
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1886
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:493
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:502
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:659
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:483
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:538
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1221
#define outerPlanState(node)
Definition: execnodes.h:1213
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:376
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:413
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:440
#define EXEC_FLAG_MARK
Definition: executor.h:69
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:269
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static TupleTableSlot * ExecGroup(PlanState *pstate)
Definition: nodeGroup.c:36
void ExecReScanGroup(GroupState *node)
Definition: nodeGroup.c:235
GroupState * ExecInitGroup(Group *node, EState *estate, int eflags)
Definition: nodeGroup.c:161
void ExecEndGroup(GroupState *node)
Definition: nodeGroup.c:226
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#define outerPlan(node)
Definition: plannodes.h:182
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:257
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:259
ExprState * eqfunction
Definition: execnodes.h:2413
ScanState ss
Definition: execnodes.h:2412
bool grp_done
Definition: execnodes.h:2414
int numCols
Definition: plannodes.h:972
Plan plan
Definition: plannodes.h:969
ExprState * qual
Definition: execnodes.h:1138
Plan * plan
Definition: execnodes.h:1117
EState * state
Definition: execnodes.h:1119
ExprContext * ps_ExprContext
Definition: execnodes.h:1156
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1157
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1123
List * qual
Definition: plannodes.h:153
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1567
PlanState ps
Definition: execnodes.h:1564
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:509
#define TupIsNull(slot)
Definition: tuptable.h:306