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-2025, 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 */
35static 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 */
161ExecInitGroup(Group *node, EState *estate, int eflags)
162{
163 GroupState *grpstate;
164 const TupleTableSlotOps *tts_ops;
165
166 /* check for unsupported flags */
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 */
225void
227{
229
232}
233
234void
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:815
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:229
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:562
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:1986
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:496
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:705
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:486
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:584
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:505
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1254
#define outerPlanState(node)
Definition: execnodes.h:1246
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:389
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:426
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:453
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:267
#define EXEC_FLAG_MARK
Definition: executor.h:69
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
GroupState * ExecInitGroup(Group *node, EState *estate, int eflags)
Definition: nodeGroup.c:161
static TupleTableSlot * ExecGroup(PlanState *pstate)
Definition: nodeGroup.c:36
void ExecReScanGroup(GroupState *node)
Definition: nodeGroup.c:235
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:231
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:269
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:271
ExprState * eqfunction
Definition: execnodes.h:2478
ScanState ss
Definition: execnodes.h:2477
bool grp_done
Definition: execnodes.h:2479
int numCols
Definition: plannodes.h:1104
Plan plan
Definition: plannodes.h:1101
ExprState * qual
Definition: execnodes.h:1171
Plan * plan
Definition: execnodes.h:1150
EState * state
Definition: execnodes.h:1152
ExprContext * ps_ExprContext
Definition: execnodes.h:1189
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1190
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1156
List * qual
Definition: plannodes.h:201
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1606
PlanState ps
Definition: execnodes.h:1603
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
#define TupIsNull(slot)
Definition: tuptable.h:306
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:509