1*0a6a1f1dSLionel Sambuc /* $NetBSD: rec_put.c,v 1.21 2013/12/14 18:04:56 christos Exp $ */
22639ae9bSBen Gras
32639ae9bSBen Gras /*-
42639ae9bSBen Gras * Copyright (c) 1990, 1993, 1994
52639ae9bSBen Gras * The Regents of the University of California. All rights reserved.
62639ae9bSBen Gras *
72639ae9bSBen Gras * Redistribution and use in source and binary forms, with or without
82639ae9bSBen Gras * modification, are permitted provided that the following conditions
92639ae9bSBen Gras * are met:
102639ae9bSBen Gras * 1. Redistributions of source code must retain the above copyright
112639ae9bSBen Gras * notice, this list of conditions and the following disclaimer.
122639ae9bSBen Gras * 2. Redistributions in binary form must reproduce the above copyright
132639ae9bSBen Gras * notice, this list of conditions and the following disclaimer in the
142639ae9bSBen Gras * documentation and/or other materials provided with the distribution.
152639ae9bSBen Gras * 3. Neither the name of the University nor the names of its contributors
162639ae9bSBen Gras * may be used to endorse or promote products derived from this software
172639ae9bSBen Gras * without specific prior written permission.
182639ae9bSBen Gras *
192639ae9bSBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
202639ae9bSBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212639ae9bSBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222639ae9bSBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
232639ae9bSBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
242639ae9bSBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
252639ae9bSBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
262639ae9bSBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272639ae9bSBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
282639ae9bSBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
292639ae9bSBen Gras * SUCH DAMAGE.
302639ae9bSBen Gras */
312639ae9bSBen Gras
322639ae9bSBen Gras #if HAVE_NBTOOL_CONFIG_H
332639ae9bSBen Gras #include "nbtool_config.h"
342639ae9bSBen Gras #endif
352639ae9bSBen Gras
362639ae9bSBen Gras #include <sys/cdefs.h>
37*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: rec_put.c,v 1.21 2013/12/14 18:04:56 christos Exp $");
382639ae9bSBen Gras
392639ae9bSBen Gras #include "namespace.h"
402639ae9bSBen Gras #include <sys/types.h>
412639ae9bSBen Gras
422639ae9bSBen Gras #include <assert.h>
432639ae9bSBen Gras #include <errno.h>
442639ae9bSBen Gras #include <stdio.h>
452639ae9bSBen Gras #include <stdlib.h>
462639ae9bSBen Gras #include <string.h>
472639ae9bSBen Gras
482639ae9bSBen Gras #include <db.h>
492639ae9bSBen Gras #include "recno.h"
502639ae9bSBen Gras
512639ae9bSBen Gras /*
522639ae9bSBen Gras * __REC_PUT -- Add a recno item to the tree.
532639ae9bSBen Gras *
542639ae9bSBen Gras * Parameters:
552639ae9bSBen Gras * dbp: pointer to access method
562639ae9bSBen Gras * key: key
572639ae9bSBen Gras * data: data
582639ae9bSBen Gras * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
592639ae9bSBen Gras *
602639ae9bSBen Gras * Returns:
612639ae9bSBen Gras * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
622639ae9bSBen Gras * already in the tree and R_NOOVERWRITE specified.
632639ae9bSBen Gras */
642639ae9bSBen Gras int
__rec_put(const DB * dbp,DBT * key,const DBT * data,u_int flags)652639ae9bSBen Gras __rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
662639ae9bSBen Gras {
672639ae9bSBen Gras BTREE *t;
682639ae9bSBen Gras DBT fdata, tdata;
692639ae9bSBen Gras recno_t nrec;
702639ae9bSBen Gras int status;
712639ae9bSBen Gras
722639ae9bSBen Gras t = dbp->internal;
732639ae9bSBen Gras
742639ae9bSBen Gras /* Toss any page pinned across calls. */
752639ae9bSBen Gras if (t->bt_pinned != NULL) {
762639ae9bSBen Gras mpool_put(t->bt_mp, t->bt_pinned, 0);
772639ae9bSBen Gras t->bt_pinned = NULL;
782639ae9bSBen Gras }
792639ae9bSBen Gras
802639ae9bSBen Gras /*
812639ae9bSBen Gras * If using fixed-length records, and the record is long, return
822639ae9bSBen Gras * EINVAL. If it's short, pad it out. Use the record data return
832639ae9bSBen Gras * memory, it's only short-term.
842639ae9bSBen Gras */
852639ae9bSBen Gras if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
862639ae9bSBen Gras if (data->size > t->bt_reclen)
872639ae9bSBen Gras goto einval;
882639ae9bSBen Gras
892639ae9bSBen Gras if (t->bt_rdata.size < t->bt_reclen) {
90*0a6a1f1dSLionel Sambuc void *np = realloc(t->bt_rdata.data, t->bt_reclen);
91*0a6a1f1dSLionel Sambuc if (np == NULL)
922639ae9bSBen Gras return (RET_ERROR);
93*0a6a1f1dSLionel Sambuc t->bt_rdata.data = np;
942639ae9bSBen Gras t->bt_rdata.size = t->bt_reclen;
952639ae9bSBen Gras }
962639ae9bSBen Gras memmove(t->bt_rdata.data, data->data, data->size);
972639ae9bSBen Gras memset((char *)t->bt_rdata.data + data->size,
982639ae9bSBen Gras t->bt_bval, t->bt_reclen - data->size);
992639ae9bSBen Gras fdata.data = t->bt_rdata.data;
1002639ae9bSBen Gras fdata.size = t->bt_reclen;
1012639ae9bSBen Gras } else {
1022639ae9bSBen Gras fdata.data = data->data;
1032639ae9bSBen Gras fdata.size = data->size;
1042639ae9bSBen Gras }
1052639ae9bSBen Gras
1062639ae9bSBen Gras switch (flags) {
1072639ae9bSBen Gras case R_CURSOR:
1082639ae9bSBen Gras if (!F_ISSET(&t->bt_cursor, CURS_INIT))
1092639ae9bSBen Gras goto einval;
1102639ae9bSBen Gras nrec = t->bt_cursor.rcursor;
1112639ae9bSBen Gras break;
1122639ae9bSBen Gras case R_SETCURSOR:
1132639ae9bSBen Gras if ((nrec = *(recno_t *)key->data) == 0)
1142639ae9bSBen Gras goto einval;
1152639ae9bSBen Gras break;
1162639ae9bSBen Gras case R_IAFTER:
1172639ae9bSBen Gras if ((nrec = *(recno_t *)key->data) == 0) {
1182639ae9bSBen Gras nrec = 1;
1192639ae9bSBen Gras flags = R_IBEFORE;
1202639ae9bSBen Gras }
1212639ae9bSBen Gras break;
1222639ae9bSBen Gras case 0:
1232639ae9bSBen Gras case R_IBEFORE:
1242639ae9bSBen Gras if ((nrec = *(recno_t *)key->data) == 0)
1252639ae9bSBen Gras goto einval;
1262639ae9bSBen Gras break;
1272639ae9bSBen Gras case R_NOOVERWRITE:
1282639ae9bSBen Gras if ((nrec = *(recno_t *)key->data) == 0)
1292639ae9bSBen Gras goto einval;
1302639ae9bSBen Gras if (nrec <= t->bt_nrecs)
1312639ae9bSBen Gras return (RET_SPECIAL);
1322639ae9bSBen Gras break;
1332639ae9bSBen Gras default:
1342639ae9bSBen Gras einval: errno = EINVAL;
1352639ae9bSBen Gras return (RET_ERROR);
1362639ae9bSBen Gras }
1372639ae9bSBen Gras
1382639ae9bSBen Gras /*
1392639ae9bSBen Gras * Make sure that records up to and including the put record are
1402639ae9bSBen Gras * already in the database. If skipping records, create empty ones.
1412639ae9bSBen Gras */
1422639ae9bSBen Gras if (nrec > t->bt_nrecs) {
1432639ae9bSBen Gras if (!F_ISSET(t, R_EOF | R_INMEM) &&
1442639ae9bSBen Gras t->bt_irec(t, nrec) == RET_ERROR)
1452639ae9bSBen Gras return (RET_ERROR);
1462639ae9bSBen Gras if (nrec > t->bt_nrecs + 1) {
1472639ae9bSBen Gras if (F_ISSET(t, R_FIXLEN)) {
14884d9c625SLionel Sambuc if ((tdata.data = malloc(t->bt_reclen)) == NULL)
1492639ae9bSBen Gras return (RET_ERROR);
1502639ae9bSBen Gras tdata.size = t->bt_reclen;
1512639ae9bSBen Gras memset(tdata.data, t->bt_bval, tdata.size);
1522639ae9bSBen Gras } else {
1532639ae9bSBen Gras tdata.data = NULL;
1542639ae9bSBen Gras tdata.size = 0;
1552639ae9bSBen Gras }
1562639ae9bSBen Gras while (nrec > t->bt_nrecs + 1)
1572639ae9bSBen Gras if (__rec_iput(t,
1582639ae9bSBen Gras t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
1592639ae9bSBen Gras return (RET_ERROR);
1602639ae9bSBen Gras if (F_ISSET(t, R_FIXLEN))
1612639ae9bSBen Gras free(tdata.data);
1622639ae9bSBen Gras }
1632639ae9bSBen Gras }
1642639ae9bSBen Gras
1652639ae9bSBen Gras if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
1662639ae9bSBen Gras return (status);
1672639ae9bSBen Gras
168f14fb602SLionel Sambuc switch (flags) {
169f14fb602SLionel Sambuc case R_IAFTER:
170f14fb602SLionel Sambuc nrec++;
171f14fb602SLionel Sambuc break;
172f14fb602SLionel Sambuc case R_SETCURSOR:
1732639ae9bSBen Gras t->bt_cursor.rcursor = nrec;
174f14fb602SLionel Sambuc break;
175f14fb602SLionel Sambuc }
1762639ae9bSBen Gras
1772639ae9bSBen Gras F_SET(t, R_MODIFIED);
1782639ae9bSBen Gras return (__rec_ret(t, NULL, nrec, key, NULL));
1792639ae9bSBen Gras }
1802639ae9bSBen Gras
1812639ae9bSBen Gras /*
1822639ae9bSBen Gras * __REC_IPUT -- Add a recno item to the tree.
1832639ae9bSBen Gras *
1842639ae9bSBen Gras * Parameters:
1852639ae9bSBen Gras * t: tree
1862639ae9bSBen Gras * nrec: record number
1872639ae9bSBen Gras * data: data
1882639ae9bSBen Gras *
1892639ae9bSBen Gras * Returns:
1902639ae9bSBen Gras * RET_ERROR, RET_SUCCESS
1912639ae9bSBen Gras */
1922639ae9bSBen Gras int
__rec_iput(BTREE * t,recno_t nrec,const DBT * data,u_int flags)1932639ae9bSBen Gras __rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
1942639ae9bSBen Gras {
1952639ae9bSBen Gras DBT tdata;
1962639ae9bSBen Gras EPG *e;
1972639ae9bSBen Gras PAGE *h;
1982639ae9bSBen Gras indx_t idx, nxtindex;
1992639ae9bSBen Gras pgno_t pg;
2002639ae9bSBen Gras uint32_t nbytes;
2012639ae9bSBen Gras int dflags, status;
2022639ae9bSBen Gras char *dest, db[NOVFLSIZE];
2032639ae9bSBen Gras
2042639ae9bSBen Gras /*
2052639ae9bSBen Gras * If the data won't fit on a page, store it on indirect pages.
2062639ae9bSBen Gras *
2072639ae9bSBen Gras * XXX
2082639ae9bSBen Gras * If the insert fails later on, these pages aren't recovered.
2092639ae9bSBen Gras */
2102639ae9bSBen Gras if (data->size > t->bt_ovflsize) {
2112639ae9bSBen Gras if (__ovfl_put(t, data, &pg) == RET_ERROR)
2122639ae9bSBen Gras return (RET_ERROR);
2132639ae9bSBen Gras tdata.data = db;
2142639ae9bSBen Gras tdata.size = NOVFLSIZE;
215f14fb602SLionel Sambuc memcpy(db, &pg, sizeof(pg));
2162639ae9bSBen Gras _DBFIT(data->size, uint32_t);
2172639ae9bSBen Gras *(uint32_t *)(void *)(db + sizeof(pgno_t)) =
2182639ae9bSBen Gras (uint32_t)data->size;
2192639ae9bSBen Gras dflags = P_BIGDATA;
2202639ae9bSBen Gras data = &tdata;
2212639ae9bSBen Gras } else
2222639ae9bSBen Gras dflags = 0;
2232639ae9bSBen Gras
2242639ae9bSBen Gras /* __rec_search pins the returned page. */
2252639ae9bSBen Gras if ((e = __rec_search(t, nrec,
2262639ae9bSBen Gras nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
2272639ae9bSBen Gras SINSERT : SEARCH)) == NULL)
2282639ae9bSBen Gras return (RET_ERROR);
2292639ae9bSBen Gras
2302639ae9bSBen Gras h = e->page;
2312639ae9bSBen Gras idx = e->index;
2322639ae9bSBen Gras
2332639ae9bSBen Gras /*
2342639ae9bSBen Gras * Add the specified key/data pair to the tree. The R_IAFTER and
2352639ae9bSBen Gras * R_IBEFORE flags insert the key after/before the specified key.
2362639ae9bSBen Gras *
2372639ae9bSBen Gras * Pages are split as required.
2382639ae9bSBen Gras */
2392639ae9bSBen Gras switch (flags) {
2402639ae9bSBen Gras case R_IAFTER:
2412639ae9bSBen Gras ++idx;
2422639ae9bSBen Gras break;
2432639ae9bSBen Gras case R_IBEFORE:
2442639ae9bSBen Gras break;
2452639ae9bSBen Gras default:
2462639ae9bSBen Gras if (nrec < t->bt_nrecs &&
2472639ae9bSBen Gras __rec_dleaf(t, h, (uint32_t)idx) == RET_ERROR) {
2482639ae9bSBen Gras mpool_put(t->bt_mp, h, 0);
2492639ae9bSBen Gras return (RET_ERROR);
2502639ae9bSBen Gras }
2512639ae9bSBen Gras break;
2522639ae9bSBen Gras }
2532639ae9bSBen Gras
2542639ae9bSBen Gras /*
2552639ae9bSBen Gras * If not enough room, split the page. The split code will insert
2562639ae9bSBen Gras * the key and data and unpin the current page. If inserting into
2572639ae9bSBen Gras * the offset array, shift the pointers up.
2582639ae9bSBen Gras */
2592639ae9bSBen Gras nbytes = NRLEAFDBT(data->size);
2602639ae9bSBen Gras if ((uint32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) {
2612639ae9bSBen Gras status = __bt_split(t, h, NULL, data, dflags, nbytes,
2622639ae9bSBen Gras (uint32_t)idx);
2632639ae9bSBen Gras if (status == RET_SUCCESS)
2642639ae9bSBen Gras ++t->bt_nrecs;
2652639ae9bSBen Gras return (status);
2662639ae9bSBen Gras }
2672639ae9bSBen Gras
2682639ae9bSBen Gras if (idx < (nxtindex = NEXTINDEX(h)))
2692639ae9bSBen Gras memmove(h->linp + idx + 1, h->linp + idx,
2702639ae9bSBen Gras (nxtindex - idx) * sizeof(indx_t));
2712639ae9bSBen Gras h->lower += sizeof(indx_t);
2722639ae9bSBen Gras
2732639ae9bSBen Gras h->linp[idx] = h->upper -= nbytes;
2742639ae9bSBen Gras dest = (char *)(void *)h + h->upper;
2752639ae9bSBen Gras WR_RLEAF(dest, data, dflags);
2762639ae9bSBen Gras
2772639ae9bSBen Gras ++t->bt_nrecs;
2782639ae9bSBen Gras F_SET(t, B_MODIFIED);
2792639ae9bSBen Gras mpool_put(t->bt_mp, h, MPOOL_DIRTY);
2802639ae9bSBen Gras
2812639ae9bSBen Gras return (RET_SUCCESS);
2822639ae9bSBen Gras }
283