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