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