diff options
Diffstat (limited to 'src/backend/optimizer/prep/prepjointree.c')
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 34144ccaf0f..9bf1c662b53 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -1435,25 +1435,40 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, /* * 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; /* @@ -1667,7 +1682,8 @@ is_simple_values(PlannerInfo *root, RangeTblEntry *rte, bool deletion_ok) /* * 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. */ /* |