aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtinsert.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/nbtree/nbtinsert.c')
-rw-r--r--src/backend/access/nbtree/nbtinsert.c147
1 files changed, 102 insertions, 45 deletions
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 63e06f8e1e3..c1cedd33bda 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.6 1996/11/05 10:35:29 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.7 1996/11/13 20:47:11 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,7 +31,10 @@ static OffsetNumber _bt_findsplitloc(Relation rel, Page page, OffsetNumber start
static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
static OffsetNumber _bt_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem);
static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem);
+
+#if 0
static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, Oid bti_oid, BTItem newItem);
+#endif
/*
* _bt_doinsert() -- Handle insertion of a single btitem in the tree.
@@ -41,7 +44,7 @@ static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, Oid bti_oid, BT
* (xid, seqno) pair.
*/
InsertIndexResult
-_bt_doinsert(Relation rel, BTItem btitem)
+_bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, bool is_update)
{
ScanKey itup_scankey;
IndexTuple itup;
@@ -59,6 +62,31 @@ _bt_doinsert(Relation rel, BTItem btitem)
/* find the page containing this key */
stack = _bt_search(rel, natts, itup_scankey, &buf);
+
+ /* if we're not allowing duplicates, make sure the key isn't */
+ /* already in the node */
+ if(index_is_unique && !is_update) {
+ OffsetNumber offset;
+ TupleDesc itupdesc;
+ Page page;
+
+ itupdesc = RelationGetTupleDescriptor(rel);
+ page = BufferGetPage(buf);
+
+ offset = _bt_binsrch(rel, buf, natts, itup_scankey, BT_DESCENT);
+
+ /* make sure the offset we're given points to an actual */
+ /* key on the page before trying to compare it */
+ if(!PageIsEmpty(page) &&
+ offset <= PageGetMaxOffsetNumber(page)) {
+ if(!_bt_compare(rel, itupdesc, page,
+ natts, itup_scankey, offset)) {
+ /* it is a duplicate */
+ elog(WARN, "Cannot insert a duplicate key into a unique index.");
+ }
+ }
+ }
+
blkno = BufferGetBlockNumber(buf);
/* trade in our read lock for a write lock */
@@ -137,6 +165,10 @@ _bt_insertonpg(Relation rel,
InsertIndexResult newres;
BTItem new_item = (BTItem) NULL;
BTItem lowLeftItem;
+ OffsetNumber leftmost_offset;
+ Page ppage;
+ BTPageOpaque ppageop;
+ BlockNumber bknum;
page = BufferGetPage(buf);
itemsz = IndexTupleDSize(btitem->bti_itup)
@@ -236,14 +268,67 @@ _bt_insertonpg(Relation rel,
lowLeftItem =
(BTItem) PageGetItem(page,
PageGetItemId(page, P_FIRSTKEY));
- /* page must have right pointer after split */
- _bt_updateitem(rel, keysz, pbuf, stack->bts_btitem->bti_oid,
- lowLeftItem);
+
+ /* this method does not work--_bt_updateitem tries to */
+ /* overwrite an entry with another entry that might be */
+ /* bigger. if lowLeftItem is bigger, it corrupts the */
+ /* parent page. instead, we have to delete the original */
+ /* leftmost item from the parent, and insert the new one */
+ /* with a regular _bt_insertonpg (it could cause a split */
+ /* because it's bigger than what was there before). */
+ /* --djm 8/21/96 */
+
+ /* _bt_updateitem(rel, keysz, pbuf, stack->bts_btitem->bti_oid,
+ lowLeftItem); */
+
+ /* get the parent page */
+ ppage = BufferGetPage(pbuf);
+ ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
+
+ /* figure out which key is leftmost (if the parent page */
+ /* is rightmost, too, it must be the root) */
+ if(P_RIGHTMOST(ppageop)) {
+ leftmost_offset = P_HIKEY;
+ } else {
+ leftmost_offset = P_FIRSTKEY;
}
+ PageIndexTupleDelete(ppage, leftmost_offset);
+
+ /* don't write anything out yet--we still have the write */
+ /* lock, and now we call another _bt_insertonpg to */
+ /* insert the correct leftmost key */
+
+ /* make a new leftmost item, using the tuple data from */
+ /* lowLeftItem. point it to the left child. */
+ /* update it on the stack at the same time. */
+ bknum = BufferGetBlockNumber(buf);
+ pfree(stack->bts_btitem);
+ stack->bts_btitem = _bt_formitem(&(lowLeftItem->bti_itup));
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
+ bknum, P_HIKEY);
+
+ /* unlock the children before doing this */
+ _bt_relbuf(rel, buf, BT_WRITE);
+ _bt_relbuf(rel, rbuf, BT_WRITE);
+
+ /* a regular _bt_binsrch should find the right place to */
+ /* put the new entry, since it should be lower than any */
+ /* other key on the page, therefore set afteritem to NULL */
+ newskey = _bt_mkscankey(rel, &(stack->bts_btitem->bti_itup));
+ newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
+ keysz, newskey, stack->bts_btitem,
+ NULL);
+
+ pfree(newres);
+ pfree(newskey);
- /* don't need the children anymore */
+ /* we have now lost our lock on the parent buffer, and */
+ /* need to get it back. */
+ pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ } else {
_bt_relbuf(rel, buf, BT_WRITE);
_bt_relbuf(rel, rbuf, BT_WRITE);
+ }
newskey = _bt_mkscankey(rel, &(new_item->bti_itup));
newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
@@ -787,6 +872,8 @@ _bt_itemcmp(Relation rel,
return (true);
}
+#if 0
+/* gone since updating in place doesn't work in general --djm 11/13/96 */
/*
* _bt_updateitem() -- updates the key of the item identified by the
* oid with the key of newItem (done in place if
@@ -804,9 +891,9 @@ _bt_updateitem(Relation rel,
OffsetNumber maxoff;
OffsetNumber i;
ItemPointerData itemPtrData;
- BTItem item, itemCopy;
+ BTItem item;
IndexTuple oldIndexTuple, newIndexTuple;
- int newSize, oldSize, first;
+ int first;
page = BufferGetPage(buf);
maxoff = PageGetMaxOffsetNumber(page);
@@ -825,48 +912,18 @@ _bt_updateitem(Relation rel,
elog(FATAL, "_bt_getstackbuf was lying!!");
}
+ if(IndexTupleDSize(newItem->bti_itup) >
+ IndexTupleDSize(item->bti_itup)) {
+ elog(NOTICE, "trying to overwrite a smaller value with a bigger one in _bt_updateitem");
+ elog(WARN, "this is not good.");
+ }
+
oldIndexTuple = &(item->bti_itup);
newIndexTuple = &(newItem->bti_itup);
- oldSize = DOUBLEALIGN(IndexTupleSize(oldIndexTuple));
- newSize = DOUBLEALIGN(IndexTupleSize(newIndexTuple));
-#ifdef NBTINSERT_PATCH_DEBUG
- printf("_bt_updateitem: newSize=%d, oldSize=%d\n", newSize, oldSize);
-#endif
- /*
- * If new and old item have the same size do the update in place
- * and return.
- */
- if (oldSize == newSize) {
/* keep the original item pointer */
ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
CopyIndexTuple(newIndexTuple, &oldIndexTuple);
ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
- return;
- }
-
- /*
- * If new and old items have different size the update in place
- * is not possible. In this case the old item is deleted and the
- * new one is inserted.
- * The new insertion should be done using _bt_insertonpg which
- * would also takes care of the page splitting if needed, but
- * unfortunately it doesn't work, so PageAddItem is used instead.
- * There is the possibility that there is not enough space in the
- * page and the item is not inserted.
- */
- itemCopy = palloc(newSize);
- memmove((char *) itemCopy, (char *) newItem, newSize);
- itemCopy->bti_oid = item->bti_oid;
- newIndexTuple = &(itemCopy->bti_itup);
- ItemPointerCopy(&(oldIndexTuple->t_tid), &(newIndexTuple->t_tid));
-
- /*
- * Get the offset number of the item then delete it and insert
- * the new item in the same place.
- */
- i = OffsetNumberPrev(i);
- PageIndexTupleDelete(page, i);
- PageAddItem(page, (Item) itemCopy, newSize, i, LP_USED);
- pfree(itemCopy);
}
+#endif