From 7f0c2d25a4bc4902380012811eae66b19480b7e2 Mon Sep 17 00:00:00 2001 From: Vladimir Petrzhikovskii Date: Thu, 29 Oct 2026 20:13:00 +0100 Subject: [PATCH] test: cover grouping set equivalences and constants On DataFusion 53.1.0 and 55.2.0 with target_partitions = 1, a GROUPING SETS ((a, b), (a)) query over rows filtered by a = b returned rows in the wrong ORDER BY order. The grouping-set AggregateExec projected the input equivalence a = b to its output, but the (a) set outputs b as NULL, so a = b is false on those rows. EnforceSorting used the equivalence and rewrote the sort [a ASC NULLS LAST, b ASC NULLS FIRST] to [b ASC NULLS LAST]. A filter constant such as b = 1 fails the same way. #24422 fixed this on main by building the properties of a grouping-set aggregate from empty EquivalenceProperties. Its tests check that grouping sets do not pick ordered aggregation. Add cases to grouping.slt for the equivalence, the constant, a row_number() variant and the query from #16965, in the target_partitions = 1 block. Closes #16965. --- .../sqllogictest/test_files/grouping.slt | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/datafusion/sqllogictest/test_files/grouping.slt b/datafusion/sqllogictest/test_files/grouping.slt index ce6ea17d01d4a..850f73f56b1cb 100644 --- a/datafusion/sqllogictest/test_files/grouping.slt +++ b/datafusion/sqllogictest/test_files/grouping.slt @@ -123,6 +123,70 @@ LIMIT 10; statement ok RESET datafusion.execution.enable_migration_aggregate; +# a = b holds before the aggregate, but not after it: the (a) grouping set +# outputs b as NULL. +# (a, b) set: (1, 1), (2, 2) +# (a) set: (1, NULL), (2, NULL) +# So the sort must keep both a and b. Queries from PostgreSQL's groupingsets.sql. +query TT +EXPLAIN SELECT a, b FROM (VALUES (1, 1), (2, 2)) AS t (a, b) WHERE a = b +GROUP BY GROUPING SETS ((a, b), (a)) ORDER BY a, b NULLS FIRST; +---- +logical_plan +01)Sort: t.a ASC NULLS LAST, t.b ASC NULLS FIRST +02)--Projection: t.a, t.b +03)----Aggregate: groupBy=[[GROUPING SETS ((t.a, t.b), (t.a))]], aggr=[[]] +04)------SubqueryAlias: t +05)--------Projection: column1 AS a, column2 AS b +06)----------Filter: column2 = column1 +07)------------Values: (Int64(1), Int64(1)), (Int64(2), Int64(2)) +physical_plan +01)SortExec: expr=[a@0 ASC NULLS LAST, b@1 ASC], preserve_partitioning=[false] +02)--ProjectionExec: expr=[a@0 as a, b@1 as b] +03)----AggregateExec: mode=Final, gby=[a@0 as a, b@1 as b, __grouping_id@2 as __grouping_id], aggr=[] +04)------AggregateExec: mode=Partial, gby=[(a@0 as a, b@1 as b), (a@0 as a, NULL as b)], aggr=[] +05)--------ProjectionExec: expr=[column1@0 as a, column2@1 as b] +06)----------FilterExec: column2@1 = column1@0 +07)------------DataSourceExec: partitions=1, partition_sizes=[1] + +query II +SELECT a, b FROM (VALUES (1, 1), (2, 2)) AS t (a, b) WHERE a = b +GROUP BY GROUPING SETS ((a, b), (a)) ORDER BY a, b NULLS FIRST; +---- +1 NULL +1 1 +2 NULL +2 2 + +query III +SELECT a, b, row_number() OVER (ORDER BY a, b NULLS FIRST) +FROM (VALUES (1, 1), (2, 2)) AS t (a, b) WHERE a = b +GROUP BY GROUPING SETS ((a, b), (a)) ORDER BY a, b NULLS FIRST; +---- +1 NULL 1 +1 1 2 +2 NULL 3 +2 2 4 + +# Same for b = 1: the (a) set outputs (1, NULL), (2, NULL), so b stays in the sort. +query II +SELECT a, b FROM (VALUES (1, 1), (2, 1)) AS t (a, b) WHERE b = 1 +GROUP BY GROUPING SETS ((a, b), (a)) ORDER BY a, b NULLS FIRST; +---- +1 NULL +1 1 +2 NULL +2 1 + +# https://github.com/apache/datafusion/issues/16965: a constant, sorted input +# must still produce one row per grouping set. +query T rowsort +SELECT id FROM (SELECT 'id' AS id UNION ALL SELECT 'id' AS id ORDER BY id) +GROUP BY GROUPING SETS ((id), ()); +---- +NULL +id + statement ok SET datafusion.execution.target_partitions = 4;