summaryrefslogtreecommitdiff
path: root/src/backend/access/hash/hashfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/hash/hashfunc.c')
-rw-r--r--src/backend/access/hash/hashfunc.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c
index d9b5524b0ab..39a58c0899a 100644
--- a/src/backend/access/hash/hashfunc.c
+++ b/src/backend/access/hash/hashfunc.c
@@ -1,19 +1,26 @@
/*-------------------------------------------------------------------------
*
* hashfunc.c
- * Comparison functions for hash access method.
+ * Support functions for hash access method.
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.51 2007/04/02 03:49:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.52 2007/06/01 15:33:18 tgl Exp $
*
* NOTES
* These functions are stored in pg_amproc. For each operator class
- * defined on hash tables, they compute the hash value of the argument.
+ * defined for hash indexes, they compute the hash value of the argument.
*
+ * 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().
*-------------------------------------------------------------------------
*/
@@ -26,19 +33,19 @@
Datum
hashchar(PG_FUNCTION_ARGS)
{
- PG_RETURN_UINT32(~((uint32) PG_GETARG_CHAR(0)));
+ return hash_uint32((int32) PG_GETARG_CHAR(0));
}
Datum
hashint2(PG_FUNCTION_ARGS)
{
- PG_RETURN_UINT32(~((uint32) PG_GETARG_INT16(0)));
+ return hash_uint32((int32) PG_GETARG_INT16(0));
}
Datum
hashint4(PG_FUNCTION_ARGS)
{
- PG_RETURN_UINT32(~PG_GETARG_UINT32(0));
+ return hash_uint32(PG_GETARG_INT32(0));
}
Datum
@@ -59,23 +66,23 @@ hashint8(PG_FUNCTION_ARGS)
lohalf ^= (val >= 0) ? hihalf : ~hihalf;
- PG_RETURN_UINT32(~lohalf);
+ return hash_uint32(lohalf);
#else
/* here if we can't count on "x >> 32" to work sanely */
- PG_RETURN_UINT32(~((uint32) PG_GETARG_INT64(0)));
+ return hash_uint32((int32) PG_GETARG_INT64(0));
#endif
}
Datum
hashoid(PG_FUNCTION_ARGS)
{
- PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
+ return hash_uint32((uint32) PG_GETARG_OID(0));
}
Datum
hashenum(PG_FUNCTION_ARGS)
{
- PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
+ return hash_uint32((uint32) PG_GETARG_OID(0));
}
Datum
@@ -283,6 +290,31 @@ hash_any(register const unsigned char *k, register int keylen)
/* case 0: nothing left to add */
}
mix(a, b, c);
+
+ /* report the result */
+ return UInt32GetDatum(c);
+}
+
+/*
+ * hash_uint32() -- hash a 32-bit value
+ *
+ * This has the same result (at least on little-endian machines) as
+ * hash_any(&k, sizeof(uint32))
+ * but is faster and doesn't force the caller to store k into memory.
+ */
+Datum
+hash_uint32(uint32 k)
+{
+ register uint32 a,
+ b,
+ c;
+
+ a = 0x9e3779b9 + k;
+ b = 0x9e3779b9;
+ c = 3923095 + (uint32) sizeof(uint32);
+
+ mix(a, b, c);
+
/* report the result */
return UInt32GetDatum(c);
}