aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/postgres_fdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 4e31b8e40dd..4b6ec14c65b 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -3952,14 +3952,6 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
* Assess whether the join between inner and outer relations can be pushed down
* to the foreign server. As a side effect, save information we obtain in this
* function to PgFdwRelationInfo passed in.
- *
- * Joins that satisfy conditions below are safe to push down.
- *
- * 1) Join type is INNER or OUTER (one of LEFT/RIGHT/FULL)
- * 2) Both outer and inner portions are safe to push-down
- * 3) All join conditions are safe to push down
- * 4) No relation has local filter (this can be relaxed for INNER JOIN, if we
- * can move unpushable clauses upwards in the join tree).
*/
static bool
foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
@@ -4036,6 +4028,26 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
return false;
}
+ /*
+ * deparseExplicitTargetList() isn't smart enough to handle anything other
+ * than a Var. In particular, if there's some PlaceHolderVar that would
+ * need to be evaluated within this join tree (because there's an upper
+ * reference to a quantity that may go to NULL as a result of an outer
+ * join), then we can't try to push the join down because we'll fail when
+ * we get to deparseExplicitTargetList(). However, a PlaceHolderVar that
+ * needs to be evaluated *at the top* of this join tree is OK, because we
+ * can do that locally after fetching the results from the remote side.
+ */
+ foreach(lc, root->placeholder_list)
+ {
+ PlaceHolderInfo *phinfo = lfirst(lc);
+ Relids relids = joinrel->relids;
+
+ if (bms_is_subset(phinfo->ph_eval_at, relids) &&
+ bms_nonempty_difference(relids, phinfo->ph_eval_at))
+ return false;
+ }
+
/* Save the join clauses, for later use. */
fpinfo->joinclauses = joinclauses;
@@ -4116,9 +4128,9 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
}
/*
- * For an inner join, as explained above all restrictions can be treated
- * alike. Treating the pushed down conditions as join conditions allows a
- * top level full outer join to be deparsed without requiring subqueries.
+ * For an inner join, all restrictions can be treated alike. Treating the
+ * pushed down conditions as join conditions allows a top level full outer
+ * join to be deparsed without requiring subqueries.
*/
if (jointype == JOIN_INNER)
{