Skip to content

Commit eb6f291

Browse files
committed
Add a 64-bit hash function for type hstore.
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
1 parent 48c41fa commit eb6f291

File tree

6 files changed

+64
-5
lines changed

6 files changed

+64
-5
lines changed

contrib/hstore/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o hstore_compat.o \
55
$(WIN32RES)
66

77
EXTENSION = hstore
8-
DATA = hstore--1.4.sql hstore--1.4--1.5.sql \
8+
DATA = hstore--1.4.sql \
9+
hstore--1.5--1.6.sql \
10+
hstore--1.4--1.5.sql \
911
hstore--1.3--1.4.sql hstore--1.2--1.3.sql \
1012
hstore--1.1--1.2.sql hstore--1.0--1.1.sql \
1113
hstore--unpackaged--1.0.sql

contrib/hstore/expected/hstore.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,3 +1515,15 @@ select json_agg(q) from (select f1, hstore_to_json_loose(f2) as f2 from test_jso
15151515
{"f1":"rec2","f2":{"b": false, "c": "null", "d": -12345, "e": "012345.6", "f": -1.234, "g": 0.345e-4, "a key": 2}}]
15161516
(1 row)
15171517

1518+
-- Check the hstore_hash() and hstore_hash_extended() function explicitly.
1519+
SELECT v as value, hstore_hash(v)::bit(32) as standard,
1520+
hstore_hash_extended(v, 0)::bit(32) as extended0,
1521+
hstore_hash_extended(v, 1)::bit(32) as extended1
1522+
FROM (VALUES (NULL::hstore), (''), ('"a key" =>1'), ('c => null'),
1523+
('e => 012345'), ('g => 2.345e+4')) x(v)
1524+
WHERE hstore_hash(v)::bit(32) != hstore_hash_extended(v, 0)::bit(32)
1525+
OR hstore_hash(v)::bit(32) = hstore_hash_extended(v, 1)::bit(32);
1526+
value | standard | extended0 | extended1
1527+
-------+----------+-----------+-----------
1528+
(0 rows)
1529+

contrib/hstore/hstore--1.5--1.6.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* contrib/hstore/hstore--1.5--1.6.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION hstore UPDATE TO '1.6'" to load this file. \quit
5+
6+
CREATE FUNCTION hstore_hash_extended(hstore, int8)
7+
RETURNS int8
8+
AS 'MODULE_PATHNAME','hstore_hash_extended'
9+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
10+
11+
ALTER OPERATOR FAMILY hash_hstore_ops USING hash ADD
12+
FUNCTION 2 hstore_hash_extended(hstore, int8);

contrib/hstore/hstore.control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# hstore extension
22
comment = 'data type for storing sets of (key, value) pairs'
3-
default_version = '1.5'
3+
default_version = '1.6'
44
module_pathname = '$libdir/hstore'
55
relocatable = true

contrib/hstore/hstore_op.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,9 +1240,10 @@ hstore_hash(PG_FUNCTION_ARGS)
12401240
VARSIZE(hs) - VARHDRSZ);
12411241

12421242
/*
1243-
* this is the only place in the code that cares whether the overall
1244-
* varlena size exactly matches the true data size; this assertion should
1245-
* be maintained by all the other code, but we make it explicit here.
1243+
* This (along with hstore_hash_extended) is the only place in the code
1244+
* that cares whether the overall varlena size exactly matches the true
1245+
* data size; this assertion should be maintained by all the other code,
1246+
* but we make it explicit here.
12461247
*/
12471248
Assert(VARSIZE(hs) ==
12481249
(HS_COUNT(hs) != 0 ?
@@ -1253,3 +1254,26 @@ hstore_hash(PG_FUNCTION_ARGS)
12531254
PG_FREE_IF_COPY(hs, 0);
12541255
PG_RETURN_DATUM(hval);
12551256
}
1257+
1258+
PG_FUNCTION_INFO_V1(hstore_hash_extended);
1259+
Datum
1260+
hstore_hash_extended(PG_FUNCTION_ARGS)
1261+
{
1262+
HStore *hs = PG_GETARG_HSTORE_P(0);
1263+
uint64 seed = PG_GETARG_INT64(1);
1264+
Datum hval;
1265+
1266+
hval = hash_any_extended((unsigned char *) VARDATA(hs),
1267+
VARSIZE(hs) - VARHDRSZ,
1268+
seed);
1269+
1270+
/* See comment in hstore_hash */
1271+
Assert(VARSIZE(hs) ==
1272+
(HS_COUNT(hs) != 0 ?
1273+
CALCDATASIZE(HS_COUNT(hs),
1274+
HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
1275+
HSHRDSIZE));
1276+
1277+
PG_FREE_IF_COPY(hs, 0);
1278+
PG_RETURN_DATUM(hval);
1279+
}

contrib/hstore/sql/hstore.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,12 @@ insert into test_json_agg values ('rec1','"a key" =>1, b => t, c => null, d=> 12
350350
('rec2','"a key" =>2, b => f, c => "null", d=> -12345, e => 012345.6, f=> -1.234, g=> 0.345e-4');
351351
select json_agg(q) from test_json_agg q;
352352
select json_agg(q) from (select f1, hstore_to_json_loose(f2) as f2 from test_json_agg) q;
353+
354+
-- Check the hstore_hash() and hstore_hash_extended() function explicitly.
355+
SELECT v as value, hstore_hash(v)::bit(32) as standard,
356+
hstore_hash_extended(v, 0)::bit(32) as extended0,
357+
hstore_hash_extended(v, 1)::bit(32) as extended1
358+
FROM (VALUES (NULL::hstore), (''), ('"a key" =>1'), ('c => null'),
359+
('e => 012345'), ('g => 2.345e+4')) x(v)
360+
WHERE hstore_hash(v)::bit(32) != hstore_hash_extended(v, 0)::bit(32)
361+
OR hstore_hash(v)::bit(32) = hstore_hash_extended(v, 1)::bit(32);

0 commit comments

Comments
 (0)