@@ -1164,10 +1164,29 @@ _bt_insertonpg(Relation rel,
1164
1164
* its post-split version is treated as an extra step in either the
1165
1165
* insert or page split critical section.
1166
1166
*/
1167
- Assert (isleaf && !ItemIdIsDead (itemid ));
1168
- Assert (itup_key -> heapkeyspace && itup_key -> allequalimage );
1167
+ Assert (isleaf && itup_key -> heapkeyspace && itup_key -> allequalimage );
1169
1168
oposting = (IndexTuple ) PageGetItem (page , itemid );
1170
1169
1170
+ /*
1171
+ * postingoff value comes from earlier call to _bt_binsrch_posting().
1172
+ * Its binary search might think that a plain tuple must be a posting
1173
+ * list tuple that needs to be split. This can happen with corruption
1174
+ * involving an existing plain tuple that is a duplicate of the new
1175
+ * item, up to and including its table TID. Check for that here in
1176
+ * passing.
1177
+ *
1178
+ * Also verify that our caller has made sure that the existing posting
1179
+ * list tuple does not have its LP_DEAD bit set.
1180
+ */
1181
+ if (!BTreeTupleIsPosting (oposting ) || ItemIdIsDead (itemid ))
1182
+ ereport (ERROR ,
1183
+ (errcode (ERRCODE_INDEX_CORRUPTED ),
1184
+ errmsg_internal ("table tid from new index tuple (%u,%u) overlaps with invalid duplicate tuple at offset %u of block %u in index \"%s\"" ,
1185
+ ItemPointerGetBlockNumber (& itup -> t_tid ),
1186
+ ItemPointerGetOffsetNumber (& itup -> t_tid ),
1187
+ BufferGetBlockNumber (buf ), newitemoff ,
1188
+ RelationGetRelationName (rel ))));
1189
+
1171
1190
/* use a mutable copy of itup as our itup from here on */
1172
1191
origitup = itup ;
1173
1192
itup = CopyIndexTuple (origitup );
0 commit comments