amcheck: Report an error when the next page to a leaf is not a leaf

This is a very unlikely condition during checking a B-tree unique constraint,
meaning that the index structure is violated badly, and we shouldn't continue
checking to avoid endless loops, etc.  So it's worth immediately throwing an
error.

Reported-by: Peter Geoghegan
Discussion: https://postgr.es/m/CAH2-Wzk%2B2116uOXdOViA27SHcr31WKPgmjsxXLBs_aTxAeThzg%40mail.gmail.com
Author: Pavel Borisov
This commit is contained in:
Alexander Korotkov 2024-05-23 02:13:43 +03:00
parent 0b5c161248
commit 97e5b0026f
1 changed files with 16 additions and 6 deletions

View File

@ -1831,7 +1831,6 @@ bt_target_page_check(BtreeCheckState *state)
if (offset == max)
{
BTScanInsert rightkey;
BlockNumber rightblock_number;
/* first offset on a right index page (log only) */
OffsetNumber rightfirstoffset = InvalidOffsetNumber;
@ -1876,10 +1875,11 @@ bt_target_page_check(BtreeCheckState *state)
* If index has unique constraint make sure that no more than one
* found equal items is visible.
*/
rightblock_number = topaque->btpo_next;
if (state->checkunique && state->indexinfo->ii_Unique &&
rightkey && P_ISLEAF(topaque) && rightblock_number != P_NONE)
rightkey && P_ISLEAF(topaque) && !P_RIGHTMOST(topaque))
{
BlockNumber rightblock_number = topaque->btpo_next;
elog(DEBUG2, "check cross page unique condition");
/*
@ -1899,9 +1899,19 @@ bt_target_page_check(BtreeCheckState *state)
rightblock_number);
topaque = BTPageGetOpaque(rightpage);
if (P_IGNORE(topaque) || !P_ISLEAF(topaque))
break;
if (P_IGNORE(topaque))
{
if (unlikely(!P_ISLEAF(topaque)))
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("right block of leaf block is non-leaf for index \"%s\"",
RelationGetRelationName(state->rel)),
errdetail_internal("Block=%u page lsn=%X/%X.",
state->targetblock,
LSN_FORMAT_ARGS(state->targetlsn))));
else
break;
}
itemid = PageGetItemIdCareful(state, rightblock_number,
rightpage,
rightfirstoffset);