xref: /original-bsd/lib/libc/db/recno/rec_put.c (revision c21e1f3a)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * 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	5.11 (Berkeley) 03/19/93";
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_CURSORLOG, R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
30  *
31  * Returns:
32  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
33  *	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 	switch (flags) {
50 	case R_CURSOR:
51 		if (!ISSET(t, BTF_SEQINIT))
52 			goto einval;
53 		nrec = t->bt_rcursor;
54 		break;
55 	case R_CURSORLOG:
56 		nrec = t->bt_rcursor + 1;
57 		SET(t, BTF_SEQINIT);
58 		break;
59 	case R_SETCURSOR:
60 		if ((nrec = *(recno_t *)key->data) == 0)
61 			goto einval;
62 		break;
63 	case R_IAFTER:
64 		if ((nrec = *(recno_t *)key->data) == 0) {
65 			nrec = 1;
66 			flags = R_IBEFORE;
67 		}
68 		break;
69 	case 0:
70 	case R_IBEFORE:
71 		if ((nrec = *(recno_t *)key->data) == 0)
72 			goto einval;
73 		break;
74 	case R_NOOVERWRITE:
75 		if ((nrec = *(recno_t *)key->data) == 0)
76 			goto einval;
77 		if (nrec <= t->bt_nrecs)
78 			return (RET_SPECIAL);
79 		break;
80 	default:
81 einval:		errno = EINVAL;
82 		return (RET_ERROR);
83 	}
84 
85 	/*
86 	 * Make sure that records up to and including the put record are
87 	 * already in the database.  If skipping records, create empty ones.
88 	 */
89 	if (nrec > t->bt_nrecs) {
90 		if (!ISSET(t, BTF_EOF | BTF_RINMEM) &&
91 		    t->bt_irec(t, nrec) == RET_ERROR)
92 			return (RET_ERROR);
93 		if (nrec > t->bt_nrecs + 1) {
94 			tdata.data = NULL;
95 			tdata.size = 0;
96 			while (nrec > t->bt_nrecs + 1)
97 				if (__rec_iput(t,
98 				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
99 					return (RET_ERROR);
100 		}
101 	}
102 
103 	if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS)
104 		return (status);
105 
106 	SET(t, BTF_MODIFIED);
107 	switch(flags) {
108 	case R_CURSORLOG:
109 		++t->bt_rcursor;
110 		break;
111 	case R_SETCURSOR:
112 		t->bt_rcursor = nrec;
113 		break;
114 	}
115 
116 	return (__rec_ret(t, NULL, nrec, key, NULL));
117 }
118 
119 /*
120  * __REC_IPUT -- Add a recno item to the tree.
121  *
122  * Parameters:
123  *	t:	tree
124  *	nrec:	record number
125  *	data:	data
126  *
127  * Returns:
128  *	RET_ERROR, RET_SUCCESS
129  */
130 int
131 __rec_iput(t, nrec, data, flags)
132 	BTREE *t;
133 	recno_t nrec;
134 	const DBT *data;
135 	u_int flags;
136 {
137 	DBT tdata;
138 	EPG *e;
139 	PAGE *h;
140 	indx_t index, nxtindex;
141 	pgno_t pg;
142 	size_t nbytes;
143 	int dflags, status;
144 	char *dest, db[NOVFLSIZE];
145 
146 	/*
147 	 * If the data won't fit on a page, store it on indirect pages.
148 	 *
149 	 * XXX
150 	 * If the insert fails later on, these pages aren't recovered.
151 	 */
152 	if (data->size > t->bt_ovflsize) {
153 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
154 			return (RET_ERROR);
155 		tdata.data = db;
156 		tdata.size = NOVFLSIZE;
157 		*(pgno_t *)db = pg;
158 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
159 		dflags = P_BIGDATA;
160 		data = &tdata;
161 	} else
162 		dflags = 0;
163 
164 	/* __rec_search pins the returned page. */
165 	if ((e = __rec_search(t, nrec,
166 	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
167 	    SINSERT : SEARCH)) == NULL)
168 		return (RET_ERROR);
169 
170 	h = e->page;
171 	index = e->index;
172 
173 	/*
174 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
175 	 * R_IBEFORE flags insert the key after/before the specified key.
176 	 *
177 	 * Pages are split as required.
178 	 */
179 	switch (flags) {
180 	case R_IAFTER:
181 		++index;
182 		break;
183 	case R_IBEFORE:
184 		break;
185 	default:
186 		if (nrec < t->bt_nrecs &&
187 		    __rec_dleaf(t, h, index) == RET_ERROR) {
188 			mpool_put(t->bt_mp, h, 0);
189 			return (RET_ERROR);
190 		}
191 		break;
192 	}
193 
194 	/*
195 	 * If not enough room, split the page.  The split code will insert
196 	 * the key and data and unpin the current page.  If inserting into
197 	 * the offset array, shift the pointers up.
198 	 */
199 	nbytes = NRLEAFDBT(data->size);
200 	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
201 		status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
202 		if (status == RET_SUCCESS)
203 			++t->bt_nrecs;
204 		return (status);
205 	}
206 
207 	if (index < (nxtindex = NEXTINDEX(h)))
208 		memmove(h->linp + index + 1, h->linp + index,
209 		    (nxtindex - index) * sizeof(indx_t));
210 	h->lower += sizeof(indx_t);
211 
212 	h->linp[index] = h->upper -= nbytes;
213 	dest = (char *)h + h->upper;
214 	WR_RLEAF(dest, data, dflags);
215 
216 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
217 	++t->bt_nrecs;
218 	return (RET_SUCCESS);
219 }
220