Skip to content

Commit 0270ad1

Browse files
committed
Fix typcache's failure to treat ranges as container types.
Like the similar logic for arrays and records, it's necessary to examine the range's subtype to decide whether the range type can support hashing. We can omit checking the subtype for btree-defined operations, though, since range subtypes are required to have those operations. (Possibly that simplification for btree cases led us to overlook that it does not apply for hash cases.) This is only an issue if the subtype lacks hash support, which is not true of any built-in range type, but it's easy to demonstrate a problem with a range type over, eg, money: you can get a "could not identify a hash function" failure when the planner is misled into thinking that hash join or aggregation would work. This was born broken, so back-patch to all supported branches.
1 parent bc639d4 commit 0270ad1

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

src/backend/utils/cache/typcache.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ static void cache_array_element_properties(TypeCacheEntry *typentry);
129129
static bool record_fields_have_equality(TypeCacheEntry *typentry);
130130
static bool record_fields_have_compare(TypeCacheEntry *typentry);
131131
static void cache_record_field_properties(TypeCacheEntry *typentry);
132+
static bool range_element_has_hashing(TypeCacheEntry *typentry);
133+
static void cache_range_element_properties(TypeCacheEntry *typentry);
132134
static void TypeCacheRelCallback(Datum arg, Oid relid);
133135
static void load_enum_cache_data(TypeCacheEntry *tcache);
134136
static EnumItem *find_enumitem(TypeCacheEnumData *enumdata, Oid arg);
@@ -405,6 +407,13 @@ lookup_type_cache(Oid type_id, int flags)
405407
!array_element_has_hashing(typentry))
406408
hash_proc = InvalidOid;
407409

410+
/*
411+
* Likewise for hash_range.
412+
*/
413+
if (hash_proc == F_HASH_RANGE &&
414+
!range_element_has_hashing(typentry))
415+
hash_proc = InvalidOid;
416+
408417
typentry->hash_proc = hash_proc;
409418
}
410419

@@ -608,6 +617,10 @@ cache_array_element_properties(TypeCacheEntry *typentry)
608617
typentry->flags |= TCFLAGS_CHECKED_ELEM_PROPERTIES;
609618
}
610619

620+
/*
621+
* Likewise, some helper functions for composite types.
622+
*/
623+
611624
static bool
612625
record_fields_have_equality(TypeCacheEntry *typentry)
613626
{
@@ -678,6 +691,43 @@ cache_record_field_properties(TypeCacheEntry *typentry)
678691
typentry->flags |= TCFLAGS_CHECKED_FIELD_PROPERTIES;
679692
}
680693

694+
/*
695+
* Likewise, some helper functions for range types.
696+
*
697+
* We can borrow the flag bits for array element properties to use for range
698+
* element properties, since those flag bits otherwise have no use in a
699+
* range type's typcache entry.
700+
*/
701+
702+
static bool
703+
range_element_has_hashing(TypeCacheEntry *typentry)
704+
{
705+
if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
706+
cache_range_element_properties(typentry);
707+
return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
708+
}
709+
710+
static void
711+
cache_range_element_properties(TypeCacheEntry *typentry)
712+
{
713+
/* load up subtype link if we didn't already */
714+
if (typentry->rngelemtype == NULL &&
715+
typentry->typtype == TYPTYPE_RANGE)
716+
load_rangetype_info(typentry);
717+
718+
if (typentry->rngelemtype != NULL)
719+
{
720+
TypeCacheEntry *elementry;
721+
722+
/* might need to calculate subtype's hash function properties */
723+
elementry = lookup_type_cache(typentry->rngelemtype->type_id,
724+
TYPECACHE_HASH_PROC);
725+
if (OidIsValid(elementry->hash_proc))
726+
typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
727+
}
728+
typentry->flags |= TCFLAGS_CHECKED_ELEM_PROPERTIES;
729+
}
730+
681731

682732
/*
683733
* lookup_rowtype_tupdesc_internal --- internal routine to lookup a rowtype

src/test/regress/expected/rangetypes.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,18 @@ select array[1,3] <@ arrayrange(array[1,2], array[2,1]);
10391039
t
10401040
(1 row)
10411041

1042+
--
1043+
-- Check behavior when subtype lacks a hash function
1044+
--
1045+
create type cashrange as range (subtype = money);
1046+
set enable_sort = off; -- try to make it pick a hash setop implementation
1047+
select '(2,5)'::cashrange except select '(5,6)'::cashrange;
1048+
cashrange
1049+
---------------
1050+
($2.00,$5.00)
1051+
(1 row)
1052+
1053+
reset enable_sort;
10421054
--
10431055
-- OUT/INOUT/TABLE functions
10441056
--

src/test/regress/sql/rangetypes.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,18 @@ select arrayrange(ARRAY[2,1], ARRAY[1,2]); -- fail
363363
select array[1,1] <@ arrayrange(array[1,2], array[2,1]);
364364
select array[1,3] <@ arrayrange(array[1,2], array[2,1]);
365365

366+
--
367+
-- Check behavior when subtype lacks a hash function
368+
--
369+
370+
create type cashrange as range (subtype = money);
371+
372+
set enable_sort = off; -- try to make it pick a hash setop implementation
373+
374+
select '(2,5)'::cashrange except select '(5,6)'::cashrange;
375+
376+
reset enable_sort;
377+
366378
--
367379
-- OUT/INOUT/TABLE functions
368380
--

0 commit comments

Comments
 (0)