158f0484fSRodney W. Grimes /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 4f1e396bcSPaul Traina * Copyright (c) 1990, 1993, 1994 558f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 658f0484fSRodney W. Grimes * 758f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 858f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 958f0484fSRodney W. Grimes * are met: 1058f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1158f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1258f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1358f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1458f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 1658f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1758f0484fSRodney W. Grimes * without specific prior written permission. 1858f0484fSRodney W. Grimes * 1958f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2058f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2158f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2258f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2358f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2458f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2558f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2658f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2758f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2858f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2958f0484fSRodney W. Grimes * SUCH DAMAGE. 3058f0484fSRodney W. Grimes */ 3158f0484fSRodney W. Grimes 3258f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 33f1e396bcSPaul Traina static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94"; 3458f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 35333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 36333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 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 620ac22237SXin LI __rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags) 6358f0484fSRodney W. Grimes { 6458f0484fSRodney W. Grimes BTREE *t; 65f1e396bcSPaul Traina DBT fdata, tdata; 6658f0484fSRodney W. Grimes recno_t nrec; 6758f0484fSRodney W. Grimes int status; 6858f0484fSRodney W. Grimes 6958f0484fSRodney W. Grimes t = dbp->internal; 7058f0484fSRodney W. Grimes 7158f0484fSRodney W. Grimes /* Toss any page pinned across calls. */ 7258f0484fSRodney W. Grimes if (t->bt_pinned != NULL) { 7358f0484fSRodney W. Grimes mpool_put(t->bt_mp, t->bt_pinned, 0); 7458f0484fSRodney W. Grimes t->bt_pinned = NULL; 7558f0484fSRodney W. Grimes } 7658f0484fSRodney W. Grimes 77f1e396bcSPaul Traina /* 78f1e396bcSPaul Traina * If using fixed-length records, and the record is long, return 79f1e396bcSPaul Traina * EINVAL. If it's short, pad it out. Use the record data return 80f1e396bcSPaul Traina * memory, it's only short-term. 81f1e396bcSPaul Traina */ 82f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) { 83f1e396bcSPaul Traina if (data->size > t->bt_reclen) 84f1e396bcSPaul Traina goto einval; 85f1e396bcSPaul Traina 86f1e396bcSPaul Traina if (t->bt_rdata.size < t->bt_reclen) { 87e8420087SWarner Losh t->bt_rdata.data = 88e8420087SWarner Losh reallocf(t->bt_rdata.data, t->bt_reclen); 89f1e396bcSPaul Traina if (t->bt_rdata.data == NULL) 90f1e396bcSPaul Traina return (RET_ERROR); 91f1e396bcSPaul Traina t->bt_rdata.size = t->bt_reclen; 92f1e396bcSPaul Traina } 93f1e396bcSPaul Traina memmove(t->bt_rdata.data, data->data, data->size); 94f1e396bcSPaul Traina memset((char *)t->bt_rdata.data + data->size, 95f1e396bcSPaul Traina t->bt_bval, t->bt_reclen - data->size); 96f1e396bcSPaul Traina fdata.data = t->bt_rdata.data; 97f1e396bcSPaul Traina fdata.size = t->bt_reclen; 98f1e396bcSPaul Traina } else { 99f1e396bcSPaul Traina fdata.data = data->data; 100f1e396bcSPaul Traina fdata.size = data->size; 101f1e396bcSPaul Traina } 102f1e396bcSPaul Traina 10358f0484fSRodney W. Grimes switch (flags) { 10458f0484fSRodney W. Grimes case R_CURSOR: 105f1e396bcSPaul Traina if (!F_ISSET(&t->bt_cursor, CURS_INIT)) 10658f0484fSRodney W. Grimes goto einval; 107f1e396bcSPaul Traina nrec = t->bt_cursor.rcursor; 10858f0484fSRodney W. Grimes break; 10958f0484fSRodney W. Grimes case R_SETCURSOR: 11058f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 11158f0484fSRodney W. Grimes goto einval; 11258f0484fSRodney W. Grimes break; 11358f0484fSRodney W. Grimes case R_IAFTER: 11458f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) { 11558f0484fSRodney W. Grimes nrec = 1; 11658f0484fSRodney W. Grimes flags = R_IBEFORE; 11758f0484fSRodney W. Grimes } 11858f0484fSRodney W. Grimes break; 11958f0484fSRodney W. Grimes case 0: 12058f0484fSRodney W. Grimes case R_IBEFORE: 12158f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 12258f0484fSRodney W. Grimes goto einval; 12358f0484fSRodney W. Grimes break; 12458f0484fSRodney W. Grimes case R_NOOVERWRITE: 12558f0484fSRodney W. Grimes if ((nrec = *(recno_t *)key->data) == 0) 12658f0484fSRodney W. Grimes goto einval; 12758f0484fSRodney W. Grimes if (nrec <= t->bt_nrecs) 12858f0484fSRodney W. Grimes return (RET_SPECIAL); 12958f0484fSRodney W. Grimes break; 13058f0484fSRodney W. Grimes default: 13158f0484fSRodney W. Grimes einval: errno = EINVAL; 13258f0484fSRodney W. Grimes return (RET_ERROR); 13358f0484fSRodney W. Grimes } 13458f0484fSRodney W. Grimes 13558f0484fSRodney W. Grimes /* 13658f0484fSRodney W. Grimes * Make sure that records up to and including the put record are 13758f0484fSRodney W. Grimes * already in the database. If skipping records, create empty ones. 13858f0484fSRodney W. Grimes */ 13958f0484fSRodney W. Grimes if (nrec > t->bt_nrecs) { 140f1e396bcSPaul Traina if (!F_ISSET(t, R_EOF | R_INMEM) && 14158f0484fSRodney W. Grimes t->bt_irec(t, nrec) == RET_ERROR) 14258f0484fSRodney W. Grimes return (RET_ERROR); 14358f0484fSRodney W. Grimes if (nrec > t->bt_nrecs + 1) { 144f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN)) { 145e1ea7827SPedro F. Giffuni if ((tdata.data = malloc(t->bt_reclen)) == NULL) 14658f0484fSRodney W. Grimes return (RET_ERROR); 14758f0484fSRodney W. Grimes tdata.size = t->bt_reclen; 14858f0484fSRodney W. Grimes memset(tdata.data, t->bt_bval, tdata.size); 14958f0484fSRodney W. Grimes } else { 15058f0484fSRodney W. Grimes tdata.data = NULL; 15158f0484fSRodney W. Grimes tdata.size = 0; 15258f0484fSRodney W. Grimes } 15358f0484fSRodney W. Grimes while (nrec > t->bt_nrecs + 1) 15458f0484fSRodney W. Grimes if (__rec_iput(t, 15558f0484fSRodney W. Grimes t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 15658f0484fSRodney W. Grimes return (RET_ERROR); 157f1e396bcSPaul Traina if (F_ISSET(t, R_FIXLEN)) 15858f0484fSRodney W. Grimes free(tdata.data); 15958f0484fSRodney W. Grimes } 16058f0484fSRodney W. Grimes } 16158f0484fSRodney W. Grimes 162f1e396bcSPaul Traina if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS) 16358f0484fSRodney W. Grimes return (status); 16458f0484fSRodney W. Grimes 1654f0682b0SBrian Feldman switch (flags) { 1664f0682b0SBrian Feldman case R_IAFTER: 1674f0682b0SBrian Feldman nrec++; 1684f0682b0SBrian Feldman break; 1694f0682b0SBrian Feldman case R_SETCURSOR: 170f1e396bcSPaul Traina t->bt_cursor.rcursor = nrec; 1714f0682b0SBrian Feldman break; 1724f0682b0SBrian Feldman } 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 1900ac22237SXin LI __rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags) 19158f0484fSRodney W. Grimes { 19258f0484fSRodney W. Grimes DBT tdata; 19358f0484fSRodney W. Grimes EPG *e; 19458f0484fSRodney W. Grimes PAGE *h; 1954c66e4b6SXin LI indx_t idx, nxtindex; 19658f0484fSRodney W. Grimes pgno_t pg; 197f1e396bcSPaul Traina u_int32_t nbytes; 19858f0484fSRodney W. Grimes int dflags, status; 19958f0484fSRodney W. Grimes char *dest, db[NOVFLSIZE]; 20058f0484fSRodney W. Grimes 20158f0484fSRodney W. Grimes /* 20258f0484fSRodney W. Grimes * If the data won't fit on a page, store it on indirect pages. 20358f0484fSRodney W. Grimes * 20458f0484fSRodney W. Grimes * XXX 20558f0484fSRodney W. Grimes * If the insert fails later on, these pages aren't recovered. 20658f0484fSRodney W. Grimes */ 20758f0484fSRodney W. Grimes if (data->size > t->bt_ovflsize) { 20858f0484fSRodney W. Grimes if (__ovfl_put(t, data, &pg) == RET_ERROR) 20958f0484fSRodney W. Grimes return (RET_ERROR); 21058f0484fSRodney W. Grimes tdata.data = db; 21158f0484fSRodney W. Grimes tdata.size = NOVFLSIZE; 212e1ea7827SPedro F. Giffuni memcpy(db, &pg, sizeof(pg)); 213f1e396bcSPaul Traina *(u_int32_t *)(db + sizeof(pgno_t)) = data->size; 21458f0484fSRodney W. Grimes dflags = P_BIGDATA; 21558f0484fSRodney W. Grimes data = &tdata; 21658f0484fSRodney W. Grimes } else 21758f0484fSRodney W. Grimes dflags = 0; 21858f0484fSRodney W. Grimes 21958f0484fSRodney W. Grimes /* __rec_search pins the returned page. */ 22058f0484fSRodney W. Grimes if ((e = __rec_search(t, nrec, 22158f0484fSRodney W. Grimes nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 22258f0484fSRodney W. Grimes SINSERT : SEARCH)) == NULL) 22358f0484fSRodney W. Grimes return (RET_ERROR); 22458f0484fSRodney W. Grimes 22558f0484fSRodney W. Grimes h = e->page; 2264c66e4b6SXin LI idx = e->index; 22758f0484fSRodney W. Grimes 22858f0484fSRodney W. Grimes /* 22958f0484fSRodney W. Grimes * Add the specified key/data pair to the tree. The R_IAFTER and 23058f0484fSRodney W. Grimes * R_IBEFORE flags insert the key after/before the specified key. 23158f0484fSRodney W. Grimes * 23258f0484fSRodney W. Grimes * Pages are split as required. 23358f0484fSRodney W. Grimes */ 23458f0484fSRodney W. Grimes switch (flags) { 23558f0484fSRodney W. Grimes case R_IAFTER: 2364c66e4b6SXin LI ++idx; 23758f0484fSRodney W. Grimes break; 23858f0484fSRodney W. Grimes case R_IBEFORE: 23958f0484fSRodney W. Grimes break; 24058f0484fSRodney W. Grimes default: 24158f0484fSRodney W. Grimes if (nrec < t->bt_nrecs && 2424c66e4b6SXin LI __rec_dleaf(t, h, idx) == RET_ERROR) { 24358f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 24458f0484fSRodney W. Grimes return (RET_ERROR); 24558f0484fSRodney W. Grimes } 24658f0484fSRodney W. Grimes break; 24758f0484fSRodney W. Grimes } 24858f0484fSRodney W. Grimes 24958f0484fSRodney W. Grimes /* 25058f0484fSRodney W. Grimes * If not enough room, split the page. The split code will insert 25158f0484fSRodney W. Grimes * the key and data and unpin the current page. If inserting into 25258f0484fSRodney W. Grimes * the offset array, shift the pointers up. 25358f0484fSRodney W. Grimes */ 25458f0484fSRodney W. Grimes nbytes = NRLEAFDBT(data->size); 255f60486b3SXin LI if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) { 2564c66e4b6SXin LI status = __bt_split(t, h, NULL, data, dflags, nbytes, idx); 25758f0484fSRodney W. Grimes if (status == RET_SUCCESS) 25858f0484fSRodney W. Grimes ++t->bt_nrecs; 25958f0484fSRodney W. Grimes return (status); 26058f0484fSRodney W. Grimes } 26158f0484fSRodney W. Grimes 2624c66e4b6SXin LI if (idx < (nxtindex = NEXTINDEX(h))) 2634c66e4b6SXin LI memmove(h->linp + idx + 1, h->linp + idx, 2644c66e4b6SXin LI (nxtindex - idx) * sizeof(indx_t)); 26558f0484fSRodney W. Grimes h->lower += sizeof(indx_t); 26658f0484fSRodney W. Grimes 2674c66e4b6SXin LI h->linp[idx] = h->upper -= nbytes; 26858f0484fSRodney W. Grimes dest = (char *)h + h->upper; 26958f0484fSRodney W. Grimes WR_RLEAF(dest, data, dflags); 27058f0484fSRodney W. Grimes 27158f0484fSRodney W. Grimes ++t->bt_nrecs; 272f1e396bcSPaul Traina F_SET(t, B_MODIFIED); 27358f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, MPOOL_DIRTY); 27458f0484fSRodney W. Grimes 27558f0484fSRodney W. Grimes return (RET_SUCCESS); 27658f0484fSRodney W. Grimes } 277