158f0484fSRodney W. Grimes /*- 2f1e396bcSPaul Traina * Copyright (c) 1990, 1993, 1994 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 658f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 758f0484fSRodney W. Grimes * are met: 858f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 958f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1058f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1158f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1258f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1358f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 1458f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1558f0484fSRodney W. Grimes * without specific prior written permission. 1658f0484fSRodney W. Grimes * 1758f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1858f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1958f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2058f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2158f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2258f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2358f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2458f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2558f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2658f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2758f0484fSRodney W. Grimes * SUCH DAMAGE. 2858f0484fSRodney W. Grimes */ 2958f0484fSRodney W. Grimes 3058f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 31f1e396bcSPaul Traina static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94"; 3258f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 33333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 34333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3558f0484fSRodney W. Grimes 3658f0484fSRodney W. Grimes #include <sys/types.h> 3758f0484fSRodney W. Grimes 3858f0484fSRodney W. Grimes #include <errno.h> 3958f0484fSRodney W. Grimes #include <stdio.h> 4058f0484fSRodney W. Grimes #include <stdlib.h> 4158f0484fSRodney W. Grimes #include <string.h> 4258f0484fSRodney W. Grimes 4358f0484fSRodney W. Grimes #include <db.h> 4458f0484fSRodney W. Grimes #include "recno.h" 4558f0484fSRodney W. Grimes 4658f0484fSRodney W. Grimes /* 4758f0484fSRodney W. Grimes * __REC_PUT -- Add a recno item to the tree. 4858f0484fSRodney W. Grimes * 4958f0484fSRodney W. Grimes * Parameters: 5058f0484fSRodney W. Grimes * dbp: pointer to access method 5158f0484fSRodney W. Grimes * key: key 5258f0484fSRodney W. Grimes * data: data 5358f0484fSRodney W. Grimes * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 5458f0484fSRodney W. Grimes * 5558f0484fSRodney W. Grimes * Returns: 5658f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is 5758f0484fSRodney W. Grimes * already in the tree and R_NOOVERWRITE specified. 5858f0484fSRodney W. Grimes */ 5958f0484fSRodney W. Grimes int 600ac22237SXin LI __rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags) 6158f0484fSRodney W. Grimes { 6258f0484fSRodney W. Grimes BTREE *t; 63f1e396bcSPaul Traina DBT fdata, tdata; 6458f0484fSRodney W. Grimes recno_t nrec; 6558f0484fSRodney W. Grimes int status; 6658f0484fSRodney W. Grimes 6758f0484fSRodney W. Grimes t = dbp->internal; 6858f0484fSRodney W. Grimes 6958f0484fSRodney W. Grimes /* Toss any page pinned across calls. */ 7058f0484fSRodney W. Grimes if (t->bt_pinned != NULL) { 7158f0484fSRodney W. Grimes mpool_put(t->bt_mp, t->bt_pinned, 0); 7258f0484fSRodney W. Grimes t->bt_pinned = NULL; 7358f0484fSRodney W. Grimes } 7458f0484fSRodney W. Grimes 75f1e396bcSPaul Traina /* 76f1e396bcSPaul Traina * If using fixed-length records, and the record is long, return 77f1e396bcSPaul Traina * EINVAL. If it's short, pad it out. Use the record data return 78f1e396bcSPaul Traina * memory, it's only short-term. 79f1e396bcSPaul Traina */ 80f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) { 81f1e396bcSPaul Traina if (data->size > t->bt_reclen) 82f1e396bcSPaul Traina goto einval; 83f1e396bcSPaul Traina 84f1e396bcSPaul Traina if (t->bt_rdata.size < t->bt_reclen) { 85e8420087SWarner Losh t->bt_rdata.data = 86e8420087SWarner Losh reallocf(t->bt_rdata.data, t->bt_reclen); 87f1e396bcSPaul Traina if (t->bt_rdata.data == NULL) 88f1e396bcSPaul Traina return (RET_ERROR); 89f1e396bcSPaul Traina t->bt_rdata.size = t->bt_reclen; 90f1e396bcSPaul Traina } 91f1e396bcSPaul Traina memmove(t->bt_rdata.data, data->data, data->size); 92f1e396bcSPaul Traina memset((char *)t->bt_rdata.data + data->size, 93f1e396bcSPaul Traina t->bt_bval, t->bt_reclen - data->size); 94f1e396bcSPaul Traina fdata.data = t->bt_rdata.data; 95f1e396bcSPaul Traina fdata.size = t->bt_reclen; 96f1e396bcSPaul Traina } else { 97f1e396bcSPaul Traina fdata.data = data->data; 98f1e396bcSPaul Traina fdata.size = data->size; 99f1e396bcSPaul Traina } 100f1e396bcSPaul Traina 10158f0484fSRodney W. Grimes switch (flags) { 10258f0484fSRodney W. Grimes case R_CURSOR: 103f1e396bcSPaul Traina if (!F_ISSET(&t->bt_cursor, CURS_INIT)) 10458f0484fSRodney W. Grimes goto einval; 105f1e396bcSPaul Traina nrec = t->bt_cursor.rcursor; 10658f0484fSRodney W. Grimes break; 10758f0484fSRodney W. Grimes case R_SETCURSOR: 10858f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 10958f0484fSRodney W. Grimes goto einval; 11058f0484fSRodney W. Grimes break; 11158f0484fSRodney W. Grimes case R_IAFTER: 11258f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) { 11358f0484fSRodney W. Grimes nrec = 1; 11458f0484fSRodney W. Grimes flags = R_IBEFORE; 11558f0484fSRodney W. Grimes } 11658f0484fSRodney W. Grimes break; 11758f0484fSRodney W. Grimes case 0: 11858f0484fSRodney W. Grimes case R_IBEFORE: 11958f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 12058f0484fSRodney W. Grimes goto einval; 12158f0484fSRodney W. Grimes break; 12258f0484fSRodney W. Grimes case R_NOOVERWRITE: 12358f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 12458f0484fSRodney W. Grimes goto einval; 12558f0484fSRodney W. Grimes if (nrec <= t->bt_nrecs) 12658f0484fSRodney W. Grimes return (RET_SPECIAL); 12758f0484fSRodney W. Grimes break; 12858f0484fSRodney W. Grimes default: 12958f0484fSRodney W. Grimes einval: errno = EINVAL; 13058f0484fSRodney W. Grimes return (RET_ERROR); 13158f0484fSRodney W. Grimes } 13258f0484fSRodney W. Grimes 13358f0484fSRodney W. Grimes /* 13458f0484fSRodney W. Grimes * Make sure that records up to and including the put record are 13558f0484fSRodney W. Grimes * already in the database. If skipping records, create empty ones. 13658f0484fSRodney W. Grimes */ 13758f0484fSRodney W. Grimes if (nrec > t->bt_nrecs) { 138f1e396bcSPaul Traina if (!F_ISSET(t, R_EOF | R_INMEM) && 13958f0484fSRodney W. Grimes t->bt_irec(t, nrec) == RET_ERROR) 14058f0484fSRodney W. Grimes return (RET_ERROR); 14158f0484fSRodney W. Grimes if (nrec > t->bt_nrecs + 1) { 142f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN)) { 14358f0484fSRodney W. Grimes if ((tdata.data = 14458f0484fSRodney W. Grimes (void *)malloc(t->bt_reclen)) == NULL) 14558f0484fSRodney W. Grimes return (RET_ERROR); 14658f0484fSRodney W. Grimes tdata.size = t->bt_reclen; 14758f0484fSRodney W. Grimes memset(tdata.data, t->bt_bval, tdata.size); 14858f0484fSRodney W. Grimes } else { 14958f0484fSRodney W. Grimes tdata.data = NULL; 15058f0484fSRodney W. Grimes tdata.size = 0; 15158f0484fSRodney W. Grimes } 15258f0484fSRodney W. Grimes while (nrec > t->bt_nrecs + 1) 15358f0484fSRodney W. Grimes if (__rec_iput(t, 15458f0484fSRodney W. Grimes t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 15558f0484fSRodney W. Grimes return (RET_ERROR); 156f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN)) 15758f0484fSRodney W. Grimes free(tdata.data); 15858f0484fSRodney W. Grimes } 15958f0484fSRodney W. Grimes } 16058f0484fSRodney W. Grimes 161f1e396bcSPaul Traina if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS) 16258f0484fSRodney W. Grimes return (status); 16358f0484fSRodney W. Grimes 1644f0682b0SBrian Feldman switch (flags) { 1654f0682b0SBrian Feldman case R_IAFTER: 1664f0682b0SBrian Feldman nrec++; 1674f0682b0SBrian Feldman break; 1684f0682b0SBrian Feldman case R_SETCURSOR: 169f1e396bcSPaul Traina t->bt_cursor.rcursor = nrec; 1704f0682b0SBrian Feldman break; 1714f0682b0SBrian Feldman } 17258f0484fSRodney W. Grimes 173f1e396bcSPaul Traina F_SET(t, R_MODIFIED); 17458f0484fSRodney W. Grimes return (__rec_ret(t, NULL, nrec, key, NULL)); 17558f0484fSRodney W. Grimes } 17658f0484fSRodney W. Grimes 17758f0484fSRodney W. Grimes /* 17858f0484fSRodney W. Grimes * __REC_IPUT -- Add a recno item to the tree. 17958f0484fSRodney W. Grimes * 18058f0484fSRodney W. Grimes * Parameters: 18158f0484fSRodney W. Grimes * t: tree 18258f0484fSRodney W. Grimes * nrec: record number 18358f0484fSRodney W. Grimes * data: data 18458f0484fSRodney W. Grimes * 18558f0484fSRodney W. Grimes * Returns: 18658f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS 18758f0484fSRodney W. Grimes */ 18858f0484fSRodney W. Grimes int 1890ac22237SXin LI __rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags) 19058f0484fSRodney W. Grimes { 19158f0484fSRodney W. Grimes DBT tdata; 19258f0484fSRodney W. Grimes EPG *e; 19358f0484fSRodney W. Grimes PAGE *h; 1944c66e4b6SXin LI indx_t idx, nxtindex; 19558f0484fSRodney W. Grimes pgno_t pg; 196f1e396bcSPaul Traina u_int32_t nbytes; 19758f0484fSRodney W. Grimes int dflags, status; 19858f0484fSRodney W. Grimes char *dest, db[NOVFLSIZE]; 19958f0484fSRodney W. Grimes 20058f0484fSRodney W. Grimes /* 20158f0484fSRodney W. Grimes * If the data won't fit on a page, store it on indirect pages. 20258f0484fSRodney W. Grimes * 20358f0484fSRodney W. Grimes * XXX 20458f0484fSRodney W. Grimes * If the insert fails later on, these pages aren't recovered. 20558f0484fSRodney W. Grimes */ 20658f0484fSRodney W. Grimes if (data->size > t->bt_ovflsize) { 20758f0484fSRodney W. Grimes if (__ovfl_put(t, data, &pg) == RET_ERROR) 20858f0484fSRodney W. Grimes return (RET_ERROR); 20958f0484fSRodney W. Grimes tdata.data = db; 21058f0484fSRodney W. Grimes tdata.size = NOVFLSIZE; 21158f0484fSRodney W. Grimes *(pgno_t *)db = pg; 212f1e396bcSPaul Traina *(u_int32_t *)(db + sizeof(pgno_t)) = data->size; 21358f0484fSRodney W. Grimes dflags = P_BIGDATA; 21458f0484fSRodney W. Grimes data = &tdata; 21558f0484fSRodney W. Grimes } else 21658f0484fSRodney W. Grimes dflags = 0; 21758f0484fSRodney W. Grimes 21858f0484fSRodney W. Grimes /* __rec_search pins the returned page. */ 21958f0484fSRodney W. Grimes if ((e = __rec_search(t, nrec, 22058f0484fSRodney W. Grimes nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 22158f0484fSRodney W. Grimes SINSERT : SEARCH)) == NULL) 22258f0484fSRodney W. Grimes return (RET_ERROR); 22358f0484fSRodney W. Grimes 22458f0484fSRodney W. Grimes h = e->page; 2254c66e4b6SXin LI idx = e->index; 22658f0484fSRodney W. Grimes 22758f0484fSRodney W. Grimes /* 22858f0484fSRodney W. Grimes * Add the specified key/data pair to the tree. The R_IAFTER and 22958f0484fSRodney W. Grimes * R_IBEFORE flags insert the key after/before the specified key. 23058f0484fSRodney W. Grimes * 23158f0484fSRodney W. Grimes * Pages are split as required. 23258f0484fSRodney W. Grimes */ 23358f0484fSRodney W. Grimes switch (flags) { 23458f0484fSRodney W. Grimes case R_IAFTER: 2354c66e4b6SXin LI ++idx; 23658f0484fSRodney W. Grimes break; 23758f0484fSRodney W. Grimes case R_IBEFORE: 23858f0484fSRodney W. Grimes break; 23958f0484fSRodney W. Grimes default: 24058f0484fSRodney W. Grimes if (nrec < t->bt_nrecs && 2414c66e4b6SXin LI __rec_dleaf(t, h, idx) == RET_ERROR) { 24258f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 24358f0484fSRodney W. Grimes return (RET_ERROR); 24458f0484fSRodney W. Grimes } 24558f0484fSRodney W. Grimes break; 24658f0484fSRodney W. Grimes } 24758f0484fSRodney W. Grimes 24858f0484fSRodney W. Grimes /* 24958f0484fSRodney W. Grimes * If not enough room, split the page. The split code will insert 25058f0484fSRodney W. Grimes * the key and data and unpin the current page. If inserting into 25158f0484fSRodney W. Grimes * the offset array, shift the pointers up. 25258f0484fSRodney W. Grimes */ 25358f0484fSRodney W. Grimes nbytes = NRLEAFDBT(data->size); 25458f0484fSRodney W. Grimes if (h->upper - h->lower < nbytes + sizeof(indx_t)) { 2554c66e4b6SXin LI status = __bt_split(t, h, NULL, data, dflags, nbytes, idx); 25658f0484fSRodney W. Grimes if (status == RET_SUCCESS) 25758f0484fSRodney W. Grimes ++t->bt_nrecs; 25858f0484fSRodney W. Grimes return (status); 25958f0484fSRodney W. Grimes } 26058f0484fSRodney W. Grimes 2614c66e4b6SXin LI if (idx < (nxtindex = NEXTINDEX(h))) 2624c66e4b6SXin LI memmove(h->linp + idx + 1, h->linp + idx, 2634c66e4b6SXin LI (nxtindex - idx) * sizeof(indx_t)); 26458f0484fSRodney W. Grimes h->lower += sizeof(indx_t); 26558f0484fSRodney W. Grimes 2664c66e4b6SXin LI h->linp[idx] = h->upper -= nbytes; 26758f0484fSRodney W. Grimes dest = (char *)h + h->upper; 26858f0484fSRodney W. Grimes WR_RLEAF(dest, data, dflags); 26958f0484fSRodney W. Grimes 27058f0484fSRodney W. Grimes ++t->bt_nrecs; 271f1e396bcSPaul Traina F_SET(t, B_MODIFIED); 27258f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, MPOOL_DIRTY); 27358f0484fSRodney W. Grimes 27458f0484fSRodney W. Grimes return (RET_SUCCESS); 27558f0484fSRodney W. Grimes } 276