150995Sbostic /*- 250995Sbostic * Copyright (c) 1990 The Regents of the University of California. 350995Sbostic * All rights reserved. 450995Sbostic * 550995Sbostic * %sccs.include.redist.c% 650995Sbostic */ 750995Sbostic 850995Sbostic #if defined(LIBC_SCCS) && !defined(lint) 9*56041Sbostic static char sccsid[] = "@(#)rec_put.c 5.4 (Berkeley) 08/26/92"; 1050995Sbostic #endif /* LIBC_SCCS and not lint */ 1150995Sbostic 1250995Sbostic #include <sys/types.h> 1350995Sbostic #include <errno.h> 1450995Sbostic #include <db.h> 1550995Sbostic #include <stdio.h> 1650995Sbostic #include <stdlib.h> 1750995Sbostic #include <string.h> 1851089Sbostic #include "recno.h" 1950995Sbostic 2050995Sbostic /* 2150995Sbostic * __REC_PUT -- Add a recno item to the tree. 2250995Sbostic * 2350995Sbostic * Parameters: 2450995Sbostic * dbp: pointer to access method 2550995Sbostic * key: key 2650995Sbostic * data: data 2751089Sbostic * flag: R_APPEND, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 2850995Sbostic * 2950995Sbostic * Returns: 3050995Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 3150995Sbostic * tree and R_NOOVERWRITE specified. 3250995Sbostic */ 3350995Sbostic int 3450995Sbostic __rec_put(dbp, key, data, flags) 3550995Sbostic const DB *dbp; 3650995Sbostic const DBT *key, *data; 3750995Sbostic u_int flags; 3850995Sbostic { 3950995Sbostic BTREE *t; 4050995Sbostic DBT tdata; 4150995Sbostic recno_t nrec; 4250995Sbostic int status; 4350995Sbostic 4451089Sbostic t = dbp->internal; 4551089Sbostic 4651089Sbostic switch (flags) { 4751089Sbostic case R_APPEND: 4851089Sbostic nrec = t->bt_nrecs + 1; 4951089Sbostic break; 5051089Sbostic case R_CURSOR: 5151089Sbostic if (ISSET(t, BTF_DELCRSR)) 5251089Sbostic goto einval; 5351089Sbostic nrec = t->bt_rcursor; 5451089Sbostic break; 5554282Sbostic case R_IAFTER: 5654282Sbostic if ((nrec = *(recno_t *)key->data) == 0) { 5754282Sbostic nrec = 1; 5854282Sbostic flags = R_IBEFORE; 5954282Sbostic } 6054282Sbostic break; 6151089Sbostic case 0: 6251089Sbostic case R_IBEFORE: 6351089Sbostic if ((nrec = *(recno_t *)key->data) == 0) 6451089Sbostic goto einval; 6551089Sbostic break; 6651089Sbostic case R_NOOVERWRITE: 6751089Sbostic if ((nrec = *(recno_t *)key->data) == 0) 6851089Sbostic goto einval; 6951089Sbostic if (nrec <= t->bt_nrecs) 7051089Sbostic return (RET_SPECIAL); 7151089Sbostic break; 7251089Sbostic default: 7351089Sbostic einval: errno = EINVAL; 7450995Sbostic return (RET_ERROR); 7550995Sbostic } 7650995Sbostic 7750995Sbostic /* 7854282Sbostic * Make sure that records up to and including the put record are 7954282Sbostic * already in the database. If skipping records, create empty ones. 8050995Sbostic */ 8150995Sbostic if (nrec > t->bt_nrecs) { 8251089Sbostic if (t->bt_irec(t, nrec) == RET_ERROR) 8351089Sbostic return (RET_ERROR); 8451089Sbostic if (nrec > t->bt_nrecs + 1) { 8551089Sbostic tdata.data = NULL; 8651089Sbostic tdata.size = 0; 87*56041Sbostic while (nrec > t->bt_nrecs + 1) 8854282Sbostic if (__rec_iput(t, 89*56041Sbostic t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 9051089Sbostic return (RET_ERROR); 9150995Sbostic } 9250995Sbostic } 9350995Sbostic --nrec; 9450995Sbostic if ((status = __rec_iput(t, nrec, data, flags)) == RET_SUCCESS) 9550995Sbostic SET(t, BTF_MODIFIED); 9650995Sbostic return (status); 9750995Sbostic } 9850995Sbostic 9950995Sbostic /* 10050995Sbostic * __REC_IPUT -- Add a recno item to the tree. 10150995Sbostic * 10250995Sbostic * Parameters: 10350995Sbostic * t: tree 10450995Sbostic * nrec: record number 10550995Sbostic * data: data 10650995Sbostic * 10750995Sbostic * Returns: 10851089Sbostic * RET_ERROR, RET_SUCCESS 10950995Sbostic */ 11050995Sbostic int 11150995Sbostic __rec_iput(t, nrec, data, flags) 11250995Sbostic BTREE *t; 11350995Sbostic recno_t nrec; 11450995Sbostic const DBT *data; 11550995Sbostic u_int flags; 11650995Sbostic { 11750995Sbostic DBT tdata; 11850995Sbostic EPG *e; 11950995Sbostic PAGE *h; 12050995Sbostic index_t index, nxtindex; 12150995Sbostic pgno_t pg; 12250995Sbostic size_t nbytes; 12351089Sbostic int dflags, status; 12450995Sbostic char *dest, db[NOVFLSIZE]; 12550995Sbostic 12650995Sbostic /* 12750995Sbostic * If the data won't fit on a page, store it on indirect pages. 12850995Sbostic * 12950995Sbostic * XXX 13050995Sbostic * If the insert fails later on, these pages aren't recovered. 13150995Sbostic */ 13251089Sbostic if (data->size > t->bt_ovflsize) { 13350995Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 13450995Sbostic return (RET_ERROR); 13550995Sbostic tdata.data = db; 13650995Sbostic tdata.size = NOVFLSIZE; 13750995Sbostic *(pgno_t *)db = pg; 13850995Sbostic *(size_t *)(db + sizeof(pgno_t)) = data->size; 13950995Sbostic dflags = P_BIGDATA; 14050995Sbostic data = &tdata; 14150995Sbostic } else 14250995Sbostic dflags = 0; 14350995Sbostic 14450995Sbostic /* __rec_search pins the returned page. */ 145*56041Sbostic if ((e = __rec_search(t, nrec, 146*56041Sbostic nrec > t->bt_nrecs ? SINSERT : SEARCH)) == NULL) 14750995Sbostic return (RET_ERROR); 14850995Sbostic 14950995Sbostic h = e->page; 15050995Sbostic index = e->index; 15150995Sbostic 15250995Sbostic /* 15351089Sbostic * Add the specified key/data pair to the tree. The R_IAFTER and 15451089Sbostic * R_IBEFORE flags insert the key after/before the specified key. 15550995Sbostic * 15650995Sbostic * Pages are split as required. 15750995Sbostic */ 15850995Sbostic switch (flags) { 15950995Sbostic case R_IAFTER: 16050995Sbostic ++index; 16150995Sbostic break; 16250995Sbostic case R_IBEFORE: 16350995Sbostic break; 16450995Sbostic default: 16551089Sbostic if (nrec < t->bt_nrecs && 16651089Sbostic __rec_dleaf(t, h, index) == RET_ERROR) { 16751089Sbostic BT_CLR(t); 16850995Sbostic mpool_put(t->bt_mp, h, 0); 16950995Sbostic return (RET_ERROR); 17050995Sbostic } 17150995Sbostic break; 17250995Sbostic } 17350995Sbostic 17450995Sbostic /* 17550995Sbostic * If not enough room, split the page. The split code will insert 17650995Sbostic * the key and data and unpin the current page. If inserting into 17750995Sbostic * the offset array, shift the pointers up. 17850995Sbostic */ 17950995Sbostic nbytes = NRLEAFDBT(data->size); 18051089Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t)) { 18151089Sbostic status = __bt_split(t, h, NULL, data, dflags, nbytes, index); 18251089Sbostic if (status == RET_SUCCESS) 18351089Sbostic ++t->bt_nrecs; 18451089Sbostic return (status); 18551089Sbostic } 18650995Sbostic 18750995Sbostic if (index < (nxtindex = NEXTINDEX(h))) 18850995Sbostic bcopy(h->linp + index, h->linp + index + 1, 18950995Sbostic (nxtindex - index) * sizeof(index_t)); 19050995Sbostic h->lower += sizeof(index_t); 19150995Sbostic 19250995Sbostic h->linp[index] = h->upper -= nbytes; 19350995Sbostic dest = (char *)h + h->upper; 19450995Sbostic WR_RLEAF(dest, data, dflags); 19550995Sbostic 19650995Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 19750995Sbostic ++t->bt_nrecs; 19850995Sbostic return (RET_SUCCESS); 19950995Sbostic } 200