Adapt hashfn.c and hashutils.h for frontend use.

hash_any() and its various variants are defined to return Datum,
which is a backend-only concept, but the underlying functions
actually want to return uint32 and uint64, and only return Datum
because it's convenient for callers who are using them to
implement a hash function for some SQL datatype.

However, changing these functions to return uint32 and uint64
seems like it might lead to programming errors or back-patching
difficulties, both because they are widely used and because
failure to use UInt{32,64}GetDatum() might not provoke a
compilation error. Instead, rename the existing functions as
well as changing the return type, and add static inline wrappers
for those callers that need the previous behavior.

Although this commit adapts hashutils.h and hashfn.c so that they
can be compiled as frontend code, it does not actually do
anything that would cause them to be so compiled. That is left
for another commit.

Patch by me, reviewed by Suraj Kharage and Mark Dilger.

Discussion: http://postgr.es/m/CA+TgmoaRiG4TXND8QuM6JXFRkM_1wL2ZNhzaUKsuec9-4yrkgw@mail.gmail.com
This commit is contained in:
Robert Haas 2020-02-24 17:27:15 +05:30
parent 9341c783cc
commit a91e2fa941
2 changed files with 55 additions and 33 deletions

View File

@ -16,15 +16,14 @@
* It is expected that every bit of a hash function's 32-bit result is
* as random as every other; failure to ensure this is likely to lead
* to poor performance of hash tables. In most cases a hash
* function should use hash_any() or its variant hash_uint32().
* function should use hash_bytes() or its variant hash_bytes_uint32(),
* or the wrappers hash_any() and hash_uint32 defined in hashfn.h.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "fmgr.h"
#include "utils/hashutils.h"
#include "utils/hsearch.h"
/*
@ -126,7 +125,7 @@
}
/*
* hash_any() -- hash a variable-length key into a 32-bit value
* hash_bytes() -- hash a variable-length key into a 32-bit value
* k : the key (the unaligned variable-length array of bytes)
* len : the length of the key, counting by bytes
*
@ -143,8 +142,8 @@
* by using the final values of both b and c. b is perhaps a little less
* well mixed than c, however.
*/
Datum
hash_any(const unsigned char *k, int keylen)
uint32
hash_bytes(const unsigned char *k, int keylen)
{
uint32 a,
b,
@ -358,20 +357,19 @@ hash_any(const unsigned char *k, int keylen)
final(a, b, c);
/* report the result */
return UInt32GetDatum(c);
return c;
}
/*
* hash_any_extended() -- hash into a 64-bit value, using an optional seed
* hash_bytes_extended() -- hash into a 64-bit value, using an optional seed
* k : the key (the unaligned variable-length array of bytes)
* len : the length of the key, counting by bytes
* seed : a 64-bit seed (0 means no seed)
*
* Returns a uint64 value. Otherwise similar to hash_any.
* Returns a uint64 value. Otherwise similar to hash_bytes.
*/
Datum
hash_any_extended(const unsigned char *k, int keylen,
uint64 seed)
uint64
hash_bytes_extended(const unsigned char *k, int keylen, uint64 seed)
{
uint32 a,
b,
@ -598,18 +596,18 @@ hash_any_extended(const unsigned char *k, int keylen,
final(a, b, c);
/* report the result */
PG_RETURN_UINT64(((uint64) b << 32) | c);
return ((uint64) b << 32) | c;
}
/*
* hash_uint32() -- hash a 32-bit value to a 32-bit value
* hash_bytes_uint32() -- hash a 32-bit value to a 32-bit value
*
* This has the same result as
* hash_any(&k, sizeof(uint32))
* hash_bytes(&k, sizeof(uint32))
* but is faster and doesn't force the caller to store k into memory.
*/
Datum
hash_uint32(uint32 k)
uint32
hash_bytes_uint32(uint32 k)
{
uint32 a,
b,
@ -621,16 +619,16 @@ hash_uint32(uint32 k)
final(a, b, c);
/* report the result */
return UInt32GetDatum(c);
return c;
}
/*
* hash_uint32_extended() -- hash a 32-bit value to a 64-bit value, with a seed
* hash_bytes_uint32_extended() -- hash 32-bit value to 64-bit value, with seed
*
* Like hash_uint32, this is a convenience function.
* Like hash_bytes_uint32, this is a convenience function.
*/
Datum
hash_uint32_extended(uint32 k, uint64 seed)
uint64
hash_bytes_uint32_extended(uint32 k, uint64 seed)
{
uint32 a,
b,
@ -650,7 +648,7 @@ hash_uint32_extended(uint32 k, uint64 seed)
final(a, b, c);
/* report the result */
PG_RETURN_UINT64(((uint64) b << 32) | c);
return ((uint64) b << 32) | c;
}
/*
@ -669,8 +667,7 @@ string_hash(const void *key, Size keysize)
Size s_len = strlen((const char *) key);
s_len = Min(s_len, keysize - 1);
return DatumGetUInt32(hash_any((const unsigned char *) key,
(int) s_len));
return hash_bytes((const unsigned char *) key, (int) s_len);
}
/*
@ -679,8 +676,7 @@ string_hash(const void *key, Size keysize)
uint32
tag_hash(const void *key, Size keysize)
{
return DatumGetUInt32(hash_any((const unsigned char *) key,
(int) keysize));
return hash_bytes((const unsigned char *) key, (int) keysize);
}
/*
@ -692,5 +688,5 @@ uint32
uint32_hash(const void *key, Size keysize)
{
Assert(keysize == sizeof(uint32));
return DatumGetUInt32(hash_uint32(*((const uint32 *) key)));
return hash_bytes_uint32(*((const uint32 *) key));
}

View File

@ -20,11 +20,37 @@
(((v) >> 31) & UINT64CONST(0x100000001)))
extern Datum hash_any(const unsigned char *k, int keylen);
extern Datum hash_any_extended(const unsigned char *k,
int keylen, uint64 seed);
extern Datum hash_uint32(uint32 k);
extern Datum hash_uint32_extended(uint32 k, uint64 seed);
extern uint32 hash_bytes(const unsigned char *k, int keylen);
extern uint64 hash_bytes_extended(const unsigned char *k,
int keylen, uint64 seed);
extern uint32 hash_bytes_uint32(uint32 k);
extern uint64 hash_bytes_uint32_extended(uint32 k, uint64 seed);
#ifndef FRONTEND
static inline Datum
hash_any(const unsigned char *k, int keylen)
{
return UInt32GetDatum(hash_bytes(k, keylen));
}
static inline Datum
hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
{
return UInt64GetDatum(hash_bytes_extended(k, keylen, seed));
}
static inline Datum
hash_uint32(uint32 k)
{
return UInt32GetDatum(hash_bytes_uint32(k));
}
static inline Datum
hash_uint32_extended(uint32 k, uint64 seed)
{
return UInt64GetDatum(hash_bytes_uint32_extended(k, seed));
}
#endif
extern uint32 string_hash(const void *key, Size keysize);
extern uint32 tag_hash(const void *key, Size keysize);