aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtinsert.c
diff options
context:
space:
mode:
authorPeter Geoghegan <pg@bowt.ie>2021-10-27 12:10:47 -0700
committerPeter Geoghegan <pg@bowt.ie>2021-10-27 12:10:47 -0700
commita5213adf3d351a31c5f5eae1a756a9d3555dc31c (patch)
tree8b101c4fa5cf5ba5110dd0a0b71d0fe38a1cdc17 /src/backend/access/nbtree/nbtinsert.c
parenteff61383b982be8dc71d942340a839bea88a9eab (diff)
downloadpostgresql-a5213adf3d351a31c5f5eae1a756a9d3555dc31c.tar.gz
postgresql-a5213adf3d351a31c5f5eae1a756a9d3555dc31c.zip
Further harden nbtree posting split code.
Add more defensive checks around posting list split code. These should detect corruption involving duplicate table TIDs earlier and more reliably than any existing check. Follow up to commit 8f72bbac. Discussion: https://postgr.es/m/CAH2-WzkrSY_kjyd1_M5xJK1uM0govJXMxPn8JUSvwcUOiHuWVw@mail.gmail.com Backpatch: 13-, where nbtree deduplication was introduced.
Diffstat (limited to 'src/backend/access/nbtree/nbtinsert.c')
-rw-r--r--src/backend/access/nbtree/nbtinsert.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 7355e1dba13..a755aee55eb 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1164,10 +1164,29 @@ _bt_insertonpg(Relation rel,
* its post-split version is treated as an extra step in either the
* insert or page split critical section.
*/
- Assert(isleaf && !ItemIdIsDead(itemid));
- Assert(itup_key->heapkeyspace && itup_key->allequalimage);
+ Assert(isleaf && itup_key->heapkeyspace && itup_key->allequalimage);
oposting = (IndexTuple) PageGetItem(page, itemid);
+ /*
+ * postingoff value comes from earlier call to _bt_binsrch_posting().
+ * Its binary search might think that a plain tuple must be a posting
+ * list tuple that needs to be split. This can happen with corruption
+ * involving an existing plain tuple that is a duplicate of the new
+ * item, up to and including its table TID. Check for that here in
+ * passing.
+ *
+ * Also verify that our caller has made sure that the existing posting
+ * list tuple does not have its LP_DEAD bit set.
+ */
+ if (!BTreeTupleIsPosting(oposting) || ItemIdIsDead(itemid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INDEX_CORRUPTED),
+ errmsg_internal("table tid from new index tuple (%u,%u) overlaps with invalid duplicate tuple at offset %u of block %u in index \"%s\"",
+ ItemPointerGetBlockNumber(&itup->t_tid),
+ ItemPointerGetOffsetNumber(&itup->t_tid),
+ BufferGetBlockNumber(buf), newitemoff,
+ RelationGetRelationName(rel))));
+
/* use a mutable copy of itup as our itup from here on */
origitup = itup;
itup = CopyIndexTuple(origitup);