]> granicus.if.org Git - postgresql/commitdiff
Fix erroneous range-union logic for varlena types in contrib/btree_gist.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Feb 2013 23:22:38 +0000 (18:22 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Feb 2013 23:22:38 +0000 (18:22 -0500)
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.

contrib/btree_gist/btree_utils_var.c

index 916706d8a479650532d16963639c179dd43260b8..10138b1f42ba8c096525dc2e0049ec1a08795100 100644 (file)
@@ -233,14 +233,13 @@ gbt_var_node_truncate(const GBT_VARKEY *node, int32 cpf_length, const gbtree_vin
 void
 gbt_var_bin_union(Datum *u, GBT_VARKEY *e, 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);
@@ -248,25 +247,26 @@ gbt_var_bin_union(Datum *u, GBT_VARKEY *e, const gbtree_vinfo *tinfo)
 
        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) ((bytea *) ro.lower, (bytea *) eo.lower) > 0)
                {
                        nr.lower = eo.lower;
-                       nr.upper = ro.upper;
-                       nk = gbt_var_key_copy(&nr, TRUE);
+                       update = true;
                }
 
                if ((*tinfo->f_cmp) ((bytea *) ro.upper, (bytea *) eo.upper) < 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
        {