@@ -145,6 +145,19 @@ typedef struct BtreeLevel
145
145
bool istruerootlevel ;
146
146
} BtreeLevel ;
147
147
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
+
148
161
PG_FUNCTION_INFO_V1 (bt_index_check );
149
162
PG_FUNCTION_INFO_V1 (bt_index_parent_check );
150
163
@@ -165,17 +178,14 @@ static void bt_recheck_sibling_links(BtreeCheckState *state,
165
178
BlockNumber btpo_prev_from_target ,
166
179
BlockNumber leftcurrent );
167
180
static 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 ,
171
184
BlockNumber nblock , OffsetNumber noffset ,
172
185
int nposting );
173
186
static 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 );
179
189
static void bt_target_page_check (BtreeCheckState * state );
180
190
static BTScanInsert bt_right_page_check_scankey (BtreeCheckState * state ,
181
191
OffsetNumber * rightfirstoffset );
@@ -997,8 +1007,7 @@ heap_entry_is_visible(BtreeCheckState *state, ItemPointer tid)
997
1007
*/
998
1008
static void
999
1009
bt_report_duplicate (BtreeCheckState * state ,
1000
- ItemPointer tid , BlockNumber block , OffsetNumber offset ,
1001
- int posting ,
1010
+ BtreeLastVisibleEntry * lVis ,
1002
1011
ItemPointer nexttid , BlockNumber nblock , OffsetNumber noffset ,
1003
1012
int nposting )
1004
1013
{
@@ -1010,18 +1019,18 @@ bt_report_duplicate(BtreeCheckState *state,
1010
1019
* pnposting = "" ;
1011
1020
1012
1021
htid = psprintf ("tid=(%u,%u)" ,
1013
- ItemPointerGetBlockNumberNoCheck (tid ),
1014
- ItemPointerGetOffsetNumberNoCheck (tid ));
1022
+ ItemPointerGetBlockNumberNoCheck (lVis -> tid ),
1023
+ ItemPointerGetOffsetNumberNoCheck (lVis -> tid ));
1015
1024
nhtid = psprintf ("tid=(%u,%u)" ,
1016
1025
ItemPointerGetBlockNumberNoCheck (nexttid ),
1017
1026
ItemPointerGetOffsetNumberNoCheck (nexttid ));
1018
- itid = psprintf ("tid=(%u,%u)" , block , offset );
1027
+ itid = psprintf ("tid=(%u,%u)" , lVis -> blkno , lVis -> offset );
1019
1028
1020
- if (nblock != block || noffset != offset )
1029
+ if (nblock != lVis -> blkno || noffset != lVis -> offset )
1021
1030
nitid = psprintf (" tid=(%u,%u)" , nblock , noffset );
1022
1031
1023
- if (posting >= 0 )
1024
- pposting = psprintf (" posting %u" , posting );
1032
+ if (lVis -> postingIndex >= 0 )
1033
+ pposting = psprintf (" posting %u" , lVis -> postingIndex );
1025
1034
1026
1035
if (nposting >= 0 )
1027
1036
pnposting = psprintf (" posting %u" , nposting );
@@ -1038,9 +1047,8 @@ bt_report_duplicate(BtreeCheckState *state,
1038
1047
/* Check if current nbtree leaf entry complies with UNIQUE constraint */
1039
1048
static void
1040
1049
bt_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 )
1044
1052
{
1045
1053
ItemPointer tid ;
1046
1054
bool has_visible_entry = false;
@@ -1049,7 +1057,7 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
1049
1057
1050
1058
/*
1051
1059
* 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.
1053
1061
*/
1054
1062
if (BTreeTupleIsPosting (itup ))
1055
1063
{
@@ -1059,11 +1067,10 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
1059
1067
if (heap_entry_is_visible (state , tid ))
1060
1068
{
1061
1069
has_visible_entry = true;
1062
- if (ItemPointerIsValid (* lVis_tid ))
1070
+ if (ItemPointerIsValid (lVis -> tid ))
1063
1071
{
1064
1072
bt_report_duplicate (state ,
1065
- * lVis_tid , * lVis_block ,
1066
- * lVis_offset , * lVis_i ,
1073
+ lVis ,
1067
1074
tid , targetblock ,
1068
1075
offset , i );
1069
1076
}
@@ -1073,59 +1080,60 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,
1073
1080
* between the posting list entries of the first tuple on the
1074
1081
* page after cross-page check.
1075
1082
*/
1076
- if (* lVis_block != targetblock && ItemPointerIsValid (* lVis_tid ))
1083
+ if (lVis -> blkno != targetblock && ItemPointerIsValid (lVis -> tid ))
1077
1084
return ;
1078
1085
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 ;
1083
1090
}
1084
1091
}
1085
1092
}
1086
1093
1087
1094
/*
1088
1095
* Current tuple has no posting list. If TID is visible save info about it
1089
1096
* 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.
1091
1098
*/
1092
1099
else
1093
1100
{
1094
1101
tid = BTreeTupleGetHeapTID (itup );
1095
1102
if (heap_entry_is_visible (state , tid ))
1096
1103
{
1097
1104
has_visible_entry = true;
1098
- if (ItemPointerIsValid (* lVis_tid ))
1105
+ if (ItemPointerIsValid (lVis -> tid ))
1099
1106
{
1100
1107
bt_report_duplicate (state ,
1101
- * lVis_tid , * lVis_block ,
1102
- * lVis_offset , * lVis_i ,
1108
+ lVis ,
1103
1109
tid , targetblock ,
1104
1110
offset , -1 );
1105
1111
}
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 ;
1110
1117
}
1111
1118
}
1112
1119
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 )
1115
1123
{
1116
1124
char * posting = "" ;
1117
1125
1118
- if (* lVis_i >= 0 )
1119
- posting = psprintf (" posting %u" , * lVis_i );
1126
+ if (lVis -> postingIndex >= 0 )
1127
+ posting = psprintf (" posting %u" , lVis -> postingIndex );
1120
1128
ereport (DEBUG1 ,
1121
1129
(errcode (ERRCODE_NO_DATA ),
1122
1130
errmsg ("index uniqueness can not be checked for index tid=(%u,%u) in index \"%s\"" ,
1123
1131
targetblock , offset ,
1124
1132
RelationGetRelationName (state -> rel )),
1125
1133
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 )),
1129
1137
errhint ("VACUUM the table and repeat the check." )));
1130
1138
}
1131
1139
}
@@ -1372,12 +1380,8 @@ bt_target_page_check(BtreeCheckState *state)
1372
1380
OffsetNumber max ;
1373
1381
BTPageOpaque topaque ;
1374
1382
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 };
1381
1385
1382
1386
topaque = BTPageGetOpaque (state -> target );
1383
1387
max = PageGetMaxOffsetNumber (state -> target );
@@ -1776,8 +1780,7 @@ bt_target_page_check(BtreeCheckState *state)
1776
1780
if (state -> checkunique && state -> indexinfo -> ii_Unique &&
1777
1781
P_ISLEAF (topaque ) && !skey -> anynullkeys )
1778
1782
bt_entry_unique_check (state , itup , state -> targetblock , offset ,
1779
- & lVis_i , & lVis_tid , & lVis_offset ,
1780
- & lVis_block );
1783
+ & lVis );
1781
1784
1782
1785
if (state -> checkunique && state -> indexinfo -> ii_Unique &&
1783
1786
P_ISLEAF (topaque ) && OffsetNumberNext (offset ) <= max )
@@ -1800,10 +1803,10 @@ bt_target_page_check(BtreeCheckState *state)
1800
1803
if (_bt_compare (state -> rel , skey , state -> target ,
1801
1804
OffsetNumberNext (offset )) != 0 || skey -> anynullkeys )
1802
1805
{
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 ;
1807
1810
}
1808
1811
skey -> scantid = scantid ; /* Restore saved scan key state */
1809
1812
}
@@ -1902,9 +1905,7 @@ bt_target_page_check(BtreeCheckState *state)
1902
1905
rightfirstoffset );
1903
1906
itup = (IndexTuple ) PageGetItem (state -> target , itemid );
1904
1907
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 );
1908
1909
}
1909
1910
}
1910
1911
}
0 commit comments