about summary refs log tree commit diff
path: root/db2/btree/bt_put.c
diff options
context:
space:
mode:
Diffstat (limited to 'db2/btree/bt_put.c')
-rw-r--r--db2/btree/bt_put.c176
1 files changed, 102 insertions, 74 deletions
diff --git a/db2/btree/bt_put.c b/db2/btree/bt_put.c
index 87f3fd9aff..a93faac98c 100644
--- a/db2/btree/bt_put.c
+++ b/db2/btree/bt_put.c
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *	Sleepycat Software.  All rights reserved.
  */
 /*
@@ -47,15 +47,13 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_put.c	10.38 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)bt_put.c	10.45 (Sleepycat) 5/25/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -75,21 +73,22 @@ static u_int32_t __bam_partsize __P((DBT *, PAGE *, u_int32_t));
  * __bam_put --
  *	Add a new key/data pair or replace an existing pair (btree).
  *
- * PUBLIC: int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, int));
+ * PUBLIC: int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
  */
 int
 __bam_put(argdbp, txn, key, data, flags)
 	DB *argdbp;
 	DB_TXN *txn;
 	DBT *key, *data;
-	int flags;
+	u_int32_t flags;
 {
 	BTREE *t;
 	CURSOR c;
 	DB *dbp;
 	PAGE *h;
 	db_indx_t indx;
-	int exact, iflags, isdeleted, newkey, replace, ret, stack;
+	u_int32_t iitem_flags, insert_flags;
+	int exact, isdeleted, newkey, ret, stack;
 
 	DEBUG_LWRITE(argdbp, txn, "bam_put", key, data, flags);
 
@@ -121,14 +120,13 @@ retry:	/*
 	 * been marked for deletion, we do a replace, otherwise, it has to be
 	 * a set of duplicates, and we simply append a new one to the set.
 	 */
-	isdeleted = replace = 0;
+	isdeleted = 0;
 	if (exact) {
 		if ((ret = __bam_isdeleted(dbp, h, indx, &isdeleted)) != 0)
 			goto err;
-		if (isdeleted) {
-			replace = 1;
+		if (isdeleted)
 			__bam_ca_replace(dbp, h->pgno, indx, REPLACE_SETUP);
-		} else
+		else
 			if (flags == DB_NOOVERWRITE) {
 				ret = DB_KEYEXIST;
 				goto err;
@@ -179,42 +177,38 @@ retry:	/*
 				t->bt_csp->page = h = c.page;
 				indx = c.dindx;
 			}
-			iflags = DB_AFTER;
+			insert_flags = DB_AFTER;
 		} else
-			iflags = DB_CURRENT;
+			insert_flags = DB_CURRENT;
 	} else
-		iflags = DB_BEFORE;
+		insert_flags = DB_BEFORE;
 
 	/*
 	 * The pages we're using may be modified by __bam_iitem(), so make
 	 * sure we reset the stack.
 	 */
-	ret = __bam_iitem(dbp,
-	    &h, &indx, key, data, iflags, newkey ? BI_NEWKEY : 0);
+	iitem_flags = 0;
+	if (newkey)
+		iitem_flags |= BI_NEWKEY;
+	if (isdeleted)
+		iitem_flags |= BI_DOINCR;
+	ret = __bam_iitem(dbp, &h, &indx, key, data, insert_flags, iitem_flags);
 	t->bt_csp->page = h;
 	t->bt_csp->indx = indx;
 
 	switch (ret) {
 	case 0:
-		/*
-		 * Done.  Clean up the cursor, and, if we're doing record
-		 * numbers, adjust the internal page counts.
-		 */
-		if (replace)
+		/* Done.  Clean up the cursor. */
+		if (isdeleted)
 			__bam_ca_replace(dbp, h->pgno, indx, REPLACE_SUCCESS);
-
-		if (!replace && F_ISSET(dbp, DB_BT_RECNUM))
-			ret = __bam_adjust(dbp, t, 1);
 		break;
 	case DB_NEEDSPLIT:
 		/*
 		 * We have to split the page.  Back out the cursor setup,
 		 * discard the stack of pages, and do the split.
 		 */
-		if (replace) {
-			replace = 0;
+		if (isdeleted)
 			__bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
-		}
 
 		(void)__bam_stkrel(dbp);
 		stack = 0;
@@ -225,7 +219,7 @@ retry:	/*
 		goto retry;
 		/* NOTREACHED */
 	default:
-		if (replace)
+		if (isdeleted)
 			__bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
 		break;
 	}
@@ -393,7 +387,8 @@ __bam_lookup(dbp, key, exactp)
 				for (indx = 0;
 				    indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
 				    h->inp[indx] == h->inp[indx + P_INDX];
-				    indx += P_INDX);
+				    indx += P_INDX)
+					;
 				e.indx = indx;
 			}
 			goto fast;
@@ -427,7 +422,7 @@ slow:	return (__bam_search(dbp, key, S_INSERT, 1, NULL, exactp));
  *	Insert an item into the tree.
  *
  * PUBLIC: int __bam_iitem __P((DB *,
- * PUBLIC:    PAGE **, db_indx_t *, DBT *, DBT *, int, int));
+ * PUBLIC:    PAGE **, db_indx_t *, DBT *, DBT *, u_int32_t, u_int32_t));
  */
 int
 __bam_iitem(dbp, hp, indxp, key, data, op, flags)
