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