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