From 0e86a027ab785cb134d8cb5b8eee200b7c046569 Mon Sep 17 00:00:00 2001
From: reshke kirill <reshke@double.cloud>
Date: Mon, 16 Dec 2024 10:49:43 +0000
Subject: [PATCH v37 4/7] Fix for gin_index_check.

Never explicitly check high key on rightmost page is entry tree.
Its value is not stored explicitly and is equal to infitity.
Also never compare gin entries for different attnums.
---
 contrib/amcheck/verify_gin.c | 56 ++++++++++++++++++++++--------------
 1 file changed, 35 insertions(+), 21 deletions(-)

diff --git a/contrib/amcheck/verify_gin.c b/contrib/amcheck/verify_gin.c
index 2dc5fbba619..ae3d24a8b86 100644
--- a/contrib/amcheck/verify_gin.c
+++ b/contrib/amcheck/verify_gin.c
@@ -163,6 +163,7 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 		Page		page;
 		OffsetNumber i,
 					maxoff;
+		BlockNumber rightlink;
 
 		CHECK_FOR_INTERRUPTS();
 
@@ -170,6 +171,7 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 									RBM_NORMAL, strategy);
 		LockBuffer(buffer, GIN_SHARE);
 		page = (Page) BufferGetPage(buffer);
+
 		Assert(GinPageIsData(page));
 
 		/* Check that the tree has the same height in all branches */
@@ -182,7 +184,7 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 
 			ItemPointerSetMin(&minItem);
 
-			elog(DEBUG1, "page blk: %u, type leaf", stack->blkno);
+			elog(DEBUG2, "page blk: %u, type leaf", stack->blkno);
 
 			if (leafdepth == -1)
 				leafdepth = stack->depth;
@@ -234,8 +236,8 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 			 * Check that tuples in each page are properly ordered and
 			 * consistent with parent high key
 			 */
-			Assert(GinPageIsData(page));
 			maxoff = GinPageGetOpaque(page)->maxoff;
+			rightlink = GinPageGetOpaque(page)->rightlink;
 
 			elog(DEBUG1, "page blk: %u, type data, maxoff %d", stack->blkno, maxoff);
 
@@ -273,7 +275,12 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 			 */
 			bound = *GinDataPageGetRightBound(page);
 
-			if (stack->parentblk != InvalidBlockNumber &&
+			/*
+			 * Gin page right bound has sane value if only not a highkey on
+			 * rightmost page on level.
+			 */
+			if (ItemPointerIsValid(&stack->parentkey) &&
+				rightlink != InvalidBlockNumber &&
 				!ItemPointerEquals(&stack->parentkey, &bound))
 				ereport(ERROR,
 						(errcode(ERRCODE_INDEX_CORRUPTED),
@@ -287,11 +294,12 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 
 			for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 			{
+				GinPostingTreeScanItem *ptr;
 				PostingItem *posting_item = GinDataPageGetPostingItem(page, i);
 
 				/* ItemPointerGetOffsetNumber expects a valid pointer */
 				if (!(i == maxoff &&
-					  GinPageGetOpaque(page)->rightlink == InvalidBlockNumber))
+					  rightlink == InvalidBlockNumber))
 					elog(DEBUG3, "key (%u, %u) -> %u",
 						 ItemPointerGetBlockNumber(&posting_item->key),
 						 ItemPointerGetOffsetNumber(&posting_item->key),
@@ -300,8 +308,7 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 					elog(DEBUG3, "key (%u, %u) -> %u",
 						 0, 0, BlockIdGetBlockNumber(&posting_item->child_blkno));
 
-				if (i == maxoff &&
-					GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)
+				if (i == maxoff && rightlink == InvalidBlockNumber)
 				{
 					/*
 					 * The rightmost item in the tree level has (0, 0) as the
@@ -340,19 +347,23 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
 									RelationGetRelationName(rel),
 									stack->blkno, i)));
 
-				/* If this is an internal page, recurse into the child */
-				if (!GinPageIsLeaf(page))
-				{
-					GinPostingTreeScanItem *ptr;
+				/* This is an internal page, recurse into the child */
+				ptr = (GinPostingTreeScanItem *) palloc(sizeof(GinPostingTreeScanItem));
+				ptr->depth = stack->depth + 1;
 
-					ptr = (GinPostingTreeScanItem *) palloc(sizeof(GinPostingTreeScanItem));
-					ptr->depth = stack->depth + 1;
+				/*
+				 * Set rightmost parent key to invalid iterm pointer. Its
+				 * value is 'Infinity' and not explicitly stored.
+				 */
+				if (rightlink == InvalidBlockNumber)
+					ItemPointerSetInvalid(&ptr->parentkey);
+				else
 					ptr->parentkey = posting_item->key;
-					ptr->parentblk = stack->blkno;
-					ptr->blkno = BlockIdGetBlockNumber(&posting_item->child_blkno);
-					ptr->next = stack->next;
-					stack->next = ptr;
-				}
+
+				ptr->parentblk = stack->blkno;
+				ptr->blkno = BlockIdGetBlockNumber(&posting_item->child_blkno);
+				ptr->next = stack->next;
+				stack->next = ptr;
 			}
 		}
 		LockBuffer(buffer, GIN_UNLOCK);
@@ -411,7 +422,8 @@ gin_check_parent_keys_consistency(Relation rel,
 		Buffer		buffer;
 		Page		page;
 		OffsetNumber i,
-					maxoff;
+					maxoff,
+					prev_attnum;
 		XLogRecPtr	lsn;
 		IndexTuple	prev_tuple;
 		BlockNumber rightlink;
@@ -488,6 +500,7 @@ gin_check_parent_keys_consistency(Relation rel,
 		 * with parent high key
 		 */
 		prev_tuple = NULL;
+		prev_attnum = InvalidAttrNumber;
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
 			ItemId		iid = PageGetItemIdCareful(rel, stack->blkno, page, i);
@@ -511,7 +524,7 @@ gin_check_parent_keys_consistency(Relation rel,
 			 * for high key on rightmost page, as this key is not really
 			 * stored explicitly.
 			 */
-			if (i != FirstOffsetNumber && stack->blkno != GIN_ROOT_BLKNO &&
+			if (i != FirstOffsetNumber && attnum == prev_attnum && stack->blkno != GIN_ROOT_BLKNO &&
 				!(i == maxoff && rightlink == InvalidBlockNumber))
 			{
 				prev_key = gintuple_get_key(&state, prev_tuple, &prev_key_category);
@@ -520,8 +533,8 @@ gin_check_parent_keys_consistency(Relation rel,
 									  current_key_category) >= 0)
 					ereport(ERROR,
 							(errcode(ERRCODE_INDEX_CORRUPTED),
-							 errmsg("index \"%s\" has wrong tuple order on entry tree page, block %u, offset %u",
-									RelationGetRelationName(rel), stack->blkno, i)));
+							 errmsg("index \"%s\" has wrong tuple order on entry tree page, block %u, offset %u, rightlink %u",
+									RelationGetRelationName(rel), stack->blkno, i, rightlink)));
 			}
 
 			/*
@@ -620,6 +633,7 @@ gin_check_parent_keys_consistency(Relation rel,
 			}
 
 			prev_tuple = CopyIndexTuple(idxtuple);
+			prev_attnum = attnum;
 		}
 
 		LockBuffer(buffer, GIN_UNLOCK);
-- 
2.43.0

