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:
parent
5bc122c9e1
commit
b8885b22d2
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user