11573Srgrimes/*- 214287Spst * Copyright (c) 1990, 1993, 1994 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 3114287Spststatic char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94"; 321573Srgrimes#endif /* LIBC_SCCS and not lint */ 3392986Sobrien#include <sys/cdefs.h> 3492986Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 361573Srgrimes#include <sys/types.h> 371573Srgrimes 381573Srgrimes#include <errno.h> 391573Srgrimes#include <stdio.h> 401573Srgrimes#include <stdlib.h> 411573Srgrimes#include <string.h> 421573Srgrimes 431573Srgrimes#include <db.h> 441573Srgrimes#include "recno.h" 451573Srgrimes 461573Srgrimes/* 471573Srgrimes * __REC_PUT -- Add a recno item to the tree. 481573Srgrimes * 491573Srgrimes * Parameters: 501573Srgrimes * dbp: pointer to access method 511573Srgrimes * key: key 521573Srgrimes * data: data 531573Srgrimes * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 541573Srgrimes * 551573Srgrimes * Returns: 561573Srgrimes * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is 571573Srgrimes * already in the tree and R_NOOVERWRITE specified. 581573Srgrimes */ 591573Srgrimesint 60189291Sdelphij__rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags) 611573Srgrimes{ 621573Srgrimes BTREE *t; 6314287Spst DBT fdata, tdata; 641573Srgrimes recno_t nrec; 651573Srgrimes int status; 661573Srgrimes 671573Srgrimes t = dbp->internal; 681573Srgrimes 691573Srgrimes /* Toss any page pinned across calls. */ 701573Srgrimes if (t->bt_pinned != NULL) { 711573Srgrimes mpool_put(t->bt_mp, t->bt_pinned, 0); 721573Srgrimes t->bt_pinned = NULL; 731573Srgrimes } 741573Srgrimes 7514287Spst /* 7614287Spst * If using fixed-length records, and the record is long, return 7714287Spst * EINVAL. If it's short, pad it out. Use the record data return 7814287Spst * memory, it's only short-term. 7914287Spst */ 8014287Spst if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) { 8114287Spst if (data->size > t->bt_reclen) 8214287Spst goto einval; 8314287Spst 8414287Spst if (t->bt_rdata.size < t->bt_reclen) { 8539327Simp t->bt_rdata.data = 8639327Simp reallocf(t->bt_rdata.data, t->bt_reclen); 8714287Spst if (t->bt_rdata.data == NULL) 8814287Spst return (RET_ERROR); 8914287Spst t->bt_rdata.size = t->bt_reclen; 9014287Spst } 9114287Spst memmove(t->bt_rdata.data, data->data, data->size); 9214287Spst memset((char *)t->bt_rdata.data + data->size, 9314287Spst t->bt_bval, t->bt_reclen - data->size); 9414287Spst fdata.data = t->bt_rdata.data; 9514287Spst fdata.size = t->bt_reclen; 9614287Spst } else { 9714287Spst fdata.data = data->data; 9814287Spst fdata.size = data->size; 9914287Spst } 10014287Spst 1011573Srgrimes switch (flags) { 1021573Srgrimes case R_CURSOR: 10314287Spst if (!F_ISSET(&t->bt_cursor, CURS_INIT)) 1041573Srgrimes goto einval; 10514287Spst nrec = t->bt_cursor.rcursor; 1061573Srgrimes break; 1071573Srgrimes case R_SETCURSOR: 1081573Srgrimes if ((nrec = *(recno_t *)key->data) == 0) 1091573Srgrimes goto einval; 1101573Srgrimes break; 1111573Srgrimes case R_IAFTER: 1121573Srgrimes if ((nrec = *(recno_t *)key->data) == 0) { 1131573Srgrimes nrec = 1; 1141573Srgrimes flags = R_IBEFORE; 1151573Srgrimes } 1161573Srgrimes break; 1171573Srgrimes case 0: 1181573Srgrimes case R_IBEFORE: 1191573Srgrimes if ((nrec = *(recno_t *)key->data) == 0) 1201573Srgrimes goto einval; 1211573Srgrimes break; 1221573Srgrimes case R_NOOVERWRITE: 1231573Srgrimes if ((nrec = *(recno_t *)key->data) == 0) 1241573Srgrimes goto einval; 1251573Srgrimes if (nrec <= t->bt_nrecs) 1261573Srgrimes return (RET_SPECIAL); 1271573Srgrimes break; 1281573Srgrimes default: 1291573Srgrimeseinval: errno = EINVAL; 1301573Srgrimes return (RET_ERROR); 1311573Srgrimes } 1321573Srgrimes 1331573Srgrimes /* 1341573Srgrimes * Make sure that records up to and including the put record are 1351573Srgrimes * already in the database. If skipping records, create empty ones. 1361573Srgrimes */ 1371573Srgrimes if (nrec > t->bt_nrecs) { 13814287Spst if (!F_ISSET(t, R_EOF | R_INMEM) && 1391573Srgrimes t->bt_irec(t, nrec) == RET_ERROR) 1401573Srgrimes return (RET_ERROR); 1411573Srgrimes if (nrec > t->bt_nrecs + 1) { 14214287Spst if (F_ISSET(t, R_FIXLEN)) { 1431573Srgrimes if ((tdata.data = 1441573Srgrimes (void *)malloc(t->bt_reclen)) == NULL) 1451573Srgrimes return (RET_ERROR); 1461573Srgrimes tdata.size = t->bt_reclen; 1471573Srgrimes memset(tdata.data, t->bt_bval, tdata.size); 1481573Srgrimes } else { 1491573Srgrimes tdata.data = NULL; 1501573Srgrimes tdata.size = 0; 1511573Srgrimes } 1521573Srgrimes while (nrec > t->bt_nrecs + 1) 1531573Srgrimes if (__rec_iput(t, 1541573Srgrimes t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 1551573Srgrimes return (RET_ERROR); 15614287Spst if (F_ISSET(t, R_FIXLEN)) 1571573Srgrimes free(tdata.data); 1581573Srgrimes } 1591573Srgrimes } 1601573Srgrimes 16114287Spst if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS) 1621573Srgrimes return (status); 1631573Srgrimes 16464381Sgreen switch (flags) { 16564381Sgreen case R_IAFTER: 16664381Sgreen nrec++; 16764381Sgreen break; 16864381Sgreen case R_SETCURSOR: 16914287Spst t->bt_cursor.rcursor = nrec; 17064381Sgreen break; 17164381Sgreen } 172189327Sdelphij 17314287Spst F_SET(t, R_MODIFIED); 1741573Srgrimes return (__rec_ret(t, NULL, nrec, key, NULL)); 1751573Srgrimes} 1761573Srgrimes 1771573Srgrimes/* 1781573Srgrimes * __REC_IPUT -- Add a recno item to the tree. 1791573Srgrimes * 1801573Srgrimes * Parameters: 1811573Srgrimes * t: tree 1821573Srgrimes * nrec: record number 1831573Srgrimes * data: data 1841573Srgrimes * 1851573Srgrimes * Returns: 1861573Srgrimes * RET_ERROR, RET_SUCCESS 1871573Srgrimes */ 1881573Srgrimesint 189189291Sdelphij__rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags) 1901573Srgrimes{ 1911573Srgrimes DBT tdata; 1921573Srgrimes EPG *e; 1931573Srgrimes PAGE *h; 194189292Sdelphij indx_t idx, nxtindex; 1951573Srgrimes pgno_t pg; 19614287Spst u_int32_t nbytes; 1971573Srgrimes int dflags, status; 1981573Srgrimes char *dest, db[NOVFLSIZE]; 1991573Srgrimes 2001573Srgrimes /* 2011573Srgrimes * If the data won't fit on a page, store it on indirect pages. 2021573Srgrimes * 2031573Srgrimes * XXX 2041573Srgrimes * If the insert fails later on, these pages aren't recovered. 2051573Srgrimes */ 2061573Srgrimes if (data->size > t->bt_ovflsize) { 2071573Srgrimes if (__ovfl_put(t, data, &pg) == RET_ERROR) 2081573Srgrimes return (RET_ERROR); 2091573Srgrimes tdata.data = db; 2101573Srgrimes tdata.size = NOVFLSIZE; 2111573Srgrimes *(pgno_t *)db = pg; 21214287Spst *(u_int32_t *)(db + sizeof(pgno_t)) = data->size; 2131573Srgrimes dflags = P_BIGDATA; 2141573Srgrimes data = &tdata; 2151573Srgrimes } else 2161573Srgrimes dflags = 0; 2171573Srgrimes 2181573Srgrimes /* __rec_search pins the returned page. */ 2191573Srgrimes if ((e = __rec_search(t, nrec, 2201573Srgrimes nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 2211573Srgrimes SINSERT : SEARCH)) == NULL) 2221573Srgrimes return (RET_ERROR); 2231573Srgrimes 2241573Srgrimes h = e->page; 225189292Sdelphij idx = e->index; 2261573Srgrimes 2271573Srgrimes /* 2281573Srgrimes * Add the specified key/data pair to the tree. The R_IAFTER and 2291573Srgrimes * R_IBEFORE flags insert the key after/before the specified key. 2301573Srgrimes * 2311573Srgrimes * Pages are split as required. 2321573Srgrimes */ 2331573Srgrimes switch (flags) { 2341573Srgrimes case R_IAFTER: 235189292Sdelphij ++idx; 2361573Srgrimes break; 2371573Srgrimes case R_IBEFORE: 2381573Srgrimes break; 2391573Srgrimes default: 2401573Srgrimes if (nrec < t->bt_nrecs && 241189292Sdelphij __rec_dleaf(t, h, idx) == RET_ERROR) { 2421573Srgrimes mpool_put(t->bt_mp, h, 0); 2431573Srgrimes return (RET_ERROR); 2441573Srgrimes } 2451573Srgrimes break; 2461573Srgrimes } 2471573Srgrimes 2481573Srgrimes /* 2491573Srgrimes * If not enough room, split the page. The split code will insert 2501573Srgrimes * the key and data and unpin the current page. If inserting into 2511573Srgrimes * the offset array, shift the pointers up. 2521573Srgrimes */ 2531573Srgrimes nbytes = NRLEAFDBT(data->size); 254190484Sdelphij if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) { 255189292Sdelphij status = __bt_split(t, h, NULL, data, dflags, nbytes, idx); 2561573Srgrimes if (status == RET_SUCCESS) 2571573Srgrimes ++t->bt_nrecs; 2581573Srgrimes return (status); 2591573Srgrimes } 2601573Srgrimes 261189292Sdelphij if (idx < (nxtindex = NEXTINDEX(h))) 262189292Sdelphij memmove(h->linp + idx + 1, h->linp + idx, 263189292Sdelphij (nxtindex - idx) * sizeof(indx_t)); 2641573Srgrimes h->lower += sizeof(indx_t); 2651573Srgrimes 266189292Sdelphij h->linp[idx] = h->upper -= nbytes; 2671573Srgrimes dest = (char *)h + h->upper; 2681573Srgrimes WR_RLEAF(dest, data, dflags); 2691573Srgrimes 2701573Srgrimes ++t->bt_nrecs; 27114287Spst F_SET(t, B_MODIFIED); 2721573Srgrimes mpool_put(t->bt_mp, h, MPOOL_DIRTY); 2731573Srgrimes 2741573Srgrimes return (RET_SUCCESS); 2751573Srgrimes} 276