1 /* $NetBSD: rec_put.c,v 1.13 2003/08/07 16:42:44 agc Exp $ */ 2 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/cdefs.h> 33 #if defined(LIBC_SCCS) && !defined(lint) 34 #if 0 35 static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94"; 36 #else 37 __RCSID("$NetBSD: rec_put.c,v 1.13 2003/08/07 16:42:44 agc Exp $"); 38 #endif 39 #endif /* LIBC_SCCS and not lint */ 40 41 #include "namespace.h" 42 #include <sys/types.h> 43 44 #include <errno.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 49 #include <db.h> 50 #include "recno.h" 51 52 /* 53 * __REC_PUT -- Add a recno item to the tree. 54 * 55 * Parameters: 56 * dbp: pointer to access method 57 * key: key 58 * data: data 59 * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 60 * 61 * Returns: 62 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is 63 * already in the tree and R_NOOVERWRITE specified. 64 */ 65 int 66 __rec_put(dbp, key, data, flags) 67 const DB *dbp; 68 DBT *key; 69 const DBT *data; 70 u_int flags; 71 { 72 BTREE *t; 73 DBT fdata, tdata; 74 recno_t nrec; 75 int status; 76 77 t = dbp->internal; 78 79 /* Toss any page pinned across calls. */ 80 if (t->bt_pinned != NULL) { 81 mpool_put(t->bt_mp, t->bt_pinned, 0); 82 t->bt_pinned = NULL; 83 } 84 85 /* 86 * If using fixed-length records, and the record is long, return 87 * EINVAL. If it's short, pad it out. Use the record data return 88 * memory, it's only short-term. 89 */ 90 if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) { 91 if (data->size > t->bt_reclen) 92 goto einval; 93 94 if (t->bt_rdata.size < t->bt_reclen) { 95 t->bt_rdata.data = t->bt_rdata.data == NULL ? 96 malloc(t->bt_reclen) : 97 realloc(t->bt_rdata.data, t->bt_reclen); 98 if (t->bt_rdata.data == NULL) 99 return (RET_ERROR); 100 t->bt_rdata.size = t->bt_reclen; 101 } 102 memmove(t->bt_rdata.data, data->data, data->size); 103 memset((char *)t->bt_rdata.data + data->size, 104 t->bt_bval, t->bt_reclen - data->size); 105 fdata.data = t->bt_rdata.data; 106 fdata.size = t->bt_reclen; 107 } else { 108 fdata.data = data->data; 109 fdata.size = data->size; 110 } 111 112 switch (flags) { 113 case R_CURSOR: 114 if (!F_ISSET(&t->bt_cursor, CURS_INIT)) 115 goto einval; 116 nrec = t->bt_cursor.rcursor; 117 break; 118 case R_SETCURSOR: 119 if ((nrec = *(recno_t *)key->data) == 0) 120 goto einval; 121 break; 122 case R_IAFTER: 123 if ((nrec = *(recno_t *)key->data) == 0) { 124 nrec = 1; 125 flags = R_IBEFORE; 126 } 127 break; 128 case 0: 129 case R_IBEFORE: 130 if ((nrec = *(recno_t *)key->data) == 0) 131 goto einval; 132 break; 133 case R_NOOVERWRITE: 134 if ((nrec = *(recno_t *)key->data) == 0) 135 goto einval; 136 if (nrec <= t->bt_nrecs) 137 return (RET_SPECIAL); 138 break; 139 default: 140 einval: errno = EINVAL; 141 return (RET_ERROR); 142 } 143 144 /* 145 * Make sure that records up to and including the put record are 146 * already in the database. If skipping records, create empty ones. 147 */ 148 if (nrec > t->bt_nrecs) { 149 if (!F_ISSET(t, R_EOF | R_INMEM) && 150 t->bt_irec(t, nrec) == RET_ERROR) 151 return (RET_ERROR); 152 if (nrec > t->bt_nrecs + 1) { 153 if (F_ISSET(t, R_FIXLEN)) { 154 if ((tdata.data = 155 (void *)malloc(t->bt_reclen)) == NULL) 156 return (RET_ERROR); 157 tdata.size = t->bt_reclen; 158 memset(tdata.data, t->bt_bval, tdata.size); 159 } else { 160 tdata.data = NULL; 161 tdata.size = 0; 162 } 163 while (nrec > t->bt_nrecs + 1) 164 if (__rec_iput(t, 165 t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 166 return (RET_ERROR); 167 if (F_ISSET(t, R_FIXLEN)) 168 free(tdata.data); 169 } 170 } 171 172 if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS) 173 return (status); 174 175 if (flags == R_SETCURSOR) 176 t->bt_cursor.rcursor = nrec; 177 178 F_SET(t, R_MODIFIED); 179 return (__rec_ret(t, NULL, nrec, key, NULL)); 180 } 181 182 /* 183 * __REC_IPUT -- Add a recno item to the tree. 184 * 185 * Parameters: 186 * t: tree 187 * nrec: record number 188 * data: data 189 * 190 * Returns: 191 * RET_ERROR, RET_SUCCESS 192 */ 193 int 194 __rec_iput(t, nrec, data, flags) 195 BTREE *t; 196 recno_t nrec; 197 const DBT *data; 198 u_int flags; 199 { 200 DBT tdata; 201 EPG *e; 202 PAGE *h; 203 indx_t idx, nxtindex; 204 pgno_t pg; 205 u_int32_t nbytes; 206 int dflags, status; 207 char *dest, db[NOVFLSIZE]; 208 209 /* 210 * If the data won't fit on a page, store it on indirect pages. 211 * 212 * XXX 213 * If the insert fails later on, these pages aren't recovered. 214 */ 215 if (data->size > t->bt_ovflsize) { 216 if (__ovfl_put(t, data, &pg) == RET_ERROR) 217 return (RET_ERROR); 218 tdata.data = db; 219 tdata.size = NOVFLSIZE; 220 *(pgno_t *)(void *)db = pg; 221 *(u_int32_t *)(void *)(db + sizeof(pgno_t)) = data->size; 222 dflags = P_BIGDATA; 223 data = &tdata; 224 } else 225 dflags = 0; 226 227 /* __rec_search pins the returned page. */ 228 if ((e = __rec_search(t, nrec, 229 nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 230 SINSERT : SEARCH)) == NULL) 231 return (RET_ERROR); 232 233 h = e->page; 234 idx = e->index; 235 236 /* 237 * Add the specified key/data pair to the tree. The R_IAFTER and 238 * R_IBEFORE flags insert the key after/before the specified key. 239 * 240 * Pages are split as required. 241 */ 242 switch (flags) { 243 case R_IAFTER: 244 ++idx; 245 break; 246 case R_IBEFORE: 247 break; 248 default: 249 if (nrec < t->bt_nrecs && 250 __rec_dleaf(t, h, (u_int32_t)idx) == RET_ERROR) { 251 mpool_put(t->bt_mp, h, 0); 252 return (RET_ERROR); 253 } 254 break; 255 } 256 257 /* 258 * If not enough room, split the page. The split code will insert 259 * the key and data and unpin the current page. If inserting into 260 * the offset array, shift the pointers up. 261 */ 262 nbytes = NRLEAFDBT(data->size); 263 if ((u_int32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) { 264 status = __bt_split(t, h, NULL, data, dflags, nbytes, 265 (u_int32_t)idx); 266 if (status == RET_SUCCESS) 267 ++t->bt_nrecs; 268 return (status); 269 } 270 271 if (idx < (nxtindex = NEXTINDEX(h))) 272 memmove(h->linp + idx + 1, h->linp + idx, 273 (nxtindex - idx) * sizeof(indx_t)); 274 h->lower += sizeof(indx_t); 275 276 h->linp[idx] = h->upper -= nbytes; 277 dest = (char *)(void *)h + h->upper; 278 WR_RLEAF(dest, data, dflags); 279 280 ++t->bt_nrecs; 281 F_SET(t, B_MODIFIED); 282 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 283 284 return (RET_SUCCESS); 285 } 286