]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
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:58:07 +0000 (13:58 +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 a44112befce09acd89982cac36d3ff0defd0ff47..12d8a68c6c16c36a908310fc17800cc48d5940b0 100644 (file)
@@ -1338,10 +1338,9 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
        }
 
        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.
         */
        while (list_length(reversed) > 2)
@@ -1349,17 +1348,17 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
                right = (GISTPageSplitInfo *) linitial(reversed);
                left = (GISTPageSplitInfo *) lsecond(reversed);
 
+               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. */
                reversed = list_delete_first(reversed);
@@ -1375,13 +1374,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);
 
        /*