postgresql/src/backend/access/gist/gistsplit.c

626 lines
16 KiB
C
Raw Normal View History

2006-06-28 14:08:35 +02:00
/*-------------------------------------------------------------------------
*
* gistsplit.c
* Split page algorithm
*
*
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
2006-06-28 14:08:35 +02:00
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
2010-09-20 22:08:53 +02:00
* src/backend/access/gist/gistsplit.c
2006-06-28 14:08:35 +02:00
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/gist_private.h"
#include "utils/rel.h"
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
typedef struct
{
2006-06-28 14:08:35 +02:00
OffsetNumber *entries;
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.
2013-02-07 23:44:02 +01:00
int len;
Datum *attr;
2006-10-04 02:30:14 +02:00
bool *isnull;
bool *equiv;
2006-06-28 14:08:35 +02:00
} GistSplitUnion;
/*
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.
2013-02-07 23:44:02 +01:00
* Form unions of subkeys after a page split, ignoring any tuples
* that are marked in gsvp->equiv[]
2006-06-28 14:08:35 +02:00
*/
2006-10-04 02:30:14 +02:00
static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
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.
2013-02-07 23:44:02 +01:00
GistSplitUnion *gsvp)
2006-10-04 02:30:14 +02:00
{
IndexTuple *cleanedItVec;
int i,
cleanedLen = 0;
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
cleanedItVec = (IndexTuple *) palloc(sizeof(IndexTuple) * gsvp->len);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
for (i = 0; i < gsvp->len; i++)
{
if (gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
2006-06-28 14:08:35 +02:00
continue;
cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
}
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.
2013-02-07 23:44:02 +01:00
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen,
2006-10-04 02:30:14 +02:00
gsvp->attr, gsvp->isnull);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
pfree(cleanedItVec);
2006-06-28 14:08:35 +02:00
}
/*
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.
2013-02-07 23:44:02 +01:00
* Recompute unions of subkeys after a page split, ignoring any tuples
* that are marked in spl->spl_equiv[]
2006-06-28 14:08:35 +02:00
*/
static void
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.
2013-02-07 23:44:02 +01:00
gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl)
2006-06-28 14:08:35 +02:00
{
2006-10-04 02:30:14 +02:00
GistSplitUnion gsvp;
2006-06-28 14:08:35 +02:00
gsvp.equiv = spl->spl_equiv;
gsvp.entries = spl->splitVector.spl_left;
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.
2013-02-07 23:44:02 +01:00
gsvp.len = spl->splitVector.spl_nleft;
gsvp.attr = spl->spl_lattr;
2006-06-28 14:08:35 +02:00
gsvp.isnull = spl->spl_lisnull;
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.
2013-02-07 23:44:02 +01:00
gistunionsubkeyvec(giststate, itvec, &gsvp);
2006-06-28 14:08:35 +02:00
gsvp.entries = spl->splitVector.spl_right;
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.
2013-02-07 23:44:02 +01:00
gsvp.len = spl->splitVector.spl_nright;
gsvp.attr = spl->spl_rattr;
2006-06-28 14:08:35 +02:00
gsvp.isnull = spl->spl_risnull;
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.
2013-02-07 23:44:02 +01:00
gistunionsubkeyvec(giststate, itvec, &gsvp);
2006-06-28 14:08:35 +02:00
}
/*
2006-10-04 02:30:14 +02:00
* find group in vector with equivalent value
2006-06-28 14:08:35 +02:00
*/
static int
gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVector *spl, int attno)
{
int i;
GISTENTRY entry;
2006-10-04 02:30:14 +02:00
int len = 0;
2006-06-28 14:08:35 +02:00
/*
2006-10-04 02:30:14 +02:00
* attno key is always not null (see gistSplitByKey), so we may not check
* for nulls
2006-06-28 14:08:35 +02:00
*/
gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL, (OffsetNumber) 0, FALSE);
2006-10-04 02:30:14 +02:00
for (i = 0; i < spl->splitVector.spl_nleft; i++)
{
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_left[i]], false);
if (penalty == 0.0)
{
2006-06-28 14:08:35 +02:00
spl->spl_equiv[spl->splitVector.spl_left[i]] = true;
len++;
}
}
gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL, (OffsetNumber) 0, FALSE);
2006-10-04 02:30:14 +02:00
for (i = 0; i < spl->splitVector.spl_nright; i++)
{
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_right[i]], false);
if (penalty == 0.0)
{
2006-06-28 14:08:35 +02:00
spl->spl_equiv[spl->splitVector.spl_right[i]] = true;
len++;
}
}
return len;
}
static void
2006-10-04 02:30:14 +02:00
cleanupOffsets(OffsetNumber *a, int *len, bool *equiv, int *LenEquiv)
{
int curlen,
i;
OffsetNumber *curwpos;
2006-06-28 14:08:35 +02:00
curlen = *len;
curwpos = a;
2006-10-04 02:30:14 +02:00
for (i = 0; i < *len; i++)
{
if (equiv[a[i]] == FALSE)
{
2006-06-28 14:08:35 +02:00
*curwpos = a[i];
curwpos++;
2006-10-04 02:30:14 +02:00
}
else
{
2006-06-28 14:08:35 +02:00
/* corner case: we shouldn't make void array */
2006-10-04 02:30:14 +02:00
if (curlen == 1)
{
equiv[a[i]] = FALSE; /* mark item as non-equivalent */
i--; /* redo the same */
2006-06-28 14:08:35 +02:00
*LenEquiv -= 1;
continue;
2006-10-04 02:30:14 +02:00
}
else
2006-06-28 14:08:35 +02:00
curlen--;
}
}
*len = curlen;
}
static void
2006-10-04 02:30:14 +02:00
placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno)
{
2006-06-28 14:08:35 +02:00
GISTENTRY identry[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
2006-10-04 02:30:14 +02:00
bool toLeft = true;
2006-06-28 14:08:35 +02:00
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull);
2006-10-04 02:30:14 +02:00
for (; attno < giststate->tupdesc->natts; attno++)
{
float lpenalty,
rpenalty;
2006-06-28 14:08:35 +02:00
GISTENTRY entry;
2006-10-04 02:30:14 +02:00
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry + attno, isnull[attno]);
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry + attno, isnull[attno]);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
if (lpenalty != rpenalty)
{
if (lpenalty > rpenalty)
2006-06-28 14:08:35 +02:00
toLeft = false;
break;
}
}
2006-10-04 02:30:14 +02:00
if (toLeft)
v->splitVector.spl_left[v->splitVector.spl_nleft++] = off;
2006-06-28 14:08:35 +02:00
else
2006-10-04 02:30:14 +02:00
v->splitVector.spl_right[v->splitVector.spl_nright++] = off;
2006-06-28 14:08:35 +02:00
}
#define SWAPVAR( s, d, t ) \
do { \
(t) = (s); \
(s) = (d); \
(d) = (t); \
} while(0)
/*
2006-10-04 02:30:14 +02:00
* adjust left and right unions according to splits by previous
* split by first columns. This function is called only in case
* when pickSplit doesn't support subsplit.
2006-06-28 14:08:35 +02:00
*/
static void
2006-10-04 02:30:14 +02:00
supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
{
bool leaveOnLeft = true,
tmpBool;
GISTENTRY entryL,
entryR,
entrySL,
entrySR;
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
{
float penalty1,
penalty2;
2006-06-28 14:08:35 +02:00
penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) +
2006-10-04 02:30:14 +02:00
gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
2006-06-28 14:08:35 +02:00
penalty2 = gistpenalty(giststate, attno, &entryL, false, &entrySR, false) +
2006-10-04 02:30:14 +02:00
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
if (penalty1 > penalty2)
2006-06-28 14:08:35 +02:00
leaveOnLeft = false;
2006-10-04 02:30:14 +02:00
}
else
{
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
float penalty1,
penalty2;
2006-06-28 14:08:35 +02:00
/*
2006-10-04 02:30:14 +02:00
* there is only one previously defined union, so we just choose swap
* or not by lowest penalty
2006-06-28 14:08:35 +02:00
*/
penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false);
2006-10-04 02:30:14 +02:00
if (penalty1 < penalty2)
leaveOnLeft = (sv->spl_ldatum_exists) ? true : false;
2006-06-28 14:08:35 +02:00
else
2006-10-04 02:30:14 +02:00
leaveOnLeft = (sv->spl_rdatum_exists) ? true : false;
2006-06-28 14:08:35 +02:00
}
2006-10-04 02:30:14 +02:00
if (leaveOnLeft == false)
{
2006-06-28 14:08:35 +02:00
/*
2006-10-04 02:30:14 +02:00
* swap left and right
2006-06-28 14:08:35 +02:00
*/
2006-10-04 02:30:14 +02:00
OffsetNumber *off,
noff;
Datum datum;
SWAPVAR(sv->spl_left, sv->spl_right, off);
SWAPVAR(sv->spl_nleft, sv->spl_nright, noff);
SWAPVAR(sv->spl_ldatum, sv->spl_rdatum, datum);
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
2006-06-28 14:08:35 +02:00
}
2006-10-04 02:30:14 +02:00
if (sv->spl_ldatum_exists)
2006-06-28 14:08:35 +02:00
gistMakeUnionKey(giststate, attno, &entryL, false, &entrySL, false,
2006-10-04 02:30:14 +02:00
&sv->spl_ldatum, &tmpBool);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
if (sv->spl_rdatum_exists)
2006-06-28 14:08:35 +02:00
gistMakeUnionKey(giststate, attno, &entryR, false, &entrySR, false,
2006-10-04 02:30:14 +02:00
&sv->spl_rdatum, &tmpBool);
2006-06-28 14:08:35 +02:00
sv->spl_ldatum_exists = sv->spl_rdatum_exists = false;
}
/*
* 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, int attno)
{
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 = FunctionCall2Coll(&giststate->unionFn[attno],
giststate->supportCollation[attno],
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 = FunctionCall2Coll(&giststate->unionFn[attno],
giststate->supportCollation[attno],
PointerGetDatum(evec),
PointerGetDatum(&nbytes));
}
2006-06-28 14:08:35 +02:00
/*
* Calls user picksplit method for attno columns to split vector to
* two vectors. May use attno+n columns data to
* get better split.
* Returns TRUE and v->spl_equiv = NULL if left and right unions of attno columns are the same,
* so caller may find better split
2006-10-04 02:30:14 +02:00
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
2006-06-28 14:08:35 +02:00
*/
static bool
gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v,
IndexTuple *itup, int len, GISTSTATE *giststate)
{
GIST_SPLITVEC *sv = &v->splitVector;
2006-10-04 02:30:14 +02:00
2006-06-28 14:08:35 +02:00
/*
* now let the user-defined picksplit function set up the split vector; in
* entryvec there is no null value!!
2006-06-28 14:08:35 +02:00
*/
2006-10-04 02:30:14 +02:00
sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
2006-06-28 14:08:35 +02:00
sv->spl_ldatum = v->spl_lattr[attno];
sv->spl_rdatum = v->spl_rattr[attno];
FunctionCall2Coll(&giststate->picksplitFn[attno],
giststate->supportCollation[attno],
PointerGetDatum(entryvec),
PointerGetDatum(sv));
2006-06-28 14:08:35 +02:00
if (sv->spl_nleft == 0 || sv->spl_nright == 0)
{
ereport(DEBUG1,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("picksplit method for column %d of index \"%s\" failed",
attno + 1, RelationGetRelationName(r)),
errhint("The index is not optimal. To optimize it, contact a developer, or try to use the column as the second one in the CREATE INDEX command.")));
2006-06-28 14:08:35 +02:00
/*
* Reinit GIST_SPLITVEC. Although that fields are not used by
* genericPickSplit(), let us set up it for further processing
*/
sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
sv->spl_ldatum = v->spl_lattr[attno];
sv->spl_rdatum = v->spl_rattr[attno];
genericPickSplit(giststate, entryvec, sv, attno);
if (sv->spl_ldatum_exists || sv->spl_rdatum_exists)
supportSecondarySplit(r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno]);
}
else
2006-10-04 02:30:14 +02:00
{
/* compatibility with old code */
if (sv->spl_left[sv->spl_nleft - 1] == InvalidOffsetNumber)
sv->spl_left[sv->spl_nleft - 1] = (OffsetNumber) (entryvec->n - 1);
if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber)
sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1);
2006-06-28 14:08:35 +02:00
if (sv->spl_ldatum_exists || sv->spl_rdatum_exists)
{
elog(DEBUG1, "picksplit method for column %d of index \"%s\" doesn't support secondary split",
attno + 1, RelationGetRelationName(r));
supportSecondarySplit(r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno]);
}
2006-06-28 14:08:35 +02:00
}
v->spl_lattr[attno] = sv->spl_ldatum;
v->spl_rattr[attno] = sv->spl_rdatum;
v->spl_lisnull[attno] = false;
v->spl_risnull[attno] = false;
/*
* if index is multikey, then we must to try get smaller bounding box for
* subkey(s)
*/
v->spl_equiv = NULL;
2006-10-04 02:30:14 +02:00
if (giststate->tupdesc->natts > 1 && attno + 1 != giststate->tupdesc->natts)
2006-06-28 14:08:35 +02:00
{
2006-10-04 02:30:14 +02:00
if (gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum))
{
2006-06-28 14:08:35 +02:00
/*
2006-10-04 02:30:14 +02:00
* Left and right key's unions are equial, so we can get better
* split by following columns. Note, unions for attno columns are
* already done.
2006-06-28 14:08:35 +02:00
*/
return true;
2006-10-04 02:30:14 +02:00
}
else
{
2006-06-28 14:08:35 +02:00
int LenEquiv;
2006-10-04 02:30:14 +02:00
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
2006-06-28 14:08:35 +02:00
LenEquiv = gistfindgroup(r, giststate, entryvec->vector, v, attno);
/*
2006-10-04 02:30:14 +02:00
* if possible, we should distribute equivalent tuples
*/
if (LenEquiv == 0)
{
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.
2013-02-07 23:44:02 +01:00
gistunionsubkey(giststate, itup, v);
2006-10-04 02:30:14 +02:00
}
else
{
cleanupOffsets(sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv);
cleanupOffsets(sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv);
2006-06-28 14:08:35 +02:00
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.
2013-02-07 23:44:02 +01:00
gistunionsubkey(giststate, itup, v);
2006-10-04 02:30:14 +02:00
if (LenEquiv == 1)
{
2006-06-28 14:08:35 +02:00
/*
2006-10-04 02:30:14 +02:00
* In case with one tuple we just choose left-right by
* penalty. It's simplify user-defined pickSplit
2006-06-28 14:08:35 +02:00
*/
OffsetNumber toMove = InvalidOffsetNumber;
2006-10-04 02:30:14 +02:00
for (toMove = FirstOffsetNumber; toMove < entryvec->n; toMove++)
if (v->spl_equiv[toMove])
2006-06-28 14:08:35 +02:00
break;
2006-10-04 02:30:14 +02:00
Assert(toMove < entryvec->n);
placeOne(r, giststate, v, itup[toMove - 1], toMove, attno + 1);
/*
* redo gistunionsubkey(): it will not degradate
* performance, because it's very rarely
*/
2006-06-28 14:08:35 +02:00
v->spl_equiv = NULL;
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.
2013-02-07 23:44:02 +01:00
gistunionsubkey(giststate, itup, v);
2006-06-28 14:08:35 +02:00
return false;
2006-10-04 02:30:14 +02:00
}
else if (LenEquiv > 1)
2006-06-28 14:08:35 +02:00
return true;
}
}
}
return false;
}
/*
2006-10-04 02:30:14 +02:00
* simple split page
2006-06-28 14:08:35 +02:00
*/
static void
2006-10-04 02:30:14 +02:00
gistSplitHalf(GIST_SPLITVEC *v, int len)
{
int i;
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
v->spl_nright = v->spl_nleft = 0;
2006-06-28 14:08:35 +02:00
v->spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
2006-10-04 02:30:14 +02:00
v->spl_right = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
for (i = 1; i <= len; i++)
if (i < len / 2)
v->spl_right[v->spl_nright++] = i;
2006-06-28 14:08:35 +02:00
else
2006-10-04 02:30:14 +02:00
v->spl_left[v->spl_nleft++] = i;
2006-06-28 14:08:35 +02:00
}
/*
* tries to split page by attno key, in case of null
* values move those to separate page.
2006-06-28 14:08:35 +02:00
*/
void
2006-10-04 02:30:14 +02:00
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
GistSplitVector *v, GistEntryVector *entryvec, int attno)
{
int i;
static OffsetNumber offNullTuples[MaxOffsetNumber];
int nOffNullTuples = 0;
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
for (i = 1; i <= len; i++)
{
Datum datum;
bool IsNull;
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
datum = index_getattr(itup[i - 1], attno + 1, giststate->tupdesc, &IsNull);
2006-06-28 14:08:35 +02:00
gistdentryinit(giststate, attno, &(entryvec->vector[i]),
datum, r, page, i,
FALSE, IsNull);
2006-10-04 02:30:14 +02:00
if (IsNull)
offNullTuples[nOffNullTuples++] = i;
2006-06-28 14:08:35 +02:00
}
2006-10-04 02:30:14 +02:00
if (nOffNullTuples == len)
{
/*
2006-06-28 14:08:35 +02:00
* Corner case: All keys in attno column are null, we should try to
* split by keys in next column. If all keys in all columns are NULL
2006-10-04 02:30:14 +02:00
* just split page half by half
2006-06-28 14:08:35 +02:00
*/
v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
2006-10-04 02:30:14 +02:00
if (attno + 1 == r->rd_att->natts)
gistSplitHalf(&v->splitVector, len);
else
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
}
else if (nOffNullTuples > 0)
{
int j = 0;
/*
* We don't want to mix NULLs and not-NULLs keys on one page, so move
* nulls to right page
2006-06-28 14:08:35 +02:00
*/
v->splitVector.spl_right = offNullTuples;
v->splitVector.spl_nright = nOffNullTuples;
v->spl_risnull[attno] = TRUE;
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0;
2006-10-04 02:30:14 +02:00
for (i = 1; i <= len; i++)
if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
2006-06-28 14:08:35 +02:00
j++;
else
2006-10-04 02:30:14 +02:00
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
2006-06-28 14:08:35 +02:00
v->spl_equiv = NULL;
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.
2013-02-07 23:44:02 +01:00
gistunionsubkey(giststate, itup, v);
2006-10-04 02:30:14 +02:00
}
else
{
2006-06-28 14:08:35 +02:00
/*
* all keys are not-null
*/
2006-10-04 02:30:14 +02:00
entryvec->n = len + 1;
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
if (gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno + 1 != r->rd_att->natts)
{
2006-06-28 14:08:35 +02:00
/*
2006-10-04 02:30:14 +02:00
* Splitting on attno column is not optimized: there is a tuples
* which can be freely left or right page, we will try to split
* page by following columns
2006-06-28 14:08:35 +02:00
*/
2006-10-04 02:30:14 +02:00
if (v->spl_equiv == NULL)
{
/*
* simple case: left and right keys for attno column are equal
2006-10-04 02:30:14 +02:00
*/
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
}
else
{
2006-06-28 14:08:35 +02:00
/* we should clean up vector from already distributed tuples */
2006-10-04 02:30:14 +02:00
IndexTuple *newitup = (IndexTuple *) palloc((len + 1) * sizeof(IndexTuple));
OffsetNumber *map = (OffsetNumber *) palloc((len + 1) * sizeof(IndexTuple));
int newlen = 0;
2006-06-28 14:08:35 +02:00
GIST_SPLITVEC backupSplit = v->splitVector;
2006-10-04 02:30:14 +02:00
for (i = 0; i < len; i++)
if (v->spl_equiv[i + 1])
{
map[newlen] = i + 1;
newitup[newlen++] = itup[i];
2006-06-28 14:08:35 +02:00
}
2006-10-04 02:30:14 +02:00
Assert(newlen > 0);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy(backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber) * v->splitVector.spl_nright);
2006-06-28 14:08:35 +02:00
2006-10-04 02:30:14 +02:00
gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno + 1);
2006-06-28 14:08:35 +02:00
/* merge result of subsplit */
2006-10-04 02:30:14 +02:00
for (i = 0; i < v->splitVector.spl_nleft; i++)
backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
for (i = 0; i < v->splitVector.spl_nright; i++)
backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
2006-06-28 14:08:35 +02:00
v->splitVector = backupSplit;
/* reunion left and right datums */
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.
2013-02-07 23:44:02 +01:00
gistunionsubkey(giststate, itup, v);
2006-06-28 14:08:35 +02:00
}
2006-10-04 02:30:14 +02:00
}
2006-06-28 14:08:35 +02:00
}
}