From c5afc439a029cbb33bed914d5639abb85dc2af64 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Mon, 10 Nov 2025 17:05:42 +0900
Subject: [PATCH v1] Use exact nullingrels matches for NestLoopParams

We have been using NRM_SUBSET to process NestLoopParams in setrefs.c,
because Vars or PHVs in NestLoopParam expressions may previously have
had nullingrels that were just subsets of those in the Vars or PHVs
actually available from the outer side.

Since 66e9df9f6, identify_current_nestloop_params ensures that any
Vars or PHVs seen in a NestLoopParam expression have nullingrels that
include exactly the outer-join relids that appear in the outer side's
output and can null the respective Var or PHV.  As noted in that
commit's message, we can now safely use NRM_EQUAL to process
NestLoopParams in setrefs.c.

This patch makes that change and removes the definition of NRM_SUBSET,
along with all remaining checks for it, since it is no longer used.
---
 src/backend/optimizer/plan/setrefs.c | 29 ++++++++++------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index ccdc9bc264a..a4c220e47fb 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -34,7 +34,6 @@
 typedef enum
 {
 	NRM_EQUAL,					/* expect exact match of nullingrels */
-	NRM_SUBSET,					/* actual Var may have a subset of input */
 	NRM_SUPERSET,				/* actual Var may have a superset of input */
 } NullingRelsMatch;
 
@@ -2387,22 +2386,19 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 			NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
 
 			/*
-			 * Because we don't reparameterize parameterized paths to match
-			 * the outer-join level at which they are used, Vars seen in the
-			 * NestLoopParam expression may have nullingrels that are just a
-			 * subset of those in the Vars actually available from the outer
-			 * side.  (Lateral references can also cause this, as explained in
-			 * the comments for identify_current_nestloop_params.)  Not
-			 * checking this exactly is a bit grotty, but the work needed to
-			 * make things match up perfectly seems well out of proportion to
-			 * the value.
+			 * identify_current_nestloop_params has already ensured that any
+			 * Vars or PHVs seen in the NestLoopParam expression have
+			 * nullingrels that include exactly the outer-join relids that
+			 * appear in the outer side's output and can null the respective
+			 * Var or PHV.  So we can use exact nullingrels matches for the
+			 * NestLoopParam expression.
 			 */
 			nlp->paramval = (Var *) fix_upper_expr(root,
 												   (Node *) nlp->paramval,
 												   outer_itlist,
 												   OUTER_VAR,
 												   rtoffset,
-												   NRM_SUBSET,
+												   NRM_EQUAL,
 												   NUM_EXEC_TLIST(outer_plan));
 			/* Check we replaced any PlaceHolderVar with simple Var */
 			if (!(IsA(nlp->paramval, Var) &&
@@ -2882,8 +2878,7 @@ build_tlist_index_other_vars(List *tlist, int ignore_rel)
  * We cross-check the varnullingrels of the subplan output Var based on
  * nrm_match.  Most call sites should pass NRM_EQUAL indicating we expect
  * an exact match.  However, there are places where we haven't cleaned
- * things up completely, and we have to settle for allowing subset or
- * superset matches.
+ * things up completely, and we have to settle for allowing superset matches.
  */
 static Var *
 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
@@ -2919,9 +2914,7 @@ search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
 			 * would affect only system columns.)
 			 */
 			if (!(varattno <= 0 ||
-				  (nrm_match == NRM_SUBSET ?
-				   bms_is_subset(var->varnullingrels, vinfo->varnullingrels) :
-				   nrm_match == NRM_SUPERSET ?
+				  (nrm_match == NRM_SUPERSET ?
 				   bms_is_subset(vinfo->varnullingrels, var->varnullingrels) :
 				   bms_equal(vinfo->varnullingrels, var->varnullingrels))))
 				elog(ERROR, "wrong varnullingrels %s (expected %s) for Var %d/%d",
@@ -2975,9 +2968,7 @@ search_indexed_tlist_for_phv(PlaceHolderVar *phv,
 				continue;
 
 			/* Verify that we kept all the nullingrels machinations straight */
-			if (!(nrm_match == NRM_SUBSET ?
-				  bms_is_subset(phv->phnullingrels, subphv->phnullingrels) :
-				  nrm_match == NRM_SUPERSET ?
+			if (!(nrm_match == NRM_SUPERSET ?
 				  bms_is_subset(subphv->phnullingrels, phv->phnullingrels) :
 				  bms_equal(subphv->phnullingrels, phv->phnullingrels)))
 				elog(ERROR, "wrong phnullingrels %s (expected %s) for PlaceHolderVar %d",
-- 
2.39.5 (Apple Git-154)

