From f738f351e992ac4d87bbdf11fcce8c61d4dc99d8 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 23 Jul 2026 14:30:56 +0000
Subject: [PATCH 2/2] Remove the vestigial range_name field of ForPortionOfExpr

The preceding commit stopped relying on the range column name recorded
in ForPortionOfExpr, since a stored copy of the node can outlive the
column name it was parsed from.  Nothing reads the field now, so remove
it rather than leave a trap for the next reader.

ForPortionOfState.fp_rangeName goes too; it was only ever copied from
range_name, and was never read at all.  The one remaining use of the
recorded name, the resname of the TargetEntry that sets the range
column, can come from the relation's tuple descriptor instead.

This can't be back-patched, as it changes the stored form of rules.

XXX: needs catversion bump

Discussion: https://postgr.es/m/CANWCAZYFEpJ5Oi45gi4q9Y6LYa4_oiAXxuNNWe-1ym-i0fF8Pw@mail.gmail.com

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 src/backend/executor/nodeModifyTable.c |  2 --
 src/backend/parser/analyze.c           |  3 +--
 src/include/nodes/execnodes.h          |  1 -
 src/include/nodes/primnodes.h          | 12 ++++--------
 4 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b9781eb3b95..1dbf0ffff9e 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -5641,7 +5641,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 		/* Create state for FOR PORTION OF operation */
 
 		fpoState = makeNode(ForPortionOfState);
-		fpoState->fp_rangeName = forPortionOf->range_name;
 		fpoState->fp_rangeType = forPortionOf->rangeType;
 		fpoState->fp_rangeAttno = forPortionOf->rangeVar->varattno;
 		fpoState->fp_targetRange = targetRange;
@@ -5928,7 +5927,6 @@ ExecInitForPortionOf(ModifyTableState *mtstate, EState *estate,
 
 	leafState = makeNode(ForPortionOfState);
 
-	leafState->fp_rangeName = fpoState->fp_rangeName;
 	leafState->fp_rangeType = fpoState->fp_rangeType;
 	leafState->fp_targetRange = fpoState->fp_targetRange;
 	map = ExecGetChildToRootMap(resultRelInfo);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 562e4facd74..adc98c1c969 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1596,7 +1596,7 @@ transformForPortionOfClause(ParseState *pstate,
 		/* Make a TLE to set the range column */
 		result->rangeTargetList = NIL;
 		tle = makeTargetEntry((Expr *) rangeTLEExpr, range_attno,
-							  forPortionOf->range_name, false);
+							  pstrdup(NameStr(attr->attname)), false);
 		result->rangeTargetList = lappend(result->rangeTargetList, tle);
 
 		/* Mark the range column as requiring update permissions */
@@ -1606,7 +1606,6 @@ transformForPortionOfClause(ParseState *pstate,
 	else
 		result->rangeTargetList = NIL;
 
-	result->range_name = forPortionOf->range_name;
 	result->location = forPortionOf->location;
 	result->targetLocation = forPortionOf->target_location;
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e64fd8c7ea3..e95ac3eda35 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -476,7 +476,6 @@ typedef struct ForPortionOfState
 {
 	NodeTag		type;
 
-	char	   *fp_rangeName;	/* the column named in FOR PORTION OF */
 	Oid			fp_rangeType;	/* the base type (not domain) of the FOR
 								 * PORTION OF expression */
 	int			fp_rangeAttno;	/* the attno of the range column */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index c6be41280c2..dbd35e7777b 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -2427,20 +2427,16 @@ typedef struct OnConflictExpr
  * In the executor we'll also build an intersect expression between the
  * targeted range and the range column, so that we can update the start/end
  * bounds of the UPDATE'd record.
+ *
+ * Note that the range column is identified only by rangeVar.  We must not
+ * record its name here, because this node can be stored on disk (in a rule
+ * or a SQL function body) and the column could be renamed afterwards.
  *----------
  */
 typedef struct ForPortionOfExpr
 {
 	NodeTag		type;
 	Var		   *rangeVar;		/* Range column */
-
-	/*
-	 * Don't use range_name to identify the range column: since this node can
-	 * be stored on disk, in a rule or a SQL function body, the name recorded
-	 * here can be stale if the column has been renamed since.  Use
-	 * rangeVar->varattno and consult the catalogs.
-	 */
-	char	   *range_name;		/* Range name (unreliable, see above) */
 	Node	   *targetFrom;		/* FOR PORTION OF FROM bound, if given */
 	Node	   *targetTo;		/* FOR PORTION OF TO bound, if given */
 	Node	   *targetRange;	/* FOR PORTION OF bounds as a range/multirange */
-- 
2.53.0

