@@ -1433,6 +1433,13 @@ bt_target_page_check(BtreeCheckState *state)
14331433bool lowersizelimit ;
14341434ItemPointer scantid ;
14351435
1436+ /*
1437+ * True if we already called bt_entry_unique_check() for the current
1438+ * item. This helps to avoid visiting the heap for keys, which are
1439+ * anyway presented only once and can't comprise a unique violation.
1440+ */
1441+ bool unique_checked = false;
1442+
14361443CHECK_FOR_INTERRUPTS ();
14371444
14381445itemid = PageGetItemIdCareful (state ,state -> targetblock ,
@@ -1775,12 +1782,18 @@ bt_target_page_check(BtreeCheckState *state)
17751782
17761783/*
17771784 * If the index is unique verify entries uniqueness by checking the
1778- * heap tuples visibility.
1785+ * heap tuples visibility. Immediately check posting tuples and
1786+ * tuples with repeated keys. Postpone check for keys, which have the
1787+ * first appearance.
17791788 */
17801789if (state -> checkunique && state -> indexinfo -> ii_Unique &&
1781- P_ISLEAF (topaque )&& !skey -> anynullkeys )
1790+ P_ISLEAF (topaque )&& !skey -> anynullkeys &&
1791+ (BTreeTupleIsPosting (itup )|| ItemPointerIsValid (lVis .tid )))
1792+ {
17821793bt_entry_unique_check (state ,itup ,state -> targetblock ,offset ,
17831794& lVis );
1795+ unique_checked = true;
1796+ }
17841797
17851798if (state -> checkunique && state -> indexinfo -> ii_Unique &&
17861799P_ISLEAF (topaque )&& OffsetNumberNext (offset ) <=max )
@@ -1799,6 +1812,9 @@ bt_target_page_check(BtreeCheckState *state)
17991812 * data (whole index tuple or last posting in index tuple). Key
18001813 * containing null value does not violate unique constraint and
18011814 * treated as different to any other key.
1815+ *
1816+ * If the next key is the same as the previous one, do the
1817+ * bt_entry_unique_check() call if it was postponed.
18021818 */
18031819if (_bt_compare (state -> rel ,skey ,state -> target ,
18041820OffsetNumberNext (offset ))!= 0 || skey -> anynullkeys )
@@ -1808,6 +1824,11 @@ bt_target_page_check(BtreeCheckState *state)
18081824lVis .postingIndex = -1 ;
18091825lVis .tid = NULL ;
18101826}
1827+ else if (!unique_checked )
1828+ {
1829+ bt_entry_unique_check (state ,itup ,state -> targetblock ,offset ,
1830+ & lVis );
1831+ }
18111832skey -> scantid = scantid ;/* Restore saved scan key state */
18121833}
18131834
@@ -1890,10 +1911,19 @@ bt_target_page_check(BtreeCheckState *state)
18901911rightkey -> scantid = NULL ;
18911912
18921913/* The first key on the next page is the same */
1893- if (_bt_compare (state -> rel ,rightkey ,state -> target ,max )== 0 && !rightkey -> anynullkeys )
1914+ if (_bt_compare (state -> rel ,rightkey ,state -> target ,max )== 0 &&
1915+ !rightkey -> anynullkeys )
18941916{
18951917Page rightpage ;
18961918
1919+ /*
1920+ * Do the bt_entry_unique_check() call if it was
1921+ * postponed.
1922+ */
1923+ if (!unique_checked )
1924+ bt_entry_unique_check (state ,itup ,state -> targetblock ,
1925+ offset ,& lVis );
1926+
18971927elog (DEBUG2 ,"cross page equal keys" );
18981928rightpage = palloc_btree_page (state ,
18991929rightblock_number );