11573Srgrimes/*-
214272Spst * Copyright (c) 1990, 1993, 1994
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Mike Olson.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 4. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
311573Srgrimes */
321573Srgrimes
331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3414272Spststatic char sccsid[] = "@(#)bt_search.c	8.8 (Berkeley) 7/31/94";
351573Srgrimes#endif /* LIBC_SCCS and not lint */
3692905Sobrien#include <sys/cdefs.h>
3792905Sobrien__FBSDID("$FreeBSD$");
381573Srgrimes
391573Srgrimes#include <sys/types.h>
401573Srgrimes
411573Srgrimes#include <stdio.h>
421573Srgrimes
431573Srgrimes#include <db.h>
441573Srgrimes#include "btree.h"
451573Srgrimes
4692905Sobrienstatic int __bt_snext(BTREE *, PAGE *, const DBT *, int *);
4792905Sobrienstatic int __bt_sprev(BTREE *, PAGE *, const DBT *, int *);
481573Srgrimes
491573Srgrimes/*
5014272Spst * __bt_search --
5114272Spst *	Search a btree for a key.
521573Srgrimes *
531573Srgrimes * Parameters:
541573Srgrimes *	t:	tree to search
551573Srgrimes *	key:	key to find
561573Srgrimes *	exactp:	pointer to exact match flag
571573Srgrimes *
581573Srgrimes * Returns:
591573Srgrimes *	The EPG for matching record, if any, or the EPG for the location
601573Srgrimes *	of the key, if it were inserted into the tree, is entered into
611573Srgrimes *	the bt_cur field of the tree.  A pointer to the field is returned.
621573Srgrimes */
631573SrgrimesEPG *
64189291Sdelphij__bt_search(BTREE *t, const DBT *key, int *exactp)
651573Srgrimes{
661573Srgrimes	PAGE *h;
67189292Sdelphij	indx_t base, idx, lim;
681573Srgrimes	pgno_t pg;
691573Srgrimes	int cmp;
701573Srgrimes
711573Srgrimes	BT_CLR(t);
721573Srgrimes	for (pg = P_ROOT;;) {
731573Srgrimes		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
741573Srgrimes			return (NULL);
751573Srgrimes
761573Srgrimes		/* Do a binary search on the current page. */
771573Srgrimes		t->bt_cur.page = h;
781573Srgrimes		for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
79189292Sdelphij			t->bt_cur.index = idx = base + (lim >> 1);
801573Srgrimes			if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
811573Srgrimes				if (h->flags & P_BLEAF) {
821573Srgrimes					*exactp = 1;
831573Srgrimes					return (&t->bt_cur);
841573Srgrimes				}
851573Srgrimes				goto next;
861573Srgrimes			}
871573Srgrimes			if (cmp > 0) {
88189292Sdelphij				base = idx + 1;
891573Srgrimes				--lim;
901573Srgrimes			}
911573Srgrimes		}
921573Srgrimes
931573Srgrimes		/*
9414272Spst		 * If it's a leaf page, we're almost done.  If no duplicates
9514272Spst		 * are allowed, or we have an exact match, we're done.  Else,
9614272Spst		 * it's possible that there were matching keys on this page,
9714272Spst		 * which later deleted, and we're on a page with no matches
9814272Spst		 * while there are matches on other pages.  If at the start or
9914272Spst		 * end of a page, check the adjacent page.
1001573Srgrimes		 */
1011573Srgrimes		if (h->flags & P_BLEAF) {
10214272Spst			if (!F_ISSET(t, B_NODUPS)) {
1031573Srgrimes				if (base == 0 &&
10414272Spst				    h->prevpg != P_INVALID &&
10514272Spst				    __bt_sprev(t, h, key, exactp))
1061573Srgrimes					return (&t->bt_cur);
1071573Srgrimes				if (base == NEXTINDEX(h) &&
10814272Spst				    h->nextpg != P_INVALID &&
10914272Spst				    __bt_snext(t, h, key, exactp))
1101573Srgrimes					return (&t->bt_cur);
1111573Srgrimes			}
11214272Spst			*exactp = 0;
11314272Spst			t->bt_cur.index = base;
1141573Srgrimes			return (&t->bt_cur);
1151573Srgrimes		}
1161573Srgrimes
1171573Srgrimes		/*
1181573Srgrimes		 * No match found.  Base is the smallest index greater than
1191573Srgrimes		 * key and may be zero or a last + 1 index.  If it's non-zero,
1201573Srgrimes		 * decrement by one, and record the internal page which should
1211573Srgrimes		 * be a parent page for the key.  If a split later occurs, the
1221573Srgrimes		 * inserted page will be to the right of the saved page.
1231573Srgrimes		 */
124189292Sdelphij		idx = base ? base - 1 : base;
1251573Srgrimes
126189292Sdelphijnext:		BT_PUSH(t, h->pgno, idx);
127189292Sdelphij		pg = GETBINTERNAL(h, idx)->pgno;
1281573Srgrimes		mpool_put(t->bt_mp, h, 0);
1291573Srgrimes	}
1301573Srgrimes}
1311573Srgrimes
1321573Srgrimes/*
13314272Spst * __bt_snext --
13414272Spst *	Check for an exact match after the key.
1351573Srgrimes *
1361573Srgrimes * Parameters:
13714272Spst *	t:	tree
13814272Spst *	h:	current page
13914272Spst *	key:	key
1401573Srgrimes *	exactp:	pointer to exact match flag
1411573Srgrimes *
1421573Srgrimes * Returns:
1431573Srgrimes *	If an exact match found.
1441573Srgrimes */
1451573Srgrimesstatic int
146189291Sdelphij__bt_snext(BTREE *t, PAGE *h, const DBT *key, int *exactp)
1471573Srgrimes{
1481573Srgrimes	EPG e;
1491573Srgrimes
1501573Srgrimes	/*
15114272Spst	 * Get the next page.  The key is either an exact
15214272Spst	 * match, or not as good as the one we already have.
1531573Srgrimes	 */
15414272Spst	if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
15514272Spst		return (0);
15614272Spst	e.index = 0;
15714272Spst	if (__bt_cmp(t, key, &e) == 0) {
15814272Spst		mpool_put(t->bt_mp, h, 0);
15914272Spst		t->bt_cur = e;
16014272Spst		*exactp = 1;
16114272Spst		return (1);
1621573Srgrimes	}
16314272Spst	mpool_put(t->bt_mp, e.page, 0);
1641573Srgrimes	return (0);
1651573Srgrimes}
1661573Srgrimes
1671573Srgrimes/*
16814272Spst * __bt_sprev --
16914272Spst *	Check for an exact match before the key.
1701573Srgrimes *
1711573Srgrimes * Parameters:
17214272Spst *	t:	tree
17314272Spst *	h:	current page
17414272Spst *	key:	key
1751573Srgrimes *	exactp:	pointer to exact match flag
1761573Srgrimes *
1771573Srgrimes * Returns:
1781573Srgrimes *	If an exact match found.
1791573Srgrimes */
1801573Srgrimesstatic int
181189291Sdelphij__bt_sprev(BTREE *t, PAGE *h, const DBT *key, int *exactp)
1821573Srgrimes{
1831573Srgrimes	EPG e;
1841573Srgrimes
1851573Srgrimes	/*
18614272Spst	 * Get the previous page.  The key is either an exact
18714272Spst	 * match, or not as good as the one we already have.
1881573Srgrimes	 */
18914272Spst	if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
19014272Spst		return (0);
19114272Spst	e.index = NEXTINDEX(e.page) - 1;
19214272Spst	if (__bt_cmp(t, key, &e) == 0) {
19314272Spst		mpool_put(t->bt_mp, h, 0);
19414272Spst		t->bt_cur = e;
19514272Spst		*exactp = 1;
19614272Spst		return (1);
1971573Srgrimes	}
19814272Spst	mpool_put(t->bt_mp, e.page, 0);
1991573Srgrimes	return (0);
2001573Srgrimes}
201