]> granicus.if.org Git - postgresql/commitdiff
Correct an old logic error in btree page splitting: when considering a split
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 27 Jan 2007 20:53:30 +0000 (20:53 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 27 Jan 2007 20:53:30 +0000 (20:53 +0000)
exactly at the point where we need to insert a new item, the calculation used
the wrong size for the "high key" of the new left page.  This could lead to
choosing an unworkable split, resulting in "PANIC: failed to add item to the
left sibling" (or "right sibling") failure.  Although this bug has been there
a long time, it's very difficult to trigger a failure before 8.2, since there
was generally a lot of free space on both sides of a chosen split.  In 8.2,
where the user-selected fill factor determines how much free space the code
tries to leave, an unworkable split is much more likely.  Report by Joe
Conway, diagnosis and fix by Heikki Linnakangas.

src/backend/access/nbtree/nbtinsert.c

index d011d8f3f1ca005967854d8cbe814f7e76390a88..0a7414869309120b616ba6067116333e82f8dcb9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.147 2007/01/05 22:19:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.148 2007/01/27 20:53:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1153,7 +1153,12 @@ _bt_findsplitloc(Relation rel,
                        /* need to try it both ways! */
                        _bt_checksplitloc(&state, offnum, leftfree, rightfree,
                                                          true, itemsz);
-                       /* here we are contemplating newitem as first on right */
+                       /*
+                        * Here we are contemplating newitem as first on right.  In this
+                        * case it, not the current item, will become the high key of the
+                        * left page, and so we have to correct the allowance made above.
+                        */
+                       leftfree += (int) itemsz - (int) newitemsz;
                        _bt_checksplitloc(&state, offnum, leftfree, rightfree,
                                                          false, newitemsz);
                }