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*58750Sbostic static char sccsid[] = "@(#)rec_put.c 5.11 (Berkeley) 03/19/93"; 1050995Sbostic #endif /* LIBC_SCCS and not lint */ 1150995Sbostic 1250995Sbostic #include <sys/types.h> 1356758Sbostic 1450995Sbostic #include <errno.h> 1550995Sbostic #include <stdio.h> 1650995Sbostic #include <stdlib.h> 1750995Sbostic #include <string.h> 1856758Sbostic 1957933Sbostic #include <db.h> 2051089Sbostic #include "recno.h" 2150995Sbostic 2250995Sbostic /* 2350995Sbostic * __REC_PUT -- Add a recno item to the tree. 2450995Sbostic * 2550995Sbostic * Parameters: 2650995Sbostic * dbp: pointer to access method 2750995Sbostic * key: key 2850995Sbostic * data: data 2956758Sbostic * flag: R_CURSORLOG, R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE 3050995Sbostic * 3150995Sbostic * Returns: 3250995Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 3350995Sbostic * tree and R_NOOVERWRITE specified. 3450995Sbostic */ 3550995Sbostic int 3650995Sbostic __rec_put(dbp, key, data, flags) 3750995Sbostic const DB *dbp; 3856758Sbostic DBT *key; 3956758Sbostic const DBT *data; 4050995Sbostic u_int flags; 4150995Sbostic { 4250995Sbostic BTREE *t; 4350995Sbostic DBT tdata; 4450995Sbostic recno_t nrec; 4550995Sbostic int status; 4650995Sbostic 4751089Sbostic t = dbp->internal; 4851089Sbostic 4951089Sbostic switch (flags) { 5051089Sbostic case R_CURSOR: 5156758Sbostic if (!ISSET(t, BTF_SEQINIT)) 5251089Sbostic goto einval; 5351089Sbostic nrec = t->bt_rcursor; 5451089Sbostic break; 5556758Sbostic case R_CURSORLOG: 5656758Sbostic nrec = t->bt_rcursor + 1; 5756758Sbostic SET(t, BTF_SEQINIT); 5856758Sbostic break; 5956758Sbostic case R_SETCURSOR: 6056758Sbostic if ((nrec = *(recno_t *)key->data) == 0) 6156758Sbostic goto einval; 6256758Sbostic break; 6354282Sbostic case R_IAFTER: 6454282Sbostic if ((nrec = *(recno_t *)key->data) == 0) { 6554282Sbostic nrec = 1; 6654282Sbostic flags = R_IBEFORE; 6754282Sbostic } 6854282Sbostic break; 6951089Sbostic case 0: 7051089Sbostic case R_IBEFORE: 7151089Sbostic if ((nrec = *(recno_t *)key->data) == 0) 7251089Sbostic goto einval; 7351089Sbostic break; 7451089Sbostic case R_NOOVERWRITE: 7551089Sbostic if ((nrec = *(recno_t *)key->data) == 0) 7651089Sbostic goto einval; 7751089Sbostic if (nrec <= t->bt_nrecs) 7851089Sbostic return (RET_SPECIAL); 7951089Sbostic break; 8051089Sbostic default: 8151089Sbostic einval: errno = EINVAL; 8250995Sbostic return (RET_ERROR); 8350995Sbostic } 8450995Sbostic 8550995Sbostic /* 8654282Sbostic * Make sure that records up to and including the put record are 8754282Sbostic * already in the database. If skipping records, create empty ones. 8850995Sbostic */ 8950995Sbostic if (nrec > t->bt_nrecs) { 90*58750Sbostic if (!ISSET(t, BTF_EOF | BTF_RINMEM) && 91*58750Sbostic t->bt_irec(t, nrec) == RET_ERROR) 9251089Sbostic return (RET_ERROR); 9351089Sbostic if (nrec > t->bt_nrecs + 1) { 9451089Sbostic tdata.data = NULL; 9551089Sbostic tdata.size = 0; 9656041Sbostic while (nrec > t->bt_nrecs + 1) 9754282Sbostic if (__rec_iput(t, 9856041Sbostic t->bt_nrecs, &tdata, 0) != RET_SUCCESS) 9951089Sbostic return (RET_ERROR); 10050995Sbostic } 10150995Sbostic } 10256758Sbostic 10356758Sbostic if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS) 10456758Sbostic return (status); 10556758Sbostic 10656758Sbostic SET(t, BTF_MODIFIED); 10756758Sbostic switch(flags) { 10856758Sbostic case R_CURSORLOG: 10956758Sbostic ++t->bt_rcursor; 11056758Sbostic break; 11156758Sbostic case R_SETCURSOR: 11256758Sbostic t->bt_rcursor = nrec; 11356758Sbostic break; 11456758Sbostic } 11556758Sbostic 11656758Sbostic return (__rec_ret(t, NULL, nrec, key, NULL)); 11750995Sbostic } 11850995Sbostic 11950995Sbostic /* 12050995Sbostic * __REC_IPUT -- Add a recno item to the tree. 12150995Sbostic * 12250995Sbostic * Parameters: 12350995Sbostic * t: tree 12450995Sbostic * nrec: record number 12550995Sbostic * data: data 12650995Sbostic * 12750995Sbostic * Returns: 12851089Sbostic * RET_ERROR, RET_SUCCESS 12950995Sbostic */ 13050995Sbostic int 13150995Sbostic __rec_iput(t, nrec, data, flags) 13250995Sbostic BTREE *t; 13350995Sbostic recno_t nrec; 13450995Sbostic const DBT *data; 13550995Sbostic u_int flags; 13650995Sbostic { 13750995Sbostic DBT tdata; 13850995Sbostic EPG *e; 13950995Sbostic PAGE *h; 14057988Sbostic indx_t index, nxtindex; 14150995Sbostic pgno_t pg; 14250995Sbostic size_t nbytes; 14351089Sbostic int dflags, status; 14450995Sbostic char *dest, db[NOVFLSIZE]; 14550995Sbostic 14650995Sbostic /* 14750995Sbostic * If the data won't fit on a page, store it on indirect pages. 14850995Sbostic * 14950995Sbostic * XXX 15050995Sbostic * If the insert fails later on, these pages aren't recovered. 15150995Sbostic */ 15251089Sbostic if (data->size > t->bt_ovflsize) { 15350995Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 15450995Sbostic return (RET_ERROR); 15550995Sbostic tdata.data = db; 15650995Sbostic tdata.size = NOVFLSIZE; 15750995Sbostic *(pgno_t *)db = pg; 15850995Sbostic *(size_t *)(db + sizeof(pgno_t)) = data->size; 15950995Sbostic dflags = P_BIGDATA; 16050995Sbostic data = &tdata; 16150995Sbostic } else 16250995Sbostic dflags = 0; 16350995Sbostic 16450995Sbostic /* __rec_search pins the returned page. */ 16556041Sbostic if ((e = __rec_search(t, nrec, 16656997Sbostic nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? 16756997Sbostic SINSERT : SEARCH)) == NULL) 16850995Sbostic return (RET_ERROR); 16950995Sbostic 17050995Sbostic h = e->page; 17150995Sbostic index = e->index; 17250995Sbostic 17350995Sbostic /* 17451089Sbostic * Add the specified key/data pair to the tree. The R_IAFTER and 17551089Sbostic * R_IBEFORE flags insert the key after/before the specified key. 17650995Sbostic * 17750995Sbostic * Pages are split as required. 17850995Sbostic */ 17950995Sbostic switch (flags) { 18050995Sbostic case R_IAFTER: 18150995Sbostic ++index; 18250995Sbostic break; 18350995Sbostic case R_IBEFORE: 18450995Sbostic break; 18550995Sbostic default: 18651089Sbostic if (nrec < t->bt_nrecs && 18751089Sbostic __rec_dleaf(t, h, index) == RET_ERROR) { 18850995Sbostic mpool_put(t->bt_mp, h, 0); 18950995Sbostic return (RET_ERROR); 19050995Sbostic } 19150995Sbostic break; 19250995Sbostic } 19350995Sbostic 19450995Sbostic /* 19550995Sbostic * If not enough room, split the page. The split code will insert 19650995Sbostic * the key and data and unpin the current page. If inserting into 19750995Sbostic * the offset array, shift the pointers up. 19850995Sbostic */ 19950995Sbostic nbytes = NRLEAFDBT(data->size); 20057988Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_t)) { 20151089Sbostic status = __bt_split(t, h, NULL, data, dflags, nbytes, index); 20251089Sbostic if (status == RET_SUCCESS) 20351089Sbostic ++t->bt_nrecs; 20451089Sbostic return (status); 20551089Sbostic } 20650995Sbostic 20750995Sbostic if (index < (nxtindex = NEXTINDEX(h))) 20858015Sbostic memmove(h->linp + index + 1, h->linp + index, 20957988Sbostic (nxtindex - index) * sizeof(indx_t)); 21057988Sbostic h->lower += sizeof(indx_t); 21150995Sbostic 21250995Sbostic h->linp[index] = h->upper -= nbytes; 21350995Sbostic dest = (char *)h + h->upper; 21450995Sbostic WR_RLEAF(dest, data, dflags); 21550995Sbostic 21650995Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 21750995Sbostic ++t->bt_nrecs; 21850995Sbostic return (RET_SUCCESS); 21950995Sbostic } 220