Fix yet another crash in page split during GiST index creation.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 16 Dec 2019 11:57:41 +0000 (13:57 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 16 Dec 2019 11:57:41 +0000 (13:57 +0200)
Commit a7ee7c8513 fixed a bug in GiST page split during index creation,
where we failed to re-find the position of a downlink after the page
containing it was split. However, that fix was incomplete; the other call
to gistinserttuples() in the same function needs to also clear
'downlinkoffnum'.

Fixes bug #16134 reported by Alexander Lakhin, for real this time. The
previous fix was enough to fix the crash with the reproducer script for
bug #16162, but the original script for #16134 was still crashing.

Backpatch to v12, like the previous incomplete fix.

Discussion: https://www.postgresql.org/message-id/d869f537-abe4-d2ea-0510-38cd053f5152%40gmail.com

src/backend/access/gist/gist.c

index b87facb2fa97e39d88b782aad5e3ae591dc56d65..a259c80616d8085e366c79405a5f19f2188ebf53 100644 (file)
@@ -1325,10 +1325,9 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
     * downlink for the original page as one operation.
     */
    LockBuffer(stack->parent->buffer, GIST_EXCLUSIVE);
-   gistFindCorrectParent(state->r, stack);
 
    /*
-    * insert downlinks for the siblings from right to left, until there are
+    * Insert downlinks for the siblings from right to left, until there are
     * only two siblings left.
     */
    for (int pos = list_length(splitinfo) - 1; pos > 1; pos--)
@@ -1336,17 +1335,17 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
        right = (GISTPageSplitInfo *) list_nth(splitinfo, pos);
        left = (GISTPageSplitInfo *) list_nth(splitinfo, pos - 1);
 
+       gistFindCorrectParent(state->r, stack);
        if (gistinserttuples(state, stack->parent, giststate,
                             &right->downlink, 1,
                             InvalidOffsetNumber,
                             left->buf, right->buf, false, false))
        {
            /*
-            * If the parent page was split, need to relocate the original
-            * parent pointer.
+            * If the parent page was split, the existing downlink might
+            * have moved.
             */
            stack->downlinkoffnum = InvalidOffsetNumber;
-           gistFindCorrectParent(state->r, stack);
        }
        /* gistinserttuples() released the lock on right->buf. */
    }
@@ -1361,13 +1360,21 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
     */
    tuples[0] = left->downlink;
    tuples[1] = right->downlink;
-   gistinserttuples(state, stack->parent, giststate,
-                    tuples, 2,
-                    stack->downlinkoffnum,
-                    left->buf, right->buf,
-                    true,      /* Unlock parent */
-                    unlockbuf  /* Unlock stack->buffer if caller wants that */
-       );
+   gistFindCorrectParent(state->r, stack);
+   if (gistinserttuples(state, stack->parent, giststate,
+                        tuples, 2,
+                        stack->downlinkoffnum,
+                        left->buf, right->buf,
+                        true,      /* Unlock parent */
+                        unlockbuf  /* Unlock stack->buffer if caller wants that */
+           ))
+   {
+       /*
+        * If the parent page was split, the downlink might have moved.
+        */
+       stack->downlinkoffnum = InvalidOffsetNumber;
+   }
+
    Assert(left->buf == stack->buffer);
 
    /*