summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/explain.c4
-rw-r--r--src/backend/executor/execScan.c23
-rw-r--r--src/backend/executor/nodeCustom.c55
-rw-r--r--src/backend/executor/nodeForeignscan.c41
-rw-r--r--src/backend/executor/nodeIndexonlyscan.c6
-rw-r--r--src/backend/foreign/foreign.c42
-rw-r--r--src/backend/nodes/copyfuncs.c8
-rw-r--r--src/backend/nodes/outfuncs.c9
-rw-r--r--src/backend/optimizer/path/joinpath.c342
-rw-r--r--src/backend/optimizer/plan/createplan.c83
-rw-r--r--src/backend/optimizer/plan/setrefs.c256
-rw-r--r--src/backend/optimizer/plan/subselect.c2
-rw-r--r--src/backend/optimizer/util/plancat.c7
-rw-r--r--src/backend/optimizer/util/relnode.c27
-rw-r--r--src/backend/utils/adt/ruleutils.c19
15 files changed, 431 insertions, 493 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index c5452e3cb6a..eeb8f19017e 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -736,11 +736,11 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ForeignScan:
*rels_used = bms_add_members(*rels_used,
- ((ForeignScan *) plan)->fdw_relids);
+ ((ForeignScan *) plan)->fs_relids);
break;
case T_CustomScan:
*rels_used = bms_add_members(*rels_used,
- ((CustomScan *) plan)->custom_relids);
+ ((CustomScan *) plan)->custom_relids);
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index fa475014f13..a96e826ba42 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -246,19 +246,18 @@ void
ExecAssignScanProjectionInfo(ScanState *node)
{
Scan *scan = (Scan *) node->ps.plan;
- Index varno;
- /* Vars in an index-only scan's tlist should be INDEX_VAR */
- if (IsA(scan, IndexOnlyScan))
- varno = INDEX_VAR;
- /* Also foreign or custom scan on pseudo relation should be INDEX_VAR */
- else if (scan->scanrelid == 0)
- {
- Assert(IsA(scan, ForeignScan) || IsA(scan, CustomScan));
- varno = INDEX_VAR;
- }
- else
- varno = scan->scanrelid;
+ ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
+}
+
+/*
+ * ExecAssignScanProjectionInfoWithVarno
+ * As above, but caller can specify varno expected in Vars in the tlist.
+ */
+void
+ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
+{
+ Scan *scan = (Scan *) node->ps.plan;
if (tlist_matches_tupdesc(&node->ps,
scan->plan.targetlist,
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index db1b4f2ffa4..0a022dff940 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -22,13 +22,24 @@
CustomScanState *
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
{
- CustomScanState *css;
- Index scan_relid = cscan->scan.scanrelid;
+ CustomScanState *css;
+ Relation scan_rel = NULL;
+ Index scanrelid = cscan->scan.scanrelid;
+ Index tlistvarno;
- /* populate a CustomScanState according to the CustomScan */
+ /*
+ * Allocate the CustomScanState object. We let the custom scan provider
+ * do the palloc, in case it wants to make a larger object that embeds
+ * CustomScanState as the first field. It must set the node tag and the
+ * methods field correctly at this time. Other standard fields should be
+ * set to zero.
+ */
css = (CustomScanState *) cscan->methods->CreateCustomScanState(cscan);
Assert(IsA(css, CustomScanState));
+ /* ensure flags is filled correctly */
+ css->flags = cscan->flags;
+
/* fill up fields of ScanState */
css->ss.ps.plan = &cscan->scan.plan;
css->ss.ps.state = estate;
@@ -36,6 +47,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps);
+ css->ss.ps.ps_TupFromTlist = false;
+
/* initialize child expressions */
css->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
@@ -49,32 +62,40 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
ExecInitResultTupleSlot(estate, &css->ss.ps);
/*
- * open the base relation and acquire an appropriate lock on it;
- * also, get and assign the scan type
+ * open the base relation, if any, and acquire an appropriate lock on it
*/
- if (scan_relid > 0)
+ if (scanrelid > 0)
{
- Relation scan_rel;
-
- scan_rel = ExecOpenScanRelation(estate, scan_relid, eflags);
+ scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags);
css->ss.ss_currentRelation = scan_rel;
- css->ss.ss_currentScanDesc = NULL; /* set by provider */
- ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
}
- else
+
+ /*
+ * Determine the scan tuple type. If the custom scan provider provided a
+ * targetlist describing the scan tuples, use that; else use base
+ * relation's rowtype.
+ */
+ if (cscan->custom_scan_tlist != NIL || scan_rel == NULL)
{
- TupleDesc ps_tupdesc;
+ TupleDesc scan_tupdesc;
- ps_tupdesc = ExecCleanTypeFromTL(cscan->custom_ps_tlist, false);
- ExecAssignScanType(&css->ss, ps_tupdesc);
+ scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false);
+ ExecAssignScanType(&css->ss, scan_tupdesc);
+ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
+ tlistvarno = INDEX_VAR;
+ }
+ else
+ {
+ ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
+ /* Node's targetlist will contain Vars with varno = scanrelid */
+ tlistvarno = scanrelid;
}
- css->ss.ps.ps_TupFromTlist = false;
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&css->ss.ps);
- ExecAssignScanProjectionInfo(&css->ss);
+ ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
/*
* The callback of custom-scan provider applies the final initialization
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index fa553ace5d6..bb28a7372d1 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -102,7 +102,9 @@ ForeignScanState *
ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
{
ForeignScanState *scanstate;
+ Relation currentRelation = NULL;
Index scanrelid = node->scan.scanrelid;
+ Index tlistvarno;
FdwRoutine *fdwroutine;
/* check for unsupported flags */
@@ -141,40 +143,55 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
ExecInitScanTupleSlot(estate, &scanstate->ss);
/*
- * open the base relation and acquire an appropriate lock on it;
- * also, get and assign the scan type
+ * open the base relation, if any, and acquire an appropriate lock on it;
+ * also acquire function pointers from the FDW's handler
*/
if (scanrelid > 0)
{
- Relation currentRelation;
-
currentRelation = ExecOpenScanRelation(estate, scanrelid, eflags);
scanstate->ss.ss_currentRelation = currentRelation;
- ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
+ fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
}
else
{
- TupleDesc ps_tupdesc;
+ /* We can't use the relcache, so get fdwroutine the hard way */
+ fdwroutine = GetFdwRoutineByServerId(node->fs_server);
+ }
- ps_tupdesc = ExecCleanTypeFromTL(node->fdw_ps_tlist, false);
- ExecAssignScanType(&scanstate->ss, ps_tupdesc);
+ /*
+ * Determine the scan tuple type. If the FDW provided a targetlist
+ * describing the scan tuples, use that; else use base relation's rowtype.
+ */
+ if (node->fdw_scan_tlist != NIL || currentRelation == NULL)
+ {
+ TupleDesc scan_tupdesc;
+
+ scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false);
+ ExecAssignScanType(&scanstate->ss, scan_tupdesc);
+ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
+ tlistvarno = INDEX_VAR;
+ }
+ else
+ {
+ ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
+ /* Node's targetlist will contain Vars with varno = scanrelid */
+ tlistvarno = scanrelid;
}
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
- ExecAssignScanProjectionInfo(&scanstate->ss);
+ ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno);
/*
- * Acquire function pointers from the FDW's handler, and init fdw_state.
+ * Initialize FDW-related state.
*/
- fdwroutine = GetFdwRoutine(node->fdw_handler);
scanstate->fdwroutine = fdwroutine;
scanstate->fdw_state = NULL;
/*
- * Tell the FDW to initiate the scan.
+ * Tell the FDW to initialize the scan.
*/
fdwroutine->BeginForeignScan(scanstate, eflags);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 06b7c3c457a..61bd644ab71 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -442,10 +442,12 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
ExecAssignScanType(&indexstate->ss, tupDesc);
/*
- * Initialize result tuple type and projection info.
+ * Initialize result tuple type and projection info. The node's
+ * targetlist will contain Vars with varno = INDEX_VAR, referencing the
+ * scan tuple.
*/
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
- ExecAssignScanProjectionInfo(&indexstate->ss);
+ ExecAssignScanProjectionInfoWithVarno(&indexstate->ss, INDEX_VAR);
/*
* If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index cdbd550fd43..763ee7c9bce 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -304,21 +304,16 @@ GetFdwRoutine(Oid fdwhandler)
/*
- * GetFdwHandlerByRelId - look up the handler of the foreign-data wrapper
- * for the given foreign table
+ * GetForeignServerIdByRelId - look up the foreign server
+ * for the given foreign table, and return its OID.
*/
Oid
-GetFdwHandlerByRelId(Oid relid)
+GetForeignServerIdByRelId(Oid relid)
{
HeapTuple tp;
- Form_pg_foreign_data_wrapper fdwform;
- Form_pg_foreign_server serverform;
Form_pg_foreign_table tableform;
Oid serverid;
- Oid fdwid;
- Oid fdwhandler;
- /* Get server OID for the foreign table. */
tp = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign table %u", relid);
@@ -326,6 +321,23 @@ GetFdwHandlerByRelId(Oid relid)
serverid = tableform->ftserver;
ReleaseSysCache(tp);
+ return serverid;
+}
+
+
+/*
+ * GetFdwRoutineByServerId - look up the handler of the foreign-data wrapper
+ * for the given foreign server, and retrieve its FdwRoutine struct.
+ */
+FdwRoutine *
+GetFdwRoutineByServerId(Oid serverid)
+{
+ HeapTuple tp;
+ Form_pg_foreign_data_wrapper fdwform;
+ Form_pg_foreign_server serverform;
+ Oid fdwid;
+ Oid fdwhandler;
+
/* Get foreign-data wrapper OID for the server. */
tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid));
if (!HeapTupleIsValid(tp))
@@ -350,9 +362,11 @@ GetFdwHandlerByRelId(Oid relid)
ReleaseSysCache(tp);
- return fdwhandler;
+ /* And finally, call the handler function. */
+ return GetFdwRoutine(fdwhandler);
}
+
/*
* GetFdwRoutineByRelId - look up the handler of the foreign-data wrapper
* for the given foreign table, and retrieve its FdwRoutine struct.
@@ -360,9 +374,13 @@ GetFdwHandlerByRelId(Oid relid)
FdwRoutine *
GetFdwRoutineByRelId(Oid relid)
{
- Oid fdwhandler = GetFdwHandlerByRelId(relid);
+ Oid serverid;
- return GetFdwRoutine(fdwhandler);
+ /* Get server OID for the foreign table. */
+ serverid = GetForeignServerIdByRelId(relid);
+
+ /* Now retrieve server's FdwRoutine struct. */
+ return GetFdwRoutineByServerId(serverid);
}
/*
@@ -656,7 +674,7 @@ get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
/*
- * get_foreign_server_oid - given a FDW name, look up the OID
+ * get_foreign_server_oid - given a server name, look up the OID
*
* If missing_ok is false, throw an error if name not found. If true, just
* return InvalidOid.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a3139d3eb5d..ed8fa72621e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -599,11 +599,11 @@ _copyForeignScan(const ForeignScan *from)
/*
* copy remainder of node
*/
- COPY_SCALAR_FIELD(fdw_handler);
+ COPY_SCALAR_FIELD(fs_server);
COPY_NODE_FIELD(fdw_exprs);
- COPY_NODE_FIELD(fdw_ps_tlist);
COPY_NODE_FIELD(fdw_private);
- COPY_BITMAPSET_FIELD(fdw_relids);
+ COPY_NODE_FIELD(fdw_scan_tlist);
+ COPY_BITMAPSET_FIELD(fs_relids);
COPY_SCALAR_FIELD(fsSystemCol);
return newnode;
@@ -627,8 +627,8 @@ _copyCustomScan(const CustomScan *from)
*/
COPY_SCALAR_FIELD(flags);
COPY_NODE_FIELD(custom_exprs);
- COPY_NODE_FIELD(custom_ps_tlist);
COPY_NODE_FIELD(custom_private);
+ COPY_NODE_FIELD(custom_scan_tlist);
COPY_BITMAPSET_FIELD(custom_relids);
/*
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index bc891d391f5..fe868b889d9 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -565,11 +565,11 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
_outScanInfo(str, (const Scan *) node);
- WRITE_OID_FIELD(fdw_handler);
+ WRITE_OID_FIELD(fs_server);
WRITE_NODE_FIELD(fdw_exprs);
- WRITE_NODE_FIELD(fdw_ps_tlist);
WRITE_NODE_FIELD(fdw_private);
- WRITE_BITMAPSET_FIELD(fdw_relids);
+ WRITE_NODE_FIELD(fdw_scan_tlist);
+ WRITE_BITMAPSET_FIELD(fs_relids);
WRITE_BOOL_FIELD(fsSystemCol);
}
@@ -582,8 +582,8 @@ _outCustomScan(StringInfo str, const CustomScan *node)
WRITE_UINT_FIELD(flags);
WRITE_NODE_FIELD(custom_exprs);
- WRITE_NODE_FIELD(custom_ps_tlist);
WRITE_NODE_FIELD(custom_private);
+ WRITE_NODE_FIELD(custom_scan_tlist);
WRITE_BITMAPSET_FIELD(custom_relids);
appendStringInfoString(str, " :methods ");
_outToken(str, node->methods->CustomName);
@@ -1844,6 +1844,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
WRITE_NODE_FIELD(subplan);
WRITE_NODE_FIELD(subroot);
WRITE_NODE_FIELD(subplan_params);
+ WRITE_OID_FIELD(serverid);
/* we don't try to print fdwroutine or fdw_private */
WRITE_NODE_FIELD(baserestrictinfo);
WRITE_NODE_FIELD(joininfo);
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index dabef3c3c7f..ba78252b8f9 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -30,21 +30,13 @@ set_join_pathlist_hook_type set_join_pathlist_hook = NULL;
static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
- List *restrictlist, List *mergeclause_list,
- JoinType jointype, SpecialJoinInfo *sjinfo,
- Relids param_source_rels, Relids extra_lateral_rels);
+ JoinType jointype, JoinPathExtraData *extra);
static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
- List *restrictlist, List *mergeclause_list,
- JoinType jointype, SpecialJoinInfo *sjinfo,
- SemiAntiJoinFactors *semifactors,
- Relids param_source_rels, Relids extra_lateral_rels);
+ JoinType jointype, JoinPathExtraData *extra);
static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
- List *restrictlist,
- JoinType jointype, SpecialJoinInfo *sjinfo,
- SemiAntiJoinFactors *semifactors,
- Relids param_source_rels, Relids extra_lateral_rels);
+ JoinType jointype, JoinPathExtraData *extra);
static List *select_mergejoin_clauses(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
@@ -86,13 +78,16 @@ add_paths_to_joinrel(PlannerInfo *root,
SpecialJoinInfo *sjinfo,
List *restrictlist)
{
- List *mergeclause_list = NIL;
+ JoinPathExtraData extra;
bool mergejoin_allowed = true;
- SemiAntiJoinFactors semifactors;
- Relids param_source_rels = NULL;
- Relids extra_lateral_rels = NULL;
ListCell *lc;
+ extra.restrictlist = restrictlist;
+ extra.mergeclause_list = NIL;
+ extra.sjinfo = sjinfo;
+ extra.param_source_rels = NULL;
+ extra.extra_lateral_rels = NULL;
+
/*
* Find potential mergejoin clauses. We can skip this if we are not
* interested in doing a mergejoin. However, mergejoin may be our only
@@ -100,13 +95,13 @@ add_paths_to_joinrel(PlannerInfo *root,
* it's a full join.
*/
if (enable_mergejoin || jointype == JOIN_FULL)
- mergeclause_list = select_mergejoin_clauses(root,
- joinrel,
- outerrel,
- innerrel,
- restrictlist,
- jointype,
- &mergejoin_allowed);
+ extra.mergeclause_list = select_mergejoin_clauses(root,
+ joinrel,
+ outerrel,
+ innerrel,
+ restrictlist,
+ jointype,
+ &mergejoin_allowed);
/*
* If it's SEMI or ANTI join, compute correction factors for cost
@@ -115,7 +110,7 @@ add_paths_to_joinrel(PlannerInfo *root,
if (jointype == JOIN_SEMI || jointype == JOIN_ANTI)
compute_semi_anti_join_factors(root, outerrel, innerrel,
jointype, sjinfo, restrictlist,
- &semifactors);
+ &extra.semifactors);
/*
* Decide whether it's sensible to generate parameterized paths for this
@@ -142,16 +137,16 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (bms_overlap(joinrel->relids, sjinfo->min_righthand) &&
!bms_overlap(joinrel->relids, sjinfo->min_lefthand))
- param_source_rels = bms_join(param_source_rels,
- bms_difference(root->all_baserels,
+ extra.param_source_rels = bms_join(extra.param_source_rels,
+ bms_difference(root->all_baserels,
sjinfo->min_righthand));
/* full joins constrain both sides symmetrically */
if (sjinfo->jointype == JOIN_FULL &&
bms_overlap(joinrel->relids, sjinfo->min_lefthand) &&
!bms_overlap(joinrel->relids, sjinfo->min_righthand))
- param_source_rels = bms_join(param_source_rels,
- bms_difference(root->all_baserels,
+ extra.param_source_rels = bms_join(extra.param_source_rels,
+ bms_difference(root->all_baserels,
sjinfo->min_lefthand));
}
@@ -168,9 +163,9 @@ add_paths_to_joinrel(PlannerInfo *root,
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc);
if (bms_is_subset(ljinfo->lateral_rhs, joinrel->relids))
- param_source_rels = bms_join(param_source_rels,
- bms_difference(ljinfo->lateral_lhs,
- joinrel->relids));
+ extra.param_source_rels = bms_join(extra.param_source_rels,
+ bms_difference(ljinfo->lateral_lhs,
+ joinrel->relids));
}
/*
@@ -195,8 +190,8 @@ add_paths_to_joinrel(PlannerInfo *root,
!bms_is_subset(phinfo->ph_eval_at, innerrel->relids))
{
/* Yes, remember its lateral rels */
- extra_lateral_rels = bms_add_members(extra_lateral_rels,
- phinfo->ph_lateral);
+ extra.extra_lateral_rels = bms_add_members(extra.extra_lateral_rels,
+ phinfo->ph_lateral);
}
}
@@ -206,9 +201,10 @@ add_paths_to_joinrel(PlannerInfo *root,
* it to required_outer below, while preserving the property that
* required_outer is exactly NULL if empty.)
*/
- extra_lateral_rels = bms_del_members(extra_lateral_rels, joinrel->relids);
- if (bms_is_empty(extra_lateral_rels))
- extra_lateral_rels = NULL;
+ extra.extra_lateral_rels = bms_del_members(extra.extra_lateral_rels,
+ joinrel->relids);
+ if (bms_is_empty(extra.extra_lateral_rels))
+ extra.extra_lateral_rels = NULL;
/*
* 1. Consider mergejoin paths where both relations must be explicitly
@@ -216,9 +212,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (mergejoin_allowed)
sort_inner_and_outer(root, joinrel, outerrel, innerrel,
- restrictlist, mergeclause_list, jointype,
- sjinfo,
- param_source_rels, extra_lateral_rels);
+ jointype, &extra);
/*
* 2. Consider paths where the outer relation need not be explicitly
@@ -229,9 +223,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (mergejoin_allowed)
match_unsorted_outer(root, joinrel, outerrel, innerrel,
- restrictlist, mergeclause_list, jointype,
- sjinfo, &semifactors,
- param_source_rels, extra_lateral_rels);
+ jointype, &extra);
#ifdef NOT_USED
@@ -248,9 +240,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (mergejoin_allowed)
match_unsorted_inner(root, joinrel, outerrel, innerrel,
- restrictlist, mergeclause_list, jointype,
- sjinfo, &semifactors,
- param_source_rels, extra_lateral_rels);
+ jointype, &extra);
#endif
/*
@@ -260,30 +250,24 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (enable_hashjoin || jointype == JOIN_FULL)
hash_inner_and_outer(root, joinrel, outerrel, innerrel,
- restrictlist, jointype,
- sjinfo, &semifactors,
- param_source_rels, extra_lateral_rels);
+ jointype, &extra);
/*
- * 5. If both inner and outer relations are managed by the same FDW,
- * give it a chance to push down joins.
+ * 5. If inner and outer relations are foreign tables (or joins) belonging
+ * to the same server, give the FDW a chance to push down joins.
*/
if (joinrel->fdwroutine &&
joinrel->fdwroutine->GetForeignJoinPaths)
joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
outerrel, innerrel,
- restrictlist, jointype, sjinfo,
- &semifactors,
- param_source_rels,
- extra_lateral_rels);
+ jointype, &extra);
+
/*
* 6. Finally, give extensions a chance to manipulate the path list.
*/
if (set_join_pathlist_hook)
set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
- restrictlist, jointype,
- sjinfo, &semifactors,
- param_source_rels, extra_lateral_rels);
+ jointype, &extra);
}
/*
@@ -294,15 +278,11 @@ add_paths_to_joinrel(PlannerInfo *root,
static void
try_nestloop_path(PlannerInfo *root,
RelOptInfo *joinrel,
- JoinType jointype,
- SpecialJoinInfo *sjinfo,
- SemiAntiJoinFactors *semifactors,
- Relids param_source_rels,
- Relids extra_lateral_rels,
Path *outer_path,
Path *inner_path,
- List *restrict_clauses,
- List *pathkeys)
+ List *pathkeys,
+ JoinType jointype,
+ JoinPathExtraData *extra)
{
Relids required_outer;
JoinCostWorkspace workspace;
@@ -314,7 +294,7 @@ try_nestloop_path(PlannerInfo *root,
required_outer = calc_nestloop_required_outer(outer_path,
inner_path);
if (required_outer &&
- !bms_overlap(required_outer, param_source_rels))
+ !bms_overlap(required_outer, extra->param_source_rels))
{
/*
* We override the param_source_rels heuristic to accept nestloop
@@ -345,7 +325,7 @@ try_nestloop_path(PlannerInfo *root,
* Independently of that, add parameterization needed for any
* PlaceHolderVars that need to be computed at the join.
*/
- required_outer = bms_add_members(required_outer, extra_lateral_rels);
+ required_outer = bms_add_members(required_outer, extra->extra_lateral_rels);
/*
* Do a precheck to quickly eliminate obviously-inferior paths. We
@@ -358,7 +338,7 @@ try_nestloop_path(PlannerInfo *root,
*/
initial_cost_nestloop(root, &workspace, jointype,
outer_path, inner_path,
- sjinfo, semifactors);
+ extra->sjinfo, &extra->semifactors);
if (add_path_precheck(joinrel,
workspace.startup_cost, workspace.total_cost,
@@ -369,11 +349,11 @@ try_nestloop_path(PlannerInfo *root,
joinrel,
jointype,
&workspace,
- sjinfo,
- semifactors,
+ extra->sjinfo,
+ &extra->semifactors,
outer_path,
inner_path,
- restrict_clauses,
+ extra->restrictlist,
pathkeys,
required_outer));
}
@@ -392,17 +372,14 @@ try_nestloop_path(PlannerInfo *root,
static void
try_mergejoin_path(PlannerInfo *root,
RelOptInfo *joinrel,
- JoinType jointype,
- SpecialJoinInfo *sjinfo,
- Relids param_source_rels,
- Relids extra_lateral_rels,
Path *outer_path,
Path *inner_path,
- List *restrict_clauses,
List *pathkeys,
List *mergeclauses,
List *outersortkeys,
- List *innersortkeys)
+ List *innersortkeys,
+ JoinType jointype,
+ JoinPathExtraData *extra)
{
Relids required_outer;
JoinCostWorkspace workspace;
@@ -414,7 +391,7 @@ try_mergejoin_path(PlannerInfo *root,
required_outer = calc_non_nestloop_required_outer(outer_path,
inner_path);
if (required_outer &&
- !bms_overlap(required_outer, param_source_rels))
+ !bms_overlap(required_outer, extra->param_source_rels))
{
/* Waste no memory when we reject a path here */
bms_free(required_outer);
@@ -425,7 +402,7 @@ try_mergejoin_path(PlannerInfo *root,
* Independently of that, add parameterization needed for any
* PlaceHolderVars that need to be computed at the join.
*/
- required_outer = bms_add_members(required_outer, extra_lateral_rels);
+ required_outer = bms_add_members(required_outer, extra->extra_lateral_rels);
/*
* If the given paths are already well enough ordered, we can skip doing
@@ -444,7 +421,7 @@ try_mergejoin_path(PlannerInfo *root,
initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
outer_path, inner_path,
outersortkeys, innersortkeys,
- sjinfo);
+ extra->sjinfo);
if (add_path_precheck(joinrel,
workspace.startup_cost, workspace.total_cost,
@@ -455,10 +432,10 @@ try_mergejoin_path(PlannerInfo *root,
joinrel,
jointype,
&workspace,
- sjinfo,
+ extra->sjinfo,
outer_path,
inner_path,
- restrict_clauses,
+ extra->restrictlist,
pathkeys,
required_outer,
mergeclauses,
@@ -480,15 +457,11 @@ try_mergejoin_path(PlannerInfo *root,
static void
try_hashjoin_path(PlannerInfo *root,
RelOptInfo *joinrel,
- JoinType jointype,
- SpecialJoinInfo *sjinfo,
- SemiAntiJoinFactors *semifactors,
- Relids param_source_rels,
- Relids extra_lateral_rels,
Path *outer_path,
Path *inner_path,
- List *restrict_clauses,
- List *hashclauses)
+ List *hashclauses,
+ JoinType jointype,
+ JoinPathExtraData *extra)
{
Relids required_outer;
JoinCostWorkspace workspace;
@@ -500,7 +473,7 @@ try_hashjoin_path(PlannerInfo *root,
required_outer = calc_non_nestloop_required_outer(outer_path,
inner_path);
if (required_outer &&
- !bms_overlap(required_outer, param_source_rels))
+ !bms_overlap(required_outer, extra->param_source_rels))
{
/* Waste no memory when we reject a path here */
bms_free(required_outer);
@@ -511,7 +484,7 @@ try_hashjoin_path(PlannerInfo *root,
* Independently of that, add parameterization needed for any
* PlaceHolderVars that need to be computed at the join.
*/
- required_outer = bms_add_members(required_outer, extra_lateral_rels);
+ required_outer = bms_add_members(required_outer, extra->extra_lateral_rels);
/*
* See comments in try_nestloop_path(). Also note that hashjoin paths
@@ -519,7 +492,7 @@ try_hashjoin_path(PlannerInfo *root,
*/
initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
outer_path, inner_path,
- sjinfo, semifactors);
+ extra->sjinfo, &extra->semifactors);
if (add_path_precheck(joinrel,
workspace.startup_cost, workspace.total_cost,
@@ -530,11 +503,11 @@ try_hashjoin_path(PlannerInfo *root,
joinrel,
jointype,
&workspace,
- sjinfo,
- semifactors,
+ extra->sjinfo,
+ &extra->semifactors,
outer_path,
inner_path,
- restrict_clauses,
+ extra->restrictlist,
required_outer,
hashclauses));
}
@@ -584,26 +557,16 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel,
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
- * 'restrictlist' contains all of the RestrictInfo nodes for restriction
- * clauses that apply to this join
- * 'mergeclause_list' is a list of RestrictInfo nodes for available
- * mergejoin clauses in this join
* 'jointype' is the type of join to do
- * 'sjinfo' is extra info about the join for selectivity estimation
- * 'param_source_rels' are OK targets for parameterization of result paths
- * 'extra_lateral_rels' are additional parameterization for result paths
+ * 'extra' contains additional input values
*/
static void
sort_inner_and_outer(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
- List *restrictlist,
- List *mergeclause_list,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- Relids param_source_rels,
- Relids extra_lateral_rels)
+ JoinPathExtraData *extra)
{
Path *outer_path;
Path *inner_path;
@@ -643,14 +606,14 @@ sort_inner_and_outer(PlannerInfo *root,
if (jointype == JOIN_UNIQUE_OUTER)
{
outer_path = (Path *) create_unique_path(root, outerrel,
- outer_path, sjinfo);
+ outer_path, extra->sjinfo);
Assert(outer_path);
jointype = JOIN_INNER;
}
else if (jointype == JOIN_UNIQUE_INNER)
{
inner_path = (Path *) create_unique_path(root, innerrel,
- inner_path, sjinfo);
+ inner_path, extra->sjinfo);
Assert(inner_path);
jointype = JOIN_INNER;
}
@@ -684,7 +647,7 @@ sort_inner_and_outer(PlannerInfo *root,
* exactly as-is as well as making variants.
*/
all_pathkeys = select_outer_pathkeys_for_merge(root,
- mergeclause_list,
+ extra->mergeclause_list,
joinrel);
foreach(l, all_pathkeys)
@@ -707,10 +670,10 @@ sort_inner_and_outer(PlannerInfo *root,
cur_mergeclauses = find_mergeclauses_for_pathkeys(root,
outerkeys,
true,
- mergeclause_list);
+ extra->mergeclause_list);
/* Should have used them all... */
- Assert(list_length(cur_mergeclauses) == list_length(mergeclause_list));
+ Assert(list_length(cur_mergeclauses) == list_length(extra->mergeclause_list));
/* Build sort pathkeys for the inner side */
innerkeys = make_inner_pathkeys_for_merge(root,
@@ -730,17 +693,14 @@ sort_inner_and_outer(PlannerInfo *root,
*/
try_mergejoin_path(root,
joinrel,
- jointype,
- sjinfo,
- param_source_rels,
- extra_lateral_rels,
outer_path,
inner_path,
- restrictlist,
merge_pathkeys,
cur_mergeclauses,
outerkeys,
- innerkeys);
+ innerkeys,
+ jointype,
+ extra);
}
}
@@ -771,28 +731,16 @@ sort_inner_and_outer(PlannerInfo *root,
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
- * 'restrictlist' contains all of the RestrictInfo nodes for restriction
- * clauses that apply to this join
- * 'mergeclause_list' is a list of RestrictInfo nodes for available
- * mergejoin clauses in this join
* 'jointype' is the type of join to do
- * 'sjinfo' is extra info about the join for selectivity estimation
- * 'semifactors' contains valid data if jointype is SEMI or ANTI
- * 'param_source_rels' are OK targets for parameterization of result paths
- * 'extra_lateral_rels' are additional parameterization for result paths
+ * 'extra' contains additional input values
*/
static void
match_unsorted_outer(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
- List *restrictlist,
- List *mergeclause_list,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- SemiAntiJoinFactors *semifactors,
- Relids param_source_rels,
- Relids extra_lateral_rels)
+ JoinPathExtraData *extra)
{
JoinType save_jointype = jointype;
bool nestjoinOK;
@@ -854,7 +802,7 @@ match_unsorted_outer(PlannerInfo *root,
if (inner_cheapest_total == NULL)
return;
inner_cheapest_total = (Path *)
- create_unique_path(root, innerrel, inner_cheapest_total, sjinfo);
+ create_unique_path(root, innerrel, inner_cheapest_total, extra->sjinfo);
Assert(inner_cheapest_total);
}
else if (nestjoinOK)
@@ -898,7 +846,7 @@ match_unsorted_outer(PlannerInfo *root,
if (outerpath != outerrel->cheapest_total_path)
continue;
outerpath = (Path *) create_unique_path(root, outerrel,
- outerpath, sjinfo);
+ outerpath, extra->sjinfo);
Assert(outerpath);
}
@@ -918,15 +866,11 @@ match_unsorted_outer(PlannerInfo *root,
*/
try_nestloop_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
outerpath,
inner_cheapest_total,
- restrictlist,
- merge_pathkeys);
+ merge_pathkeys,
+ jointype,
+ extra);
}
else if (nestjoinOK)
{
@@ -944,30 +888,22 @@ match_unsorted_outer(PlannerInfo *root,
try_nestloop_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
outerpath,
innerpath,
- restrictlist,
- merge_pathkeys);
+ merge_pathkeys,
+ jointype,
+ extra);
}
/* Also consider materialized form of the cheapest inner path */
if (matpath != NULL)
try_nestloop_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
outerpath,
matpath,
- restrictlist,
- merge_pathkeys);
+ merge_pathkeys,
+ jointype,
+ extra);
}
/* Can't do anything else if outer path needs to be unique'd */
@@ -982,7 +918,7 @@ match_unsorted_outer(PlannerInfo *root,
mergeclauses = find_mergeclauses_for_pathkeys(root,
outerpath->pathkeys,
true,
- mergeclause_list);
+ extra->mergeclause_list);
/*
* Done with this outer path if no chance for a mergejoin.
@@ -1000,7 +936,7 @@ match_unsorted_outer(PlannerInfo *root,
else
continue;
}
- if (useallclauses && list_length(mergeclauses) != list_length(mergeclause_list))
+ if (useallclauses && list_length(mergeclauses) != list_length(extra->mergeclause_list))
continue;
/* Compute the required ordering of the inner path */
@@ -1016,17 +952,14 @@ match_unsorted_outer(PlannerInfo *root,
*/
try_mergejoin_path(root,
joinrel,
- jointype,
- sjinfo,
- param_source_rels,
- extra_lateral_rels,
outerpath,
inner_cheapest_total,
- restrictlist,
merge_pathkeys,
mergeclauses,
NIL,
- innersortkeys);
+ innersortkeys,
+ jointype,
+ extra);
/* Can't do anything else if inner path needs to be unique'd */
if (save_jointype == JOIN_UNIQUE_INNER)
@@ -1115,17 +1048,14 @@ match_unsorted_outer(PlannerInfo *root,
newclauses = mergeclauses;
try_mergejoin_path(root,
joinrel,
- jointype,
- sjinfo,
- param_source_rels,
- extra_lateral_rels,
outerpath,
innerpath,
- restrictlist,
merge_pathkeys,
newclauses,
NIL,
- NIL);
+ NIL,
+ jointype,
+ extra);
cheapest_total_inner = innerpath;
}
/* Same on the basis of cheapest startup cost ... */
@@ -1161,17 +1091,14 @@ match_unsorted_outer(PlannerInfo *root,
}
try_mergejoin_path(root,
joinrel,
- jointype,
- sjinfo,
- param_source_rels,
- extra_lateral_rels,
outerpath,
innerpath,
- restrictlist,
merge_pathkeys,
newclauses,
NIL,
- NIL);
+ NIL,
+ jointype,
+ extra);
}
cheapest_startup_inner = innerpath;
}
@@ -1193,25 +1120,16 @@ match_unsorted_outer(PlannerInfo *root,
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
- * 'restrictlist' contains all of the RestrictInfo nodes for restriction
- * clauses that apply to this join
* 'jointype' is the type of join to do
- * 'sjinfo' is extra info about the join for selectivity estimation
- * 'semifactors' contains valid data if jointype is SEMI or ANTI
- * 'param_source_rels' are OK targets for parameterization of result paths
- * 'extra_lateral_rels' are additional parameterization for result paths
+ * 'extra' contains additional input values
*/
static void
hash_inner_and_outer(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
- List *restrictlist,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- SemiAntiJoinFactors *semifactors,
- Relids param_source_rels,
- Relids extra_lateral_rels)
+ JoinPathExtraData *extra)
{
bool isouterjoin = IS_OUTER_JOIN(jointype);
List *hashclauses;
@@ -1225,7 +1143,7 @@ hash_inner_and_outer(PlannerInfo *root,
* usable with this pair of sub-relations.
*/
hashclauses = NIL;
- foreach(l, restrictlist)
+ foreach(l, extra->restrictlist)
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
@@ -1276,53 +1194,41 @@ hash_inner_and_outer(PlannerInfo *root,
{
cheapest_total_outer = (Path *)
create_unique_path(root, outerrel,
- cheapest_total_outer, sjinfo);
+ cheapest_total_outer, extra->sjinfo);
Assert(cheapest_total_outer);
jointype = JOIN_INNER;
try_hashjoin_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
cheapest_total_outer,
cheapest_total_inner,
- restrictlist,
- hashclauses);
+ hashclauses,
+ jointype,
+ extra);
/* no possibility of cheap startup here */
}
else if (jointype == JOIN_UNIQUE_INNER)
{
cheapest_total_inner = (Path *)
create_unique_path(root, innerrel,
- cheapest_total_inner, sjinfo);
+ cheapest_total_inner, extra->sjinfo);
Assert(cheapest_total_inner);
jointype = JOIN_INNER;
try_hashjoin_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
cheapest_total_outer,
cheapest_total_inner,
- restrictlist,
- hashclauses);
+ hashclauses,
+ jointype,
+ extra);
if (cheapest_startup_outer != NULL &&
cheapest_startup_outer != cheapest_total_outer)
try_hashjoin_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
cheapest_startup_outer,
cheapest_total_inner,
- restrictlist,
- hashclauses);
+ hashclauses,
+ jointype,
+ extra);
}
else
{
@@ -1339,15 +1245,11 @@ hash_inner_and_outer(PlannerInfo *root,
if (cheapest_startup_outer != NULL)
try_hashjoin_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
cheapest_startup_outer,
cheapest_total_inner,
- restrictlist,
- hashclauses);
+ hashclauses,
+ jointype,
+ extra);
foreach(lc1, outerrel->cheapest_parameterized_paths)
{
@@ -1377,15 +1279,11 @@ hash_inner_and_outer(PlannerInfo *root,
try_hashjoin_path(root,
joinrel,
- jointype,
- sjinfo,
- semifactors,
- param_source_rels,
- extra_lateral_rels,
outerpath,
innerpath,
- restrictlist,
- hashclauses);
+ hashclauses,
+ jointype,
+ extra);
}
}
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 3246332d6e3..c8092372831 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -44,6 +44,7 @@
#include "utils/lsyscache.h"
+static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path);
static Plan *create_scan_plan(PlannerInfo *root, Path *best_path);
static List *build_path_tlist(PlannerInfo *root, Path *path);
static bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
@@ -219,7 +220,7 @@ create_plan(PlannerInfo *root, Path *best_path)
* create_plan_recurse
* Recursive guts of create_plan().
*/
-Plan *
+static Plan *
create_plan_recurse(PlannerInfo *root, Path *best_path)
{
Plan *plan;
@@ -1950,7 +1951,7 @@ create_worktablescan_plan(PlannerInfo *root, Path *best_path,
/*
* create_foreignscan_plan
- * Returns a foreignscan plan for the base relation scanned by 'best_path'
+ * Returns a foreignscan plan for the relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static ForeignScan *
@@ -1965,9 +1966,11 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
ListCell *lc;
int i;
+ Assert(rel->fdwroutine != NULL);
+
/*
- * If we're scanning a base relation, look up the OID.
- * (We can skip this if scanning a join relation.)
+ * If we're scanning a base relation, fetch its OID. (Irrelevant if
+ * scanning a join relation.)
*/
if (scan_relid > 0)
{
@@ -1978,7 +1981,6 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
Assert(rte->rtekind == RTE_RELATION);
rel_oid = rte->relid;
}
- Assert(rel->fdwroutine != NULL);
/*
* Sort clauses into best execution order. We do this first since the FDW
@@ -1996,42 +1998,22 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
scan_plan = rel->fdwroutine->GetForeignPlan(root, rel, rel_oid,
best_path,
tlist, scan_clauses);
- /*
- * Sanity check. There may be resjunk entries in fdw_ps_tlist that
- * are included only to help EXPLAIN deparse plans properly. We require
- * that these are at the end, so that when the executor builds the scan
- * descriptor based on the non-junk entries, it gets the attribute
- * numbers correct.
- */
- if (scan_plan->scan.scanrelid == 0)
- {
- bool found_resjunk = false;
-
- foreach (lc, scan_plan->fdw_ps_tlist)
- {
- TargetEntry *tle = lfirst(lc);
-
- if (tle->resjunk)
- found_resjunk = true;
- else if (found_resjunk)
- elog(ERROR, "junk TLE should not apper prior to valid one");
- }
- }
- /* Set the relids that are represented by this foreign scan for Explain */
- scan_plan->fdw_relids = best_path->path.parent->relids;
/* Copy cost data from Path to Plan; no need to make FDW do this */
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
- /* Track FDW server-id; no need to make FDW do this */
- scan_plan->fdw_handler = rel->fdw_handler;
+ /* Copy foreign server OID; likewise, no need to make FDW do this */
+ scan_plan->fs_server = rel->serverid;
+
+ /* Likewise, copy the relids that are represented by this foreign scan */
+ scan_plan->fs_relids = best_path->path.parent->relids;
/*
* 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.)
+ * wouldn't work.) We assume fdw_scan_tlist contains no such variables.
*/
if (best_path->path.param_info)
{
@@ -2087,7 +2069,6 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
{
CustomScan *cplan;
RelOptInfo *rel = best_path->path.parent;
- ListCell *lc;
/*
* Sort clauses into the best execution order, although custom-scan
@@ -2107,41 +2088,21 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
Assert(IsA(cplan, CustomScan));
/*
- * Sanity check. There may be resjunk entries in custom_ps_tlist that
- * are included only to help EXPLAIN deparse plans properly. We require
- * that these are at the end, so that when the executor builds the scan
- * descriptor based on the non-junk entries, it gets the attribute
- * numbers correct.
- */
- if (cplan->scan.scanrelid == 0)
- {
- bool found_resjunk = false;
-
- foreach (lc, cplan->custom_ps_tlist)
- {
- TargetEntry *tle = lfirst(lc);
-
- if (tle->resjunk)
- found_resjunk = true;
- else if (found_resjunk)
- elog(ERROR, "junk TLE should not apper prior to valid one");
- }
- }
- /* Set the relids that are represented by this custom scan for Explain */
- cplan->custom_relids = best_path->path.parent->relids;
-
- /*
* Copy cost data from Path to Plan; no need to make custom-plan providers
* do this
*/
copy_path_costsize(&cplan->scan.plan, &best_path->path);
+ /* Likewise, copy the relids that are represented by this custom scan */
+ cplan->custom_relids = best_path->path.parent->relids;
+
/*
* Replace any outer-relation variables with nestloop params in the qual
* and custom_exprs expressions. We do this last so that the custom-plan
* provider doesn't have to be involved. (Note that parts of custom_exprs
* could have come from join clauses, so doing this beforehand on the
- * scan_clauses wouldn't work.)
+ * scan_clauses wouldn't work.) We assume custom_scan_tlist contains no
+ * such variables.
*/
if (best_path->path.param_info)
{
@@ -3611,7 +3572,8 @@ make_foreignscan(List *qptlist,
List *qpqual,
Index scanrelid,
List *fdw_exprs,
- List *fdw_private)
+ List *fdw_private,
+ List *fdw_scan_tlist)
{
ForeignScan *node = makeNode(ForeignScan);
Plan *plan = &node->scan.plan;
@@ -3622,8 +3584,13 @@ make_foreignscan(List *qptlist,
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
+ /* fs_server will be filled in by create_foreignscan_plan */
+ node->fs_server = InvalidOid;
node->fdw_exprs = fdw_exprs;
node->fdw_private = fdw_private;
+ node->fdw_scan_tlist = fdw_scan_tlist;
+ /* fs_relids will be filled in by create_foreignscan_plan */
+ node->fs_relids = NULL;
/* fsSystemCol will be filled in by create_foreignscan_plan */
node->fsSystemCol = false;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 612d32571af..fac51c91474 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -86,12 +86,6 @@ static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob);
static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte);
static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
-static void set_foreignscan_references(PlannerInfo *root,
- ForeignScan *fscan,
- int rtoffset);
-static void set_customscan_references(PlannerInfo *root,
- CustomScan *cscan,
- int rtoffset);
static Plan *set_indexonlyscan_references(PlannerInfo *root,
IndexOnlyScan *plan,
int rtoffset);
@@ -99,6 +93,12 @@ static Plan *set_subqueryscan_references(PlannerInfo *root,
SubqueryScan *plan,
int rtoffset);
static bool trivial_subqueryscan(SubqueryScan *plan);
+static void set_foreignscan_references(PlannerInfo *root,
+ ForeignScan *fscan,
+ int rtoffset);
+static void set_customscan_references(PlannerInfo *root,
+ CustomScan *cscan,
+ int rtoffset);
static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
@@ -573,7 +573,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
case T_ForeignScan:
set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
break;
-
case T_CustomScan:
set_customscan_references(root, (CustomScan *) plan, rtoffset);
break;
@@ -891,121 +890,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
}
/*
- * set_foreignscan_references
- * Do set_plan_references processing on an ForeignScan
- */
-static void
-set_foreignscan_references(PlannerInfo *root,
- ForeignScan *fscan,
- int rtoffset)
-{
- if (rtoffset > 0)
- {
- Bitmapset *tempset = NULL;
- int x = -1;
-
- while ((x = bms_next_member(fscan->fdw_relids, x)) >= 0)
- tempset = bms_add_member(tempset, x + rtoffset);
- fscan->fdw_relids = tempset;
- }
-
- if (fscan->scan.scanrelid == 0)
- {
- indexed_tlist *pscan_itlist = build_tlist_index(fscan->fdw_ps_tlist);
-
- fscan->scan.plan.targetlist = (List *)
- fix_upper_expr(root,
- (Node *) fscan->scan.plan.targetlist,
- pscan_itlist,
- INDEX_VAR,
- rtoffset);
- fscan->scan.plan.qual = (List *)
- fix_upper_expr(root,
- (Node *) fscan->scan.plan.qual,
- pscan_itlist,
- INDEX_VAR,
- rtoffset);
- fscan->fdw_exprs = (List *)
- fix_upper_expr(root,
- (Node *) fscan->fdw_exprs,
- pscan_itlist,
- INDEX_VAR,
- rtoffset);
- fscan->fdw_ps_tlist =
- fix_scan_list(root, fscan->fdw_ps_tlist, rtoffset);
- pfree(pscan_itlist);
- }
- else
- {
- fscan->scan.scanrelid += rtoffset;
- fscan->scan.plan.targetlist =
- fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
- fscan->scan.plan.qual =
- fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
- fscan->fdw_exprs =
- fix_scan_list(root, fscan->fdw_exprs, rtoffset);
- }
-}
-
-/*
- * set_customscan_references
- * Do set_plan_references processing on an CustomScan
- */
-static void
-set_customscan_references(PlannerInfo *root,
- CustomScan *cscan,
- int rtoffset)
-{
- if (rtoffset > 0)
- {
- Bitmapset *tempset = NULL;
- int x = -1;
-
- while ((x = bms_next_member(cscan->custom_relids, x)) >= 0)
- tempset = bms_add_member(tempset, x + rtoffset);
- cscan->custom_relids = tempset;
- }
-
- if (cscan->scan.scanrelid == 0)
- {
- indexed_tlist *pscan_itlist =
- build_tlist_index(cscan->custom_ps_tlist);
-
- cscan->scan.plan.targetlist = (List *)
- fix_upper_expr(root,
- (Node *) cscan->scan.plan.targetlist,
- pscan_itlist,
- INDEX_VAR,
- rtoffset);
- cscan->scan.plan.qual = (List *)
- fix_upper_expr(root,
- (Node *) cscan->scan.plan.qual,
- pscan_itlist,
- INDEX_VAR,
- rtoffset);
- cscan->custom_exprs = (List *)
- fix_upper_expr(root,
- (Node *) cscan->custom_exprs,
- pscan_itlist,
- INDEX_VAR,
- rtoffset);
- cscan->custom_ps_tlist =
- fix_scan_list(root, cscan->custom_ps_tlist, rtoffset);
- pfree(pscan_itlist);
- }
- else
- {
- cscan->scan.scanrelid += rtoffset;
- cscan->scan.plan.targetlist =
- fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
- cscan->scan.plan.qual =
- fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
- cscan->custom_exprs =
- fix_scan_list(root, cscan->custom_exprs, rtoffset);
- }
-}
-
-/*
* set_indexonlyscan_references
* Do set_plan_references processing on an IndexOnlyScan
*
@@ -1180,6 +1064,134 @@ trivial_subqueryscan(SubqueryScan *plan)
}
/*
+ * set_foreignscan_references
+ * Do set_plan_references processing on a ForeignScan
+ */
+static void
+set_foreignscan_references(PlannerInfo *root,
+ ForeignScan *fscan,
+ int rtoffset)
+{
+ /* Adjust scanrelid if it's valid */
+ if (fscan->scan.scanrelid > 0)
+ fscan->scan.scanrelid += rtoffset;
+
+ if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
+ {
+ /* Adjust tlist, qual, fdw_exprs to reference custom scan tuple */
+ indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
+
+ fscan->scan.plan.targetlist = (List *)
+ fix_upper_expr(root,
+ (Node *) fscan->scan.plan.targetlist,
+ itlist,
+ INDEX_VAR,
+ rtoffset);
+ fscan->scan.plan.qual = (List *)
+ fix_upper_expr(root,
+ (Node *) fscan->scan.plan.qual,
+ itlist,
+ INDEX_VAR,
+ rtoffset);
+ fscan->fdw_exprs = (List *)
+ fix_upper_expr(root,
+ (Node *) fscan->fdw_exprs,
+ itlist,
+ INDEX_VAR,
+ rtoffset);
+ pfree(itlist);
+ /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
+ fscan->fdw_scan_tlist =
+ fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset);
+ }
+ else
+ {
+ /* Adjust tlist, qual, fdw_exprs in the standard way */
+ fscan->scan.plan.targetlist =
+ fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
+ fscan->scan.plan.qual =
+ fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
+ fscan->fdw_exprs =
+ fix_scan_list(root, fscan->fdw_exprs, rtoffset);
+ }
+
+ /* Adjust fs_relids if needed */
+ if (rtoffset > 0)
+ {
+ Bitmapset *tempset = NULL;
+ int x = -1;
+
+ while ((x = bms_next_member(fscan->fs_relids, x)) >= 0)
+ tempset = bms_add_member(tempset, x + rtoffset);
+ fscan->fs_relids = tempset;
+ }
+}
+
+/*
+ * set_customscan_references
+ * Do set_plan_references processing on a CustomScan
+ */
+static void
+set_customscan_references(PlannerInfo *root,
+ CustomScan *cscan,
+ int rtoffset)
+{
+ /* Adjust scanrelid if it's valid */
+ if (cscan->scan.scanrelid > 0)
+ cscan->scan.scanrelid += rtoffset;
+
+ if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
+ {
+ /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
+ indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
+
+ cscan->scan.plan.targetlist = (List *)
+ fix_upper_expr(root,
+ (Node *) cscan->scan.plan.targetlist,
+ itlist,
+ INDEX_VAR,
+ rtoffset);
+ cscan->scan.plan.qual = (List *)
+ fix_upper_expr(root,
+ (Node *) cscan->scan.plan.qual,
+ itlist,
+ INDEX_VAR,
+ rtoffset);
+ cscan->custom_exprs = (List *)
+ fix_upper_expr(root,
+ (Node *) cscan->custom_exprs,
+ itlist,
+ INDEX_VAR,
+ rtoffset);
+ pfree(itlist);
+ /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
+ cscan->custom_scan_tlist =
+ fix_scan_list(root, cscan->custom_scan_tlist, rtoffset);
+ }
+ else
+ {
+ /* Adjust tlist, qual, custom_exprs in the standard way */
+ cscan->scan.plan.targetlist =
+ fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
+ cscan->scan.plan.qual =
+ fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
+ cscan->custom_exprs =
+ fix_scan_list(root, cscan->custom_exprs, rtoffset);
+ }
+
+ /* Adjust custom_relids if needed */
+ if (rtoffset > 0)
+ {
+ Bitmapset *tempset = NULL;
+ int x = -1;
+
+ while ((x = bms_next_member(cscan->custom_relids, x)) >= 0)
+ tempset = bms_add_member(tempset, x + rtoffset);
+ cscan->custom_relids = tempset;
+ }
+}
+
+/*
* copyVar
* Copy a Var node.
*
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 0220672fc43..afccee53acf 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2318,12 +2318,14 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
case T_ForeignScan:
finalize_primnode((Node *) ((ForeignScan *) plan)->fdw_exprs,
&context);
+ /* We assume fdw_scan_tlist cannot contain Params */
context.paramids = bms_add_members(context.paramids, scan_params);
break;
case T_CustomScan:
finalize_primnode((Node *) ((CustomScan *) plan)->custom_exprs,
&context);
+ /* We assume custom_scan_tlist cannot contain Params */
context.paramids = bms_add_members(context.paramids, scan_params);
break;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 894e0db802d..b425680f476 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -380,17 +380,18 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
rel->indexlist = indexinfos;
- /* Grab the fdwroutine info using the relcache, while we have it */
+ /* Grab foreign-table info using the relcache, while we have it */
if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
- rel->fdw_handler = GetFdwHandlerByRelId(RelationGetRelid(relation));
+ rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
}
else
{
- rel->fdw_handler = InvalidOid;
+ rel->serverid = InvalidOid;
rel->fdwroutine = NULL;
}
+
heap_close(relation, NoLock);
/*
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 56235663d7f..1d635cd6d21 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -14,7 +14,6 @@
*/
#include "postgres.h"
-#include "foreign/fdwapi.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
@@ -122,8 +121,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->subplan = NULL;
rel->subroot = NULL;
rel->subplan_params = NIL;
+ rel->serverid = InvalidOid;
rel->fdwroutine = NULL;
- rel->fdw_handler = InvalidOid;
rel->fdw_private = NULL;
rel->baserestrictinfo = NIL;
rel->baserestrictcost.startup = 0;
@@ -385,6 +384,7 @@ build_join_rel(PlannerInfo *root,
joinrel->subplan = NULL;
joinrel->subroot = NULL;
joinrel->subplan_params = NIL;
+ joinrel->serverid = InvalidOid;
joinrel->fdwroutine = NULL;
joinrel->fdw_private = NULL;
joinrel->baserestrictinfo = NIL;
@@ -394,6 +394,17 @@ build_join_rel(PlannerInfo *root,
joinrel->has_eclass_joins = false;
/*
+ * Set up foreign-join fields if outer and inner relation are foreign
+ * tables (or joins) belonging to the same server.
+ */
+ if (OidIsValid(outer_rel->serverid) &&
+ inner_rel->serverid == outer_rel->serverid)
+ {
+ joinrel->serverid = outer_rel->serverid;
+ joinrel->fdwroutine = outer_rel->fdwroutine;
+ }
+
+ /*
* Create a new tlist containing just the vars that need to be output from
* this join (ie, are needed for higher joinclauses or final output).
*
@@ -429,18 +440,6 @@ build_join_rel(PlannerInfo *root,
sjinfo, restrictlist);
/*
- * Set FDW handler and routine if both outer and inner relation
- * are managed by same FDW driver.
- */
- if (OidIsValid(outer_rel->fdw_handler) &&
- OidIsValid(inner_rel->fdw_handler) &&
- outer_rel->fdw_handler == inner_rel->fdw_handler)
- {
- joinrel->fdw_handler = outer_rel->fdw_handler;
- joinrel->fdwroutine = GetFdwRoutine(joinrel->fdw_handler);
- }
-
- /*
* Add the joinrel to the query's joinrel list, and store it into the
* auxiliary hashtable if there is one. NB: GEQO requires us to append
* the new joinrel to the end of the list!
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 4b3cd85ad90..156b5331f36 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -128,8 +128,8 @@ typedef struct
* varlevelsup > 0). We store the PlanState node that is the immediate
* parent of the expression to be deparsed, as well as a list of that
* PlanState's ancestors. In addition, we store its outer and inner subplan
- * state nodes, as well as their plan nodes' targetlists, and the indextlist
- * if the current PlanState is an IndexOnlyScanState. (These fields could
+ * state nodes, as well as their plan nodes' targetlists, and the index tlist
+ * if the current plan node might contain INDEX_VAR Vars. (These fields could
* be derived on-the-fly from the current PlanState, but it seems notationally
* clearer to set them up as separate fields.)
*/
@@ -2586,10 +2586,11 @@ deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
* provide the parent PlanState node. Then OUTER_VAR and INNER_VAR references
* can be resolved by drilling down into the left and right child plans.
* Similarly, INDEX_VAR references can be resolved by reference to the
- * indextlist given in the parent IndexOnlyScan node. (Note that we don't
- * currently support deparsing of indexquals in regular IndexScan or
- * BitmapIndexScan nodes; for those, we can only deparse the indexqualorig
- * fields, which won't contain INDEX_VAR Vars.)
+ * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
+ * ForeignScan and CustomScan nodes. (Note that we don't currently support
+ * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
+ * for those, we can only deparse the indexqualorig fields, which won't
+ * contain INDEX_VAR Vars.)
*
* Note: planstate really ought to be declared as "PlanState *", but we use
* "Node *" to avoid having to include execnodes.h in ruleutils.h.
@@ -3870,13 +3871,13 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
else
dpns->inner_tlist = NIL;
- /* index_tlist is set only if it's an IndexOnlyScan */
+ /* Set up referent for INDEX_VAR Vars, if needed */
if (IsA(ps->plan, IndexOnlyScan))
dpns->index_tlist = ((IndexOnlyScan *) ps->plan)->indextlist;
else if (IsA(ps->plan, ForeignScan))
- dpns->index_tlist = ((ForeignScan *) ps->plan)->fdw_ps_tlist;
+ dpns->index_tlist = ((ForeignScan *) ps->plan)->fdw_scan_tlist;
else if (IsA(ps->plan, CustomScan))
- dpns->index_tlist = ((CustomScan *) ps->plan)->custom_ps_tlist;
+ dpns->index_tlist = ((CustomScan *) ps->plan)->custom_scan_tlist;
else
dpns->index_tlist = NIL;
}