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