diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2023-02-23 11:05:58 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2023-02-23 11:05:58 -0500 |
commit | 739f1d6218f5ce1e0243127ab23f431a7d07977c (patch) | |
tree | 6d18b2d4fe765e81300b770962cfd6a7fca3cedd /src/backend/optimizer/util/relnode.c | |
parent | 03d02f54a64089284582cc60d94a8af09ff4e081 (diff) |
Fix mis-handling of outer join quals generated by EquivalenceClasses.
It's possible, in admittedly-rather-contrived cases, for an eclass
to generate a derived "join" qual that constrains the post-outer-join
value(s) of some RHS variable(s) without mentioning the LHS at all.
While the mechanisms were set up to work for this, we fell foul of
the "get_common_eclass_indexes" filter installed by commit 3373c7155:
it could decide that such an eclass wasn't relevant to the join, so
that the required qual clause wouldn't get emitted there or anywhere
else.
To fix, apply get_common_eclass_indexes only at inner joins, where
its rule is still valid. At an outer join, fall back to examining all
eclasses that mention either input (or the OJ relid, though it should
be impossible for an eclass to mention that without mentioning either
input). Perhaps we can improve on that later, but the cost/benefit of
adding more complexity to skip some irrelevant eclasses is dubious.
To allow cheaply distinguishing outer from inner joins, pass the
ojrelid to generate_join_implied_equalities as a separate argument.
This also allows cleaning up some sloppiness that had crept into
the definition of its join_relids argument, and it allows accurate
calculation of nominal_join_relids for a child outer join. (The
latter oversight seems not to have been a live bug, but it certainly
could have caused problems in future.)
Also fix what might be a live bug in check_index_predicates: it was
being sloppy about what it passed to generate_join_implied_equalities.
Per report from Richard Guo.
Discussion: https://postgr.es/m/CAMbWs4-DsTBfOvXuw64GdFss2=M5cwtEhY=0DCS7t2gT7P6hSA@mail.gmail.com
Diffstat (limited to 'src/backend/optimizer/util/relnode.c')
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index d29a25f8aa6..9ad44a0508c 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -47,7 +47,8 @@ static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, static List *build_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, - RelOptInfo *inner_rel); + RelOptInfo *inner_rel, + SpecialJoinInfo *sjinfo); static void build_joinrel_joinlist(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel); @@ -667,7 +668,8 @@ build_join_rel(PlannerInfo *root, *restrictlist_ptr = build_joinrel_restrictlist(root, joinrel, outer_rel, - inner_rel); + inner_rel, + sjinfo); return joinrel; } @@ -779,7 +781,8 @@ build_join_rel(PlannerInfo *root, * for set_joinrel_size_estimates().) */ restrictlist = build_joinrel_restrictlist(root, joinrel, - outer_rel, inner_rel); + outer_rel, inner_rel, + sjinfo); if (restrictlist_ptr) *restrictlist_ptr = restrictlist; build_joinrel_joinlist(joinrel, outer_rel, inner_rel); @@ -1220,6 +1223,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * 'joinrel' is a join relation node * 'outer_rel' and 'inner_rel' are a pair of relations that can be joined * to form joinrel. + * 'sjinfo': join context info * * build_joinrel_restrictlist() returns a list of relevant restrictinfos, * whereas build_joinrel_joinlist() stores its results in the joinrel's @@ -1234,7 +1238,8 @@ static List * build_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, - RelOptInfo *inner_rel) + RelOptInfo *inner_rel, + SpecialJoinInfo *sjinfo) { List *result; Relids both_input_relids; @@ -1260,7 +1265,8 @@ build_joinrel_restrictlist(PlannerInfo *root, generate_join_implied_equalities(root, joinrel->relids, outer_rel->relids, - inner_rel)); + inner_rel, + sjinfo->ojrelid)); return result; } @@ -1543,7 +1549,8 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, generate_join_implied_equalities(root, joinrelids, required_outer, - baserel)); + baserel, + 0)); /* Compute set of serial numbers of the enforced clauses */ pserials = NULL; @@ -1665,7 +1672,8 @@ get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel, eclauses = generate_join_implied_equalities(root, join_and_req, required_outer, - joinrel); + joinrel, + 0); /* We only want ones that aren't movable to lower levels */ dropped_ecs = NIL; foreach(lc, eclauses) |