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*56733Sbostic static char sccsid[] = "@(#)bt_get.c 5.5 (Berkeley) 11/13/92"; 1346135Smao #endif /* LIBC_SCCS and not lint */ 1446135Smao 1550989Sbostic #include <sys/types.h> 16*56733Sbostic 17*56733Sbostic #include <db.h> 1850989Sbostic #include <errno.h> 19*56733Sbostic #include <stddef.h> 2050989Sbostic #include <stdio.h> 21*56733Sbostic 2246135Smao #include "btree.h" 2346135Smao 2446135Smao /* 2550989Sbostic * __BT_GET -- Get a record from the btree. 2646135Smao * 2750989Sbostic * Parameters: 2850989Sbostic * dbp: pointer to access method 2950989Sbostic * key: key to find 3050989Sbostic * data: data to return 3150989Sbostic * flag: currently unused 3246135Smao * 3350989Sbostic * Returns: 3450989Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 3546135Smao */ 3646135Smao int 3750989Sbostic __bt_get(dbp, key, data, flags) 3850989Sbostic const DB *dbp; 3951103Sbostic const DBT *key; 4051103Sbostic DBT *data; 4150989Sbostic u_int flags; 4246135Smao { 4350989Sbostic BTREE *t; 4450989Sbostic EPG *e; 4550989Sbostic int exact, status; 4646135Smao 4750989Sbostic if (flags) { 4850989Sbostic errno = EINVAL; 4950989Sbostic return (RET_ERROR); 5046135Smao } 5150989Sbostic t = dbp->internal; 5250989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 5350989Sbostic return (RET_ERROR); 5450989Sbostic if (!exact) { 5550989Sbostic mpool_put(t->bt_mp, e->page, 0); 5650989Sbostic return (RET_SPECIAL); 5750989Sbostic } 5846135Smao 5950989Sbostic /* 6050989Sbostic * A special case is if we found the record but it's flagged for 6150989Sbostic * deletion. In this case, we want to find another record with the 6250989Sbostic * same key, if it exists. Rather than look around the tree we call 6351103Sbostic * __bt_first and have it redo the search, as __bt_first will not 6450989Sbostic * return keys marked for deletion. Slow, but should never happen. 6550989Sbostic */ 6650989Sbostic if (ISSET(t, BTF_DELCRSR) && e->page->pgno == t->bt_bcursor.pgno && 6750989Sbostic e->index == t->bt_bcursor.index) { 6850989Sbostic mpool_put(t->bt_mp, e->page, 0); 6950989Sbostic if ((e = __bt_first(t, key, &exact)) == NULL) 7046135Smao return (RET_ERROR); 7150989Sbostic if (!exact) 7250989Sbostic return (RET_SPECIAL); 7346135Smao } 7446135Smao 7551103Sbostic status = __bt_ret(t, e, NULL, data); 7650989Sbostic mpool_put(t->bt_mp, e->page, 0); 7750989Sbostic return (status); 7846135Smao } 7946135Smao 8046135Smao /* 8151103Sbostic * __BT_FIRST -- Find the first entry. 8246135Smao * 8350989Sbostic * Parameters: 8450989Sbostic * t: the tree 8550989Sbostic * key: the key 8646135Smao * 8750989Sbostic * Returns: 8851103Sbostic * The first entry in the tree greater than or equal to key. 8946135Smao */ 9050989Sbostic EPG * 9150989Sbostic __bt_first(t, key, exactp) 9250989Sbostic BTREE *t; 9351103Sbostic const DBT *key; 9450989Sbostic int *exactp; 9546135Smao { 9650989Sbostic register PAGE *h; 9750989Sbostic register EPG *e; 9850989Sbostic EPG save; 9950989Sbostic pgno_t cpgno, pg; 10050989Sbostic index_t cindex; 10150989Sbostic int found; 10246135Smao 10350989Sbostic /* 10450989Sbostic * Find any matching record; __bt_search pins the page. Only exact 10551103Sbostic * matches are tricky, otherwise just return the location of the key 10651103Sbostic * if it were to be inserted into the tree. 10750989Sbostic */ 10850989Sbostic if ((e = __bt_search(t, key, exactp)) == NULL) 10950989Sbostic return (NULL); 11051103Sbostic if (!*exactp) 11150989Sbostic return (e); 11246135Smao 11350989Sbostic if (ISSET(t, BTF_DELCRSR)) { 11450989Sbostic cpgno = t->bt_bcursor.pgno; 11550989Sbostic cindex = t->bt_bcursor.index; 116*56733Sbostic } else { 11750989Sbostic cpgno = P_INVALID; 118*56733Sbostic cindex = 0; /* GCC thinks it's uninitialized. */ 119*56733Sbostic } 12046135Smao 12150989Sbostic /* 12250989Sbostic * Walk backwards, skipping empty pages, as long as the entry matches 12350989Sbostic * and there are keys left in the tree. Save a copy of each match in 12450989Sbostic * case we go too far. A special case is that we don't return a match 12550989Sbostic * on records that the cursor references that have already been flagged 12650989Sbostic * for deletion. 12750989Sbostic */ 12850989Sbostic save = *e; 12950989Sbostic h = e->page; 13050989Sbostic found = 0; 13150989Sbostic do { 13250989Sbostic if (cpgno != h->pgno || cindex != e->index) { 13350989Sbostic if (save.page->pgno != e->page->pgno) { 13450989Sbostic mpool_put(t->bt_mp, save.page, 0); 13550989Sbostic save = *e; 13650989Sbostic } else 13750989Sbostic save.index = e->index; 13850989Sbostic found = 1; 13946135Smao } 14046135Smao /* 14150989Sbostic * Make a special effort not to unpin the page the last (or 14250989Sbostic * original) match was on, but also make sure it's unpinned 14350989Sbostic * if an error occurs. 14446135Smao */ 14550989Sbostic if (e->index == 0) 14650989Sbostic do { 14750989Sbostic if (h->prevpg == P_INVALID) 14850989Sbostic goto done1; 14950989Sbostic if (h->pgno != save.page->pgno) 15050989Sbostic mpool_put(t->bt_mp, h, 0); 15150989Sbostic if ((h = mpool_get(t->bt_mp, 15250989Sbostic h->prevpg, 0)) == NULL) { 15350989Sbostic if (h->pgno == save.page->pgno) 15450989Sbostic mpool_put(t->bt_mp, 15550989Sbostic save.page, 0); 15650989Sbostic return (NULL); 15746135Smao } 15850989Sbostic } while ((e->index = NEXTINDEX(h)) == 0); 15950989Sbostic --e->index; 16050989Sbostic } while (__bt_cmp(t, key, e) == 0); 16146135Smao 16250989Sbostic /* 16350989Sbostic * Reach here with the last page that was looked at pinned, which may 16450989Sbostic * or may not be the same as the last (or original) match page. If 16550989Sbostic * it's not useful, release it. 16650989Sbostic */ 16750989Sbostic done1: if (h->pgno != save.page->pgno) 16850989Sbostic mpool_put(t->bt_mp, h, 0); 16946135Smao 17046135Smao /* 17150989Sbostic * If still haven't found a record, the only possibility left is the 17250989Sbostic * next one. Move forward one slot, skipping empty pages and check. 17346135Smao */ 17450989Sbostic if (!found) { 17550989Sbostic h = save.page; 17650989Sbostic if (++save.index == NEXTINDEX(h)) { 17750989Sbostic do { 17850989Sbostic pg = h->nextpg; 17950989Sbostic mpool_put(t->bt_mp, h, 0); 18050989Sbostic if (pg == P_INVALID) { 18150989Sbostic *exactp = 0; 18250989Sbostic return (e); 18346135Smao } 18450989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 18550989Sbostic return (NULL); 18650989Sbostic } while ((save.index = NEXTINDEX(h)) == 0); 18750989Sbostic save.page = h; 18846135Smao } 18950989Sbostic if (__bt_cmp(t, key, &save) != 0) { 19050989Sbostic *exactp = 0; 19150989Sbostic return (e); 19246135Smao } 19346135Smao } 19450989Sbostic *e = save; 19550989Sbostic *exactp = 1; 19650989Sbostic return (e); 19746135Smao } 198