150995Sbostic /*-
261207Sbostic * Copyright (c) 1990, 1993
361207Sbostic * The Regents of the University of California. All rights reserved.
450995Sbostic *
550995Sbostic * %sccs.include.redist.c%
650995Sbostic */
750995Sbostic
850995Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*66293Sbostic static char sccsid[] = "@(#)rec_put.c 8.3 (Berkeley) 03/01/94";
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
2959865Sbostic * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
3050995Sbostic *
3150995Sbostic * Returns:
3259865Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
3359865Sbostic * already in the tree and R_NOOVERWRITE specified.
3450995Sbostic */
3550995Sbostic int
__rec_put(dbp,key,data,flags)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
4964461Sbostic /* Toss any page pinned across calls. */
5064461Sbostic if (t->bt_pinned != NULL) {
5164461Sbostic mpool_put(t->bt_mp, t->bt_pinned, 0);
5264461Sbostic t->bt_pinned = NULL;
5364461Sbostic }
5464461Sbostic
5551089Sbostic switch (flags) {
5651089Sbostic case R_CURSOR:
5760053Sbostic if (!ISSET(t, B_SEQINIT))
5851089Sbostic goto einval;
5951089Sbostic nrec = t->bt_rcursor;
6051089Sbostic break;
6156758Sbostic case R_SETCURSOR:
6256758Sbostic if ((nrec = *(recno_t *)key->data) == 0)
6356758Sbostic goto einval;
6456758Sbostic break;
6554282Sbostic case R_IAFTER:
6654282Sbostic if ((nrec = *(recno_t *)key->data) == 0) {
6754282Sbostic nrec = 1;
6854282Sbostic flags = R_IBEFORE;
6954282Sbostic }
7054282Sbostic break;
7151089Sbostic case 0:
7251089Sbostic case R_IBEFORE:
7351089Sbostic if ((nrec = *(recno_t *)key->data) == 0)
7451089Sbostic goto einval;
7551089Sbostic break;
7651089Sbostic case R_NOOVERWRITE:
7751089Sbostic if ((nrec = *(recno_t *)key->data) == 0)
7851089Sbostic goto einval;
7951089Sbostic if (nrec <= t->bt_nrecs)
8051089Sbostic return (RET_SPECIAL);
8151089Sbostic break;
8251089Sbostic default:
8351089Sbostic einval: errno = EINVAL;
8450995Sbostic return (RET_ERROR);
8550995Sbostic }
8650995Sbostic
8750995Sbostic /*
8854282Sbostic * Make sure that records up to and including the put record are
8954282Sbostic * already in the database. If skipping records, create empty ones.
9050995Sbostic */
9150995Sbostic if (nrec > t->bt_nrecs) {
9260053Sbostic if (!ISSET(t, R_EOF | R_INMEM) &&
9358750Sbostic t->bt_irec(t, nrec) == RET_ERROR)
9451089Sbostic return (RET_ERROR);
9551089Sbostic if (nrec > t->bt_nrecs + 1) {
96*66293Sbostic if (ISSET(t, R_FIXLEN)) {
97*66293Sbostic if ((tdata.data =
98*66293Sbostic (void *)malloc(t->bt_reclen)) == NULL)
99*66293Sbostic return (RET_ERROR);
100*66293Sbostic tdata.size = t->bt_reclen;
101*66293Sbostic memset(tdata.data, t->bt_bval, tdata.size);
102*66293Sbostic } else {
103*66293Sbostic tdata.data = NULL;
104*66293Sbostic tdata.size = 0;
105*66293Sbostic }
10656041Sbostic while (nrec > t->bt_nrecs + 1)
10754282Sbostic if (__rec_iput(t,
10856041Sbostic t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
10951089Sbostic return (RET_ERROR);
110*66293Sbostic if (ISSET(t, R_FIXLEN))
111*66293Sbostic free(tdata.data);
11250995Sbostic }
11350995Sbostic }
11456758Sbostic
11556758Sbostic if ((status = __rec_iput(t, nrec - 1, data, flags)) != RET_SUCCESS)
11656758Sbostic return (status);
11756758Sbostic
11859865Sbostic if (flags == R_SETCURSOR)
11956758Sbostic t->bt_rcursor = nrec;
12056758Sbostic
12160053Sbostic SET(t, R_MODIFIED);
12256758Sbostic return (__rec_ret(t, NULL, nrec, key, NULL));
12350995Sbostic }
12450995Sbostic
12550995Sbostic /*
12650995Sbostic * __REC_IPUT -- Add a recno item to the tree.
12750995Sbostic *
12850995Sbostic * Parameters:
12950995Sbostic * t: tree
13050995Sbostic * nrec: record number
13150995Sbostic * data: data
13250995Sbostic *
13350995Sbostic * Returns:
13451089Sbostic * RET_ERROR, RET_SUCCESS
13550995Sbostic */
13650995Sbostic int
__rec_iput(t,nrec,data,flags)13750995Sbostic __rec_iput(t, nrec, data, flags)
13850995Sbostic BTREE *t;
13950995Sbostic recno_t nrec;
14050995Sbostic const DBT *data;
14150995Sbostic u_int flags;
14250995Sbostic {
14350995Sbostic DBT tdata;
14450995Sbostic EPG *e;
14550995Sbostic PAGE *h;
14657988Sbostic indx_t index, nxtindex;
14750995Sbostic pgno_t pg;
14850995Sbostic size_t nbytes;
14951089Sbostic int dflags, status;
15050995Sbostic char *dest, db[NOVFLSIZE];
15150995Sbostic
15250995Sbostic /*
15350995Sbostic * If the data won't fit on a page, store it on indirect pages.
15450995Sbostic *
15550995Sbostic * XXX
15650995Sbostic * If the insert fails later on, these pages aren't recovered.
15750995Sbostic */
15851089Sbostic if (data->size > t->bt_ovflsize) {
15950995Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR)
16050995Sbostic return (RET_ERROR);
16150995Sbostic tdata.data = db;
16250995Sbostic tdata.size = NOVFLSIZE;
16350995Sbostic *(pgno_t *)db = pg;
16450995Sbostic *(size_t *)(db + sizeof(pgno_t)) = data->size;
16550995Sbostic dflags = P_BIGDATA;
16650995Sbostic data = &tdata;
16750995Sbostic } else
16850995Sbostic dflags = 0;
16950995Sbostic
17050995Sbostic /* __rec_search pins the returned page. */
17156041Sbostic if ((e = __rec_search(t, nrec,
17256997Sbostic nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
17356997Sbostic SINSERT : SEARCH)) == NULL)
17450995Sbostic return (RET_ERROR);
17550995Sbostic
17650995Sbostic h = e->page;
17750995Sbostic index = e->index;
17850995Sbostic
17950995Sbostic /*
18051089Sbostic * Add the specified key/data pair to the tree. The R_IAFTER and
18151089Sbostic * R_IBEFORE flags insert the key after/before the specified key.
18250995Sbostic *
18350995Sbostic * Pages are split as required.
18450995Sbostic */
18550995Sbostic switch (flags) {
18650995Sbostic case R_IAFTER:
18750995Sbostic ++index;
18850995Sbostic break;
18950995Sbostic case R_IBEFORE:
19050995Sbostic break;
19150995Sbostic default:
19251089Sbostic if (nrec < t->bt_nrecs &&
19351089Sbostic __rec_dleaf(t, h, index) == RET_ERROR) {
19450995Sbostic mpool_put(t->bt_mp, h, 0);
19550995Sbostic return (RET_ERROR);
19650995Sbostic }
19750995Sbostic break;
19850995Sbostic }
19950995Sbostic
20050995Sbostic /*
20150995Sbostic * If not enough room, split the page. The split code will insert
20250995Sbostic * the key and data and unpin the current page. If inserting into
20350995Sbostic * the offset array, shift the pointers up.
20450995Sbostic */
20550995Sbostic nbytes = NRLEAFDBT(data->size);
20657988Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
20751089Sbostic status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
20851089Sbostic if (status == RET_SUCCESS)
20951089Sbostic ++t->bt_nrecs;
21051089Sbostic return (status);
21151089Sbostic }
21250995Sbostic
21350995Sbostic if (index < (nxtindex = NEXTINDEX(h)))
21458015Sbostic memmove(h->linp + index + 1, h->linp + index,
21557988Sbostic (nxtindex - index) * sizeof(indx_t));
21657988Sbostic h->lower += sizeof(indx_t);
21750995Sbostic
21850995Sbostic h->linp[index] = h->upper -= nbytes;
21950995Sbostic dest = (char *)h + h->upper;
22050995Sbostic WR_RLEAF(dest, data, dflags);
22150995Sbostic
22260053Sbostic ++t->bt_nrecs;
22360053Sbostic SET(t, B_MODIFIED);
22450995Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY);
22560053Sbostic
22650995Sbostic return (RET_SUCCESS);
22750995Sbostic }
228