From 2a3b3f96df7f52441ad13e574b8ce3f42b71740b Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Wed, 26 Sep 2018 05:00:36 -0400
Subject: [PATCH 1/2] hstore - add extended hash function v1

---
 contrib/hstore/Makefile                    |  3 ++-
 contrib/hstore/expected/hstore.out         | 12 ++++++++++++
 contrib/hstore/hstore--1.5--1.6.sql        | 12 ++++++++++++
 contrib/hstore/hstore--unpackaged--1.0.sql |  1 +
 contrib/hstore/hstore.control              |  2 +-
 contrib/hstore/hstore_op.c                 | 20 ++++++++++++++++++++
 contrib/hstore/sql/hstore.sql              |  9 +++++++++
 7 files changed, 57 insertions(+), 2 deletions(-)
 create mode 100644 contrib/hstore/hstore--1.5--1.6.sql

diff --git a/contrib/hstore/Makefile b/contrib/hstore/Makefile
index 46d26f8052..8170e307fe 100644
--- a/contrib/hstore/Makefile
+++ b/contrib/hstore/Makefile
@@ -5,7 +5,8 @@ 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
diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index f0d421602d..4f1db01b3e 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.5--1.6.sql b/contrib/hstore/hstore--1.5--1.6.sql
new file mode 100644
index 0000000000..c5a2bae02f
--- /dev/null
+++ b/contrib/hstore/hstore--1.5--1.6.sql
@@ -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);
diff --git a/contrib/hstore/hstore--unpackaged--1.0.sql b/contrib/hstore/hstore--unpackaged--1.0.sql
index 19a7802805..2128165433 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.control b/contrib/hstore/hstore.control
index 8a719475b8..93688cdd83 100644
--- a/contrib/hstore/hstore.control
+++ b/contrib/hstore/hstore.control
@@ -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
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index 8f9277f8da..898324bbe9 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_HSTORE_P(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 d64b9f77c7..76ac48b021 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.18.0

