diff options
author | Alexander Korotkov | 2024-05-22 23:13:43 +0000 |
---|---|---|
committer | Alexander Korotkov | 2024-05-22 23:13:43 +0000 |
commit | 97e5b0026fc276ab1bcde58ae98ae1fcd9c3acc3 (patch) | |
tree | 1c2ec4796a1db2290af5f5029e9c4531df08b2d3 /contrib | |
parent | 0b5c161248110b164a3333006004c78f9529a109 (diff) |
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
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/amcheck/verify_nbtree.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index 5354b393b11..4347f9594c9 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -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); |