summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/prep/prepjointree.c19
-rw-r--r--src/test/regress/expected/join.out31
-rw-r--r--src/test/regress/sql/join.sql8
3 files changed, 51 insertions, 7 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 2f589b1b99f..73ff40721c9 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -3213,6 +3213,8 @@ remove_useless_result_rtes(PlannerInfo *root)
* jtnode is the current jointree node. If it could be valid to merge
* its quals into those of the parent node, parent_quals should point to
* the parent's quals list; otherwise, pass NULL for parent_quals.
+ * (Note that in some cases, parent_quals points to the quals of a parent
+ * more than one level up in the tree.)
*/
static Node *
remove_useless_results_recurse(PlannerInfo *root, Node *jtnode,
@@ -3316,13 +3318,22 @@ remove_useless_results_recurse(PlannerInfo *root, Node *jtnode,
int varno;
/*
- * First, recurse. We can accept pushed-up FromExpr quals from either
- * child if the jointype is INNER, and we can accept them from the RHS
- * child if the jointype is LEFT.
+ * First, recurse. We can absorb pushed-up FromExpr quals from either
+ * child into this node if the jointype is INNER, since then this is
+ * equivalent to a FromExpr. When the jointype is LEFT, we can absorb
+ * quals from the RHS child into the current node, as they're
+ * essentially degenerate quals of the outer join. Moreover, if we've
+ * been passed down a parent_quals pointer then we can allow quals of
+ * the LHS child to be absorbed into the parent. (This is important
+ * to ensure we remove single-child FromExprs immediately below
+ * commutable left joins.) For other jointypes, we can't move child
+ * quals up, or at least there's no particular reason to.
*/
j->larg = remove_useless_results_recurse(root, j->larg,
(j->jointype == JOIN_INNER) ?
- &j->quals : NULL,
+ &j->quals :
+ (j->jointype == JOIN_LEFT) ?
+ parent_quals : NULL,
dropped_outer_joins);
j->rarg = remove_useless_results_recurse(root, j->rarg,
(j->jointype == JOIN_INNER ||
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index cd1163d039b..6917faec141 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2531,20 +2531,45 @@ select * from int4_tbl t1
on s.f1 = t1.f1;
QUERY PLAN
-------------------------------------------------
+ Hash Right Join
+ Hash Cond: (t2.f1 = t1.f1)
+ -> Nested Loop Left Join
+ Join Filter: (t2.f1 > 1)
+ -> Nested Loop Left Join
+ Join Filter: (t2.f1 > 0)
+ Filter: (t3.f1 IS NULL)
+ -> Seq Scan on int4_tbl t2
+ -> Materialize
+ -> Seq Scan on int4_tbl t3
+ -> Seq Scan on tenk1 t4
+ -> Hash
+ -> Seq Scan on int4_tbl t1
+(13 rows)
+
+explain (costs off)
+select * from int4_tbl t1
+ left join ((select t2.f1 from int4_tbl t2
+ left join int4_tbl t3 on t2.f1 > 0
+ where t2.f1 <> coalesce(t3.f1, -1)) s
+ left join tenk1 t4 on s.f1 > 1)
+ on s.f1 = t1.f1;
+ QUERY PLAN
+-----------------------------------------------------------------
Nested Loop Left Join
Join Filter: (t2.f1 > 1)
-> Hash Right Join
Hash Cond: (t2.f1 = t1.f1)
-> Nested Loop Left Join
Join Filter: (t2.f1 > 0)
- Filter: (t3.f1 IS NULL)
+ Filter: (t2.f1 <> COALESCE(t3.f1, '-1'::integer))
-> Seq Scan on int4_tbl t2
-> Materialize
-> Seq Scan on int4_tbl t3
-> Hash
-> Seq Scan on int4_tbl t1
- -> Seq Scan on tenk1 t4
-(13 rows)
+ -> Materialize
+ -> Seq Scan on tenk1 t4
+(14 rows)
explain (costs off)
select * from onek t1
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 7ca737eec0f..55080bec9af 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -503,6 +503,14 @@ select * from int4_tbl t1
on s.f1 = t1.f1;
explain (costs off)
+select * from int4_tbl t1
+ left join ((select t2.f1 from int4_tbl t2
+ left join int4_tbl t3 on t2.f1 > 0
+ where t2.f1 <> coalesce(t3.f1, -1)) s
+ left join tenk1 t4 on s.f1 > 1)
+ on s.f1 = t1.f1;
+
+explain (costs off)
select * from onek t1
left join onek t2 on t1.unique1 = t2.unique1
left join onek t3 on t2.unique1 = t3.unique1