summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-10-25 09:53:32 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-10-25 09:53:32 +0000
commitb8885b22d21f23da57e77bfa2665f6abdc6cc3d7 (patch)
tree6e8dac7a13607a14c9e4b91a2f6ab10dc9c39496
parent5bc122c9e113fa71d9e35c912b2f7f37e810e9bd (diff)
downloadpostgresql-b8885b22d21f23da57e77bfa2665f6abdc6cc3d7.tar.gz
There is a bug in the btree insert code which can cause, under very rare
conditions, the corruption of index data and possibly of shared memory data. Submitted by: Massimo Dal Zotto <dz@cs.unitn.it>
-rw-r--r--src/backend/access/nbtree/nbtinsert.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 536c0aa385..b67d2d492d 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.1.1.1 1996/07/09 06:21:12 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.1.1.1.2.1 1996/10/25 09:53:32 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -789,7 +789,8 @@ _bt_itemcmp(Relation rel,
/*
* _bt_updateitem() -- updates the key of the item identified by the
- * oid with the key of newItem (done in place)
+ * oid with the key of newItem (done in place if
+ * possible)
*
*/
static void
@@ -803,14 +804,17 @@ _bt_updateitem(Relation rel,
OffsetNumber maxoff;
OffsetNumber i;
ItemPointerData itemPtrData;
- BTItem item;
+ BTItem item, itemCopy;
IndexTuple oldIndexTuple, newIndexTuple;
+ int newSize, oldSize, first;
page = BufferGetPage(buf);
maxoff = PageGetMaxOffsetNumber(page);
/* locate item on the page */
- i = P_HIKEY;
+ first = P_RIGHTMOST((BTPageOpaque) PageGetSpecialPointer(page)) \
+ ? P_HIKEY : P_FIRSTKEY;
+ i = first;
do {
item = (BTItem) PageGetItem(page, PageGetItemId(page, i));
i = OffsetNumberNext(i);
@@ -823,9 +827,46 @@ _bt_updateitem(Relation rel,
oldIndexTuple = &(item->bti_itup);
newIndexTuple = &(newItem->bti_itup);
-
- /* keep the original item pointer */
- ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
- CopyIndexTuple(newIndexTuple, &oldIndexTuple);
- ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
+ 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);
}