diff options
| author | Andrew Gierth | 2019-06-30 22:49:23 +0000 |
|---|---|---|
| committer | Andrew Gierth | 2019-06-30 22:49:23 +0000 |
| commit | 05dc5f4767e1c5ed157b2870f05d57f3378302f4 (patch) | |
| tree | f26fd5ab91cb91bdde62f172d07539237f6d112c /src | |
| parent | 43085a4f693e35d674a9965c484e4e87f18f6d29 (diff) | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 39 | ||||
| -rw-r--r-- | src/test/regress/expected/groupingsets.out | 13 | ||||
| -rw-r--r-- | src/test/regress/sql/groupingsets.sql | 3 |
3 files changed, 34 insertions, 21 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 0f46914e540..41e316fee07 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -3438,7 +3438,6 @@ static List * reorder_grouping_sets(List *groupingsets, List *sortclause) { ListCell *lc; - ListCell *lc2; List *previous = NIL; List *result = NIL; @@ -3448,35 +3447,33 @@ reorder_grouping_sets(List *groupingsets, List *sortclause) List *new_elems = list_difference_int(candidate, previous); 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)) - { - previous = lappend_int(previous, ref); - new_elems = list_delete_int(new_elems, ref); - } - else - { - /* diverged from the sortclause; give up on it */ - sortclause = NIL; - break; - } + if (list_member_int(new_elems, ref)) + { + previous = lappend_int(previous, ref); + new_elems = list_delete_int(new_elems, ref); } - - foreach(lc2, new_elems) + else { - 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); result = lcons(gs, result); - list_free(new_elems); } list_free(previous); diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out index 381ebce8a1e..5d92b08d20a 100644 --- a/src/test/regress/expected/groupingsets.out +++ b/src/test/regress/expected/groupingsets.out @@ -637,6 +637,19 @@ select a, b, sum(v.x) | | 9 (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. 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 diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql index 5d6485913b3..d8f78fcc000 100644 --- a/src/test/regress/sql/groupingsets.sql +++ b/src/test/regress/sql/groupingsets.sql @@ -213,6 +213,9 @@ select a, b, sum(v.x) from (values (1),(2)) v(x), gstest_data(v.x) 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. select (select grouping(a,b) from gstest2) from gstest2 group by a,b; |
