aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/equivclass.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-05-17 11:13:52 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-05-17 11:14:04 -0400
commit9df8f903eb6758be5a19e66cdf77e922e9329c31 (patch)
treeb2726b13ad6c830593a71fd6b1c5ac317a8ef62b /src/backend/optimizer/path/equivclass.c
parent867be9c0738bef591544d39985f886b7d8e99bf0 (diff)
downloadpostgresql-9df8f903eb6758be5a19e66cdf77e922e9329c31.tar.gz
postgresql-9df8f903eb6758be5a19e66cdf77e922e9329c31.zip
Fix some issues with improper placement of outer join clauses.
After applying outer-join identity 3 in the forward direction, it was possible for the planner to mistakenly apply a qual clause from above the two outer joins at the now-lower join level. This can give the wrong answer, since a value that would get nulled by the now-upper join might not yet be null. To fix, when we perform such a transformation, consider that the now-lower join hasn't really completed the outer join it's nominally responsible for and thus its relid set should not include that OJ's relid (nor should its output Vars have that nullingrel bit set). Instead we add those bits when the now-upper join is performed. The existing rules for qual placement then suffice to prevent higher qual clauses from dropping below the now-upper join. There are a few complications from needing to consider transitive closures in case multiple pushdowns have happened, but all in all it's not a very complex patch. This is all new logic (from 2489d76c4) so no need to back-patch. The added test cases all have the same results as in v15. Tom Lane and Richard Guo Discussion: https://postgr.es/m/0b819232-4b50-f245-1c7d-c8c61bf41827@postgrespro.ru
Diffstat (limited to 'src/backend/optimizer/path/equivclass.c')
-rw-r--r--src/backend/optimizer/path/equivclass.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 9949d5b1d3b..2db1bf64487 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -1366,19 +1366,20 @@ generate_base_implied_equalities_broken(PlannerInfo *root,
* commutative duplicates, i.e. if the algorithm selects "a.x = b.y" but
* we already have "b.y = a.x", we return the existing clause.
*
- * If we are considering an outer join, ojrelid is the associated OJ relid,
- * otherwise it's zero.
+ * If we are considering an outer join, sjinfo is the associated OJ info,
+ * otherwise it can be NULL.
*
* join_relids should always equal bms_union(outer_relids, inner_rel->relids)
- * plus ojrelid if that's not zero. We could simplify this function's API by
- * computing it internally, but most callers have the value at hand anyway.
+ * plus whatever add_outer_joins_to_relids() would add. We could simplify
+ * this function's API by computing it internally, but most callers have the
+ * value at hand anyway.
*/
List *
generate_join_implied_equalities(PlannerInfo *root,
Relids join_relids,
Relids outer_relids,
RelOptInfo *inner_rel,
- Index ojrelid)
+ SpecialJoinInfo *sjinfo)
{
List *result = NIL;
Relids inner_relids = inner_rel->relids;
@@ -1396,8 +1397,10 @@ generate_join_implied_equalities(PlannerInfo *root,
nominal_inner_relids = inner_rel->top_parent_relids;
/* ECs will be marked with the parent's relid, not the child's */
nominal_join_relids = bms_union(outer_relids, nominal_inner_relids);
- if (ojrelid != 0)
- nominal_join_relids = bms_add_member(nominal_join_relids, ojrelid);
+ nominal_join_relids = add_outer_joins_to_relids(root,
+ nominal_join_relids,
+ sjinfo,
+ NULL);
}
else
{
@@ -1418,7 +1421,7 @@ generate_join_implied_equalities(PlannerInfo *root,
* At inner joins, we can be smarter: only consider eclasses mentioning
* both input rels.
*/
- if (ojrelid != 0)
+ if (sjinfo && sjinfo->ojrelid != 0)
matching_ecs = get_eclass_indexes_for_relids(root, nominal_join_relids);
else
matching_ecs = get_common_eclass_indexes(root, nominal_inner_relids,
@@ -1467,7 +1470,7 @@ generate_join_implied_equalities(PlannerInfo *root,
* generate_join_implied_equalities_for_ecs
* As above, but consider only the listed ECs.
*
- * For the sole current caller, we can assume ojrelid == 0, that is we are
+ * For the sole current caller, we can assume sjinfo == NULL, that is we are
* not interested in outer-join filter clauses. This might need to change
* in future.
*/