Skip to content

Commit daec84f

Browse files
committed
Fixed (I hope) unique btree index implementation.
1 parent c6a6057 commit daec84f

File tree

1 file changed

+88
-26
lines changed

1 file changed

+88
-26
lines changed

src/backend/access/nbtree/nbtinsert.c

Lines changed: 88 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
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
*/
@@ -17,6 +17,7 @@
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
*/
4344
InsertIndexResult
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
{
4647
ScanKey itup_scankey;
4748
IndexTuple 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 */
6162
stack = _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-
8764
blkno = 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

10178
buf = _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 */
104166
res = _bt_insertonpg(rel, buf, stack, natts, itup_scankey,

0 commit comments

Comments
 (0)