]> granicus.if.org Git - postgresql/commitdiff
Fix failure to mark all aggregates with appropriate transtype.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 2 Jul 2016 17:23:02 +0000 (13:23 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 2 Jul 2016 17:23:12 +0000 (13:23 -0400)
In commit 915b703e1 I gave get_agg_clause_costs() the responsibility of
marking Aggref nodes with the appropriate aggtranstype.  I failed to notice
that where it was being called from, it might see only a subset of the
Aggref nodes that were in the original targetlist.  Specifically, if there
are duplicate aggregate calls in the tlist, either make_sort_input_target
or make_window_input_target might put just a single instance into the
grouping_target, and then only that instance would get marked.  Fix by
moving the call back into grouping_planner(), before we start building
assorted PathTargets from the query tlist.  Per report from Stefan Huehner.

Report: <20160702131056.GD3165@huehner.biz>

src/backend/optimizer/plan/planner.c
src/test/regress/expected/limit.out
src/test/regress/sql/limit.sql

index a66317367c3435a5b92b8179e7732054812c1d8d..ddf1109de76f4a75601af0d2721f13aa3a8ee5c0 100644 (file)
@@ -114,6 +114,7 @@ static Size estimate_hashagg_tablesize(Path *path,
 static RelOptInfo *create_grouping_paths(PlannerInfo *root,
                                          RelOptInfo *input_rel,
                                          PathTarget *target,
+                                         const AggClauseCosts *agg_costs,
                                          List *rollup_lists,
                                          List *rollup_groupclauses);
 static RelOptInfo *create_window_paths(PlannerInfo *root,
@@ -1499,6 +1500,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
                PathTarget *grouping_target;
                PathTarget *scanjoin_target;
                bool            have_grouping;
+               AggClauseCosts agg_costs;
                WindowFuncLists *wflists = NULL;
                List       *activeWindows = NIL;
                List       *rollup_lists = NIL;
@@ -1623,6 +1625,28 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
                 */
                root->processed_tlist = tlist;
 
+               /*
+                * Collect statistics about aggregates for estimating costs, and mark
+                * all the aggregates with resolved aggtranstypes.  We must do this
+                * before slicing and dicing the tlist into various pathtargets, else
+                * some copies of the Aggref nodes might escape being marked with the
+                * correct transtypes.
+                *
+                * Note: currently, we do not detect duplicate aggregates here.  This
+                * may result in somewhat-overestimated cost, which is fine for our
+                * purposes since all Paths will get charged the same.  But at some
+                * point we might wish to do that detection in the planner, rather
+                * than during executor startup.
+                */
+               MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
+               if (parse->hasAggs)
+               {
+                       get_agg_clause_costs(root, (Node *) tlist, AGGSPLIT_SIMPLE,
+                                                                &agg_costs);
+                       get_agg_clause_costs(root, parse->havingQual, AGGSPLIT_SIMPLE,
+                                                                &agg_costs);
+               }
+
                /*
                 * Locate any window functions in the tlist.  (We don't need to look
                 * anywhere else, since expressions used in ORDER BY will be in there
@@ -1822,6 +1846,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
                        current_rel = create_grouping_paths(root,
                                                                                                current_rel,
                                                                                                grouping_target,
+                                                                                               &agg_costs,
                                                                                                rollup_lists,
                                                                                                rollup_groupclauses);
                }
@@ -3244,6 +3269,7 @@ estimate_hashagg_tablesize(Path *path, const AggClauseCosts *agg_costs,
  *
  * input_rel: contains the source-data Paths
  * target: the pathtarget for the result Paths to compute
+ * agg_costs: cost info about all aggregates in query (in AGGSPLIT_SIMPLE mode)
  * rollup_lists: list of grouping sets, or NIL if not doing grouping sets
  * rollup_groupclauses: list of grouping clauses for grouping sets,
  *             or NIL if not doing grouping sets
@@ -3260,6 +3286,7 @@ static RelOptInfo *
 create_grouping_paths(PlannerInfo *root,
                                          RelOptInfo *input_rel,
                                          PathTarget *target,
+                                         const AggClauseCosts *agg_costs,
                                          List *rollup_lists,
                                          List *rollup_groupclauses)
 {
@@ -3267,7 +3294,6 @@ create_grouping_paths(PlannerInfo *root,
        Path       *cheapest_path = input_rel->cheapest_total_path;
        RelOptInfo *grouped_rel;
        PathTarget *partial_grouping_target = NULL;
-       AggClauseCosts agg_costs;
        AggClauseCosts agg_partial_costs;       /* parallel only */
        AggClauseCosts agg_final_costs;         /* parallel only */
        Size            hashaggtablesize;
@@ -3364,20 +3390,6 @@ create_grouping_paths(PlannerInfo *root,
                return grouped_rel;
        }
 
-       /*
-        * Collect statistics about aggregates for estimating costs.  Note: we do
-        * not detect duplicate aggregates here; a somewhat-overestimated cost is
-        * okay for our purposes.
-        */
-       MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
-       if (parse->hasAggs)
-       {
-               get_agg_clause_costs(root, (Node *) target->exprs, AGGSPLIT_SIMPLE,
-                                                        &agg_costs);
-               get_agg_clause_costs(root, parse->havingQual, AGGSPLIT_SIMPLE,
-                                                        &agg_costs);
-       }
-
        /*
         * Estimate number of groups.
         */
@@ -3414,7 +3426,7 @@ create_grouping_paths(PlannerInfo *root,
         */
        can_hash = (parse->groupClause != NIL &&
                                parse->groupingSets == NIL &&
-                               agg_costs.numOrderedAggs == 0 &&
+                               agg_costs->numOrderedAggs == 0 &&
                                grouping_is_hashable(parse->groupClause));
 
        /*
@@ -3446,7 +3458,7 @@ create_grouping_paths(PlannerInfo *root,
                /* We don't know how to do grouping sets in parallel. */
                try_parallel_aggregation = false;
        }
-       else if (agg_costs.hasNonPartial || agg_costs.hasNonSerial)
+       else if (agg_costs->hasNonPartial || agg_costs->hasNonSerial)
        {
                /* Insufficient support for partial mode. */
                try_parallel_aggregation = false;
@@ -3627,7 +3639,7 @@ create_grouping_paths(PlannerInfo *root,
                                                                                                  (List *) parse->havingQual,
                                                                                                          rollup_lists,
                                                                                                          rollup_groupclauses,
-                                                                                                         &agg_costs,
+                                                                                                         agg_costs,
                                                                                                          dNumGroups));
                                }
                                else if (parse->hasAggs)
@@ -3645,7 +3657,7 @@ create_grouping_paths(PlannerInfo *root,
                                                                                         AGGSPLIT_SIMPLE,
                                                                                         parse->groupClause,
                                                                                         (List *) parse->havingQual,
-                                                                                        &agg_costs,
+                                                                                        agg_costs,
                                                                                         dNumGroups));
                                }
                                else if (parse->groupClause)
