Make reduce_outer_joins() smarter about semijoins.

reduce_outer_joins() mistakenly treated a semijoin like a left join for
purposes of deciding whether not-null constraints created by the join's
quals could be passed down into the join's left-hand side (possibly
resulting in outer-join simplification there).  Actually, semijoin works
like inner join for this purpose, ie, we do not need to see any rows that
can't possibly satisfy the quals.  Hence, two-line fix to treat semi and
inner joins alike.  Per observation by Andres Freund about a performance
gripe from Yazan Suleiman.

Back-patch to 8.4, since this oversight has been there since the current
handling of semijoins was implemented.
This commit is contained in:
Tom Lane 2011-01-30 17:04:31 -05:00
parent 507069de6d
commit 9688c4e6f1
1 changed files with 8 additions and 3 deletions

View File

@ -1840,6 +1840,11 @@ reduce_outer_joins_pass2(Node *jtnode,
* is that we pass either the local or the upper constraints, * is that we pass either the local or the upper constraints,
* never both, to the children of an outer join. * never both, to the children of an outer join.
* *
* Note that a SEMI join works like an inner join here: it's okay
* to pass down both local and upper constraints. (There can't
* be any upper constraints affecting its inner side, but it's
* not worth having a separate code path to avoid passing them.)
*
* At a FULL join we just punt and pass nothing down --- is it * At a FULL join we just punt and pass nothing down --- is it
* possible to be smarter? * possible to be smarter?
*/ */
@ -1849,7 +1854,7 @@ reduce_outer_joins_pass2(Node *jtnode,
if (!computed_local_nonnullable_vars) if (!computed_local_nonnullable_vars)
local_nonnullable_vars = find_nonnullable_vars(j->quals); local_nonnullable_vars = find_nonnullable_vars(j->quals);
local_forced_null_vars = find_forced_null_vars(j->quals); local_forced_null_vars = find_forced_null_vars(j->quals);
if (jointype == JOIN_INNER) if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
{ {
/* OK to merge upper and local constraints */ /* OK to merge upper and local constraints */
local_nonnullable_rels = bms_add_members(local_nonnullable_rels, local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
@ -1869,14 +1874,14 @@ reduce_outer_joins_pass2(Node *jtnode,
if (left_state->contains_outer) if (left_state->contains_outer)
{ {
if (jointype == JOIN_INNER) if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
{ {
/* pass union of local and upper constraints */ /* pass union of local and upper constraints */
pass_nonnullable_rels = local_nonnullable_rels; pass_nonnullable_rels = local_nonnullable_rels;
pass_nonnullable_vars = local_nonnullable_vars; pass_nonnullable_vars = local_nonnullable_vars;
pass_forced_null_vars = local_forced_null_vars; pass_forced_null_vars = local_forced_null_vars;
} }
else if (jointype != JOIN_FULL) /* ie, LEFT/SEMI/ANTI */ else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
{ {
/* can't pass local constraints to non-nullable side */ /* can't pass local constraints to non-nullable side */
pass_nonnullable_rels = nonnullable_rels; pass_nonnullable_rels = nonnullable_rels;