xref: /netbsd-src/lib/libc/db/recno/rec_put.c (revision e73d0381b5765ef6ac3833e140dc1fc952a43832)
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