]> granicus.if.org Git - postgresql/commitdiff
Fix build_grouping_chain() to not clobber its input lists.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 14 Jan 2016 16:51:57 +0000 (11:51 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 14 Jan 2016 16:51:57 +0000 (11:51 -0500)
There's no good reason for stomping on the input data; it makes the logic
in this function no simpler, in fact probably the reverse.  And it makes
it impossible to separate path generation from plan generation, as I'm
working towards doing; that will require more than one traversal of these
lists.

src/backend/optimizer/plan/planner.c

index fed1acc684f655f9297f40cb0b2d175500f103de..131dc8a7b1aa1854f9110b072343af5fc33afebe 100644 (file)
@@ -2035,13 +2035,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                                   &agg_costs,
                                                                                                   numGroups,
                                                                                                   result_plan);
-
-                               /*
-                                * these are destroyed by build_grouping_chain, so make sure
-                                * we don't try and touch them again
-                                */
-                               rollup_groupclauses = NIL;
-                               rollup_lists = NIL;
                        }
                        else if (parse->groupClause)
                        {
@@ -2461,10 +2454,10 @@ remap_groupColIdx(PlannerInfo *root, List *groupClause)
 
 /*
  * Build Agg and Sort nodes to implement sorted grouping with one or more
- * grouping sets. (A plain GROUP BY or just the presence of aggregates counts
+ * grouping sets.  A plain GROUP BY or just the presence of aggregates counts
  * for this purpose as a single grouping set; the calling code is responsible
- * for providing a non-empty rollup_groupclauses list for such cases, though
- * rollup_lists may be null.)
+ * for providing a single-element rollup_groupclauses list for such cases,
+ * though rollup_lists may be nil.
  *
  * The last entry in rollup_groupclauses (which is the one the input is sorted
  * on, if at all) is the one used for the returned Agg node. Any additional
@@ -2473,8 +2466,6 @@ remap_groupColIdx(PlannerInfo *root, List *groupClause)
  * participate in the plan directly, but they are both a convenient way to
  * represent the required data and a convenient way to account for the costs
  * of execution.
- *
- * rollup_groupclauses and rollup_lists are destroyed by this function.
  */
 static Plan *
 build_grouping_chain(PlannerInfo *root,
@@ -2514,62 +2505,71 @@ build_grouping_chain(PlannerInfo *root,
         * Generate the side nodes that describe the other sort and group
         * operations besides the top one.
         */
-       while (list_length(rollup_groupclauses) > 1)
+       if (list_length(rollup_groupclauses) > 1)
        {
-               List       *groupClause = linitial(rollup_groupclauses);
-               List       *gsets = linitial(rollup_lists);
-               AttrNumber *new_grpColIdx;
-               Plan       *sort_plan;
-               Plan       *agg_plan;
-
-               Assert(groupClause);
-               Assert(gsets);
-
-               new_grpColIdx = remap_groupColIdx(root, groupClause);
+               ListCell   *lc,
+                                  *lc2;
 
-               sort_plan = (Plan *)
-                       make_sort_from_groupcols(root,
-                                                                        groupClause,
-                                                                        new_grpColIdx,
-                                                                        result_plan);
-
-               /*
-                * sort_plan includes the cost of result_plan over again, which is not
-                * what we want (since it's not actually running that plan). So
-                * correct the cost figures.
-                */
+               Assert(list_length(rollup_groupclauses) == list_length(rollup_lists));
+               forboth(lc, rollup_groupclauses, lc2, rollup_lists)
+               {
+                       List       *groupClause = (List *) lfirst(lc);
+                       List       *gsets = (List *) lfirst(lc2);
+                       AttrNumber *new_grpColIdx;
+                       Plan       *sort_plan;
+                       Plan       *agg_plan;
+
+                       /* We want to iterate over all but the last rollup list elements */
+                       if (lnext(lc) == NULL)
+                               break;
 
-               sort_plan->startup_cost -= result_plan->total_cost;
-               sort_plan->total_cost -= result_plan->total_cost;
+                       new_grpColIdx = remap_groupColIdx(root, groupClause);
 
-               agg_plan = (Plan *) make_agg(root,
-                                                                        tlist,
-                                                                        (List *) parse->havingQual,
-                                                                        AGG_SORTED,
-                                                                        agg_costs,
-                                                                        list_length(linitial(gsets)),
-                                                                        new_grpColIdx,
-                                                                        extract_grouping_ops(groupClause),
-                                                                        gsets,
-                                                                        numGroups,
-                                                                        sort_plan);
+                       sort_plan = (Plan *)
+                               make_sort_from_groupcols(root,
+                                                                                groupClause,
+                                                                                new_grpColIdx,
+                                                                                result_plan);
 
-               sort_plan->lefttree = NULL;
+                       /*
+                        * sort_plan includes the cost of result_plan, which is not what
+                        * we want (since we'll not actually run that plan again).  So
+                        * correct the cost figures.
+                        */
+                       sort_plan->startup_cost -= result_plan->total_cost;
+                       sort_plan->total_cost -= result_plan->total_cost;
+
+                       agg_plan = (Plan *) make_agg(root,
+                                                                                tlist,
+                                                                                (List *) parse->havingQual,
+                                                                                AGG_SORTED,
+                                                                                agg_costs,
+                                                                                list_length(linitial(gsets)),
+                                                                                new_grpColIdx,
+                                                                                extract_grouping_ops(groupClause),
+                                                                                gsets,
+                                                                                numGroups,
+                                                                                sort_plan);
 
-               chain = lappend(chain, agg_plan);
+                       /*
+                        * Nuke stuff we don't need to avoid bloating debug output.
+                        */
+                       sort_plan->targetlist = NIL;
+                       sort_plan->lefttree = NULL;
 
-               if (rollup_lists)
-                       rollup_lists = list_delete_first(rollup_lists);
+                       agg_plan->targetlist = NIL;
+                       agg_plan->qual = NIL;
 
-               rollup_groupclauses = list_delete_first(rollup_groupclauses);
+                       chain = lappend(chain, agg_plan);
+               }
        }
 
        /*
         * Now make the final Agg node
         */
        {
-               List       *groupClause = linitial(rollup_groupclauses);
-               List       *gsets = rollup_lists ? linitial(rollup_lists) : NIL;
+               List       *groupClause = (List *) llast(rollup_groupclauses);
+               List       *gsets = rollup_lists ? (List *) llast(rollup_lists) : NIL;
                int                     numGroupCols;
                ListCell   *lc;
 
@@ -2601,14 +2601,6 @@ build_grouping_chain(PlannerInfo *root,
                        Plan       *subplan = lfirst(lc);
 
                        result_plan->total_cost += subplan->total_cost;
-
-                       /*
-                        * Nuke stuff we don't need to avoid bloating debug output.
-                        */
-
-                       subplan->targetlist = NIL;
-                       subplan->qual = NIL;
-                       subplan->lefttree->targetlist = NIL;
                }
        }