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>
This commit is contained in:
Marc G. Fournier 1996-10-25 09:53:32 +00:00
parent 5bc122c9e1
commit b8885b22d2

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * _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 static void
@ -803,14 +804,17 @@ _bt_updateitem(Relation rel,
OffsetNumber maxoff; OffsetNumber maxoff;
OffsetNumber i; OffsetNumber i;
ItemPointerData itemPtrData; ItemPointerData itemPtrData;
BTItem item; BTItem item, itemCopy;
IndexTuple oldIndexTuple, newIndexTuple; IndexTuple oldIndexTuple, newIndexTuple;
int newSize, oldSize, first;
page = BufferGetPage(buf); page = BufferGetPage(buf);
maxoff = PageGetMaxOffsetNumber(page); maxoff = PageGetMaxOffsetNumber(page);
/* locate item on the page */ /* locate item on the page */
i = P_HIKEY; first = P_RIGHTMOST((BTPageOpaque) PageGetSpecialPointer(page)) \
? P_HIKEY : P_FIRSTKEY;
i = first;
do { do {
item = (BTItem) PageGetItem(page, PageGetItemId(page, i)); item = (BTItem) PageGetItem(page, PageGetItemId(page, i));
i = OffsetNumberNext(i); i = OffsetNumberNext(i);
@ -823,9 +827,46 @@ _bt_updateitem(Relation rel,
oldIndexTuple = &(item->bti_itup); oldIndexTuple = &(item->bti_itup);
newIndexTuple = &(newItem->bti_itup); newIndexTuple = &(newItem->bti_itup);
oldSize = DOUBLEALIGN(IndexTupleSize(oldIndexTuple));
/* keep the original item pointer */ newSize = DOUBLEALIGN(IndexTupleSize(newIndexTuple));
ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData); #ifdef NBTINSERT_PATCH_DEBUG
CopyIndexTuple(newIndexTuple, &oldIndexTuple); printf("_bt_updateitem: newSize=%d, oldSize=%d\n", newSize, oldSize);
ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid)); #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);
} }