From be603a87641bf14eacb87113f1aa4c89dd2c0f32 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Sat, 12 Sep 2026 21:34:17 +0530 Subject: [PATCH v1] Fix zero-column UNION with parallel plans generate_union_paths() skips adding a Sort above an Append path for a zero-column UNION, since such a set operation has no grouping columns. The Gather path did not have the same check and could therefore produce a Sort with no sort keys. tuplesort_begin_heap() does not support that and fails its nkeys > 0 assertion. Apply the same guard to the Gather path. Test with populated relations so the test also exercises tuple processing in non-assert builds. Reported-by: Alexander Lakhin Bug: #19684 Backpatch-through: 17 --- src/backend/optimizer/prep/prepunion.c | 3 ++- src/test/regress/expected/union.out | 21 +++++++++++++++++++++ src/test/regress/sql/union.sql | 11 +++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index b136f12ff3b..0270f1e6b39 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -987,7 +987,8 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, { path = gpath; - path = (Path *) create_sort_path(root, result_rel, path, + if (groupList != NIL) + path = (Path *) create_sort_path(root, result_rel, path, make_pathkeys_for_sortclauses(root, groupList, tlist), -1.0); diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index 84abcd6b14f..defc111478f 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -1085,6 +1085,27 @@ select from cte union select from cte; -- (1 row) +-- Ensure no sort is added to a parallel plan with no sort keys +set cpu_tuple_cost = 1000; +set min_parallel_table_scan_size = 1; +explain (costs off) +select from tenk1 union select from tenk1; + QUERY PLAN +------------------------------------------------------ + Unique + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Seq Scan on tenk1 + -> Parallel Seq Scan on tenk1 tenk1_1 +(6 rows) + +select from tenk1 union select from tenk1; +-- +(1 row) + +reset cpu_tuple_cost; +reset min_parallel_table_scan_size; reset enable_hashagg; reset enable_groupagg; -- diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index c8de276c2b5..c1f00ef171d 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -362,6 +362,17 @@ select from cte union select from cte; with cte as not materialized (select s from generate_series(1,5) s) select from cte union select from cte; +-- Ensure no sort is added to a parallel plan with no sort keys +set cpu_tuple_cost = 1000; +set min_parallel_table_scan_size = 1; + +explain (costs off) +select from tenk1 union select from tenk1; +select from tenk1 union select from tenk1; + +reset cpu_tuple_cost; +reset min_parallel_table_scan_size; + reset enable_hashagg; reset enable_groupagg; -- 2.34.1