/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1990, 1993, 19944* The Regents of the University of California. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the University nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/3031#include <sys/types.h>3233#include <errno.h>34#include <stdio.h>35#include <stdlib.h>36#include <string.h>3738#include <db.h>39#include "recno.h"4041/*42* __REC_PUT -- Add a recno item to the tree.43*44* Parameters:45* dbp: pointer to access method46* key: key47* data: data48* flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE49*50* Returns:51* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is52* already in the tree and R_NOOVERWRITE specified.53*/54int55__rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)56{57BTREE *t;58DBT fdata, tdata;59recno_t nrec;60int status;6162t = dbp->internal;6364/* Toss any page pinned across calls. */65if (t->bt_pinned != NULL) {66mpool_put(t->bt_mp, t->bt_pinned, 0);67t->bt_pinned = NULL;68}6970/*71* If using fixed-length records, and the record is long, return72* EINVAL. If it's short, pad it out. Use the record data return73* memory, it's only short-term.74*/75if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {76if (data->size > t->bt_reclen)77goto einval;7879if (t->bt_rdata.size < t->bt_reclen) {80t->bt_rdata.data =81reallocf(t->bt_rdata.data, t->bt_reclen);82if (t->bt_rdata.data == NULL)83return (RET_ERROR);84t->bt_rdata.size = t->bt_reclen;85}86memmove(t->bt_rdata.data, data->data, data->size);87memset((char *)t->bt_rdata.data + data->size,88t->bt_bval, t->bt_reclen - data->size);89fdata.data = t->bt_rdata.data;90fdata.size = t->bt_reclen;91} else {92fdata.data = data->data;93fdata.size = data->size;94}9596switch (flags) {97case R_CURSOR:98if (!F_ISSET(&t->bt_cursor, CURS_INIT))99goto einval;100nrec = t->bt_cursor.rcursor;101break;102case R_SETCURSOR:103if ((nrec = *(recno_t *)key->data) == 0)104goto einval;105break;106case R_IAFTER:107if ((nrec = *(recno_t *)key->data) == 0) {108nrec = 1;109flags = R_IBEFORE;110}111break;112case 0:113case R_IBEFORE:114if ((nrec = *(recno_t *)key->data) == 0)115goto einval;116break;117case R_NOOVERWRITE:118if ((nrec = *(recno_t *)key->data) == 0)119goto einval;120if (nrec <= t->bt_nrecs)121return (RET_SPECIAL);122break;123default:124einval: errno = EINVAL;125return (RET_ERROR);126}127128/*129* Make sure that records up to and including the put record are130* already in the database. If skipping records, create empty ones.131*/132if (nrec > t->bt_nrecs) {133if (!F_ISSET(t, R_EOF | R_INMEM) &&134t->bt_irec(t, nrec) == RET_ERROR)135return (RET_ERROR);136if (nrec > t->bt_nrecs + 1) {137if (F_ISSET(t, R_FIXLEN)) {138if ((tdata.data = malloc(t->bt_reclen)) == NULL)139return (RET_ERROR);140tdata.size = t->bt_reclen;141memset(tdata.data, t->bt_bval, tdata.size);142} else {143tdata.data = NULL;144tdata.size = 0;145}146while (nrec > t->bt_nrecs + 1)147if (__rec_iput(t,148t->bt_nrecs, &tdata, 0) != RET_SUCCESS)149return (RET_ERROR);150if (F_ISSET(t, R_FIXLEN))151free(tdata.data);152}153}154155if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)156return (status);157158switch (flags) {159case R_IAFTER:160nrec++;161break;162case R_SETCURSOR:163t->bt_cursor.rcursor = nrec;164break;165}166167F_SET(t, R_MODIFIED);168return (__rec_ret(t, NULL, nrec, key, NULL));169}170171/*172* __REC_IPUT -- Add a recno item to the tree.173*174* Parameters:175* t: tree176* nrec: record number177* data: data178*179* Returns:180* RET_ERROR, RET_SUCCESS181*/182int183__rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)184{185DBT tdata;186EPG *e;187PAGE *h;188indx_t idx, nxtindex;189pgno_t pg;190u_int32_t nbytes;191int dflags, status;192char *dest, db[NOVFLSIZE];193194/*195* If the data won't fit on a page, store it on indirect pages.196*197* XXX198* If the insert fails later on, these pages aren't recovered.199*/200if (data->size > t->bt_ovflsize) {201if (__ovfl_put(t, data, &pg) == RET_ERROR)202return (RET_ERROR);203tdata.data = db;204tdata.size = NOVFLSIZE;205memcpy(db, &pg, sizeof(pg));206*(u_int32_t *)(db + sizeof(pgno_t)) = data->size;207dflags = P_BIGDATA;208data = &tdata;209} else210dflags = 0;211212/* __rec_search pins the returned page. */213if ((e = __rec_search(t, nrec,214nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?215SINSERT : SEARCH)) == NULL)216return (RET_ERROR);217218h = e->page;219idx = e->index;220221/*222* Add the specified key/data pair to the tree. The R_IAFTER and223* R_IBEFORE flags insert the key after/before the specified key.224*225* Pages are split as required.226*/227switch (flags) {228case R_IAFTER:229++idx;230break;231case R_IBEFORE:232break;233default:234if (nrec < t->bt_nrecs &&235__rec_dleaf(t, h, idx) == RET_ERROR) {236mpool_put(t->bt_mp, h, 0);237return (RET_ERROR);238}239break;240}241242/*243* If not enough room, split the page. The split code will insert244* the key and data and unpin the current page. If inserting into245* the offset array, shift the pointers up.246*/247nbytes = NRLEAFDBT(data->size);248if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {249status = __bt_split(t, h, NULL, data, dflags, nbytes, idx);250if (status == RET_SUCCESS)251++t->bt_nrecs;252return (status);253}254255if (idx < (nxtindex = NEXTINDEX(h)))256memmove(h->linp + idx + 1, h->linp + idx,257(nxtindex - idx) * sizeof(indx_t));258h->lower += sizeof(indx_t);259260h->linp[idx] = h->upper -= nbytes;261dest = (char *)h + h->upper;262WR_RLEAF(dest, data, dflags);263264++t->bt_nrecs;265F_SET(t, B_MODIFIED);266mpool_put(t->bt_mp, h, MPOOL_DIRTY);267268return (RET_SUCCESS);269}270271272