aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtsearch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/nbtree/nbtsearch.c')
-rw-r--r--src/backend/access/nbtree/nbtsearch.c146
1 files changed, 99 insertions, 47 deletions
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 99fb38f18ce..b72ccedf96e 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.16 1997/03/24 08:48:12 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.17 1997/04/16 01:48:17 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@@ -160,7 +160,8 @@ _bt_moveright(Relation rel,
ItemId hikey;
ItemId itemid;
BlockNumber rblkno;
-
+ int natts = rel->rd_rel->relnatts;
+
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
@@ -178,22 +179,43 @@ _bt_moveright(Relation rel,
*/
if (_bt_skeycmp(rel, keysz, scankey, page, hikey,
- BTGreaterEqualStrategyNumber)) {
-
+ BTGreaterEqualStrategyNumber))
+ {
/* move right as long as we need to */
- do {
+ do
+ {
+ OffsetNumber offmax;
/*
* 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
* step right.
+ *
+ * NOTE for multi-column indices: we may do scan using
+ * keys not for all attrs. But we handle duplicates
+ * using all attrs in _bt_insert/_bt_spool code.
+ * And so we've to compare scankey with _last_ item
+ * on this page to do not lose "good" tuples if number
+ * of attrs > keysize. Example: (2,0) - last items on
+ * this page, (2,1) - first item on next page (hikey),
+ * 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
*/
- if (PageGetMaxOffsetNumber(page) > P_HIKEY) {
+ if ( (offmax = PageGetMaxOffsetNumber(page)) > P_HIKEY)
+ {
itemid = PageGetItemId(page, P_FIRSTKEY);
if (_bt_skeycmp(rel, keysz, scankey, page, itemid,
BTEqualStrategyNumber)) {
/* break is for the "move right" while loop */
break;
}
+ else if ( natts > keysz )
+ {
+ itemid = PageGetItemId(page, offmax);
+ if (_bt_skeycmp(rel, keysz, scankey, page, itemid,
+ BTLessEqualStrategyNumber))
+ break;
+ }
}
/* step right one page */
@@ -346,6 +368,7 @@ _bt_binsrch(Relation rel,
Page page;
BTPageOpaque opaque;
OffsetNumber low, mid, high;
+ int natts = rel->rd_rel->relnatts;
int result;
page = BufferGetPage(buf);
@@ -379,55 +402,84 @@ _bt_binsrch(Relation rel,
else if (result < 0)
high = mid - 1;
else
- return (_bt_firsteq(rel, itupdesc, page, keysz, scankey, mid));
+ {
+ mid = _bt_firsteq(rel, itupdesc, page, keysz, scankey, mid);
+ /*
+ * NOTE for multi-column indices: we may do scan using
+ * keys not for all attrs. But we handle duplicates using
+ * all attrs in _bt_insert/_bt_spool code. And so while
+ * searching on internal pages having number of attrs > keysize
+ * we want to point at the last item < the scankey, not at the
+ * first item = the scankey (!!!), and let _bt_moveright
+ * decide later whether to move right or not (see comments and
+ * example there). Note also that INSERTions are not affected
+ * by this code (natts == keysz). - vadim 04/15/97
+ */
+ if ( natts == keysz || opaque->btpo_flags & BTP_LEAF )
+ return (mid);
+ low = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ if ( mid == low )
+ return (mid);
+ return (OffsetNumberPrev(mid));
+ }
}
- /*
- * We terminated because the endpoints got too close together. There
- * are two cases to take care of.
- *
- * For non-insertion searches on internal pages, we want to point at
- * the last key <, or first key =, the scankey on the page. This
- * guarantees that we'll descend the tree correctly.
- *
- * For all other cases, we want to point at the first key >=
- * the scankey on the page. This guarantees that scans and
- * insertions will happen correctly.
+ /*
+ * We terminated because the endpoints got too close together. There
+ * are two cases to take care of.
+ *
+ * For non-insertion searches on internal pages, we want to point at
+ * the last key <, or first key =, the scankey on the page. This
+ * guarantees that we'll descend the tree correctly.
+ * (NOTE comments above for multi-column indices).
+ *
+ * For all other cases, we want to point at the first key >=
+ * the scankey on the page. This guarantees that scans and
+ * insertions will happen correctly.
+ */
+
+ if (!(opaque->btpo_flags & BTP_LEAF) && srchtype == BT_DESCENT)
+ { /*
+ * We want the last key <, or first key ==, the scan key.
*/
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- if (!(opaque->btpo_flags & BTP_LEAF) && srchtype == BT_DESCENT) {
-
+ if (result == 0)
+ {
+ mid = _bt_firsteq(rel, itupdesc, page, keysz, scankey, high);
/*
- * We want the last key <, or first key ==, the scan key.
+ * If natts > keysz we want last item < the scan key.
+ * See comments above for multi-column indices.
*/
-
+ if ( natts == keysz )
+ return (mid);
+ low = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ if ( mid == low )
+ return (mid);
+ return (OffsetNumberPrev(mid));
+ }
+ else if (result > 0)
+ return (high);
+ else
+ return (low);
+ }
+ else /* we want the first key >= the scan key */
+ {
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
+ if (result <= 0)
+ return (low);
+ else
+ {
+ if (low == high)
+ return (OffsetNumberNext(low));
+
result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
-
- if (result == 0) {
- return (_bt_firsteq(rel, itupdesc, page, keysz, scankey, high));
- } else if (result > 0) {
+ if (result <= 0)
return (high);
- } else {
- return (low);
- }
- } else {
-
- /* we want the first key >= the scan key */
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
- if (result <= 0) {
- return (low);
- } else {
- if (low == high)
- return (OffsetNumberNext(low));
-
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
- if (result <= 0)
- return (high);
- else
- return (OffsetNumberNext(high));
- }
+ else
+ return (OffsetNumberNext(high));
}
+ }
}
static OffsetNumber
@@ -1107,7 +1159,7 @@ _bt_twostep(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
while (offnum <= maxoff) {
itemid = PageGetItemId(page, offnum);
btitem = (BTItem) PageGetItem(page, itemid);
- if (btitem->bti_oid == svitem->bti_oid) {
+ if ( BTItemSame (btitem, svitem) ) {
pfree(svitem);
ItemPointerSet(current, blkno, offnum);
return (false);