diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 111 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 9 | ||||
-rw-r--r-- | src/include/optimizer/pathnode.h | 13 |
3 files changed, 126 insertions, 7 deletions
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index b57de6b4c67..08133a28fd2 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -2079,15 +2079,14 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel, /* * create_foreignscan_path - * Creates a path corresponding to a scan of a foreign table, foreign join, - * or foreign upper-relation processing, returning the pathnode. + * Creates a path corresponding to a scan of a foreign base table, + * returning the pathnode. * * This function is never called from core Postgres; rather, it's expected - * to be called by the GetForeignPaths, GetForeignJoinPaths, or - * GetForeignUpperPaths 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. However, there is a usually-sane default for the pathtarget - * (rel->reltarget), so we let a NULL for "target" select that. + * 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. However, there is a usually-sane default for + * the pathtarget (rel->reltarget), so we let a NULL for "target" select that. */ ForeignPath * create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, @@ -2100,6 +2099,9 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, { ForeignPath *pathnode = makeNode(ForeignPath); + /* Historically some FDWs were confused about when to use this */ + Assert(IS_SIMPLE_REL(rel)); + pathnode->path.pathtype = T_ForeignScan; pathnode->path.parent = rel; pathnode->path.pathtarget = target ? target : rel->reltarget; @@ -2120,6 +2122,101 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, } /* + * create_foreign_join_path + * Creates a path corresponding to a scan of a foreign join, + * returning the pathnode. + * + * This function is never called from core Postgres; rather, it's expected + * to be called by the GetForeignJoinPaths 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. However, there is a usually-sane default for + * the pathtarget (rel->reltarget), so we let a NULL for "target" select that. + */ +ForeignPath * +create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Relids required_outer, + Path *fdw_outerpath, + List *fdw_private) +{ + ForeignPath *pathnode = makeNode(ForeignPath); + + /* + * We should use get_joinrel_parampathinfo to handle parameterized paths, + * but the API of this function doesn't support it, and existing + * extensions aren't yet trying to build such paths anyway. For the + * moment just throw an error if someone tries it; eventually we should + * revisit this. + */ + if (!bms_is_empty(required_outer) || !bms_is_empty(rel->lateral_relids)) + elog(ERROR, "parameterized foreign joins are not supported yet"); + + pathnode->path.pathtype = T_ForeignScan; + pathnode->path.parent = rel; + pathnode->path.pathtarget = target ? target : rel->reltarget; + pathnode->path.param_info = NULL; /* XXX see above */ + pathnode->path.parallel_aware = false; + pathnode->path.parallel_safe = rel->consider_parallel; + pathnode->path.parallel_workers = 0; + pathnode->path.rows = rows; + pathnode->path.startup_cost = startup_cost; + pathnode->path.total_cost = total_cost; + pathnode->path.pathkeys = pathkeys; + + pathnode->fdw_outerpath = fdw_outerpath; + pathnode->fdw_private = fdw_private; + + return pathnode; +} + +/* + * create_foreign_upper_path + * Creates a path corresponding to an upper relation that's computed + * directly by an FDW, returning the pathnode. + * + * This function is never called from core Postgres; rather, it's expected to + * be called by the GetForeignUpperPaths 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. However, there is a usually-sane default for + * the pathtarget (rel->reltarget), so we let a NULL for "target" select that. + */ +ForeignPath * +create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Path *fdw_outerpath, + List *fdw_private) +{ + ForeignPath *pathnode = makeNode(ForeignPath); + + /* + * Upper relations should never have any lateral references, since joining + * is complete. + */ + Assert(bms_is_empty(rel->lateral_relids)); + + pathnode->path.pathtype = T_ForeignScan; + pathnode->path.parent = rel; + pathnode->path.pathtarget = target ? target : rel->reltarget; + pathnode->path.param_info = NULL; + pathnode->path.parallel_aware = false; + pathnode->path.parallel_safe = rel->consider_parallel; + pathnode->path.parallel_workers = 0; + pathnode->path.rows = rows; + pathnode->path.startup_cost = startup_cost; + pathnode->path.total_cost = total_cost; + pathnode->path.pathkeys = pathkeys; + + pathnode->fdw_outerpath = fdw_outerpath; + pathnode->fdw_private = fdw_private; + + return pathnode; +} + +/* * calc_nestloop_required_outer * Compute the required_outer set for a nestloop join path * diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index f04c6b76f49..4130514952b 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -1225,6 +1225,9 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, double rows; ListCell *lc; + /* If rel has LATERAL refs, every path for it should account for them */ + Assert(bms_is_subset(baserel->lateral_relids, required_outer)); + /* Unparameterized paths have no ParamPathInfo */ if (bms_is_empty(required_outer)) return NULL; @@ -1320,6 +1323,9 @@ get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel, double rows; ListCell *lc; + /* If rel has LATERAL refs, every path for it should account for them */ + Assert(bms_is_subset(joinrel->lateral_relids, required_outer)); + /* Unparameterized paths have no ParamPathInfo or extra join clauses */ if (bms_is_empty(required_outer)) return NULL; @@ -1511,6 +1517,9 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer) { ParamPathInfo *ppi; + /* If rel has LATERAL refs, every path for it should account for them */ + Assert(bms_is_subset(appendrel->lateral_relids, required_outer)); + /* Unparameterized paths have no ParamPathInfo */ if (bms_is_empty(required_outer)) return NULL; diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index d0c8f99d0a5..ef2c9b47289 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -118,6 +118,19 @@ extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer, Path *fdw_outerpath, List *fdw_private); +extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Relids required_outer, + Path *fdw_outerpath, + List *fdw_private); +extern ForeignPath *create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Path *fdw_outerpath, + List *fdw_private); extern Relids calc_nestloop_required_outer(Relids outerrelids, Relids outer_paramrels, |