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