]> granicus.if.org Git - postgresql/commitdiff
Apply my original fix for Taiki Yamaguchi's bug report about DISTINCT MAX().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 31 Mar 2008 16:59:26 +0000 (16:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 31 Mar 2008 16:59:26 +0000 (16:59 +0000)
Add some regression tests for plausible failures in this area.

src/backend/optimizer/path/equivclass.c
src/backend/optimizer/plan/planagg.c
src/include/optimizer/paths.h
src/test/regress/expected/aggregates.out
src/test/regress/sql/aggregates.sql

index 1bc6d15a3e83eaa1e70de86eb553e7436e3ec44c..b289ea6e65b37c998305cade838cd2aaf89d5f77 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.9 2008/01/09 20:42:27 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.10 2008/03/31 16:59:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1638,6 +1638,44 @@ add_child_rel_equivalences(PlannerInfo *root,
 }
 
 
+/*
+ * mutate_eclass_expressions
+ *       Apply an expression tree mutator to all expressions stored in
+ *       equivalence classes.
+ *
+ * This is a bit of a hack ... it's currently needed only by planagg.c,
+ * which needs to do a global search-and-replace of MIN/MAX Aggrefs
+ * after eclasses are already set up.  Without changing the eclasses too,
+ * subsequent matching of ORDER BY clauses would fail.
+ *
+ * Note that we assume the mutation won't affect relation membership or any
+ * other properties we keep track of (which is a bit bogus, but by the time
+ * planagg.c runs, it no longer matters).  Also we must be called in the
+ * main planner memory context.
+ */
+void
+mutate_eclass_expressions(PlannerInfo *root,
+                                                 Node *(*mutator) (),
+                                                 void *context)
+{
+       ListCell   *lc1;
+
+       foreach(lc1, root->eq_classes)
+       {
+               EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
+               ListCell   *lc2;
+
+               foreach(lc2, cur_ec->ec_members)
+               {
+                       EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
+
+                       cur_em->em_expr = (Expr *)
+                               mutator((Node *) cur_em->em_expr, context);
+               }
+       }
+}
+
+
 /*
  * find_eclass_clauses_for_index_join
  *       Create joinclauses usable for a nestloop-with-inner-indexscan
index e472e48ccb5aa5bbc5802d2bd347262be9bb3639..5bb92111f6065035a9758f81014cac061c743c54 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.36 2008/01/01 19:45:50 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.37 2008/03/31 16:59:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -187,6 +187,18 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
        hqual = replace_aggs_with_params_mutator(parse->havingQual,
                                                                                         &aggs_list);
 
+       /*
+        * We have to replace Aggrefs with Params in equivalence classes too,
+        * else ORDER BY or DISTINCT on an optimized aggregate will fail.
+        *
+        * Note: at some point it might become necessary to mutate other
+        * data structures too, such as the query's sortClause or distinctClause.
+        * Right now, those won't be examined after this point.
+        */
+       mutate_eclass_expressions(root,
+                                                         replace_aggs_with_params_mutator,
+                                                         &aggs_list);
+
        /*
         * Generate the output plan --- basically just a Result
         */
index f3e50c5cbf96a40fb332c2fd1965092290b89ead..81e8089df169812fd758261dc8dbb52e1db9488c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.103 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.104 2008/03/31 16:59:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -127,6 +127,9 @@ extern void add_child_rel_equivalences(PlannerInfo *root,
                                                   AppendRelInfo *appinfo,
                                                   RelOptInfo *parent_rel,
                                                   RelOptInfo *child_rel);
+extern void mutate_eclass_expressions(PlannerInfo *root,
+                                                                         Node *(*mutator) (),
+                                                                         void *context);
 extern List *find_eclass_clauses_for_index_join(PlannerInfo *root,
                                                                   RelOptInfo *rel,
                                                                   Relids outer_relids);
index 74635479e486e8c8c473c2e7513311eee883d617..ae65314166f06c753e210ee5b377b9faa943dc51 100644 (file)
@@ -484,3 +484,36 @@ from int4_tbl;
  -2147483647 |  0
 (5 rows)
 
+-- check some cases that were handled incorrectly in 8.3.0
+select distinct max(unique2) from tenk1;
+ max  
+------
+ 9999
+(1 row)
+
+select max(unique2) from tenk1 order by 1;
+ max  
+------
+ 9999
+(1 row)
+
+select max(unique2) from tenk1 order by max(unique2);
+ max  
+------
+ 9999
+(1 row)
+
+select max(unique2) from tenk1 order by max(unique2)+1;
+ max  
+------
+ 9999
+(1 row)
+
+select max(unique2), generate_series(1,3) as g from tenk1 order by g desc;
+ max  | g 
+------+---
+ 9999 | 3
+ 9999 | 2
+ 9999 | 1
+(3 rows)
+
index 890aa8dea02d583d3112f46f778000091036494b..afa997e7ea7e8d0a608e9665386fcc47cc9d623d 100644 (file)
@@ -217,3 +217,10 @@ select min(tenthous) from tenk1 where thousand = 33;
 -- check parameter propagation into an indexscan subquery
 select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt
 from int4_tbl;
+
+-- check some cases that were handled incorrectly in 8.3.0
+select distinct max(unique2) from tenk1;
+select max(unique2) from tenk1 order by 1;
+select max(unique2) from tenk1 order by max(unique2);
+select max(unique2) from tenk1 order by max(unique2)+1;
+select max(unique2), generate_series(1,3) as g from tenk1 order by g desc;