Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libc / db / btree / search.c
blob3006888071463f03e86d3a057a689a8e75f116a1
1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Mike Olson.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)search.c 5.2 (Berkeley) 4/8/91";
39 #endif /* LIBC_SCCS and not lint */
41 #include <sys/types.h>
42 #include <db.h>
43 #include "btree.h"
46 * _BT_FIRST -- Find the first item in the tree that matches the supplied
47 * key.
49 * This routine supports deletion. When the user supplies a key to
50 * be deleted, we find the first one, and iteratively delete all the
51 * matching ones that follow it.
53 * Parameters:
54 * t -- btree in which to find first occurrence
55 * key -- key to find
57 * Returns:
58 * The BTITEM for the matching item. If there's no match,
59 * this may point to the first item > than the supplied key,
60 * or off the end of the page.
62 * Warnings:
63 * The BTITEM returned is in static space and will be overwritten
64 * by the next search of any kind in any btree.
67 BTITEM *
68 _bt_first(t, key)
69 BTREE_P t;
70 DBT *key;
72 BTHEADER *h;
73 BTITEM *item;
74 index_t next;
75 int r;
77 /* find any matching item */
78 item = _bt_search(t, key);
79 h = t->bt_curpage;
80 next = NEXTINDEX(h);
82 /* if we're off the end of the page, search failed and we're done */
83 if (item->bti_index >= next)
84 return (item);
86 /* as long as we have an exact match, walk backwards */
87 while ((r = _bt_cmp(t, key->data, item->bti_index)) == 0) {
89 /* at start of page? */
90 if (item->bti_index == 0) {
92 /* if no prev page, we're done */
93 if (h->h_prevpg == P_NONE)
94 return (item);
96 /* walk backward, skipping empty pages */
97 do {
98 if (_bt_getpage(t, h->h_prevpg) == RET_ERROR)
99 return ((BTITEM *) NULL);
100 h = t->bt_curpage;
101 } while (NEXTINDEX(h) == 0 && h->h_prevpg != P_NONE);
103 if (NEXTINDEX(h) != 0)
104 item->bti_index = NEXTINDEX(h) - 1;
105 else
106 item->bti_index = 0;
108 item->bti_pgno = h->h_pgno;
109 } else {
110 item->bti_index--;
114 /* if we went too far backwards, step forward one entry */
115 if (r > 0) {
116 if (++(item->bti_index) >= NEXTINDEX(h)
117 && h->h_nextpg != P_NONE) {
119 /* walk forward, skipping empty pages */
120 do {
121 if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
122 return ((BTITEM *) NULL);
123 h = t->bt_curpage;
124 } while (h->h_nextpg != P_NONE && NEXTINDEX(h) == 0);
126 item->bti_index = 0;
127 item->bti_pgno = h->h_pgno;
131 /* got it */
132 return (item);
136 * _BT_SEARCH, _BT_SEARCHR -- Search for a particular key in the tree.
138 * Parameters:
139 * t -- btree in which to search
140 * key -- key to find
142 * Returns:
143 * BTITEM for matching item, if any, or the BTITEM for the
144 * location of the key, if it were in the tree.
146 * Warnings:
147 * The BTITEM returned is in static memory, and will be
148 * overwritten by the next search of any kind in any tree.
151 BTITEM *
152 _bt_search(t, key)
153 BTREE_P t;
154 DBT *key;
156 /* we want to start all of our searches at the root */
157 if (_bt_getpage(t, (pgno_t) P_ROOT) == RET_ERROR)
158 return ((BTITEM *) NULL);
160 return (_bt_searchr(t, key));
163 BTITEM *
164 _bt_searchr(t, key)
165 BTREE_P t;
166 DBT *key;
168 BTHEADER *h = t->bt_curpage;
169 index_t index;
170 IDATUM *id;
171 DATUM *d;
172 static BTITEM item;
174 /* do a binary search on the current page */
175 index = _bt_binsrch(t, key->data);
178 * At this point, the binary search terminated because the endpoints
179 * got too close together, or we have a match. Figure out which
180 * case applies and decide what to do based on the page type.
182 if (h->h_flags & F_LEAF) {
183 item.bti_pgno = h->h_pgno;
184 item.bti_index = index;
185 if (index < NEXTINDEX(h))
186 d = (DATUM *) GETDATUM(h,index);
187 else
188 d = (DATUM *) NULL;
190 item.bti_datum = d;
191 return(&item);
192 } else {
193 id = (IDATUM *) GETDATUM(h, index);
194 if (_bt_push(t, h->h_pgno) == RET_ERROR)
195 return ((BTITEM *) NULL);
196 if (_bt_getpage(t, id->i_pgno) == RET_ERROR)
197 return ((BTITEM *) NULL);
198 return (_bt_searchr(t, key));
203 * _BT_BINSRCH -- Do a binary search for a given key on the current page.
205 * Searches on internal pages are handled slightly differently from
206 * searches on leaf pages. This is because internal page searches
207 * find the largest item <= key in the tree, and leaf searches find
208 * the smallest item >= key. This guarantees that leaf page searches
209 * leave us pointing at the item's correct position, and internal
210 * searches descend the tree correctly.
212 * Parameters:
213 * t -- tree to search
214 * key -- key we're looking for
216 * Returns:
217 * Index of the line pointer array entry for the (closest)
218 * match to key on the current page, with "closest" as defined
219 * above.
222 index_t
223 _bt_binsrch(t, key)
224 BTREE_P t;
225 char *key;
227 index_t lbound, ubound, cur;
228 BTHEADER *h = t->bt_curpage;
229 int match = 0;
230 int r;
232 lbound = 0;
233 ubound = NEXTINDEX(h);
234 if (ubound > 0)
235 --ubound;
237 /* do a binary search on the current page */
238 while ((ubound - lbound) > 1) {
239 cur = lbound + ((ubound - lbound) / 2);
240 r = _bt_cmp(t, key, cur);
242 if (r > 0)
243 lbound = cur + 1;
244 else if (r < 0)
245 ubound = cur;
246 else {
247 match++;
248 break;
253 * At this point, the binary search terminated because the endpoints
254 * got too close together, or we have a match. Figure out which
255 * case applies, decide what to do based on the page type (leaf or
256 * internal), and do the right thing.
258 if (match) {
259 return (cur);
260 } else if (ubound != lbound) {
261 if (h->h_flags & F_LEAF) {
262 r = _bt_cmp(t, key, lbound);
263 if (r <= 0) {
264 return (lbound);
266 } else {
267 r = _bt_cmp(t, key, ubound);
269 /* for internal nodes, move as far left as possible */
270 if (r < 0) {
271 r = _bt_cmp(t, key, lbound);
272 if (r < 0 && lbound > 0)
273 --lbound;
274 return (lbound);
275 } else {
276 return (ubound);
281 if (h->h_flags & F_LEAF) {
282 if (ubound < NEXTINDEX(h)) {
283 r = _bt_cmp(t, key, ubound);
284 if (r > 0)
285 ubound++;
287 } else {
288 /* for internal pages, move as far left as possible */
289 if (ubound == NEXTINDEX(h))
290 ubound--;
292 while (_bt_cmp(t, key, ubound) < 0)
293 ubound--;
295 return (ubound);