summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/outfuncs.c4
-rw-r--r--src/backend/optimizer/path/allpaths.c13
-rw-r--r--src/backend/optimizer/path/costsize.c2
-rw-r--r--src/backend/optimizer/plan/createplan.c67
-rw-r--r--src/backend/optimizer/plan/setrefs.c2
-rw-r--r--src/backend/optimizer/plan/subselect.c2
-rw-r--r--src/backend/optimizer/util/pathnode.c2
-rw-r--r--src/backend/optimizer/util/relnode.c4
9 files changed, 69 insertions, 30 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 868fb7130a..5cde22543f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -591,8 +591,9 @@ _copyForeignScan(const ForeignScan *from)
/*
* copy remainder of node
*/
- COPY_SCALAR_FIELD(fsSystemCol);
+ COPY_NODE_FIELD(fdw_exprs);
COPY_NODE_FIELD(fdw_private);
+ COPY_SCALAR_FIELD(fsSystemCol);
return newnode;
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 9daeb3e7b4..51181a9a74 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -559,8 +559,9 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
_outScanInfo(str, (const Scan *) node);
- WRITE_BOOL_FIELD(fsSystemCol);
+ WRITE_NODE_FIELD(fdw_exprs);
WRITE_NODE_FIELD(fdw_private);
+ WRITE_BOOL_FIELD(fsSystemCol);
}
static void
@@ -1741,6 +1742,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
WRITE_FLOAT_FIELD(allvisfrac, "%.6f");
WRITE_NODE_FIELD(subplan);
WRITE_NODE_FIELD(subroot);
+ /* we don't try to print fdwroutine or fdw_private */
WRITE_NODE_FIELD(baserestrictinfo);
WRITE_NODE_FIELD(joininfo);
WRITE_BOOL_FIELD(has_eclass_joins);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6e81ce0fc2..03c604a03d 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -396,6 +396,12 @@ set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
/* Mark rel with estimated output rows, width, etc */
set_foreign_size_estimates(root, rel);
+
+ /* Get FDW routine pointers for the rel */
+ rel->fdwroutine = GetFdwRoutineByRelId(rte->relid);
+
+ /* Let FDW adjust the size estimates, if it can */
+ rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid);
}
/*
@@ -405,11 +411,8 @@ set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
static void
set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
- FdwRoutine *fdwroutine;
-
- /* Call the FDW's PlanForeignScan function to generate path(s) */
- fdwroutine = GetFdwRoutineByRelId(rte->relid);
- fdwroutine->PlanForeignScan(rte->relid, root, rel);
+ /* Call the FDW's GetForeignPaths function to generate path(s) */
+ rel->fdwroutine->GetForeignPaths(root, rel, rte->relid);
/* Select cheapest path */
set_cheapest(rel);
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 885d8558c3..24c853d47e 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3745,7 +3745,7 @@ set_cte_size_estimates(PlannerInfo *root, RelOptInfo *rel, Plan *cteplan)
* using what will be purely datatype-driven estimates from the targetlist.
* There is no way to do anything sane with the rows value, so we just put
* a default estimate and hope that the wrapper can improve on it. The
- * wrapper's PlanForeignScan function will be called momentarily.
+ * wrapper's GetForeignRelSize function will be called momentarily.
*
* The rel's targetlist and restrictinfo list must have been constructed
* already.
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index b1df56cafd..94140d304f 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -20,6 +20,7 @@
#include <math.h>
#include "access/skey.h"
+#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -119,8 +120,6 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
-static ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
- Index scanrelid, bool fsSystemCol, List *fdw_private);
static BitmapAnd *make_bitmap_and(List *bitmapplans);
static BitmapOr *make_bitmap_or(List *bitmapplans);
static NestLoop *make_nestloop(List *tlist,
@@ -1816,7 +1815,6 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
RelOptInfo *rel = best_path->path.parent;
Index scan_relid = rel->relid;
RangeTblEntry *rte;
- bool fsSystemCol;
int i;
/* it should be a base rel... */
@@ -1825,31 +1823,56 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
rte = planner_rt_fetch(scan_relid, root);
Assert(rte->rtekind == RTE_RELATION);
- /* Sort clauses into best execution order */
+ /*
+ * Sort clauses into best execution order. We do this first since the
+ * FDW might have more info than we do and wish to adjust the ordering.
+ */
scan_clauses = order_qual_clauses(root, scan_clauses);
- /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
- scan_clauses = extract_actual_clauses(scan_clauses, false);
+ /*
+ * Let the FDW perform its processing on the restriction clauses and
+ * generate the plan node. Note that the FDW might remove restriction
+ * clauses that it intends to execute remotely, or even add more (if it
+ * has selected some join clauses for remote use but also wants them
+ * rechecked locally).
+ */
+ scan_plan = rel->fdwroutine->GetForeignPlan(root, rel, rte->relid,
+ best_path,
+ tlist, scan_clauses);
+
+ /* Copy cost data from Path to Plan; no need to make FDW do this */
+ copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
- /* Detect whether any system columns are requested from rel */
- fsSystemCol = false;
+ /*
+ * Replace any outer-relation variables with nestloop params in the qual
+ * and fdw_exprs expressions. We do this last so that the FDW doesn't
+ * have to be involved. (Note that parts of fdw_exprs could have come
+ * from join clauses, so doing this beforehand on the scan_clauses
+ * wouldn't work.)
+ */
+ if (best_path->path.required_outer)
+ {
+ scan_plan->scan.plan.qual = (List *)
+ replace_nestloop_params(root, (Node *) scan_plan->scan.plan.qual);
+ scan_plan->fdw_exprs = (List *)
+ replace_nestloop_params(root, (Node *) scan_plan->fdw_exprs);
+ }
+
+ /*
+ * Detect whether any system columns are requested from rel. This is a
+ * bit of a kluge and might go away someday, so we intentionally leave it
+ * out of the API presented to FDWs.
+ */
+ scan_plan->fsSystemCol = false;
for (i = rel->min_attr; i < 0; i++)
{
if (!bms_is_empty(rel->attr_needed[i - rel->min_attr]))
{
- fsSystemCol = true;
+ scan_plan->fsSystemCol = true;
break;
}
}
- scan_plan = make_foreignscan(tlist,
- scan_clauses,
- scan_relid,
- fsSystemCol,
- best_path->fdw_private);
-
- copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
-
return scan_plan;
}
@@ -3183,24 +3206,26 @@ make_worktablescan(List *qptlist,
return node;
}
-static ForeignScan *
+ForeignScan *
make_foreignscan(List *qptlist,
List *qpqual,
Index scanrelid,
- bool fsSystemCol,
+ List *fdw_exprs,
List *fdw_private)
{
ForeignScan *node = makeNode(ForeignScan);
Plan *plan = &node->scan.plan;
- /* cost should be inserted by caller */
+ /* cost will be filled in by create_foreignscan_plan */
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
- node->fsSystemCol = fsSystemCol;
+ node->fdw_exprs = fdw_exprs;
node->fdw_private = fdw_private;
+ /* fsSystemCol will be filled in by create_foreignscan_plan */
+ node->fsSystemCol = false;
return node;
}
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index e1b48fb4f5..69396694aa 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -428,6 +428,8 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
splan->scan.plan.qual =
fix_scan_list(root, splan->scan.plan.qual, rtoffset);
+ splan->fdw_exprs =
+ fix_scan_list(root, splan->fdw_exprs, rtoffset);
}
break;
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 40a420a354..b64db1e1c0 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2137,6 +2137,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
break;
case T_ForeignScan:
+ finalize_primnode((Node *) ((ForeignScan *) plan)->fdw_exprs,
+ &context);
context.paramids = bms_add_members(context.paramids, scan_params);
break;
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 6d1545476d..a2fc75a659 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1767,7 +1767,7 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel)
* returning the pathnode.
*
* This function is never called from core Postgres; rather, it's expected
- * to be called by the PlanForeignScan function of a foreign data wrapper.
+ * to be called by the GetForeignPaths function of a foreign data wrapper.
* We make the FDW supply all fields of the path, since we do not have any
* way to calculate them in core.
*/
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 0cdf638c1d..cee092a881 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -113,6 +113,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->allvisfrac = 0;
rel->subplan = NULL;
rel->subroot = NULL;
+ rel->fdwroutine = NULL;
+ rel->fdw_private = NULL;
rel->baserestrictinfo = NIL;
rel->baserestrictcost.startup = 0;
rel->baserestrictcost.per_tuple = 0;
@@ -366,6 +368,8 @@ build_join_rel(PlannerInfo *root,
joinrel->allvisfrac = 0;
joinrel->subplan = NULL;
joinrel->subroot = NULL;
+ joinrel->fdwroutine = NULL;
+ joinrel->fdw_private = NULL;
joinrel->baserestrictinfo = NIL;
joinrel->baserestrictcost.startup = 0;
joinrel->baserestrictcost.per_tuple = 0;