@@ -435,13 +430,13 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
 	PAGE **hp;
 	db_indx_t *indxp;
 	DBT *key, *data;
-	int op, flags;
+	u_int32_t op, flags;
 {
 	BTREE *t;
 	BKEYDATA *bk;
 	DBT tdbt;
 	PAGE *h;
-	db_indx_t indx;
+	db_indx_t indx, nbytes;
 	u_int32_t data_size, have_bytes, need_bytes, needed;
 	int bigkey, bigdata, dupadjust, replace, ret;
 
@@ -466,12 +461,27 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
 			++*indxp;
 
 		/* Remove the current item if it's a DB_CURRENT op. */
-		if (op == DB_CURRENT && (ret = __db_ditem(dbp, *hp, *indxp,
-		    BKEYDATA_SIZE(GET_BKEYDATA(*hp, *indxp)->len))) != 0)
-			return (ret);
+		if (op == DB_CURRENT) {
+			bk = GET_BKEYDATA(*hp, *indxp);
+			switch (B_TYPE(bk->type)) {
+			case B_KEYDATA:
+				nbytes = BKEYDATA_SIZE(bk->len);
+				break;
+			case B_OVERFLOW:
+				nbytes = BOVERFLOW_SIZE;
+				break;
+			default:
+				return (__db_pgfmt(dbp, h->pgno));
+			}
+			if ((ret = __db_ditem(dbp, *hp, *indxp, nbytes)) != 0)
+				return (ret);
+		}
 
 		/* Put the new/replacement item onto the page. */
-		return (__db_dput(dbp, data, hp, indxp, __bam_new));
+		if ((ret = __db_dput(dbp, data, hp, indxp, __bam_new)) != 0)
+			return (ret);
+
+		goto done;
 	}
 
 	/* Handle fixed-length records: build the real record. */
@@ -568,7 +578,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
 		case DB_BEFORE:		/* 2. Insert a new key/data pair. */
 			break;
 		default:
-			abort();
+			return (EINVAL);
 		}
 
 		/* Add the key. */
@@ -638,7 +648,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
 			replace = 1;
 			break;
 		default:
-			abort();
+			return (EINVAL);
 		}
 	}
 
@@ -666,9 +676,8 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
 			return (ret);
 	}
 
-	++t->lstat.bt_added;
-
-	ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY);
+	if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0)
+		return (ret);
 
 	/*
 	 * If the page is at least 50% full, and we added a duplicate, see if
@@ -681,9 +690,25 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
 			return (ret);
 	}
 
+	/*
+	 * If we've changed the record count, update the tree.  Record counts
+	 * need to be updated in recno databases and in btree databases where
+	 * we are supporting records.  In both cases, adjust the count if the
+	 * operation wasn't performed on the current record or when the caller
+	 * overrides and wants the adjustment made regardless.
+	 */
+done:	if (LF_ISSET(BI_DOINCR) ||
+	    (op != DB_CURRENT &&
+	    (F_ISSET(dbp, DB_BT_RECNUM) || dbp->type == DB_RECNO)))
+		if ((ret = __bam_adjust(dbp, t, 1)) != 0)
+			return (ret);
+
+	/* If we've modified a recno file, set the flag */
 	if (t->bt_recno != NULL)
 		F_SET(t->bt_recno, RECNO_MODIFIED);
 
