xref: /csrg-svn/lib/libc/db/btree/bt_seq.c (revision 46133)
1*46133Smao /*-
2*46133Smao  * Copyright (c) 1990 The Regents of the University of California.
3*46133Smao  * All rights reserved.
4*46133Smao  *
5*46133Smao  * This code is derived from software contributed to Berkeley by
6*46133Smao  * Mike Olson.
7*46133Smao  *
8*46133Smao  * %sccs.include.redist.c%
9*46133Smao  */
10*46133Smao 
11*46133Smao #if defined(LIBC_SCCS) && !defined(lint)
12*46133Smao static char sccsid[] = "@(#)bt_seq.c	5.1 (Berkeley) 01/23/91";
13*46133Smao #endif /* LIBC_SCCS and not lint */
14*46133Smao 
15*46133Smao #include <sys/types.h>
16*46133Smao #include <sys/errno.h>
17*46133Smao #include <db.h>
18*46133Smao #include "btree.h"
19*46133Smao 
20*46133Smao /*
21*46133Smao  *  _BT_SEQINIT -- Initialize a sequential scan on the btree.
22*46133Smao  *
23*46133Smao  *	Sets the tree's notion of the current scan location correctly
24*46133Smao  *	given a key and a direction.
25*46133Smao  *
26*46133Smao  *	Parameters:
27*46133Smao  *		t -- tree in which to initialize scan
28*46133Smao  *		key -- key for initial scan position
29*46133Smao  *		flags -- R_NEXT, R_PREV
30*46133Smao  *
31*46133Smao  *	Returns:
32*46133Smao  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if there's no data
33*46133Smao  *		in the tree to scan.
34*46133Smao  *
35*46133Smao  *	Side Effects:
36*46133Smao  *		Changes current scan position for the tree.  Almost certainly
37*46133Smao  *		changes current page, as well.  Sets BTF_SEQINIT bit in tree
38*46133Smao  *		flags, so that we know we've initialized a scan.
39*46133Smao  */
40*46133Smao 
41*46133Smao int
42*46133Smao _bt_seqinit(t, key, flags)
43*46133Smao 	BTREE_P t;
44*46133Smao 	DBT *key;
45*46133Smao 	int flags;
46*46133Smao {
47*46133Smao 	BTITEM *item;
48*46133Smao 	BTHEADER *h;
49*46133Smao 	CURSOR *c;
50*46133Smao 	IDATUM *id;
51*46133Smao 	index_t last;
52*46133Smao 
53*46133Smao 	/*
54*46133Smao 	 *  Figure out if we really have to search for the key that the
55*46133Smao 	 *  user supplied.  If key is null, then this is an unkeyed scan
56*46133Smao 	 *  and we can just start from an endpoint.
57*46133Smao 	 */
58*46133Smao 
59*46133Smao 	c = &(t->bt_cursor);
60*46133Smao 
61*46133Smao 	if (flags == R_CURSOR) {
62*46133Smao 		if (key->data != (char *) NULL) {
63*46133Smao 
64*46133Smao 			/* key supplied, find first instance of it */
65*46133Smao 			item = _bt_first(t, key);
66*46133Smao 			c->c_index = item->bti_index;
67*46133Smao 			c->c_pgno = t->bt_curpage->h_pgno;
68*46133Smao 		} else {
69*46133Smao 			errno = EINVAL;
70*46133Smao 			return (RET_ERROR);
71*46133Smao 		}
72*46133Smao 
73*46133Smao 	} else {
74*46133Smao 
75*46133Smao 		/*
76*46133Smao 		 *  Unkeyed scan.  For backward scans, find the last item
77*46133Smao 		 *  in the tree; for forward scans, find the first item.
78*46133Smao 		 */
79*46133Smao 
80*46133Smao 		if (_bt_getpage(t, (pgno_t) P_ROOT) == RET_ERROR)
81*46133Smao 			return (RET_ERROR);
82*46133Smao 		h = t->bt_curpage;
83*46133Smao 		if (flags == R_LAST || flags == R_PREV) {
84*46133Smao 
85*46133Smao 			/* backward scan */
86*46133Smao 			while (!(h->h_flags & F_LEAF)) {
87*46133Smao 				last = NEXTINDEX(h) - 1;
88*46133Smao 				id = (IDATUM *) GETDATUM(h,last);
89*46133Smao 				if (_bt_getpage(t, id->i_pgno) == RET_ERROR)
90*46133Smao 					return (RET_ERROR);
91*46133Smao 				h = t->bt_curpage;
92*46133Smao 			}
93*46133Smao 
94*46133Smao 			/* skip empty pages */
95*46133Smao 			while (NEXTINDEX(h) == 0 && h->h_prevpg != P_NONE) {
96*46133Smao 				if (_bt_getpage(t, h->h_prevpg) == RET_ERROR)
97*46133Smao 					return (RET_ERROR);
98*46133Smao 				h = t->bt_curpage;
99*46133Smao 			}
100*46133Smao 
101*46133Smao 			c->c_pgno = h->h_pgno;
102*46133Smao 			if (NEXTINDEX(h) > 0)
103*46133Smao 				c->c_index = NEXTINDEX(h) - 1;
104*46133Smao 			else
105*46133Smao 				c->c_index = 0;
106*46133Smao 		} else if (flags == R_FIRST || flags == R_NEXT) {
107*46133Smao 			/* forward scan */
108*46133Smao 			while (!(h->h_flags & F_LEAF)) {
109*46133Smao 				id = (IDATUM *) GETDATUM(h,0);
110*46133Smao 				if (_bt_getpage(t, id->i_pgno) == RET_ERROR)
111*46133Smao 					return (RET_ERROR);
112*46133Smao 				h = t->bt_curpage;
113*46133Smao 			}
114*46133Smao 
115*46133Smao 			/* skip empty pages */
116*46133Smao 			while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE) {
117*46133Smao 				if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
118*46133Smao 					return (RET_ERROR);
119*46133Smao 				h = t->bt_curpage;
120*46133Smao 			}
121*46133Smao 
122*46133Smao 			c->c_pgno = h->h_pgno;
123*46133Smao 			c->c_index = 0;
124*46133Smao 		} else {
125*46133Smao 			/* no flags passed in */
126*46133Smao 			errno = EINVAL;
127*46133Smao 			return (RET_ERROR);
128*46133Smao 		}
129*46133Smao 	}
130*46133Smao 
131*46133Smao 	/* okay, scan is initialized */
132*46133Smao 	t->bt_flags |= BTF_SEQINIT;
133*46133Smao 
134*46133Smao 	if (c->c_index == NEXTINDEX(t->bt_curpage))
135*46133Smao 		return (RET_SPECIAL);
136*46133Smao 
137*46133Smao 	return (RET_SUCCESS);
138*46133Smao }
139*46133Smao 
140*46133Smao /*
141*46133Smao  *  _BT_SEQADVANCE -- Advance the sequential scan on this tree.
142*46133Smao  *
143*46133Smao  *	Moves the current location pointer for the scan on this tree one
144*46133Smao  *	spot in the requested direction.
145*46133Smao  *
146*46133Smao  *	Parameters:
147*46133Smao  *		t -- btree being scanned
148*46133Smao  *		flags -- for R_NEXT, R_PREV
149*46133Smao  *
150*46133Smao  *	Returns:
151*46133Smao  *		RET_SUCCESS, RET_ERROR, or RET_SPECIAL if there is no
152*46133Smao  *		more data in the specified direction.
153*46133Smao  *
154*46133Smao  *	Side Effects:
155*46133Smao  *		May change current page.
156*46133Smao  */
157*46133Smao 
158*46133Smao int
159*46133Smao _bt_seqadvance(t, flags)
160*46133Smao 	BTREE_P t;
161*46133Smao 	int flags;
162*46133Smao {
163*46133Smao 	BTHEADER *h;
164*46133Smao 	CURSOR *c;
165*46133Smao 	index_t index;
166*46133Smao 
167*46133Smao 	c = &(t->bt_cursor);
168*46133Smao 	index = c->c_index;
169*46133Smao 
170*46133Smao 	if (_bt_getpage(t, c->c_pgno) == RET_ERROR)
171*46133Smao 		return (RET_ERROR);
172*46133Smao 	h = t->bt_curpage;
173*46133Smao 
174*46133Smao 	/* by the time we get here, don't need the cursor key anymore */
175*46133Smao 	if (c->c_key != (char *) NULL)
176*46133Smao 		(void) free(c->c_key);
177*46133Smao 
178*46133Smao 	if (flags == R_NEXT) {
179*46133Smao 
180*46133Smao 		/*
181*46133Smao 		 *  This is a forward scan.  If the cursor is pointing
182*46133Smao 		 *  at a virtual record (that is, it was pointing at
183*46133Smao 		 *  a record that got deleted), then we should return
184*46133Smao 		 *  the record it's pointing at now.  Otherwise, we
185*46133Smao 		 *  should advance the scan.  In either case, we need
186*46133Smao 		 *  to be careful not to run off the end of the current
187*46133Smao 		 *  page.
188*46133Smao 		 */
189*46133Smao 
190*46133Smao 		if (c->c_flags & CRSR_BEFORE) {
191*46133Smao 
192*46133Smao 			if (index >= NEXTINDEX(h)) {
193*46133Smao 				/* out of items on this page, get next page */
194*46133Smao 				if (h->h_nextpg == P_NONE) {
195*46133Smao 					/* tell caller we're done... */
196*46133Smao 					c->c_index = NEXTINDEX(h);
197*46133Smao 					return (RET_SPECIAL);
198*46133Smao 				}
199*46133Smao 
200*46133Smao 				/* skip empty pages */
201*46133Smao 				do {
202*46133Smao 					if (_bt_getpage(t, h->h_nextpg)
203*46133Smao 					    == RET_ERROR) {
204*46133Smao 						c->c_index = NEXTINDEX(h);
205*46133Smao 						return (RET_ERROR);
206*46133Smao 					}
207*46133Smao 					h = t->bt_curpage;
208*46133Smao 					c->c_pgno = h->h_pgno;
209*46133Smao 				} while (NEXTINDEX(h) == 0
210*46133Smao 					 && h->h_nextpg != P_NONE);
211*46133Smao 
212*46133Smao 				if (NEXTINDEX(h) == 0) {
213*46133Smao 					/* tell caller we're done */
214*46133Smao 					c->c_index = NEXTINDEX(h);
215*46133Smao 					return (RET_SPECIAL);
216*46133Smao 				}
217*46133Smao 				index = 0;
218*46133Smao 			}
219*46133Smao 			c->c_flags &= ~CRSR_BEFORE;
220*46133Smao 
221*46133Smao 		} else if (++index >= NEXTINDEX(h)) {
222*46133Smao 
223*46133Smao 			/* out of items on this page, get next page */
224*46133Smao 			if (h->h_nextpg == P_NONE) {
225*46133Smao 				/* tell caller we're done... */
226*46133Smao 				c->c_index = NEXTINDEX(h);
227*46133Smao 				return (RET_SPECIAL);
228*46133Smao 			}
229*46133Smao 
230*46133Smao 			/* skip empty pages */
231*46133Smao 			do {
232*46133Smao 				if (_bt_getpage(t, h->h_nextpg) == RET_ERROR) {
233*46133Smao 					c->c_index = NEXTINDEX(h);
234*46133Smao 					return (RET_ERROR);
235*46133Smao 				}
236*46133Smao 				h = t->bt_curpage;
237*46133Smao 				c->c_pgno = h->h_pgno;
238*46133Smao 			} while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE);
239*46133Smao 
240*46133Smao 			if (NEXTINDEX(h) == 0) {
241*46133Smao 				/* tell caller we're done */
242*46133Smao 				c->c_index = NEXTINDEX(h);
243*46133Smao 				return (RET_SPECIAL);
244*46133Smao 			}
245*46133Smao 			index = 0;
246*46133Smao 		}
247*46133Smao 	} else if (flags == R_PREV) {
248*46133Smao 
249*46133Smao 		/* for backward scans, life is substantially easier */
250*46133Smao 		c->c_flags &= ~CRSR_BEFORE;
251*46133Smao 		if (c->c_key != (char *) NULL) {
252*46133Smao 			(void) free(c->c_key);
253*46133Smao 			c->c_key = (char *) NULL;
254*46133Smao 		}
255*46133Smao 
256*46133Smao 		if (index == 0) {
257*46133Smao 
258*46133Smao 			/* we may be done */
259*46133Smao 			c->c_index = 0;
260*46133Smao 
261*46133Smao 			/* out of items on this page, get next page */
262*46133Smao 			if (h->h_prevpg == P_NONE)
263*46133Smao 				return (RET_SPECIAL);
264*46133Smao 
265*46133Smao 			/* skip empty pages */
266*46133Smao 			do {
267*46133Smao 				if (_bt_getpage(t, h->h_prevpg) == RET_ERROR)
268*46133Smao 					return (RET_ERROR);
269*46133Smao 				h = t->bt_curpage;
270*46133Smao 				c->c_pgno = h->h_pgno;
271*46133Smao 			} while (NEXTINDEX(h) == 0 && h->h_prevpg != P_NONE);
272*46133Smao 
273*46133Smao 			if (NEXTINDEX(h) == 0)
274*46133Smao 				return (RET_SPECIAL);
275*46133Smao 
276*46133Smao 			index = NEXTINDEX(h) - 1;
277*46133Smao 		} else
278*46133Smao 			--index;
279*46133Smao 	} else {
280*46133Smao 		/* must specify a direction */
281*46133Smao 		errno = EINVAL;
282*46133Smao 		return (RET_ERROR);
283*46133Smao 	}
284*46133Smao 
285*46133Smao 	c->c_index = index;
286*46133Smao 	return (RET_SUCCESS);
287*46133Smao }
288