1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* hashfunc.c
|
2007-06-01 17:33:19 +02:00
|
|
|
* Support functions for hash access method.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/access/hash/hashfunc.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* These functions are stored in pg_amproc. For each operator class
|
2007-06-01 17:33:19 +02:00
|
|
|
* defined for hash indexes, they compute the hash value of the argument.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2007-06-01 17:33:19 +02:00
|
|
|
* Additional hash functions appear in /utils/adt/ files for various
|
|
|
|
* specialized datatypes.
|
|
|
|
*
|
|
|
|
* 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 joins, for example. In most cases a hash
|
|
|
|
* function should use hash_any() or its variant hash_uint32().
|
1996-07-09 08:22:35 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1996-10-20 08:34:30 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1996-11-10 04:06:38 +01:00
|
|
|
#include "access/hash.h"
|
2019-03-22 12:09:32 +01:00
|
|
|
#include "catalog/pg_collation.h"
|
2020-02-27 04:55:41 +01:00
|
|
|
#include "common/hashfn.h"
|
2016-12-28 18:00:00 +01:00
|
|
|
#include "utils/builtins.h"
|
2021-09-02 23:24:41 +02:00
|
|
|
#include "utils/float.h"
|
2019-03-22 12:09:32 +01:00
|
|
|
#include "utils/pg_locale.h"
|
2023-01-10 05:48:59 +01:00
|
|
|
#include "varatt.h"
|
1996-11-10 04:06:38 +01:00
|
|
|
|
2016-12-28 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Datatype-specific hash functions.
|
|
|
|
*
|
|
|
|
* These support both hash indexes and hash joins.
|
|
|
|
*
|
|
|
|
* NOTE: some of these are also used by catcache operations, without
|
|
|
|
* any direct connection to hash indexes. Also, the common hash_any
|
|
|
|
* routine is also used by dynahash tables.
|
|
|
|
*/
|
2000-06-19 05:55:01 +02:00
|
|
|
|
2003-06-23 00:04:55 +02:00
|
|
|
/* Note: this is used for both "char" and boolean datatypes */
|
2000-06-19 05:55:01 +02:00
|
|
|
Datum
|
|
|
|
hashchar(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
return hash_uint32((int32) PG_GETARG_CHAR(0));
|
2000-06-19 05:55:01 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashcharextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hash_uint32_extended((int32) PG_GETARG_CHAR(0), PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
hashint2(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
return hash_uint32((int32) PG_GETARG_INT16(0));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashint2extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hash_uint32_extended((int32) PG_GETARG_INT16(0), PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
hashint4(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
return hash_uint32(PG_GETARG_INT32(0));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashint4extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hash_uint32_extended(PG_GETARG_INT32(0), PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
hashint8(PG_FUNCTION_ARGS)
|
1999-03-14 06:09:05 +01:00
|
|
|
{
|
2004-06-13 23:57:28 +02:00
|
|
|
/*
|
|
|
|
* The idea here is to produce a hash value compatible with the values
|
2006-12-23 01:43:13 +01:00
|
|
|
* produced by hashint4 and hashint2 for logically equal inputs; this is
|
|
|
|
* necessary to support cross-type hash joins across these input types.
|
|
|
|
* Since all three types are signed, we can xor the high half of the int8
|
|
|
|
* value if the sign is positive, or the complement of the high half when
|
|
|
|
* the sign is negative.
|
2004-06-13 23:57:28 +02:00
|
|
|
*/
|
|
|
|
int64 val = PG_GETARG_INT64(0);
|
|
|
|
uint32 lohalf = (uint32) val;
|
|
|
|
uint32 hihalf = (uint32) (val >> 32);
|
|
|
|
|
|
|
|
lohalf ^= (val >= 0) ? hihalf : ~hihalf;
|
|
|
|
|
2007-06-01 17:33:19 +02:00
|
|
|
return hash_uint32(lohalf);
|
2000-06-19 05:55:01 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashint8extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Same approach as hashint8 */
|
|
|
|
int64 val = PG_GETARG_INT64(0);
|
|
|
|
uint32 lohalf = (uint32) val;
|
|
|
|
uint32 hihalf = (uint32) (val >> 32);
|
|
|
|
|
|
|
|
lohalf ^= (val >= 0) ? hihalf : ~hihalf;
|
|
|
|
|
|
|
|
return hash_uint32_extended(lohalf, PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2000-06-19 05:55:01 +02:00
|
|
|
Datum
|
|
|
|
hashoid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
return hash_uint32((uint32) PG_GETARG_OID(0));
|
1999-03-14 06:09:05 +01:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashoidextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hash_uint32_extended((uint32) PG_GETARG_OID(0), PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
Datum
|
|
|
|
hashenum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
return hash_uint32((uint32) PG_GETARG_OID(0));
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashenumextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
return hash_uint32_extended((uint32) PG_GETARG_OID(0), PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
hashfloat4(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
float4 key = PG_GETARG_FLOAT4(0);
|
2006-12-23 01:43:13 +01:00
|
|
|
float8 key8;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-06-23 00:04:55 +02:00
|
|
|
/*
|
|
|
|
* On IEEE-float machines, minus zero and zero have different bit patterns
|
|
|
|
* but should compare as equal. We must ensure that they have the same
|
2006-12-23 01:43:13 +01:00
|
|
|
* hash value, which is most reliably done this way:
|
2003-06-23 00:04:55 +02:00
|
|
|
*/
|
|
|
|
if (key == (float4) 0)
|
|
|
|
PG_RETURN_UINT32(0);
|
|
|
|
|
2006-12-23 01:43:13 +01:00
|
|
|
/*
|
|
|
|
* To support cross-type hashing of float8 and float4, we want to return
|
|
|
|
* the same hash value hashfloat8 would produce for an equal float8 value.
|
|
|
|
* So, widen the value to float8 and hash that. (We must do this rather
|
|
|
|
* than have hashfloat8 try to narrow its value to float4; that could fail
|
|
|
|
* on overflow.)
|
|
|
|
*/
|
|
|
|
key8 = key;
|
|
|
|
|
2021-09-04 22:29:08 +02:00
|
|
|
/*
|
|
|
|
* Similarly, NaNs can have different bit patterns but they should all
|
|
|
|
* compare as equal. For backwards-compatibility reasons we force them to
|
|
|
|
* have the hash value of a standard float8 NaN. (You'd think we could
|
|
|
|
* replace key with a float4 NaN and then widen it; but on some old
|
|
|
|
* platforms, that way produces a different bit pattern.)
|
|
|
|
*/
|
|
|
|
if (isnan(key8))
|
|
|
|
key8 = get_float8_nan();
|
|
|
|
|
2006-12-23 01:43:13 +01:00
|
|
|
return hash_any((unsigned char *) &key8, sizeof(key8));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashfloat4extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float4 key = PG_GETARG_FLOAT4(0);
|
|
|
|
uint64 seed = PG_GETARG_INT64(1);
|
|
|
|
float8 key8;
|
|
|
|
|
|
|
|
/* Same approach as hashfloat4 */
|
|
|
|
if (key == (float4) 0)
|
|
|
|
PG_RETURN_UINT64(seed);
|
|
|
|
key8 = key;
|
2021-09-04 22:29:08 +02:00
|
|
|
if (isnan(key8))
|
|
|
|
key8 = get_float8_nan();
|
2017-09-01 04:21:21 +02:00
|
|
|
|
|
|
|
return hash_any_extended((unsigned char *) &key8, sizeof(key8), seed);
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
hashfloat8(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
float8 key = PG_GETARG_FLOAT8(0);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2003-06-23 00:04:55 +02:00
|
|
|
/*
|
|
|
|
* On IEEE-float machines, minus zero and zero have different bit patterns
|
|
|
|
* but should compare as equal. We must ensure that they have the same
|
2006-12-23 01:43:13 +01:00
|
|
|
* hash value, which is most reliably done this way:
|
2003-06-23 00:04:55 +02:00
|
|
|
*/
|
|
|
|
if (key == (float8) 0)
|
|
|
|
PG_RETURN_UINT32(0);
|
|
|
|
|
2021-09-02 23:24:41 +02:00
|
|
|
/*
|
|
|
|
* Similarly, NaNs can have different bit patterns but they should all
|
|
|
|
* compare as equal. For backwards-compatibility reasons we force them to
|
|
|
|
* have the hash value of a standard NaN.
|
|
|
|
*/
|
|
|
|
if (isnan(key))
|
|
|
|
key = get_float8_nan();
|
|
|
|
|
2002-03-09 18:35:37 +01:00
|
|
|
return hash_any((unsigned char *) &key, sizeof(key));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashfloat8extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 key = PG_GETARG_FLOAT8(0);
|
|
|
|
uint64 seed = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
/* Same approach as hashfloat8 */
|
|
|
|
if (key == (float8) 0)
|
|
|
|
PG_RETURN_UINT64(seed);
|
2021-09-02 23:24:41 +02:00
|
|
|
if (isnan(key))
|
|
|
|
key = get_float8_nan();
|
2017-09-01 04:21:21 +02:00
|
|
|
|
|
|
|
return hash_any_extended((unsigned char *) &key, sizeof(key), seed);
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
hashoidvector(PG_FUNCTION_ARGS)
|
1998-08-19 04:04:17 +02:00
|
|
|
{
|
2005-03-29 02:17:27 +02:00
|
|
|
oidvector *key = (oidvector *) PG_GETARG_POINTER(0);
|
1998-08-19 04:04:17 +02:00
|
|
|
|
2005-03-29 02:17:27 +02:00
|
|
|
return hash_any((unsigned char *) key->values, key->dim1 * sizeof(Oid));
|
2000-02-21 04:36:59 +01:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashoidvectorextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
oidvector *key = (oidvector *) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
return hash_any_extended((unsigned char *) key->values,
|
|
|
|
key->dim1 * sizeof(Oid),
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
2000-06-19 05:55:01 +02:00
|
|
|
hashname(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-19 05:55:01 +02:00
|
|
|
char *key = NameStr(*PG_GETARG_NAME(0));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
Remove triggerable Assert in hashname().
hashname() asserted that the key string it is given is shorter than
NAMEDATALEN. That should surely always be true if the input is in fact a
regular value of type "name". However, for reasons of coding convenience,
we allow plain old C strings to be treated as "name" values in many places.
Some SQL functions accept arbitrary "text" inputs, convert them to C
strings, and pass them otherwise-untransformed to syscache lookups for name
columns, allowing an overlength input value to trigger hashname's Assert.
This would be a DOS problem, except that it only happens in assert-enabled
builds which aren't recommended for production. In a production build,
you'll just get a name lookup error, since regardless of the hash value
computed by hashname, the later equality comparison checks can't match.
Likewise, if the catalog lookup is done by seqscan or indexscan searches,
there will just be a lookup error, since the name comparison functions
don't contain any similar length checks, and will see an overlength input
as unequal to any stored entry.
After discussion we concluded that we should simply remove this Assert.
It's inessential to hashname's own functionality, and having such an
assertion in only some paths for name lookup is more of a foot-gun than
a useful check. There may or may not be a case for the affected callers
to do something other than let the name lookup fail, but we'll consider
that separately; in any case we probably don't want to change such
behavior in the back branches.
Per report from Tushar Ahuja. Back-patch to all supported branches.
Report: https://postgr.es/m/7d0809ee-6f25-c9d6-8e74-5b2967830d49@enterprisedb.com
Discussion: https://postgr.es/m/17691.1482523168@sss.pgh.pa.us
2016-12-26 20:58:02 +01:00
|
|
|
return hash_any((unsigned char *) key, strlen(key));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashnameextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *key = NameStr(*PG_GETARG_NAME(0));
|
|
|
|
|
|
|
|
return hash_any_extended((unsigned char *) key, strlen(key),
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2003-06-23 00:04:55 +02:00
|
|
|
Datum
|
|
|
|
hashtext(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
text *key = PG_GETARG_TEXT_PP(0);
|
2019-03-22 12:09:32 +01:00
|
|
|
Oid collid = PG_GET_COLLATION();
|
|
|
|
pg_locale_t mylocale = 0;
|
2003-06-23 00:04:55 +02:00
|
|
|
Datum result;
|
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
if (!collid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INDETERMINATE_COLLATION),
|
|
|
|
errmsg("could not determine which collation to use for string hashing"),
|
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
|
|
|
|
2022-01-20 09:38:05 +01:00
|
|
|
if (!lc_collate_is_c(collid))
|
2019-03-22 12:09:32 +01:00
|
|
|
mylocale = pg_newlocale_from_collation(collid);
|
|
|
|
|
2023-02-23 20:17:41 +01:00
|
|
|
if (pg_locale_deterministic(mylocale))
|
2019-03-22 12:09:32 +01:00
|
|
|
{
|
|
|
|
result = hash_any((unsigned char *) VARDATA_ANY(key),
|
|
|
|
VARSIZE_ANY_EXHDR(key));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
Size bsize,
|
|
|
|
rsize;
|
2023-02-23 20:20:00 +01:00
|
|
|
char *buf;
|
|
|
|
const char *keydata = VARDATA_ANY(key);
|
|
|
|
size_t keylen = VARSIZE_ANY_EXHDR(key);
|
|
|
|
|
|
|
|
|
|
|
|
bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
|
|
|
|
buf = palloc(bsize + 1);
|
|
|
|
|
|
|
|
rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
|
|
|
|
if (rsize != bsize)
|
|
|
|
elog(ERROR, "pg_strnxfrm() returned unexpected result");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In principle, there's no reason to include the terminating NUL
|
2023-05-19 23:24:48 +02:00
|
|
|
* character in the hash, but it was done before and the behavior must
|
|
|
|
* be preserved.
|
2023-02-23 20:20:00 +01:00
|
|
|
*/
|
|
|
|
result = hash_any((uint8_t *) buf, bsize + 1);
|
|
|
|
|
|
|
|
pfree(buf);
|
2019-03-22 12:09:32 +01:00
|
|
|
}
|
2003-06-23 00:04:55 +02:00
|
|
|
|
|
|
|
/* Avoid leaking memory for toasted inputs */
|
|
|
|
PG_FREE_IF_COPY(key, 0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashtextextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *key = PG_GETARG_TEXT_PP(0);
|
2019-03-22 12:09:32 +01:00
|
|
|
Oid collid = PG_GET_COLLATION();
|
|
|
|
pg_locale_t mylocale = 0;
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum result;
|
|
|
|
|
2019-03-22 12:09:32 +01:00
|
|
|
if (!collid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INDETERMINATE_COLLATION),
|
|
|
|
errmsg("could not determine which collation to use for string hashing"),
|
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
|
|
|
|
2022-01-20 09:38:05 +01:00
|
|
|
if (!lc_collate_is_c(collid))
|
2019-03-22 12:09:32 +01:00
|
|
|
mylocale = pg_newlocale_from_collation(collid);
|
|
|
|
|
2023-02-23 20:17:41 +01:00
|
|
|
if (pg_locale_deterministic(mylocale))
|
2019-03-22 12:09:32 +01:00
|
|
|
{
|
|
|
|
result = hash_any_extended((unsigned char *) VARDATA_ANY(key),
|
|
|
|
VARSIZE_ANY_EXHDR(key),
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-05-19 23:24:48 +02:00
|
|
|
Size bsize,
|
|
|
|
rsize;
|
2023-02-23 20:20:00 +01:00
|
|
|
char *buf;
|
|
|
|
const char *keydata = VARDATA_ANY(key);
|
|
|
|
size_t keylen = VARSIZE_ANY_EXHDR(key);
|
|
|
|
|
|
|
|
bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
|
|
|
|
buf = palloc(bsize + 1);
|
|
|
|
|
|
|
|
rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
|
|
|
|
if (rsize != bsize)
|
|
|
|
elog(ERROR, "pg_strnxfrm() returned unexpected result");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In principle, there's no reason to include the terminating NUL
|
2023-05-19 23:24:48 +02:00
|
|
|
* character in the hash, but it was done before and the behavior must
|
|
|
|
* be preserved.
|
2023-02-23 20:20:00 +01:00
|
|
|
*/
|
|
|
|
result = hash_any_extended((uint8_t *) buf, bsize + 1,
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
|
|
|
|
pfree(buf);
|
2019-03-22 12:09:32 +01:00
|
|
|
}
|
2017-09-01 04:21:21 +02:00
|
|
|
|
|
|
|
PG_FREE_IF_COPY(key, 0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-06-19 05:55:01 +02:00
|
|
|
/*
|
|
|
|
* hashvarlena() can be used for any varlena datatype in which there are
|
|
|
|
* no non-significant bits, ie, distinct bitpatterns never compare as equal.
|
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
2000-06-19 05:55:01 +02:00
|
|
|
hashvarlena(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2007-09-22 00:52:52 +02:00
|
|
|
struct varlena *key = PG_GETARG_VARLENA_PP(0);
|
2000-12-09 00:57:03 +01:00
|
|
|
Datum result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-09-22 00:52:52 +02:00
|
|
|
result = hash_any((unsigned char *) VARDATA_ANY(key),
|
|
|
|
VARSIZE_ANY_EXHDR(key));
|
2000-12-09 00:57:03 +01:00
|
|
|
|
|
|
|
/* Avoid leaking memory for toasted inputs */
|
|
|
|
PG_FREE_IF_COPY(key, 0);
|
|
|
|
|
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 04:21:21 +02:00
|
|
|
Datum
|
|
|
|
hashvarlenaextended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
struct varlena *key = PG_GETARG_VARLENA_PP(0);
|
|
|
|
Datum result;
|
|
|
|
|
|
|
|
result = hash_any_extended((unsigned char *) VARDATA_ANY(key),
|
|
|
|
VARSIZE_ANY_EXHDR(key),
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(key, 0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|