]>
git.saurik.com Git - apple/libc.git/blob - db.subproj/btree.subproj/bt_seq.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1990, 1993
24 * The Regents of the University of California. All rights reserved.
26 * This code is derived from software contributed to Berkeley by
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 #include <sys/types.h>
69 static int bt_seqadv
__P((BTREE
*, EPG
*, int));
70 static int bt_seqset
__P((BTREE
*, EPG
*, DBT
*, int));
73 * Sequential scan support.
75 * The tree can be scanned sequentially, starting from either end of the tree
76 * or from any specific key. A scan request before any scanning is done is
77 * initialized as starting from the least node.
79 * Each tree has an EPGNO which has the current position of the cursor. The
80 * cursor has to survive deletions/insertions in the tree without losing its
81 * position. This is done by noting deletions without doing them, and then
82 * doing them when the cursor moves (or the tree is closed).
86 * __BT_SEQ -- Btree sequential scan interface.
89 * dbp: pointer to access method
90 * key: key for positioning and return value
91 * data: data return value
92 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
95 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
98 __bt_seq(dbp
, key
, data
, flags
)
109 /* Toss any page pinned across calls. */
110 if (t
->bt_pinned
!= NULL
) {
111 mpool_put(t
->bt_mp
, t
->bt_pinned
, 0);
116 * If scan unitialized as yet, or starting at a specific record, set
117 * the scan to a specific key. Both bt_seqset and bt_seqadv pin the
118 * page the cursor references if they're successful.
123 if (ISSET(t
, B_SEQINIT
)) {
124 status
= bt_seqadv(t
, &e
, flags
);
131 status
= bt_seqset(t
, &e
, key
, flags
);
138 if (status
== RET_SUCCESS
) {
139 status
= __bt_ret(t
, &e
, key
, data
);
141 /* Update the actual cursor. */
142 t
->bt_bcursor
.pgno
= e
.page
->pgno
;
143 t
->bt_bcursor
.index
= e
.index
;
146 * If the user is doing concurrent access, we copied the
147 * key/data, toss the page.
149 if (ISSET(t
, B_DB_LOCK
))
150 mpool_put(t
->bt_mp
, e
.page
, 0);
152 t
->bt_pinned
= e
.page
;
159 * BT_SEQSET -- Set the sequential scan to a specific key.
163 * ep: storage for returned key
164 * key: key for initial scan position
165 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
168 * Pins the page the cursor references.
171 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
174 bt_seqset(t
, ep
, key
, flags
)
186 * Delete any already deleted record that we've been saving because
187 * the cursor pointed to it. Since going to a specific key, should
188 * delete any logically deleted records so they aren't found.
190 if (ISSET(t
, B_DELCRSR
) && __bt_crsrdel(t
, &t
->bt_bcursor
))
194 * Find the first, last or specific key in the tree and point the cursor
195 * at it. The cursor may not be moved until a new key has been found.
198 case R_CURSOR
: /* Keyed scan. */
200 * Find the first instance of the key or the smallest key which
201 * is greater than or equal to the specified key. If run out
202 * of keys, return RET_SPECIAL.
204 if (key
->data
== NULL
|| key
->size
== 0) {
208 e
= __bt_first(t
, key
, &exact
); /* Returns pinned page. */
212 * If at the end of a page, skip any empty pages and find the
215 if (e
->index
== NEXTINDEX(e
->page
)) {
219 mpool_put(t
->bt_mp
, h
, 0);
221 return (RET_SPECIAL
);
222 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
224 } while (NEXTINDEX(h
) == 0);
230 case R_FIRST
: /* First record. */
232 /* Walk down the left-hand side of the tree. */
233 for (pg
= P_ROOT
;;) {
234 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
236 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
238 pg
= GETBINTERNAL(h
, 0)->pgno
;
239 mpool_put(t
->bt_mp
, h
, 0);
242 /* Skip any empty pages. */
243 while (NEXTINDEX(h
) == 0 && h
->nextpg
!= P_INVALID
) {
245 mpool_put(t
->bt_mp
, h
, 0);
246 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
250 if (NEXTINDEX(h
) == 0) {
251 mpool_put(t
->bt_mp
, h
, 0);
252 return (RET_SPECIAL
);
258 case R_LAST
: /* Last record. */
260 /* Walk down the right-hand side of the tree. */
261 for (pg
= P_ROOT
;;) {
262 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
264 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
266 pg
= GETBINTERNAL(h
, NEXTINDEX(h
) - 1)->pgno
;
267 mpool_put(t
->bt_mp
, h
, 0);
270 /* Skip any empty pages. */
271 while (NEXTINDEX(h
) == 0 && h
->prevpg
!= P_INVALID
) {
273 mpool_put(t
->bt_mp
, h
, 0);
274 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
278 if (NEXTINDEX(h
) == 0) {
279 mpool_put(t
->bt_mp
, h
, 0);
280 return (RET_SPECIAL
);
284 ep
->index
= NEXTINDEX(h
) - 1;
287 return (RET_SUCCESS
);
291 * BT_SEQADVANCE -- Advance the sequential scan.
295 * flags: R_NEXT, R_PREV
298 * Pins the page the new key/data record is on.
301 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
304 bt_seqadv(t
, e
, flags
)
314 /* Save the current cursor if going to delete it. */
316 if (ISSET(t
, B_DELCRSR
))
319 if ((h
= mpool_get(t
->bt_mp
, c
->pgno
, 0)) == NULL
)
323 * Find the next/previous record in the tree and point the cursor at it.
324 * The cursor may not be moved until a new key has been found.
328 case R_NEXT
: /* Next record. */
329 if (++index
== NEXTINDEX(h
)) {
332 mpool_put(t
->bt_mp
, h
, 0);
334 return (RET_SPECIAL
);
335 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
337 } while (NEXTINDEX(h
) == 0);
341 case R_PREV
: /* Previous record. */
345 mpool_put(t
->bt_mp
, h
, 0);
347 return (RET_SPECIAL
);
348 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
350 } while (NEXTINDEX(h
) == 0);
351 index
= NEXTINDEX(h
) - 1;
360 * Delete any already deleted record that we've been saving because the
361 * cursor pointed to it. This could cause the new index to be shifted
362 * down by one if the record we're deleting is on the same page and has
365 if (ISSET(t
, B_DELCRSR
)) {
366 CLR(t
, B_DELCRSR
); /* Don't try twice. */
367 if (c
->pgno
== delc
.pgno
&& c
->index
> delc
.index
)
369 if (__bt_crsrdel(t
, &delc
))
372 return (RET_SUCCESS
);
376 * __BT_CRSRDEL -- Delete the record referenced by the cursor.
382 * RET_ERROR, RET_SUCCESS
392 CLR(t
, B_DELCRSR
); /* Don't try twice. */
393 if ((h
= mpool_get(t
->bt_mp
, c
->pgno
, 0)) == NULL
)
395 status
= __bt_dleaf(t
, h
, c
->index
);
396 mpool_put(t
->bt_mp
, h
, MPOOL_DIRTY
);