1*e73d0381Schristos /* $NetBSD: rec_put.c,v 1.21 2013/12/14 18:04:56 christos Exp $ */
22c84ad3aScgd
39f0aa214Scgd /*-
4a6d14e36Scgd * Copyright (c) 1990, 1993, 1994
59f0aa214Scgd * The Regents of the University of California. All rights reserved.
69f0aa214Scgd *
79f0aa214Scgd * Redistribution and use in source and binary forms, with or without
89f0aa214Scgd * modification, are permitted provided that the following conditions
99f0aa214Scgd * are met:
109f0aa214Scgd * 1. Redistributions of source code must retain the above copyright
119f0aa214Scgd * notice, this list of conditions and the following disclaimer.
129f0aa214Scgd * 2. Redistributions in binary form must reproduce the above copyright
139f0aa214Scgd * notice, this list of conditions and the following disclaimer in the
149f0aa214Scgd * documentation and/or other materials provided with the distribution.
15eb7c1594Sagc * 3. Neither the name of the University nor the names of its contributors
169f0aa214Scgd * may be used to endorse or promote products derived from this software
179f0aa214Scgd * without specific prior written permission.
189f0aa214Scgd *
199f0aa214Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209f0aa214Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219f0aa214Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229f0aa214Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239f0aa214Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249f0aa214Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259f0aa214Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269f0aa214Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279f0aa214Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289f0aa214Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299f0aa214Scgd * SUCH DAMAGE.
309f0aa214Scgd */
319f0aa214Scgd
32d3595ddfSjoerg #if HAVE_NBTOOL_CONFIG_H
33d3595ddfSjoerg #include "nbtool_config.h"
34d3595ddfSjoerg #endif
35d3595ddfSjoerg
3600ae392dSchristos #include <sys/cdefs.h>
37*e73d0381Schristos __RCSID("$NetBSD: rec_put.c,v 1.21 2013/12/14 18:04:56 christos Exp $");
389f0aa214Scgd
3943fa6fe3Sjtc #include "namespace.h"
409f0aa214Scgd #include <sys/types.h>
419f0aa214Scgd
42cb9daf8fSchristos #include <assert.h>
439f0aa214Scgd #include <errno.h>
449f0aa214Scgd #include <stdio.h>
459f0aa214Scgd #include <stdlib.h>
469f0aa214Scgd #include <string.h>
479f0aa214Scgd
489f0aa214Scgd #include <db.h>
499f0aa214Scgd #include "recno.h"
509f0aa214Scgd
519f0aa214Scgd /*
529f0aa214Scgd * __REC_PUT -- Add a recno item to the tree.
539f0aa214Scgd *
549f0aa214Scgd * Parameters:
559f0aa214Scgd * dbp: pointer to access method
569f0aa214Scgd * key: key
579f0aa214Scgd * data: data
589f0aa214Scgd * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
599f0aa214Scgd *
609f0aa214Scgd * Returns:
619f0aa214Scgd * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
629f0aa214Scgd * already in the tree and R_NOOVERWRITE specified.
639f0aa214Scgd */
649f0aa214Scgd int
__rec_put(const DB * dbp,DBT * key,const DBT * data,u_int flags)65cb9daf8fSchristos __rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
669f0aa214Scgd {
679f0aa214Scgd BTREE *t;
68738330daScgd DBT fdata, tdata;
699f0aa214Scgd recno_t nrec;
709f0aa214Scgd int status;
719f0aa214Scgd
729f0aa214Scgd t = dbp->internal;
739f0aa214Scgd
7445e27c80Scgd /* Toss any page pinned across calls. */
7545e27c80Scgd if (t->bt_pinned != NULL) {
7645e27c80Scgd mpool_put(t->bt_mp, t->bt_pinned, 0);
7745e27c80Scgd t->bt_pinned = NULL;
7845e27c80Scgd }
7945e27c80Scgd
80738330daScgd /*
81738330daScgd * If using fixed-length records, and the record is long, return
82738330daScgd * EINVAL. If it's short, pad it out. Use the record data return
83738330daScgd * memory, it's only short-term.
84738330daScgd */
85738330daScgd if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
86738330daScgd if (data->size > t->bt_reclen)
87738330daScgd goto einval;
88738330daScgd
89738330daScgd if (t->bt_rdata.size < t->bt_reclen) {
90*e73d0381Schristos void *np = realloc(t->bt_rdata.data, t->bt_reclen);
91*e73d0381Schristos if (np == NULL)
92738330daScgd return (RET_ERROR);
93*e73d0381Schristos t->bt_rdata.data = np;
94738330daScgd t->bt_rdata.size = t->bt_reclen;
95738330daScgd }
96738330daScgd memmove(t->bt_rdata.data, data->data, data->size);
97738330daScgd memset((char *)t->bt_rdata.data + data->size,
98738330daScgd t->bt_bval, t->bt_reclen - data->size);
99738330daScgd fdata.data = t->bt_rdata.data;
100738330daScgd fdata.size = t->bt_reclen;
101738330daScgd } else {
102738330daScgd fdata.data = data->data;
103738330daScgd fdata.size = data->size;
104738330daScgd }
105738330daScgd
1069f0aa214Scgd switch (flags) {
1079f0aa214Scgd case R_CURSOR:
108738330daScgd if (!F_ISSET(&t->bt_cursor, CURS_INIT))
1099f0aa214Scgd goto einval;
110738330daScgd nrec = t->bt_cursor.rcursor;
1119f0aa214Scgd break;
1129f0aa214Scgd case R_SETCURSOR:
1139f0aa214Scgd if ((nrec = *(recno_t *)key->data) == 0)
1149f0aa214Scgd goto einval;
1159f0aa214Scgd break;
1169f0aa214Scgd case R_IAFTER:
1179f0aa214Scgd if ((nrec = *(recno_t *)key->data) == 0) {
1189f0aa214Scgd nrec = 1;
1199f0aa214Scgd flags = R_IBEFORE;
1209f0aa214Scgd }
1219f0aa214Scgd break;
1229f0aa214Scgd case 0:
1239f0aa214Scgd case R_IBEFORE:
1249f0aa214Scgd if ((nrec = *(recno_t *)key->data) == 0)
1259f0aa214Scgd goto einval;
1269f0aa214Scgd break;
1279f0aa214Scgd case R_NOOVERWRITE:
1289f0aa214Scgd if ((nrec = *(recno_t *)key->data) == 0)
1299f0aa214Scgd goto einval;
1309f0aa214Scgd if (nrec <= t->bt_nrecs)
1319f0aa214Scgd return (RET_SPECIAL);
1329f0aa214Scgd break;
1339f0aa214Scgd default:
1349f0aa214Scgd einval: errno = EINVAL;
1359f0aa214Scgd return (RET_ERROR);
1369f0aa214Scgd }
1379f0aa214Scgd
1389f0aa214Scgd /*
1399f0aa214Scgd * Make sure that records up to and including the put record are
1409f0aa214Scgd * already in the database. If skipping records, create empty ones.
1419f0aa214Scgd */
1429f0aa214Scgd if (nrec > t->bt_nrecs) {
143738330daScgd if (!F_ISSET(t, R_EOF | R_INMEM) &&
1449f0aa214Scgd t->bt_irec(t, nrec) == RET_ERROR)
1459f0aa214Scgd return (RET_ERROR);
1469f0aa214Scgd if (nrec > t->bt_nrecs + 1) {
147738330daScgd if (F_ISSET(t, R_FIXLEN)) {
148b605a13bSchristos if ((tdata.data = malloc(t->bt_reclen)) == NULL)
149bc3e04dbScgd return (RET_ERROR);
150bc3e04dbScgd tdata.size = t->bt_reclen;
151bc3e04dbScgd memset(tdata.data, t->bt_bval, tdata.size);
152bc3e04dbScgd } else {
1539f0aa214Scgd tdata.data = NULL;
1549f0aa214Scgd tdata.size = 0;
155bc3e04dbScgd }
1569f0aa214Scgd while (nrec > t->bt_nrecs + 1)
1579f0aa214Scgd if (__rec_iput(t,
1589f0aa214Scgd t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
1599f0aa214Scgd return (RET_ERROR);
160738330daScgd if (F_ISSET(t, R_FIXLEN))
161bc3e04dbScgd free(tdata.data);
1629f0aa214Scgd }
1639f0aa214Scgd }
1649f0aa214Scgd
165738330daScgd if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
1669f0aa214Scgd return (status);
1679f0aa214Scgd
1685589fc5eSchristos switch (flags) {
1695589fc5eSchristos case R_IAFTER:
1705589fc5eSchristos nrec++;
1715589fc5eSchristos break;
1725589fc5eSchristos case R_SETCURSOR:
173738330daScgd t->bt_cursor.rcursor = nrec;
1745589fc5eSchristos break;
1755589fc5eSchristos }
1769f0aa214Scgd
177738330daScgd F_SET(t, R_MODIFIED);
1789f0aa214Scgd return (__rec_ret(t, NULL, nrec, key, NULL));
1799f0aa214Scgd }
1809f0aa214Scgd
1819f0aa214Scgd /*
1829f0aa214Scgd * __REC_IPUT -- Add a recno item to the tree.
1839f0aa214Scgd *
1849f0aa214Scgd * Parameters:
1859f0aa214Scgd * t: tree
1869f0aa214Scgd * nrec: record number
1879f0aa214Scgd * data: data
1889f0aa214Scgd *
1899f0aa214Scgd * Returns:
1909f0aa214Scgd * RET_ERROR, RET_SUCCESS
1919f0aa214Scgd */
1929f0aa214Scgd int
__rec_iput(BTREE * t,recno_t nrec,const DBT * data,u_int flags)193cb9daf8fSchristos __rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
1949f0aa214Scgd {
1959f0aa214Scgd DBT tdata;
1969f0aa214Scgd EPG *e;
1979f0aa214Scgd PAGE *h;
19861238e71Schristos indx_t idx, nxtindex;
1999f0aa214Scgd pgno_t pg;
20040b37a3bSjoerg uint32_t nbytes;
2019f0aa214Scgd int dflags, status;
2029f0aa214Scgd char *dest, db[NOVFLSIZE];
2039f0aa214Scgd
2049f0aa214Scgd /*
2059f0aa214Scgd * If the data won't fit on a page, store it on indirect pages.
2069f0aa214Scgd *
2079f0aa214Scgd * XXX
2089f0aa214Scgd * If the insert fails later on, these pages aren't recovered.
2099f0aa214Scgd */
2109f0aa214Scgd if (data->size > t->bt_ovflsize) {
2119f0aa214Scgd if (__ovfl_put(t, data, &pg) == RET_ERROR)
2129f0aa214Scgd return (RET_ERROR);
2139f0aa214Scgd tdata.data = db;
2149f0aa214Scgd tdata.size = NOVFLSIZE;
2155589fc5eSchristos memcpy(db, &pg, sizeof(pg));
21640b37a3bSjoerg _DBFIT(data->size, uint32_t);
21740b37a3bSjoerg *(uint32_t *)(void *)(db + sizeof(pgno_t)) =
21840b37a3bSjoerg (uint32_t)data->size;
2199f0aa214Scgd dflags = P_BIGDATA;
2209f0aa214Scgd data = &tdata;
2219f0aa214Scgd } else
2229f0aa214Scgd dflags = 0;
2239f0aa214Scgd
2249f0aa214Scgd /* __rec_search pins the returned page. */
2259f0aa214Scgd if ((e = __rec_search(t, nrec,
2269f0aa214Scgd nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
2279f0aa214Scgd SINSERT : SEARCH)) == NULL)
2289f0aa214Scgd return (RET_ERROR);
2299f0aa214Scgd
2309f0aa214Scgd h = e->page;
23161238e71Schristos idx = e->index;
2329f0aa214Scgd
2339f0aa214Scgd /*
2349f0aa214Scgd * Add the specified key/data pair to the tree. The R_IAFTER and
2359f0aa214Scgd * R_IBEFORE flags insert the key after/before the specified key.
2369f0aa214Scgd *
2379f0aa214Scgd * Pages are split as required.
2389f0aa214Scgd */
2399f0aa214Scgd switch (flags) {
2409f0aa214Scgd case R_IAFTER:
24161238e71Schristos ++idx;
2429f0aa214Scgd break;
2439f0aa214Scgd case R_IBEFORE:
2449f0aa214Scgd break;
2459f0aa214Scgd default:
2469f0aa214Scgd if (nrec < t->bt_nrecs &&
24740b37a3bSjoerg __rec_dleaf(t, h, (uint32_t)idx) == RET_ERROR) {
2489f0aa214Scgd mpool_put(t->bt_mp, h, 0);
2499f0aa214Scgd return (RET_ERROR);
2509f0aa214Scgd }
2519f0aa214Scgd break;
2529f0aa214Scgd }
2539f0aa214Scgd
2549f0aa214Scgd /*
2559f0aa214Scgd * If not enough room, split the page. The split code will insert
2569f0aa214Scgd * the key and data and unpin the current page. If inserting into
2579f0aa214Scgd * the offset array, shift the pointers up.
2589f0aa214Scgd */
2599f0aa214Scgd nbytes = NRLEAFDBT(data->size);
26040b37a3bSjoerg if ((uint32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) {
26161238e71Schristos status = __bt_split(t, h, NULL, data, dflags, nbytes,
26240b37a3bSjoerg (uint32_t)idx);
2639f0aa214Scgd if (status == RET_SUCCESS)
2649f0aa214Scgd ++t->bt_nrecs;
2659f0aa214Scgd return (status);
2669f0aa214Scgd }
2679f0aa214Scgd
26861238e71Schristos if (idx < (nxtindex = NEXTINDEX(h)))
26961238e71Schristos memmove(h->linp + idx + 1, h->linp + idx,
27061238e71Schristos (nxtindex - idx) * sizeof(indx_t));
2719f0aa214Scgd h->lower += sizeof(indx_t);
2729f0aa214Scgd
27361238e71Schristos h->linp[idx] = h->upper -= nbytes;
27461238e71Schristos dest = (char *)(void *)h + h->upper;
2759f0aa214Scgd WR_RLEAF(dest, data, dflags);
2769f0aa214Scgd
2779f0aa214Scgd ++t->bt_nrecs;
278738330daScgd F_SET(t, B_MODIFIED);
2799f0aa214Scgd mpool_put(t->bt_mp, h, MPOOL_DIRTY);
2809f0aa214Scgd
2819f0aa214Scgd return (RET_SUCCESS);
2829f0aa214Scgd }
283