Fix misimplementation of typcache logic for extended hashing.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Oct 2017 20:08:17 +0000 (16:08 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Oct 2017 20:08:17 +0000 (16:08 -0400)
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.

src/backend/utils/cache/typcache.c

index 16c52c5a38af2c131ecc97c05930f5daf4a1c668..a0a71dd86a89370b646f88accba0a442c02653f2 100644 (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;
 }