xref: /csrg-svn/lib/libc/db/btree/bt_seq.c (revision 46455)
146133Smao /*-
246133Smao  * Copyright (c) 1990 The Regents of the University of California.
346133Smao  * All rights reserved.
446133Smao  *
546133Smao  * This code is derived from software contributed to Berkeley by
646133Smao  * Mike Olson.
746133Smao  *
846133Smao  * %sccs.include.redist.c%
946133Smao  */
1046133Smao 
1146133Smao #if defined(LIBC_SCCS) && !defined(lint)
12*46455Smao static char sccsid[] = "@(#)bt_seq.c	5.2 (Berkeley) 02/18/91";
1346133Smao #endif /* LIBC_SCCS and not lint */
1446133Smao 
1546133Smao #include <sys/types.h>
1646133Smao #include <sys/errno.h>
1746133Smao #include <db.h>
1846133Smao #include "btree.h"
1946133Smao 
2046133Smao /*
2146133Smao  *  _BT_SEQINIT -- Initialize a sequential scan on the btree.
2246133Smao  *
2346133Smao  *	Sets the tree's notion of the current scan location correctly
2446133Smao  *	given a key and a direction.
2546133Smao  *
2646133Smao  *	Parameters:
2746133Smao  *		t -- tree in which to initialize scan
2846133Smao  *		key -- key for initial scan position
2946133Smao  *		flags -- R_NEXT, R_PREV
3046133Smao  *
3146133Smao  *	Returns:
3246133Smao  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if there's no data
3346133Smao  *		in the tree to scan.
3446133Smao  *
3546133Smao  *	Side Effects:
3646133Smao  *		Changes current scan position for the tree.  Almost certainly
3746133Smao  *		changes current page, as well.  Sets BTF_SEQINIT bit in tree
3846133Smao  *		flags, so that we know we've initialized a scan.
3946133Smao  */
4046133Smao 
4146133Smao int
4246133Smao _bt_seqinit(t, key, flags)
4346133Smao 	BTREE_P t;
4446133Smao 	DBT *key;
4546133Smao 	int flags;
4646133Smao {
4746133Smao 	BTITEM *item;
4846133Smao 	BTHEADER *h;
4946133Smao 	CURSOR *c;
5046133Smao 	IDATUM *id;
5146133Smao 	index_t last;
5246133Smao 
5346133Smao 	/*
5446133Smao 	 *  Figure out if we really have to search for the key that the
5546133Smao 	 *  user supplied.  If key is null, then this is an unkeyed scan
5646133Smao 	 *  and we can just start from an endpoint.
5746133Smao 	 */
5846133Smao 
5946133Smao 	c = &(t->bt_cursor);
6046133Smao 
6146133Smao 	if (flags == R_CURSOR) {
6246133Smao 		if (key->data != (char *) NULL) {
6346133Smao 
6446133Smao 			/* key supplied, find first instance of it */
6546133Smao 			item = _bt_first(t, key);
6646133Smao 			c->c_index = item->bti_index;
6746133Smao 			c->c_pgno = t->bt_curpage->h_pgno;
6846133Smao 		} else {
6946133Smao 			errno = EINVAL;
7046133Smao 			return (RET_ERROR);
7146133Smao 		}
7246133Smao 
7346133Smao 	} else {
7446133Smao 
7546133Smao 		/*
7646133Smao 		 *  Unkeyed scan.  For backward scans, find the last item
7746133Smao 		 *  in the tree; for forward scans, find the first item.
7846133Smao 		 */
7946133Smao 
8046133Smao 		if (_bt_getpage(t, (pgno_t) P_ROOT) == RET_ERROR)
8146133Smao 			return (RET_ERROR);
8246133Smao 		h = t->bt_curpage;
8346133Smao 		if (flags == R_LAST || flags == R_PREV) {
8446133Smao 
8546133Smao 			/* backward scan */
8646133Smao 			while (!(h->h_flags & F_LEAF)) {
8746133Smao 				last = NEXTINDEX(h) - 1;
8846133Smao 				id = (IDATUM *) GETDATUM(h,last);
8946133Smao 				if (_bt_getpage(t, id->i_pgno) == RET_ERROR)
9046133Smao 					return (RET_ERROR);
9146133Smao 				h = t->bt_curpage;
9246133Smao 			}
9346133Smao 
9446133Smao 			/* skip empty pages */
9546133Smao 			while (NEXTINDEX(h) == 0 && h->h_prevpg != P_NONE) {
9646133Smao 				if (_bt_getpage(t, h->h_prevpg) == RET_ERROR)
9746133Smao 					return (RET_ERROR);
9846133Smao 				h = t->bt_curpage;
9946133Smao 			}
10046133Smao 
10146133Smao 			c->c_pgno = h->h_pgno;
10246133Smao 			if (NEXTINDEX(h) > 0)
10346133Smao 				c->c_index = NEXTINDEX(h) - 1;
10446133Smao 			else
10546133Smao 				c->c_index = 0;
10646133Smao 		} else if (flags == R_FIRST || flags == R_NEXT) {
10746133Smao 			/* forward scan */
10846133Smao 			while (!(h->h_flags & F_LEAF)) {
10946133Smao 				id = (IDATUM *) GETDATUM(h,0);
11046133Smao 				if (_bt_getpage(t, id->i_pgno) == RET_ERROR)
11146133Smao 					return (RET_ERROR);
11246133Smao 				h = t->bt_curpage;
11346133Smao 			}
11446133Smao 
11546133Smao 			/* skip empty pages */
11646133Smao 			while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE) {
11746133Smao 				if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
11846133Smao 					return (RET_ERROR);
11946133Smao 				h = t->bt_curpage;
12046133Smao 			}
12146133Smao 
12246133Smao 			c->c_pgno = h->h_pgno;
12346133Smao 			c->c_index = 0;
12446133Smao 		} else {
12546133Smao 			/* no flags passed in */
12646133Smao 			errno = EINVAL;
12746133Smao 			return (RET_ERROR);
12846133Smao 		}
12946133Smao 	}
13046133Smao 
13146133Smao 	/* okay, scan is initialized */
13246133Smao 	t->bt_flags |= BTF_SEQINIT;
13346133Smao 
134*46455Smao 	/* don't need the descent stack anymore */
135*46455Smao 	while (_bt_pop(t) != P_NONE)
136*46455Smao 		continue;
137*46455Smao 
13846133Smao 	if (c->c_index == NEXTINDEX(t->bt_curpage))
13946133Smao 		return (RET_SPECIAL);
14046133Smao 
14146133Smao 	return (RET_SUCCESS);
14246133Smao }
14346133Smao 
14446133Smao /*
14546133Smao  *  _BT_SEQADVANCE -- Advance the sequential scan on this tree.
14646133Smao  *
14746133Smao  *	Moves the current location pointer for the scan on this tree one
14846133Smao  *	spot in the requested direction.
14946133Smao  *
15046133Smao  *	Parameters:
15146133Smao  *		t -- btree being scanned
15246133Smao  *		flags -- for R_NEXT, R_PREV
15346133Smao  *
15446133Smao  *	Returns:
15546133Smao  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if there is no
15646133Smao  *		more data in the specified direction.
15746133Smao  *
15846133Smao  *	Side Effects:
15946133Smao  *		May change current page.
16046133Smao  */
16146133Smao 
16246133Smao int
16346133Smao _bt_seqadvance(t, flags)
16446133Smao 	BTREE_P t;
16546133Smao 	int flags;
16646133Smao {
16746133Smao 	BTHEADER *h;
16846133Smao 	CURSOR *c;
16946133Smao 	index_t index;
17046133Smao 
17146133Smao 	c = &(t->bt_cursor);
17246133Smao 	index = c->c_index;
17346133Smao 
17446133Smao 	if (_bt_getpage(t, c->c_pgno) == RET_ERROR)
17546133Smao 		return (RET_ERROR);
17646133Smao 	h = t->bt_curpage;
17746133Smao 
17846133Smao 	/* by the time we get here, don't need the cursor key anymore */
17946133Smao 	if (c->c_key != (char *) NULL)
18046133Smao 		(void) free(c->c_key);
18146133Smao 
18246133Smao 	if (flags == R_NEXT) {
18346133Smao 
18446133Smao 		/*
18546133Smao 		 *  This is a forward scan.  If the cursor is pointing
18646133Smao 		 *  at a virtual record (that is, it was pointing at
18746133Smao 		 *  a record that got deleted), then we should return
18846133Smao 		 *  the record it's pointing at now.  Otherwise, we
18946133Smao 		 *  should advance the scan.  In either case, we need
19046133Smao 		 *  to be careful not to run off the end of the current
19146133Smao 		 *  page.
19246133Smao 		 */
19346133Smao 
19446133Smao 		if (c->c_flags & CRSR_BEFORE) {
19546133Smao 
19646133Smao 			if (index >= NEXTINDEX(h)) {
19746133Smao 				/* out of items on this page, get next page */
19846133Smao 				if (h->h_nextpg == P_NONE) {
19946133Smao 					/* tell caller we're done... */
20046133Smao 					c->c_index = NEXTINDEX(h);
20146133Smao 					return (RET_SPECIAL);
20246133Smao 				}
20346133Smao 
20446133Smao 				/* skip empty pages */
20546133Smao 				do {
20646133Smao 					if (_bt_getpage(t, h->h_nextpg)
20746133Smao 					    == RET_ERROR) {
20846133Smao 						c->c_index = NEXTINDEX(h);
20946133Smao 						return (RET_ERROR);
21046133Smao 					}
21146133Smao 					h = t->bt_curpage;
21246133Smao 					c->c_pgno = h->h_pgno;
21346133Smao 				} while (NEXTINDEX(h) == 0
21446133Smao 					 && h->h_nextpg != P_NONE);
21546133Smao 
21646133Smao 				if (NEXTINDEX(h) == 0) {
21746133Smao 					/* tell caller we're done */
21846133Smao 					c->c_index = NEXTINDEX(h);
21946133Smao 					return (RET_SPECIAL);
22046133Smao 				}
22146133Smao 				index = 0;
22246133Smao 			}
22346133Smao 			c->c_flags &= ~CRSR_BEFORE;
22446133Smao 
22546133Smao 		} else if (++index >= NEXTINDEX(h)) {
22646133Smao 
22746133Smao 			/* out of items on this page, get next page */
22846133Smao 			if (h->h_nextpg == P_NONE) {
22946133Smao 				/* tell caller we're done... */
23046133Smao 				c->c_index = NEXTINDEX(h);
23146133Smao 				return (RET_SPECIAL);
23246133Smao 			}
23346133Smao 
23446133Smao 			/* skip empty pages */
23546133Smao 			do {
23646133Smao 				if (_bt_getpage(t, h->h_nextpg) == RET_ERROR) {
23746133Smao 					c->c_index = NEXTINDEX(h);
23846133Smao 					return (RET_ERROR);
23946133Smao 				}
24046133Smao 				h = t->bt_curpage;
24146133Smao 				c->c_pgno = h->h_pgno;
24246133Smao 			} while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE);
24346133Smao 
24446133Smao 			if (NEXTINDEX(h) == 0) {
24546133Smao 				/* tell caller we're done */
24646133Smao 				c->c_index = NEXTINDEX(h);
24746133Smao 				return (RET_SPECIAL);
24846133Smao 			}
24946133Smao 			index = 0;
25046133Smao 		}
25146133Smao 	} else if (flags == R_PREV) {
25246133Smao 
25346133Smao 		/* for backward scans, life is substantially easier */
25446133Smao 		c->c_flags &= ~CRSR_BEFORE;
25546133Smao 		if (c->c_key != (char *) NULL) {
25646133Smao 			(void) free(c->c_key);
25746133Smao 			c->c_key = (char *) NULL;
25846133Smao 		}
25946133Smao 
26046133Smao 		if (index == 0) {
26146133Smao 
26246133Smao 			/* we may be done */
26346133Smao 			c->c_index = 0;
26446133Smao 
26546133Smao 			/* out of items on this page, get next page */
26646133Smao 			if (h->h_prevpg == P_NONE)
26746133Smao 				return (RET_SPECIAL);
26846133Smao 
26946133Smao 			/* skip empty pages */
27046133Smao 			do {
27146133Smao 				if (_bt_getpage(t, h->h_prevpg) == RET_ERROR)
27246133Smao 					return (RET_ERROR);
27346133Smao 				h = t->bt_curpage;
27446133Smao 				c->c_pgno = h->h_pgno;
27546133Smao 			} while (NEXTINDEX(h) == 0 && h->h_prevpg != P_NONE);
27646133Smao 
27746133Smao 			if (NEXTINDEX(h) == 0)
27846133Smao 				return (RET_SPECIAL);
27946133Smao 
28046133Smao 			index = NEXTINDEX(h) - 1;
28146133Smao 		} else
28246133Smao 			--index;
28346133Smao 	} else {
28446133Smao 		/* must specify a direction */
28546133Smao 		errno = EINVAL;
28646133Smao 		return (RET_ERROR);
28746133Smao 	}
28846133Smao 
28946133Smao 	c->c_index = index;
29046133Smao 	return (RET_SUCCESS);
29146133Smao }
292