diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 9150fe832f..bca6276449 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -168,6 +168,8 @@ static void cache_array_element_properties(TypeCacheEntry *typentry); static bool record_fields_have_equality(TypeCacheEntry *typentry); static bool record_fields_have_compare(TypeCacheEntry *typentry); static void cache_record_field_properties(TypeCacheEntry *typentry); +static bool range_element_has_hashing(TypeCacheEntry *typentry); +static void cache_range_element_properties(TypeCacheEntry *typentry); static void TypeCacheRelCallback(Datum arg, Oid relid); static void TypeCacheOpcCallback(Datum arg, int cacheid, uint32 hashvalue); static void TypeCacheConstrCallback(Datum arg, int cacheid, uint32 hashvalue); @@ -481,6 +483,13 @@ lookup_type_cache(Oid type_id, int flags) !array_element_has_hashing(typentry)) hash_proc = InvalidOid; + /* + * Likewise for hash_range. + */ + if (hash_proc == F_HASH_RANGE && + !range_element_has_hashing(typentry)) + hash_proc = InvalidOid; + /* Force update of hash_proc_finfo only if we're changing state */ if (typentry->hash_proc != hash_proc) typentry->hash_proc_finfo.fn_oid = InvalidOid; @@ -1113,6 +1122,10 @@ cache_array_element_properties(TypeCacheEntry *typentry) typentry->flags |= TCFLAGS_CHECKED_ELEM_PROPERTIES; } +/* + * Likewise, some helper functions for composite types. + */ + static bool record_fields_have_equality(TypeCacheEntry *typentry) { @@ -1183,6 +1196,43 @@ cache_record_field_properties(TypeCacheEntry *typentry) typentry->flags |= TCFLAGS_CHECKED_FIELD_PROPERTIES; } +/* + * Likewise, some helper functions for range types. + * + * We can borrow the flag bits for array element properties to use for range + * element properties, since those flag bits otherwise have no use in a + * range type's typcache entry. + */ + +static bool +range_element_has_hashing(TypeCacheEntry *typentry) +{ + if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES)) + cache_range_element_properties(typentry); + return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0; +} + +static void +cache_range_element_properties(TypeCacheEntry *typentry) +{ + /* load up subtype link if we didn't already */ + if (typentry->rngelemtype == NULL && + typentry->typtype == TYPTYPE_RANGE) + load_rangetype_info(typentry); + + if (typentry->rngelemtype != NULL) + { + TypeCacheEntry *elementry; + + /* might need to calculate subtype's hash function properties */ + elementry = lookup_type_cache(typentry->rngelemtype->type_id, + TYPECACHE_HASH_PROC); + if (OidIsValid(elementry->hash_proc)) + typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING; + } + typentry->flags |= TCFLAGS_CHECKED_ELEM_PROPERTIES; +} + /* * lookup_rowtype_tupdesc_internal --- internal routine to lookup a rowtype diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index 4a2336cd8d..accf1e0d9e 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -1354,6 +1354,18 @@ select *, row_to_json(upper(t)) as u from drop type two_ints cascade; NOTICE: drop cascades to type two_ints_range -- +-- Check behavior when subtype lacks a hash function +-- +create type cashrange as range (subtype = money); +set enable_sort = off; -- try to make it pick a hash setop implementation +select '(2,5)'::cashrange except select '(5,6)'::cashrange; + cashrange +--------------- + ($2.00,$5.00) +(1 row) + +reset enable_sort; +-- -- OUT/INOUT/TABLE functions -- create function outparam_succeed(i anyrange, out r anyrange, out t text) diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql index a60df9095e..55638a85ee 100644 --- a/src/test/regress/sql/rangetypes.sql +++ b/src/test/regress/sql/rangetypes.sql @@ -461,6 +461,18 @@ select *, row_to_json(upper(t)) as u from drop type two_ints cascade; +-- +-- Check behavior when subtype lacks a hash function +-- + +create type cashrange as range (subtype = money); + +set enable_sort = off; -- try to make it pick a hash setop implementation + +select '(2,5)'::cashrange except select '(5,6)'::cashrange; + +reset enable_sort; + -- -- OUT/INOUT/TABLE functions --