xref: /freebsd/lib/libc/db/recno/rec_put.c (revision afe61c15161c324a7af299a9b8457aba5afc92db)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)rec_put.c	8.3 (Berkeley) 3/1/94";
36 #endif /* LIBC_SCCS and not lint */
37 
38 #include <sys/types.h>
39 
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include <db.h>
46 #include "recno.h"
47 
48 /*
49  * __REC_PUT -- Add a recno item to the tree.
50  *
51  * Parameters:
52  *	dbp:	pointer to access method
53  *	key:	key
54  *	data:	data
55  *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
56  *
57  * Returns:
58  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
59  *	already in the tree and R_NOOVERWRITE specified.
60  */
61 int
62 __rec_put(dbp, key, data, flags)
63 	const DB *dbp;
64 	DBT *key;
65 	const DBT *data;
66 	u_int flags;
67 {
68 	BTREE *t;
69 	DBT tdata;
70 	recno_t nrec;
71 	int status;
72 
73 	t = dbp->internal;
74 
75 	/* Toss any page pinned across calls. */
76 	if (t->bt_pinned != NULL) {
77 		mpool_put(t->bt_mp, t->bt_pinned, 0);
78 		t->bt_pinned = NULL;
79 	}
80 
81 	switch (flags) {
82 	case R_CURSOR:
83 		if (!ISSET(t, B_SEQINIT))
84 			goto einval;
85 		nrec = t->bt_rcursor;
86 		break;
87 	case R_SETCURSOR:
88 		if ((nrec = *(recno_t *)key->data) == 0)
89 			goto einval;
90 		break;
91 	case R_IAFTER:
92 		if ((nrec = *(recno_t *)key->data) == 0) {
93 			nrec = 1;
94 			flags = R_IBEFORE;
95 		}
96 		break;
97 	case 0:
98 	case R_IBEFORE:
99 		if ((nrec = *(recno_t *)key->data) == 0)
100 			goto einval;
101 		break;
102 	case R_NOOVERWRITE:
103 		if ((nrec = *(recno_t *)key->data) == 0)
104 			goto einval;
105 		if (nrec <= t->bt_nrecs)
106 			return (RET_SPECIAL);
107 		break;
108 	default:
109 einval:		errno = EINVAL;
110 		return (RET_ERROR);
111 	}
112 
113 	/*
114 	 * Make sure that records up to and including the put record are
115 	 * already in the database.  If skipping records, create empty ones.
116 	 */
117 	if (nrec > t->bt_nrecs) {
118 		if (!ISSET(t, R_EOF | R_INMEM) &&
119 		    t->bt_irec(t, nrec) == RET_ERROR)
120 			return (RET_ERROR);
121 		if (nrec > t->bt_nrecs + 1) {
122 			if (ISSET(t, R_FIXLEN)) {
123 				if ((tdata.data =
124 				    (void *)malloc(t->bt_reclen)) == NULL)
125 					return (RET_ERROR);
126 				tdata.size = t->bt_reclen;
127 				memset(tdata.data, t->bt_bval, tdata.size);
128 			} else {
129 				tdata.data = NULL;
130 				tdata.size = 0;
131 			}
132 			while (nrec > t->bt_nrecs + 1)
133 				if (__rec_iput(t,
134 				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
135 					return (RET_ERROR);
136 			if (ISSET(t, R_FIXLEN))
137 				free(tdata.data);
138 		}
139 	}
140 
141 	if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS)
142 		return (status);
143 
144 	if (flags == R_SETCURSOR)
145 		t->bt_rcursor = nrec;
146 
147 	SET(t, R_MODIFIED);
148 	return (__rec_ret(t, NULL, nrec, key, NULL));
149 }
150 
151 /*
152  * __REC_IPUT -- Add a recno item to the tree.
153  *
154  * Parameters:
155  *	t:	tree
156  *	nrec:	record number
157  *	data:	data
158  *
159  * Returns:
160  *	RET_ERROR, RET_SUCCESS
161  */
162 int
163 __rec_iput(t, nrec, data, flags)
164 	BTREE *t;
165 	recno_t nrec;
166 	const DBT *data;
167 	u_int flags;
168 {
169 	DBT tdata;
170 	EPG *e;
171 	PAGE *h;
172 	indx_t index, nxtindex;
173 	pgno_t pg;
174 	size_t nbytes;
175 	int dflags, status;
176 	char *dest, db[NOVFLSIZE];
177 
178 	/*
179 	 * If the data won't fit on a page, store it on indirect pages.
180 	 *
181 	 * XXX
182 	 * If the insert fails later on, these pages aren't recovered.
183 	 */
184 	if (data->size > t->bt_ovflsize) {
185 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
186 			return (RET_ERROR);
187 		tdata.data = db;
188 		tdata.size = NOVFLSIZE;
189 		*(pgno_t *)db = pg;
190 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
191 		dflags = P_BIGDATA;
192 		data = &tdata;
193 	} else
194 		dflags = 0;
195 
196 	/* __rec_search pins the returned page. */
197 	if ((e = __rec_search(t, nrec,
198 	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
199 	    SINSERT : SEARCH)) == NULL)
200 		return (RET_ERROR);
201 
202 	h = e->page;
203 	index = e->index;
204 
205 	/*
206 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
207 	 * R_IBEFORE flags insert the key after/before the specified key.
208 	 *
209 	 * Pages are split as required.
210 	 */
211 	switch (flags) {
212 	case R_IAFTER:
213 		++index;
214 		break;
215 	case R_IBEFORE:
216 		break;
217 	default:
218 		if (nrec < t->bt_nrecs &&
219 		    __rec_dleaf(t, h, index) == RET_ERROR) {
220 			mpool_put(t->bt_mp, h, 0);
221 			return (RET_ERROR);
222 		}
223 		break;
224 	}
225 
226 	/*
227 	 * If not enough room, split the page.  The split code will insert
228 	 * the key and data and unpin the current page.  If inserting into
229 	 * the offset array, shift the pointers up.
230 	 */
231 	nbytes = NRLEAFDBT(data->size);
232 	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
233 		status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
234 		if (status == RET_SUCCESS)
235 			++t->bt_nrecs;
236 		return (status);
237 	}
238 
239 	if (index < (nxtindex = NEXTINDEX(h)))
240 		memmove(h->linp + index + 1, h->linp + index,
241 		    (nxtindex - index) * sizeof(indx_t));
242 	h->lower += sizeof(indx_t);
243 
244 	h->linp[index] = h->upper -= nbytes;
245 	dest = (char *)h + h->upper;
246 	WR_RLEAF(dest, data, dflags);
247 
248 	++t->bt_nrecs;
249 	SET(t, B_MODIFIED);
250 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
251 
252 	return (RET_SUCCESS);
253 }
254