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*66358Sbostic static char sccsid[] = "@(#)bt_search.c 8.6 (Berkeley) 03/15/94";
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
2265050Sbostic static int bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
2365050Sbostic 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 *
__bt_search(t,key,exactp)3950989Sbostic __bt_search(t, key, exactp)
4050989Sbostic BTREE *t;
4150989Sbostic const DBT *key;
4250989Sbostic int *exactp;
4346132Smao {
44*66358Sbostic PAGE *h;
4566192Sbostic indx_t base, index, lim;
4650989Sbostic pgno_t pg;
4766192Sbostic int cmp;
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
7365050Sbostic * done. If duplicates are allowed, it's possible that there
7465050Sbostic * were duplicate keys on duplicate pages, and they were later
7565050Sbostic * deleted, so we could be on a page with no matches while
7665050Sbostic * there are matches on other pages. If we're at the start or
7765050Sbostic * 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)) {
8365050Sbostic if (base == 0 &&
8465050Sbostic bt_sprev(t, h, key, exactp))
8565050Sbostic return (&t->bt_cur);
8665021Sbostic if (base == NEXTINDEX(h) &&
8765050Sbostic bt_snext(t, h, key, exactp))
8865050Sbostic 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
10965050Sbostic /*
11065050Sbostic * BT_SNEXT -- Check for an exact match after the key.
11165050Sbostic *
11265050Sbostic * Parameters:
11365050Sbostic * t: tree to search
11465050Sbostic * h: current page.
11565050Sbostic * key: key to find
11665050Sbostic * exactp: pointer to exact match flag
11765050Sbostic *
11865050Sbostic * Returns:
11965050Sbostic * If an exact match found.
12065050Sbostic */
12165050Sbostic static int
bt_snext(t,h,key,exactp)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;
15465050Sbostic return (1);
15565021Sbostic }
15665021Sbostic }
15765050Sbostic return (0);
15865021Sbostic }
15965021Sbostic
16065050Sbostic /*
16165050Sbostic * BT_SPREV -- Check for an exact match before the key.
16265050Sbostic *
16365050Sbostic * Parameters:
16465050Sbostic * t: tree to search
16565050Sbostic * h: current page.
16665050Sbostic * key: key to find
16765050Sbostic * exactp: pointer to exact match flag
16865050Sbostic *
16965050Sbostic * Returns:
17065050Sbostic * If an exact match found.
17165050Sbostic */
17265050Sbostic static int
bt_sprev(t,h,key,exactp)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;
20565050Sbostic return (1);
20665021Sbostic }
20765021Sbostic }
20865050Sbostic return (0);
20965021Sbostic }
210