From 9f0909cd6fa8721ea870afdbee3bb183226065b9 Mon Sep 17 00:00:00 2001
From: Andrew Repp <reppa@vmware.com>
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

