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