Detect duplicate aggregate calls and evaluate only one copy. This
authorTom Lane
Tue, 4 Feb 2003 00:48:23 +0000 (00:48 +0000)
committerTom Lane
Tue, 4 Feb 2003 00:48:23 +0000 (00:48 +0000)
speeds up some useful real-world cases like
SELECT x, COUNT(*) FROM t GROUP BY x HAVING COUNT(*) > 100.

src/backend/executor/nodeAgg.c

index d8eeae15ad7f5bf7e2f7fdb52f47175accff3458..0cb2f3e2b6ffc994b9cee44be9b872527afcfc95 100644 (file)
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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)
 
    /*
     * 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;
    foreach(alist, aggstate->aggs)
    {
        AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(alist);
        Aggref     *aggref = (Aggref *) aggrefstate->xprstate.expr;
-       AggStatePerAgg peraggstate = &peragg[++aggno];
+       AggStatePerAgg peraggstate;
        HeapTuple   aggTuple;
        Form_pg_aggregate aggform;
        AclResult   aclresult;
        Oid         transfn_oid,
                    finalfn_oid;
        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 */
        aggrefstate->aggno = aggno;
@@ -1271,6 +1293,9 @@ ExecInitAgg(Agg *node, EState *estate)
        ReleaseSysCache(aggTuple);
    }
 
+   /* Update numaggs to match number of unique aggregates found */
+   aggstate->numaggs = aggno + 1;
+
    return aggstate;
 }