summaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gist.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2011-01-09 21:09:58 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2011-01-09 21:36:22 +0200
commitca63029eac379d82f78a985a5d4068b9954deb02 (patch)
treecc73bbef1f2b6233b482874aae9627085f662482 /src/backend/access/gist/gist.c
parent52fd2d65a33c9c33b29788e9df89d7716f1ec0bc (diff)
downloadpostgresql-ca63029eac379d82f78a985a5d4068b9954deb02.tar.gz
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.
Diffstat (limited to 'src/backend/access/gist/gist.c')
-rw-r--r--src/backend/access/gist/gist.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 4bd1e43827..9529413e80 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -741,22 +741,28 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
/*
* Update the tuple.
*
- * gistinserthere() might have to split the page to make the
- * updated tuple fit. It will adjust the stack so that after
- * the call, we'll be holding a lock on the page containing
- * the tuple, which might have moved right.
- *
- * Except if this causes a root split, gistinserthere()
- * returns 'true'. In that case, stack only holds the new
- * root, and the child page was released. Have to start
- * all over.
+ * We still hold the lock after gistinserttuples(), but it
+ * might have to split the page to make the updated tuple fit.
+ * In that case the updated tuple might migrate to the other
+ * 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
+ * tuple.
*/
if (gistinserttuples(&state, stack, giststate, &newtup, 1,
stack->childoffnum, InvalidBuffer))
{
- UnlockReleaseBuffer(stack->buffer);
- xlocked = false;
- state.stack = stack = stack->parent;
+ /*
+ * 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);
+ xlocked = false;
+ state.stack = stack = stack->parent;
+ }
continue;
}
}