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.c108
1 files changed, 62 insertions, 46 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 066cffba955..28093e54562 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -3999,53 +3999,22 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
fpinfo->jointype = jointype;
/*
- * If user is willing to estimate cost for a scan of either of the joining
- * relations using EXPLAIN, he intends to estimate scans on that relation
- * more accurately. Then, it makes sense to estimate the cost the join
- * with that relation more accurately using EXPLAIN.
- */
- fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate ||
- fpinfo_i->use_remote_estimate;
-
- /*
- * Since both the joining relations come from the same server, the server
- * level options should have same value for both the relations. Pick from
- * any side.
- */
- fpinfo->fdw_startup_cost = fpinfo_o->fdw_startup_cost;
- fpinfo->fdw_tuple_cost = fpinfo_o->fdw_tuple_cost;
-
- /*
- * Set cached relation costs to some negative value, so that we can detect
- * when they are set to some sensible costs, during one (usually the
- * first) of the calls to estimate_path_cost_size().
- */
- fpinfo->rel_startup_cost = -1;
- fpinfo->rel_total_cost = -1;
-
- /* Mark that this join can be pushed down safely */
- fpinfo->pushdown_safe = true;
-
- /*
- * Set fetch size to maximum of the joining sides, since we are expecting
- * the rows returned by the join to be proportional to the relation sizes.
- */
- if (fpinfo_o->fetch_size > fpinfo_i->fetch_size)
- fpinfo->fetch_size = fpinfo_o->fetch_size;
- else
- fpinfo->fetch_size = fpinfo_i->fetch_size;
-
- /*
* Pull the other remote conditions from the joining relations into join
- * clauses or other remote clauses (remote_conds) of this relation. This
- * avoids building subqueries at every join step.
+ * clauses or other remote clauses (remote_conds) of this relation wherever
+ * possible. This avoids building subqueries at every join step, which is
+ * not currently supported by the deparser logic.
*
* For an inner join, clauses from both the relations are added to the
- * other remote clauses. For an OUTER join, the clauses from the outer
- * side are added to remote_conds since those can be evaluated after the
- * join is evaluated. The clauses from inner side are added to the
+ * other remote clauses. For LEFT and RIGHT OUTER join, the clauses from the
+ * outer side are added to remote_conds since those can be evaluated after
+ * the join is evaluated. The clauses from inner side are added to the
* joinclauses, since they need to evaluated while constructing the join.
*
+ * For a FULL OUTER JOIN, the other clauses from either relation can not be
+ * added to the joinclauses or remote_conds, since each relation acts as an
+ * outer relation for the other. Consider such full outer join as
+ * unshippable because of the reasons mentioned above in this comment.
+ *
* The joining sides can not have local conditions, thus no need to test
* shippability of the clauses being pulled up.
*/
@@ -4073,10 +4042,8 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
break;
case JOIN_FULL:
- fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
- list_copy(fpinfo_i->remote_conds));
- fpinfo->joinclauses = list_concat(fpinfo->joinclauses,
- list_copy(fpinfo_o->remote_conds));
+ if (fpinfo_i->remote_conds || fpinfo_o->remote_conds)
+ return false;
break;
default:
@@ -4085,6 +4052,55 @@ 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.
+ */
+ if (jointype == JOIN_INNER)
+ {
+ Assert(!fpinfo->joinclauses);
+ fpinfo->joinclauses = fpinfo->remote_conds;
+ fpinfo->remote_conds = NIL;
+ }
+
+ /* Mark that this join can be pushed down safely */
+ fpinfo->pushdown_safe = true;
+
+ /*
+ * If user is willing to estimate cost for a scan of either of the joining
+ * relations using EXPLAIN, he intends to estimate scans on that relation
+ * more accurately. Then, it makes sense to estimate the cost the join
+ * with that relation more accurately using EXPLAIN.
+ */
+ fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate ||
+ fpinfo_i->use_remote_estimate;
+
+ /*
+ * Since both the joining relations come from the same server, the server
+ * level options should have same value for both the relations. Pick from
+ * any side.
+ */
+ fpinfo->fdw_startup_cost = fpinfo_o->fdw_startup_cost;
+ fpinfo->fdw_tuple_cost = fpinfo_o->fdw_tuple_cost;
+
+ /*
+ * Set cached relation costs to some negative value, so that we can detect
+ * when they are set to some sensible costs, during one (usually the
+ * first) of the calls to estimate_path_cost_size().
+ */
+ fpinfo->rel_startup_cost = -1;
+ fpinfo->rel_total_cost = -1;
+
+ /*
+ * Set fetch size to maximum of the joining sides, since we are expecting
+ * the rows returned by the join to be proportional to the relation sizes.
+ */
+ if (fpinfo_o->fetch_size > fpinfo_i->fetch_size)
+ fpinfo->fetch_size = fpinfo_o->fetch_size;
+ else
+ fpinfo->fetch_size = fpinfo_i->fetch_size;
+
+ /*
* Set the string describing this join relation to be used in EXPLAIN
* output of corresponding ForeignScan.
*/