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