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*51103Sbostic static char sccsid[] = "@(#)bt_get.c 5.4 (Berkeley) 09/12/91"; 1346135Smao #endif /* LIBC_SCCS and not lint */ 1446135Smao 1550989Sbostic #include <sys/types.h> 1650989Sbostic #include <errno.h> 1746135Smao #include <db.h> 1850989Sbostic #include <stdio.h> 1950989Sbostic #include <stddef.h> 2046135Smao #include "btree.h" 2146135Smao 2246135Smao /* 2350989Sbostic * __BT_GET -- Get a record from the btree. 2446135Smao * 2550989Sbostic * Parameters: 2650989Sbostic * dbp: pointer to access method 2750989Sbostic * key: key to find 2850989Sbostic * data: data to return 2950989Sbostic * flag: currently unused 3046135Smao * 3150989Sbostic * Returns: 3250989Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 3346135Smao */ 3446135Smao int 3550989Sbostic __bt_get(dbp, key, data, flags) 3650989Sbostic const DB *dbp; 37*51103Sbostic const DBT *key; 38*51103Sbostic DBT *data; 3950989Sbostic u_int flags; 4046135Smao { 4150989Sbostic BTREE *t; 4250989Sbostic EPG *e; 4350989Sbostic int exact, status; 4446135Smao 4550989Sbostic if (flags) { 4650989Sbostic errno = EINVAL; 4750989Sbostic return (RET_ERROR); 4846135Smao } 4950989Sbostic t = dbp->internal; 5050989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 5150989Sbostic return (RET_ERROR); 5250989Sbostic if (!exact) { 5350989Sbostic mpool_put(t->bt_mp, e->page, 0); 5450989Sbostic return (RET_SPECIAL); 5550989Sbostic } 5646135Smao 5750989Sbostic /* 5850989Sbostic * A special case is if we found the record but it's flagged for 5950989Sbostic * deletion. In this case, we want to find another record with the 6050989Sbostic * same key, if it exists. Rather than look around the tree we call 61*51103Sbostic * __bt_first and have it redo the search, as __bt_first will not 6250989Sbostic * return keys marked for deletion. Slow, but should never happen. 6350989Sbostic */ 6450989Sbostic if (ISSET(t, BTF_DELCRSR) && e->page->pgno == t->bt_bcursor.pgno && 6550989Sbostic e->index == t->bt_bcursor.index) { 6650989Sbostic mpool_put(t->bt_mp, e->page, 0); 6750989Sbostic if ((e = __bt_first(t, key, &exact)) == NULL) 6846135Smao return (RET_ERROR); 6950989Sbostic if (!exact) 7050989Sbostic return (RET_SPECIAL); 7146135Smao } 7246135Smao 73*51103Sbostic status = __bt_ret(t, e, NULL, data); 7450989Sbostic mpool_put(t->bt_mp, e->page, 0); 7550989Sbostic return (status); 7646135Smao } 7746135Smao 7846135Smao /* 79*51103Sbostic * __BT_FIRST -- Find the first entry. 8046135Smao * 8150989Sbostic * Parameters: 8250989Sbostic * t: the tree 8350989Sbostic * key: the key 8446135Smao * 8550989Sbostic * Returns: 86*51103Sbostic * The first entry in the tree greater than or equal to key. 8746135Smao */ 8850989Sbostic EPG * 8950989Sbostic __bt_first(t, key, exactp) 9050989Sbostic BTREE *t; 91*51103Sbostic const DBT *key; 9250989Sbostic int *exactp; 9346135Smao { 9450989Sbostic register PAGE *h; 9550989Sbostic register EPG *e; 9650989Sbostic EPG save; 9750989Sbostic pgno_t cpgno, pg; 9850989Sbostic index_t cindex; 9950989Sbostic int found; 10046135Smao 10150989Sbostic /* 10250989Sbostic * Find any matching record; __bt_search pins the page. Only exact 103*51103Sbostic * matches are tricky, otherwise just return the location of the key 104*51103Sbostic * if it were to be inserted into the tree. 10550989Sbostic */ 10650989Sbostic if ((e = __bt_search(t, key, exactp)) == NULL) 10750989Sbostic return (NULL); 108*51103Sbostic if (!*exactp) 10950989Sbostic return (e); 11046135Smao 11150989Sbostic if (ISSET(t, BTF_DELCRSR)) { 11250989Sbostic cpgno = t->bt_bcursor.pgno; 11350989Sbostic cindex = t->bt_bcursor.index; 11450989Sbostic } else 11550989Sbostic cpgno = P_INVALID; 11646135Smao 11750989Sbostic /* 11850989Sbostic * Walk backwards, skipping empty pages, as long as the entry matches 11950989Sbostic * and there are keys left in the tree. Save a copy of each match in 12050989Sbostic * case we go too far. A special case is that we don't return a match 12150989Sbostic * on records that the cursor references that have already been flagged 12250989Sbostic * for deletion. 12350989Sbostic */ 12450989Sbostic save = *e; 12550989Sbostic h = e->page; 12650989Sbostic found = 0; 12750989Sbostic do { 12850989Sbostic if (cpgno != h->pgno || cindex != e->index) { 12950989Sbostic if (save.page->pgno != e->page->pgno) { 13050989Sbostic mpool_put(t->bt_mp, save.page, 0); 13150989Sbostic save = *e; 13250989Sbostic } else 13350989Sbostic save.index = e->index; 13450989Sbostic found = 1; 13546135Smao } 13646135Smao /* 13750989Sbostic * Make a special effort not to unpin the page the last (or 13850989Sbostic * original) match was on, but also make sure it's unpinned 13950989Sbostic * if an error occurs. 14046135Smao */ 14150989Sbostic if (e->index == 0) 14250989Sbostic do { 14350989Sbostic if (h->prevpg == P_INVALID) 14450989Sbostic goto done1; 14550989Sbostic if (h->pgno != save.page->pgno) 14650989Sbostic mpool_put(t->bt_mp, h, 0); 14750989Sbostic if ((h = mpool_get(t->bt_mp, 14850989Sbostic h->prevpg, 0)) == NULL) { 14950989Sbostic if (h->pgno == save.page->pgno) 15050989Sbostic mpool_put(t->bt_mp, 15150989Sbostic save.page, 0); 15250989Sbostic return (NULL); 15346135Smao } 15450989Sbostic } while ((e->index = NEXTINDEX(h)) == 0); 15550989Sbostic --e->index; 15650989Sbostic } while (__bt_cmp(t, key, e) == 0); 15746135Smao 15850989Sbostic /* 15950989Sbostic * Reach here with the last page that was looked at pinned, which may 16050989Sbostic * or may not be the same as the last (or original) match page. If 16150989Sbostic * it's not useful, release it. 16250989Sbostic */ 16350989Sbostic done1: if (h->pgno != save.page->pgno) 16450989Sbostic mpool_put(t->bt_mp, h, 0); 16546135Smao 16646135Smao /* 16750989Sbostic * If still haven't found a record, the only possibility left is the 16850989Sbostic * next one. Move forward one slot, skipping empty pages and check. 16946135Smao */ 17050989Sbostic if (!found) { 17150989Sbostic h = save.page; 17250989Sbostic if (++save.index == NEXTINDEX(h)) { 17350989Sbostic do { 17450989Sbostic pg = h->nextpg; 17550989Sbostic mpool_put(t->bt_mp, h, 0); 17650989Sbostic if (pg == P_INVALID) { 17750989Sbostic *exactp = 0; 17850989Sbostic return (e); 17946135Smao } 18050989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 18150989Sbostic return (NULL); 18250989Sbostic } while ((save.index = NEXTINDEX(h)) == 0); 18350989Sbostic save.page = h; 18446135Smao } 18550989Sbostic if (__bt_cmp(t, key, &save) != 0) { 18650989Sbostic *exactp = 0; 18750989Sbostic return (e); 18846135Smao } 18946135Smao } 19050989Sbostic *e = save; 19150989Sbostic *exactp = 1; 19250989Sbostic return (e); 19346135Smao } 194