aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gistproc.c
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2009-04-06 14:47:02 +0000
committerTeodor Sigaev <teodor@sigaev.ru>2009-04-06 14:47:02 +0000
commit4bc176deae5a6a7e6ac55d79f0cc28591bc4ae38 (patch)
treedfdea517f9dbb9dcb429128ee1b9fea77800a1ac /src/backend/access/gist/gistproc.c
parent9462a22ab61ff49a79eeac860b66bb0dd6405266 (diff)
downloadpostgresql-4bc176deae5a6a7e6ac55d79f0cc28591bc4ae38.tar.gz
postgresql-4bc176deae5a6a7e6ac55d79f0cc28591bc4ae38.zip
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/gistproc.c')
-rw-r--r--src/backend/access/gist/gistproc.c121
1 files changed, 80 insertions, 41 deletions
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 45e73107b29..9ba1d9ec252 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.9.2.1 2007/09/07 17:04:46 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.9.2.2 2009/04/06 14:47:02 teodor Exp $
*
*-------------------------------------------------------------------------
*/
@@ -268,6 +268,69 @@ chooseLR(GIST_SPLITVEC *v,
}
/*
+ * Trivial split: half of entries will be placed on one page
+ * and another half - to another
+ */
+static void
+fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
+{
+ OffsetNumber i,
+ maxoff;
+ BOX *unionL = NULL,
+ *unionR = NULL;
+ int nbytes;
+
+ 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))
+ {
+ BOX * cur = DatumGetBoxP(entryvec->vector[i].key);
+
+ if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
+ {
+ v->spl_left[v->spl_nleft] = i;
+ if (unionL == NULL)
+ {
+ unionL = (BOX *) palloc(sizeof(BOX));
+ *unionL = *cur;
+ }
+ else
+ adjustBox(unionL, cur);
+
+ v->spl_nleft++;
+ }
+ else
+ {
+ v->spl_right[v->spl_nright] = i;
+ if (unionR == NULL)
+ {
+ unionR = (BOX *) palloc(sizeof(BOX));
+ *unionR = *cur;
+ }
+ else
+ adjustBox(unionR, cur);
+
+ v->spl_nright++;
+ }
+ }
+
+ if (v->spl_ldatum_exists)
+ adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
+ v->spl_ldatum = BoxPGetDatum(unionL);
+
+ if (v->spl_rdatum_exists)
+ adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
+ v->spl_rdatum = BoxPGetDatum(unionR);
+
+ v->spl_ldatum_exists = v->spl_rdatum_exists = false;
+}
+
+/*
* The GiST PickSplit method
*
* New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
@@ -319,52 +382,22 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
adjustBox(&pageunion, cur);
}
- nbytes = (maxoff + 2) * sizeof(OffsetNumber);
- listL = (OffsetNumber *) palloc(nbytes);
- listR = (OffsetNumber *) palloc(nbytes);
- unionL = (BOX *) palloc(sizeof(BOX));
- unionR = (BOX *) palloc(sizeof(BOX));
if (allisequal)
{
- cur = DatumGetBoxP(entryvec->vector[OffsetNumberNext(FirstOffsetNumber)].key);
- if (memcmp((void *) cur, (void *) &pageunion, sizeof(BOX)) == 0)
- {
- v->spl_left = listL;
- v->spl_right = listR;
- v->spl_nleft = v->spl_nright = 0;
- memcpy((void *) unionL, (void *) &pageunion, sizeof(BOX));
- memcpy((void *) unionR, (void *) &pageunion, sizeof(BOX));
-
- 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++;
- }
- }
-
- if (v->spl_ldatum_exists)
- adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
- v->spl_ldatum = BoxPGetDatum(unionL);
-
- if (v->spl_rdatum_exists)
- adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
- v->spl_rdatum = BoxPGetDatum(unionR);
-
- v->spl_ldatum_exists = v->spl_rdatum_exists = false;
-
- PG_RETURN_POINTER(v);
- }
+ /*
+ * All entries are the same
+ */
+ fallbackSplit(entryvec, v);
+ PG_RETURN_POINTER(v);
}
+ nbytes = (maxoff + 2) * sizeof(OffsetNumber);
+ listL = (OffsetNumber *) palloc(nbytes);
+ listR = (OffsetNumber *) palloc(nbytes);
listB = (OffsetNumber *) palloc(nbytes);
listT = (OffsetNumber *) palloc(nbytes);
+ unionL = (BOX *) palloc(sizeof(BOX));
+ unionR = (BOX *) palloc(sizeof(BOX));
unionB = (BOX *) palloc(sizeof(BOX));
unionT = (BOX *) palloc(sizeof(BOX));
@@ -445,6 +478,12 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
else
ADDLIST(listT, unionT, posT, i);
}
+
+ if (IS_BADRATIO(posR, posL) && IS_BADRATIO(posT, posB))
+ {
+ fallbackSplit(entryvec, v);
+ PG_RETURN_POINTER(v);
+ }
}
/* which split more optimal? */