xref: /csrg-svn/lib/libc/db/recno/rec_put.c (revision 64461)
150995Sbostic /*-
261207Sbostic  * Copyright (c) 1990, 1993
361207Sbostic  *	The Regents of the University of California.  All rights reserved.
450995Sbostic  *
550995Sbostic  * %sccs.include.redist.c%
650995Sbostic  */
750995Sbostic 
850995Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*64461Sbostic static char sccsid[] = "@(#)rec_put.c	8.2 (Berkeley) 09/07/93";
1050995Sbostic #endif /* LIBC_SCCS and not lint */
1150995Sbostic 
1250995Sbostic #include <sys/types.h>
1356758Sbostic 
1450995Sbostic #include <errno.h>
1550995Sbostic #include <stdio.h>
1650995Sbostic #include <stdlib.h>
1750995Sbostic #include <string.h>
1856758Sbostic 
1957933Sbostic #include <db.h>
2051089Sbostic #include "recno.h"
2150995Sbostic 
2250995Sbostic /*
2350995Sbostic  * __REC_PUT -- Add a recno item to the tree.
2450995Sbostic  *
2550995Sbostic  * Parameters:
2650995Sbostic  *	dbp:	pointer to access method
2750995Sbostic  *	key:	key
2850995Sbostic  *	data:	data
2959865Sbostic  *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
3050995Sbostic  *
3150995Sbostic  * Returns:
3259865Sbostic  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
3359865Sbostic  *	already in the tree and R_NOOVERWRITE specified.
3450995Sbostic  */
3550995Sbostic int
3650995Sbostic __rec_put(dbp, key, data, flags)
3750995Sbostic 	const DB *dbp;
3856758Sbostic 	DBT *key;
3956758Sbostic 	const DBT *data;
4050995Sbostic 	u_int flags;
4150995Sbostic {
4250995Sbostic 	BTREE *t;
4350995Sbostic 	DBT tdata;
4450995Sbostic 	recno_t nrec;
4550995Sbostic 	int status;
4650995Sbostic 
4751089Sbostic 	t = dbp->internal;
4851089Sbostic 
49*64461Sbostic 	/* Toss any page pinned across calls. */
50*64461Sbostic 	if (t->bt_pinned != NULL) {
51*64461Sbostic 		mpool_put(t->bt_mp, t->bt_pinned, 0);
52*64461Sbostic 		t->bt_pinned = NULL;
53*64461Sbostic 	}
54*64461Sbostic 
5551089Sbostic 	switch (flags) {
5651089Sbostic 	case R_CURSOR:
5760053Sbostic 		if (!ISSET(t, B_SEQINIT))
5851089Sbostic 			goto einval;
5951089Sbostic 		nrec = t->bt_rcursor;
6051089Sbostic 		break;
6156758Sbostic 	case R_SETCURSOR:
6256758Sbostic 		if ((nrec = *(recno_t *)key->data) == 0)
6356758Sbostic 			goto einval;
6456758Sbostic 		break;
6554282Sbostic 	case R_IAFTER:
6654282Sbostic 		if ((nrec = *(recno_t *)key->data) == 0) {
6754282Sbostic 			nrec = 1;
6854282Sbostic 			flags = R_IBEFORE;
6954282Sbostic 		}
7054282Sbostic 		break;
7151089Sbostic 	case 0:
7251089Sbostic 	case R_IBEFORE:
7351089Sbostic 		if ((nrec = *(recno_t *)key->data) == 0)
7451089Sbostic 			goto einval;
7551089Sbostic 		break;
7651089Sbostic 	case R_NOOVERWRITE:
7751089Sbostic 		if ((nrec = *(recno_t *)key->data) == 0)
7851089Sbostic 			goto einval;
7951089Sbostic 		if (nrec <= t->bt_nrecs)
8051089Sbostic 			return (RET_SPECIAL);
8151089Sbostic 		break;
8251089Sbostic 	default:
8351089Sbostic einval:		errno = EINVAL;
8450995Sbostic 		return (RET_ERROR);
8550995Sbostic 	}
8650995Sbostic 
8750995Sbostic 	/*
8854282Sbostic 	 * Make sure that records up to and including the put record are
8954282Sbostic 	 * already in the database.  If skipping records, create empty ones.
9050995Sbostic 	 */
9150995Sbostic 	if (nrec > t->bt_nrecs) {
9260053Sbostic 		if (!ISSET(t, R_EOF | R_INMEM) &&
9358750Sbostic 		    t->bt_irec(t, nrec) == RET_ERROR)
9451089Sbostic 			return (RET_ERROR);
9551089Sbostic 		if (nrec > t->bt_nrecs + 1) {
9651089Sbostic 			tdata.data = NULL;
9751089Sbostic 			tdata.size = 0;
9856041Sbostic 			while (nrec > t->bt_nrecs + 1)
9954282Sbostic 				if (__rec_iput(t,
10056041Sbostic 				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
10151089Sbostic 					return (RET_ERROR);
10250995Sbostic 		}
10350995Sbostic 	}
10456758Sbostic 
10556758Sbostic 	if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS)
10656758Sbostic 		return (status);
10756758Sbostic 
10859865Sbostic 	if (flags == R_SETCURSOR)
10956758Sbostic 		t->bt_rcursor = nrec;
11056758Sbostic 
11160053Sbostic 	SET(t, R_MODIFIED);
11256758Sbostic 	return (__rec_ret(t, NULL, nrec, key, NULL));
11350995Sbostic }
11450995Sbostic 
11550995Sbostic /*
11650995Sbostic  * __REC_IPUT -- Add a recno item to the tree.
11750995Sbostic  *
11850995Sbostic  * Parameters:
11950995Sbostic  *	t:	tree
12050995Sbostic  *	nrec:	record number
12150995Sbostic  *	data:	data
12250995Sbostic  *
12350995Sbostic  * Returns:
12451089Sbostic  *	RET_ERROR, RET_SUCCESS
12550995Sbostic  */
12650995Sbostic int
12750995Sbostic __rec_iput(t, nrec, data, flags)
12850995Sbostic 	BTREE *t;
12950995Sbostic 	recno_t nrec;
13050995Sbostic 	const DBT *data;
13150995Sbostic 	u_int flags;
13250995Sbostic {
13350995Sbostic 	DBT tdata;
13450995Sbostic 	EPG *e;
13550995Sbostic 	PAGE *h;
13657988Sbostic 	indx_t index, nxtindex;
13750995Sbostic 	pgno_t pg;
13850995Sbostic 	size_t nbytes;
13951089Sbostic 	int dflags, status;
14050995Sbostic 	char *dest, db[NOVFLSIZE];
14150995Sbostic 
14250995Sbostic 	/*
14350995Sbostic 	 * If the data won't fit on a page, store it on indirect pages.
14450995Sbostic 	 *
14550995Sbostic 	 * XXX
14650995Sbostic 	 * If the insert fails later on, these pages aren't recovered.
14750995Sbostic 	 */
14851089Sbostic 	if (data->size > t->bt_ovflsize) {
14950995Sbostic 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
15050995Sbostic 			return (RET_ERROR);
15150995Sbostic 		tdata.data = db;
15250995Sbostic 		tdata.size = NOVFLSIZE;
15350995Sbostic 		*(pgno_t *)db = pg;
15450995Sbostic 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
15550995Sbostic 		dflags = P_BIGDATA;
15650995Sbostic 		data = &tdata;
15750995Sbostic 	} else
15850995Sbostic 		dflags = 0;
15950995Sbostic 
16050995Sbostic 	/* __rec_search pins the returned page. */
16156041Sbostic 	if ((e = __rec_search(t, nrec,
16256997Sbostic 	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
16356997Sbostic 	    SINSERT : SEARCH)) == NULL)
16450995Sbostic 		return (RET_ERROR);
16550995Sbostic 
16650995Sbostic 	h = e->page;
16750995Sbostic 	index = e->index;
16850995Sbostic 
16950995Sbostic 	/*
17051089Sbostic 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
17151089Sbostic 	 * R_IBEFORE flags insert the key after/before the specified key.
17250995Sbostic 	 *
17350995Sbostic 	 * Pages are split as required.
17450995Sbostic 	 */
17550995Sbostic 	switch (flags) {
17650995Sbostic 	case R_IAFTER:
17750995Sbostic 		++index;
17850995Sbostic 		break;
17950995Sbostic 	case R_IBEFORE:
18050995Sbostic 		break;
18150995Sbostic 	default:
18251089Sbostic 		if (nrec < t->bt_nrecs &&
18351089Sbostic 		    __rec_dleaf(t, h, index) == RET_ERROR) {
18450995Sbostic 			mpool_put(t->bt_mp, h, 0);
18550995Sbostic 			return (RET_ERROR);
18650995Sbostic 		}
18750995Sbostic 		break;
18850995Sbostic 	}
18950995Sbostic 
19050995Sbostic 	/*
19150995Sbostic 	 * If not enough room, split the page.  The split code will insert
19250995Sbostic 	 * the key and data and unpin the current page.  If inserting into
19350995Sbostic 	 * the offset array, shift the pointers up.
19450995Sbostic 	 */
19550995Sbostic 	nbytes = NRLEAFDBT(data->size);
19657988Sbostic 	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
19751089Sbostic 		status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
19851089Sbostic 		if (status == RET_SUCCESS)
19951089Sbostic 			++t->bt_nrecs;
20051089Sbostic 		return (status);
20151089Sbostic 	}
20250995Sbostic 
20350995Sbostic 	if (index < (nxtindex = NEXTINDEX(h)))
20458015Sbostic 		memmove(h->linp + index + 1, h->linp + index,
20557988Sbostic 		    (nxtindex - index) * sizeof(indx_t));
20657988Sbostic 	h->lower += sizeof(indx_t);
20750995Sbostic 
20850995Sbostic 	h->linp[index] = h->upper -= nbytes;
20950995Sbostic 	dest = (char *)h + h->upper;
21050995Sbostic 	WR_RLEAF(dest, data, dflags);
21150995Sbostic 
21260053Sbostic 	++t->bt_nrecs;
21360053Sbostic 	SET(t, B_MODIFIED);
21450995Sbostic 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
21560053Sbostic 
21650995Sbostic 	return (RET_SUCCESS);
21750995Sbostic }
218