Commit 3f5834fb authored by Vadim B. Mikheev's avatar Vadim B. Mikheev

Fix duplicates handling.

parent 43b6f1e6
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.7 1997/04/16 01:48:15 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.8 1997/05/30 18:35:33 vadim Exp $
*
* NOTES
* Postgres btree pages look like ordinary relation pages. The opaque
......@@ -441,6 +441,9 @@ _bt_metaproot(Relation rel, BlockNumber rootbknum, int level)
* This is possible because we save a bit image of the last item
* we looked at in the parent, and the update algorithm guarantees
* that if items above us in the tree move, they only move right.
*
* Also, re-set bts_blkno & bts_offset if changed and
* bts_btitem (it may be changed - see _bt_insertonpg).
*/
Buffer
_bt_getstackbuf(Relation rel, BTStack stack, int access)
......@@ -453,6 +456,8 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
ItemId itemid;
BTItem item;
BTPageOpaque opaque;
BTItem item_save;
int item_nbytes;
blkno = stack->bts_blkno;
buf = _bt_getbuf(rel, blkno, access);
......@@ -466,7 +471,14 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
/* if the item is where we left it, we're done */
if ( BTItemSame (item, stack->bts_btitem) )
{
pfree(stack->bts_btitem);
item_nbytes = ItemIdGetLength(itemid);
item_save = (BTItem) palloc(item_nbytes);
memmove((char *) item_save, (char *) item, item_nbytes);
stack->bts_btitem = item_save;
return (buf);
}
/* if the item has just moved right on this page, we're done */
for (i = OffsetNumberNext(stack->bts_offset);
......@@ -477,9 +489,17 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
/* if the item is where we left it, we're done */
if ( BTItemSame (item, stack->bts_btitem) )
{
stack->bts_offset = i;
pfree(stack->bts_btitem);
item_nbytes = ItemIdGetLength(itemid);
item_save = (BTItem) palloc(item_nbytes);
memmove((char *) item_save, (char *) item, item_nbytes);
stack->bts_btitem = item_save;
return (buf);
}
}
}
/* by here, the item we're looking for moved right at least one page */
for (;;) {
......@@ -503,9 +523,18 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
itemid = PageGetItemId(page, offnum);
item = (BTItem) PageGetItem(page, itemid);
if ( BTItemSame (item, stack->bts_btitem) )
{
stack->bts_offset = offnum;
stack->bts_blkno = blkno;
pfree(stack->bts_btitem);
item_nbytes = ItemIdGetLength(itemid);
item_save = (BTItem) palloc(item_nbytes);
memmove((char *) item_save, (char *) item, item_nbytes);
stack->bts_btitem = item_save;
return (buf);
}
}
}
}
void
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.19 1997/05/05 03:41:19 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.20 1997/05/30 18:35:37 vadim Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -158,9 +158,7 @@ _bt_moveright(Relation rel,
Page page;
BTPageOpaque opaque;
ItemId hikey;
ItemId itemid;
BlockNumber rblkno;
int natts = rel->rd_rel->relnatts;
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
......@@ -184,7 +182,7 @@ _bt_moveright(Relation rel,
/* move right as long as we need to */
do
{
OffsetNumber offmax;
OffsetNumber offmax = PageGetMaxOffsetNumber(page);
/*
* If this page consists of all duplicate keys (hikey and first
* key on the page have the same value), then we don't need to
......@@ -200,22 +198,43 @@ _bt_moveright(Relation rel,
* our scankey is x = 2. Scankey >= (2,1) because of
* we compare first attrs only, but we shouldn't to move
* right of here. - vadim 04/15/97
*
* XXX
* This code changed again! Actually, we break our
* duplicates handling in single case: if we insert
* new minimum key into leftmost page with duplicates
* and splitting doesn't occure then _bt_insertonpg doesn't
* worry about duplicates-rule. Fix _bt_insertonpg ?
* But I don't see why don't compare scankey with _last_
* item on the page instead of first one, in any cases.
* So - we do it in that way now. - vadim 05/26/97
*
* Also, if we are on an "pseudo-empty" leaf page (i.e. there is
* only hikey here) and scankey == hikey then we don't move
* right! It's fix for bug described in _bt_insertonpg(). It's
* right - at least till index cleanups are perfomed by vacuum
* in exclusive mode: so, though this page may be just splitted,
* it may not be "emptied" before we got here. - vadim 05/27/97
*/
if ( (offmax = PageGetMaxOffsetNumber(page)) > P_HIKEY)
if ( _bt_skeycmp (rel, keysz, scankey, page, hikey,
BTEqualStrategyNumber) )
{
itemid = PageGetItemId(page, P_FIRSTKEY);
if (_bt_skeycmp(rel, keysz, scankey, page, itemid,
BTEqualStrategyNumber)) {
/* break is for the "move right" while loop */
if ( opaque->btpo_flags & BTP_CHAIN )
{
Assert ( ( opaque->btpo_flags & BTP_LEAF ) || offmax > P_HIKEY );
break;
}
else if ( natts > keysz )
if ( offmax > P_HIKEY )
{
itemid = PageGetItemId(page, offmax);
if (_bt_skeycmp(rel, keysz, scankey, page, itemid,
BTLessEqualStrategyNumber))
if ( _bt_skeycmp (rel, keysz, scankey, page,
PageGetItemId (page, offmax),
BTLessEqualStrategyNumber) )
break;
}
else if ( offmax == P_HIKEY &&
( opaque->btpo_flags & BTP_LEAF ) )
break;
}
/* step right one page */
......@@ -371,27 +390,37 @@ _bt_binsrch(Relation rel,
int natts = rel->rd_rel->relnatts;
int result;
itupdesc = RelationGetTupleDescriptor(rel);
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
/* by convention, item 0 on any non-rightmost page is the high key */
/* by convention, item 1 on any non-rightmost page is the high key */
low = mid = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
high = PageGetMaxOffsetNumber(page);
/*
* Since for non-rightmost pages, the zeroeth item on the page is the
* Since for non-rightmost pages, the first item on the page is the
* high key, there are two notions of emptiness. One is if nothing
* appears on the page. The other is if nothing but the high key does.
* The reason we test high <= low, rather than high == low, is that
* after vacuuming there may be nothing *but* the high key on a page.
* In that case, given the scheme above, low = 1 and high = 0.
* In that case, given the scheme above, low = 2 and high = 1.
*/
if (PageIsEmpty(page) || (! P_RIGHTMOST(opaque) && high <= low))
if ( PageIsEmpty (page) )
return (low);
itupdesc = RelationGetTupleDescriptor(rel);
if ( (! P_RIGHTMOST(opaque) && high <= low))
{
if ( high < low ||
(srchtype == BT_DESCENT && !(opaque->btpo_flags & BTP_LEAF)) )
return (low);
/* It's insertion and high == low == 2 */
result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
if ( result > 0 )
return ( OffsetNumberNext (low) );
return (low);
}
while ((high - low) > 1) {
mid = low + ((high - low) / 2);
......@@ -736,6 +765,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
TupleDesc itupdesc;
Buffer buf;
Page page;
BTPageOpaque pop;
BTStack stack;
OffsetNumber offnum, maxoff;
bool offGmax = false;
......@@ -804,8 +834,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
stack = _bt_search(rel, 1, &skdata, &buf);
_bt_freestack(stack);
/* find the nearest match to the manufactured scan key on the page */
offnum = _bt_binsrch(rel, buf, 1, &skdata, BT_DESCENT);
blkno = BufferGetBlockNumber(buf);
page = BufferGetPage(buf);
/*
......@@ -821,8 +850,39 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
_bt_relbuf(rel, buf, BT_READ);
return ((RetrieveIndexResult) NULL);
}
maxoff = PageGetMaxOffsetNumber(page);
pop = (BTPageOpaque) PageGetSpecialPointer(page);
/*
* Now _bt_moveright doesn't move from non-rightmost leaf page
* if scankey == hikey and there is only hikey there. It's
* good for insertion, but we need to do work for scan here.
* - vadim 05/27/97
*/
while ( maxoff == P_HIKEY && !P_RIGHTMOST(pop) &&
_bt_skeycmp(rel, 1, &skdata, page,
PageGetItemId(page, P_HIKEY),
BTGreaterEqualStrategyNumber) )
{
/* step right one page */
blkno = pop->btpo_next;
_bt_relbuf(rel, buf, BT_READ);
buf = _bt_getbuf(rel, blkno, BT_READ);
page = BufferGetPage(buf);
if (PageIsEmpty(page)) {
ItemPointerSetInvalid(current);
so->btso_curbuf = InvalidBuffer;
_bt_relbuf(rel, buf, BT_READ);
return ((RetrieveIndexResult) NULL);
}
maxoff = PageGetMaxOffsetNumber(page);
pop = (BTPageOpaque) PageGetSpecialPointer(page);
}
/* find the nearest match to the manufactured scan key on the page */
offnum = _bt_binsrch(rel, buf, 1, &skdata, BT_DESCENT);
if (offnum > maxoff)
{
......@@ -830,7 +890,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
offGmax = true;
}
blkno = BufferGetBlockNumber(buf);
ItemPointerSet(current, blkno, offnum);
/*
......@@ -889,7 +948,32 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
break;
case BTGreaterEqualStrategyNumber:
if (result < 0) {
if ( offGmax )
{
if (result < 0)
{
Assert ( !P_RIGHTMOST(pop) && maxoff == P_HIKEY );
if ( !_bt_step(scan, &buf, ForwardScanDirection) )
{
_bt_relbuf(scan->relation, buf, BT_READ);
so->btso_curbuf = InvalidBuffer;
ItemPointerSetInvalid(&(scan->currentItemData));
return ((RetrieveIndexResult) NULL);
}
}
else if (result > 0)
{ /*
* Just remember: _bt_binsrch() returns the OffsetNumber of
* the first matching key on the page, or the OffsetNumber at
* which the matching key WOULD APPEAR IF IT WERE on this page.
* No key on this page, but offnum from _bt_binsrch() greater
* maxoff - have to move right. - vadim 12/06/96
*/
(void) _bt_twostep(scan, &buf, ForwardScanDirection);
}
}
else if (result < 0)
{
do {
if (!_bt_twostep(scan, &buf, BackwardScanDirection))
break;
......@@ -902,16 +986,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
if (result > 0)
(void) _bt_twostep(scan, &buf, ForwardScanDirection);
}
else if ( offGmax && result > 0 )
{ /*
* Just remember: _bt_binsrch() returns the OffsetNumber of
* the first matching key on the page, or the OffsetNumber at
* which the matching key WOULD APPEAR IF IT WERE on this page.
* No key on this page, but offnum from _bt_binsrch() greater
* maxoff - have to move right. - vadim 12/06/96
*/
(void) _bt_twostep(scan, &buf, ForwardScanDirection);
}
break;
case BTGreaterStrategyNumber:
......
......@@ -5,7 +5,7 @@
*
*
* IDENTIFICATION
* $Id: nbtsort.c,v 1.15 1997/04/18 03:37:57 vadim Exp $
* $Id: nbtsort.c,v 1.16 1997/05/30 18:35:40 vadim Exp $
*
* NOTES
*
......@@ -983,6 +983,12 @@ _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags)
oopaque->btpo_next = BufferGetBlockNumber(nbuf);
nopaque->btpo_prev = BufferGetBlockNumber(obuf);
nopaque->btpo_next = P_NONE;
if ( _bt_itemcmp(index, _bt_nattr,
(BTItem) PageGetItem(opage, PageGetItemId(opage, P_HIKEY)),
(BTItem) PageGetItem(opage, PageGetItemId(opage, P_FIRSTKEY)),
BTEqualStrategyNumber) )
oopaque->btpo_flags |= BTP_CHAIN;
}
/*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment