summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-01-30 17:04:31 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2011-01-30 17:05:15 -0500
commit1df57f63f3f60c684aa8918910ac410e9c780713 (patch)
tree7a51e5befb4b87f929ae0c711fa7e37314d0bbb0 /src
parent2fb64d857003c91378ba86b03d753a63ebee95b2 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/prep/prepjointree.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index dbe7836b423..5a49768c6ce 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1745,6 +1745,11 @@ reduce_outer_joins_pass2(Node *jtnode,
* is that we pass either the local or the upper constraints,
* 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
* possible to be smarter?
*/
@@ -1754,7 +1759,7 @@ reduce_outer_joins_pass2(Node *jtnode,
if (!computed_local_nonnullable_vars)
local_nonnullable_vars = find_nonnullable_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 */
local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
@@ -1774,14 +1779,14 @@ reduce_outer_joins_pass2(Node *jtnode,
if (left_state->contains_outer)
{
- if (jointype == JOIN_INNER)
+ if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
{
/* pass union of local and upper constraints */
pass_nonnullable_rels = local_nonnullable_rels;
pass_nonnullable_vars = local_nonnullable_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 */
pass_nonnullable_rels = nonnullable_rels;