summaryrefslogtreecommitdiff
path: root/src/backend/access/gist
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2009-04-07 17:48:11 +0000
committerTeodor Sigaev <teodor@sigaev.ru>2009-04-07 17:48:11 +0000
commit077d10dcb9ebb6f7a9d40be2b01764c91b510bf1 (patch)
tree03f43218088ff24f293b06a56425e201ec94402f /src/backend/access/gist
parentc58da6562845a9b8e4df7dd3f3ae0d95b6c1e267 (diff)
Fix 'all at one page bug' in picksplit method of R-tree emulation. Add defense
from buggy user-defined picksplit to GiST.
Diffstat (limited to 'src/backend/access/gist')
-rw-r--r--src/backend/access/gist/gist.c82
1 files changed, 76 insertions, 6 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 75e29473263..0e86f77265f 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.112.4.1 2005/08/30 07:57:48 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.112.4.2 2009/04/07 17:48:11 teodor Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1200,6 +1200,63 @@ gistadjsubkey(Relation r,
}
/*
+ * Trivial picksplit implementaion. Function called only
+ * if user-defined picksplit puts all keys to the one page.
+ * That is a bug of user-defined picksplit but we'd like
+ * to "fix" that.
+ */
+static void
+genericPickSplit(GISTSTATE *giststate, GistEntryVector *entryvec, GIST_SPLITVEC *v)
+{
+ OffsetNumber i,
+ maxoff;
+ int nbytes;
+ GistEntryVector *evec;
+
+ maxoff = entryvec->n - 1;
+
+ nbytes = (maxoff + 2) * sizeof(OffsetNumber);
+
+ v->spl_left = (OffsetNumber *) palloc(nbytes);
+ v->spl_right = (OffsetNumber *) palloc(nbytes);
+ v->spl_nleft = v->spl_nright = 0;
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
+ {
+ v->spl_left[v->spl_nleft] = i;
+ v->spl_nleft++;
+ }
+ else
+ {
+ v->spl_right[v->spl_nright] = i;
+ v->spl_nright++;
+ }
+ }
+
+ /*
+ * Form unions of each page
+ */
+
+ evec = palloc( sizeof(GISTENTRY) * entryvec->n + GEVHDRSZ );
+
+ evec->n = v->spl_nleft;
+ memcpy(evec->vector, entryvec->vector + FirstOffsetNumber,
+ sizeof(GISTENTRY) * evec->n);
+ v->spl_ldatum = FunctionCall2(&giststate->unionFn[0],
+ PointerGetDatum(evec),
+ PointerGetDatum(&nbytes));
+
+ evec->n = v->spl_nright;
+ memcpy(evec->vector, entryvec->vector + FirstOffsetNumber + v->spl_nleft,
+ sizeof(GISTENTRY) * evec->n);
+ v->spl_rdatum = FunctionCall2(&giststate->unionFn[0],
+ PointerGetDatum(evec),
+ PointerGetDatum(&nbytes));
+}
+
+/*
* gistSplit -- split a page in the tree.
*/
static IndexTuple *
@@ -1284,11 +1341,24 @@ gistSplit(Relation r,
PointerGetDatum(entryvec),
PointerGetDatum(&v));
- /* compatibility with old code */
- if (v.spl_left[v.spl_nleft - 1] == InvalidOffsetNumber)
- v.spl_left[v.spl_nleft - 1] = (OffsetNumber) *len;
- if (v.spl_right[v.spl_nright - 1] == InvalidOffsetNumber)
- v.spl_right[v.spl_nright - 1] = (OffsetNumber) *len;
+ if ( v.spl_nleft == 0 || v.spl_nright == 0 )
+ {
+ ereport(DEBUG1,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("Picksplit method for first column of index \"%s\" failed",
+ RelationGetRelationName(r)),
+ errhint("Index is not optimal, to optimize it contact developer or try to use the column as a second one in create index command")));
+
+ genericPickSplit(giststate, entryvec, &v);
+ }
+ else
+ {
+ /* compatibility with old code */
+ if (v.spl_left[v.spl_nleft - 1] == InvalidOffsetNumber)
+ v.spl_left[v.spl_nleft - 1] = (OffsetNumber) *len;
+ if (v.spl_right[v.spl_nright - 1] == InvalidOffsetNumber)
+ v.spl_right[v.spl_nright - 1] = (OffsetNumber) *len;
+ }
v.spl_lattr[0] = v.spl_ldatum;
v.spl_rattr[0] = v.spl_rdatum;