v4-0001-Fix-incorrect-use-of-targetlist-in-dummy-UNIONs.patch
application/octet-stream
Filename: v4-0001-Fix-incorrect-use-of-targetlist-in-dummy-UNIONs.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v4-0001
Subject: Fix incorrect use of targetlist in dummy UNIONs
| File | + | − |
|---|---|---|
| src/backend/optimizer/plan/setrefs.c | 20 | 4 |
| src/backend/optimizer/prep/prepunion.c | 0 | 1 |
| src/test/regress/expected/union.out | 11 | 7 |
| src/test/regress/sql/union.sql | 2 | 1 |
From 44bbaa642fe09f38fb0d49434b236ac5c1621a3d Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Sat, 4 Oct 2025 16:26:32 +1300
Subject: [PATCH v4 1/2] Fix incorrect use of targetlist in dummy UNIONs
I had thought that using the targetlist of the first UNION child was ok,
but it's not as this could cause:
ERROR: could not find pathkey item to sort
Instead, use the top-level UNION's targetlist and fix setrefs.c so it
rewrites the varno==0 Vars into varno==1 vars so that we display the
targetlist item from the first UNION child. If we didn't do this,
EXPLAIN VERBOSE would give us something like:
ERROR: bogus varno: 0
---
src/backend/optimizer/plan/setrefs.c | 24 ++++++++++++++++++++----
src/backend/optimizer/prep/prepunion.c | 1 -
src/test/regress/expected/union.out | 18 +++++++++++-------
src/test/regress/sql/union.sql | 3 ++-
4 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 6950eff2c5b..10d0cc4c2d3 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1034,16 +1034,32 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
* expected to occur here, it seems safer to special-case
* it here and keep the assertions that ROWID_VARs
* shouldn't be seen by fix_scan_expr.
+ *
+ * We also must handle the case where set operations have
+ * been short-circuited resulting in a dummy Result node.
+ * prepunion.c uses varno==0 for the set op targetlist.
+ * Rewrite these to use varno==1. Otherwise EXPLAIN will
+ * have trouble displaying targetlists.
*/
foreach(l, splan->plan.targetlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
Var *var = (Var *) tle->expr;
- if (var && IsA(var, Var) && var->varno == ROWID_VAR)
- tle->expr = (Expr *) makeNullConst(var->vartype,
- var->vartypmod,
- var->varcollid);
+ if (var && IsA(var, Var))
+ {
+ if (var->varno == ROWID_VAR)
+ tle->expr = (Expr *) makeNullConst(var->vartype,
+ var->vartypmod,
+ var->varcollid);
+ else if (var->varno == 0)
+ tle->expr = (Expr *) makeVar(1,
+ var->varattno,
+ var->vartype,
+ var->vartypmod,
+ var->varcollid,
+ var->varlevelsup);
+ }
}
splan->plan.targetlist =
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 547dbd53540..da9431108a2 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -826,7 +826,6 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
/* If all UNION children were dummy rels, make the resulting rel dummy */
if (cheapest_pathlist == NIL)
{
- result_rel->reltarget = create_pathtarget(root, list_nth(tlist_list, 0));
mark_dummy_rel(result_rel);
return result_rel;
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out
index 7c089e0d598..15931beea3a 100644
--- a/src/test/regress/expected/union.out
+++ b/src/test/regress/expected/union.out
@@ -1258,14 +1258,18 @@ SELECT two FROM tenk1 WHERE 1=2
UNION
SELECT four FROM tenk1 WHERE 1=2
UNION
-SELECT ten FROM tenk1 WHERE 1=2;
- QUERY PLAN
---------------------------------
- Result
+SELECT ten FROM tenk1 WHERE 1=2
+ORDER BY 1;
+ QUERY PLAN
+--------------------------------------
+ Sort
Output: unnamed_subquery.two
- Replaces: Aggregate
- One-Time Filter: false
-(4 rows)
+ Sort Key: unnamed_subquery.two
+ -> Result
+ Output: unnamed_subquery.two
+ Replaces: Aggregate
+ One-Time Filter: false
+(7 rows)
-- Test constraint exclusion of UNION ALL subqueries
explain (costs off)
diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql
index 56bd20e741c..e252316f69b 100644
--- a/src/test/regress/sql/union.sql
+++ b/src/test/regress/sql/union.sql
@@ -484,7 +484,8 @@ SELECT two FROM tenk1 WHERE 1=2
UNION
SELECT four FROM tenk1 WHERE 1=2
UNION
-SELECT ten FROM tenk1 WHERE 1=2;
+SELECT ten FROM tenk1 WHERE 1=2
+ORDER BY 1;
-- Test constraint exclusion of UNION ALL subqueries
explain (costs off)
--
2.43.0