Repair logic for reordering grouping sets optimization.
The logic in reorder_grouping_sets to order grouping set elements to match a pre-specified sort ordering was defective, resulting in unnecessary sort nodes (though the query output would still be correct). Repair, simplifying the code a little, and add a test. Per report from Richard Guo, though I didn't use their patch. Original bug seems to have been my fault. Backpatch back to 9.5 where grouping sets were introduced. Discussion: https://postgr.es/m/CAN_9JTzyjGcUjiBHxLsgqfk7PkdLGXiM=pwM+=ph2LsWw0WO1A@mail.gmail.com
This commit is contained in:
parent
c000a47ad1
commit
da53be23d1
@ -3530,7 +3530,6 @@ static List *
|
|||||||
reorder_grouping_sets(List *groupingsets, List *sortclause)
|
reorder_grouping_sets(List *groupingsets, List *sortclause)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
ListCell *lc2;
|
|
||||||
List *previous = NIL;
|
List *previous = NIL;
|
||||||
List *result = NIL;
|
List *result = NIL;
|
||||||
|
|
||||||
@ -3540,35 +3539,33 @@ reorder_grouping_sets(List *groupingsets, List *sortclause)
|
|||||||
List *new_elems = list_difference_int(candidate, previous);
|
List *new_elems = list_difference_int(candidate, previous);
|
||||||
GroupingSetData *gs = makeNode(GroupingSetData);
|
GroupingSetData *gs = makeNode(GroupingSetData);
|
||||||
|
|
||||||
if (list_length(new_elems) > 0)
|
while (list_length(sortclause) > list_length(previous) &&
|
||||||
|
list_length(new_elems) > 0)
|
||||||
{
|
{
|
||||||
while (list_length(sortclause) > list_length(previous))
|
SortGroupClause *sc = list_nth(sortclause, list_length(previous));
|
||||||
{
|
int ref = sc->tleSortGroupRef;
|
||||||
SortGroupClause *sc = list_nth(sortclause, list_length(previous));
|
|
||||||
int ref = sc->tleSortGroupRef;
|
|
||||||
|
|
||||||
if (list_member_int(new_elems, ref))
|
if (list_member_int(new_elems, ref))
|
||||||
{
|
{
|
||||||
previous = lappend_int(previous, ref);
|
previous = lappend_int(previous, ref);
|
||||||
new_elems = list_delete_int(new_elems, ref);
|
new_elems = list_delete_int(new_elems, ref);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* diverged from the sortclause; give up on it */
|
|
||||||
sortclause = NIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
foreach(lc2, new_elems)
|
|
||||||
{
|
{
|
||||||
previous = lappend_int(previous, lfirst_int(lc2));
|
/* diverged from the sortclause; give up on it */
|
||||||
|
sortclause = NIL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Safe to use list_concat (which shares cells of the second arg)
|
||||||
|
* because we know that new_elems does not share cells with anything.
|
||||||
|
*/
|
||||||
|
previous = list_concat(previous, new_elems);
|
||||||
|
|
||||||
gs->set = list_copy(previous);
|
gs->set = list_copy(previous);
|
||||||
result = lcons(gs, result);
|
result = lcons(gs, result);
|
||||||
list_free(new_elems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list_free(previous);
|
list_free(previous);
|
||||||
|
@ -637,6 +637,19 @@ select a, b, sum(v.x)
|
|||||||
| | 9
|
| | 9
|
||||||
(12 rows)
|
(12 rows)
|
||||||
|
|
||||||
|
-- Test reordering of grouping sets
|
||||||
|
explain (costs off)
|
||||||
|
select * from gstest1 group by grouping sets((a,b,v),(v)) order by v,b,a;
|
||||||
|
QUERY PLAN
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
GroupAggregate
|
||||||
|
Group Key: "*VALUES*".column3, "*VALUES*".column2, "*VALUES*".column1
|
||||||
|
Group Key: "*VALUES*".column3
|
||||||
|
-> Sort
|
||||||
|
Sort Key: "*VALUES*".column3, "*VALUES*".column2, "*VALUES*".column1
|
||||||
|
-> Values Scan on "*VALUES*"
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
-- Agg level check. This query should error out.
|
-- Agg level check. This query should error out.
|
||||||
select (select grouping(a,b) from gstest2) from gstest2 group by a,b;
|
select (select grouping(a,b) from gstest2) from gstest2 group by a,b;
|
||||||
ERROR: arguments to GROUPING must be grouping expressions of the associated query level
|
ERROR: arguments to GROUPING must be grouping expressions of the associated query level
|
||||||
|
@ -213,6 +213,9 @@ select a, b, sum(v.x)
|
|||||||
from (values (1),(2)) v(x), gstest_data(v.x)
|
from (values (1),(2)) v(x), gstest_data(v.x)
|
||||||
group by cube (a,b) order by a,b;
|
group by cube (a,b) order by a,b;
|
||||||
|
|
||||||
|
-- Test reordering of grouping sets
|
||||||
|
explain (costs off)
|
||||||
|
select * from gstest1 group by grouping sets((a,b,v),(v)) order by v,b,a;
|
||||||
|
|
||||||
-- Agg level check. This query should error out.
|
-- Agg level check. This query should error out.
|
||||||
select (select grouping(a,b) from gstest2) from gstest2 group by a,b;
|
select (select grouping(a,b) from gstest2) from gstest2 group by a,b;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user