]> granicus.if.org Git - postgresql/commitdiff
Add a 64-bit hash function for type hstore.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Nov 2018 18:37:34 +0000 (13:37 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Nov 2018 18:37:34 +0000 (13:37 -0500)
There's some question about the correctness of the hash function, but
if it's wrong, the 32-bit version is also wrong.

Amul Sul, reviewed by Hironobu Suzuki

Discussion: https://postgr.es/m/CAAJ_b947JjnNr9Cp45iNjSqKf6PA5mCTmKsRwPjows93YwQrmw@mail.gmail.com

contrib/hstore/Makefile
contrib/hstore/expected/hstore.out
contrib/hstore/hstore--1.5--1.6.sql [new file with mode: 0644]
contrib/hstore/hstore.control
contrib/hstore/hstore_op.c
contrib/hstore/sql/hstore.sql

index 46d26f8052d869278cc15979c6749142019011d1..b29d02b13722f7db3f8aa649805a7a4bae16869e 100644 (file)
@@ -5,7 +5,9 @@ OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o hstore_compat.o \
        $(WIN32RES)
 
 EXTENSION = hstore
-DATA = hstore--1.4.sql hstore--1.4--1.5.sql \
+DATA = hstore--1.4.sql \
+       hstore--1.5--1.6.sql \
+       hstore--1.4--1.5.sql \
        hstore--1.3--1.4.sql hstore--1.2--1.3.sql \
        hstore--1.1--1.2.sql hstore--1.0--1.1.sql \
        hstore--unpackaged--1.0.sql
index f0d421602d5f01fd7a24aaa4ac9ef3ba490a11a8..4f1db01b3ebcebe8729e9b41c6914a542df1066e 100644 (file)
@@ -1515,3 +1515,15 @@ select json_agg(q) from (select f1, hstore_to_json_loose(f2) as f2 from test_jso
   {"f1":"rec2","f2":{"b": false, "c": "null", "d": -12345, "e": "012345.6", "f": -1.234, "g": 0.345e-4, "a key": 2}}]
 (1 row)
 
+-- Check the hstore_hash() and hstore_hash_extended() function explicitly.
+SELECT v as value, hstore_hash(v)::bit(32) as standard,
+       hstore_hash_extended(v, 0)::bit(32) as extended0,
+       hstore_hash_extended(v, 1)::bit(32) as extended1
+FROM   (VALUES (NULL::hstore), (''), ('"a key" =>1'), ('c => null'),
+       ('e => 012345'), ('g => 2.345e+4')) x(v)
+WHERE  hstore_hash(v)::bit(32) != hstore_hash_extended(v, 0)::bit(32)
+       OR hstore_hash(v)::bit(32) = hstore_hash_extended(v, 1)::bit(32);
+ value | standard | extended0 | extended1 
+-------+----------+-----------+-----------
+(0 rows)
+
diff --git a/contrib/hstore/hstore--1.5--1.6.sql b/contrib/hstore/hstore--1.5--1.6.sql
new file mode 100644 (file)
index 0000000..c5a2bae
--- /dev/null
@@ -0,0 +1,12 @@
+/* contrib/hstore/hstore--1.5--1.6.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION hstore UPDATE TO '1.6'" to load this file. \quit
+
+CREATE FUNCTION hstore_hash_extended(hstore, int8)
+RETURNS int8
+AS 'MODULE_PATHNAME','hstore_hash_extended'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+ALTER OPERATOR FAMILY hash_hstore_ops USING hash ADD
+    FUNCTION    2   hstore_hash_extended(hstore, int8);
index 8a719475b82f4185c9939be3e5ad5848a0aedd74..93688cdd83c33872df276b11a4f67f486b75b72e 100644 (file)
@@ -1,5 +1,5 @@
 # hstore extension
 comment = 'data type for storing sets of (key, value) pairs'
-default_version = '1.5'
+default_version = '1.6'
 module_pathname = '$libdir/hstore'
 relocatable = true
index 8f9277f8da2dd59ca4f84ffddfa3fbff97a234b3..a915215fb6fc00f90ee0bd423b59089be605f93e 100644 (file)
@@ -1240,9 +1240,10 @@ hstore_hash(PG_FUNCTION_ARGS)
                                                                VARSIZE(hs) - VARHDRSZ);
 
        /*
-        * this is the only place in the code that cares whether the overall
-        * varlena size exactly matches the true data size; this assertion should
-        * be maintained by all the other code, but we make it explicit here.
+        * This (along with hstore_hash_extended) is the only place in the code
+        * that cares whether the overall varlena size exactly matches the true
+        * data size; this assertion should be maintained by all the other code,
+        * but we make it explicit here.
         */
        Assert(VARSIZE(hs) ==
                   (HS_COUNT(hs) != 0 ?
@@ -1253,3 +1254,26 @@ hstore_hash(PG_FUNCTION_ARGS)
        PG_FREE_IF_COPY(hs, 0);
        PG_RETURN_DATUM(hval);
 }
+
+PG_FUNCTION_INFO_V1(hstore_hash_extended);
+Datum
+hstore_hash_extended(PG_FUNCTION_ARGS)
+{
+       HStore     *hs = PG_GETARG_HSTORE_P(0);
+       uint64          seed = PG_GETARG_INT64(1);
+       Datum           hval;
+
+       hval = hash_any_extended((unsigned char *) VARDATA(hs),
+                                                        VARSIZE(hs) - VARHDRSZ,
+                                                        seed);
+
+       /* See comment in hstore_hash */
+       Assert(VARSIZE(hs) ==
+                  (HS_COUNT(hs) != 0 ?
+                       CALCDATASIZE(HS_COUNT(hs),
+                                                HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
+                       HSHRDSIZE));
+
+       PG_FREE_IF_COPY(hs, 0);
+       PG_RETURN_DATUM(hval);
+}
index d64b9f77c752d78ca23a418e6baad6523f5bf6d9..76ac48b021da51f1fef67cd4d579b5252fa2b14d 100644 (file)
@@ -350,3 +350,12 @@ insert into test_json_agg values ('rec1','"a key" =>1, b => t, c => null, d=> 12
        ('rec2','"a key" =>2, b => f, c => "null", d=> -12345, e => 012345.6, f=> -1.234, g=> 0.345e-4');
 select json_agg(q) from test_json_agg q;
 select json_agg(q) from (select f1, hstore_to_json_loose(f2) as f2 from test_json_agg) q;
+
+-- Check the hstore_hash() and hstore_hash_extended() function explicitly.
+SELECT v as value, hstore_hash(v)::bit(32) as standard,
+       hstore_hash_extended(v, 0)::bit(32) as extended0,
+       hstore_hash_extended(v, 1)::bit(32) as extended1
+FROM   (VALUES (NULL::hstore), (''), ('"a key" =>1'), ('c => null'),
+       ('e => 012345'), ('g => 2.345e+4')) x(v)
+WHERE  hstore_hash(v)::bit(32) != hstore_hash_extended(v, 0)::bit(32)
+       OR hstore_hash(v)::bit(32) = hstore_hash_extended(v, 1)::bit(32);