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