From 5d765cda1a35450cc205b9b9576e045b5145a12c Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 1 Dec 2025 23:18:31 +0200
Subject: [PATCH v1 4/4] Fix amcheck's handling of half-dead B-tree pages

Discussion: https://www.postgresql.org/message-id/abd65090-5336-42cc-b768-2bdd66738404@iki.fi
---
 contrib/amcheck/verify_nbtree.c                    |  2 +-
 .../nbtree/expected/nbtree_half_dead_pages.out     | 14 ++++++++++++++
 .../modules/nbtree/sql/nbtree_half_dead_pages.sql  |  5 +++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index f26c20b59aa..75751e2a1e9 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -2268,7 +2268,7 @@ bt_child_highkey_check(BtreeCheckState *state,
 		 * If we visit page with high key, check that it is equal to the
 		 * target key next to corresponding downlink.
 		 */
-		if (!rightsplit && !P_RIGHTMOST(opaque))
+		if (!rightsplit && !P_RIGHTMOST(opaque) && !P_ISHALFDEAD(opaque))
 		{
 			BTPageOpaque topaque;
 			IndexTuple	highkey;
diff --git a/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out b/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out
index 8fd472f8df2..e94f016696d 100644
--- a/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out
+++ b/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out
@@ -11,6 +11,7 @@
 -- This uses injection points to interrupt some page deletions
 set client_min_messages TO 'warning';
 create extension if not exists injection_points;
+create extension if not exists amcheck;
 reset client_min_messages;
 -- Make all injection points local to this process, for concurrency.
 SELECT injection_points_set_local();
@@ -57,6 +58,13 @@ select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
  120001
 (4 rows)
 
+-- Also check the index with amcheck
+select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
+ bt_index_parent_check 
+-----------------------
+ 
+(1 row)
+
 -- Finish the deletion and re-check
 vacuum nbtree_half_dead_pages;
 NOTICE:  notice triggered for injection point nbtree-finish-half-dead-page-vacuum
@@ -69,3 +77,9 @@ select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
  120001
 (4 rows)
 
+select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
+ bt_index_parent_check 
+-----------------------
+ 
+(1 row)
+
diff --git a/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql b/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql
index d4b9a3f824d..fd279b87e0e 100644
--- a/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql
+++ b/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql
@@ -12,6 +12,7 @@
 -- This uses injection points to interrupt some page deletions
 set client_min_messages TO 'warning';
 create extension if not exists injection_points;
+create extension if not exists amcheck;
 reset client_min_messages;
 
 -- Make all injection points local to this process, for concurrency.
@@ -38,6 +39,10 @@ SELECT injection_points_detach('nbtree-leave-page-half-dead');
 
 select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
 
+-- Also check the index with amcheck
+select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
+
 -- Finish the deletion and re-check
 vacuum nbtree_half_dead_pages;
 select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
+select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
-- 
2.47.3