@@ -3727,7 +3739,7 @@ create_grouping_paths(PlannerInfo *root,
        if (can_hash)
        {
                hashaggtablesize = estimate_hashagg_tablesize(cheapest_path,
-                                                                                                         &agg_costs,
+                                                                                                         agg_costs,
                                                                                                          dNumGroups);
 
                /*
@@ -3751,7 +3763,7 @@ create_grouping_paths(PlannerInfo *root,
                                                                         AGGSPLIT_SIMPLE,
                                                                         parse->groupClause,
                                                                         (List *) parse->havingQual,
-                                                                        &agg_costs,
+                                                                        agg_costs,
                                                                         dNumGroups));
                }
 
index 659a1015b48f375cb3ccc29f9b3afe1fd8523b9b..9c3eecfc3bd0c544b0ba8196444bd9b97cd00430 100644 (file)
@@ -296,3 +296,27 @@ order by s2 desc;
   0 |  0
 (3 rows)
 
+-- test for failure to set all aggregates' aggtranstype
+explain (verbose, costs off)
+select sum(tenthous) as s1, sum(tenthous) + random()*0 as s2
+  from tenk1 group by thousand order by thousand limit 3;
+                                                    QUERY PLAN                                                     
+-------------------------------------------------------------------------------------------------------------------
+ Limit
+   Output: (sum(tenthous)), (((sum(tenthous))::double precision + (random() * '0'::double precision))), thousand
+   ->  GroupAggregate
+         Output: sum(tenthous), ((sum(tenthous))::double precision + (random() * '0'::double precision)), thousand
+         Group Key: tenk1.thousand
+         ->  Index Only Scan using tenk1_thous_tenthous on public.tenk1
+               Output: thousand, tenthous
+(7 rows)
+
+select sum(tenthous) as s1, sum(tenthous) + random()*0 as s2
+  from tenk1 group by thousand order by thousand limit 3;
+  s1   |  s2   
+-------+-------
+ 45000 | 45000
+ 45010 | 45010
+ 45020 | 45020
+(3 rows)
+
index ef5686c520b3c5dbe2d3cecdb4c743efccb9f0ca..8015f81fc2b3b7a3520966ffb7bc4b2af72c4813 100644 (file)
@@ -91,3 +91,11 @@ order by s2 desc;
 
 select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2
 order by s2 desc;
+
+-- test for failure to set all aggregates' aggtranstype
+explain (verbose, costs off)
+select sum(tenthous) as s1, sum(tenthous) + random()*0 as s2
+  from tenk1 group by thousand order by thousand limit 3;
+
+select sum(tenthous) as s1, sum(tenthous) + random()*0 as s2
+  from tenk1 group by thousand order by thousand limit 3;