xref: /csrg-svn/lib/libc/db/btree/bt_search.c (revision 65050)
146132Smao /*-
261196Sbostic  * Copyright (c) 1990, 1993
361196Sbostic  *	The Regents of the University of California.  All rights reserved.
446132Smao  *
546132Smao  * This code is derived from software contributed to Berkeley by
646132Smao  * Mike Olson.
746132Smao  *
846132Smao  * %sccs.include.redist.c%
946132Smao  */
1046132Smao 
1146132Smao #if defined(LIBC_SCCS) && !defined(lint)
12*65050Sbostic static char sccsid[] = "@(#)bt_search.c	8.4 (Berkeley) 12/10/93";
1346132Smao #endif /* LIBC_SCCS and not lint */
1446132Smao 
1546132Smao #include <sys/types.h>
1656739Sbostic 
1750989Sbostic #include <stdio.h>
1856739Sbostic 
1957932Sbostic #include <db.h>
2046132Smao #include "btree.h"
2146132Smao 
22*65050Sbostic static int bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
23*65050Sbostic static int bt_sprev __P((BTREE *, PAGE *, const DBT *, int *));
2465021Sbostic 
2546132Smao /*
2650989Sbostic  * __BT_SEARCH -- Search a btree for a key.
2746132Smao  *
2850989Sbostic  * Parameters:
2950989Sbostic  *	t:	tree to search
3050989Sbostic  *	key:	key to find
3150989Sbostic  *	exactp:	pointer to exact match flag
3246132Smao  *
3350989Sbostic  * Returns:
3464484Sbostic  *	The EPG for matching record, if any, or the EPG for the location
3564484Sbostic  *	of the key, if it were inserted into the tree, is entered into
3664484Sbostic  *	the bt_cur field of the tree.  A pointer to the field is returned.
3746132Smao  */
3850989Sbostic EPG *
3950989Sbostic __bt_search(t, key, exactp)
4050989Sbostic 	BTREE *t;
4150989Sbostic 	const DBT *key;
4250989Sbostic 	int *exactp;
4346132Smao {
4465021Sbostic 	PAGE *h, *n;
4565021Sbostic 	indx_t index;
4650989Sbostic 	pgno_t pg;
4765021Sbostic 	int base, cmp, lim;
4846132Smao 
4957449Sbostic 	BT_CLR(t);
5050989Sbostic 	for (pg = P_ROOT;;) {
5150989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
5250989Sbostic 			return (NULL);
5346132Smao 
5450989Sbostic 		/* Do a binary search on the current page. */
5564484Sbostic 		t->bt_cur.page = h;
5650989Sbostic 		for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
5764484Sbostic 			t->bt_cur.index = index = base + (lim >> 1);
5864484Sbostic 			if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
5950989Sbostic 				if (h->flags & P_BLEAF) {
6050989Sbostic 					*exactp = 1;
6164484Sbostic 					return (&t->bt_cur);
6250989Sbostic 				}
6350989Sbostic 				goto next;
6446132Smao 			}
6550989Sbostic 			if (cmp > 0) {
6650989Sbostic 				base = index + 1;
6750989Sbostic 				--lim;
6846132Smao 			}
6946132Smao 		}
7046132Smao 
7165021Sbostic 		/*
7265021Sbostic 		 * If it's a leaf page, and duplicates aren't allowed, we're
73*65050Sbostic 		 * done.  If duplicates are allowed, it's possible that there
74*65050Sbostic 		 * were duplicate keys on duplicate pages, and they were later
75*65050Sbostic 		 * deleted, so we could be on a page with no matches while
76*65050Sbostic 		 * there are matches on other pages.  If we're at the start or
77*65050Sbostic 		 * end of a page, check on both sides.
7865021Sbostic 		 */
7950989Sbostic 		if (h->flags & P_BLEAF) {
8064484Sbostic 			t->bt_cur.index = base;
8150989Sbostic 			*exactp = 0;
8265021Sbostic 			if (!ISSET(t, B_NODUPS)) {
83*65050Sbostic 				if (base == 0 &&
84*65050Sbostic 				    bt_sprev(t, h, key, exactp))
85*65050Sbostic 					return (&t->bt_cur);
8665021Sbostic 				if (base == NEXTINDEX(h) &&
87*65050Sbostic 				    bt_snext(t, h, key, exactp))
88*65050Sbostic 					return (&t->bt_cur);
8965021Sbostic 			}
9064484Sbostic 			return (&t->bt_cur);
9146132Smao 		}
9246132Smao 
9357448Sbostic 		/*
9457448Sbostic 		 * No match found.  Base is the smallest index greater than
9557448Sbostic 		 * key and may be zero or a last + 1 index.  If it's non-zero,
9657448Sbostic 		 * decrement by one, and record the internal page which should
9757448Sbostic 		 * be a parent page for the key.  If a split later occurs, the
9857448Sbostic 		 * inserted page will be to the right of the saved page.
9957448Sbostic 		 */
10057448Sbostic 		index = base ? base - 1 : base;
10157448Sbostic 
10251105Sbostic next:		if (__bt_push(t, h->pgno, index) == RET_ERROR)
10350989Sbostic 			return (NULL);
10450989Sbostic 		pg = GETBINTERNAL(h, index)->pgno;
10550989Sbostic 		mpool_put(t->bt_mp, h, 0);
10646132Smao 	}
10746132Smao }
10865021Sbostic 
109*65050Sbostic /*
110*65050Sbostic  * BT_SNEXT -- Check for an exact match after the key.
111*65050Sbostic  *
112*65050Sbostic  * Parameters:
113*65050Sbostic  *	t:	tree to search
114*65050Sbostic  *	h:	current page.
115*65050Sbostic  *	key:	key to find
116*65050Sbostic  *	exactp:	pointer to exact match flag
117*65050Sbostic  *
118*65050Sbostic  * Returns:
119*65050Sbostic  *	If an exact match found.
120*65050Sbostic  */
121*65050Sbostic static int
12265021Sbostic bt_snext(t, h, key, exactp)
12365021Sbostic 	BTREE *t;
12465021Sbostic 	PAGE *h;
12565021Sbostic 	const DBT *key;
12665021Sbostic 	int *exactp;
12765021Sbostic {
12865021Sbostic 	EPG e;
12965021Sbostic 	PAGE *tp;
13065021Sbostic 	pgno_t pg;
13165021Sbostic 
13265021Sbostic 	/* Skip until reach the end of the tree or a key. */
13365021Sbostic 	for (pg = h->nextpg; pg != P_INVALID;) {
13465021Sbostic 		if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) {
13565021Sbostic 			mpool_put(t->bt_mp, h, 0);
13665021Sbostic 			return (NULL);
13765021Sbostic 		}
13865021Sbostic 		if (NEXTINDEX(tp) != 0)
13965021Sbostic 			break;
14065021Sbostic 		pg = tp->prevpg;
14165021Sbostic 		mpool_put(t->bt_mp, tp, 0);
14265021Sbostic 	}
14365021Sbostic 	/*
14465021Sbostic 	 * The key is either an exact match, or not as good as
14565021Sbostic 	 * the one we already have.
14665021Sbostic 	 */
14765021Sbostic 	if (pg != P_INVALID) {
14865021Sbostic 		e.page = tp;
14965021Sbostic 		e.index = NEXTINDEX(tp) - 1;
15065021Sbostic 		if (__bt_cmp(t, key, &e) == 0) {
15165021Sbostic 			mpool_put(t->bt_mp, h, 0);
15265021Sbostic 			t->bt_cur = e;
15365021Sbostic 			*exactp = 1;
154*65050Sbostic 			return (1);
15565021Sbostic 		}
15665021Sbostic 	}
157*65050Sbostic 	return (0);
15865021Sbostic }
15965021Sbostic 
160*65050Sbostic /*
161*65050Sbostic  * BT_SPREV -- Check for an exact match before the key.
162*65050Sbostic  *
163*65050Sbostic  * Parameters:
164*65050Sbostic  *	t:	tree to search
165*65050Sbostic  *	h:	current page.
166*65050Sbostic  *	key:	key to find
167*65050Sbostic  *	exactp:	pointer to exact match flag
168*65050Sbostic  *
169*65050Sbostic  * Returns:
170*65050Sbostic  *	If an exact match found.
171*65050Sbostic  */
172*65050Sbostic static int
17365021Sbostic bt_sprev(t, h, key, exactp)
17465021Sbostic 	BTREE *t;
17565021Sbostic 	PAGE *h;
17665021Sbostic 	const DBT *key;
17765021Sbostic 	int *exactp;
17865021Sbostic {
17965021Sbostic 	EPG e;
18065021Sbostic 	PAGE *tp;
18165021Sbostic 	pgno_t pg;
18265021Sbostic 
18365021Sbostic 	/* Skip until reach the beginning of the tree or a key. */
18465021Sbostic 	for (pg = h->prevpg; pg != P_INVALID;) {
18565021Sbostic 		if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) {
18665021Sbostic 			mpool_put(t->bt_mp, h, 0);
18765021Sbostic 			return (NULL);
18865021Sbostic 		}
18965021Sbostic 		if (NEXTINDEX(tp) != 0)
19065021Sbostic 			break;
19165021Sbostic 		pg = tp->prevpg;
19265021Sbostic 		mpool_put(t->bt_mp, tp, 0);
19365021Sbostic 	}
19465021Sbostic 	/*
19565021Sbostic 	 * The key is either an exact match, or not as good as
19665021Sbostic 	 * the one we already have.
19765021Sbostic 	 */
19865021Sbostic 	if (pg != P_INVALID) {
19965021Sbostic 		e.page = tp;
20065021Sbostic 		e.index = NEXTINDEX(tp) - 1;
20165021Sbostic 		if (__bt_cmp(t, key, &e) == 0) {
20265021Sbostic 			mpool_put(t->bt_mp, h, 0);
20365021Sbostic 			t->bt_cur = e;
20465021Sbostic 			*exactp = 1;
205*65050Sbostic 			return (1);
20665021Sbostic 		}
20765021Sbostic 	}
208*65050Sbostic 	return (0);
20965021Sbostic }
210