From 32c4b647ec492a20b159c546a24a021a45360c6b Mon Sep 17 00:00:00 2001
From: Amit Langote <amitlan@postgresql.org>
Date: Wed, 24 Jun 2026 13:22:11 +0900
Subject: [PATCH v1] Avoid ABI break in ModifyTableState from the FDW pruning
 fix

Commit 1ef917e3a6 fixed the re-indexing of ModifyTable's FDW arrays
when initial runtime pruning removes result relations, but it did so
by adding a new mt_fdwPrivLists field to ModifyTableState.  Although
the field was placed at the end of the struct to keep the offsets of
existing fields stable, it still enlarges sizeof(ModifyTableState),
which the ABI compliance check flags on the buildfarm (e.g. crake).

The field existed only so that show_modifytable_info() could recover the
re-indexed fdw_private after executor startup; the executor-side fix in
ExecInitModifyTable() that actually prevents the crash does not depend on
it.  Remove the field and have show_modifytable_info() instead look up
each kept relation's fdw_private from the original, pre-pruning
node->fdwPrivLists, which is parallel to node->resultRelations and is
left intact by pruning, by matching on the range table index.

This is applied to REL_18 only; master keeps the mt_fdwPrivLists field
and is unaffected, so the two diverge slightly here.

Reported on the buildfarm (member crake).

Per a suggestion from Tom Lane.

Discussion: https://postgr.es/m/CA+HiwqEhe7-v5Q0-oOoW3RaO4voYcGK-JfinbYEWXwutDGSOtQ@mail.gmail.com
---
 src/backend/commands/explain.c         | 21 ++++++++++++++++++++-
 src/backend/executor/nodeModifyTable.c |  1 -
 src/include/nodes/execnodes.h          |  8 +++-----
 3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 6d2624e75b8..7aa6636af5f 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -4609,7 +4609,26 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
 			fdwroutine != NULL &&
 			fdwroutine->ExplainForeignModify != NULL)
 		{
-			List	   *fdw_private = (List *) list_nth(mtstate->mt_fdwPrivLists, j);
+			Index		rti = resultRelInfo->ri_RangeTableIndex;
+			List	   *fdw_private = NIL;
+			ListCell   *lc1;
+			ListCell   *lc2;
+
+			/*
+			 * node->fdwPrivLists is indexed by the original, pre-pruning
+			 * result relation order and is parallel to node->resultRelations.
+			 * Initial pruning may have dropped earlier relations, so the kept
+			 * index j need not match the original position; find this
+			 * relation's entry by its range table index instead.
+			 */
+			forboth(lc1, node->resultRelations, lc2, node->fdwPrivLists)
+			{
+				if (lfirst_int(lc1) == (int) rti)
+				{
+					fdw_private = (List *) lfirst(lc2);
+					break;
+				}
+			}
 
 			fdwroutine->ExplainForeignModify(mtstate,
 											 resultRelInfo,
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index cac30666663..7c1d0e9588e 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -4770,7 +4770,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 	mtstate->mt_updateColnosLists = updateColnosLists;
 	mtstate->mt_mergeActionLists = mergeActionLists;
 	mtstate->mt_mergeJoinConditions = mergeJoinConditions;
-	mtstate->mt_fdwPrivLists = fdwPrivLists;
 
 	/*----------
 	 * Resolve the target relation. This is the same as:
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 6677a03caab..409e172bfb6 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1453,15 +1453,13 @@ typedef struct ModifyTableState
 	double		mt_merge_deleted;
 
 	/*
-	 * Lists of valid updateColnosLists, mergeActionLists,
-	 * mergeJoinConditions, and fdwPrivLists.  These contain only entries for
-	 * unpruned relations, filtered from the corresponding lists in
-	 * ModifyTable.
+	 * Lists of valid updateColnosLists, mergeActionLists, and
+	 * mergeJoinConditions.  These contain only entries for unpruned
+	 * relations, filtered from the corresponding lists in ModifyTable.
 	 */
 	List	   *mt_updateColnosLists;
 	List	   *mt_mergeActionLists;
 	List	   *mt_mergeJoinConditions;
-	List	   *mt_fdwPrivLists;
 } ModifyTableState;
 
 /* ----------------
-- 
2.47.3

