From e0cf7be1682feb8dbca80adefbaac06ef8315ba4 Mon Sep 17 00:00:00 2001 From: Alexander Pyhalov Date: Tue, 9 Aug 2022 14:47:16 +0300 Subject: [PATCH] postgres_fdw should avoid sorted paths which don't provide all required vars --- contrib/postgres_fdw/postgres_fdw.c | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 16320170cee..e21ddd7485f 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -541,6 +541,7 @@ static void merge_fdw_options(PgFdwRelationInfo *fpinfo, const PgFdwRelationInfo *fpinfo_o, const PgFdwRelationInfo *fpinfo_i); static int get_batch_size_option(Relation rel); +static bool path_provides_local_vars(Path *path, PgFdwRelationInfo *fpinfo); /* @@ -5775,6 +5776,54 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, return true; } +/* + * Determines if all vars, used by fpinfo->local_conds, + * are provided by path. + */ +static bool +path_provides_local_vars(Path *path, PgFdwRelationInfo *fpinfo) +{ + List *vars_provided; + ListCell *lc1; + ListCell *lc2; + ListCell *lc3; + + if (path == NULL) + return false; + + /* Get all vars, provided by path */ + vars_provided = pull_var_clause((Node *) path->pathtarget->exprs, PVC_INCLUDE_PLACEHOLDERS); + + foreach(lc1, fpinfo->local_conds) + { + RestrictInfo *ri = (RestrictInfo *) lfirst(lc1); + List *vars_used; + + /* Get vars, used by this restriction clause */ + vars_used = pull_var_clause((Node *) ri->clause, PVC_INCLUDE_PLACEHOLDERS); + foreach(lc2, vars_used) + { + Var *used = lfirst(lc2); + bool found = false; + + foreach(lc3, vars_provided) + { + Var *provided = lfirst(lc3); + + if (provided->varno == used->varno && provided->varattno == used->varattno) + { + found = true; + break; + } + } + if (!found) + return false; + } + } + + return true; +} + static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel, Path *epq_path) @@ -5812,6 +5861,13 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel, useful_pathkeys, -1.0); + /* + * Sorted path should provide all vars needed by local conditions or + * we'll not be able to use it + */ + if (sorted_epq_path != NULL && !path_provides_local_vars(sorted_epq_path, (PgFdwRelationInfo *) rel->fdw_private)) + return; + if (IS_SIMPLE_REL(rel)) add_path(rel, (Path *) create_foreignscan_path(root, rel, -- 2.34.1