]> granicus.if.org Git - postgresql/commitdiff
Improve hash_array() logic for combining hash values.
authorRobert Haas <rhaas@postgresql.org>
Mon, 23 May 2011 19:17:18 +0000 (15:17 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 23 May 2011 19:17:18 +0000 (15:17 -0400)
The new logic is less vulnerable to transpositions.

This invalidates the contents of hash indexes built with the old
functions; hence, bump catversion.

Dean Rasheed

src/backend/utils/adt/arrayfuncs.c
src/include/catalog/catversion.h

index a8af6f09537c7651e39ac624ef933bdc90497203..3e43e951e10c2897f1612b7ca1ffcce3ecc514f8 100644 (file)
@@ -3533,7 +3533,7 @@ hash_array(PG_FUNCTION_ARGS)
        int                     ndims = ARR_NDIM(array);
        int                *dims = ARR_DIMS(array);
        Oid                     element_type = ARR_ELEMTYPE(array);
-       uint32          result = 0;
+       uint32          result = 1;
        int                     nitems;
        TypeCacheEntry *typentry;
        int                     typlen;
@@ -3617,11 +3617,17 @@ hash_array(PG_FUNCTION_ARGS)
                }
 
                /*
-                * Combine hash values of successive elements by rotating the previous
-                * value left 1 bit, then XOR'ing in the new element's hash value.
+                * Combine hash values of successive elements by multiplying the
+                * current value by 31 and adding on the new element's hash value.
+                *
+                * The result is a sum in which each element's hash value is
+                * multiplied by a different power of 31. This is modulo 2^32
+                * arithmetic, and the powers of 31 modulo 2^32 form a cyclic group of
+                * order 2^27. So for arrays of up to 2^27 elements, each element's
+                * hash value is multiplied by a different (odd) number, resulting in
+                * a good mixing of all the elements' hash values.
                 */
-               result = (result << 1) | (result >> 31);
-               result ^= elthash;
+               result = (result << 5) - result + elthash;
        }
 
        /* Avoid leaking memory when handed toasted input. */
index 49d1e7db6f2446388bed10642396160b5db63ce5..0200a81dbf6394106b8aa6ce236bd5e96f5a74ce 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201105131
+#define CATALOG_VERSION_NO     201105231
 
 #endif