diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 228387eaee..eb9939ea5d 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2362,7 +2362,8 @@ _copyRestrictInfo(const RestrictInfo *from) COPY_SCALAR_FIELD(right_bucketsize); COPY_SCALAR_FIELD(left_mcvfreq); COPY_SCALAR_FIELD(right_mcvfreq); - COPY_SCALAR_FIELD(hasheqoperator); + COPY_SCALAR_FIELD(lefthasheqoperator); + COPY_SCALAR_FIELD(righthasheqoperator); return newnode; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 2e5ed77e18..38f3f5a803 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2565,7 +2565,8 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node) WRITE_NODE_FIELD(right_em); WRITE_BOOL_FIELD(outer_is_left); WRITE_OID_FIELD(hashjoinoperator); - WRITE_OID_FIELD(hasheqoperator); + WRITE_OID_FIELD(lefthasheqoperator); + WRITE_OID_FIELD(righthasheqoperator); } static void diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 6407ede12a..82654f1b7d 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -394,9 +394,15 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info, RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); OpExpr *opexpr; Node *expr; + Oid hasheqoperator; - /* can't use a memoize node without a valid hash equals operator */ - if (!OidIsValid(rinfo->hasheqoperator) || + opexpr = (OpExpr *) rinfo->clause; + + /* + * Bail if the rinfo is not compatible. We need a join OpExpr + * with 2 args. + */ + if (!IsA(opexpr, OpExpr) || list_length(opexpr->args) != 2 || !clause_sides_match_join(rinfo, outerrel, innerrel)) { list_free(*operators); @@ -406,15 +412,28 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info, /* * We already checked that this is an OpExpr with 2 args when - * setting hasheqoperator. + * setting the lefthasheqoperator and righthasheqoperator. */ - opexpr = (OpExpr *) rinfo->clause; if (rinfo->outer_is_left) - expr = (Node *) linitial(opexpr->args); + { + expr = (Node *)linitial(opexpr->args); + hasheqoperator = rinfo->lefthasheqoperator; + } else - expr = (Node *) lsecond(opexpr->args); + { + expr = (Node *)lsecond(opexpr->args); + hasheqoperator = rinfo->righthasheqoperator; + } + + /* can't do memoize if we can't hash the outer type */ + if (!OidIsValid(hasheqoperator)) + { + list_free(*operators); + list_free(*param_exprs); + return false; + } - *operators = lappend_oid(*operators, rinfo->hasheqoperator); + *operators = lappend_oid(*operators, hasheqoperator); *param_exprs = lappend(*param_exprs, expr); } } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index e25dc9a7ca..607ae284a5 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -2711,8 +2711,8 @@ check_hashjoinable(RestrictInfo *restrictinfo) /* * check_memoizable * If the restrictinfo's clause is suitable to be used for a Memoize node, - * set the hasheqoperator to the hash equality operator that will be needed - * during caching. + * set the lefthasheqoperator and righthasheqoperator to the hash equality + * operator that will be needed during caching. */ static void check_memoizable(RestrictInfo *restrictinfo) @@ -2720,6 +2720,7 @@ check_memoizable(RestrictInfo *restrictinfo) TypeCacheEntry *typentry; Expr *clause = restrictinfo->clause; Node *leftarg; + Node *rightarg; if (restrictinfo->pseudoconstant) return; @@ -2733,8 +2734,14 @@ check_memoizable(RestrictInfo *restrictinfo) typentry = lookup_type_cache(exprType(leftarg), TYPECACHE_HASH_PROC | TYPECACHE_EQ_OPR); - if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr)) - return; + if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr)) + restrictinfo->lefthasheqoperator = typentry->eq_opr; + + rightarg = lsecond(((OpExpr *) clause)->args); + + typentry = lookup_type_cache(exprType(rightarg), TYPECACHE_HASH_PROC | + TYPECACHE_EQ_OPR); - restrictinfo->hasheqoperator = typentry->eq_opr; + if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr)) + restrictinfo->righthasheqoperator = typentry->eq_opr; } diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index aa9fb3a9fa..c2380fef6c 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -217,7 +217,8 @@ make_restrictinfo_internal(PlannerInfo *root, restrictinfo->left_mcvfreq = -1; restrictinfo->right_mcvfreq = -1; - restrictinfo->hasheqoperator = InvalidOid; + restrictinfo->lefthasheqoperator = InvalidOid; + restrictinfo->righthasheqoperator = InvalidOid; return restrictinfo; } @@ -368,7 +369,8 @@ commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op) result->right_bucketsize = rinfo->left_bucketsize; result->left_mcvfreq = rinfo->right_mcvfreq; result->right_mcvfreq = rinfo->left_mcvfreq; - result->hasheqoperator = InvalidOid; + result->lefthasheqoperator = InvalidOid; + result->righthasheqoperator = InvalidOid; return result; } diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 2a53a6e344..46d3d5582c 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -2122,8 +2122,9 @@ typedef struct RestrictInfo Selectivity left_mcvfreq; /* left side's most common val's freq */ Selectivity right_mcvfreq; /* right side's most common val's freq */ - /* hash equality operator used for memoize nodes, else InvalidOid */ - Oid hasheqoperator; + /* hash equality operators used for memoize nodes, else InvalidOid */ + Oid lefthasheqoperator; + Oid righthasheqoperator; } RestrictInfo; /*