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