xref: /minix3/lib/libc/db/recno/rec_put.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: rec_put.c,v 1.21 2013/12/14 18:04:56 christos Exp $	*/
22639ae9bSBen Gras 
32639ae9bSBen Gras /*-
42639ae9bSBen Gras  * Copyright (c) 1990, 1993, 1994
52639ae9bSBen Gras  *	The Regents of the University of California.  All rights reserved.
62639ae9bSBen Gras  *
72639ae9bSBen Gras  * Redistribution and use in source and binary forms, with or without
82639ae9bSBen Gras  * modification, are permitted provided that the following conditions
92639ae9bSBen Gras  * are met:
102639ae9bSBen Gras  * 1. Redistributions of source code must retain the above copyright
112639ae9bSBen Gras  *    notice, this list of conditions and the following disclaimer.
122639ae9bSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
132639ae9bSBen Gras  *    notice, this list of conditions and the following disclaimer in the
142639ae9bSBen Gras  *    documentation and/or other materials provided with the distribution.
152639ae9bSBen Gras  * 3. Neither the name of the University nor the names of its contributors
162639ae9bSBen Gras  *    may be used to endorse or promote products derived from this software
172639ae9bSBen Gras  *    without specific prior written permission.
182639ae9bSBen Gras  *
192639ae9bSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
202639ae9bSBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212639ae9bSBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222639ae9bSBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
232639ae9bSBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
242639ae9bSBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
252639ae9bSBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
262639ae9bSBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272639ae9bSBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
282639ae9bSBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
292639ae9bSBen Gras  * SUCH DAMAGE.
302639ae9bSBen Gras  */
312639ae9bSBen Gras 
322639ae9bSBen Gras #if HAVE_NBTOOL_CONFIG_H
332639ae9bSBen Gras #include "nbtool_config.h"
342639ae9bSBen Gras #endif
352639ae9bSBen Gras 
362639ae9bSBen Gras #include <sys/cdefs.h>
37*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: rec_put.c,v 1.21 2013/12/14 18:04:56 christos Exp $");
382639ae9bSBen Gras 
392639ae9bSBen Gras #include "namespace.h"
402639ae9bSBen Gras #include <sys/types.h>
412639ae9bSBen Gras 
422639ae9bSBen Gras #include <assert.h>
432639ae9bSBen Gras #include <errno.h>
442639ae9bSBen Gras #include <stdio.h>
452639ae9bSBen Gras #include <stdlib.h>
462639ae9bSBen Gras #include <string.h>
472639ae9bSBen Gras 
482639ae9bSBen Gras #include <db.h>
492639ae9bSBen Gras #include "recno.h"
502639ae9bSBen Gras 
512639ae9bSBen Gras /*
522639ae9bSBen Gras  * __REC_PUT -- Add a recno item to the tree.
532639ae9bSBen Gras  *
542639ae9bSBen Gras  * Parameters:
552639ae9bSBen Gras  *	dbp:	pointer to access method
562639ae9bSBen Gras  *	key:	key
572639ae9bSBen Gras  *	data:	data
582639ae9bSBen Gras  *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
592639ae9bSBen Gras  *
602639ae9bSBen Gras  * Returns:
612639ae9bSBen Gras  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
622639ae9bSBen Gras  *	already in the tree and R_NOOVERWRITE specified.
632639ae9bSBen Gras  */
642639ae9bSBen Gras int
__rec_put(const DB * dbp,DBT * key,const DBT * data,u_int flags)652639ae9bSBen Gras __rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
662639ae9bSBen Gras {
672639ae9bSBen Gras 	BTREE *t;
682639ae9bSBen Gras 	DBT fdata, tdata;
692639ae9bSBen Gras 	recno_t nrec;
702639ae9bSBen Gras 	int status;
712639ae9bSBen Gras 
722639ae9bSBen Gras 	t = dbp->internal;
732639ae9bSBen Gras 
742639ae9bSBen Gras 	/* Toss any page pinned across calls. */
752639ae9bSBen Gras 	if (t->bt_pinned != NULL) {
762639ae9bSBen Gras 		mpool_put(t->bt_mp, t->bt_pinned, 0);
772639ae9bSBen Gras 		t->bt_pinned = NULL;
782639ae9bSBen Gras 	}
792639ae9bSBen Gras 
802639ae9bSBen Gras 	/*
812639ae9bSBen Gras 	 * If using fixed-length records, and the record is long, return
822639ae9bSBen Gras 	 * EINVAL.  If it's short, pad it out.  Use the record data return
832639ae9bSBen Gras 	 * memory, it's only short-term.
842639ae9bSBen Gras 	 */
852639ae9bSBen Gras 	if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
862639ae9bSBen Gras 		if (data->size > t->bt_reclen)
872639ae9bSBen Gras 			goto einval;
882639ae9bSBen Gras 
892639ae9bSBen Gras 		if (t->bt_rdata.size < t->bt_reclen) {
90*0a6a1f1dSLionel Sambuc 			void *np = realloc(t->bt_rdata.data, t->bt_reclen);
91*0a6a1f1dSLionel Sambuc 			if (np == NULL)
922639ae9bSBen Gras 				return (RET_ERROR);
93*0a6a1f1dSLionel Sambuc 			t->bt_rdata.data = np;
942639ae9bSBen Gras 			t->bt_rdata.size = t->bt_reclen;
952639ae9bSBen Gras 		}
962639ae9bSBen Gras 		memmove(t->bt_rdata.data, data->data, data->size);
972639ae9bSBen Gras 		memset((char *)t->bt_rdata.data + data->size,
982639ae9bSBen Gras 		    t->bt_bval, t->bt_reclen - data->size);
992639ae9bSBen Gras 		fdata.data = t->bt_rdata.data;
1002639ae9bSBen Gras 		fdata.size = t->bt_reclen;
1012639ae9bSBen Gras 	} else {
1022639ae9bSBen Gras 		fdata.data = data->data;
1032639ae9bSBen Gras 		fdata.size = data->size;
1042639ae9bSBen Gras 	}
1052639ae9bSBen Gras 
1062639ae9bSBen Gras 	switch (flags) {
1072639ae9bSBen Gras 	case R_CURSOR:
1082639ae9bSBen Gras 		if (!F_ISSET(&t->bt_cursor, CURS_INIT))
1092639ae9bSBen Gras 			goto einval;
1102639ae9bSBen Gras 		nrec = t->bt_cursor.rcursor;
1112639ae9bSBen Gras 		break;
1122639ae9bSBen Gras 	case R_SETCURSOR:
1132639ae9bSBen Gras 		if ((nrec = *(recno_t *)key->data) == 0)
1142639ae9bSBen Gras 			goto einval;
1152639ae9bSBen Gras 		break;
1162639ae9bSBen Gras 	case R_IAFTER:
1172639ae9bSBen Gras 		if ((nrec = *(recno_t *)key->data) == 0) {
1182639ae9bSBen Gras 			nrec = 1;
1192639ae9bSBen Gras 			flags = R_IBEFORE;
1202639ae9bSBen Gras 		}
1212639ae9bSBen Gras 		break;
1222639ae9bSBen Gras 	case 0:
1232639ae9bSBen Gras 	case R_IBEFORE:
1242639ae9bSBen Gras 		if ((nrec = *(recno_t *)key->data) == 0)
1252639ae9bSBen Gras 			goto einval;
1262639ae9bSBen Gras 		break;
1272639ae9bSBen Gras 	case R_NOOVERWRITE:
1282639ae9bSBen Gras 		if ((nrec = *(recno_t *)key->data) == 0)
1292639ae9bSBen Gras 			goto einval;
1302639ae9bSBen Gras 		if (nrec <= t->bt_nrecs)
1312639ae9bSBen Gras 			return (RET_SPECIAL);
1322639ae9bSBen Gras 		break;
1332639ae9bSBen Gras 	default:
1342639ae9bSBen Gras einval:		errno = EINVAL;
1352639ae9bSBen Gras 		return (RET_ERROR);
1362639ae9bSBen Gras 	}
1372639ae9bSBen Gras 
1382639ae9bSBen Gras 	/*
1392639ae9bSBen Gras 	 * Make sure that records up to and including the put record are
1402639ae9bSBen Gras 	 * already in the database.  If skipping records, create empty ones.
1412639ae9bSBen Gras 	 */
1422639ae9bSBen Gras 	if (nrec > t->bt_nrecs) {
1432639ae9bSBen Gras 		if (!F_ISSET(t, R_EOF | R_INMEM) &&
1442639ae9bSBen Gras 		    t->bt_irec(t, nrec) == RET_ERROR)
1452639ae9bSBen Gras 			return (RET_ERROR);
1462639ae9bSBen Gras 		if (nrec > t->bt_nrecs + 1) {
1472639ae9bSBen Gras 			if (F_ISSET(t, R_FIXLEN)) {
14884d9c625SLionel Sambuc 				if ((tdata.data = malloc(t->bt_reclen)) == NULL)
1492639ae9bSBen Gras 					return (RET_ERROR);
1502639ae9bSBen Gras 				tdata.size = t->bt_reclen;
1512639ae9bSBen Gras 				memset(tdata.data, t->bt_bval, tdata.size);
1522639ae9bSBen Gras 			} else {
1532639ae9bSBen Gras 				tdata.data = NULL;
1542639ae9bSBen Gras 				tdata.size = 0;
1552639ae9bSBen Gras 			}
1562639ae9bSBen Gras 			while (nrec > t->bt_nrecs + 1)
1572639ae9bSBen Gras 				if (__rec_iput(t,
1582639ae9bSBen Gras 				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
1592639ae9bSBen Gras 					return (RET_ERROR);
1602639ae9bSBen Gras 			if (F_ISSET(t, R_FIXLEN))
1612639ae9bSBen Gras 				free(tdata.data);
1622639ae9bSBen Gras 		}
1632639ae9bSBen Gras 	}
1642639ae9bSBen Gras 
1652639ae9bSBen Gras 	if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
1662639ae9bSBen Gras 		return (status);
1672639ae9bSBen Gras 
168f14fb602SLionel Sambuc 	switch (flags) {
169f14fb602SLionel Sambuc 	case R_IAFTER:
170f14fb602SLionel Sambuc 		nrec++;
171f14fb602SLionel Sambuc 		break;
172f14fb602SLionel Sambuc 	case R_SETCURSOR:
1732639ae9bSBen Gras 		t->bt_cursor.rcursor = nrec;
174f14fb602SLionel Sambuc 		break;
175f14fb602SLionel Sambuc 	}
1762639ae9bSBen Gras 
1772639ae9bSBen Gras 	F_SET(t, R_MODIFIED);
1782639ae9bSBen Gras 	return (__rec_ret(t, NULL, nrec, key, NULL));
1792639ae9bSBen Gras }
1802639ae9bSBen Gras 
1812639ae9bSBen Gras /*
1822639ae9bSBen Gras  * __REC_IPUT -- Add a recno item to the tree.
1832639ae9bSBen Gras  *
1842639ae9bSBen Gras  * Parameters:
1852639ae9bSBen Gras  *	t:	tree
1862639ae9bSBen Gras  *	nrec:	record number
1872639ae9bSBen Gras  *	data:	data
1882639ae9bSBen Gras  *
1892639ae9bSBen Gras  * Returns:
1902639ae9bSBen Gras  *	RET_ERROR, RET_SUCCESS
1912639ae9bSBen Gras  */
1922639ae9bSBen Gras int
__rec_iput(BTREE * t,recno_t nrec,const DBT * data,u_int flags)1932639ae9bSBen Gras __rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
1942639ae9bSBen Gras {
1952639ae9bSBen Gras 	DBT tdata;
1962639ae9bSBen Gras 	EPG *e;
1972639ae9bSBen Gras 	PAGE *h;
1982639ae9bSBen Gras 	indx_t idx, nxtindex;
1992639ae9bSBen Gras 	pgno_t pg;
2002639ae9bSBen Gras 	uint32_t nbytes;
2012639ae9bSBen Gras 	int dflags, status;
2022639ae9bSBen Gras 	char *dest, db[NOVFLSIZE];
2032639ae9bSBen Gras 
2042639ae9bSBen Gras 	/*
2052639ae9bSBen Gras 	 * If the data won't fit on a page, store it on indirect pages.
2062639ae9bSBen Gras 	 *
2072639ae9bSBen Gras 	 * XXX
2082639ae9bSBen Gras 	 * If the insert fails later on, these pages aren't recovered.
2092639ae9bSBen Gras 	 */
2102639ae9bSBen Gras 	if (data->size > t->bt_ovflsize) {
2112639ae9bSBen Gras 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
2122639ae9bSBen Gras 			return (RET_ERROR);
2132639ae9bSBen Gras 		tdata.data = db;
2142639ae9bSBen Gras 		tdata.size = NOVFLSIZE;
215f14fb602SLionel Sambuc 		memcpy(db, &pg, sizeof(pg));
2162639ae9bSBen Gras 		_DBFIT(data->size, uint32_t);
2172639ae9bSBen Gras 		*(uint32_t *)(void *)(db + sizeof(pgno_t)) =
2182639ae9bSBen Gras 		    (uint32_t)data->size;
2192639ae9bSBen Gras 		dflags = P_BIGDATA;
2202639ae9bSBen Gras 		data = &tdata;
2212639ae9bSBen Gras 	} else
2222639ae9bSBen Gras 		dflags = 0;
2232639ae9bSBen Gras 
2242639ae9bSBen Gras 	/* __rec_search pins the returned page. */
2252639ae9bSBen Gras 	if ((e = __rec_search(t, nrec,
2262639ae9bSBen Gras 	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
2272639ae9bSBen Gras 	    SINSERT : SEARCH)) == NULL)
2282639ae9bSBen Gras 		return (RET_ERROR);
2292639ae9bSBen Gras 
2302639ae9bSBen Gras 	h = e->page;
2312639ae9bSBen Gras 	idx = e->index;
2322639ae9bSBen Gras 
2332639ae9bSBen Gras 	/*
2342639ae9bSBen Gras 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
2352639ae9bSBen Gras 	 * R_IBEFORE flags insert the key after/before the specified key.
2362639ae9bSBen Gras 	 *
2372639ae9bSBen Gras 	 * Pages are split as required.
2382639ae9bSBen Gras 	 */
2392639ae9bSBen Gras 	switch (flags) {
2402639ae9bSBen Gras 	case R_IAFTER:
2412639ae9bSBen Gras 		++idx;
2422639ae9bSBen Gras 		break;
2432639ae9bSBen Gras 	case R_IBEFORE:
2442639ae9bSBen Gras 		break;
2452639ae9bSBen Gras 	default:
2462639ae9bSBen Gras 		if (nrec < t->bt_nrecs &&
2472639ae9bSBen Gras 		    __rec_dleaf(t, h, (uint32_t)idx) == RET_ERROR) {
2482639ae9bSBen Gras 			mpool_put(t->bt_mp, h, 0);
2492639ae9bSBen Gras 			return (RET_ERROR);
2502639ae9bSBen Gras 		}
2512639ae9bSBen Gras 		break;
2522639ae9bSBen Gras 	}
2532639ae9bSBen Gras 
2542639ae9bSBen Gras 	/*
2552639ae9bSBen Gras 	 * If not enough room, split the page.  The split code will insert
2562639ae9bSBen Gras 	 * the key and data and unpin the current page.  If inserting into
2572639ae9bSBen Gras 	 * the offset array, shift the pointers up.
2582639ae9bSBen Gras 	 */
2592639ae9bSBen Gras 	nbytes = NRLEAFDBT(data->size);
2602639ae9bSBen Gras 	if ((uint32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) {
2612639ae9bSBen Gras 		status = __bt_split(t, h, NULL, data, dflags, nbytes,
2622639ae9bSBen Gras 		    (uint32_t)idx);
2632639ae9bSBen Gras 		if (status == RET_SUCCESS)
2642639ae9bSBen Gras 			++t->bt_nrecs;
2652639ae9bSBen Gras 		return (status);
2662639ae9bSBen Gras 	}
2672639ae9bSBen Gras 
2682639ae9bSBen Gras 	if (idx < (nxtindex = NEXTINDEX(h)))
2692639ae9bSBen Gras 		memmove(h->linp + idx + 1, h->linp + idx,
2702639ae9bSBen Gras 		    (nxtindex - idx) * sizeof(indx_t));
2712639ae9bSBen Gras 	h->lower += sizeof(indx_t);
2722639ae9bSBen Gras 
2732639ae9bSBen Gras 	h->linp[idx] = h->upper -= nbytes;
2742639ae9bSBen Gras 	dest = (char *)(void *)h + h->upper;
2752639ae9bSBen Gras 	WR_RLEAF(dest, data, dflags);
2762639ae9bSBen Gras 
2772639ae9bSBen Gras 	++t->bt_nrecs;
2782639ae9bSBen Gras 	F_SET(t, B_MODIFIED);
2792639ae9bSBen Gras 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
2802639ae9bSBen Gras 
2812639ae9bSBen Gras 	return (RET_SUCCESS);
2822639ae9bSBen Gras }
283