From 99c83aa75bbe3a8893fc4779629e08f927d55bf0 Mon Sep 17 00:00:00 2001
From: Zhijie Hou <sherlockcpp@foxmail.com>
Date: Mon, 5 Oct 2026 14:44:40 +0800
Subject: [PATCH vTopup] Use computed index to check

---
 src/backend/replication/logical/relation.c | 54 ++++++++--------------
 1 file changed, 20 insertions(+), 34 deletions(-)

diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index 8b173e379d0..05e1495c4bc 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -307,40 +307,24 @@ logicalrep_report_missing_or_gen_attrs(LogicalRepRelation *remoterel,
 static void
 logicalrep_rel_mark_updatable(LogicalRepRelMapEntry *entry)
 {
-	Bitmapset  *idkey;
 	LogicalRepRelation *remoterel = &entry->remoterel;
-	int			i;
+	Relation	idxrel;
 
 	entry->updatable = true;
 
-	idkey = RelationGetIndexAttrBitmap(entry->localrel,
-									   INDEX_ATTR_BITMAP_IDENTITY_KEY);
-
-	/*
-	 * Fall back to the PK if no replica identity, but only if the PK is not
-	 * deferrable.  INDEX_ATTR_BITMAP_PRIMARY_KEY includes the columns of a
-	 * deferrable PK, but such a PK cannot serve as a replica identity (its
-	 * uniqueness may be transiently violated), and FindLogicalRepLocalIndex()
-	 * will not use it to look up tuples.
-	 */
-	if (idkey == NULL)
+	if (!entry->idxisreplident)
 	{
-		if (OidIsValid(RelationGetPrimaryKeyIndex(entry->localrel, false)))
-			idkey = RelationGetIndexAttrBitmap(entry->localrel,
-											   INDEX_ATTR_BITMAP_PRIMARY_KEY);
-
-		/*
-		 * If no replica identity index and no usable PK, the published table
-		 * must have replica identity FULL.
-		 */
-		if (idkey == NULL && remoterel->replident != REPLICA_IDENTITY_FULL)
+		if (remoterel->replident != REPLICA_IDENTITY_FULL)
 			entry->updatable = false;
+
+		return;
 	}
 
-	i = -1;
-	while ((i = bms_next_member(idkey, i)) >= 0)
+	idxrel = index_open(entry->localindexoid, AccessShareLock);
+
+	for (int i = 0; i < idxrel->rd_index->indnkeyatts; i++)
 	{
-		int			attnum = i + FirstLowInvalidHeapAttributeNumber;
+		int		attnum = idxrel->rd_index->indkey.values[i];
 
 		if (!AttrNumberIsForUserDefinedAttr(attnum))
 			ereport(ERROR,
@@ -358,6 +342,8 @@ logicalrep_rel_mark_updatable(LogicalRepRelMapEntry *entry)
 			break;
 		}
 	}
+
+	index_close(idxrel, AccessShareLock);
 }
 
 /*
@@ -492,12 +478,6 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 		bms_free(generatedattrs);
 		bms_free(missingatts);
 
-		/*
-		 * Set if the table's replica identity is enough to apply
-		 * update/delete.
-		 */
-		logicalrep_rel_mark_updatable(entry);
-
 		/*
 		 * Finding a usable index is an infrequent task. It occurs when an
 		 * operation is first performed on the relation, or after invalidation
@@ -508,6 +488,12 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 														entry->attrmap,
 														&entry->idxisreplident);
 
+		/*
+		 * Set if the table's replica identity is enough to apply
+		 * update/delete.
+		 */
+		logicalrep_rel_mark_updatable(entry);
+
 		entry->localrelvalid = true;
 	}
 
@@ -757,9 +743,6 @@ logicalrep_partition_open(LogicalRepRelMapEntry *root,
 			   attrmap->maplen * sizeof(AttrNumber));
 	}
 
-	/* Set if the table's replica identity is enough to apply update/delete. */
-	logicalrep_rel_mark_updatable(entry);
-
 	/* state and statelsn are left set to 0. */
 	MemoryContextSwitchTo(oldctx);
 
@@ -776,6 +759,9 @@ logicalrep_partition_open(LogicalRepRelMapEntry *root,
 													entry->attrmap,
 													&entry->idxisreplident);
 
+	/* Set if the table's replica identity is enough to apply update/delete. */
+	logicalrep_rel_mark_updatable(entry);
+
 	entry->localrelvalid = true;
 
 	return entry;
-- 
2.34.1

