Fix crash in the new GiST insertion code, when an update splits the root page.

This bug was exercised by contrib/intarray/bench, as noted by Tom Lane.
This commit is contained in:
Heikki Linnakangas 2011-01-09 21:09:58 +02:00
parent 52fd2d65a3
commit ca63029eac
1 changed files with 18 additions and 12 deletions

View File

@ -741,22 +741,28 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
/* /*
* Update the tuple. * Update the tuple.
* *
* gistinserthere() might have to split the page to make the * We still hold the lock after gistinserttuples(), but it
* updated tuple fit. It will adjust the stack so that after * might have to split the page to make the updated tuple fit.
* the call, we'll be holding a lock on the page containing * In that case the updated tuple might migrate to the other
* the tuple, which might have moved right. * half of the split, so we have to go back to the parent and
* * descend back to the half that's a better fit for the new
* Except if this causes a root split, gistinserthere() * tuple.
* returns 'true'. In that case, stack only holds the new
* root, and the child page was released. Have to start
* all over.
*/ */
if (gistinserttuples(&state, stack, giststate, &newtup, 1, if (gistinserttuples(&state, stack, giststate, &newtup, 1,
stack->childoffnum, InvalidBuffer)) stack->childoffnum, InvalidBuffer))
{
/*
* If this was a root split, the root page continues to
* be the parent and the updated tuple went to one of the
* child pages, so we just need to retry from the root
* page.
*/
if (stack->blkno != GIST_ROOT_BLKNO)
{ {
UnlockReleaseBuffer(stack->buffer); UnlockReleaseBuffer(stack->buffer);
xlocked = false; xlocked = false;
state.stack = stack = stack->parent; state.stack = stack = stack->parent;
}
continue; continue;
} }
} }