@@ -617,7 +617,7 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level)
617
617
/* Internal page -- downlink gets leftmost on next level */
618
618
itemid = PageGetItemId (state -> target , P_FIRSTDATAKEY (opaque ));
619
619
itup = (IndexTuple ) PageGetItem (state -> target , itemid );
620
- nextleveldown .leftmost = ItemPointerGetBlockNumber (& (itup -> t_tid ));
620
+ nextleveldown .leftmost = ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid ));
621
621
nextleveldown .level = opaque -> btpo .level - 1 ;
622
622
}
623
623
else
@@ -722,6 +722,39 @@ bt_target_page_check(BtreeCheckState *state)
722
722
elog (DEBUG2 , "verifying %u items on %s block %u" , max ,
723
723
P_ISLEAF (topaque ) ? "leaf" : "internal" , state -> targetblock );
724
724
725
+
726
+ /* Check the number of attributes in high key if any */
727
+ if (!P_RIGHTMOST (topaque ))
728
+ {
729
+ if (!_bt_check_natts (state -> rel , state -> target , P_HIKEY ))
730
+ {
731
+ ItemId itemid ;
732
+ IndexTuple itup ;
733
+ char * itid ,
734
+ * htid ;
735
+
736
+ itemid = PageGetItemId (state -> target , P_HIKEY );
737
+ itup = (IndexTuple ) PageGetItem (state -> target , itemid );
738
+ itid = psprintf ("(%u,%u)" , state -> targetblock , P_HIKEY );
739
+ htid = psprintf ("(%u,%u)" ,
740
+ ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid )),
741
+ ItemPointerGetOffsetNumberNoCheck (& (itup -> t_tid )));
742
+
743
+ ereport (ERROR ,
744
+ (errcode (ERRCODE_INDEX_CORRUPTED ),
745
+ errmsg ("wrong number of index tuple attributes for index \"%s\"" ,
746
+ RelationGetRelationName (state -> rel )),
747
+ errdetail_internal ("Index tid=%s natts=%u points to %s tid=%s page lsn=%X/%X." ,
748
+ itid ,
749
+ BTreeTupGetNAtts (itup , state -> rel ),
750
+ P_ISLEAF (topaque ) ? "heap" : "index" ,
751
+ htid ,
752
+ (uint32 ) (state -> targetlsn >> 32 ),
753
+ (uint32 ) state -> targetlsn )));
754
+ }
755
+ }
756
+
757
+
725
758
/*
726
759
* Loop over page items, starting from first non-highkey item, not high
727
760
* key (if any). Also, immediately skip "negative infinity" real item (if
@@ -760,6 +793,30 @@ bt_target_page_check(BtreeCheckState *state)
760
793
(uint32 ) state -> targetlsn ),
761
794
errhint ("This could be a torn page problem" )));
762
795
796
+ /* Check the number of index tuple attributes */
797
+ if (!_bt_check_natts (state -> rel , state -> target , offset ))
798
+ {
799
+ char * itid ,
800
+ * htid ;
801
+
802
+ itid = psprintf ("(%u,%u)" , state -> targetblock , offset );
803
+ htid = psprintf ("(%u,%u)" ,
804
+ ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid )),
805
+ ItemPointerGetOffsetNumberNoCheck (& (itup -> t_tid )));
806
+
807
+ ereport (ERROR ,
808
+ (errcode (ERRCODE_INDEX_CORRUPTED ),
809
+ errmsg ("wrong number of index tuple attributes for index \"%s\"" ,
810
+ RelationGetRelationName (state -> rel )),
811
+ errdetail_internal ("Index tid=%s natts=%u points to %s tid=%s page lsn=%X/%X." ,
812
+ itid ,
813
+ BTreeTupGetNAtts (itup , state -> rel ),
814
+ P_ISLEAF (topaque ) ? "heap" : "index" ,
815
+ htid ,
816
+ (uint32 ) (state -> targetlsn >> 32 ),
817
+ (uint32 ) state -> targetlsn )));
818
+ }
819
+
763
820
/*
764
821
* Don't try to generate scankey using "negative infinity" garbage
765
822
* data on internal pages
@@ -802,8 +859,8 @@ bt_target_page_check(BtreeCheckState *state)
802
859
803
860
itid = psprintf ("(%u,%u)" , state -> targetblock , offset );
804
861
htid = psprintf ("(%u,%u)" ,
805
- ItemPointerGetBlockNumber (& (itup -> t_tid )),
806
- ItemPointerGetOffsetNumber (& (itup -> t_tid )));
862
+ ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid )),
863
+ ItemPointerGetOffsetNumberNoCheck (& (itup -> t_tid )));
807
864
808
865
ereport (ERROR ,
809
866
(errcode (ERRCODE_INDEX_CORRUPTED ),
@@ -834,17 +891,17 @@ bt_target_page_check(BtreeCheckState *state)
834
891
835
892
itid = psprintf ("(%u,%u)" , state -> targetblock , offset );
836
893
htid = psprintf ("(%u,%u)" ,
837
- ItemPointerGetBlockNumber (& (itup -> t_tid )),
838
- ItemPointerGetOffsetNumber (& (itup -> t_tid )));
894
+ ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid )),
895
+ ItemPointerGetOffsetNumberNoCheck (& (itup -> t_tid )));
839
896
nitid = psprintf ("(%u,%u)" , state -> targetblock ,
840
897
OffsetNumberNext (offset ));
841
898
842
899
/* Reuse itup to get pointed-to heap location of second item */
843
900
itemid = PageGetItemId (state -> target , OffsetNumberNext (offset ));
844
901
itup = (IndexTuple ) PageGetItem (state -> target , itemid );
845
902
nhtid = psprintf ("(%u,%u)" ,
846
- ItemPointerGetBlockNumber (& (itup -> t_tid )),
847
- ItemPointerGetOffsetNumber (& (itup -> t_tid )));
903
+ ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid )),
904
+ ItemPointerGetOffsetNumberNoCheck (& (itup -> t_tid )));
848
905
849
906
ereport (ERROR ,
850
907
(errcode (ERRCODE_INDEX_CORRUPTED ),
@@ -932,7 +989,7 @@ bt_target_page_check(BtreeCheckState *state)
932
989
*/
933
990
if (!P_ISLEAF (topaque ) && state -> readonly )
934
991
{
935
- BlockNumber childblock = ItemPointerGetBlockNumber (& (itup -> t_tid ));
992
+ BlockNumber childblock = ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid ));
936
993
937
994
bt_downlink_check (state , childblock , skey );
938
995
}
@@ -1326,6 +1383,11 @@ bt_tuple_present_callback(Relation index, HeapTuple htup, Datum *values,
1326
1383
* or otherwise varied when or how compression was applied, our assumption
1327
1384
* would break, leading to false positive reports of corruption. For now,
1328
1385
* we don't decompress/normalize toasted values as part of fingerprinting.
1386
+ *
1387
+ * In future, non-pivot index tuples might get use of
1388
+ * BT_N_KEYS_OFFSET_MASK. Then binary representation of index tuple linked
1389
+ * to particular heap tuple might vary and meeds to be normalized before
1390
+ * bloom filter lookup.
1329
1391
*/
1330
1392
itup = index_form_tuple (RelationGetDescr (index ), values , isnull );
1331
1393
itup -> t_tid = htup -> t_self ;
@@ -1336,8 +1398,8 @@ bt_tuple_present_callback(Relation index, HeapTuple htup, Datum *values,
1336
1398
ereport (ERROR ,
1337
1399
(errcode (ERRCODE_DATA_CORRUPTED ),
1338
1400
errmsg ("heap tuple (%u,%u) from table \"%s\" lacks matching index tuple within index \"%s\"" ,
1339
- ItemPointerGetBlockNumber (& (itup -> t_tid )),
1340
- ItemPointerGetOffsetNumber (& (itup -> t_tid )),
1401
+ ItemPointerGetBlockNumberNoCheck (& (itup -> t_tid )),
1402
+ ItemPointerGetOffsetNumberNoCheck (& (itup -> t_tid )),
1341
1403
RelationGetRelationName (state -> heaprel ),
1342
1404
RelationGetRelationName (state -> rel )),
1343
1405
!state -> readonly
@@ -1368,6 +1430,10 @@ offset_is_negative_infinity(BTPageOpaque opaque, OffsetNumber offset)
1368
1430
* infinity item is either first or second line item, or there is none
1369
1431
* within page.
1370
1432
*
1433
+ * "Negative infinity" tuple is a special corner case of pivot tuples,
1434
+ * it has zero attributes while rest of pivot tuples have nkeyatts number
1435
+ * of attributes.
1436
+ *
1371
1437
* Right-most pages don't have a high key, but could be said to
1372
1438
* conceptually have a "positive infinity" high key. Thus, there is a
1373
1439
* symmetry between down link items in parent pages, and high keys in
@@ -1391,10 +1457,10 @@ static inline bool
1391
1457
invariant_leq_offset (BtreeCheckState * state , ScanKey key ,
1392
1458
OffsetNumber upperbound )
1393
1459
{
1394
- int16 natts = state -> rel -> rd_rel -> relnatts ;
1460
+ int16 nkeyatts = IndexRelationGetNumberOfKeyAttributes ( state -> rel ) ;
1395
1461
int32 cmp ;
1396
1462
1397
- cmp = _bt_compare (state -> rel , natts , key , state -> target , upperbound );
1463
+ cmp = _bt_compare (state -> rel , nkeyatts , key , state -> target , upperbound );
1398
1464
1399
1465
return cmp <= 0 ;
1400
1466
}
@@ -1410,10 +1476,10 @@ static inline bool
1410
1476
invariant_geq_offset (BtreeCheckState * state , ScanKey key ,
1411
1477
OffsetNumber lowerbound )
1412
1478
{
1413
- int16 natts = state -> rel -> rd_rel -> relnatts ;
1479
+ int16 nkeyatts = IndexRelationGetNumberOfKeyAttributes ( state -> rel ) ;
1414
1480
int32 cmp ;
1415
1481
1416
- cmp = _bt_compare (state -> rel , natts , key , state -> target , lowerbound );
1482
+ cmp = _bt_compare (state -> rel , nkeyatts , key , state -> target , lowerbound );
1417
1483
1418
1484
return cmp >= 0 ;
1419
1485
}
@@ -1433,10 +1499,10 @@ invariant_leq_nontarget_offset(BtreeCheckState *state,
1433
1499
Page nontarget , ScanKey key ,
1434
1500
OffsetNumber upperbound )
1435
1501
{
1436
- int16 natts = state -> rel -> rd_rel -> relnatts ;
1502
+ int16 nkeyatts = IndexRelationGetNumberOfKeyAttributes ( state -> rel ) ;
1437
1503
int32 cmp ;
1438
1504
1439
- cmp = _bt_compare (state -> rel , natts , key , nontarget , upperbound );
1505
+ cmp = _bt_compare (state -> rel , nkeyatts , key , nontarget , upperbound );
1440
1506
1441
1507
return cmp <= 0 ;
1442
1508
}
0 commit comments