aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-02-07 18:22:27 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2013-02-07 18:22:27 -0500
commitff1e846d346c357d84fd5cbcf6a1bc8969c268ab (patch)
tree5604d12b1d6a63b2c2632cb02af8cbfa288e28b8
parentf8a1ef8c3b67fd40e4104d4b1efe3586f6952dc6 (diff)
downloadpostgresql-ff1e846d346c357d84fd5cbcf6a1bc8969c268ab.tar.gz
postgresql-ff1e846d346c357d84fd5cbcf6a1bc8969c268ab.zip
Fix erroneous range-union logic for varlena types in contrib/btree_gist.
gbt_var_bin_union() failed to do the right thing when the existing range needed to be widened at both ends rather than just one end. This could result in an invalid index in which keys that are present would not be found by searches, because the searches would not think they need to descend to the relevant leaf pages. This error affected all the varlena datatypes supported by btree_gist (text, bytea, bit, numeric). Per investigation of a trouble report from Tomas Vondra. (There is also an issue in gbt_var_penalty(), but that should only result in inefficiency not wrong answers. I'm committing this separately so that we have a git state in which it can be tested that bad penalty results don't produce invalid indexes.) Back-patch to all supported branches.
-rw-r--r--contrib/btree_gist/btree_utils_var.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/contrib/btree_gist/btree_utils_var.c b/contrib/btree_gist/btree_utils_var.c
index 9f8a132775b..691b10388ed 100644
--- a/contrib/btree_gist/btree_utils_var.c
+++ b/contrib/btree_gist/btree_utils_var.c
@@ -225,13 +225,13 @@ void
gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
const gbtree_vinfo *tinfo)
{
- GBT_VARKEY *nk = NULL;
- GBT_VARKEY *tmp = NULL;
- GBT_VARKEY_R nr;
GBT_VARKEY_R eo = gbt_var_key_readable(e);
+ GBT_VARKEY_R nr;
if (eo.lower == eo.upper) /* leaf */
{
+ GBT_VARKEY *tmp;
+
tmp = gbt_var_leaf2node(e, tinfo);
if (tmp != e)
eo = gbt_var_key_readable(tmp);
@@ -239,25 +239,26 @@ gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
if (DatumGetPointer(*u))
{
-
GBT_VARKEY_R ro = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(*u));
+ bool update = false;
+
+ nr.lower = ro.lower;
+ nr.upper = ro.upper;
if ((*tinfo->f_cmp) (ro.lower, eo.lower, collation) > 0)
{
nr.lower = eo.lower;
- nr.upper = ro.upper;
- nk = gbt_var_key_copy(&nr, TRUE);
+ update = true;
}
if ((*tinfo->f_cmp) (ro.upper, eo.upper, collation) < 0)
{
nr.upper = eo.upper;
- nr.lower = ro.lower;
- nk = gbt_var_key_copy(&nr, TRUE);
+ update = true;
}
- if (nk)
- *u = PointerGetDatum(nk);
+ if (update)
+ *u = PointerGetDatum(gbt_var_key_copy(&nr, TRUE));
}
else
{