aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
authorAndrew Gierth <rhodiumtoad@postgresql.org>2019-06-30 23:49:13 +0100
committerAndrew Gierth <rhodiumtoad@postgresql.org>2019-06-30 23:49:13 +0100
commitda53be23d1c5e529675e958eaee54cfed4e4dbac (patch)
treec312d87428ebd5ff945c4adc6e5ba2dae3f907b4 /src/backend/optimizer/plan/planner.c
parentc000a47ad1fdd4fb92c7068279d97e0c3db4f8eb (diff)
downloadpostgresql-da53be23d1c5e529675e958eaee54cfed4e4dbac.tar.gz
postgresql-da53be23d1c5e529675e958eaee54cfed4e4dbac.zip
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/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c39
1 files changed, 18 insertions, 21 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index cb897cc7f4e..eadc04222ef 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -3530,7 +3530,6 @@ static List *
reorder_grouping_sets(List *groupingsets, List *sortclause)
{
ListCell *lc;
- ListCell *lc2;
List *previous = NIL;
List *result = NIL;
@@ -3540,35 +3539,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);