Skip to content

Commit 39a3105

Browse files
committed
Fix incorrect hash equality operator bug in Memoize
In v14, because we don't have a field in RestrictInfo to cache both the left and right type's hash equality operator, we just restrict the scope of Memoize to only when the left and right types of a RestrictInfo are the same. In master we add another field to RestrictInfo and cache both hash equality operators. Reported-by: Jaime Casanova Author: David Rowley Discussion: https://postgr.es/m/20210929185544.GB24346%40ahch-to Backpatch-through: 14
1 parent e2fbb88 commit 39a3105

File tree

6 files changed

+54
-22
lines changed

6 files changed

+54
-22
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2362,7 +2362,8 @@ _copyRestrictInfo(const RestrictInfo *from)
23622362
COPY_SCALAR_FIELD(right_bucketsize);
23632363
COPY_SCALAR_FIELD(left_mcvfreq);
23642364
COPY_SCALAR_FIELD(right_mcvfreq);
2365-
COPY_SCALAR_FIELD(hasheqoperator);
2365+
COPY_SCALAR_FIELD(left_hasheqoperator);
2366+
COPY_SCALAR_FIELD(right_hasheqoperator);
23662367

23672368
return newnode;
23682369
}

src/backend/nodes/outfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2565,7 +2565,8 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node)
25652565
WRITE_NODE_FIELD(right_em);
25662566
WRITE_BOOL_FIELD(outer_is_left);
25672567
WRITE_OID_FIELD(hashjoinoperator);
2568-
WRITE_OID_FIELD(hasheqoperator);
2568+
WRITE_OID_FIELD(left_hasheqoperator);
2569+
WRITE_OID_FIELD(right_hasheqoperator);
25692570
}
25702571

25712572
static void

src/backend/optimizer/path/joinpath.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,27 +394,42 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info,
394394
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
395395
OpExpr *opexpr;
396396
Node *expr;
397+
Oid hasheqoperator;
397398

398-
/* can't use a memoize node without a valid hash equals operator */
399-
if (!OidIsValid(rinfo->hasheqoperator) ||
399+
opexpr = (OpExpr *) rinfo->clause;
400+
401+
/*
402+
* Bail if the rinfo is not compatible. We need a join OpExpr
403+
* with 2 args.
404+
*/
405+
if (!IsA(opexpr, OpExpr) || list_length(opexpr->args) != 2 ||
400406
!clause_sides_match_join(rinfo, outerrel, innerrel))
401407
{
402408
list_free(*operators);
403409
list_free(*param_exprs);
404410
return false;
405411
}
406412

407-
/*
408-
* We already checked that this is an OpExpr with 2 args when
409-
* setting hasheqoperator.
410-
*/
411-
opexpr = (OpExpr *) rinfo->clause;
412413
if (rinfo->outer_is_left)
414+
{
413415
expr = (Node *) linitial(opexpr->args);
416+
hasheqoperator = rinfo->left_hasheqoperator;
417+
}
414418
else
419+
{
415420
expr = (Node *) lsecond(opexpr->args);
421+
hasheqoperator = rinfo->right_hasheqoperator;
422+
}
423+
424+
/* can't do memoize if we can't hash the outer type */
425+
if (!OidIsValid(hasheqoperator))
426+
{
427+
list_free(*operators);
428+
list_free(*param_exprs);
429+
return false;
430+
}
416431

417-
*operators = lappend_oid(*operators, rinfo->hasheqoperator);
432+
*operators = lappend_oid(*operators, hasheqoperator);
418433
*param_exprs = lappend(*param_exprs, expr);
419434
}
420435
}

src/backend/optimizer/plan/initsplan.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,15 +2711,16 @@ check_hashjoinable(RestrictInfo *restrictinfo)
27112711
/*
27122712
* check_memoizable
27132713
* If the restrictinfo's clause is suitable to be used for a Memoize node,
2714-
* set the hasheqoperator to the hash equality operator that will be needed
2715-
* during caching.
2714+
* set the lefthasheqoperator and righthasheqoperator to the hash equality
2715+
* operator that will be needed during caching.
27162716
*/
27172717
static void
27182718
check_memoizable(RestrictInfo *restrictinfo)
27192719
{
27202720
TypeCacheEntry *typentry;
27212721
Expr *clause = restrictinfo->clause;
2722-
Node *leftarg;
2722+
Oid lefttype;
2723+
Oid righttype;
27232724

27242725
if (restrictinfo->pseudoconstant)
27252726
return;
@@ -2728,13 +2729,24 @@ check_memoizable(RestrictInfo *restrictinfo)
27282729
if (list_length(((OpExpr *) clause)->args) != 2)
27292730
return;
27302731

2731-
leftarg = linitial(((OpExpr *) clause)->args);
2732+
lefttype = exprType(linitial(((OpExpr *) clause)->args));
27322733

2733-
typentry = lookup_type_cache(exprType(leftarg), TYPECACHE_HASH_PROC |
2734+
typentry = lookup_type_cache(lefttype, TYPECACHE_HASH_PROC |
27342735
TYPECACHE_EQ_OPR);
27352736

2736-
if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr))
2737-
return;
2737+
if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
2738+
restrictinfo->left_hasheqoperator = typentry->eq_opr;
2739+
2740+
righttype = exprType(lsecond(((OpExpr *) clause)->args));
2741+
2742+
/*
2743+
* Lookup the right type, unless it's the same as the left type, in which
2744+
* case typentry is already pointing to the required TypeCacheEntry.
2745+
*/
2746+
if (lefttype != righttype)
2747+
typentry = lookup_type_cache(righttype, TYPECACHE_HASH_PROC |
2748+
TYPECACHE_EQ_OPR);
27382749

2739-
restrictinfo->hasheqoperator = typentry->eq_opr;
2750+
if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
2751+
restrictinfo->right_hasheqoperator = typentry->eq_opr;
27402752
}

src/backend/optimizer/util/restrictinfo.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ make_restrictinfo_internal(PlannerInfo *root,
217217
restrictinfo->left_mcvfreq = -1;
218218
restrictinfo->right_mcvfreq = -1;
219219

220-
restrictinfo->hasheqoperator = InvalidOid;
220+
restrictinfo->left_hasheqoperator = InvalidOid;
221+
restrictinfo->right_hasheqoperator = InvalidOid;
221222

222223
return restrictinfo;
223224
}
@@ -368,7 +369,8 @@ commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
368369
result->right_bucketsize = rinfo->left_bucketsize;
369370
result->left_mcvfreq = rinfo->right_mcvfreq;
370371
result->right_mcvfreq = rinfo->left_mcvfreq;
371-
result->hasheqoperator = InvalidOid;
372+
result->left_hasheqoperator = InvalidOid;
373+
result->right_hasheqoperator = InvalidOid;
372374

373375
return result;
374376
}

src/include/nodes/pathnodes.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,8 +2122,9 @@ typedef struct RestrictInfo
21222122
Selectivity left_mcvfreq; /* left side's most common val's freq */
21232123
Selectivity right_mcvfreq; /* right side's most common val's freq */
21242124

2125-
/* hash equality operator used for memoize nodes, else InvalidOid */
2126-
Oid hasheqoperator;
2125+
/* hash equality operators used for memoize nodes, else InvalidOid */
2126+
Oid left_hasheqoperator;
2127+
Oid right_hasheqoperator;
21272128
} RestrictInfo;
21282129

21292130
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy