2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid
[] = "@(#)bt_seq.c 8.7 (Berkeley) 7/20/94";
39 #endif /* LIBC_SCCS and not lint */
41 #include <sys/types.h>
51 static int __bt_first
__P((BTREE
*, const DBT
*, EPG
*, int *));
52 static int __bt_seqadv
__P((BTREE
*, EPG
*, int));
53 static int __bt_seqset
__P((BTREE
*, EPG
*, DBT
*, int));
56 * Sequential scan support.
58 * The tree can be scanned sequentially, starting from either end of the
59 * tree or from any specific key. A scan request before any scanning is
60 * done is initialized as starting from the least node.
65 * Btree sequential scan interface.
68 * dbp: pointer to access method
69 * key: key for positioning and return value
70 * data: data return value
71 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
74 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
77 __bt_seq(dbp
, key
, data
, flags
)
88 /* Toss any page pinned across calls. */
89 if (t
->bt_pinned
!= NULL
) {
90 mpool_put(t
->bt_mp
, t
->bt_pinned
, 0);
95 * If scan uninitialized as yet, or starting at a specific record, set
96 * the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
97 * the page the cursor references if they're successful.
102 if (F_ISSET(&t
->bt_cursor
, CURS_INIT
)) {
103 status
= __bt_seqadv(t
, &e
, flags
);
110 status
= __bt_seqset(t
, &e
, key
, flags
);
117 if (status
== RET_SUCCESS
) {
118 __bt_setcur(t
, e
.page
->pgno
, e
.index
);
121 __bt_ret(t
, &e
, key
, &t
->bt_rkey
, data
, &t
->bt_rdata
, 0);
124 * If the user is doing concurrent access, we copied the
125 * key/data, toss the page.
127 if (F_ISSET(t
, B_DB_LOCK
))
128 mpool_put(t
->bt_mp
, e
.page
, 0);
130 t
->bt_pinned
= e
.page
;
137 * Set the sequential scan to a specific key.
141 * ep: storage for returned key
142 * key: key for initial scan position
143 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
146 * Pins the page the cursor references.
149 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
152 __bt_seqset(t
, ep
, key
, flags
)
163 * Find the first, last or specific key in the tree and point the
164 * cursor at it. The cursor may not be moved until a new key has
168 case R_CURSOR
: /* Keyed scan. */
170 * Find the first instance of the key or the smallest key
171 * which is greater than or equal to the specified key.
173 if (key
->data
== NULL
|| key
->size
== 0) {
177 return (__bt_first(t
, key
, ep
, &exact
));
178 case R_FIRST
: /* First record. */
180 /* Walk down the left-hand side of the tree. */
181 for (pg
= P_ROOT
;;) {
182 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
185 /* Check for an empty tree. */
186 if (NEXTINDEX(h
) == 0) {
187 mpool_put(t
->bt_mp
, h
, 0);
188 return (RET_SPECIAL
);
191 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
193 pg
= GETBINTERNAL(h
, 0)->pgno
;
194 mpool_put(t
->bt_mp
, h
, 0);
199 case R_LAST
: /* Last record. */
201 /* Walk down the right-hand side of the tree. */
202 for (pg
= P_ROOT
;;) {
203 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
206 /* Check for an empty tree. */
207 if (NEXTINDEX(h
) == 0) {
208 mpool_put(t
->bt_mp
, h
, 0);
209 return (RET_SPECIAL
);
212 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
214 pg
= GETBINTERNAL(h
, NEXTINDEX(h
) - 1)->pgno
;
215 mpool_put(t
->bt_mp
, h
, 0);
219 ep
->index
= NEXTINDEX(h
) - 1;
222 return (RET_SUCCESS
);
227 * Advance the sequential scan.
231 * flags: R_NEXT, R_PREV
234 * Pins the page the new key/data record is on.
237 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
240 __bt_seqadv(t
, ep
, flags
)
252 * There are a couple of states that we can be in. The cursor has
253 * been initialized by the time we get here, but that's all we know.
258 * The cursor was deleted where there weren't any duplicate records,
259 * so the key was saved. Find out where that key would go in the
260 * current tree. It doesn't matter if the returned key is an exact
261 * match or not -- if it's an exact match, the record was added after
262 * the delete so we can just return it. If not, as long as there's
263 * a record there, return it.
265 if (F_ISSET(c
, CURS_ACQUIRE
))
266 return (__bt_first(t
, &c
->key
, ep
, &exact
));
268 /* Get the page referenced by the cursor. */
269 if ((h
= mpool_get(t
->bt_mp
, c
->pg
.pgno
, 0)) == NULL
)
273 * Find the next/previous record in the tree and point the cursor at
274 * it. The cursor may not be moved until a new key has been found.
277 case R_NEXT
: /* Next record. */
279 * The cursor was deleted in duplicate records, and moved
280 * forward to a record that has yet to be returned. Clear
281 * that flag, and return the record.
283 if (F_ISSET(c
, CURS_AFTER
))
286 if (++index
== NEXTINDEX(h
)) {
288 mpool_put(t
->bt_mp
, h
, 0);
290 return (RET_SPECIAL
);
291 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
296 case R_PREV
: /* Previous record. */
298 * The cursor was deleted in duplicate records, and moved
299 * backward to a record that has yet to be returned. Clear
300 * that flag, and return the record.
302 if (F_ISSET(c
, CURS_BEFORE
)) {
303 usecurrent
: F_CLR(c
, CURS_AFTER
| CURS_BEFORE
);
305 ep
->index
= c
->pg
.index
;
306 return (RET_SUCCESS
);
311 mpool_put(t
->bt_mp
, h
, 0);
313 return (RET_SPECIAL
);
314 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
316 index
= NEXTINDEX(h
) - 1;
324 return (RET_SUCCESS
);
329 * Find the first entry.
335 * exactp: pointer to exact match flag
338 * The first entry in the tree greater than or equal to key,
339 * or RET_SPECIAL if no such key exists.
342 __bt_first(t
, key
, erval
, exactp
)
353 * Find any matching record; __bt_search pins the page.
355 * If it's an exact match and duplicates are possible, walk backwards
356 * in the tree until we find the first one. Otherwise, make sure it's
357 * a valid key (__bt_search may return an index just past the end of a
358 * page) and return it.
360 if ((ep
= __bt_search(t
, key
, exactp
)) == NULL
)
361 return (RET_SPECIAL
);
363 if (F_ISSET(t
, B_NODUPS
)) {
365 return (RET_SUCCESS
);
369 * Walk backwards, as long as the entry matches and there are
370 * keys left in the tree. Save a copy of each match in case
376 if (save
.page
->pgno
!= ep
->page
->pgno
) {
377 mpool_put(t
->bt_mp
, save
.page
, 0);
380 save
.index
= ep
->index
;
383 * Don't unpin the page the last (or original) match
384 * was on, but make sure it's unpinned if an error
387 if (ep
->index
== 0) {
388 if (h
->prevpg
== P_INVALID
)
390 if (h
->pgno
!= save
.page
->pgno
)
391 mpool_put(t
->bt_mp
, h
, 0);
392 if ((h
= mpool_get(t
->bt_mp
,
393 h
->prevpg
, 0)) == NULL
) {
394 if (h
->pgno
== save
.page
->pgno
)
400 ep
->index
= NEXTINDEX(h
);
403 } while (__bt_cmp(t
, key
, ep
) == 0);
406 * Reach here with the last page that was looked at pinned,
407 * which may or may not be the same as the last (or original)
408 * match page. If it's not useful, release it.
410 if (h
->pgno
!= save
.page
->pgno
)
411 mpool_put(t
->bt_mp
, h
, 0);
414 return (RET_SUCCESS
);
417 /* If at the end of a page, find the next entry. */
418 if (ep
->index
== NEXTINDEX(ep
->page
)) {
421 mpool_put(t
->bt_mp
, h
, 0);
423 return (RET_SPECIAL
);
424 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
430 return (RET_SUCCESS
);
435 * Set the cursor to an entry in the tree.
443 __bt_setcur(t
, pgno
, index
)
448 /* Lose any already deleted key. */
449 if (t
->bt_cursor
.key
.data
!= NULL
) {
450 free(t
->bt_cursor
.key
.data
);
451 t
->bt_cursor
.key
.size
= 0;
452 t
->bt_cursor
.key
.data
= NULL
;
454 F_CLR(&t
->bt_cursor
, CURS_ACQUIRE
| CURS_AFTER
| CURS_BEFORE
);
456 /* Update the cursor. */
457 t
->bt_cursor
.pg
.pgno
= pgno
;
458 t
->bt_cursor
.pg
.index
= index
;
459 F_SET(&t
->bt_cursor
, CURS_INIT
);