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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Postgres btree pages look like ordinary relation pages. The opaque * Postgres btree pages look like ordinary relation pages. The opaque
...@@ -441,6 +441,9 @@ _bt_metaproot(Relation rel, BlockNumber rootbknum, int level) ...@@ -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 * This is possible because we save a bit image of the last item
* we looked at in the parent, and the update algorithm guarantees * we looked at in the parent, and the update algorithm guarantees
* that if items above us in the tree move, they only move right. * 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 Buffer
_bt_getstackbuf(Relation rel, BTStack stack, int access) _bt_getstackbuf(Relation rel, BTStack stack, int access)
...@@ -453,6 +456,8 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access) ...@@ -453,6 +456,8 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
ItemId itemid; ItemId itemid;
BTItem item; BTItem item;
BTPageOpaque opaque; BTPageOpaque opaque;
BTItem item_save;
int item_nbytes;
blkno = stack->bts_blkno; blkno = stack->bts_blkno;
buf = _bt_getbuf(rel, blkno, access); buf = _bt_getbuf(rel, blkno, access);
...@@ -466,7 +471,14 @@ _bt_getstackbuf(Relation rel, BTStack stack, int 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 the item is where we left it, we're done */
if ( BTItemSame (item, stack->bts_btitem) ) 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); return (buf);
}
/* if the item has just moved right on this page, we're done */ /* if the item has just moved right on this page, we're done */
for (i = OffsetNumberNext(stack->bts_offset); for (i = OffsetNumberNext(stack->bts_offset);
...@@ -477,9 +489,17 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access) ...@@ -477,9 +489,17 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
/* if the item is where we left it, we're done */ /* if the item is where we left it, we're done */
if ( BTItemSame (item, stack->bts_btitem) ) 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); return (buf);
} }
} }
}
/* by here, the item we're looking for moved right at least one page */ /* by here, the item we're looking for moved right at least one page */
for (;;) { for (;;) {
...@@ -503,9 +523,18 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access) ...@@ -503,9 +523,18 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
itemid = PageGetItemId(page, offnum); itemid = PageGetItemId(page, offnum);
item = (BTItem) PageGetItem(page, itemid); item = (BTItem) PageGetItem(page, itemid);
if ( BTItemSame (item, stack->bts_btitem) ) 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); return (buf);
} }
} }
}
} }
void void
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -158,9 +158,7 @@ _bt_moveright(Relation rel,
Page page; Page page;
BTPageOpaque opaque; BTPageOpaque opaque;
ItemId hikey; ItemId hikey;
ItemId itemid;
BlockNumber rblkno; BlockNumber rblkno;
int natts = rel->rd_rel->relnatts;
page = BufferGetPage(buf); page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
...@@ -184,7 +182,7 @@ _bt_moveright(Relation rel, ...@@ -184,7 +182,7 @@ _bt_moveright(Relation rel,
/* move right as long as we need to */ /* move right as long as we need to */
do do
{ {
OffsetNumber offmax; OffsetNumber offmax = PageGetMaxOffsetNumber(page);
/* /*
* If this page consists of all duplicate keys (hikey and first * 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 * key on the page have the same value), then we don't need to
...@@ -200,22 +198,43 @@ _bt_moveright(Relation rel, ...@@ -200,22 +198,43 @@ _bt_moveright(Relation rel,
* our scankey is x = 2. Scankey >= (2,1) because of * our scankey is x = 2. Scankey >= (2,1) because of
* we compare first attrs only, but we shouldn't to move * we compare first attrs only, but we shouldn't to move
* right of here. - vadim 04/15/97 * 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 ( opaque->btpo_flags & BTP_CHAIN )
if (_bt_skeycmp(rel, keysz, scankey, page, itemid, {
BTEqualStrategyNumber)) { Assert ( ( opaque->btpo_flags & BTP_LEAF ) || offmax > P_HIKEY );
/* break is for the "move right" while loop */
break; break;
} }
else if ( natts > keysz ) if ( offmax > P_HIKEY )
{ {
itemid = PageGetItemId(page, offmax); if ( _bt_skeycmp (rel, keysz, scankey, page,
if (_bt_skeycmp(rel, keysz, scankey, page, itemid, PageGetItemId (page, offmax),
BTLessEqualStrategyNumber)) BTLessEqualStrategyNumber) )
break; break;
} }
else if ( offmax == P_HIKEY &&
( opaque->btpo_flags & BTP_LEAF ) )
break;
} }
/* step right one page */ /* step right one page */
...@@ -371,27 +390,37 @@ _bt_binsrch(Relation rel, ...@@ -371,27 +390,37 @@ _bt_binsrch(Relation rel,
int natts = rel->rd_rel->relnatts; int natts = rel->rd_rel->relnatts;
int result; int result;
itupdesc = RelationGetTupleDescriptor(rel);
page = BufferGetPage(buf); page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page); 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; low = mid = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
high = PageGetMaxOffsetNumber(page); 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 * 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. * 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 * 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. * 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); return (low);
if ( (! P_RIGHTMOST(opaque) && high <= low))
itupdesc = RelationGetTupleDescriptor(rel); {
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) { while ((high - low) > 1) {
mid = low + ((high - low) / 2); mid = low + ((high - low) / 2);
...@@ -736,6 +765,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ...@@ -736,6 +765,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
TupleDesc itupdesc; TupleDesc itupdesc;
Buffer buf; Buffer buf;
Page page; Page page;
BTPageOpaque pop;
BTStack stack; BTStack stack;
OffsetNumber offnum, maxoff; OffsetNumber offnum, maxoff;
bool offGmax = false; bool offGmax = false;
...@@ -804,8 +834,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ...@@ -804,8 +834,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
stack = _bt_search(rel, 1, &skdata, &buf); stack = _bt_search(rel, 1, &skdata, &buf);
_bt_freestack(stack); _bt_freestack(stack);
/* find the nearest match to the manufactured scan key on the page */ blkno = BufferGetBlockNumber(buf);
offnum = _bt_binsrch(rel, buf, 1, &skdata, BT_DESCENT);
page = BufferGetPage(buf); page = BufferGetPage(buf);
/* /*
...@@ -821,8 +850,39 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ...@@ -821,8 +850,39 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
_bt_relbuf(rel, buf, BT_READ); _bt_relbuf(rel, buf, BT_READ);
return ((RetrieveIndexResult) NULL); 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); 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) if (offnum > maxoff)
{ {
...@@ -830,7 +890,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ...@@ -830,7 +890,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
offGmax = true; offGmax = true;
} }
blkno = BufferGetBlockNumber(buf);
ItemPointerSet(current, blkno, offnum); ItemPointerSet(current, blkno, offnum);
/* /*
...@@ -889,7 +948,32 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ...@@ -889,7 +948,32 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
break; break;
case BTGreaterEqualStrategyNumber: 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 { do {
if (!_bt_twostep(scan, &buf, BackwardScanDirection)) if (!_bt_twostep(scan, &buf, BackwardScanDirection))
break; break;
...@@ -902,16 +986,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ...@@ -902,16 +986,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
if (result > 0) if (result > 0)
(void) _bt_twostep(scan, &buf, ForwardScanDirection); (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; break;
case BTGreaterStrategyNumber: case BTGreaterStrategyNumber:
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -983,6 +983,12 @@ _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags) ...@@ -983,6 +983,12 @@ _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags)
oopaque->btpo_next = BufferGetBlockNumber(nbuf); oopaque->btpo_next = BufferGetBlockNumber(nbuf);
nopaque->btpo_prev = BufferGetBlockNumber(obuf); nopaque->btpo_prev = BufferGetBlockNumber(obuf);
nopaque->btpo_next = P_NONE; 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