aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/postgres_fdw.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2017-03-16 13:34:59 -0400
committerRobert Haas <rhaas@postgresql.org>2017-03-16 13:34:59 -0400
commitb30fb56b07a885f3476fe05920249f4832ca8da5 (patch)
tree9cd61df6b4b83556a935fc52106b958201c17ad7 /contrib/postgres_fdw/postgres_fdw.c
parenta3eac988c26706059ae74c740a1abcb588449abe (diff)
downloadpostgresql-b30fb56b07a885f3476fe05920249f4832ca8da5.tar.gz
postgresql-b30fb56b07a885f3476fe05920249f4832ca8da5.zip
postgres_fdw: Push down FULL JOINs with restriction clauses.
The previous deparsing logic wasn't smart enough to produce subqueries when deparsing; make it smart enough to do that. However, we only do it that way when necessary, because it generates more complicated SQL which will be harder for any humans reading the queries to understand. Etsuro Fujita, reviewed by Ashutosh Bapat Discussion: http://postgr.es/m/c449261a-b033-dc02-9254-2fe5b7044795@lab.ntt.co.jp
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c67
1 files changed, 58 insertions, 9 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 990313a5977..e8cb2d0b4da 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -669,6 +669,13 @@ postgresGetForeignRelSize(PlannerInfo *root,
if (*refname && strcmp(refname, relname) != 0)
appendStringInfo(fpinfo->relation_name, " %s",
quote_identifier(rte->eref->aliasname));
+
+ /* No outer and inner relations. */
+ fpinfo->make_outerrel_subquery = false;
+ fpinfo->make_innerrel_subquery = false;
+ fpinfo->lower_subquery_rels = NULL;
+ /* Set the relation index. */
+ fpinfo->relation_index = baserel->relid;
}
/*
@@ -1238,7 +1245,7 @@ postgresGetForeignPlan(PlannerInfo *root,
initStringInfo(&sql);
deparseSelectStmtForRel(&sql, root, foreignrel, fdw_scan_tlist,
remote_conds, best_path->path.pathkeys,
- &retrieved_attrs, &params_list);
+ false, &retrieved_attrs, &params_list);
/*
* Build the fdw_private list that will be available to the executor.
@@ -2550,8 +2557,8 @@ estimate_path_cost_size(PlannerInfo *root,
initStringInfo(&sql);
appendStringInfoString(&sql, "EXPLAIN ");
deparseSelectStmtForRel(&sql, root, foreignrel, fdw_scan_tlist,
- remote_conds, pathkeys, &retrieved_attrs,
- NULL);
+ remote_conds, pathkeys, false,
+ &retrieved_attrs, NULL);
/* Get the remote estimate */
conn = GetConnection(fpinfo->user, false);
@@ -4150,10 +4157,22 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
fpinfo->jointype = jointype;
/*
+ * By default, both the input relations are not required to be deparsed
+ * as subqueries, but there might be some relations covered by the input
+ * relations that are required to be deparsed as subqueries, so save the
+ * relids of those relations for later use by the deparser.
+ */
+ fpinfo->make_outerrel_subquery = false;
+ fpinfo->make_innerrel_subquery = false;
+ Assert(bms_is_subset(fpinfo_o->lower_subquery_rels, outerrel->relids));
+ Assert(bms_is_subset(fpinfo_i->lower_subquery_rels, innerrel->relids));
+ fpinfo->lower_subquery_rels = bms_union(fpinfo_o->lower_subquery_rels,
+ fpinfo_i->lower_subquery_rels);
+
+ /*
* Pull the other remote conditions from the joining relations into join
* 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.
+ * wherever possible. This avoids building subqueries at every join step.
*
* For an inner join, clauses from both the relations are added to the
* other remote clauses. For LEFT and RIGHT OUTER join, the clauses from
@@ -4164,8 +4183,7 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
*
* 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.
+ * as an outer relation for the other.
*
* The joining sides can not have local conditions, thus no need to test
* shippability of the clauses being pulled up.
@@ -4194,8 +4212,29 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
break;
case JOIN_FULL:
- if (fpinfo_i->remote_conds || fpinfo_o->remote_conds)
- return false;
+
+ /*
+ * In this case, if any of the input relations has conditions,
+ * we need to deparse that relation as a subquery so that the
+ * conditions can be evaluated before the join. Remember it in
+ * the fpinfo of this relation so that the deparser can take
+ * appropriate action. Also, save the relids of base relations
+ * covered by that relation for later use by the deparser.
+ */
+ if (fpinfo_o->remote_conds)
+ {
+ fpinfo->make_outerrel_subquery = true;
+ fpinfo->lower_subquery_rels =
+ bms_add_members(fpinfo->lower_subquery_rels,
+ outerrel->relids);
+ }
+ if (fpinfo_i->remote_conds)
+ {
+ fpinfo->make_innerrel_subquery = true;
+ fpinfo->lower_subquery_rels =
+ bms_add_members(fpinfo->lower_subquery_rels,
+ innerrel->relids);
+ }
break;
default:
@@ -4276,6 +4315,16 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
get_jointype_name(fpinfo->jointype),
fpinfo_i->relation_name->data);
+ /*
+ * Set the relation index. This is defined as the position of this
+ * joinrel in the join_rel_list list plus the length of the rtable list.
+ * Note that since this joinrel is at the end of the join_rel_list list
+ * when we are called, we can get the position by list_length.
+ */
+ Assert(fpinfo->relation_index == 0); /* shouldn't be set yet */
+ fpinfo->relation_index =
+ list_length(root->parse->rtable) + list_length(root->join_rel_list);
+
return true;
}