|
45 | 45 | * Portions Copyright (c) 1994, Regents of the University of California |
46 | 46 | * |
47 | 47 | * IDENTIFICATION |
48 | | - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.102 2003/01/10 23:54:24 tgl Exp $ |
| 48 | + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.103 2003/02/04 00:48:23 tgl Exp $ |
49 | 49 | * |
50 | 50 | *------------------------------------------------------------------------- |
51 | 51 | */ |
@@ -1159,20 +1159,42 @@ ExecInitAgg(Agg *node, EState *estate) |
1159 | 1159 |
|
1160 | 1160 | /* |
1161 | 1161 | * Perform lookups of aggregate function info, and initialize the |
1162 | | - * unchanging fields of the per-agg data |
| 1162 | + * unchanging fields of the per-agg data. We also detect duplicate |
| 1163 | + * aggregates (for example, "SELECT sum(x) ... HAVING sum(x) > 0"). |
| 1164 | + * When duplicates are detected, we only make an AggStatePerAgg struct |
| 1165 | + * for the first one. The clones are simply pointed at the same result |
| 1166 | + * entry by giving them duplicate aggno values. |
1163 | 1167 | */ |
1164 | 1168 | aggno=-1; |
1165 | 1169 | foreach(alist,aggstate->aggs) |
1166 | 1170 | { |
1167 | 1171 | AggrefExprState*aggrefstate= (AggrefExprState*)lfirst(alist); |
1168 | 1172 | Aggref*aggref= (Aggref*)aggrefstate->xprstate.expr; |
1169 | | -AggStatePerAggperaggstate=&peragg[++aggno]; |
| 1173 | +AggStatePerAggperaggstate; |
1170 | 1174 | HeapTupleaggTuple; |
1171 | 1175 | Form_pg_aggregateaggform; |
1172 | 1176 | AclResultaclresult; |
1173 | 1177 | Oidtransfn_oid, |
1174 | 1178 | finalfn_oid; |
1175 | 1179 | DatumtextInitVal; |
| 1180 | +inti; |
| 1181 | + |
| 1182 | +/* Look for a previous duplicate aggregate */ |
| 1183 | +for (i=0;i <=aggno;i++) |
| 1184 | +{ |
| 1185 | +if (equal(aggref,peragg[i].aggref)&& |
| 1186 | +!contain_volatile_functions((Node*)aggref)) |
| 1187 | +break; |
| 1188 | +} |
| 1189 | +if (i <=aggno) |
| 1190 | +{ |
| 1191 | +/* Found a match to an existing entry, so just mark it */ |
| 1192 | +aggrefstate->aggno=i; |
| 1193 | +continue; |
| 1194 | +} |
| 1195 | + |
| 1196 | +/* Nope, so assign a new PerAgg record */ |
| 1197 | +peraggstate=&peragg[++aggno]; |
1176 | 1198 |
|
1177 | 1199 | /* Mark Aggref state node with assigned index in the result array */ |
1178 | 1200 | aggrefstate->aggno=aggno; |
@@ -1271,6 +1293,9 @@ ExecInitAgg(Agg *node, EState *estate) |
1271 | 1293 | ReleaseSysCache(aggTuple); |
1272 | 1294 | } |
1273 | 1295 |
|
| 1296 | +/* Update numaggs to match number of unique aggregates found */ |
| 1297 | +aggstate->numaggs=aggno+1; |
| 1298 | + |
1274 | 1299 | returnaggstate; |
1275 | 1300 | } |
1276 | 1301 |
|
|