mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Fix build_grouping_chain() to not clobber its input lists.
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.
This commit is contained in:
@ -2035,13 +2035,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
|||||||
&agg_costs,
|
&agg_costs,
|
||||||
numGroups,
|
numGroups,
|
||||||
result_plan);
|
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)
|
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
|
* 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 this purpose as a single grouping set; the calling code is responsible
|
||||||
* for providing a non-empty rollup_groupclauses list for such cases, though
|
* for providing a single-element rollup_groupclauses list for such cases,
|
||||||
* rollup_lists may be null.)
|
* though rollup_lists may be nil.
|
||||||
*
|
*
|
||||||
* The last entry in rollup_groupclauses (which is the one the input is sorted
|
* 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
|
* 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
|
* 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
|
* represent the required data and a convenient way to account for the costs
|
||||||
* of execution.
|
* of execution.
|
||||||
*
|
|
||||||
* rollup_groupclauses and rollup_lists are destroyed by this function.
|
|
||||||
*/
|
*/
|
||||||
static Plan *
|
static Plan *
|
||||||
build_grouping_chain(PlannerInfo *root,
|
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
|
* Generate the side nodes that describe the other sort and group
|
||||||
* operations besides the top one.
|
* operations besides the top one.
|
||||||
*/
|
*/
|
||||||
while (list_length(rollup_groupclauses) > 1)
|
if (list_length(rollup_groupclauses) > 1)
|
||||||
{
|
{
|
||||||
List *groupClause = linitial(rollup_groupclauses);
|
ListCell *lc,
|
||||||
List *gsets = linitial(rollup_lists);
|
*lc2;
|
||||||
AttrNumber *new_grpColIdx;
|
|
||||||
Plan *sort_plan;
|
|
||||||
Plan *agg_plan;
|
|
||||||
|
|
||||||
Assert(groupClause);
|
Assert(list_length(rollup_groupclauses) == list_length(rollup_lists));
|
||||||
Assert(gsets);
|
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;
|
||||||
|
|
||||||
new_grpColIdx = remap_groupColIdx(root, groupClause);
|
/* We want to iterate over all but the last rollup list elements */
|
||||||
|
if (lnext(lc) == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
sort_plan = (Plan *)
|
new_grpColIdx = remap_groupColIdx(root, groupClause);
|
||||||
make_sort_from_groupcols(root,
|
|
||||||
groupClause,
|
|
||||||
new_grpColIdx,
|
|
||||||
result_plan);
|
|
||||||
|
|
||||||
/*
|
sort_plan = (Plan *)
|
||||||
* sort_plan includes the cost of result_plan over again, which is not
|
make_sort_from_groupcols(root,
|
||||||
* what we want (since it's not actually running that plan). So
|
groupClause,
|
||||||
* correct the cost figures.
|
new_grpColIdx,
|
||||||
*/
|
result_plan);
|
||||||
|
|
||||||
sort_plan->startup_cost -= result_plan->total_cost;
|
/*
|
||||||
sort_plan->total_cost -= result_plan->total_cost;
|
* 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,
|
agg_plan = (Plan *) make_agg(root,
|
||||||
tlist,
|
tlist,
|
||||||
(List *) parse->havingQual,
|
(List *) parse->havingQual,
|
||||||
AGG_SORTED,
|
AGG_SORTED,
|
||||||
agg_costs,
|
agg_costs,
|
||||||
list_length(linitial(gsets)),
|
list_length(linitial(gsets)),
|
||||||
new_grpColIdx,
|
new_grpColIdx,
|
||||||
extract_grouping_ops(groupClause),
|
extract_grouping_ops(groupClause),
|
||||||
gsets,
|
gsets,
|
||||||
numGroups,
|
numGroups,
|
||||||
sort_plan);
|
sort_plan);
|
||||||
|
|
||||||
sort_plan->lefttree = NULL;
|
/*
|
||||||
|
* Nuke stuff we don't need to avoid bloating debug output.
|
||||||
|
*/
|
||||||
|
sort_plan->targetlist = NIL;
|
||||||
|
sort_plan->lefttree = NULL;
|
||||||
|
|
||||||
chain = lappend(chain, agg_plan);
|
agg_plan->targetlist = NIL;
|
||||||
|
agg_plan->qual = NIL;
|
||||||
|
|
||||||
if (rollup_lists)
|
chain = lappend(chain, agg_plan);
|
||||||
rollup_lists = list_delete_first(rollup_lists);
|
}
|
||||||
|
|
||||||
rollup_groupclauses = list_delete_first(rollup_groupclauses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now make the final Agg node
|
* Now make the final Agg node
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
List *groupClause = linitial(rollup_groupclauses);
|
List *groupClause = (List *) llast(rollup_groupclauses);
|
||||||
List *gsets = rollup_lists ? linitial(rollup_lists) : NIL;
|
List *gsets = rollup_lists ? (List *) llast(rollup_lists) : NIL;
|
||||||
int numGroupCols;
|
int numGroupCols;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
@ -2601,14 +2601,6 @@ build_grouping_chain(PlannerInfo *root,
|
|||||||
Plan *subplan = lfirst(lc);
|
Plan *subplan = lfirst(lc);
|
||||||
|
|
||||||
result_plan->total_cost += subplan->total_cost;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user