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*57989Sbostic static char sccsid[] = "@(#)bt_get.c 5.8 (Berkeley) 02/14/93"; 1346135Smao #endif /* LIBC_SCCS and not lint */ 1446135Smao 1550989Sbostic #include <sys/types.h> 1656733Sbostic 1750989Sbostic #include <errno.h> 1856733Sbostic #include <stddef.h> 1950989Sbostic #include <stdio.h> 2056733Sbostic 2157932Sbostic #include <db.h> 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; 100*57989Sbostic indx_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; 11656733Sbostic } else { 11750989Sbostic cpgno = P_INVALID; 11856733Sbostic cindex = 0; /* GCC thinks it's uninitialized. */ 11956733Sbostic } 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 */ 14557002Sbostic while (e->index == 0) { 14657002Sbostic if (h->prevpg == P_INVALID) 14757002Sbostic goto done1; 14857002Sbostic if (h->pgno != save.page->pgno) 14957002Sbostic mpool_put(t->bt_mp, h, 0); 15057002Sbostic if ((h = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL) { 15157002Sbostic if (h->pgno == save.page->pgno) 15257002Sbostic mpool_put(t->bt_mp, save.page, 0); 15357002Sbostic return (NULL); 15457002Sbostic } 15557002Sbostic e->page = h; 15657002Sbostic e->index = NEXTINDEX(h); 15757002Sbostic } 15850989Sbostic --e->index; 15950989Sbostic } while (__bt_cmp(t, key, e) == 0); 16046135Smao 16150989Sbostic /* 16250989Sbostic * Reach here with the last page that was looked at pinned, which may 16350989Sbostic * or may not be the same as the last (or original) match page. If 16450989Sbostic * it's not useful, release it. 16550989Sbostic */ 16650989Sbostic done1: if (h->pgno != save.page->pgno) 16750989Sbostic mpool_put(t->bt_mp, h, 0); 16846135Smao 16946135Smao /* 17050989Sbostic * If still haven't found a record, the only possibility left is the 17150989Sbostic * next one. Move forward one slot, skipping empty pages and check. 17246135Smao */ 17350989Sbostic if (!found) { 17450989Sbostic h = save.page; 17550989Sbostic if (++save.index == NEXTINDEX(h)) { 17650989Sbostic do { 17750989Sbostic pg = h->nextpg; 17850989Sbostic mpool_put(t->bt_mp, h, 0); 17950989Sbostic if (pg == P_INVALID) { 18050989Sbostic *exactp = 0; 18150989Sbostic return (e); 18246135Smao } 18350989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 18450989Sbostic return (NULL); 18550989Sbostic } while ((save.index = NEXTINDEX(h)) == 0); 18650989Sbostic save.page = h; 18746135Smao } 18850989Sbostic if (__bt_cmp(t, key, &save) != 0) { 18950989Sbostic *exactp = 0; 19050989Sbostic return (e); 19146135Smao } 19246135Smao } 19350989Sbostic *e = save; 19450989Sbostic *exactp = 1; 19550989Sbostic return (e); 19646135Smao } 197