xref: /csrg-svn/lib/libc/db/recno/rec_put.c (revision 50995)
1*50995Sbostic /*-
2*50995Sbostic  * Copyright (c) 1990 The Regents of the University of California.
3*50995Sbostic  * All rights reserved.
4*50995Sbostic  *
5*50995Sbostic  * %sccs.include.redist.c%
6*50995Sbostic  */
7*50995Sbostic 
8*50995Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*50995Sbostic static char sccsid[] = "@(#)rec_put.c	5.1 (Berkeley) 09/04/91";
10*50995Sbostic #endif /* LIBC_SCCS and not lint */
11*50995Sbostic 
12*50995Sbostic #include <sys/types.h>
13*50995Sbostic #include <errno.h>
14*50995Sbostic #include <db.h>
15*50995Sbostic #include <stdio.h>
16*50995Sbostic #include <stdlib.h>
17*50995Sbostic #include <string.h>
18*50995Sbostic #include "../btree/btree.h"
19*50995Sbostic 
20*50995Sbostic /*
21*50995Sbostic  * __REC_PUT -- Add a recno item to the tree.
22*50995Sbostic  *
23*50995Sbostic  * Parameters:
24*50995Sbostic  *	dbp:	pointer to access method
25*50995Sbostic  *	key:	key
26*50995Sbostic  *	data:	data
27*50995Sbostic  *	flag:	R_NOOVERWRITE
28*50995Sbostic  *
29*50995Sbostic  * Returns:
30*50995Sbostic  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
31*50995Sbostic  *	tree and R_NOOVERWRITE specified.
32*50995Sbostic  */
33*50995Sbostic int
34*50995Sbostic __rec_put(dbp, key, data, flags)
35*50995Sbostic 	const DB *dbp;
36*50995Sbostic 	const DBT *key, *data;
37*50995Sbostic 	u_int flags;
38*50995Sbostic {
39*50995Sbostic 	BTREE *t;
40*50995Sbostic 	DBT tdata;
41*50995Sbostic 	recno_t nrec;
42*50995Sbostic 	int status;
43*50995Sbostic 
44*50995Sbostic 	if (flags &&
45*50995Sbostic 	    flags != R_IAFTER && flags != R_IBEFORE && flags != R_NOOVERWRITE ||
46*50995Sbostic 	    (nrec = *(recno_t *)key->data) == 0) {
47*50995Sbostic 		errno = EINVAL;
48*50995Sbostic 		return (RET_ERROR);
49*50995Sbostic 	}
50*50995Sbostic 
51*50995Sbostic 	/*
52*50995Sbostic 	 * If skipping records, either get them from the original file or
53*50995Sbostic 	 * create empty ones.
54*50995Sbostic 	 */
55*50995Sbostic 	t = dbp->internal;
56*50995Sbostic 	if (nrec > t->bt_nrecs && t->bt_irec(t, nrec) == RET_ERROR)
57*50995Sbostic 		return (RET_ERROR);
58*50995Sbostic 	if (nrec > t->bt_nrecs) {
59*50995Sbostic 		tdata.data = NULL;
60*50995Sbostic 		tdata.size = 0;
61*50995Sbostic 		while (nrec > t->bt_nrecs) {
62*50995Sbostic 			status = __rec_iput(t, nrec, &tdata, 0);
63*50995Sbostic 			if (status != RET_SUCCESS)
64*50995Sbostic 				return (RET_ERROR);
65*50995Sbostic 		}
66*50995Sbostic 	}
67*50995Sbostic 	--nrec;
68*50995Sbostic 	if ((status = __rec_iput(t, nrec, data, flags)) == RET_SUCCESS)
69*50995Sbostic 		SET(t, BTF_MODIFIED);
70*50995Sbostic 	return (status);
71*50995Sbostic }
72*50995Sbostic 
73*50995Sbostic /*
74*50995Sbostic  * __REC_IPUT -- Add a recno item to the tree.
75*50995Sbostic  *
76*50995Sbostic  * Parameters:
77*50995Sbostic  *	t:	tree
78*50995Sbostic  *	nrec:	record number
79*50995Sbostic  *	data:	data
80*50995Sbostic  *	flag:	R_NOOVERWRITE
81*50995Sbostic  *
82*50995Sbostic  * Returns:
83*50995Sbostic  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
84*50995Sbostic  *	tree and R_NOOVERWRITE specified.
85*50995Sbostic  */
86*50995Sbostic int
87*50995Sbostic __rec_iput(t, nrec, data, flags)
88*50995Sbostic 	BTREE *t;
89*50995Sbostic 	recno_t nrec;
90*50995Sbostic 	const DBT *data;
91*50995Sbostic 	u_int flags;
92*50995Sbostic {
93*50995Sbostic 	DBT tdata;
94*50995Sbostic 	EPG *e;
95*50995Sbostic 	EPGNO *parent;
96*50995Sbostic 	PAGE *h;
97*50995Sbostic 	index_t index, nxtindex;
98*50995Sbostic 	pgno_t pg;
99*50995Sbostic 	size_t nbytes;
100*50995Sbostic 	int dflags, exact;
101*50995Sbostic 	char *dest, db[NOVFLSIZE];
102*50995Sbostic 
103*50995Sbostic 	/*
104*50995Sbostic 	 * If the data won't fit on a page, store it on indirect pages.
105*50995Sbostic 	 *
106*50995Sbostic 	 * XXX
107*50995Sbostic 	 * If the insert fails later on, these pages aren't recovered.
108*50995Sbostic 	 */
109*50995Sbostic 	if (data->size >= t->bt_minkeypage) {
110*50995Sbostic 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
111*50995Sbostic 			return (RET_ERROR);
112*50995Sbostic 		tdata.data = db;
113*50995Sbostic 		tdata.size = NOVFLSIZE;
114*50995Sbostic 		*(pgno_t *)db = pg;
115*50995Sbostic 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
116*50995Sbostic 		dflags = P_BIGDATA;
117*50995Sbostic 		data = &tdata;
118*50995Sbostic 	} else
119*50995Sbostic 		dflags = 0;
120*50995Sbostic 
121*50995Sbostic 	/* __rec_search pins the returned page. */
122*50995Sbostic 	if ((e = __rec_search(t, nrec, &exact)) == NULL)
123*50995Sbostic 		return (RET_ERROR);
124*50995Sbostic 
125*50995Sbostic 	h = e->page;
126*50995Sbostic 	index = e->index;
127*50995Sbostic 
128*50995Sbostic 	/*
129*50995Sbostic 	 * Add the specified key/data pair to the tree.  If an identical key
130*50995Sbostic 	 * is already in the tree, and R_NOOVERWRITE is set, an error is
131*50995Sbostic 	 * returned.  If R_NOOVERWRITE is not set, the key is either added (if
132*50995Sbostic 	 * duplicates are permitted) or an error is returned.  The R_IAFTER
133*50995Sbostic 	 * and R_IBEFORE flags insert the key after/before the specified key.
134*50995Sbostic 	 *
135*50995Sbostic 	 * Pages are split as required.
136*50995Sbostic 	 */
137*50995Sbostic 	switch (flags) {
138*50995Sbostic 	case R_IAFTER:
139*50995Sbostic 		if (!exact) {
140*50995Sbostic 			errno = EINVAL;
141*50995Sbostic 			goto err;
142*50995Sbostic 		}
143*50995Sbostic 		++index;
144*50995Sbostic 		break;
145*50995Sbostic 	case R_IBEFORE:
146*50995Sbostic 		if (!exact) {
147*50995Sbostic 			errno = EINVAL;
148*50995Sbostic 			goto err;
149*50995Sbostic 		}
150*50995Sbostic 		break;
151*50995Sbostic 	case R_NOOVERWRITE:
152*50995Sbostic 		if (!exact)
153*50995Sbostic 			break;
154*50995Sbostic 		BT_CLR(t);
155*50995Sbostic 		mpool_put(t->bt_mp, h, 0);
156*50995Sbostic 		return (RET_SPECIAL);
157*50995Sbostic 	default:
158*50995Sbostic 		if (!exact || NOTSET(t, BTF_NODUPS))
159*50995Sbostic 			break;
160*50995Sbostic 		if (__rec_dleaf(t, h, index) == RET_ERROR) {
161*50995Sbostic err:			BT_CLR(t);
162*50995Sbostic 			mpool_put(t->bt_mp, h, 0);
163*50995Sbostic 			return (RET_ERROR);
164*50995Sbostic 		}
165*50995Sbostic 		break;
166*50995Sbostic 	}
167*50995Sbostic 
168*50995Sbostic 	/*
169*50995Sbostic 	 * If not enough room, split the page.  The split code will insert
170*50995Sbostic 	 * the key and data and unpin the current page.  If inserting into
171*50995Sbostic 	 * the offset array, shift the pointers up.
172*50995Sbostic 	 */
173*50995Sbostic 	nbytes = NRLEAFDBT(data->size);
174*50995Sbostic 	if (h->upper - h->lower < nbytes + sizeof(index_t))
175*50995Sbostic 		return (__bt_split(t, h, NULL, data, dflags, nbytes, index));
176*50995Sbostic 
177*50995Sbostic 	if (index < (nxtindex = NEXTINDEX(h)))
178*50995Sbostic 		bcopy(h->linp + index, h->linp + index + 1,
179*50995Sbostic 		    (nxtindex - index) * sizeof(index_t));
180*50995Sbostic 	h->lower += sizeof(index_t);
181*50995Sbostic 
182*50995Sbostic 	h->linp[index] = h->upper -= nbytes;
183*50995Sbostic 	dest = (char *)h + h->upper;
184*50995Sbostic 	WR_RLEAF(dest, data, dflags);
185*50995Sbostic 
186*50995Sbostic 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
187*50995Sbostic 
188*50995Sbostic 	/* Increment the count on all parent pages. */
189*50995Sbostic 	while  ((parent = BT_POP(t)) != NULL) {
190*50995Sbostic 		if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
191*50995Sbostic 			return (RET_ERROR);
192*50995Sbostic 		++GETRINTERNAL(h, parent->index)->nrecs;
193*50995Sbostic 		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
194*50995Sbostic 	}
195*50995Sbostic 	++t->bt_nrecs;
196*50995Sbostic 	return (RET_SUCCESS);
197*50995Sbostic }
198