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.2 (Berkeley) 09/07/93"; 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 tdata.data = NULL; 97 tdata.size = 0; 98 while (nrec > t->bt_nrecs + 1) 99 if (__rec_iput(t, 100 t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 101 return (RET_ERROR); 102 } 103 } 104 105 if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS) 106 return (status); 107 108 if (flags == R_SETCURSOR) 109 t->bt_rcursor = nrec; 110 111 SET(t, R_MODIFIED); 112 return (__rec_ret(t, NULL, nrec, key, NULL)); 113 } 114 115 /* 116 * __REC_IPUT -- Add a recno item to the tree. 117 * 118 * Parameters: 119 * t: tree 120 * nrec: record number 121 * data: data 122 * 123 * Returns: 124 * RET_ERROR, RET_SUCCESS 125 */ 126 int 127 __rec_iput(t, nrec, data, flags) 128 BTREE *t; 129 recno_t nrec; 130 const DBT *data; 131 u_int flags; 132 { 133 DBT tdata; 134 EPG *e; 135 PAGE *h; 136 indx_t index, nxtindex; 137 pgno_t pg; 138 size_t nbytes; 139 int dflags, status; 140 char *dest, db[NOVFLSIZE]; 141 142 /* 143 * If the data won't fit on a page, store it on indirect pages. 144 * 145 * XXX 146 * If the insert fails later on, these pages aren't recovered. 147 */ 148 if (data->size > t->bt_ovflsize) { 149 if (__ovfl_put(t, data, &pg) == RET_ERROR) 150 return (RET_ERROR); 151 tdata.data = db; 152 tdata.size = NOVFLSIZE; 153 *(pgno_t *)db = pg; 154 *(size_t *)(db + sizeof(pgno_t)) = data->size; 155 dflags = P_BIGDATA; 156 data = &tdata; 157 } else 158 dflags = 0; 159 160 /* __rec_search pins the returned page. */ 161 if ((e = __rec_search(t, nrec, 162 nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 163 SINSERT : SEARCH)) == NULL) 164 return (RET_ERROR); 165 166 h = e->page; 167 index = e->index; 168 169 /* 170 * Add the specified key/data pair to the tree. The R_IAFTER and 171 * R_IBEFORE flags insert the key after/before the specified key. 172 * 173 * Pages are split as required. 174 */ 175 switch (flags) { 176 case R_IAFTER: 177 ++index; 178 break; 179 case R_IBEFORE: 180 break; 181 default: 182 if (nrec < t->bt_nrecs && 183 __rec_dleaf(t, h, index) == RET_ERROR) { 184 mpool_put(t->bt_mp, h, 0); 185 return (RET_ERROR); 186 } 187 break; 188 } 189 190 /* 191 * If not enough room, split the page. The split code will insert 192 * the key and data and unpin the current page. If inserting into 193 * the offset array, shift the pointers up. 194 */ 195 nbytes = NRLEAFDBT(data->size); 196 if (h->upper - h->lower < nbytes + sizeof(indx_t)) { 197 status = __bt_split(t, h, NULL, data, dflags, nbytes, index); 198 if (status == RET_SUCCESS) 199 ++t->bt_nrecs; 200 return (status); 201 } 202 203 if (index < (nxtindex = NEXTINDEX(h))) 204 memmove(h->linp + index + 1, h->linp + index, 205 (nxtindex - index) * sizeof(indx_t)); 206 h->lower += sizeof(indx_t); 207 208 h->linp[index] = h->upper -= nbytes; 209 dest = (char *)h + h->upper; 210 WR_RLEAF(dest, data, dflags); 211 212 ++t->bt_nrecs; 213 SET(t, B_MODIFIED); 214 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 215 216 return (RET_SUCCESS); 217 } 218