8000 There is a bug in the btree insert code which can cause, under very rare · home201448/postgres@b8885b2 · GitHub
[go: up one dir, main page]

Skip to content

Commit b8885b2

Browse files
committed
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>
1 parent 5bc122c commit b8885b2

File tree

1 file changed

+50
-9
lines changed

1 file changed

+50
-9
lines changed

src/backend/access/nbtree/nbtinsert.c

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.1.1.1 1996/07/09 06:21:12 scrappy Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.1.1.1.2.1 1996/10/25 09:53:32 scrappy Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -789,7 +789,8 @@ _bt_itemcmp(Relation rel,
789789

790790
/*
791791
* _bt_updateitem() -- updates the key of the item identified by the
792-
* oid with the key of newItem (done in place)
792+
* oid with the key of newItem (done in place if
793+
* possible)
793794
*
794795
*/
795796
static void
@@ -803,14 +804,17 @@ _bt_updateitem(Relation rel,
803804
OffsetNumber maxoff;
804805
OffsetNumber i;
805806
ItemPointerData itemPtrData;
806-
BTItem item;
807+
BTItem item, itemCopy;
807808
IndexTuple oldIndexTuple, newIndexTuple;
809+
int newSize, oldSize, first;
808810

809811
page = BufferGetPage(buf);
810812
maxoff = PageGetMaxOffsetNumber(page);
811813

812814
/* locate item on the page */
813-
i = P_HIKEY;
815+
first = P_RIGHTMOST((BTPageOpaque) PageGetSpecialPointer(page)) \
816+
? P_HIKEY : P_FIRSTKEY;
817+
i = first;
814818
do {
815819
item = (BTItem) PageGetItem(page, PageGetItemId(page, i));
816820
i = OffsetNumberNext(i);
@@ -823,9 +827,46 @@ _bt_updateitem(Relation rel,
823827

824828
oldIndexTuple = &(item->bti_itup);
825829
newIndexTuple = &(newItem->bti_itup);
826-
827-
/* keep the original item pointer */
828-
ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
829-
CopyIndexTuple(newIndexTuple, &oldIndexTuple);
830-
ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
830+
oldSize = DOUBLEALIGN(IndexTupleSize(oldIndexTuple));
831+
newSize = DOUBLEALIGN(IndexTupleSize(newIndexTuple));
832+
#ifdef NBTINSERT_PATCH_DEBUG
833+
printf("_bt_updateitem: newSize=%d, oldSize=%d\n", newSize, oldSize);
834+
#endif
835+
836+
/*
837+
* If new and old item have the same size do the update in place
838+
* and return.
839+
*/
840+
if (oldSize == newSize) {
841+
/* keep the original item pointer */
842+
ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
843+
CopyIndexTuple(newIndexTuple, &oldIndexTuple);
844+
ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
845+
return;
846+
}
847+
848+
/*
849+
* If new and old items have different size the update in place
850+
* is not possible. In this case the old item is deleted and the
851+
* new one is inserted.
852+
* The new insertion should be done using _bt_insertonpg which
853+
* would also takes care of the page splitting if needed, but
854+
* unfortunately it doesn't work, so PageAddItem is used instead.
855+
* There is the possibility that there is not enough space in the
856+
* page and the item is not inserted.
857+
*/
858+
itemCopy = palloc(newSize);
859+
memmove((char *) itemCopy, (char *) newItem, newSize);
860+
itemCopy->bti_oid = item->bti_oid;
861+
newIndexTuple = &(itemCopy->bti_itup);
862+
ItemPointerCopy(&(oldIndexTuple->t_tid), &(newIndexTuple->t_tid));
863+
864+
/*
865+
* Get the offset number of the item then delete it and insert
866+
* the new item in the same place.
867+
*/
868+
i = OffsetNumberPrev(i);
869+
PageIndexTupleDelete(page, i);
870+
PageAddItem(page, (Item) itemCopy, newSize, i, LP_USED);
871+
pfree(itemCopy);
831872
}

0 commit comments

Comments
 (0)
0