From dc4b6235a0150de2a1e15f315dee550cc4ccdd92 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Wed, 31 May 2023 14:17:11 +0800
Subject: [PATCH v1] Fix nulling bitmap for nestloop parameters

---
 src/backend/optimizer/util/paramassign.c | 12 ++++++++++++
 src/test/regress/expected/join.out       | 16 ++++++++++++++++
 src/test/regress/sql/join.sql            |  5 +++++
 3 files changed, 33 insertions(+)

diff --git a/src/backend/optimizer/util/paramassign.c b/src/backend/optimizer/util/paramassign.c
index 66534c0a78..192e1752e9 100644
--- a/src/backend/optimizer/util/paramassign.c
+++ b/src/backend/optimizer/util/paramassign.c
@@ -503,6 +503,14 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
  * Identify any NestLoopParams that should be supplied by a NestLoop plan
  * node with the specified lefthand rels.  Remove them from the active
  * root->curOuterParams list and return them as the result list.
+ *
+ * We also need to adjust the nulling bitmap for them, for the case that we
+ * have transformed the first form of identity 3 to the second form.  In such
+ * case, the selected params should not have the A/B join in their nulling
+ * bitmap.  (Note there is no problem when identity 3 is applied in the other
+ * direction, because setrefs.c only checks that the nullingrels in
+ * NestLoopParams are just a subset of those in the Vars actually available
+ * from the outer.)
  */
 List *
 identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids)
@@ -524,6 +532,8 @@ identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids)
 		{
 			root->curOuterParams = foreach_delete_current(root->curOuterParams,
 														  cell);
+			nlp->paramval->varnullingrels =
+				bms_intersect(nlp->paramval->varnullingrels, leftrelids);
 			result = lappend(result, nlp);
 		}
 		else if (IsA(nlp->paramval, PlaceHolderVar) &&
@@ -533,6 +543,8 @@ identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids)
 		{
 			root->curOuterParams = foreach_delete_current(root->curOuterParams,
 														  cell);
+			((PlaceHolderVar *) nlp->paramval)->phnullingrels =
+				bms_intersect(((PlaceHolderVar *) nlp->paramval)->phnullingrels, leftrelids);
 			result = lappend(result, nlp);
 		}
 	}
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 4c278b2fa3..681d30c608 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2589,6 +2589,22 @@ on t2.q2 = 123;
                ->  Seq Scan on int8_tbl t5
 (12 rows)
 
+explain (costs off)
+select * from int8_tbl t1
+	left join int8_tbl t2 on true
+	left join lateral (select * from int8_tbl t3 where t3.q1 = t2.q1 offset 0) s on t2.q1 = 1;
+                QUERY PLAN                 
+-------------------------------------------
+ Nested Loop Left Join
+   ->  Seq Scan on int8_tbl t1
+   ->  Materialize
+         ->  Nested Loop Left Join
+               Join Filter: (t2.q1 = 1)
+               ->  Seq Scan on int8_tbl t2
+               ->  Seq Scan on int8_tbl t3
+                     Filter: (q1 = t2.q1)
+(8 rows)
+
 --
 -- check a case where we formerly got confused by conflicting sort orders
 -- in redundant merge join path keys
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 4baf5ebc13..862335bda9 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -514,6 +514,11 @@ select * from int8_tbl t1 left join
     left join int8_tbl t5 on t2.q1 = t5.q1
 on t2.q2 = 123;
 
+explain (costs off)
+select * from int8_tbl t1
+	left join int8_tbl t2 on true
+	left join lateral (select * from int8_tbl t3 where t3.q1 = t2.q1 offset 0) s on t2.q1 = 1;
+
 --
 -- check a case where we formerly got confused by conflicting sort orders
 -- in redundant merge join path keys
-- 
2.31.0

