Skip to content

Commit cf21c46

Browse files
committed
Repair crash with unsortable grouping sets.
If there were multiple grouping sets, none of them empty, all of which were unsortable, then an oversight in consider_groupingsets_paths led to a null pointer dereference. Fix, and add a regression test for this case. Per report from Dang Minh Huong, though I didn't use their patch. Backpatch to 10.x where hashed grouping sets were added.
1 parent 5b1b728 commit cf21c46

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4200,7 +4200,28 @@ consider_groupingsets_paths(PlannerInfo *root,
42004200

42014201
Assert(can_hash);
42024202

4203-
if (pathkeys_contained_in(root->group_pathkeys, path->pathkeys))
4203+
/*
4204+
* If the input is coincidentally sorted usefully (which can happen
4205+
* even if is_sorted is false, since that only means that our caller
4206+
* has set up the sorting for us), then save some hashtable space by
4207+
* making use of that. But we need to watch out for degenerate cases:
4208+
*
4209+
* 1) If there are any empty grouping sets, then group_pathkeys might
4210+
* be NIL if all non-empty grouping sets are unsortable. In this case,
4211+
* there will be a rollup containing only empty groups, and the
4212+
* pathkeys_contained_in test is vacuously true; this is ok.
4213+
*
4214+
* XXX: the above relies on the fact that group_pathkeys is generated
4215+
* from the first rollup. If we add the ability to consider multiple
4216+
* sort orders for grouping input, this assumption might fail.
4217+
*
4218+
* 2) If there are no empty sets and only unsortable sets, then the
4219+
* rollups list will be empty (and thus l_start == NULL), and
4220+
* group_pathkeys will be NIL; we must ensure that the vacuously-true
4221+
* pathkeys_contain_in test doesn't cause us to crash.
4222+
*/
4223+
if (l_start != NULL &&
4224+
pathkeys_contained_in(root->group_pathkeys, path->pathkeys))
42044225
{
42054226
unhashed_rollup = lfirst(l_start);
42064227
exclude_groups = unhashed_rollup->numGroups;

src/test/regress/expected/groupingsets.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,18 @@ explain (costs off)
10181018
-> Values Scan on "*VALUES*"
10191019
(9 rows)
10201020

1021+
-- unsortable cases
1022+
select unsortable_col, count(*)
1023+
from gstest4 group by grouping sets ((unsortable_col),(unsortable_col))
1024+
order by unsortable_col::text;
1025+
unsortable_col | count
1026+
----------------+-------
1027+
1 | 4
1028+
1 | 4
1029+
2 | 4
1030+
2 | 4
1031+
(4 rows)
1032+
10211033
-- mixed hashable/sortable cases
10221034
select unhashable_col, unsortable_col,
10231035
grouping(unhashable_col, unsortable_col),

src/test/regress/sql/groupingsets.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ explain (costs off)
292292
select a, b, grouping(a,b), array_agg(v order by v)
293293
from gstest1 group by cube(a,b);
294294

295+
-- unsortable cases
296+
select unsortable_col, count(*)
297+
from gstest4 group by grouping sets ((unsortable_col),(unsortable_col))
298+
order by unsortable_col::text;
299+
295300
-- mixed hashable/sortable cases
296301
select unhashable_col, unsortable_col,
297302
grouping(unhashable_col, unsortable_col),

0 commit comments

Comments
 (0)