diff options
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 137e2ce0491..754753cc12d 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -861,28 +861,45 @@ testexpr_is_hashable(Node *testexpr) return false; } +/* + * Check expression is hashable + strict + * + * We could use op_hashjoinable() and op_strict(), but do it like this to + * avoid a redundant cache lookup. + */ static bool hash_ok_operator(OpExpr *expr) { Oid opid = expr->opno; - HeapTuple tup; - Form_pg_operator optup; /* quick out if not a binary operator */ if (list_length(expr->args) != 2) return false; - /* else must look up the operator properties */ - tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opid)); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for operator %u", opid); - optup = (Form_pg_operator) GETSTRUCT(tup); - if (!optup->oprcanhash || !func_strict(optup->oprcode)) + if (opid == ARRAY_EQ_OP) + { + /* array_eq is strict, but must check input type to ensure hashable */ + Node *leftarg = linitial(expr->args); + + return op_hashjoinable(opid, exprType(leftarg)); + } + else { + /* else must look up the operator properties */ + HeapTuple tup; + Form_pg_operator optup; + + tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for operator %u", opid); + optup = (Form_pg_operator) GETSTRUCT(tup); + if (!optup->oprcanhash || !func_strict(optup->oprcode)) + { + ReleaseSysCache(tup); + return false; + } ReleaseSysCache(tup); - return false; + return true; } - ReleaseSysCache(tup); - return true; } |