From 9f0909cd6fa8721ea870afdbee3bb183226065b9 Mon Sep 17 00:00:00 2001 From: Andrew Repp Date: Tue, 24 Jan 2023 20:42:17 -0600 Subject: [PATCH v1 1/1] Change enum hashing to consider enumsortorder --- src/backend/access/hash/hashfunc.c | 25 +++++++++++++++++++-- src/backend/utils/cache/typcache.c | 36 ++++++++++++++++++++++++++++++ src/include/utils/typcache.h | 2 ++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c index e3e40d6c21..50728362b6 100644 --- a/src/backend/access/hash/hashfunc.c +++ b/src/backend/access/hash/hashfunc.c @@ -32,6 +32,7 @@ #include "utils/builtins.h" #include "utils/float.h" #include "utils/pg_locale.h" +#include "utils/typcache.h" #include "varatt.h" /* @@ -129,13 +130,33 @@ hashoidextended(PG_FUNCTION_ARGS) Datum hashenum(PG_FUNCTION_ARGS) { - return hash_uint32((uint32) PG_GETARG_OID(0)); + /*extract the oid of the enum we're hashing*/ + uint32 enum_oid = (uint32) PG_GETARG_OID(0); + float4 enum_sort_order = extract_enum_sort_order(enum_oid); + + /* + * Maintain consistent approach with hashfloat4 by casting the float4 enum + * sort order to a float8, and hashing that. + */ + float8 key8 = enum_sort_order; + return hash_any((unsigned char *) &key8, sizeof(key8)); } Datum hashenumextended(PG_FUNCTION_ARGS) { - return hash_uint32_extended((uint32) PG_GETARG_OID(0), PG_GETARG_INT64(1)); + /*extract the oid of the enum we're hashing*/ + uint32 enum_oid = (uint32) PG_GETARG_OID(0); + uint64 seed = PG_GETARG_INT64(1); + float4 enum_sort_order = extract_enum_sort_order(enum_oid); + + /* + * Maintain consistent approach with hashfloat4extended by casting the float4 enum + * sort order to a float8, and hashing that with seed value. + */ + float8 key8 = enum_sort_order; + + return hash_any_extended((unsigned char *) &key8, sizeof(key8), seed); } Datum diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 4a3e0fdb7f..eb554a0a5f 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -2876,3 +2876,39 @@ shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum) } CurrentSession->shared_typmod_registry = NULL; } + +float4 +extract_enum_sort_order(uint32 enum_oid) +{ + Form_pg_enum en; + TypeCacheEntry *tcache; + Oid typeoid; + TypeCacheEnumData *enumdata; + EnumItem *enum_obj; + + /* Get the OID of the enum type containing our enum */ + HeapTuple enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enum_oid)); + if (!HeapTupleIsValid(enum_tup)){ + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid internal value for enum: %u", + enum_oid))); + } + en = (Form_pg_enum) GETSTRUCT(enum_tup); + typeoid = en->enumtypid; + ReleaseSysCache(enum_tup); + + /* extract sort order from our enum */ + tcache = lookup_type_cache(typeoid, 0); + if (tcache->enumData == NULL){ + load_enum_cache_data(tcache); + } + enumdata = tcache->enumData; + enum_obj = find_enumitem(enumdata, enum_oid); + if (enum_obj == NULL){ + elog(ERROR, "enum value %u not found in cache for enum %s", + enum_oid, format_type_be(tcache->type_id)); + } + + return enum_obj->sort_order; +} diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h index 95f3a9ee30..e7af7d4942 100644 --- a/src/include/utils/typcache.h +++ b/src/include/utils/typcache.h @@ -199,6 +199,8 @@ extern uint64 assign_record_type_identifier(Oid type_id, int32 typmod); extern int compare_values_of_enum(TypeCacheEntry *tcache, Oid arg1, Oid arg2); +extern float4 extract_enum_sort_order(uint32 enum_oid); + extern size_t SharedRecordTypmodRegistryEstimate(void); extern void SharedRecordTypmodRegistryInit(SharedRecordTypmodRegistry *, -- 2.25.1