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 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 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