/*
* Don't pull up a subquery with an empty jointree, unless it has no quals
- * and deletion_ok is TRUE. query_planner() will correctly generate a
- * Result plan for a jointree that's totally empty, but we can't cope with
- * an empty FromExpr appearing lower down in a jointree: we identify join
- * rels via baserelid sets, so we couldn't distinguish a join containing
- * such a FromExpr from one without it. This would for example break the
- * PlaceHolderVar mechanism, since we'd have no way to identify where to
- * evaluate a PHV coming out of the subquery. We can only handle such
- * cases if the place where the subquery is linked is a FromExpr or inner
- * JOIN that would still be nonempty after removal of the subquery, so
- * that it's still identifiable via its contained baserelids. Safe
- * contexts are signaled by deletion_ok. But even in a safe context, we
- * must keep the subquery if it has any quals, because it's unclear where
- * to put them in the upper query. (Note that deletion of a subquery is
- * also dependent on the check below that its targetlist contains no
- * set-returning functions. Deletion from a FROM list or inner JOIN is
- * okay only if the subquery must return exactly one row.)
+ * and deletion_ok is TRUE and we're not underneath an outer join.
+ *
+ * query_planner() will correctly generate a Result plan for a jointree
+ * that's totally empty, but we can't cope with an empty FromExpr
+ * appearing lower down in a jointree: we identify join rels via baserelid
+ * sets, so we couldn't distinguish a join containing such a FromExpr from
+ * one without it. We can only handle such cases if the place where the
+ * subquery is linked is a FromExpr or inner JOIN that would still be
+ * nonempty after removal of the subquery, so that it's still identifiable
+ * via its contained baserelids. Safe contexts are signaled by
+ * deletion_ok.
+ *
+ * But even in a safe context, we must keep the subquery if it has any
+ * quals, because it's unclear where to put them in the upper query.
+ *
+ * Also, we must forbid pullup if such a subquery is underneath an outer
+ * join, because then we might need to wrap its output columns with
+ * PlaceHolderVars, and the PHVs would then have empty relid sets meaning
+ * we couldn't tell where to evaluate them. (This test is separate from
+ * the deletion_ok flag for possible future expansion: deletion_ok tells
+ * whether the immediate parent site in the jointree could cope, not
+ * whether we'd have PHV issues. It's possible this restriction could be
+ * fixed by letting the PHVs use the relids of the parent jointree item,
+ * but that complication is for another day.)
+ *
+ * Note that deletion of a subquery is also dependent on the check below
+ * that its targetlist contains no set-returning functions. Deletion from
+ * a FROM list or inner JOIN is okay only if the subquery must return
+ * exactly one row.
*/
if (subquery->jointree->fromlist == NIL &&
- (subquery->jointree->quals || !deletion_ok))
+ (subquery->jointree->quals != NULL ||
+ !deletion_ok ||
+ lowest_outer_join != NULL))
return false;
/*
/*
* Because VALUES can't appear under an outer join (or at least, we won't
- * try to pull it up if it does), we need not worry about LATERAL.
+ * try to pull it up if it does), we need not worry about LATERAL, nor
+ * about validity of PHVs for the VALUES' outputs.
*/
/*
----+----+---------+---------
(0 rows)
+--
+-- regression test: check handling of empty-FROM subquery underneath outer join
+--
+explain (costs off)
+select * from int8_tbl i1 left join (int8_tbl i2 join
+ (select 123 as x) ss on i2.q1 = x) on i1.q2 = i2.q2
+order by 1, 2;
+ QUERY PLAN
+-------------------------------------------------
+ Sort
+ Sort Key: i1.q1, i1.q2
+ -> Hash Left Join
+ Hash Cond: (i1.q2 = i2.q2)
+ -> Seq Scan on int8_tbl i1
+ -> Hash
+ -> Hash Join
+ Hash Cond: (i2.q1 = (123))
+ -> Seq Scan on int8_tbl i2
+ -> Hash
+ -> Result
+(11 rows)
+
+select * from int8_tbl i1 left join (int8_tbl i2 join
+ (select 123 as x) ss on i2.q1 = x) on i1.q2 = i2.q2
+order by 1, 2;
+ q1 | q2 | q1 | q2 | x
+------------------+-------------------+-----+------------------+-----
+ 123 | 456 | 123 | 456 | 123
+ 123 | 4567890123456789 | 123 | 4567890123456789 | 123
+ 4567890123456789 | -4567890123456789 | | |
+ 4567890123456789 | 123 | | |
+ 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 123
+(5 rows)
+
--
-- Clean up
--