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.4 (Berkeley) 08/26/92"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/types.h> 13 #include <errno.h> 14 #include <db.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include "recno.h" 19 20 /* 21 * __REC_PUT -- Add a recno item to the tree. 22 * 23 * Parameters: 24 * dbp: pointer to access method 25 * key: key 26 * data: data 27 * flag: R_APPEND, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 28 * 29 * Returns: 30 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 31 * tree and R_NOOVERWRITE specified. 32 */ 33 int 34 __rec_put(dbp, key, data, flags) 35 const DB *dbp; 36 const DBT *key, *data; 37 u_int flags; 38 { 39 BTREE *t; 40 DBT tdata; 41 recno_t nrec; 42 int status; 43 44 t = dbp->internal; 45 46 switch (flags) { 47 case R_APPEND: 48 nrec = t->bt_nrecs + 1; 49 break; 50 case R_CURSOR: 51 if (ISSET(t, BTF_DELCRSR)) 52 goto einval; 53 nrec = t->bt_rcursor; 54 break; 55 case R_IAFTER: 56 if ((nrec = *(recno_t *)key->data) == 0) { 57 nrec = 1; 58 flags = R_IBEFORE; 59 } 60 break; 61 case 0: 62 case R_IBEFORE: 63 if ((nrec = *(recno_t *)key->data) == 0) 64 goto einval; 65 break; 66 case R_NOOVERWRITE: 67 if ((nrec = *(recno_t *)key->data) == 0) 68 goto einval; 69 if (nrec <= t->bt_nrecs) 70 return (RET_SPECIAL); 71 break; 72 default: 73 einval: errno = EINVAL; 74 return (RET_ERROR); 75 } 76 77 /* 78 * Make sure that records up to and including the put record are 79 * already in the database. If skipping records, create empty ones. 80 */ 81 if (nrec > t->bt_nrecs) { 82 if (t->bt_irec(t, nrec) == RET_ERROR) 83 return (RET_ERROR); 84 if (nrec > t->bt_nrecs + 1) { 85 tdata.data = NULL; 86 tdata.size = 0; 87 while (nrec > t->bt_nrecs + 1) 88 if (__rec_iput(t, 89 t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 90 return (RET_ERROR); 91 } 92 } 93 --nrec; 94 if ((status = __rec_iput(t, nrec, data, flags)) == RET_SUCCESS) 95 SET(t, BTF_MODIFIED); 96 return (status); 97 } 98 99 /* 100 * __REC_IPUT -- Add a recno item to the tree. 101 * 102 * Parameters: 103 * t: tree 104 * nrec: record number 105 * data: data 106 * 107 * Returns: 108 * RET_ERROR, RET_SUCCESS 109 */ 110 int 111 __rec_iput(t, nrec, data, flags) 112 BTREE *t; 113 recno_t nrec; 114 const DBT *data; 115 u_int flags; 116 { 117 DBT tdata; 118 EPG *e; 119 PAGE *h; 120 index_t index, nxtindex; 121 pgno_t pg; 122 size_t nbytes; 123 int dflags, status; 124 char *dest, db[NOVFLSIZE]; 125 126 /* 127 * If the data won't fit on a page, store it on indirect pages. 128 * 129 * XXX 130 * If the insert fails later on, these pages aren't recovered. 131 */ 132 if (data->size > t->bt_ovflsize) { 133 if (__ovfl_put(t, data, &pg) == RET_ERROR) 134 return (RET_ERROR); 135 tdata.data = db; 136 tdata.size = NOVFLSIZE; 137 *(pgno_t *)db = pg; 138 *(size_t *)(db + sizeof(pgno_t)) = data->size; 139 dflags = P_BIGDATA; 140 data = &tdata; 141 } else 142 dflags = 0; 143 144 /* __rec_search pins the returned page. */ 145 if ((e = __rec_search(t, nrec, 146 nrec > t->bt_nrecs ? SINSERT : SEARCH)) == NULL) 147 return (RET_ERROR); 148 149 h = e->page; 150 index = e->index; 151 152 /* 153 * Add the specified key/data pair to the tree. The R_IAFTER and 154 * R_IBEFORE flags insert the key after/before the specified key. 155 * 156 * Pages are split as required. 157 */ 158 switch (flags) { 159 case R_IAFTER: 160 ++index; 161 break; 162 case R_IBEFORE: 163 break; 164 default: 165 if (nrec < t->bt_nrecs && 166 __rec_dleaf(t, h, index) == RET_ERROR) { 167 BT_CLR(t); 168 mpool_put(t->bt_mp, h, 0); 169 return (RET_ERROR); 170 } 171 break; 172 } 173 174 /* 175 * If not enough room, split the page. The split code will insert 176 * the key and data and unpin the current page. If inserting into 177 * the offset array, shift the pointers up. 178 */ 179 nbytes = NRLEAFDBT(data->size); 180 if (h->upper - h->lower < nbytes + sizeof(index_t)) { 181 status = __bt_split(t, h, NULL, data, dflags, nbytes, index); 182 if (status == RET_SUCCESS) 183 ++t->bt_nrecs; 184 return (status); 185 } 186 187 if (index < (nxtindex = NEXTINDEX(h))) 188 bcopy(h->linp + index, h->linp + index + 1, 189 (nxtindex - index) * sizeof(index_t)); 190 h->lower += sizeof(index_t); 191 192 h->linp[index] = h->upper -= nbytes; 193 dest = (char *)h + h->upper; 194 WR_RLEAF(dest, data, dflags); 195 196 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 197 ++t->bt_nrecs; 198 return (RET_SUCCESS); 199 } 200