@@ -145,6 +145,19 @@ typedef struct BtreeLevel
145145 bool istruerootlevel ;
146146} BtreeLevel ;
147147
148+ /*
149+ * Information about the last visible entry with current B-tree key. Used
150+ * for validation of the unique constraint.
151+ */
152+ typedef struct BtreeLastVisibleEntry
153+ {
154+ BlockNumber blkno ; /* Index block */
155+ OffsetNumber offset ; /* Offset on index block */
156+ int postingIndex ; /* Number in the posting list (-1 for
157+ * non-deduplicated tuples) */
158+ ItemPointer tid ; /* Heap tid */
159+ } BtreeLastVisibleEntry ;
160+
148161PG_FUNCTION_INFO_V1 (bt_index_check );
149162PG_FUNCTION_INFO_V1 (bt_index_parent_check );
150163
@@ -165,17 +178,14 @@ static void bt_recheck_sibling_links(BtreeCheckState *state,
165178 BlockNumber btpo_prev_from_target ,
166179 BlockNumber leftcurrent );
167180static bool heap_entry_is_visible (BtreeCheckState * state , ItemPointer tid );
168- static void bt_report_duplicate (BtreeCheckState * state , ItemPointer tid ,
169- BlockNumber block , OffsetNumber offset ,
170- int posting , ItemPointer nexttid ,
181+ static void bt_report_duplicate (BtreeCheckState * state ,
182+ BtreeLastVisibleEntry * lVis ,
183+ ItemPointer nexttid ,
171184 BlockNumber nblock , OffsetNumber noffset ,
172185 int nposting );
173186static void bt_entry_unique_check (BtreeCheckState * state , IndexTuple itup ,
174- BlockNumber targetblock ,
175- OffsetNumber offset , int * lVis_i ,
176- ItemPointer * lVis_tid ,
177- OffsetNumber * lVis_offset ,
178- BlockNumber * lVis_block );
187+ BlockNumber targetblock , OffsetNumber offset ,
188+ BtreeLastVisibleEntry * lVis );
179189static void bt_target_page_check (BtreeCheckState * state );
180190static BTScanInsert bt_right_page_check_scankey (BtreeCheckState * state ,
181191 OffsetNumber * rightfirstoffset );
@@ -997,8 +1007,7 @@ heap_entry_is_visible(BtreeCheckState *state, ItemPointer tid)
9971007 */
9981008static void
9991009bt_report_duplicate (BtreeCheckState * state ,
1000- ItemPointer tid , BlockNumber block , OffsetNumber offset ,
1001- int posting ,
1010+ BtreeLastVisibleEntry * lVis ,
10021011 ItemPointer nexttid , BlockNumber nblock , OffsetNumber noffset ,
10031012 int nposting )
10041013{
@@ -1010,18 +1019,18 @@ bt_report_duplicate(BtreeCheckState *state,
10101019 * pnposting = "" ;
10111020
10121021 htid = psprintf ("tid=(%u,%u)" ,
1013- ItemPointerGetBlockNumberNoCheck (tid ),
1014- ItemPointerGetOffsetNumberNoCheck (tid ));
1022+ ItemPointerGetBlockNumberNoCheck (lVis -> tid ),
1023+ ItemPointerGetOffsetNumberNoCheck (lVis -> tid ));
10151024 nhtid = psprintf ("tid=(%u,%u)" ,
10161025 ItemPointerGetBlockNumberNoCheck (nexttid ),
10171026 ItemPointerGetOffsetNumberNoCheck (nexttid ));
1018- itid = psprintf ("tid=(%u,%u)" , block , offset );
1027+ itid = psprintf ("tid=(%u,%u)" , lVis -> blkno , lVis -> offset );
10191028
1020- if (nblock != block || noffset != offset )
1029+ if (nblock != lVis -> blkno || noffset != lVis -> offset )
10211030 nitid = psprintf (" tid=(%u,%u)" , nblock , noffset );
10221031
1023- if (posting >= 0 )
1024- pposting = psprintf (" posting %u" , posting );
1032+ if (lVis -> postingIndex >= 0 )
1033+ pposting = psprintf (" posting %u" , lVis -> postingIndex );
10251034
10261035 if (nposting >= 0 )
10271036 pnposting = psprintf (" posting %u" , nposting );
@@ -1038,9 +1047,8 @@ bt_report_duplicate(BtreeCheckState *state,
10381047/* Check if current nbtree leaf entry complies with UNIQUE constraint */
10391048static void
10401049bt_entry_unique_check (BtreeCheckState * state , IndexTuple itup ,
1041- BlockNumber targetblock , OffsetNumber offset , int * lVis_i ,
1042- ItemPointer * lVis_tid , OffsetNumber * lVis_offset ,
1043- BlockNumber * lVis_block )
1050+ BlockNumber targetblock , OffsetNumber offset ,
1051+ BtreeLastVisibleEntry * lVis )
10441052{
10451053 ItemPointer tid ;
10461054 bool has_visible_entry = false;
@@ -1049,7 +1057,7 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
10491057
10501058 /*
10511059 * Current tuple has posting list. Report duplicate if TID of any posting
1052- * list entry is visible and lVis_tid is valid.
1060+ * list entry is visible and lVis->tid is valid.
10531061 */
10541062 if (BTreeTupleIsPosting (itup ))
10551063 {
@@ -1059,11 +1067,10 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
10591067 if (heap_entry_is_visible (state , tid ))
10601068 {
10611069 has_visible_entry = true;
1062- if (ItemPointerIsValid (* lVis_tid ))
1070+ if (ItemPointerIsValid (lVis -> tid ))
10631071 {
10641072 bt_report_duplicate (state ,
1065- * lVis_tid , * lVis_block ,
1066- * lVis_offset , * lVis_i ,
1073+ lVis ,
10671074 tid , targetblock ,
10681075 offset , i );
10691076 }
@@ -1073,59 +1080,60 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
10731080 * between the posting list entries of the first tuple on the
10741081 * page after cross-page check.
10751082 */
1076- if (* lVis_block != targetblock && ItemPointerIsValid (* lVis_tid ))
1083+ if (lVis -> blkno != targetblock && ItemPointerIsValid (lVis -> tid ))
10771084 return ;
10781085
1079- * lVis_i = i ;
1080- * lVis_tid = tid ;
1081- * lVis_offset = offset ;
1082- * lVis_block = targetblock ;
1086+ lVis -> blkno = targetblock ;
1087+ lVis -> offset = offset ;
1088+ lVis -> postingIndex = i ;
1089+ lVis -> tid = tid ;
10831090 }
10841091 }
10851092 }
10861093
10871094 /*
10881095 * Current tuple has no posting list. If TID is visible save info about it
10891096 * for the next comparisons in the loop in bt_target_page_check(). Report
1090- * duplicate if lVis_tid is already valid.
1097+ * duplicate if lVis->tid is already valid.
10911098 */
10921099 else
10931100 {
10941101 tid = BTreeTupleGetHeapTID (itup );
10951102 if (heap_entry_is_visible (state , tid ))
10961103 {
10971104 has_visible_entry = true;
1098- if (ItemPointerIsValid (* lVis_tid ))
1105+ if (ItemPointerIsValid (lVis -> tid ))
10991106 {
11001107 bt_report_duplicate (state ,
1101- * lVis_tid , * lVis_block ,
1102- * lVis_offset , * lVis_i ,
1108+ lVis ,
11031109 tid , targetblock ,
11041110 offset , -1 );
11051111 }
1106- * lVis_i = -1 ;
1107- * lVis_tid = tid ;
1108- * lVis_offset = offset ;
1109- * lVis_block = targetblock ;
1112+
1113+ lVis -> blkno = targetblock ;
1114+ lVis -> offset = offset ;
1115+ lVis -> tid = tid ;
1116+ lVis -> postingIndex = -1 ;
11101117 }
11111118 }
11121119
1113- if (!has_visible_entry && * lVis_block != InvalidBlockNumber &&
1114- * lVis_block != targetblock )
1120+ if (!has_visible_entry &&
1121+ lVis -> blkno != InvalidBlockNumber &&
1122+ lVis -> blkno != targetblock )
11151123 {
11161124 char * posting = "" ;
11171125
1118- if (* lVis_i >= 0 )
1119- posting = psprintf (" posting %u" , * lVis_i );
1126+ if (lVis -> postingIndex >= 0 )
1127+ posting = psprintf (" posting %u" , lVis -> postingIndex );
11201128 ereport (DEBUG1 ,
11211129 (errcode (ERRCODE_NO_DATA ),
11221130 errmsg ("index uniqueness can not be checked for index tid=(%u,%u) in index \"%s\"" ,
11231131 targetblock , offset ,
11241132 RelationGetRelationName (state -> rel )),
11251133 errdetail ("It doesn't have visible heap tids and key is equal to the tid=(%u,%u)%s (points to heap tid=(%u,%u))." ,
1126- * lVis_block , * lVis_offset , posting ,
1127- ItemPointerGetBlockNumberNoCheck (* lVis_tid ),
1128- ItemPointerGetOffsetNumberNoCheck (* lVis_tid )),
1134+ lVis -> blkno , lVis -> offset , posting ,
1135+ ItemPointerGetBlockNumberNoCheck (lVis -> tid ),
1136+ ItemPointerGetOffsetNumberNoCheck (lVis -> tid )),
11291137 errhint ("VACUUM the table and repeat the check." )));
11301138 }
11311139}
@@ -1372,12 +1380,8 @@ bt_target_page_check(BtreeCheckState *state)
13721380 OffsetNumber max ;
13731381 BTPageOpaque topaque ;
13741382
1375- /* last visible entry info for checking indexes with unique constraint */
1376- int lVis_i = -1 ; /* the position of last visible item for
1377- * posting tuple. for non-posting tuple (-1) */
1378- ItemPointer lVis_tid = NULL ;
1379- BlockNumber lVis_block = InvalidBlockNumber ;
1380- OffsetNumber lVis_offset = InvalidOffsetNumber ;
1383+ /* Last visible entry info for checking indexes with unique constraint */
1384+ BtreeLastVisibleEntry lVis = {InvalidBlockNumber , InvalidOffsetNumber , -1 , NULL };
13811385
13821386 topaque = BTPageGetOpaque (state -> target );
13831387 max = PageGetMaxOffsetNumber (state -> target );
@@ -1776,8 +1780,7 @@ bt_target_page_check(BtreeCheckState *state)
17761780 if (state -> checkunique && state -> indexinfo -> ii_Unique &&
17771781 P_ISLEAF (topaque ) && !skey -> anynullkeys )
17781782 bt_entry_unique_check (state , itup , state -> targetblock , offset ,
1779- & lVis_i , & lVis_tid , & lVis_offset ,
1780- & lVis_block );
1783+ & lVis );
17811784
17821785 if (state -> checkunique && state -> indexinfo -> ii_Unique &&
17831786 P_ISLEAF (topaque ) && OffsetNumberNext (offset ) <= max )
@@ -1800,10 +1803,10 @@ bt_target_page_check(BtreeCheckState *state)
18001803 if (_bt_compare (state -> rel , skey , state -> target ,
18011804 OffsetNumberNext (offset )) != 0 || skey -> anynullkeys )
18021805 {
1803- lVis_i = -1 ;
1804- lVis_tid = NULL ;
1805- lVis_block = InvalidBlockNumber ;
1806- lVis_offset = InvalidOffsetNumber ;
1806+ lVis . blkno = InvalidBlockNumber ;
1807+ lVis . offset = InvalidOffsetNumber ;
1808+ lVis . postingIndex = -1 ;
1809+ lVis . tid = NULL ;
18071810 }
18081811 skey -> scantid = scantid ; /* Restore saved scan key state */
18091812 }
@@ -1902,9 +1905,7 @@ bt_target_page_check(BtreeCheckState *state)
19021905 rightfirstoffset );
19031906 itup = (IndexTuple ) PageGetItem (state -> target , itemid );
19041907
1905- bt_entry_unique_check (state , itup , rightblock_number , rightfirstoffset ,
1906- & lVis_i , & lVis_tid , & lVis_offset ,
1907- & lVis_block );
1908+ bt_entry_unique_check (state , itup , rightblock_number , rightfirstoffset , & lVis );
19081909 }
19091910 }
19101911 }
0 commit comments