v1-0001-Fix-how-SJE-checks-against-PHVs.patch

application/octet-stream

Filename: v1-0001-Fix-how-SJE-checks-against-PHVs.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #18187: Unexpected error: "variable not found in subplan target lists" triggered by JOIN

Patch

Format: format-patch
Series: patch v1-0001
Subject: Fix how SJE checks against PHVs
File+
src/backend/optimizer/plan/analyzejoins.c 2 2
src/test/regress/expected/join.out 14 0
src/test/regress/sql/join.sql 5 0
From 6438e8845234dbf9e47a3213390a4d7b60844ca3 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Fri, 10 Nov 2023 15:35:11 +0800
Subject: [PATCH v1] Fix how SJE checks against PHVs

Do not remove self joins if the rel to be removed is laterally referenced by
PHVs.
---
 src/backend/optimizer/plan/analyzejoins.c |  4 ++--
 src/test/regress/expected/join.out        | 14 ++++++++++++++
 src/test/regress/sql/join.sql             |  5 +++++
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 271f694d99..b9be19a687 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -476,7 +476,6 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
 			phv->phrels = replace_relid(phv->phrels, ojrelid, subst);
 			Assert(!bms_is_empty(phv->phrels));
 			replace_varno((Node *) phv->phexpr, relid, subst);
-			phinfo->ph_lateral = replace_relid(phinfo->ph_lateral, relid, subst);
 			Assert(phv->phnullingrels == NULL); /* no need to adjust */
 		}
 	}
@@ -2134,7 +2133,8 @@ remove_self_joins_one_group(PlannerInfo *root, Relids relids)
 
 				/* there isn't any other place to eval PHV */
 				if (bms_is_subset(phinfo->ph_eval_at, joinrelids) ||
-					bms_is_subset(phinfo->ph_needed, joinrelids))
+					bms_is_subset(phinfo->ph_needed, joinrelids) ||
+					bms_is_member(r, phinfo->ph_lateral))
 					break;
 			}
 			if (lc)
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index b60f5a67c1..3cc8fd6e6d 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -6821,6 +6821,20 @@ on true;
                            Filter: (id IS NOT NULL)
 (8 rows)
 
+-- Check that SJE does not remove self joins if a PHV references the removed rel laterally
+explain (costs off)
+select * from emp1 t1 join emp1 t2 on t1.id = t2.id left join
+    lateral (select t1.id as t1id, * from generate_series(1,1) t3) s on true;
+                    QUERY PLAN                     
+---------------------------------------------------
+ Nested Loop Left Join
+   ->  Nested Loop
+         ->  Seq Scan on emp1 t1
+         ->  Index Scan using emp1_pkey on emp1 t2
+               Index Cond: (id = t1.id)
+   ->  Function Scan on generate_series t3
+(6 rows)
+
 -- We can remove the join even if we find the join can't duplicate rows and
 -- the base quals of each side are different.  In the following case we end up
 -- moving quals over to s1 to make it so it can't match any rows.
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index fbaee480d3..670379129c 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -2600,6 +2600,11 @@ select * from emp1 t1 left join
         on true)
 on true;
 
+-- Check that SJE does not remove self joins if a PHV references the removed rel laterally
+explain (costs off)
+select * from emp1 t1 join emp1 t2 on t1.id = t2.id left join
+    lateral (select t1.id as t1id, * from generate_series(1,1) t3) s on true;
+
 -- We can remove the join even if we find the join can't duplicate rows and
 -- the base quals of each side are different.  In the following case we end up
 -- moving quals over to s1 to make it so it can't match any rows.
-- 
2.31.0