/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * %sccs.include.redist.c% */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rec_put.c 5.13 (Berkeley) 05/16/93"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include #include #include #include "recno.h" /* * __REC_PUT -- Add a recno item to the tree. * * Parameters: * dbp: pointer to access method * key: key * data: data * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE * * Returns: * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is * already in the tree and R_NOOVERWRITE specified. */ int __rec_put(dbp, key, data, flags) const DB *dbp; DBT *key; const DBT *data; u_int flags; { BTREE *t; DBT tdata; recno_t nrec; int status; t = dbp->internal; switch (flags) { case R_CURSOR: if (!ISSET(t, B_SEQINIT)) goto einval; nrec = t->bt_rcursor; break; case R_SETCURSOR: if ((nrec = *(recno_t *)key->data) == 0) goto einval; break; case R_IAFTER: if ((nrec = *(recno_t *)key->data) == 0) { nrec = 1; flags = R_IBEFORE; } break; case 0: case R_IBEFORE: if ((nrec = *(recno_t *)key->data) == 0) goto einval; break; case R_NOOVERWRITE: if ((nrec = *(recno_t *)key->data) == 0) goto einval; if (nrec <= t->bt_nrecs) return (RET_SPECIAL); break; default: einval: errno = EINVAL; return (RET_ERROR); } /* * Make sure that records up to and including the put record are * already in the database. If skipping records, create empty ones. */ if (nrec > t->bt_nrecs) { if (!ISSET(t, R_EOF | R_INMEM) && t->bt_irec(t, nrec) == RET_ERROR) return (RET_ERROR); if (nrec > t->bt_nrecs + 1) { tdata.data = NULL; tdata.size = 0; while (nrec > t->bt_nrecs + 1) if (__rec_iput(t, t->bt_nrecs, &tdata, 0) != RET_SUCCESS) return (RET_ERROR); } } if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS) return (status); if (flags == R_SETCURSOR) t->bt_rcursor = nrec; SET(t, R_MODIFIED); return (__rec_ret(t, NULL, nrec, key, NULL)); } /* * __REC_IPUT -- Add a recno item to the tree. * * Parameters: * t: tree * nrec: record number * data: data * * Returns: * RET_ERROR, RET_SUCCESS */ int __rec_iput(t, nrec, data, flags) BTREE *t; recno_t nrec; const DBT *data; u_int flags; { DBT tdata; EPG *e; PAGE *h; indx_t index, nxtindex; pgno_t pg; size_t nbytes; int dflags, status; char *dest, db[NOVFLSIZE]; /* * If the data won't fit on a page, store it on indirect pages. * * XXX * If the insert fails later on, these pages aren't recovered. */ if (data->size > t->bt_ovflsize) { if (__ovfl_put(t, data, &pg) == RET_ERROR) return (RET_ERROR); tdata.data = db; tdata.size = NOVFLSIZE; *(pgno_t *)db = pg; *(size_t *)(db + sizeof(pgno_t)) = data->size; dflags = P_BIGDATA; data = &tdata; } else dflags = 0; /* __rec_search pins the returned page. */ if ((e = __rec_search(t, nrec, nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ? SINSERT : SEARCH)) == NULL) return (RET_ERROR); h = e->page; index = e->index; /* * Add the specified key/data pair to the tree. The R_IAFTER and * R_IBEFORE flags insert the key after/before the specified key. * * Pages are split as required. */ switch (flags) { case R_IAFTER: ++index; break; case R_IBEFORE: break; default: if (nrec < t->bt_nrecs && __rec_dleaf(t, h, index) == RET_ERROR) { mpool_put(t->bt_mp, h, 0); return (RET_ERROR); } break; } /* * If not enough room, split the page. The split code will insert * the key and data and unpin the current page. If inserting into * the offset array, shift the pointers up. */ nbytes = NRLEAFDBT(data->size); if (h->upper - h->lower < nbytes + sizeof(indx_t)) { status = __bt_split(t, h, NULL, data, dflags, nbytes, index); if (status == RET_SUCCESS) ++t->bt_nrecs; return (status); } if (index < (nxtindex = NEXTINDEX(h))) memmove(h->linp + index + 1, h->linp + index, (nxtindex - index) * sizeof(indx_t)); h->lower += sizeof(indx_t); h->linp[index] = h->upper -= nbytes; dest = (char *)h + h->upper; WR_RLEAF(dest, data, dflags); ++t->bt_nrecs; SET(t, B_MODIFIED); mpool_put(t->bt_mp, h, MPOOL_DIRTY); return (RET_SUCCESS); }