From 0a75015e109f5c58db9440215e8a88540c5ed119 Mon Sep 17 00:00:00 2001
From: Arseniy Mukhin <arseniy.mukhin.dev@gmail.com>
Date: Tue, 22 Jul 2025 17:37:13 +0300
Subject: [PATCH v8 3/4] amcheck: common_verify - register snapshot with
 indcheckxmin check

Moves check to common_verify. Every index needs it for heapallindexed check.
---
 contrib/amcheck/verify_common.c | 29 +++++++++++++++++++++++++++++
 contrib/amcheck/verify_common.h |  2 ++
 contrib/amcheck/verify_nbtree.c | 23 +----------------------
 3 files changed, 32 insertions(+), 22 deletions(-)

diff --git a/contrib/amcheck/verify_common.c b/contrib/amcheck/verify_common.c
index a31ce06ed99..bbcefe82898 100644
--- a/contrib/amcheck/verify_common.c
+++ b/contrib/amcheck/verify_common.c
@@ -189,3 +189,32 @@ index_checkable(Relation rel, Oid am_id)
 
 	return amcheck_index_mainfork_expected(rel);
 }
+
+/*
+ * GetTransactionSnapshot() always acquires a new MVCC snapshot in
+ * READ COMMITTED mode.  A new snapshot is guaranteed to have all
+ * the entries it requires in the index.
+ *
+ * We must defend against the possibility that an old xact
+ * snapshot was returned at higher isolation levels when that
+ * snapshot is not safe for index scans of the target index.  This
+ * is possible when the snapshot sees tuples that are before the
+ * index's indcheckxmin horizon.  Throwing an error here should be
+ * very rare.  It doesn't seem worth using a secondary snapshot to
+ * avoid this.
+ */
+Snapshot
+RegisterSnapshotAndCheckIndexCheckXMin(Relation idxrel)
+{
+	Snapshot	snapshot = RegisterSnapshot(GetTransactionSnapshot());
+
+	if (IsolationUsesXactSnapshot() && idxrel->rd_index->indcheckxmin &&
+		!TransactionIdPrecedes(HeapTupleHeaderGetXmin(idxrel->rd_indextuple->t_data),
+							   snapshot->xmin))
+		ereport(ERROR,
+				(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+				 errmsg("index \"%s\" cannot be verified using transaction snapshot",
+						RelationGetRelationName(idxrel))));
+
+	return snapshot;
+}
diff --git a/contrib/amcheck/verify_common.h b/contrib/amcheck/verify_common.h
index 3f4c57f963d..7679e33da77 100644
--- a/contrib/amcheck/verify_common.h
+++ b/contrib/amcheck/verify_common.h
@@ -26,3 +26,5 @@ extern void amcheck_lock_relation_and_check(Oid indrelid,
 											Oid am_id,
 											IndexDoCheckCallback check,
 											LOCKMODE lockmode, void *state);
+
+extern Snapshot RegisterSnapshotAndCheckIndexCheckXMin(Relation idxrel);
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 0949c88983a..c9aa9044045 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -441,28 +441,7 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
 		 */
 		if (!state->readonly)
 		{
-			snapshot = RegisterSnapshot(GetTransactionSnapshot());
-
-			/*
-			 * GetTransactionSnapshot() always acquires a new MVCC snapshot in
-			 * READ COMMITTED mode.  A new snapshot is guaranteed to have all
-			 * the entries it requires in the index.
-			 *
-			 * We must defend against the possibility that an old xact
-			 * snapshot was returned at higher isolation levels when that
-			 * snapshot is not safe for index scans of the target index.  This
-			 * is possible when the snapshot sees tuples that are before the
-			 * index's indcheckxmin horizon.  Throwing an error here should be
-			 * very rare.  It doesn't seem worth using a secondary snapshot to
-			 * avoid this.
-			 */
-			if (IsolationUsesXactSnapshot() && rel->rd_index->indcheckxmin &&
-				!TransactionIdPrecedes(HeapTupleHeaderGetXmin(rel->rd_indextuple->t_data),
-									   snapshot->xmin))
-				ereport(ERROR,
-						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
-						 errmsg("index \"%s\" cannot be verified using transaction snapshot",
-								RelationGetRelationName(rel))));
+			snapshot = RegisterSnapshotAndCheckIndexCheckXMin(state->rel);
 		}
 	}
 
-- 
2.43.0

