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.1 (Berkeley) 06/04/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 switch (flags) { 50 case R_CURSOR: 51 if (!ISSET(t, B_SEQINIT)) 52 goto einval; 53 nrec = t->bt_rcursor; 54 break; 55 case R_SETCURSOR: 56 if ((nrec = *(recno_t *)key->data) == 0) 57 goto einval; 58 break; 59 case R_IAFTER: 60 if ((nrec = *(recno_t *)key->data) == 0) { 61 nrec = 1; 62 flags = R_IBEFORE; 63 } 64 break; 65 case 0: 66 case R_IBEFORE: 67 if ((nrec = *(recno_t *)key->data) == 0) 68 goto einval; 69 break; 70 case R_NOOVERWRITE: 71 if ((nrec = *(recno_t *)key->data) == 0) 72 goto einval; 73 if (nrec <= t->bt_nrecs) 74 return (RET_SPECIAL); 75 break; 76 default: 77 einval: errno = EINVAL; 78 return (RET_ERROR); 79 } 80 81 /* 82 * Make sure that records up to and including the put record are 83 * already in the database. If skipping records, create empty ones. 84 */ 85 if (nrec > t->bt_nrecs) { 86 if (!ISSET(t, R_EOF | R_INMEM) && 87 t->bt_irec(t, nrec) == RET_ERROR) 88 return (RET_ERROR); 89 if (nrec > t->bt_nrecs + 1) { 90 tdata.data = NULL; 91 tdata.size = 0; 92 while (nrec > t->bt_nrecs + 1) 93 if (__rec_iput(t, 94 t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 95 return (RET_ERROR); 96 } 97 } 98 99 if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS) 100 return (status); 101 102 if (flags == R_SETCURSOR) 103 t->bt_rcursor = nrec; 104 105 SET(t, R_MODIFIED); 106 return (__rec_ret(t, NULL, nrec, key, NULL)); 107 } 108 109 /* 110 * __REC_IPUT -- Add a recno item to the tree. 111 * 112 * Parameters: 113 * t: tree 114 * nrec: record number 115 * data: data 116 * 117 * Returns: 118 * RET_ERROR, RET_SUCCESS 119 */ 120 int 121 __rec_iput(t, nrec, data, flags) 122 BTREE *t; 123 recno_t nrec; 124 const DBT *data; 125 u_int flags; 126 { 127 DBT tdata; 128 EPG *e; 129 PAGE *h; 130 indx_t index, nxtindex; 131 pgno_t pg; 132 size_t nbytes; 133 int dflags, status; 134 char *dest, db[NOVFLSIZE]; 135 136 /* 137 * If the data won't fit on a page, store it on indirect pages. 138 * 139 * XXX 140 * If the insert fails later on, these pages aren't recovered. 141 */ 142 if (data->size > t->bt_ovflsize) { 143 if (__ovfl_put(t, data, &pg) == RET_ERROR) 144 return (RET_ERROR); 145 tdata.data = db; 146 tdata.size = NOVFLSIZE; 147 *(pgno_t *)db = pg; 148 *(size_t *)(db + sizeof(pgno_t)) = data->size; 149 dflags = P_BIGDATA; 150 data = &tdata; 151 } else 152 dflags = 0; 153 154 /* __rec_search pins the returned page. */ 155 if ((e = __rec_search(t, nrec, 156 nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 157 SINSERT : SEARCH)) == NULL) 158 return (RET_ERROR); 159 160 h = e->page; 161 index = e->index; 162 163 /* 164 * Add the specified key/data pair to the tree. The R_IAFTER and 165 * R_IBEFORE flags insert the key after/before the specified key. 166 * 167 * Pages are split as required. 168 */ 169 switch (flags) { 170 case R_IAFTER: 171 ++index; 172 break; 173 case R_IBEFORE: 174 break; 175 default: 176 if (nrec < t->bt_nrecs && 177 __rec_dleaf(t, h, index) == RET_ERROR) { 178 mpool_put(t->bt_mp, h, 0); 179 return (RET_ERROR); 180 } 181 break; 182 } 183 184 /* 185 * If not enough room, split the page. The split code will insert 186 * the key and data and unpin the current page. If inserting into 187 * the offset array, shift the pointers up. 188 */ 189 nbytes = NRLEAFDBT(data->size); 190 if (h->upper - h->lower < nbytes + sizeof(indx_t)) { 191 status = __bt_split(t, h, NULL, data, dflags, nbytes, index); 192 if (status == RET_SUCCESS) 193 ++t->bt_nrecs; 194 return (status); 195 } 196 197 if (index < (nxtindex = NEXTINDEX(h))) 198 memmove(h->linp + index + 1, h->linp + index, 199 (nxtindex - index) * sizeof(indx_t)); 200 h->lower += sizeof(indx_t); 201 202 h->linp[index] = h->upper -= nbytes; 203 dest = (char *)h + h->upper; 204 WR_RLEAF(dest, data, dflags); 205 206 ++t->bt_nrecs; 207 SET(t, B_MODIFIED); 208 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 209 210 return (RET_SUCCESS); 211 } 212