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