@ -145,6 +145,19 @@ typedef struct BtreeLevel
bool istruerootlevel ;
} BtreeLevel ;
/*
* Information about the last visible entry with current B - tree key . Used
* for validation of the unique constraint .
*/
typedef struct BtreeLastVisibleEntry
{
BlockNumber blkno ; /* Index block */
OffsetNumber offset ; /* Offset on index block */
int postingIndex ; /* Number in the posting list (-1 for
* non - deduplicated tuples ) */
ItemPointer tid ; /* Heap tid */
} BtreeLastVisibleEntry ;
PG_FUNCTION_INFO_V1 ( bt_index_check ) ;
PG_FUNCTION_INFO_V1 ( bt_index_parent_check ) ;
@ -165,17 +178,14 @@ static void bt_recheck_sibling_links(BtreeCheckState *state,
BlockNumber btpo_prev_from_target ,
BlockNumber leftcurrent ) ;
static bool heap_entry_is_visible ( BtreeCheckState * state , ItemPointer tid ) ;
static void bt_report_duplicate ( BtreeCheckState * state , ItemPointer tid ,
BlockNumber block , OffsetNumber offset ,
int posting , ItemPointer nexttid ,
static void bt_report_duplicate ( BtreeCheckState * state ,
BtreeLastVisibleEntry * lVis ,
ItemPointer nexttid ,
BlockNumber nblock , OffsetNumber noffset ,
int nposting ) ;
static void bt_entry_unique_check ( BtreeCheckState * state , IndexTuple itup ,
BlockNumber targetblock ,
OffsetNumber offset , int * lVis_i ,
ItemPointer * lVis_tid ,
OffsetNumber * lVis_offset ,
BlockNumber * lVis_block ) ;
BlockNumber targetblock , OffsetNumber offset ,
BtreeLastVisibleEntry * lVis ) ;
static void bt_target_page_check ( BtreeCheckState * state ) ;
static BTScanInsert bt_right_page_check_scankey ( BtreeCheckState * state ,
OffsetNumber * rightfirstoffset ) ;
@ -997,8 +1007,7 @@ heap_entry_is_visible(BtreeCheckState *state, ItemPointer tid)
*/
static void
bt_report_duplicate ( BtreeCheckState * state ,
ItemPointer tid , BlockNumber block , OffsetNumber offset ,
int posting ,
BtreeLastVisibleEntry * lVis ,
ItemPointer nexttid , BlockNumber nblock , OffsetNumber noffset ,
int nposting )
{
@ -1010,18 +1019,18 @@ bt_report_duplicate(BtreeCheckState *state,
* pnposting = " " ;
htid = psprintf ( " tid=(%u,%u) " ,
ItemPointerGetBlockNumberNoCheck ( tid ) ,
ItemPointerGetOffsetNumberNoCheck ( tid ) ) ;
ItemPointerGetBlockNumberNoCheck ( lVis - > tid ) ,
ItemPointerGetOffsetNumberNoCheck ( lVis - > tid ) ) ;
nhtid = psprintf ( " tid=(%u,%u) " ,
ItemPointerGetBlockNumberNoCheck ( nexttid ) ,
ItemPointerGetOffsetNumberNoCheck ( nexttid ) ) ;
itid = psprintf ( " tid=(%u,%u) " , block , offset ) ;
itid = psprintf ( " tid=(%u,%u) " , lVis - > blkno , lVis - > offset ) ;
if ( nblock ! = block | | noffset ! = offset )
if ( nblock ! = lVis - > blkno | | noffset ! = lVis - > offset )
nitid = psprintf ( " tid=(%u,%u) " , nblock , noffset ) ;
if ( posting > = 0 )
pposting = psprintf ( " posting %u " , posting ) ;
if ( lVis - > postingIndex > = 0 )
pposting = psprintf ( " posting %u " , lVis - > postingIndex ) ;
if ( nposting > = 0 )
pnposting = psprintf ( " posting %u " , nposting ) ;
@ -1038,9 +1047,8 @@ bt_report_duplicate(BtreeCheckState *state,
/* Check if current nbtree leaf entry complies with UNIQUE constraint */
static void
bt_entry_unique_check ( BtreeCheckState * state , IndexTuple itup ,
BlockNumber targetblock , OffsetNumber offset , int * lVis_i ,
ItemPointer * lVis_tid , OffsetNumber * lVis_offset ,
BlockNumber * lVis_block )
BlockNumber targetblock , OffsetNumber offset ,
BtreeLastVisibleEntry * lVis )
{
ItemPointer tid ;
bool has_visible_entry = false ;
@ -1049,7 +1057,7 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
/*
* Current tuple has posting list . Report duplicate if TID of any posting
* list entry is visible and lVis_ tid is valid .
* list entry is visible and lVis - > tid is valid .
*/
if ( BTreeTupleIsPosting ( itup ) )
{
@ -1059,11 +1067,10 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
if ( heap_entry_is_visible ( state , tid ) )
{
has_visible_entry = true ;
if ( ItemPointerIsValid ( * lVis_ tid) )
if ( ItemPointerIsValid ( lVis - > tid ) )
{
bt_report_duplicate ( state ,
* lVis_tid , * lVis_block ,
* lVis_offset , * lVis_i ,
lVis ,
tid , targetblock ,
offset , i ) ;
}
@ -1073,13 +1080,13 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
* between the posting list entries of the first tuple on the
* page after cross - page check .
*/
if ( * lVis_block ! = targetblock & & ItemPointerIsValid ( * lVis_ tid) )
if ( lVis - > blkno ! = targetblock & & ItemPointerIsValid ( lVis - > tid ) )
return ;
* lVis_i = i ;
* lVis_tid = tid ;
* lVis_offset = offset ;
* lVis_block = targetblock ;
lVis - > blkno = targetblock ;
lVis - > offset = offset ;
lVis - > postingIndex = i ;
lVis - > tid = tid ;
}
}
}
@ -1087,7 +1094,7 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
/*
* Current tuple has no posting list . If TID is visible save info about it
* for the next comparisons in the loop in bt_target_page_check ( ) . Report
* duplicate if lVis_ tid is already valid .
* duplicate if lVis - > tid is already valid .
*/
else
{
@ -1095,37 +1102,38 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
if ( heap_entry_is_visible ( state , tid ) )
{
has_visible_entry = true ;
if ( ItemPointerIsValid ( * lVis_ tid) )
if ( ItemPointerIsValid ( lVis - > tid ) )
{
bt_report_duplicate ( state ,
* lVis_tid , * lVis_block ,
* lVis_offset , * lVis_i ,
lVis ,
tid , targetblock ,
offset , - 1 ) ;
}
* lVis_i = - 1 ;
* lVis_tid = tid ;
* lVis_offset = offset ;
* lVis_block = targetblock ;
lVis - > blkno = targetblock ;
lVis - > offset = offset ;
lVis - > tid = tid ;
lVis - > postingIndex = - 1 ;
}
}
if ( ! has_visible_entry & & * lVis_block ! = InvalidBlockNumber & &
* lVis_block ! = targetblock )
if ( ! has_visible_entry & &
lVis - > blkno ! = InvalidBlockNumber & &
lVis - > blkno ! = targetblock )
{
char * posting = " " ;
if ( * lVis_i > = 0 )
posting = psprintf ( " posting %u " , * lVis_i ) ;
if ( lVis - > postingIndex > = 0 )
posting = psprintf ( " posting %u " , lVis - > postingIndex ) ;
ereport ( DEBUG1 ,
( errcode ( ERRCODE_NO_DATA ) ,
errmsg ( " index uniqueness can not be checked for index tid=(%u,%u) in index \" %s \" " ,
targetblock , offset ,
RelationGetRelationName ( state - > rel ) ) ,
errdetail ( " It doesn't have visible heap tids and key is equal to the tid=(%u,%u)%s (points to heap tid=(%u,%u)). " ,
* lVis_block , * lVis_ offset, posting ,
ItemPointerGetBlockNumberNoCheck ( * lVis_ tid) ,
ItemPointerGetOffsetNumberNoCheck ( * lVis_ tid) ) ,
lVis - > blkno , lVis - > offset , posting ,
ItemPointerGetBlockNumberNoCheck ( lVis - > tid ) ,
ItemPointerGetOffsetNumberNoCheck ( lVis - > tid ) ) ,
errhint ( " VACUUM the table and repeat the check. " ) ) ) ;
}
}
@ -1372,12 +1380,8 @@ bt_target_page_check(BtreeCheckState *state)
OffsetNumber max ;
BTPageOpaque topaque ;
/* last visible entry info for checking indexes with unique constraint */
int lVis_i = - 1 ; /* the position of last visible item for
* posting tuple . for non - posting tuple ( - 1 ) */
ItemPointer lVis_tid = NULL ;
BlockNumber lVis_block = InvalidBlockNumber ;
OffsetNumber lVis_offset = InvalidOffsetNumber ;
/* Last visible entry info for checking indexes with unique constraint */
BtreeLastVisibleEntry lVis = { InvalidBlockNumber , InvalidOffsetNumber , - 1 , NULL } ;
topaque = BTPageGetOpaque ( state - > target ) ;
max = PageGetMaxOffsetNumber ( state - > target ) ;
@ -1776,8 +1780,7 @@ bt_target_page_check(BtreeCheckState *state)
if ( state - > checkunique & & state - > indexinfo - > ii_Unique & &
P_ISLEAF ( topaque ) & & ! skey - > anynullkeys )
bt_entry_unique_check ( state , itup , state - > targetblock , offset ,
& lVis_i , & lVis_tid , & lVis_offset ,
& lVis_block ) ;
& lVis ) ;
if ( state - > checkunique & & state - > indexinfo - > ii_Unique & &
P_ISLEAF ( topaque ) & & OffsetNumberNext ( offset ) < = max )
@ -1800,10 +1803,10 @@ bt_target_page_check(BtreeCheckState *state)
if ( _bt_compare ( state - > rel , skey , state - > target ,
OffsetNumberNext ( offset ) ) ! = 0 | | skey - > anynullkeys )
{
lVis_i = - 1 ;
lVis_tid = NULL ;
lVis_block = InvalidBlockNumber ;
lVis_offset = InvalidOffsetNumber ;
lVis . blkno = InvalidBlockNumber ;
lVis . offset = InvalidOffsetNumber ;
lVis . postingIndex = - 1 ;
lVis . tid = NULL ;
}
skey - > scantid = scantid ; /* Restore saved scan key state */
}
@ -1902,9 +1905,7 @@ bt_target_page_check(BtreeCheckState *state)
rightfirstoffset ) ;
itup = ( IndexTuple ) PageGetItem ( state - > target , itemid ) ;
bt_entry_unique_check ( state , itup , rightblock_number , rightfirstoffset ,
& lVis_i , & lVis_tid , & lVis_offset ,
& lVis_block ) ;
bt_entry_unique_check ( state , itup , rightblock_number , rightfirstoffset , & lVis ) ;
}
}
}