v6-0001-misc-fix-based-on-v5.no-cfbot

application/octet-stream

Filename: v6-0001-misc-fix-based-on-v5.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 70522698f357ecc14e1877c43465e6308d46bdd0 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Tue, 21 Apr 2026 11:53:32 +0800
Subject: [PATCH v6 1/1] misc fix based on v5

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             | 35 +++++++++++++++----
 src/test/regress/expected/for_portion_of.out | 36 ++++++++++----------
 src/test/regress/sql/for_portion_of.sql      |  2 +-
 3 files changed, 48 insertions(+), 25 deletions(-)

diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 29a8d3aba74..fb69832dbeb 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1409,7 +1409,6 @@ Bitmapset *
 ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
 {
 	RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
-	Bitmapset *updatedCols = perminfo->updatedCols;
 
 	if (perminfo == NULL)
 		return NULL;
@@ -1420,7 +1419,31 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
 		TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
 
 		if (map)
-			updatedCols = execute_attr_map_cols(map->attrMap, updatedCols);
+		{
+			/* See below */
+			if (relinfo->ri_forPortionOf)
+			{
+				AttrNumber	rangeAttno = relinfo->ri_forPortionOf->fp_rangeAttno;
+
+				rangeAttno = map->attrMap->attnums[rangeAttno - 1];
+
+				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);
+				}
+			}
+
+			return execute_attr_map_cols(map->attrMap, perminfo->updatedCols);
+		}
 	}
 
 	/*
@@ -1438,21 +1461,21 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
 		AttrNumber	rangeAttno = relinfo->ri_forPortionOf->fp_rangeAttno;
 
 		if (!bms_is_member(rangeAttno - FirstLowInvalidHeapAttributeNumber,
-						   updatedCols))
+						   perminfo->updatedCols))
 		{
 			MemoryContext oldContext;
 
 			oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
 
-			updatedCols =
-				bms_add_member(updatedCols,
+			perminfo->updatedCols =
+				bms_add_member(perminfo->updatedCols,
 							   rangeAttno - FirstLowInvalidHeapAttributeNumber);
 
 			MemoryContextSwitchTo(oldContext);
 		}
 	}
 
-	return updatedCols;
+	return perminfo->updatedCols;
 }
 
 /* Return a bitmap representing generated columns being updated */
diff --git a/src/test/regress/expected/for_portion_of.out b/src/test/regress/expected/for_portion_of.out
index 602aca6e6aa..273d710f895 100644
--- a/src/test/regress/expected/for_portion_of.out
+++ b/src/test/regress/expected/for_portion_of.out
@@ -2064,24 +2064,24 @@ UPDATE temporal_partitioned FOR PORTION OF valid_at FROM '2000-06-01' TO '2000-0
       id = '[3,4)'
   WHERE id = '[5,6)';
 -- Update all partitions at once (each with leftovers)
-SELECT * FROM temporal_partitioned ORDER BY id, valid_at;
-  id   |        valid_at         |  name   | range_len 
--------+-------------------------+---------+-----------
- [1,2) | [2000-01-01,2000-03-01) | one     |        60
- [1,2) | [2000-03-01,2000-04-01) | one^1   |        31
- [1,2) | [2000-04-01,2000-06-01) | one     |        61
- [1,2) | [2000-07-01,2010-01-01) | one     |      3471
- [2,3) | [2000-06-01,2000-07-01) | three^2 |        30
- [3,4) | [2000-01-01,2000-03-01) | three   |        60
- [3,4) | [2000-03-01,2000-04-01) | three^1 |        31
- [3,4) | [2000-04-01,2000-06-01) | three   |        61
- [3,4) | [2000-06-01,2000-07-01) | five^2  |        30
- [3,4) | [2000-07-01,2010-01-01) | three   |      3471
- [4,5) | [2000-06-01,2000-07-01) | one^2   |        30
- [5,6) | [2000-01-01,2000-03-01) | five    |        60
- [5,6) | [2000-03-01,2000-04-01) | five^1  |        31
- [5,6) | [2000-04-01,2000-06-01) | five    |        61
- [5,6) | [2000-07-01,2010-01-01) | five    |      3471
+SELECT *, upper(valid_at) - lower(valid_at) as range_len1 FROM temporal_partitioned ORDER BY id, valid_at;
+  id   |        valid_at         |  name   | range_len | range_len1 
+-------+-------------------------+---------+-----------+------------
+ [1,2) | [2000-01-01,2000-03-01) | one     |        60 |         60
+ [1,2) | [2000-03-01,2000-04-01) | one^1   |        31 |         31
+ [1,2) | [2000-04-01,2000-06-01) | one     |        61 |         61
+ [1,2) | [2000-07-01,2010-01-01) | one     |      3471 |       3471
+ [2,3) | [2000-06-01,2000-07-01) | three^2 |        30 |         30
+ [3,4) | [2000-01-01,2000-03-01) | three   |        60 |         60
+ [3,4) | [2000-03-01,2000-04-01) | three^1 |        31 |         31
+ [3,4) | [2000-04-01,2000-06-01) | three   |        61 |         61
+ [3,4) | [2000-06-01,2000-07-01) | five^2  |        30 |         30
+ [3,4) | [2000-07-01,2010-01-01) | three   |      3471 |       3471
+ [4,5) | [2000-06-01,2000-07-01) | one^2   |        30 |         30
+ [5,6) | [2000-01-01,2000-03-01) | five    |        60 |         60
+ [5,6) | [2000-03-01,2000-04-01) | five^1  |        31 |         31
+ [5,6) | [2000-04-01,2000-06-01) | five    |        61 |         61
+ [5,6) | [2000-07-01,2010-01-01) | five    |      3471 |       3471
 (15 rows)
 
 SELECT * FROM temporal_partitioned_1 ORDER BY id, valid_at;
diff --git a/src/test/regress/sql/for_portion_of.sql b/src/test/regress/sql/for_portion_of.sql
index 001e83e4ce4..68d129842a3 100644
--- a/src/test/regress/sql/for_portion_of.sql
+++ b/src/test/regress/sql/for_portion_of.sql
@@ -1370,7 +1370,7 @@ UPDATE temporal_partitioned FOR PORTION OF valid_at FROM '2000-06-01' TO '2000-0
 
 -- Update all partitions at once (each with leftovers)
 
-SELECT * FROM temporal_partitioned ORDER BY id, valid_at;
+SELECT *, upper(valid_at) - lower(valid_at) as range_len1 FROM temporal_partitioned ORDER BY id, valid_at;
 SELECT * FROM temporal_partitioned_1 ORDER BY id, valid_at;
 SELECT * FROM temporal_partitioned_3 ORDER BY id, valid_at;
 SELECT * FROM temporal_partitioned_5 ORDER BY id, valid_at;
-- 
2.34.1