aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gistsplit.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-02-07 17:44:02 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2013-02-07 17:44:02 -0500
commit166d534fcd1d16edb7c6d57429b2ebde80c02ff7 (patch)
treeab34996053264db74315877e9737f64ef8259213 /src/backend/access/gist/gistsplit.c
parentc5aad8dc14d8ad9d7d55ee4a9b136b6273c7991a (diff)
downloadpostgresql-166d534fcd1d16edb7c6d57429b2ebde80c02ff7.tar.gz
postgresql-166d534fcd1d16edb7c6d57429b2ebde80c02ff7.zip
Repair bugs in GiST page splitting code for multi-column indexes.
When considering a non-last column in a multi-column GiST index, gistsplit.c tries to improve on the split chosen by the opclass-specific pickSplit function by considering penalties for the next column. However, there were two bugs in this code: it failed to recompute the union keys for the leftmost index columns, even though these might well change after reassigning tuples; and it included the old union keys in the recomputation for the columns it did recompute, so that those keys couldn't get smaller even if they should. The first problem could result in an invalid index in which searches wouldn't find index entries that are in fact present; the second would make the index less efficient to search. Both of these errors were caused by misuse of gistMakeUnionItVec, whose API was designed in a way that just begged such errors to be made. There is no situation in which it's safe or useful to compute the union keys for a subset of the index columns, and there is no caller that wants any previous union keys to be included in the computation; so the undocumented choice to treat the union keys as in/out rather than pure output parameters is a waste of code as well as being dangerous. Hence, rather than just making a minimal patch, I've changed the API of gistMakeUnionItVec to remove the "startkey" parameter (it now always processes all index columns) and treat the attr/isnull arrays as purely output parameters. In passing, also get rid of a couple of unnecessary and dangerous uses of static variables in gistutil.c. It's remarkable that the one in gistMakeUnionKey hasn't given us portability troubles before now, because in addition to posing a re-entrancy hazard, it was unsafely assuming that a static char[] array would have at least Datum alignment. Per investigation of a trouble report from Tomas Vondra. (There are also some bugs in contrib/btree_gist to be fixed, but that seems like material for a separate patch.) Back-patch to all supported branches.
Diffstat (limited to 'src/backend/access/gist/gistsplit.c')
-rw-r--r--src/backend/access/gist/gistsplit.c39
1 files changed, 20 insertions, 19 deletions
diff --git a/src/backend/access/gist/gistsplit.c b/src/backend/access/gist/gistsplit.c
index a96b881cf1d..fd35dd2e52d 100644
--- a/src/backend/access/gist/gistsplit.c
+++ b/src/backend/access/gist/gistsplit.c
@@ -19,21 +19,21 @@
typedef struct
{
- Datum *attr;
- int len;
OffsetNumber *entries;
+ int len;
+ Datum *attr;
bool *isnull;
bool *equiv;
} GistSplitUnion;
/*
- * Forms unions of subkeys after page split, but
- * uses only tuples that aren't in groups of equivalent tuples
+ * Form unions of subkeys after a page split, ignoring any tuples
+ * that are marked in gsvp->equiv[]
*/
static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
- GistSplitUnion *gsvp, int startkey)
+ GistSplitUnion *gsvp)
{
IndexTuple *cleanedItVec;
int i,
@@ -49,35 +49,36 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
}
- gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
+ gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen,
gsvp->attr, gsvp->isnull);
pfree(cleanedItVec);
}
/*
- * unions subkeys for after user picksplit over attno-1 column
+ * Recompute unions of subkeys after a page split, ignoring any tuples
+ * that are marked in spl->spl_equiv[]
*/
static void
-gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno)
+gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl)
{
GistSplitUnion gsvp;
gsvp.equiv = spl->spl_equiv;
- gsvp.attr = spl->spl_lattr;
- gsvp.len = spl->splitVector.spl_nleft;
gsvp.entries = spl->splitVector.spl_left;
+ gsvp.len = spl->splitVector.spl_nleft;
+ gsvp.attr = spl->spl_lattr;
gsvp.isnull = spl->spl_lisnull;
- gistunionsubkeyvec(giststate, itvec, &gsvp, attno);
+ gistunionsubkeyvec(giststate, itvec, &gsvp);
- gsvp.attr = spl->spl_rattr;
- gsvp.len = spl->splitVector.spl_nright;
gsvp.entries = spl->splitVector.spl_right;
+ gsvp.len = spl->splitVector.spl_nright;
+ gsvp.attr = spl->spl_rattr;
gsvp.isnull = spl->spl_risnull;
- gistunionsubkeyvec(giststate, itvec, &gsvp, attno);
+ gistunionsubkeyvec(giststate, itvec, &gsvp);
}
/*
@@ -443,14 +444,14 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
*/
if (LenEquiv == 0)
{
- gistunionsubkey(giststate, itup, v, attno + 1);
+ gistunionsubkey(giststate, itup, v);
}
else
{
cleanupOffsets(sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv);
cleanupOffsets(sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv);
- gistunionsubkey(giststate, itup, v, attno + 1);
+ gistunionsubkey(giststate, itup, v);
if (LenEquiv == 1)
{
/*
@@ -471,7 +472,7 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
* performance, because it's very rarely
*/
v->spl_equiv = NULL;
- gistunionsubkey(giststate, itup, v, attno + 1);
+ gistunionsubkey(giststate, itup, v);
return false;
}
@@ -562,7 +563,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_equiv = NULL;
- gistunionsubkey(giststate, itup, v, attno);
+ gistunionsubkey(giststate, itup, v);
}
else
{
@@ -617,7 +618,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
v->splitVector = backupSplit;
/* reunion left and right datums */
- gistunionsubkey(giststate, itup, v, attno);
+ gistunionsubkey(giststate, itup, v);
}
}
}