15
15
* locate group boundaries.
16
16
*
17
17
* IDENTIFICATION
18
- * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.59 2004/12/31 21:59:45 pgsql Exp $
18
+ * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.60 2005/03/10 23: 21:21 tgl Exp $
19
19
*
20
20
*-------------------------------------------------------------------------
21
21
*/
35
35
TupleTableSlot *
36
36
ExecGroup (GroupState * node )
37
37
{
38
- EState * estate ;
39
38
ExprContext * econtext ;
40
39
TupleDesc tupdesc ;
41
40
int numCols ;
42
41
AttrNumber * grpColIdx ;
43
- HeapTuple outerTuple = NULL ;
42
+ HeapTuple outerTuple ;
44
43
HeapTuple firsttuple ;
45
44
TupleTableSlot * outerslot ;
46
- ProjectionInfo * projInfo ;
47
- TupleTableSlot * resultSlot ;
48
45
49
46
/*
50
47
* get state info from node
51
48
*/
52
49
if (node -> grp_done )
53
50
return NULL ;
54
- estate = node -> ss .ps .state ;
55
51
econtext = node -> ss .ps .ps_ExprContext ;
56
52
tupdesc = ExecGetScanType (& node -> ss );
57
53
numCols = ((Group * ) node -> ss .ps .plan )-> numCols ;
@@ -62,67 +58,101 @@ ExecGroup(GroupState *node)
62
58
* reset the per-tuple memory context once per input tuple.
63
59
*/
64
60
65
- /* If we don't already have first tuple of group, fetch it */
66
- /* this should occur on the first call only */
61
+ /*
62
+ * If first time through, acquire first input tuple and determine
63
+ * whether to return it or not.
64
+ */
67
65
firsttuple = node -> grp_firstTuple ;
68
66
if (firsttuple == NULL )
69
67
{
70
68
outerslot = ExecProcNode (outerPlanState (node ));
71
69
if (TupIsNull (outerslot ))
72
70
{
71
+ /* empty input, so return nothing */
73
72
node -> grp_done = TRUE;
74
73
return NULL ;
75
74
}
76
- node -> grp_firstTuple = firsttuple =
77
- heap_copytuple (outerslot -> val );
75
+ node -> grp_firstTuple = firsttuple = heap_copytuple (outerslot -> val );
76
+ /* Set up tuple as input for qual test and projection */
77
+ ExecStoreTuple (firsttuple ,
78
+ node -> ss .ss_ScanTupleSlot ,
79
+ InvalidBuffer ,
80
+ false);
81
+ econtext -> ecxt_scantuple = node -> ss .ss_ScanTupleSlot ;
82
+ /*
83
+ * Check the qual (HAVING clause); if the group does not match,
84
+ * ignore it and fall into scan loop.
85
+ */
86
+ if (ExecQual (node -> ss .ps .qual , econtext , false))
87
+ {
88
+ /*
89
+ * Form and return a projection tuple using the first input
90
+ * tuple.
91
+ */
92
+ return ExecProject (node -> ss .ps .ps_ProjInfo , NULL );
93
+ }
78
94
}
79
95
80
96
/*
81
- * Scan over all tuples that belong to this group
97
+ * This loop iterates once per input tuple group. At the head of the
98
+ * loop, we have finished processing the first tuple of the group and
99
+ * now need to scan over all the other group members.
82
100
*/
83
101
for (;;)
84
102
{
85
- outerslot = ExecProcNode (outerPlanState (node ));
86
- if (TupIsNull (outerslot ))
103
+ /*
104
+ * Scan over all remaining tuples that belong to this group
105
+ */
106
+ for (;;)
87
107
{
88
- node -> grp_done = TRUE;
89
- outerTuple = NULL ;
90
- break ;
91
- }
92
- outerTuple = outerslot -> val ;
108
+ outerslot = ExecProcNode (outerPlanState (node ));
109
+ if (TupIsNull (outerslot ))
110
+ {
111
+ /* no more groups, so we're done */
112
+ node -> grp_done = TRUE;
113
+ return NULL ;
114
+ }
115
+ outerTuple = outerslot -> val ;
93
116
117
+ /*
118
+ * Compare with first tuple and see if this tuple is of the same
119
+ * group. If so, ignore it and keep scanning.
120
+ */
121
+ if (!execTuplesMatch (firsttuple , outerTuple ,
122
+ tupdesc ,
123
+ numCols , grpColIdx ,
124
+ node -> eqfunctions ,
125
+ econtext -> ecxt_per_tuple_memory ))
126
+ break ;
127
+ }
94
128
/*
95
- * Compare with first tuple and see if this tuple is of the same
96
- * group .
129
+ * We have the first tuple of the next input group. See if we
130
+ * want to return it .
97
131
*/
98
- if (!execTuplesMatch (firsttuple , outerTuple ,
99
- tupdesc ,
100
- numCols , grpColIdx ,
101
- node -> eqfunctions ,
102
- econtext -> ecxt_per_tuple_memory ))
103
- break ;
104
- }
105
-
106
- /*
107
- * form a projection tuple based on the (copied) first tuple of the
108
- * group, and store it in the result tuple slot.
109
- */
110
- ExecStoreTuple (firsttuple ,
111
- node -> ss .ss_ScanTupleSlot ,
112
- InvalidBuffer ,
113
- false);
114
- econtext -> ecxt_scantuple = node -> ss .ss_ScanTupleSlot ;
115
- projInfo = node -> ss .ps .ps_ProjInfo ;
116
- resultSlot = ExecProject (projInfo , NULL );
117
-
118
- /* save first tuple of next group, if we are not done yet */
119
- if (!node -> grp_done )
120
- {
121
132
heap_freetuple (firsttuple );
122
- node -> grp_firstTuple = heap_copytuple (outerTuple );
133
+ node -> grp_firstTuple = firsttuple = heap_copytuple (outerTuple );
134
+ /* Set up tuple as input for qual test and projection */
135
+ ExecStoreTuple (firsttuple ,
136
+ node -> ss .ss_ScanTupleSlot ,
137
+ InvalidBuffer ,
138
+ false);
139
+ econtext -> ecxt_scantuple = node -> ss .ss_ScanTupleSlot ;
140
+ /*
141
+ * Check the qual (HAVING clause); if the group does not match,
142
+ * ignore it and loop back to scan the rest of the group.
143
+ */
144
+ if (ExecQual (node -> ss .ps .qual , econtext , false))
145
+ {
146
+ /*
147
+ * Form and return a projection tuple using the first input
148
+ * tuple.
149
+ */
150
+ return ExecProject (node -> ss .ps .ps_ProjInfo , NULL );
151
+ }
123
152
}
124
153
125
- return resultSlot ;
154
+ /* NOTREACHED */
155
+ return NULL ;
126
156
}
127
157
128
158
/* -----------------
0 commit comments