1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-03 20:02:46 +03:00

Hash support for row types

Add hash functions for the record type as well as a hash operator
family and operator class for the record type.  This enables all the
hash functionality for the record type such as hash-based plans for
UNION/INTERSECT/EXCEPT DISTINCT, recursive queries using UNION
DISTINCT, hash joins, and hash partitioning.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/38eccd35-4e2d-6767-1b3c-dada1eac3124%402ndquadrant.com
This commit is contained in:
Peter Eisentraut
2020-11-19 09:24:37 +01:00
parent 7888b09994
commit 01e658fa74
19 changed files with 462 additions and 75 deletions

View File

@ -1358,13 +1358,18 @@ op_hashjoinable(Oid opno, Oid inputtype)
TypeCacheEntry *typentry;
/* As in op_mergejoinable, let the typcache handle the hard cases */
/* Eventually we'll need a similar case for record_eq ... */
if (opno == ARRAY_EQ_OP)
{
typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
if (typentry->hash_proc == F_HASH_ARRAY)
result = true;
}
else if (opno == RECORD_EQ_OP)
{
typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
if (typentry->hash_proc == F_HASH_RECORD)
result = true;
}
else
{
/* For all other operators, rely on pg_operator.oprcanhash */

View File

@ -97,8 +97,10 @@ static TypeCacheEntry *firstDomainTypeEntry = NULL;
#define TCFLAGS_CHECKED_FIELD_PROPERTIES 0x004000
#define TCFLAGS_HAVE_FIELD_EQUALITY 0x008000
#define TCFLAGS_HAVE_FIELD_COMPARE 0x010000
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS 0x020000
#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE 0x040000
#define TCFLAGS_HAVE_FIELD_HASHING 0x020000
#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING 0x040000
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS 0x080000
#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE 0x100000
/* The flags associated with equality/comparison/hashing are all but these: */
#define TCFLAGS_OPERATOR_FLAGS \
@ -297,6 +299,8 @@ 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);
static bool record_fields_have_hashing(TypeCacheEntry *typentry);
static bool record_fields_have_extended_hashing(TypeCacheEntry *typentry);
static void cache_record_field_properties(TypeCacheEntry *typentry);
static bool range_element_has_hashing(TypeCacheEntry *typentry);
static bool range_element_has_extended_hashing(TypeCacheEntry *typentry);
@ -677,18 +681,16 @@ lookup_type_cache(Oid type_id, int flags)
HASHSTANDARD_PROC);
/*
* As above, make sure hash_array will succeed. We don't currently
* support hashing for composite types, but when we do, we'll need
* more logic here to check that case too.
* As above, make sure hash_array, hash_record, or hash_range will
* succeed.
*/
if (hash_proc == F_HASH_ARRAY &&
!array_element_has_hashing(typentry))
hash_proc = InvalidOid;
/*
* Likewise for hash_range.
*/
if (hash_proc == F_HASH_RANGE &&
else if (hash_proc == F_HASH_RECORD &&
!record_fields_have_hashing(typentry))
hash_proc = InvalidOid;
else if (hash_proc == F_HASH_RANGE &&
!range_element_has_hashing(typentry))
hash_proc = InvalidOid;
@ -721,18 +723,16 @@ lookup_type_cache(Oid type_id, int flags)
HASHEXTENDED_PROC);
/*
* As above, make sure hash_array_extended will succeed. We don't
* currently support hashing for composite types, but when we do,
* we'll need more logic here to check that case too.
* As above, make sure hash_array_extended, hash_record_extended, or
* hash_range_extended will succeed.
*/
if (hash_extended_proc == F_HASH_ARRAY_EXTENDED &&
!array_element_has_extended_hashing(typentry))
hash_extended_proc = InvalidOid;
/*
* Likewise for hash_range_extended.
*/
if (hash_extended_proc == F_HASH_RANGE_EXTENDED &&
else if (hash_extended_proc == F_HASH_RECORD_EXTENDED &&
!record_fields_have_extended_hashing(typentry))
hash_extended_proc = InvalidOid;
else if (hash_extended_proc == F_HASH_RANGE_EXTENDED &&
!range_element_has_extended_hashing(typentry))
hash_extended_proc = InvalidOid;
@ -1447,6 +1447,22 @@ record_fields_have_compare(TypeCacheEntry *typentry)
return (typentry->flags & TCFLAGS_HAVE_FIELD_COMPARE) != 0;
}
static bool
record_fields_have_hashing(TypeCacheEntry *typentry)
{
if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
cache_record_field_properties(typentry);
return (typentry->flags & TCFLAGS_HAVE_FIELD_HASHING) != 0;
}
static bool
record_fields_have_extended_hashing(TypeCacheEntry *typentry)
{
if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
cache_record_field_properties(typentry);
return (typentry->flags & TCFLAGS_HAVE_FIELD_EXTENDED_HASHING) != 0;
}
static void
cache_record_field_properties(TypeCacheEntry *typentry)
{
@ -1456,8 +1472,12 @@ cache_record_field_properties(TypeCacheEntry *typentry)
* everything will (we may get a failure at runtime ...)
*/
if (typentry->type_id == RECORDOID)
{
typentry->flags |= (TCFLAGS_HAVE_FIELD_EQUALITY |
TCFLAGS_HAVE_FIELD_COMPARE);
TCFLAGS_HAVE_FIELD_COMPARE |
TCFLAGS_HAVE_FIELD_HASHING |
TCFLAGS_HAVE_FIELD_EXTENDED_HASHING);
}
else if (typentry->typtype == TYPTYPE_COMPOSITE)
{
TupleDesc tupdesc;
@ -1474,7 +1494,9 @@ cache_record_field_properties(TypeCacheEntry *typentry)
/* Have each property if all non-dropped fields have the property */
newflags = (TCFLAGS_HAVE_FIELD_EQUALITY |
TCFLAGS_HAVE_FIELD_COMPARE);
TCFLAGS_HAVE_FIELD_COMPARE |
TCFLAGS_HAVE_FIELD_HASHING |
TCFLAGS_HAVE_FIELD_EXTENDED_HASHING);
for (i = 0; i < tupdesc->natts; i++)
{
TypeCacheEntry *fieldentry;
@ -1485,11 +1507,17 @@ cache_record_field_properties(TypeCacheEntry *typentry)
fieldentry = lookup_type_cache(attr->atttypid,
TYPECACHE_EQ_OPR |
TYPECACHE_CMP_PROC);
TYPECACHE_CMP_PROC |
TYPECACHE_HASH_PROC |
TYPECACHE_HASH_EXTENDED_PROC);
if (!OidIsValid(fieldentry->eq_opr))
newflags &= ~TCFLAGS_HAVE_FIELD_EQUALITY;
if (!OidIsValid(fieldentry->cmp_proc))
newflags &= ~TCFLAGS_HAVE_FIELD_COMPARE;
if (!OidIsValid(fieldentry->hash_proc))
newflags &= ~TCFLAGS_HAVE_FIELD_HASHING;
if (!OidIsValid(fieldentry->hash_extended_proc))
newflags &= ~TCFLAGS_HAVE_FIELD_EXTENDED_HASHING;
/* We can drop out of the loop once we disprove all bits */
if (newflags == 0)
@ -1514,12 +1542,16 @@ cache_record_field_properties(TypeCacheEntry *typentry)
}
baseentry = lookup_type_cache(typentry->domainBaseType,
TYPECACHE_EQ_OPR |
TYPECACHE_CMP_PROC);
TYPECACHE_CMP_PROC |
TYPECACHE_HASH_PROC |
TYPECACHE_HASH_EXTENDED_PROC);
if (baseentry->typtype == TYPTYPE_COMPOSITE)
{
typentry->flags |= TCFLAGS_DOMAIN_BASE_IS_COMPOSITE;
typentry->flags |= baseentry->flags & (TCFLAGS_HAVE_FIELD_EQUALITY |
TCFLAGS_HAVE_FIELD_COMPARE);
TCFLAGS_HAVE_FIELD_COMPARE |
TCFLAGS_HAVE_FIELD_HASHING |
TCFLAGS_HAVE_FIELD_EXTENDED_HASHING);
}
}
typentry->flags |= TCFLAGS_CHECKED_FIELD_PROPERTIES;