* 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,
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 ||
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
left join tenk1 t4 on s.f1 > 1)
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