From a1756489050ba5ff7e3ba441116cb4b6ef6d684e Mon Sep 17 00:00:00 2001
From: Amul Sul <sulamul@gmail.com>
Date: Fri, 8 Sep 2017 12:29:13 +0530
Subject: [PATCH 2/2] hstore - add extended hash function

---
 contrib/hstore/expected/hstore.out         | 12 ++++++++++++
 contrib/hstore/hstore--1.4--1.5.sql        |  8 ++++++++
 contrib/hstore/hstore--1.5.sql             |  8 +++++++-
 contrib/hstore/hstore--unpackaged--1.0.sql |  1 +
 contrib/hstore/hstore_op.c                 | 20 ++++++++++++++++++++
 contrib/hstore/sql/hstore.sql              |  9 +++++++++
 6 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index f0d4216..4f1db01 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -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.4--1.5.sql b/contrib/hstore/hstore--1.4--1.5.sql
index 443dc84..26610ce 100644
--- a/contrib/hstore/hstore--1.4--1.5.sql
+++ b/contrib/hstore/hstore--1.4--1.5.sql
@@ -2,3 +2,11 @@
 
 -- complain if script is sourced in psql, rather than via ALTER EXTENSION
 \echo Use "ALTER EXTENSION hstore UPDATE TO '1.5'" 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);
diff --git a/contrib/hstore/hstore--1.5.sql b/contrib/hstore/hstore--1.5.sql
index 4ec3ec6..182275c 100644
--- a/contrib/hstore/hstore--1.5.sql
+++ b/contrib/hstore/hstore--1.5.sql
@@ -439,11 +439,17 @@ RETURNS integer
 AS 'MODULE_PATHNAME','hstore_hash'
 LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
 
+CREATE FUNCTION hstore_hash_extended(hstore, int8)
+RETURNS int8
+AS 'MODULE_PATHNAME','hstore_hash_extended'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
 CREATE OPERATOR CLASS hash_hstore_ops
 DEFAULT FOR TYPE hstore USING hash
 AS
 	OPERATOR	1	= ,
-	FUNCTION	1	hstore_hash(hstore);
+	FUNCTION	1	hstore_hash(hstore),
+	FUNCTION	2	hstore_hash_extended(hstore, int8);
 
 -- GiST support
 
diff --git a/contrib/hstore/hstore--unpackaged--1.0.sql b/contrib/hstore/hstore--unpackaged--1.0.sql
index 19a7802..2128165 100644
--- a/contrib/hstore/hstore--unpackaged--1.0.sql
+++ b/contrib/hstore/hstore--unpackaged--1.0.sql
@@ -71,6 +71,7 @@ ALTER EXTENSION hstore ADD operator #<=#(hstore,hstore);
 ALTER EXTENSION hstore ADD operator family btree_hstore_ops using btree;
 ALTER EXTENSION hstore ADD operator class btree_hstore_ops using btree;
 ALTER EXTENSION hstore ADD function hstore_hash(hstore);
+ALTER EXTENSION hstore ADD function hstore_hash_extended(hstore,int8);
 ALTER EXTENSION hstore ADD operator family hash_hstore_ops using hash;
 ALTER EXTENSION hstore ADD operator class hash_hstore_ops using hash;
 ALTER EXTENSION hstore ADD type ghstore;
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index 612be23..c962c49 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1253,3 +1253,23 @@ 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_HS(0);
+	Datum		hval = hash_any_extended((unsigned char *) VARDATA(hs),
+								VARSIZE(hs) - VARHDRSZ,
+								PG_GETARG_INT64(1));
+
+	/* Same approach as 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);
+}
diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql
index d64b9f7..76ac48b 100644
--- a/contrib/hstore/sql/hstore.sql
+++ b/contrib/hstore/sql/hstore.sql
@@ -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);
-- 
2.6.2

