xref: /original-bsd/lib/libc/db/recno/rec_put.c (revision f737e041)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)rec_put.c	8.3 (Berkeley) 03/01/94";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/types.h>
13 
14 #include <errno.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <db.h>
20 #include "recno.h"
21 
22 /*
23  * __REC_PUT -- Add a recno item to the tree.
24  *
25  * Parameters:
26  *	dbp:	pointer to access method
27  *	key:	key
28  *	data:	data
29  *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
30  *
31  * Returns:
32  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
33  *	already in the tree and R_NOOVERWRITE specified.
34  */
35 int
36 __rec_put(dbp, key, data, flags)
37 	const DB *dbp;
38 	DBT *key;
39 	const DBT *data;
40 	u_int flags;
41 {
42 	BTREE *t;
43 	DBT tdata;
44 	recno_t nrec;
45 	int status;
46 
47 	t = dbp->internal;
48 
49 	/* Toss any page pinned across calls. */
50 	if (t->bt_pinned != NULL) {
51 		mpool_put(t->bt_mp, t->bt_pinned, 0);
52 		t->bt_pinned = NULL;
53 	}
54 
55 	switch (flags) {
56 	case R_CURSOR:
57 		if (!ISSET(t, B_SEQINIT))
58 			goto einval;
59 		nrec = t->bt_rcursor;
60 		break;
61 	case R_SETCURSOR:
62 		if ((nrec = *(recno_t *)key->data) == 0)
63 			goto einval;
64 		break;
65 	case R_IAFTER:
66 		if ((nrec = *(recno_t *)key->data) == 0) {
67 			nrec = 1;
68 			flags = R_IBEFORE;
69 		}
70 		break;
71 	case 0:
72 	case R_IBEFORE:
73 		if ((nrec = *(recno_t *)key->data) == 0)
74 			goto einval;
75 		break;
76 	case R_NOOVERWRITE:
77 		if ((nrec = *(recno_t *)key->data) == 0)
78 			goto einval;
79 		if (nrec <= t->bt_nrecs)
80 			return (RET_SPECIAL);
81 		break;
82 	default:
83 einval:		errno = EINVAL;
84 		return (RET_ERROR);
85 	}
86 
87 	/*
88 	 * Make sure that records up to and including the put record are
89 	 * already in the database.  If skipping records, create empty ones.
90 	 */
91 	if (nrec > t->bt_nrecs) {
92 		if (!ISSET(t, R_EOF | R_INMEM) &&
93 		    t->bt_irec(t, nrec) == RET_ERROR)
94 			return (RET_ERROR);
95 		if (nrec > t->bt_nrecs + 1) {
96 			if (ISSET(t, R_FIXLEN)) {
97 				if ((tdata.data =
98 				    (void *)malloc(t->bt_reclen)) == NULL)
99 					return (RET_ERROR);
100 				tdata.size = t->bt_reclen;
101 				memset(tdata.data, t->bt_bval, tdata.size);
102 			} else {
103 				tdata.data = NULL;
104 				tdata.size = 0;
105 			}
106 			while (nrec > t->bt_nrecs + 1)
107 				if (__rec_iput(t,
108 				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
109 					return (RET_ERROR);
110 			if (ISSET(t, R_FIXLEN))
111 				free(tdata.data);
112 		}
113 	}
114 
115 	if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS)
116 		return (status);
117 
118 	if (flags == R_SETCURSOR)
119 		t->bt_rcursor = nrec;
120 
121 	SET(t, R_MODIFIED);
122 	return (__rec_ret(t, NULL, nrec, key, NULL));
123 }
124 
125 /*
126  * __REC_IPUT -- Add a recno item to the tree.
127  *
128  * Parameters:
129  *	t:	tree
130  *	nrec:	record number
131  *	data:	data
132  *
133  * Returns:
134  *	RET_ERROR, RET_SUCCESS
135  */
136 int
137 __rec_iput(t, nrec, data, flags)
138 	BTREE *t;
139 	recno_t nrec;
140 	const DBT *data;
141 	u_int flags;
142 {
143 	DBT tdata;
144 	EPG *e;
145 	PAGE *h;
146 	indx_t index, nxtindex;
147 	pgno_t pg;
148 	size_t nbytes;
149 	int dflags, status;
150 	char *dest, db[NOVFLSIZE];
151 
152 	/*
153 	 * If the data won't fit on a page, store it on indirect pages.
154 	 *
155 	 * XXX
156 	 * If the insert fails later on, these pages aren't recovered.
157 	 */
158 	if (data->size > t->bt_ovflsize) {
159 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
160 			return (RET_ERROR);
161 		tdata.data = db;
162 		tdata.size = NOVFLSIZE;
163 		*(pgno_t *)db = pg;
164 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
165 		dflags = P_BIGDATA;
166 		data = &tdata;
167 	} else
168 		dflags = 0;
169 
170 	/* __rec_search pins the returned page. */
171 	if ((e = __rec_search(t, nrec,
172 	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
173 	    SINSERT : SEARCH)) == NULL)
174 		return (RET_ERROR);
175 
176 	h = e->page;
177 	index = e->index;
178 
179 	/*
180 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
181 	 * R_IBEFORE flags insert the key after/before the specified key.
182 	 *
183 	 * Pages are split as required.
184 	 */
185 	switch (flags) {
186 	case R_IAFTER:
187 		++index;
188 		break;
189 	case R_IBEFORE:
190 		break;
191 	default:
192 		if (nrec < t->bt_nrecs &&
193 		    __rec_dleaf(t, h, index) == RET_ERROR) {
194 			mpool_put(t->bt_mp, h, 0);
195 			return (RET_ERROR);
196 		}
197 		break;
198 	}
199 
200 	/*
201 	 * If not enough room, split the page.  The split code will insert
202 	 * the key and data and unpin the current page.  If inserting into
203 	 * the offset array, shift the pointers up.
204 	 */
205 	nbytes = NRLEAFDBT(data->size);
206 	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
207 		status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
208 		if (status == RET_SUCCESS)
209 			++t->bt_nrecs;
210 		return (status);
211 	}
212 
213 	if (index < (nxtindex = NEXTINDEX(h)))
214 		memmove(h->linp + index + 1, h->linp + index,
215 		    (nxtindex - index) * sizeof(indx_t));
216 	h->lower += sizeof(indx_t);
217 
218 	h->linp[index] = h->upper -= nbytes;
219 	dest = (char *)h + h->upper;
220 	WR_RLEAF(dest, data, dflags);
221 
222 	++t->bt_nrecs;
223 	SET(t, B_MODIFIED);
224 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
225 
226 	return (RET_SUCCESS);
227 }
228