Fix misimplementation of typcache logic for extended hashing.

The previous coding would report that an array type supports extended
hashing if its element type supports regular hashing.  This bug is
only latent at the moment, since AFAICS there is not yet any code
that depends on checking presence of extended-hashing support to make
any decisions.  (And in any case it wouldn't matter unless the element
type has only regular hashing, which isn't true of any core data type.)
But that doesn't make it less broken.  Extend the
cache_array_element_properties infrastructure to check this properly.
This commit is contained in:
Tom Lane 2017-10-20 16:08:17 -04:00
parent 2959213bf3
commit a8f1efc8ac
1 changed files with 36 additions and 23 deletions

View File

@ -79,22 +79,23 @@ static HTAB *TypeCacheHash = NULL;
static TypeCacheEntry *firstDomainTypeEntry = NULL;
/* Private flag bits in the TypeCacheEntry.flags field */
#define TCFLAGS_CHECKED_BTREE_OPCLASS 0x0001
#define TCFLAGS_CHECKED_HASH_OPCLASS 0x0002
#define TCFLAGS_CHECKED_EQ_OPR 0x0004
#define TCFLAGS_CHECKED_LT_OPR 0x0008
#define TCFLAGS_CHECKED_GT_OPR 0x0010
#define TCFLAGS_CHECKED_CMP_PROC 0x0020
#define TCFLAGS_CHECKED_HASH_PROC 0x0040
#define TCFLAGS_CHECKED_ELEM_PROPERTIES 0x0080
#define TCFLAGS_HAVE_ELEM_EQUALITY 0x0100
#define TCFLAGS_HAVE_ELEM_COMPARE 0x0200
#define TCFLAGS_HAVE_ELEM_HASHING 0x0400
#define TCFLAGS_CHECKED_FIELD_PROPERTIES 0x0800
#define TCFLAGS_HAVE_FIELD_EQUALITY 0x1000
#define TCFLAGS_HAVE_FIELD_COMPARE 0x2000
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS 0x4000
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC 0x8000
#define TCFLAGS_CHECKED_BTREE_OPCLASS 0x000001
#define TCFLAGS_CHECKED_HASH_OPCLASS 0x000002
#define TCFLAGS_CHECKED_EQ_OPR 0x000004
#define TCFLAGS_CHECKED_LT_OPR 0x000008
#define TCFLAGS_CHECKED_GT_OPR 0x000010
#define TCFLAGS_CHECKED_CMP_PROC 0x000020
#define TCFLAGS_CHECKED_HASH_PROC 0x000040
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC 0x000080
#define TCFLAGS_CHECKED_ELEM_PROPERTIES 0x000100
#define TCFLAGS_HAVE_ELEM_EQUALITY 0x000200
#define TCFLAGS_HAVE_ELEM_COMPARE 0x000400
#define TCFLAGS_HAVE_ELEM_HASHING 0x000800
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING 0x001000
#define TCFLAGS_CHECKED_FIELD_PROPERTIES 0x002000
#define TCFLAGS_HAVE_FIELD_EQUALITY 0x004000
#define TCFLAGS_HAVE_FIELD_COMPARE 0x008000
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS 0x010000
/*
* Data stored about a domain type's constraints. Note that we do not create
@ -273,6 +274,7 @@ static List *prep_domain_constraints(List *constraints, MemoryContext execctx);
static bool array_element_has_equality(TypeCacheEntry *typentry);
static bool array_element_has_compare(TypeCacheEntry *typentry);
static bool array_element_has_hashing(TypeCacheEntry *typentry);
static bool array_element_has_extended_hashing(TypeCacheEntry *typentry);
static void cache_array_element_properties(TypeCacheEntry *typentry);
static bool record_fields_have_equality(TypeCacheEntry *typentry);
static bool record_fields_have_compare(TypeCacheEntry *typentry);
@ -451,8 +453,8 @@ lookup_type_cache(Oid type_id, int flags)
* eq_opr; if we already found one from the btree opclass, that
* decision is still good.
*/
typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC);
typentry->flags &= ~(TCFLAGS_CHECKED_HASH_EXTENDED_PROC);
typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
TCFLAGS_CHECKED_HASH_EXTENDED_PROC);
typentry->flags |= TCFLAGS_CHECKED_HASH_OPCLASS;
}
@ -500,8 +502,8 @@ lookup_type_cache(Oid type_id, int flags)
* equality operator. This is so we can ensure that the hash
* functions match the operator.
*/
typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC);
typentry->flags &= ~(TCFLAGS_CHECKED_HASH_EXTENDED_PROC);
typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
TCFLAGS_CHECKED_HASH_EXTENDED_PROC);
typentry->flags |= TCFLAGS_CHECKED_EQ_OPR;
}
if ((flags & TYPECACHE_LT_OPR) &&
@ -637,10 +639,10 @@ lookup_type_cache(Oid type_id, int flags)
* we'll need more logic here to check that case too.
*/
if (hash_extended_proc == F_HASH_ARRAY_EXTENDED &&
!array_element_has_hashing(typentry))
!array_element_has_extended_hashing(typentry))
hash_extended_proc = InvalidOid;
/* Force update of hash_proc_finfo only if we're changing state */
/* Force update of proc finfo only if we're changing state */
if (typentry->hash_extended_proc != hash_extended_proc)
typentry->hash_extended_proc_finfo.fn_oid = InvalidOid;
@ -1269,6 +1271,14 @@ array_element_has_hashing(TypeCacheEntry *typentry)
return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
}
static bool
array_element_has_extended_hashing(TypeCacheEntry *typentry)
{
if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
cache_array_element_properties(typentry);
return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
}
static void
cache_array_element_properties(TypeCacheEntry *typentry)
{
@ -1281,13 +1291,16 @@ cache_array_element_properties(TypeCacheEntry *typentry)
elementry = lookup_type_cache(elem_type,
TYPECACHE_EQ_OPR |
TYPECACHE_CMP_PROC |
TYPECACHE_HASH_PROC);
TYPECACHE_HASH_PROC |
TYPECACHE_HASH_EXTENDED_PROC);
if (OidIsValid(elementry->eq_opr))
typentry->flags |= TCFLAGS_HAVE_ELEM_EQUALITY;
if (OidIsValid(elementry->cmp_proc))
typentry->flags |= TCFLAGS_HAVE_ELEM_COMPARE;
if (OidIsValid(elementry->hash_proc))
typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
if (OidIsValid(elementry->hash_extended_proc))
typentry->flags |= TCFLAGS_HAVE_ELEM_EXTENDED_HASHING;
}
typentry->flags |= TCFLAGS_CHECKED_ELEM_PROPERTIES;
}