Commit 85caf178 authored by Tom Lane's avatar Tom Lane

Detect duplicate aggregate calls and evaluate only one copy. This

speeds up some useful real-world cases like
SELECT x, COUNT(*) FROM t GROUP BY x HAVING COUNT(*) > 100.
parent ef5842b5
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.102 2003/01/10 23:54:24 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.103 2003/02/04 00:48:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1159,20 +1159,42 @@ ExecInitAgg(Agg *node, EState *estate) ...@@ -1159,20 +1159,42 @@ ExecInitAgg(Agg *node, EState *estate)
/* /*
* Perform lookups of aggregate function info, and initialize the * Perform lookups of aggregate function info, and initialize the
* unchanging fields of the per-agg data * unchanging fields of the per-agg data. We also detect duplicate
* aggregates (for example, "SELECT sum(x) ... HAVING sum(x) > 0").
* When duplicates are detected, we only make an AggStatePerAgg struct
* for the first one. The clones are simply pointed at the same result
* entry by giving them duplicate aggno values.
*/ */
aggno = -1; aggno = -1;
foreach(alist, aggstate->aggs) foreach(alist, aggstate->aggs)
{ {
AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(alist); AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(alist);
Aggref *aggref = (Aggref *) aggrefstate->xprstate.expr; Aggref *aggref = (Aggref *) aggrefstate->xprstate.expr;
AggStatePerAgg peraggstate = &peragg[++aggno]; AggStatePerAgg peraggstate;
HeapTuple aggTuple; HeapTuple aggTuple;
Form_pg_aggregate aggform; Form_pg_aggregate aggform;
AclResult aclresult; AclResult aclresult;
Oid transfn_oid, Oid transfn_oid,
finalfn_oid; finalfn_oid;
Datum textInitVal; Datum textInitVal;
int i;
/* Look for a previous duplicate aggregate */
for (i = 0; i <= aggno; i++)
{
if (equal(aggref, peragg[i].aggref) &&
!contain_volatile_functions((Node *) aggref))
break;
}
if (i <= aggno)
{
/* Found a match to an existing entry, so just mark it */
aggrefstate->aggno = i;
continue;
}
/* Nope, so assign a new PerAgg record */
peraggstate = &peragg[++aggno];
/* Mark Aggref state node with assigned index in the result array */ /* Mark Aggref state node with assigned index in the result array */
aggrefstate->aggno = aggno; aggrefstate->aggno = aggno;
...@@ -1271,6 +1293,9 @@ ExecInitAgg(Agg *node, EState *estate) ...@@ -1271,6 +1293,9 @@ ExecInitAgg(Agg *node, EState *estate)
ReleaseSysCache(aggTuple); ReleaseSysCache(aggTuple);
} }
/* Update numaggs to match number of unique aggregates found */
aggstate->numaggs = aggno + 1;
return aggstate; return aggstate;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment