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
__rec_put(dbp,key,data,flags)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
__rec_iput(t,nrec,data,flags)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