146135Smao /*- 246135Smao * Copyright (c) 1990 The Regents of the University of California. 346135Smao * All rights reserved. 446135Smao * 546135Smao * This code is derived from software contributed to Berkeley by 646135Smao * Mike Olson. 746135Smao * 846135Smao * %sccs.include.redist.c% 946135Smao */ 1046135Smao 1146135Smao #if defined(LIBC_SCCS) && !defined(lint) 12*50989Sbostic static char sccsid[] = "@(#)bt_get.c 5.3 (Berkeley) 09/04/91"; 1346135Smao #endif /* LIBC_SCCS and not lint */ 1446135Smao 15*50989Sbostic #include <sys/types.h> 16*50989Sbostic #include <errno.h> 1746135Smao #include <db.h> 18*50989Sbostic #include <stdio.h> 19*50989Sbostic #include <stddef.h> 2046135Smao #include "btree.h" 2146135Smao 2246135Smao /* 23*50989Sbostic * __BT_GET -- Get a record from the btree. 2446135Smao * 25*50989Sbostic * Parameters: 26*50989Sbostic * dbp: pointer to access method 27*50989Sbostic * key: key to find 28*50989Sbostic * data: data to return 29*50989Sbostic * flag: currently unused 3046135Smao * 31*50989Sbostic * Returns: 32*50989Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 3346135Smao */ 3446135Smao int 35*50989Sbostic __bt_get(dbp, key, data, flags) 36*50989Sbostic const DB *dbp; 37*50989Sbostic DBT *key, *data; 38*50989Sbostic u_int flags; 3946135Smao { 40*50989Sbostic BTREE *t; 41*50989Sbostic EPG *e; 42*50989Sbostic int exact, status; 4346135Smao 44*50989Sbostic if (flags) { 45*50989Sbostic errno = EINVAL; 46*50989Sbostic return (RET_ERROR); 4746135Smao } 48*50989Sbostic t = dbp->internal; 49*50989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 50*50989Sbostic return (RET_ERROR); 51*50989Sbostic if (!exact) { 52*50989Sbostic mpool_put(t->bt_mp, e->page, 0); 53*50989Sbostic return (RET_SPECIAL); 54*50989Sbostic } 5546135Smao 56*50989Sbostic /* 57*50989Sbostic * A special case is if we found the record but it's flagged for 58*50989Sbostic * deletion. In this case, we want to find another record with the 59*50989Sbostic * same key, if it exists. Rather than look around the tree we call 60*50989Sbostic * __bt_first and have it redo the search as __bt_first will not 61*50989Sbostic * return keys marked for deletion. Slow, but should never happen. 62*50989Sbostic */ 63*50989Sbostic if (ISSET(t, BTF_DELCRSR) && e->page->pgno == t->bt_bcursor.pgno && 64*50989Sbostic e->index == t->bt_bcursor.index) { 65*50989Sbostic mpool_put(t->bt_mp, e->page, 0); 66*50989Sbostic if ((e = __bt_first(t, key, &exact)) == NULL) 6746135Smao return (RET_ERROR); 68*50989Sbostic if (!exact) 69*50989Sbostic return (RET_SPECIAL); 7046135Smao } 7146135Smao 72*50989Sbostic status = __bt_ret(t, e, data, key); 73*50989Sbostic mpool_put(t->bt_mp, e->page, 0); 74*50989Sbostic return (status); 7546135Smao } 7646135Smao 7746135Smao /* 78*50989Sbostic * __BT_FIRST -- Find the first record in the tree matching the key. 7946135Smao * 80*50989Sbostic * Parameters: 81*50989Sbostic * t: the tree 82*50989Sbostic * key: the key 8346135Smao * 84*50989Sbostic * Returns: 85*50989Sbostic * The first matching record. 8646135Smao */ 87*50989Sbostic EPG * 88*50989Sbostic __bt_first(t, key, exactp) 89*50989Sbostic BTREE *t; 90*50989Sbostic DBT *key; 91*50989Sbostic int *exactp; 9246135Smao { 93*50989Sbostic register PAGE *h; 94*50989Sbostic register EPG *e; 95*50989Sbostic EPG save; 96*50989Sbostic pgno_t cpgno, pg; 97*50989Sbostic index_t cindex; 98*50989Sbostic int found; 9946135Smao 100*50989Sbostic /* 101*50989Sbostic * Find any matching record; __bt_search pins the page. Only exact 102*50989Sbostic * matches are interesting. 103*50989Sbostic */ 104*50989Sbostic if ((e = __bt_search(t, key, exactp)) == NULL) 105*50989Sbostic return (NULL); 106*50989Sbostic if (!*exactp) { 107*50989Sbostic mpool_put(t->bt_mp, e->page, 0); 108*50989Sbostic return (e); 10946135Smao } 11046135Smao 111*50989Sbostic if (ISSET(t, BTF_DELCRSR)) { 112*50989Sbostic cpgno = t->bt_bcursor.pgno; 113*50989Sbostic cindex = t->bt_bcursor.index; 114*50989Sbostic } else 115*50989Sbostic cpgno = P_INVALID; 11646135Smao 117*50989Sbostic /* 118*50989Sbostic * Walk backwards, skipping empty pages, as long as the entry matches 119*50989Sbostic * and there are keys left in the tree. Save a copy of each match in 120*50989Sbostic * case we go too far. A special case is that we don't return a match 121*50989Sbostic * on records that the cursor references that have already been flagged 122*50989Sbostic * for deletion. 123*50989Sbostic */ 124*50989Sbostic save = *e; 125*50989Sbostic h = e->page; 126*50989Sbostic found = 0; 127*50989Sbostic do { 128*50989Sbostic if (cpgno != h->pgno || cindex != e->index) { 129*50989Sbostic if (save.page->pgno != e->page->pgno) { 130*50989Sbostic mpool_put(t->bt_mp, save.page, 0); 131*50989Sbostic save = *e; 132*50989Sbostic } else 133*50989Sbostic save.index = e->index; 134*50989Sbostic found = 1; 13546135Smao } 13646135Smao /* 137*50989Sbostic * Make a special effort not to unpin the page the last (or 138*50989Sbostic * original) match was on, but also make sure it's unpinned 139*50989Sbostic * if an error occurs. 14046135Smao */ 141*50989Sbostic if (e->index == 0) 142*50989Sbostic do { 143*50989Sbostic if (h->prevpg == P_INVALID) 144*50989Sbostic goto done1; 145*50989Sbostic if (h->pgno != save.page->pgno) 146*50989Sbostic mpool_put(t->bt_mp, h, 0); 147*50989Sbostic if ((h = mpool_get(t->bt_mp, 148*50989Sbostic h->prevpg, 0)) == NULL) { 149*50989Sbostic if (h->pgno == save.page->pgno) 150*50989Sbostic mpool_put(t->bt_mp, 151*50989Sbostic save.page, 0); 152*50989Sbostic return (NULL); 15346135Smao } 154*50989Sbostic } while ((e->index = NEXTINDEX(h)) == 0); 155*50989Sbostic --e->index; 156*50989Sbostic } while (__bt_cmp(t, key, e) == 0); 15746135Smao 158*50989Sbostic /* 159*50989Sbostic * Reach here with the last page that was looked at pinned, which may 160*50989Sbostic * or may not be the same as the last (or original) match page. If 161*50989Sbostic * it's not useful, release it. 162*50989Sbostic */ 163*50989Sbostic done1: if (h->pgno != save.page->pgno) 164*50989Sbostic mpool_put(t->bt_mp, h, 0); 16546135Smao 16646135Smao /* 167*50989Sbostic * If still haven't found a record, the only possibility left is the 168*50989Sbostic * next one. Move forward one slot, skipping empty pages and check. 16946135Smao */ 170*50989Sbostic if (!found) { 171*50989Sbostic h = save.page; 172*50989Sbostic if (++save.index == NEXTINDEX(h)) { 173*50989Sbostic do { 174*50989Sbostic pg = h->nextpg; 175*50989Sbostic mpool_put(t->bt_mp, h, 0); 176*50989Sbostic if (pg == P_INVALID) { 177*50989Sbostic *exactp = 0; 178*50989Sbostic return (e); 17946135Smao } 180*50989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 181*50989Sbostic return (NULL); 182*50989Sbostic } while ((save.index = NEXTINDEX(h)) == 0); 183*50989Sbostic save.page = h; 18446135Smao } 185*50989Sbostic if (__bt_cmp(t, key, &save) != 0) { 186*50989Sbostic *exactp = 0; 187*50989Sbostic return (e); 18846135Smao } 18946135Smao } 190*50989Sbostic *e = save; 191*50989Sbostic *exactp = 1; 192*50989Sbostic return (e); 19346135Smao } 194