77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.8 1996/12/06 09:45:30 vadim Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.9 1997/01/10 10:06:20 vadim Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
1717#include <utils/memutils.h>
1818#include <storage/bufpage.h>
1919#include <access/nbtree.h>
20+ #include <access/heapam.h>
2021#include <storage/bufmgr.h>
2122
2223#ifndef HAVE_MEMMOVE
@@ -41,7 +42,7 @@ static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, Oid bti_oid, BT
4142 *(xid, seqno) pair.
4243 */
4344InsertIndexResult
44- _bt_doinsert (Relation rel ,BTItem btitem ,bool index_is_unique ,bool is_update )
45+ _bt_doinsert (Relation rel ,BTItem btitem ,bool index_is_unique ,Relation heapRel )
4546{
4647ScanKey itup_scankey ;
4748IndexTuple itup ;
@@ -60,30 +61,6 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, bool is_update)
6061/* find the page containing this key */
6162stack = _bt_search (rel ,natts ,itup_scankey ,& buf );
6263
63- /* if we're not allowing duplicates, make sure the key isn't */
64- /* already in the node */
65- if (index_is_unique && !is_update ) {
66- OffsetNumber offset ;
67- TupleDesc itupdesc ;
68- Page page ;
69-
70- itupdesc = RelationGetTupleDescriptor (rel );
71- page = BufferGetPage (buf );
72-
73- offset = _bt_binsrch (rel ,buf ,natts ,itup_scankey ,BT_DESCENT );
74-
75- /* make sure the offset we're given points to an actual */
76- /* key on the page before trying to compare it */
77- if (!PageIsEmpty (page )&&
78- offset <=PageGetMaxOffsetNumber (page )) {
79- if (!_bt_compare (rel ,itupdesc ,page ,
80- natts ,itup_scankey ,offset )) {
81- /* it is a duplicate */
82- elog (WARN ,"Cannot insert a duplicate key into a unique index." );
83- }
84- }
85- }
86-
8764blkno = BufferGetBlockNumber (buf );
8865
8966/* trade in our read lock for a write lock */
@@ -99,6 +76,91 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, bool is_update)
9976 */
10077
10178buf = _bt_moveright (rel ,buf ,natts ,itup_scankey ,BT_WRITE );
79+
80+ /* if we're not allowing duplicates, make sure the key isn't */
81+ /* already in the node */
82+ if (index_is_unique )
83+ {
84+ OffsetNumber offset ,maxoff ;
85+ Page page ;
86+
87+ page = BufferGetPage (buf );
88+ maxoff = PageGetMaxOffsetNumber (page );
89+
90+ offset = _bt_binsrch (rel ,buf ,natts ,itup_scankey ,BT_DESCENT );
91+
92+ /* make sure the offset we're given points to an actual */
93+ /* key on the page before trying to compare it */
94+ if ( !PageIsEmpty (page )&& offset <=maxoff )
95+ {
96+ TupleDesc itupdesc ;
97+ BTItem btitem ;
98+ IndexTuple itup ;
99+ HeapTuple htup ;
100+ BTPageOpaque opaque ;
101+ Buffer nbuf ;
102+ BlockNumber blkno ;
103+
104+ itupdesc = RelationGetTupleDescriptor (rel );
105+ nbuf = InvalidBuffer ;
106+ opaque = (BTPageOpaque )PageGetSpecialPointer (page );
107+ while ( !_bt_compare (rel ,itupdesc ,page ,
108+ natts ,itup_scankey ,offset ) )
109+ {/* they're equal */
110+ btitem = (BTItem )PageGetItem (page ,PageGetItemId (page ,offset ));
111+ itup = & (btitem -> bti_itup );
112+ htup = heap_fetch (heapRel ,SelfTimeQual ,& (itup -> t_tid ),NULL );
113+ if (htup != (HeapTuple )NULL )
114+ {/* it is a duplicate */
115+ elog (WARN ,"Cannot insert a duplicate key into a unique index." );
116+ }
117+ /* get next offnum */
118+ if (offset < maxoff )
119+ {
120+ offset = OffsetNumberNext (offset );
121+ }
122+ else
123+ {/* move right ? */
124+ if (P_RIGHTMOST (opaque ) )
125+ break ;
126+ if (_bt_compare (rel ,itupdesc ,page ,
127+ natts ,itup_scankey ,P_HIKEY ) )
128+ break ;
129+ /*
130+ * min key of the right page is the same,
131+ * ooh - so many dead duplicates...
132+ */
133+ blkno = opaque -> btpo_next ;
134+ if (nbuf != InvalidBuffer )
135+ _bt_relbuf (rel ,nbuf ,BT_READ );
136+ for (nbuf = InvalidBuffer ; ; )
137+ {
138+ nbuf = _bt_getbuf (rel ,blkno ,BT_READ );
139+ page = BufferGetPage (nbuf );
140+ maxoff = PageGetMaxOffsetNumber (page );
141+ opaque = (BTPageOpaque )PageGetSpecialPointer (page );
142+ offset = P_RIGHTMOST (opaque ) ?P_HIKEY :P_FIRSTKEY ;
143+ if ( !PageIsEmpty (page )&& offset <=maxoff )
144+ {/* Found some key */
145+ break ;
146+ }
147+ else
148+ {/* Empty or "pseudo"-empty page - get next */
149+ blkno = opaque -> btpo_next ;
150+ _bt_relbuf (rel ,nbuf ,BT_READ );
151+ nbuf = InvalidBuffer ;
152+ if (blkno == P_NONE )
153+ break ;
154+ }
155+ }
156+ if (nbuf == InvalidBuffer )
157+ break ;
158+ }
159+ }
160+ if (nbuf != InvalidBuffer )
161+ _bt_relbuf (rel ,nbuf ,BT_READ );
162+ }
163+ }
102164
103165/* do the insertion */
104166res = _bt_insertonpg (rel ,buf ,stack ,natts ,itup_scankey ,