diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-10-30 21:55:20 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-10-30 21:56:11 -0400 |
commit | 186cbbda8f8dc5e42f68fc7892f206a76d56a20f (patch) | |
tree | 2c909d8365726683a61515b639c02a9ac00682f4 /src/backend/utils/cache/lsyscache.c | |
parent | bd1ff9713369c2f54391112b92e0c22ab5c99180 (diff) | |
download | postgresql-186cbbda8f8dc5e42f68fc7892f206a76d56a20f.tar.gz postgresql-186cbbda8f8dc5e42f68fc7892f206a76d56a20f.zip |
Provide hashing support for arrays.
The core of this patch is hash_array() and associated typcache
infrastructure, which works just about exactly like the existing support
for array comparison.
In addition I did some work to ensure that the planner won't think that an
array type is hashable unless its element type is hashable, and similarly
for sorting. This includes adding a datatype parameter to op_hashjoinable
and op_mergejoinable, and adding an explicit "hashable" flag to
SortGroupClause. The lack of a cross-check on the element type was a
pre-existing bug in mergejoin support --- but it didn't matter so much
before, because if you couldn't sort the element type there wasn't any good
alternative to failing anyhow. Now that we have the alternative of hashing
the array type, there are cases where we can avoid a failure by being picky
at the planner stage, so it's time to be picky.
The issue of exactly how to combine the per-element hash values to produce
an array hash is still open for discussion, but the rest of this is pretty
solid, so I'll commit it as-is.
Diffstat (limited to 'src/backend/utils/cache/lsyscache.c')
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 75 |
1 files changed, 63 insertions, 12 deletions
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 740e8c4ab42..df765e9d5e3 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -34,6 +34,7 @@ #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/typcache.h" /* Hook for plugins to get control in get_attavgwidth() */ get_attavgwidth_hook_type get_attavgwidth_hook = NULL; @@ -1054,20 +1055,47 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype) * will fail to find any mergejoin plans unless there are suitable btree * opfamily entries for this operator and associated sortops. The pg_operator * flag is just a hint to tell the planner whether to bother looking.) + * + * In some cases (currently only array_eq), mergejoinability depends on the + * specific input data type the operator is invoked for, so that must be + * passed as well. We currently assume that only one input's type is needed + * to check this --- by convention, pass the left input's data type. */ bool -op_mergejoinable(Oid opno) +op_mergejoinable(Oid opno, Oid inputtype) { HeapTuple tp; bool result = false; - tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); - if (HeapTupleIsValid(tp)) + if (opno == ARRAY_EQ_OP) { - Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + /* + * For array_eq, can sort if element type has a default btree opclass. + * We could use GetDefaultOpClass, but that's fairly expensive and not + * cached, so let's use the typcache instead. + */ + Oid elem_type = get_base_element_type(inputtype); - result = optup->oprcanmerge; - ReleaseSysCache(tp); + if (OidIsValid(elem_type)) + { + TypeCacheEntry *typentry; + + typentry = lookup_type_cache(elem_type, TYPECACHE_BTREE_OPFAMILY); + if (OidIsValid(typentry->btree_opf)) + result = true; + } + } + else + { + /* For all other operators, rely on pg_operator.oprcanmerge */ + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); + if (HeapTupleIsValid(tp)) + { + Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + + result = optup->oprcanmerge; + ReleaseSysCache(tp); + } } return result; } @@ -1077,20 +1105,43 @@ op_mergejoinable(Oid opno) * * Returns true if the operator is hashjoinable. (There must be a suitable * hash opfamily entry for this operator if it is so marked.) + * + * In some cases (currently only array_eq), hashjoinability depends on the + * specific input data type the operator is invoked for, so that must be + * passed as well. We currently assume that only one input's type is needed + * to check this --- by convention, pass the left input's data type. */ bool -op_hashjoinable(Oid opno) +op_hashjoinable(Oid opno, Oid inputtype) { HeapTuple tp; bool result = false; - tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); - if (HeapTupleIsValid(tp)) + if (opno == ARRAY_EQ_OP) { - Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + /* For array_eq, can hash if element type has a default hash opclass */ + Oid elem_type = get_base_element_type(inputtype); - result = optup->oprcanhash; - ReleaseSysCache(tp); + if (OidIsValid(elem_type)) + { + TypeCacheEntry *typentry; + + typentry = lookup_type_cache(elem_type, TYPECACHE_HASH_OPFAMILY); + if (OidIsValid(typentry->hash_opf)) + result = true; + } + } + else + { + /* For all other operators, rely on pg_operator.oprcanhash */ + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); + if (HeapTupleIsValid(tp)) + { + Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + + result = optup->oprcanhash; + ReleaseSysCache(tp); + } } return result; } |