]> git.saurik.com Git - apple/libc.git/blame - db.subproj/recno.subproj/rec_put.c
Libc-166.tar.gz
[apple/libc.git] / db.subproj / recno.subproj / rec_put.c
CommitLineData
e9ce8d39
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1990, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 */
54
55
56#include <sys/types.h>
57
58#include <errno.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62
63#include <db.h>
64#include "recno.h"
65
66/*
67 * __REC_PUT -- Add a recno item to the tree.
68 *
69 * Parameters:
70 * dbp: pointer to access method
71 * key: key
72 * data: data
73 * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
74 *
75 * Returns:
76 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
77 * already in the tree and R_NOOVERWRITE specified.
78 */
79int
80__rec_put(dbp, key, data, flags)
81 const DB *dbp;
82 DBT *key;
83 const DBT *data;
84 u_int flags;
85{
86 BTREE *t;
87 DBT tdata;
88 recno_t nrec;
89 int status;
90
91 t = dbp->internal;
92
93 /* Toss any page pinned across calls. */
94 if (t->bt_pinned != NULL) {
95 mpool_put(t->bt_mp, t->bt_pinned, 0);
96 t->bt_pinned = NULL;
97 }
98
99 switch (flags) {
100 case R_CURSOR:
101 if (!ISSET(t, B_SEQINIT))
102 goto einval;
103 nrec = t->bt_rcursor;
104 break;
105 case R_SETCURSOR:
106 if ((nrec = *(recno_t *)key->data) == 0)
107 goto einval;
108 break;
109 case R_IAFTER:
110 if ((nrec = *(recno_t *)key->data) == 0) {
111 nrec = 1;
112 flags = R_IBEFORE;
113 }
114 break;
115 case 0:
116 case R_IBEFORE:
117 if ((nrec = *(recno_t *)key->data) == 0)
118 goto einval;
119 break;
120 case R_NOOVERWRITE:
121 if ((nrec = *(recno_t *)key->data) == 0)
122 goto einval;
123 if (nrec <= t->bt_nrecs)
124 return (RET_SPECIAL);
125 break;
126 default:
127einval: errno = EINVAL;
128 return (RET_ERROR);
129 }
130
131 /*
132 * Make sure that records up to and including the put record are
133 * already in the database. If skipping records, create empty ones.
134 */
135 if (nrec > t->bt_nrecs) {
136 if (!ISSET(t, R_EOF | R_INMEM) &&
137 t->bt_irec(t, nrec) == RET_ERROR)
138 return (RET_ERROR);
139 if (nrec > t->bt_nrecs + 1) {
140 if (ISSET(t, R_FIXLEN)) {
141 if ((tdata.data =
142 (void *)malloc(t->bt_reclen)) == NULL)
143 return (RET_ERROR);
144 tdata.size = t->bt_reclen;
145 memset(tdata.data, t->bt_bval, tdata.size);
146 } else {
147 tdata.data = NULL;
148 tdata.size = 0;
149 }
150 while (nrec > t->bt_nrecs + 1)
151 if (__rec_iput(t,
152 t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
153 return (RET_ERROR);
154 if (ISSET(t, R_FIXLEN))
155 free(tdata.data);
156 }
157 }
158
159 if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS)
160 return (status);
161
162 if (flags == R_SETCURSOR)
163 t->bt_rcursor = nrec;
164
165 SET(t, R_MODIFIED);
166 return (__rec_ret(t, NULL, nrec, key, NULL));
167}
168
169/*
170 * __REC_IPUT -- Add a recno item to the tree.
171 *
172 * Parameters:
173 * t: tree
174 * nrec: record number
175 * data: data
176 *
177 * Returns:
178 * RET_ERROR, RET_SUCCESS
179 */
180int
181__rec_iput(t, nrec, data, flags)
182 BTREE *t;
183 recno_t nrec;
184 const DBT *data;
185 u_int flags;
186{
187 DBT tdata;
188 EPG *e;
189 PAGE *h;
190 indx_t index, nxtindex;
191 pgno_t pg;
192 size_t nbytes;
193 int dflags, status;
194 char *dest, db[NOVFLSIZE];
195
196 /*
197 * If the data won't fit on a page, store it on indirect pages.
198 *
199 * XXX
200 * If the insert fails later on, these pages aren't recovered.
201 */
202 if (data->size > t->bt_ovflsize) {
203 if (__ovfl_put(t, data, &pg) == RET_ERROR)
204 return (RET_ERROR);
205 tdata.data = db;
206 tdata.size = NOVFLSIZE;
207 *(pgno_t *)db = pg;
208 *(size_t *)(db + sizeof(pgno_t)) = data->size;
209 dflags = P_BIGDATA;
210 data = &tdata;
211 } else
212 dflags = 0;
213
214 /* __rec_search pins the returned page. */
215 if ((e = __rec_search(t, nrec,
216 nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
217 SINSERT : SEARCH)) == NULL)
218 return (RET_ERROR);
219
220 h = e->page;
221 index = e->index;
222
223 /*
224 * Add the specified key/data pair to the tree. The R_IAFTER and
225 * R_IBEFORE flags insert the key after/before the specified key.
226 *
227 * Pages are split as required.
228 */
229 switch (flags) {
230 case R_IAFTER:
231 ++index;
232 break;
233 case R_IBEFORE:
234 break;
235 default:
236 if (nrec < t->bt_nrecs &&
237 __rec_dleaf(t, h, index) == RET_ERROR) {
238 mpool_put(t->bt_mp, h, 0);
239 return (RET_ERROR);
240 }
241 break;
242 }
243
244 /*
245 * If not enough room, split the page. The split code will insert
246 * the key and data and unpin the current page. If inserting into
247 * the offset array, shift the pointers up.
248 */
249 nbytes = NRLEAFDBT(data->size);
250 if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
251 status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
252 if (status == RET_SUCCESS)
253 ++t->bt_nrecs;
254 return (status);
255 }
256
257 if (index < (nxtindex = NEXTINDEX(h)))
258 memmove(h->linp + index + 1, h->linp + index,
259 (nxtindex - index) * sizeof(indx_t));
260 h->lower += sizeof(indx_t);
261
262 h->linp[index] = h->upper -= nbytes;
263 dest = (char *)h + h->upper;
264 WR_RLEAF(dest, data, dflags);
265
266 ++t->bt_nrecs;
267 SET(t, B_MODIFIED);
268 mpool_put(t->bt_mp, h, MPOOL_DIRTY);
269
270 return (RET_SUCCESS);
271}