From 3c3015f5c51d8501ac9f3bb79c4d83901519da04 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 25 Jul 2026 10:46:29 -0400
Subject: [PATCH v2 1/3] Postpone initialization of
 all_result_relids/leaf_result_relids.

Nothing actually pays attention to these PlannerInfo fields
before add_other_rels_to_query(), since they're not really
useful until that function has finished filling them in.
By delaying their setup until just before we call that function,
we can remove them from the set of things that join removal
has to worry about.  (It was already not doing anything with
them, but now we do not need an argument why that's okay.)

This is just some minor refactoring before the main patch
to deal with bug #19560.

Bug: #19560
Reported-by: Orestis Markou <orestis@orestis.gr>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/1186816.1784573544@sss.pgh.pa.us
---
 src/backend/optimizer/plan/analyzejoins.c | 11 -----------
 src/backend/optimizer/plan/planmain.c     | 17 +++++++++++++++++
 src/backend/optimizer/plan/planner.c      | 18 ++----------------
 3 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 881950e5264..e1af49d3dea 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -2178,17 +2178,6 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
 	ChangeVarNodesExtended((Node *) root->processed_tlist, toRemove->relid,
 						   toKeep->relid, 0, replace_relid_callback);
 
-	/*
-	 * No need to touch all_result_relids or leaf_result_relids: at this point
-	 * those sets contain only parse->resultRelation; inheritance children
-	 * have not been added yet; that happens later in add_other_rels_to_query.
-	 * And remove_self_joins_recurse rejects parse->resultRelation as an SJE
-	 * candidate to preserve the EPQ mechanism.  So toRemove->relid cannot be
-	 * a member.
-	 */
-	Assert(!bms_is_member(toRemove->relid, root->all_result_relids));
-	Assert(!bms_is_member(toRemove->relid, root->leaf_result_relids));
-
 	/*
 	 * There may be references to the rel in root->fkey_list, but if so,
 	 * match_foreign_keys_to_quals() will get rid of them.
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index 02495e22e24..c123a397c1a 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -28,6 +28,7 @@
 #include "optimizer/paths.h"
 #include "optimizer/placeholder.h"
 #include "optimizer/planmain.h"
+#include "parser/parsetree.h"
 
 
 /*
@@ -274,6 +275,22 @@ query_planner(PlannerInfo *root,
 	 */
 	setup_eager_aggregation(root);
 
+	/*
+	 * If there's a result relation, initialize all_result_relids to include
+	 * it; and if we've verified that it is non-inheriting, mark it as a leaf
+	 * target.  add_other_rels_to_query() will expand these sets if the result
+	 * relation has children.
+	 */
+	if (parse->resultRelation)
+	{
+		RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable);
+
+		root->all_result_relids = bms_make_singleton(parse->resultRelation);
+		if (!rte->inh)
+			root->leaf_result_relids =
+				bms_make_singleton(parse->resultRelation);
+	}
+
 	/*
 	 * Now expand appendrels by adding "otherrels" for their children.  We
 	 * delay this to the end so that we have as much information as possible
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 3225185d16f..16ad18babaa 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -803,9 +803,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name,
 	root->eq_classes = NIL;
 	root->ec_merging_done = false;
 	root->last_rinfo_serial = 0;
-	root->all_result_relids =
-		parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL;
-	root->leaf_result_relids = NULL;	/* we'll find out leaf-ness later */
+	root->all_result_relids = NULL;
+	root->leaf_result_relids = NULL;
 	root->append_rel_list = NIL;
 	root->row_identity_vars = NIL;
 	root->rowMarks = NIL;
@@ -976,19 +975,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name,
 											list_length(rte->securityQuals));
 	}
 
-	/*
-	 * If we have now verified that the query target relation is
-	 * non-inheriting, mark it as a leaf target.
-	 */
-	if (parse->resultRelation)
-	{
-		RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable);
-
-		if (!rte->inh)
-			root->leaf_result_relids =
-				bms_make_singleton(parse->resultRelation);
-	}
-
 	/*
 	 * This would be a convenient time to check access permissions for all
 	 * relations mentioned in the query, since it would be better to fail now,
-- 
2.52.0

