From d3a9fdf6cbc1702e40952136b84be08c0089b69d Mon Sep 17 00:00:00 2001 From: John Naylor Date: Sat, 9 Dec 2023 17:19:10 +0700 Subject: [PATCH v7 07/13] Use bytewise fasthash in guc_name_hash The previous hash function did not have a final bit mixing step, so only depended on a few characters of the input. The intermediate mixing steps could result in collisions even with a finalizer. Also, it's not necessary to branch depending on the case of the input -- we can borrow a trick from the keyword hashes and unconditionally bitwise-OR with 0x20. That will do the correct case folding for letters while leaving most other characters legal in GUC names unchanged. --- src/backend/utils/misc/guc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index e76c083003..053be81d14 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -33,6 +33,7 @@ #include "catalog/objectaccess.h" #include "catalog/pg_authid.h" #include "catalog/pg_parameter_acl.h" +#include "common/hashfn_unstable.h" #include "guc_internal.h" #include "libpq/pqformat.h" #include "parser/scansup.h" @@ -1324,22 +1325,21 @@ guc_name_compare(const char *namea, const char *nameb) static uint32 guc_name_hash(const void *key, Size keysize) { - uint32 result = 0; const char *name = *(const char *const *) key; + fasthash_state hs; + + fasthash_init(&hs, 0, 0); while (*name) { char ch = *name++; - /* Case-fold in the same way as guc_name_compare */ - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; + /* quick and dirty casefolding suitable for hashing */ + ch |= 0x20; - /* Merge into hash ... not very bright, but it needn't be */ - result = pg_rotate_left32(result, 5); - result ^= (uint32) ch; + fasthash_accum_byte(&hs, (unsigned char) ch); } - return result; + return fasthash_final32(&hs); } /* -- 2.43.0