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