OSDN Git Service

Detect duplicate aggregate calls and evaluate only one copy. This
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Feb 2003 00:48:23 +0000 (00:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 d8eeae1..0cb2f3e 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;
 }