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
|
* 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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user