]> granicus.if.org Git - postgresql/commitdiff
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;
 }