xref: /csrg-svn/lib/libc/db/recno/rec_put.c (revision 51089)
150995Sbostic /*-
250995Sbostic  * Copyright (c) 1990 The Regents of the University of California.
350995Sbostic  * All rights reserved.
450995Sbostic  *
550995Sbostic  * %sccs.include.redist.c%
650995Sbostic  */
750995Sbostic 
850995Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*51089Sbostic static char sccsid[] = "@(#)rec_put.c	5.2 (Berkeley) 09/11/91";
1050995Sbostic #endif /* LIBC_SCCS and not lint */
1150995Sbostic 
1250995Sbostic #include <sys/types.h>
1350995Sbostic #include <errno.h>
1450995Sbostic #include <db.h>
1550995Sbostic #include <stdio.h>
1650995Sbostic #include <stdlib.h>
1750995Sbostic #include <string.h>
18*51089Sbostic #include "recno.h"
1950995Sbostic 
2050995Sbostic /*
2150995Sbostic  * __REC_PUT -- Add a recno item to the tree.
2250995Sbostic  *
2350995Sbostic  * Parameters:
2450995Sbostic  *	dbp:	pointer to access method
2550995Sbostic  *	key:	key
2650995Sbostic  *	data:	data
27*51089Sbostic  *	flag:	R_APPEND, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
2850995Sbostic  *
2950995Sbostic  * Returns:
3050995Sbostic  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
3150995Sbostic  *	tree and R_NOOVERWRITE specified.
3250995Sbostic  */
3350995Sbostic int
3450995Sbostic __rec_put(dbp, key, data, flags)
3550995Sbostic 	const DB *dbp;
3650995Sbostic 	const DBT *key, *data;
3750995Sbostic 	u_int flags;
3850995Sbostic {
3950995Sbostic 	BTREE *t;
4050995Sbostic 	DBT tdata;
4150995Sbostic 	recno_t nrec;
4250995Sbostic 	int status;
4350995Sbostic 
44*51089Sbostic 	t = dbp->internal;
45*51089Sbostic 
46*51089Sbostic 	switch (flags) {
47*51089Sbostic 	case R_APPEND:
48*51089Sbostic 		nrec = t->bt_nrecs + 1;
49*51089Sbostic 		break;
50*51089Sbostic 	case R_CURSOR:
51*51089Sbostic 		if (ISSET(t, BTF_DELCRSR))
52*51089Sbostic 			goto einval;
53*51089Sbostic 		nrec = t->bt_rcursor;
54*51089Sbostic 		break;
55*51089Sbostic 	case 0:
56*51089Sbostic 	case R_IAFTER:
57*51089Sbostic 	case R_IBEFORE:
58*51089Sbostic 		if ((nrec = *(recno_t *)key->data) == 0)
59*51089Sbostic 			goto einval;
60*51089Sbostic 		break;
61*51089Sbostic 	case R_NOOVERWRITE:
62*51089Sbostic 		if ((nrec = *(recno_t *)key->data) == 0)
63*51089Sbostic 			goto einval;
64*51089Sbostic 		if (nrec <= t->bt_nrecs)
65*51089Sbostic 			return (RET_SPECIAL);
66*51089Sbostic 		break;
67*51089Sbostic 	default:
68*51089Sbostic einval:		errno = EINVAL;
6950995Sbostic 		return (RET_ERROR);
7050995Sbostic 	}
7150995Sbostic 
7250995Sbostic 	/*
73*51089Sbostic 	 * Make sure that records up to and including the put record are already
74*51089Sbostic  	 * in the database.  If skipping records, create empty ones.
7550995Sbostic 	 */
7650995Sbostic 	if (nrec > t->bt_nrecs) {
77*51089Sbostic 		if (t->bt_irec(t, nrec) == RET_ERROR)
78*51089Sbostic 			return (RET_ERROR);
79*51089Sbostic 		if (nrec > t->bt_nrecs + 1) {
80*51089Sbostic 			tdata.data = NULL;
81*51089Sbostic 			tdata.size = 0;
82*51089Sbostic 			while (nrec > t->bt_nrecs)
83*51089Sbostic 				if (__rec_iput(t, nrec, &tdata, 0)
84*51089Sbostic 				    != RET_SUCCESS)
85*51089Sbostic 					return (RET_ERROR);
8650995Sbostic 		}
8750995Sbostic 	}
8850995Sbostic 	--nrec;
8950995Sbostic 	if ((status = __rec_iput(t, nrec, data, flags)) == RET_SUCCESS)
9050995Sbostic 		SET(t, BTF_MODIFIED);
9150995Sbostic 	return (status);
9250995Sbostic }
9350995Sbostic 
9450995Sbostic /*
9550995Sbostic  * __REC_IPUT -- Add a recno item to the tree.
9650995Sbostic  *
9750995Sbostic  * Parameters:
9850995Sbostic  *	t:	tree
9950995Sbostic  *	nrec:	record number
10050995Sbostic  *	data:	data
10150995Sbostic  *
10250995Sbostic  * Returns:
103*51089Sbostic  *	RET_ERROR, RET_SUCCESS
10450995Sbostic  */
10550995Sbostic int
10650995Sbostic __rec_iput(t, nrec, data, flags)
10750995Sbostic 	BTREE *t;
10850995Sbostic 	recno_t nrec;
10950995Sbostic 	const DBT *data;
11050995Sbostic 	u_int flags;
11150995Sbostic {
11250995Sbostic 	DBT tdata;
11350995Sbostic 	EPG *e;
11450995Sbostic 	PAGE *h;
11550995Sbostic 	index_t index, nxtindex;
11650995Sbostic 	pgno_t pg;
11750995Sbostic 	size_t nbytes;
118*51089Sbostic 	int dflags, status;
11950995Sbostic 	char *dest, db[NOVFLSIZE];
12050995Sbostic 
12150995Sbostic 	/*
12250995Sbostic 	 * If the data won't fit on a page, store it on indirect pages.
12350995Sbostic 	 *
12450995Sbostic 	 * XXX
12550995Sbostic 	 * If the insert fails later on, these pages aren't recovered.
12650995Sbostic 	 */
127*51089Sbostic 	if (data->size > t->bt_ovflsize) {
12850995Sbostic 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
12950995Sbostic 			return (RET_ERROR);
13050995Sbostic 		tdata.data = db;
13150995Sbostic 		tdata.size = NOVFLSIZE;
13250995Sbostic 		*(pgno_t *)db = pg;
13350995Sbostic 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
13450995Sbostic 		dflags = P_BIGDATA;
13550995Sbostic 		data = &tdata;
13650995Sbostic 	} else
13750995Sbostic 		dflags = 0;
13850995Sbostic 
13950995Sbostic 	/* __rec_search pins the returned page. */
140*51089Sbostic 	if ((e = __rec_search(t, nrec, SINSERT)) == NULL)
14150995Sbostic 		return (RET_ERROR);
14250995Sbostic 
14350995Sbostic 	h = e->page;
14450995Sbostic 	index = e->index;
14550995Sbostic 
14650995Sbostic 	/*
147*51089Sbostic 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
148*51089Sbostic 	 * R_IBEFORE flags insert the key after/before the specified key.
14950995Sbostic 	 *
15050995Sbostic 	 * Pages are split as required.
15150995Sbostic 	 */
15250995Sbostic 	switch (flags) {
15350995Sbostic 	case R_IAFTER:
15450995Sbostic 		++index;
15550995Sbostic 		break;
15650995Sbostic 	case R_IBEFORE:
15750995Sbostic 		break;
15850995Sbostic 	default:
159*51089Sbostic 		if (nrec < t->bt_nrecs &&
160*51089Sbostic 		    __rec_dleaf(t, h, index) == RET_ERROR) {
161*51089Sbostic 			BT_CLR(t);
16250995Sbostic 			mpool_put(t->bt_mp, h, 0);
16350995Sbostic 			return (RET_ERROR);
16450995Sbostic 		}
16550995Sbostic 		break;
16650995Sbostic 	}
16750995Sbostic 
16850995Sbostic 	/*
16950995Sbostic 	 * If not enough room, split the page.  The split code will insert
17050995Sbostic 	 * the key and data and unpin the current page.  If inserting into
17150995Sbostic 	 * the offset array, shift the pointers up.
17250995Sbostic 	 */
17350995Sbostic 	nbytes = NRLEAFDBT(data->size);
174*51089Sbostic 	if (h->upper - h->lower < nbytes + sizeof(index_t)) {
175*51089Sbostic 		status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
176*51089Sbostic 		if (status == RET_SUCCESS)
177*51089Sbostic 			++t->bt_nrecs;
178*51089Sbostic 		return (status);
179*51089Sbostic 	}
18050995Sbostic 
18150995Sbostic 	if (index < (nxtindex = NEXTINDEX(h)))
18250995Sbostic 		bcopy(h->linp + index, h->linp + index + 1,
18350995Sbostic 		    (nxtindex - index) * sizeof(index_t));
18450995Sbostic 	h->lower += sizeof(index_t);
18550995Sbostic 
18650995Sbostic 	h->linp[index] = h->upper -= nbytes;
18750995Sbostic 	dest = (char *)h + h->upper;
18850995Sbostic 	WR_RLEAF(dest, data, dflags);
18950995Sbostic 
19050995Sbostic 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
19150995Sbostic 	++t->bt_nrecs;
19250995Sbostic 	return (RET_SUCCESS);
19350995Sbostic }
194