Home | History | Annotate | Line # | Download | only in recno
rec_put.c revision 1.1.1.2
      1 /*-
      2  * Copyright (c) 1990, 1993, 1994
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #if defined(LIBC_SCCS) && !defined(lint)
     35 static char sccsid[] = "@(#)rec_put.c	8.7 (Berkeley) 8/18/94";
     36 #endif /* LIBC_SCCS and not lint */
     37 
     38 #include <sys/types.h>
     39 
     40 #include <errno.h>
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 
     45 #include <db.h>
     46 #include "recno.h"
     47 
     48 /*
     49  * __REC_PUT -- Add a recno item to the tree.
     50  *
     51  * Parameters:
     52  *	dbp:	pointer to access method
     53  *	key:	key
     54  *	data:	data
     55  *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
     56  *
     57  * Returns:
     58  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
     59  *	already in the tree and R_NOOVERWRITE specified.
     60  */
     61 int
     62 __rec_put(dbp, key, data, flags)
     63 	const DB *dbp;
     64 	DBT *key;
     65 	const DBT *data;
     66 	u_int flags;
     67 {
     68 	BTREE *t;
     69 	DBT fdata, tdata;
     70 	recno_t nrec;
     71 	int status;
     72 
     73 	t = dbp->internal;
     74 
     75 	/* Toss any page pinned across calls. */
     76 	if (t->bt_pinned != NULL) {
     77 		mpool_put(t->bt_mp, t->bt_pinned, 0);
     78 		t->bt_pinned = NULL;
     79 	}
     80 
     81 	/*
     82 	 * If using fixed-length records, and the record is long, return
     83 	 * EINVAL.  If it's short, pad it out.  Use the record data return
     84 	 * memory, it's only short-term.
     85 	 */
     86 	if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
     87 		if (data->size > t->bt_reclen)
     88 			goto einval;
     89 
     90 		if (t->bt_rdata.size < t->bt_reclen) {
     91 			t->bt_rdata.data = t->bt_rdata.data == NULL ?
     92 			    malloc(t->bt_reclen) :
     93 			    realloc(t->bt_rdata.data, t->bt_reclen);
     94 			if (t->bt_rdata.data == NULL)
     95 				return (RET_ERROR);
     96 			t->bt_rdata.size = t->bt_reclen;
     97 		}
     98 		memmove(t->bt_rdata.data, data->data, data->size);
     99 		memset((char *)t->bt_rdata.data + data->size,
    100 		    t->bt_bval, t->bt_reclen - data->size);
    101 		fdata.data = t->bt_rdata.data;
    102 		fdata.size = t->bt_reclen;
    103 	} else {
    104 		fdata.data = data->data;
    105 		fdata.size = data->size;
    106 	}
    107 
    108 	switch (flags) {
    109 	case R_CURSOR:
    110 		if (!F_ISSET(&t->bt_cursor, CURS_INIT))
    111 			goto einval;
    112 		nrec = t->bt_cursor.rcursor;
    113 		break;
    114 	case R_SETCURSOR:
    115 		if ((nrec = *(recno_t *)key->data) == 0)
    116 			goto einval;
    117 		break;
    118 	case R_IAFTER:
    119 		if ((nrec = *(recno_t *)key->data) == 0) {
    120 			nrec = 1;
    121 			flags = R_IBEFORE;
    122 		}
    123 		break;
    124 	case 0:
    125 	case R_IBEFORE:
    126 		if ((nrec = *(recno_t *)key->data) == 0)
    127 			goto einval;
    128 		break;
    129 	case R_NOOVERWRITE:
    130 		if ((nrec = *(recno_t *)key->data) == 0)
    131 			goto einval;
    132 		if (nrec <= t->bt_nrecs)
    133 			return (RET_SPECIAL);
    134 		break;
    135 	default:
    136 einval:		errno = EINVAL;
    137 		return (RET_ERROR);
    138 	}
    139 
    140 	/*
    141 	 * Make sure that records up to and including the put record are
    142 	 * already in the database.  If skipping records, create empty ones.
    143 	 */
    144 	if (nrec > t->bt_nrecs) {
    145 		if (!F_ISSET(t, R_EOF | R_INMEM) &&
    146 		    t->bt_irec(t, nrec) == RET_ERROR)
    147 			return (RET_ERROR);
    148 		if (nrec > t->bt_nrecs + 1) {
    149 			if (F_ISSET(t, R_FIXLEN)) {
    150 				if ((tdata.data =
    151 				    (void *)malloc(t->bt_reclen)) == NULL)
    152 					return (RET_ERROR);
    153 				tdata.size = t->bt_reclen;
    154 				memset(tdata.data, t->bt_bval, tdata.size);
    155 			} else {
    156 				tdata.data = NULL;
    157 				tdata.size = 0;
    158 			}
    159 			while (nrec > t->bt_nrecs + 1)
    160 				if (__rec_iput(t,
    161 				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
    162 					return (RET_ERROR);
    163 			if (F_ISSET(t, R_FIXLEN))
    164 				free(tdata.data);
    165 		}
    166 	}
    167 
    168 	if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
    169 		return (status);
    170 
    171 	if (flags == R_SETCURSOR)
    172 		t->bt_cursor.rcursor = nrec;
    173 
    174 	F_SET(t, R_MODIFIED);
    175 	return (__rec_ret(t, NULL, nrec, key, NULL));
    176 }
    177 
    178 /*
    179  * __REC_IPUT -- Add a recno item to the tree.
    180  *
    181  * Parameters:
    182  *	t:	tree
    183  *	nrec:	record number
    184  *	data:	data
    185  *
    186  * Returns:
    187  *	RET_ERROR, RET_SUCCESS
    188  */
    189 int
    190 __rec_iput(t, nrec, data, flags)
    191 	BTREE *t;
    192 	recno_t nrec;
    193 	const DBT *data;
    194 	u_int flags;
    195 {
    196 	DBT tdata;
    197 	EPG *e;
    198 	PAGE *h;
    199 	indx_t index, nxtindex;
    200 	pgno_t pg;
    201 	u_int32_t nbytes;
    202 	int dflags, status;
    203 	char *dest, db[NOVFLSIZE];
    204 
    205 	/*
    206 	 * If the data won't fit on a page, store it on indirect pages.
    207 	 *
    208 	 * XXX
    209 	 * If the insert fails later on, these pages aren't recovered.
    210 	 */
    211 	if (data->size > t->bt_ovflsize) {
    212 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
    213 			return (RET_ERROR);
    214 		tdata.data = db;
    215 		tdata.size = NOVFLSIZE;
    216 		*(pgno_t *)db = pg;
    217 		*(u_int32_t *)(db + sizeof(pgno_t)) = data->size;
    218 		dflags = P_BIGDATA;
    219 		data = &tdata;
    220 	} else
    221 		dflags = 0;
    222 
    223 	/* __rec_search pins the returned page. */
    224 	if ((e = __rec_search(t, nrec,
    225 	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
    226 	    SINSERT : SEARCH)) == NULL)
    227 		return (RET_ERROR);
    228 
    229 	h = e->page;
    230 	index = e->index;
    231 
    232 	/*
    233 	 * Add the specified key/data pair to the tree.  The R_IAFTER and
    234 	 * R_IBEFORE flags insert the key after/before the specified key.
    235 	 *
    236 	 * Pages are split as required.
    237 	 */
    238 	switch (flags) {
    239 	case R_IAFTER:
    240 		++index;
    241 		break;
    242 	case R_IBEFORE:
    243 		break;
    244 	default:
    245 		if (nrec < t->bt_nrecs &&
    246 		    __rec_dleaf(t, h, index) == RET_ERROR) {
    247 			mpool_put(t->bt_mp, h, 0);
    248 			return (RET_ERROR);
    249 		}
    250 		break;
    251 	}
    252 
    253 	/*
    254 	 * If not enough room, split the page.  The split code will insert
    255 	 * the key and data and unpin the current page.  If inserting into
    256 	 * the offset array, shift the pointers up.
    257 	 */
    258 	nbytes = NRLEAFDBT(data->size);
    259 	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
    260 		status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
    261 		if (status == RET_SUCCESS)
    262 			++t->bt_nrecs;
    263 		return (status);
    264 	}
    265 
    266 	if (index < (nxtindex = NEXTINDEX(h)))
    267 		memmove(h->linp + index + 1, h->linp + index,
    268 		    (nxtindex - index) * sizeof(indx_t));
    269 	h->lower += sizeof(indx_t);
    270 
    271 	h->linp[index] = h->upper -= nbytes;
    272 	dest = (char *)h + h->upper;
    273 	WR_RLEAF(dest, data, dflags);
    274 
    275 	++t->bt_nrecs;
    276 	F_SET(t, B_MODIFIED);
    277 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
    278 
    279 	return (RET_SUCCESS);
    280 }
    281