v4-0001-add-UPDATE-FOR-PORTION-OF-col-to-ExecGetUpdatedCols.no-cfbot

application/octet-stream

Filename: v4-0001-add-UPDATE-FOR-PORTION-OF-col-to-ExecGetUpdatedCols.no-cfbot
Type: application/octet-stream
Part: 0
Message: Re: FOR PORTION OF does not recompute GENERATED STORED columns that depend on the range column
From 222056ec0ce0374fcaa9f64ac73ec0896ac979c2 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 17 Apr 2026 16:03:44 +0800
Subject: [PATCH v4 1/1] add UPDATE FOR PORTION OF col to ExecGetUpdatedCols

Discussion: https://postgr.es/m/CAHg+QDcd=t69gLf9yQexO07EJ2mx0Z70NFHo6h94X1EDA=hM0g@mail.gmail.com
Discussion: https://postgr.es/m/CAHg+QDcsXsUVaZ+JwM02yDRQEi=cL_rTH_ROLDYgOx004sQu7A@mail.gmail.com
---
 src/backend/executor/execUtils.c       | 47 ++++++++++++++------------
 src/backend/executor/nodeModifyTable.c | 15 --------
 2 files changed, 25 insertions(+), 37 deletions(-)

diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 5df7f2edf85..2c0ab1c0214 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1412,6 +1412,31 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
 	if (perminfo == NULL)
 		return NULL;
 
+	/*
+	 * For UPDATE ... FOR PORTION OF, the range column is being modified
+	 * (narrowed via intersection), but it is not included in updatedCols
+	 * because the user does not need UPDATE permission on it. Now mannualy
+	 * add it to updatedCols.
+	 */
+	if (relinfo->ri_forPortionOf)
+	{
+		AttrNumber	rangeAttno = relinfo->ri_forPortionOf->fp_rangeAttno;
+
+		if (!bms_is_member(rangeAttno - FirstLowInvalidHeapAttributeNumber,
+						   perminfo->updatedCols))
+		{
+			MemoryContext oldContext;
+
+			oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+			perminfo->updatedCols =
+				bms_add_member(perminfo->updatedCols,
+							   rangeAttno - FirstLowInvalidHeapAttributeNumber);
+
+			MemoryContextSwitchTo(oldContext);
+		}
+	}
+
 	/* Map the columns to child's attribute numbers if needed. */
 	if (relinfo->ri_RootResultRelInfo)
 	{
@@ -1430,29 +1455,7 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
 {
 	/* Compute the info if we didn't already */
 	if (!relinfo->ri_extraUpdatedCols_valid)
-	{
-		if (relinfo->ri_forPortionOf)
-		{
-			MemoryContext oldContext;
-
-			AttrNumber	rangeAttno = relinfo->ri_forPortionOf->fp_rangeAttno;
-
-			oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
-
-			/*
-			 * For UPDATE ... FOR PORTION OF, the range column is actually
-			 * being modified (narrowed via intersection), but it is not
-			 * included in updatedCols because the user does not need UPDATE
-			 * permission on it. So we need to add it to ri_extraUpdatedCols
-			 */
-			relinfo->ri_extraUpdatedCols =
-				bms_add_member(relinfo->ri_extraUpdatedCols, rangeAttno - FirstLowInvalidHeapAttributeNumber);
-
-			MemoryContextSwitchTo(oldContext);
-		}
-
 		ExecInitGenerated(relinfo, estate, CMD_UPDATE);
-	}
 	return relinfo->ri_extraUpdatedCols;
 }
 
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 4395089565f..7af0268646b 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -477,21 +477,6 @@ ExecInitGenerated(ResultRelInfo *resultRelInfo,
 	else
 		updatedCols = NULL;
 
-	/*
-	 * For UPDATE ... FOR PORTION OF, the range column is also being modified
-	 * (narrowed via intersection), but it is not included in updatedCols
-	 * because the user does not need UPDATE permission on it.  We must
-	 * account for it here so that generated columns referencing the range
-	 * column are recomputed.
-	 */
-	if (resultRelInfo->ri_forPortionOf)
-	{
-		AttrNumber	rangeAttno = resultRelInfo->ri_forPortionOf->fp_rangeAttno;
-
-		updatedCols = bms_add_member(bms_copy(updatedCols),
-									 rangeAttno - FirstLowInvalidHeapAttributeNumber);
-	}
-
 	/*
 	 * Make sure these data structures are built in the per-query memory
 	 * context so they'll survive throughout the query.
-- 
2.34.1