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
* $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);
}