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 * 3. All advertising materials mentioning features or use of this software 1458f0484fSRodney W. Grimes * must display the following acknowledgement: 1558f0484fSRodney W. Grimes * This product includes software developed by the University of 1658f0484fSRodney W. Grimes * California, Berkeley and its contributors. 1758f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 1858f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1958f0484fSRodney W. Grimes * without specific prior written permission. 2058f0484fSRodney W. Grimes * 2158f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2258f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2358f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2458f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2558f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2658f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2758f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2858f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2958f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3058f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3158f0484fSRodney W. Grimes * SUCH DAMAGE. 3258f0484fSRodney W. Grimes */ 3358f0484fSRodney W. Grimes 3458f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 35f1e396bcSPaul Traina static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94"; 3658f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 3758f0484fSRodney W. Grimes 3858f0484fSRodney W. Grimes #include <sys/types.h> 3958f0484fSRodney W. Grimes 4058f0484fSRodney W. Grimes #include <errno.h> 4158f0484fSRodney W. Grimes #include <stdio.h> 4258f0484fSRodney W. Grimes #include <stdlib.h> 4358f0484fSRodney W. Grimes #include <string.h> 4458f0484fSRodney W. Grimes 4558f0484fSRodney W. Grimes #include <db.h> 4658f0484fSRodney W. Grimes #include "recno.h" 4758f0484fSRodney W. Grimes 4858f0484fSRodney W. Grimes /* 4958f0484fSRodney W. Grimes * __REC_PUT -- Add a recno item to the tree. 5058f0484fSRodney W. Grimes * 5158f0484fSRodney W. Grimes * Parameters: 5258f0484fSRodney W. Grimes * dbp: pointer to access method 5358f0484fSRodney W. Grimes * key: key 5458f0484fSRodney W. Grimes * data: data 5558f0484fSRodney W. Grimes * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 5658f0484fSRodney W. Grimes * 5758f0484fSRodney W. Grimes * Returns: 5858f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is 5958f0484fSRodney W. Grimes * already in the tree and R_NOOVERWRITE specified. 6058f0484fSRodney W. Grimes */ 6158f0484fSRodney W. Grimes int 6258f0484fSRodney W. Grimes __rec_put(dbp, key, data, flags) 6358f0484fSRodney W. Grimes const DB *dbp; 6458f0484fSRodney W. Grimes DBT *key; 6558f0484fSRodney W. Grimes const DBT *data; 6658f0484fSRodney W. Grimes u_int flags; 6758f0484fSRodney W. Grimes { 6858f0484fSRodney W. Grimes BTREE *t; 69f1e396bcSPaul Traina DBT fdata, tdata; 7058f0484fSRodney W. Grimes recno_t nrec; 7158f0484fSRodney W. Grimes int status; 7258f0484fSRodney W. Grimes 7358f0484fSRodney W. Grimes t = dbp->internal; 7458f0484fSRodney W. Grimes 7558f0484fSRodney W. Grimes /* Toss any page pinned across calls. */ 7658f0484fSRodney W. Grimes if (t->bt_pinned != NULL) { 7758f0484fSRodney W. Grimes mpool_put(t->bt_mp, t->bt_pinned, 0); 7858f0484fSRodney W. Grimes t->bt_pinned = NULL; 7958f0484fSRodney W. Grimes } 8058f0484fSRodney W. Grimes 81f1e396bcSPaul Traina /* 82f1e396bcSPaul Traina * If using fixed-length records, and the record is long, return 83f1e396bcSPaul Traina * EINVAL. If it's short, pad it out. Use the record data return 84f1e396bcSPaul Traina * memory, it's only short-term. 85f1e396bcSPaul Traina */ 86f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) { 87f1e396bcSPaul Traina if (data->size > t->bt_reclen) 88f1e396bcSPaul Traina goto einval; 89f1e396bcSPaul Traina 90f1e396bcSPaul Traina if (t->bt_rdata.size < t->bt_reclen) { 91f1e396bcSPaul Traina t->bt_rdata.data = t->bt_rdata.data == NULL ? 92f1e396bcSPaul Traina malloc(t->bt_reclen) : 93f1e396bcSPaul Traina realloc(t->bt_rdata.data, t->bt_reclen); 94f1e396bcSPaul Traina if (t->bt_rdata.data == NULL) 95f1e396bcSPaul Traina return (RET_ERROR); 96f1e396bcSPaul Traina t->bt_rdata.size = t->bt_reclen; 97f1e396bcSPaul Traina } 98f1e396bcSPaul Traina memmove(t->bt_rdata.data, data->data, data->size); 99f1e396bcSPaul Traina memset((char *)t->bt_rdata.data + data->size, 100f1e396bcSPaul Traina t->bt_bval, t->bt_reclen - data->size); 101f1e396bcSPaul Traina fdata.data = t->bt_rdata.data; 102f1e396bcSPaul Traina fdata.size = t->bt_reclen; 103f1e396bcSPaul Traina } else { 104f1e396bcSPaul Traina fdata.data = data->data; 105f1e396bcSPaul Traina fdata.size = data->size; 106f1e396bcSPaul Traina } 107f1e396bcSPaul Traina 10858f0484fSRodney W. Grimes switch (flags) { 10958f0484fSRodney W. Grimes case R_CURSOR: 110f1e396bcSPaul Traina if (!F_ISSET(&t->bt_cursor, CURS_INIT)) 11158f0484fSRodney W. Grimes goto einval; 112f1e396bcSPaul Traina nrec = t->bt_cursor.rcursor; 11358f0484fSRodney W. Grimes break; 11458f0484fSRodney W. Grimes case R_SETCURSOR: 11558f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 11658f0484fSRodney W. Grimes goto einval; 11758f0484fSRodney W. Grimes break; 11858f0484fSRodney W. Grimes case R_IAFTER: 11958f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) { 12058f0484fSRodney W. Grimes nrec = 1; 12158f0484fSRodney W. Grimes flags = R_IBEFORE; 12258f0484fSRodney W. Grimes } 12358f0484fSRodney W. Grimes break; 12458f0484fSRodney W. Grimes case 0: 12558f0484fSRodney W. Grimes case R_IBEFORE: 12658f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 12758f0484fSRodney W. Grimes goto einval; 12858f0484fSRodney W. Grimes break; 12958f0484fSRodney W. Grimes case R_NOOVERWRITE: 13058f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 13158f0484fSRodney W. Grimes goto einval; 13258f0484fSRodney W. Grimes if (nrec <= t->bt_nrecs) 13358f0484fSRodney W. Grimes return (RET_SPECIAL); 13458f0484fSRodney W. Grimes break; 13558f0484fSRodney W. Grimes default: 13658f0484fSRodney W. Grimes einval: errno = EINVAL; 13758f0484fSRodney W. Grimes return (RET_ERROR); 13858f0484fSRodney W. Grimes } 13958f0484fSRodney W. Grimes 14058f0484fSRodney W. Grimes /* 14158f0484fSRodney W. Grimes * Make sure that records up to and including the put record are 14258f0484fSRodney W. Grimes * already in the database. If skipping records, create empty ones. 14358f0484fSRodney W. Grimes */ 14458f0484fSRodney W. Grimes if (nrec > t->bt_nrecs) { 145f1e396bcSPaul Traina if (!F_ISSET(t, R_EOF | R_INMEM) && 14658f0484fSRodney W. Grimes t->bt_irec(t, nrec) == RET_ERROR) 14758f0484fSRodney W. Grimes return (RET_ERROR); 14858f0484fSRodney W. Grimes if (nrec > t->bt_nrecs + 1) { 149f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN)) { 15058f0484fSRodney W. Grimes if ((tdata.data = 15158f0484fSRodney W. Grimes (void *)malloc(t->bt_reclen)) == NULL) 15258f0484fSRodney W. Grimes return (RET_ERROR); 15358f0484fSRodney W. Grimes tdata.size = t->bt_reclen; 15458f0484fSRodney W. Grimes memset(tdata.data, t->bt_bval, tdata.size); 15558f0484fSRodney W. Grimes } else { 15658f0484fSRodney W. Grimes tdata.data = NULL; 15758f0484fSRodney W. Grimes tdata.size = 0; 15858f0484fSRodney W. Grimes } 15958f0484fSRodney W. Grimes while (nrec > t->bt_nrecs + 1) 16058f0484fSRodney W. Grimes if (__rec_iput(t, 16158f0484fSRodney W. Grimes t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 16258f0484fSRodney W. Grimes return (RET_ERROR); 163f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN)) 16458f0484fSRodney W. Grimes free(tdata.data); 16558f0484fSRodney W. Grimes } 16658f0484fSRodney W. Grimes } 16758f0484fSRodney W. Grimes 168f1e396bcSPaul Traina if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS) 16958f0484fSRodney W. Grimes return (status); 17058f0484fSRodney W. Grimes 17158f0484fSRodney W. Grimes if (flags == R_SETCURSOR) 172f1e396bcSPaul Traina t->bt_cursor.rcursor = nrec; 17358f0484fSRodney W. Grimes 174f1e396bcSPaul Traina F_SET(t, R_MODIFIED); 17558f0484fSRodney W. Grimes return (__rec_ret(t, NULL, nrec, key, NULL)); 17658f0484fSRodney W. Grimes } 17758f0484fSRodney W. Grimes 17858f0484fSRodney W. Grimes /* 17958f0484fSRodney W. Grimes * __REC_IPUT -- Add a recno item to the tree. 18058f0484fSRodney W. Grimes * 18158f0484fSRodney W. Grimes * Parameters: 18258f0484fSRodney W. Grimes * t: tree 18358f0484fSRodney W. Grimes * nrec: record number 18458f0484fSRodney W. Grimes * data: data 18558f0484fSRodney W. Grimes * 18658f0484fSRodney W. Grimes * Returns: 18758f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS 18858f0484fSRodney W. Grimes */ 18958f0484fSRodney W. Grimes int 19058f0484fSRodney W. Grimes __rec_iput(t, nrec, data, flags) 19158f0484fSRodney W. Grimes BTREE *t; 19258f0484fSRodney W. Grimes recno_t nrec; 19358f0484fSRodney W. Grimes const DBT *data; 19458f0484fSRodney W. Grimes u_int flags; 19558f0484fSRodney W. Grimes { 19658f0484fSRodney W. Grimes DBT tdata; 19758f0484fSRodney W. Grimes EPG *e; 19858f0484fSRodney W. Grimes PAGE *h; 19958f0484fSRodney W. Grimes indx_t index, nxtindex; 20058f0484fSRodney W. Grimes pgno_t pg; 201f1e396bcSPaul Traina u_int32_t nbytes; 20258f0484fSRodney W. Grimes int dflags, status; 20358f0484fSRodney W. Grimes char *dest, db[NOVFLSIZE]; 20458f0484fSRodney W. Grimes 20558f0484fSRodney W. Grimes /* 20658f0484fSRodney W. Grimes * If the data won't fit on a page, store it on indirect pages. 20758f0484fSRodney W. Grimes * 20858f0484fSRodney W. Grimes * XXX 20958f0484fSRodney W. Grimes * If the insert fails later on, these pages aren't recovered. 21058f0484fSRodney W. Grimes */ 21158f0484fSRodney W. Grimes if (data->size > t->bt_ovflsize) { 21258f0484fSRodney W. Grimes if (__ovfl_put(t, data, &pg) == RET_ERROR) 21358f0484fSRodney W. Grimes return (RET_ERROR); 21458f0484fSRodney W. Grimes tdata.data = db; 21558f0484fSRodney W. Grimes tdata.size = NOVFLSIZE; 21658f0484fSRodney W. Grimes *(pgno_t *)db = pg; 217f1e396bcSPaul Traina *(u_int32_t *)(db + sizeof(pgno_t)) = data->size; 21858f0484fSRodney W. Grimes dflags = P_BIGDATA; 21958f0484fSRodney W. Grimes data = &tdata; 22058f0484fSRodney W. Grimes } else 22158f0484fSRodney W. Grimes dflags = 0; 22258f0484fSRodney W. Grimes 22358f0484fSRodney W. Grimes /* __rec_search pins the returned page. */ 22458f0484fSRodney W. Grimes if ((e = __rec_search(t, nrec, 22558f0484fSRodney W. Grimes nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 22658f0484fSRodney W. Grimes SINSERT : SEARCH)) == NULL) 22758f0484fSRodney W. Grimes return (RET_ERROR); 22858f0484fSRodney W. Grimes 22958f0484fSRodney W. Grimes h = e->page; 23058f0484fSRodney W. Grimes index = e->index; 23158f0484fSRodney W. Grimes 23258f0484fSRodney W. Grimes /* 23358f0484fSRodney W. Grimes * Add the specified key/data pair to the tree. The R_IAFTER and 23458f0484fSRodney W. Grimes * R_IBEFORE flags insert the key after/before the specified key. 23558f0484fSRodney W. Grimes * 23658f0484fSRodney W. Grimes * Pages are split as required. 23758f0484fSRodney W. Grimes */ 23858f0484fSRodney W. Grimes switch (flags) { 23958f0484fSRodney W. Grimes case R_IAFTER: 24058f0484fSRodney W. Grimes ++index; 24158f0484fSRodney W. Grimes break; 24258f0484fSRodney W. Grimes case R_IBEFORE: 24358f0484fSRodney W. Grimes break; 24458f0484fSRodney W. Grimes default: 24558f0484fSRodney W. Grimes if (nrec < t->bt_nrecs && 24658f0484fSRodney W. Grimes __rec_dleaf(t, h, index) == RET_ERROR) { 24758f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 24858f0484fSRodney W. Grimes return (RET_ERROR); 24958f0484fSRodney W. Grimes } 25058f0484fSRodney W. Grimes break; 25158f0484fSRodney W. Grimes } 25258f0484fSRodney W. Grimes 25358f0484fSRodney W. Grimes /* 25458f0484fSRodney W. Grimes * If not enough room, split the page. The split code will insert 25558f0484fSRodney W. Grimes * the key and data and unpin the current page. If inserting into 25658f0484fSRodney W. Grimes * the offset array, shift the pointers up. 25758f0484fSRodney W. Grimes */ 25858f0484fSRodney W. Grimes nbytes = NRLEAFDBT(data->size); 25958f0484fSRodney W. Grimes if (h->upper - h->lower < nbytes + sizeof(indx_t)) { 26058f0484fSRodney W. Grimes status = __bt_split(t, h, NULL, data, dflags, nbytes, index); 26158f0484fSRodney W. Grimes if (status == RET_SUCCESS) 26258f0484fSRodney W. Grimes ++t->bt_nrecs; 26358f0484fSRodney W. Grimes return (status); 26458f0484fSRodney W. Grimes } 26558f0484fSRodney W. Grimes 26658f0484fSRodney W. Grimes if (index < (nxtindex = NEXTINDEX(h))) 26758f0484fSRodney W. Grimes memmove(h->linp + index + 1, h->linp + index, 26858f0484fSRodney W. Grimes (nxtindex - index) * sizeof(indx_t)); 26958f0484fSRodney W. Grimes h->lower += sizeof(indx_t); 27058f0484fSRodney W. Grimes 27158f0484fSRodney W. Grimes h->linp[index] = h->upper -= nbytes; 27258f0484fSRodney W. Grimes dest = (char *)h + h->upper; 27358f0484fSRodney W. Grimes WR_RLEAF(dest, data, dflags); 27458f0484fSRodney W. Grimes 27558f0484fSRodney W. Grimes ++t->bt_nrecs; 276f1e396bcSPaul Traina F_SET(t, B_MODIFIED); 27758f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, MPOOL_DIRTY); 27858f0484fSRodney W. Grimes 27958f0484fSRodney W. Grimes return (RET_SUCCESS); 28058f0484fSRodney W. Grimes } 281