+	++t->lstat.bt_added;
+
 	return (ret);
 }
 
@@ -1036,8 +1061,8 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
 	BOVERFLOW *bo;
 	DBT copy;
 	u_int32_t len, tlen;
-	int ret;
 	u_int8_t *p;
+	int ret;
 
 	COMPQUIET(bo, NULL);
 
@@ -1065,59 +1090,62 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
 		bk->len = 0;
 	}
 
-	/* We use nul bytes for extending the record, get it over with. */
+	/*
+	 * We use nul bytes for any part of the record that isn't specified,
+	 * get it over with.
+	 */
 	memset(t->bt_rdata.data, 0, nbytes);
 
-	tlen = 0;
 	if (B_TYPE(bk->type) == B_OVERFLOW) {
-		/* Take up to doff bytes from the record. */
+		/*
+		 * In the case of an overflow record, we shift things around
+		 * in the current record rather than allocate a separate copy.
+		 */
 		memset(&copy, 0, sizeof(copy));
 		if ((ret = __db_goff(dbp, &copy, bo->tlen,
 		    bo->pgno, &t->bt_rdata.data, &t->bt_rdata.ulen)) != 0)
 			return (ret);
-		tlen += dbt->doff;
+
+		/* Skip any leading data from the original record. */
+		tlen = dbt->doff;
+		p = (u_int8_t *)t->bt_rdata.data + dbt->doff;
 
 		/*
-		 * If the original record was larger than the offset:
-		 *	If dlen > size, shift the remaining data down.
-		 *	If dlen < size, shift the remaining data up.
+		 * Copy in any trailing data from the original record.
+		 *
+		 * If the original record was larger than the original offset
+		 * plus the bytes being deleted, there is trailing data in the
+		 * original record we need to preserve.  If we aren't deleting
+		 * the same number of bytes as we're inserting, copy it up or
+		 * down, into place.
+		 *
 		 * Use memmove(), the regions may overlap.
 		 */
-		p = t->bt_rdata.data;
-		if (bo->tlen > dbt->doff)
-			if (dbt->dlen > dbt->size) {
-				tlen += len = bo->tlen -
-				    dbt->doff - (dbt->dlen - dbt->size);
-				memmove(p + dbt->doff + dbt->size,
-				    p + dbt->doff + dbt->dlen, len);
-			} else if (dbt->dlen < dbt->size) {
-				tlen += len = bo->tlen -
-				    dbt->doff - (dbt->size - dbt->dlen);
-				memmove(p + dbt->doff + dbt->dlen,
-				    p + dbt->doff + dbt->size, len);
-			} else
-				tlen += bo->tlen - dbt->doff;
+		if (bo->tlen > dbt->doff + dbt->dlen) {
+			len = bo->tlen - (dbt->doff + dbt->dlen);
+			if (dbt->dlen != dbt->size)
+				memmove(p + dbt->size, p + dbt->dlen, len);
+			tlen += len;
+		}
 
-		/* Copy in the user's data. */
-		memcpy((u_int8_t *)t->bt_rdata.data + dbt->doff,
-		    dbt->data, dbt->size);
+		/* Copy in the application provided data. */
+		memcpy(p, dbt->data, dbt->size);
 		tlen += dbt->size;
 	} else {
-		/* Take up to doff bytes from the record. */
+		/* Copy in any leading data from the original record. */
 		memcpy(t->bt_rdata.data,
 		    bk->data, dbt->doff > bk->len ? bk->len : dbt->doff);
-		tlen += dbt->doff;
+		tlen = dbt->doff;
+		p = (u_int8_t *)t->bt_rdata.data + dbt->doff;
 
-		/* Copy in the user's data. */
-		memcpy((u_int8_t *)t->bt_rdata.data +
-		    dbt->doff, dbt->data, dbt->size);
+		/* Copy in the application provided data. */
+		memcpy(p, dbt->data, dbt->size);
 		tlen += dbt->size;
 
-		/* Copy in any remaining data. */
+		/* Copy in any trailing data from the original record. */
 		len = dbt->doff + dbt->dlen;
 		if (bk->len > len) {
-			memcpy((u_int8_t *)t->bt_rdata.data + dbt->doff +
-			    dbt->size, bk->data + len, bk->len - len);
+			memcpy(p + dbt->size, bk->data + len, bk->len - len);
 			tlen += bk->len - len;
 		}
 	}