*** a/contrib/postgres_fdw/postgres_fdw.c --- b/contrib/postgres_fdw/postgres_fdw.c *************** *** 295,300 **** static bool postgresAnalyzeForeignTable(Relation relation, --- 295,301 ---- static void estimate_path_cost_size(PlannerInfo *root, RelOptInfo *baserel, List *join_conds, + List *param_conds, double *p_rows, int *p_width, Cost *p_startup_cost, Cost *p_total_cost); static void get_remote_estimate(const char *sql, *************** *** 493,499 **** postgresGetForeignRelSize(PlannerInfo *root, * values in fpinfo so we don't need to do it again to generate the * basic foreign path. */ ! estimate_path_cost_size(root, baserel, NIL, &fpinfo->rows, &fpinfo->width, &fpinfo->startup_cost, &fpinfo->total_cost); --- 494,500 ---- * values in fpinfo so we don't need to do it again to generate the * basic foreign path. */ ! estimate_path_cost_size(root, baserel, NIL, NIL, &fpinfo->rows, &fpinfo->width, &fpinfo->startup_cost, &fpinfo->total_cost); *************** *** 523,529 **** postgresGetForeignRelSize(PlannerInfo *root, set_baserel_size_estimates(root, baserel); /* Fill in basically-bogus cost estimates for use later. */ ! estimate_path_cost_size(root, baserel, NIL, &fpinfo->rows, &fpinfo->width, &fpinfo->startup_cost, &fpinfo->total_cost); } --- 524,530 ---- set_baserel_size_estimates(root, baserel); /* Fill in basically-bogus cost estimates for use later. */ ! estimate_path_cost_size(root, baserel, NIL, NIL, &fpinfo->rows, &fpinfo->width, &fpinfo->startup_cost, &fpinfo->total_cost); } *************** *** 541,547 **** postgresGetForeignPaths(PlannerInfo *root, --- 542,550 ---- PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) baserel->fdw_private; ForeignPath *path; List *join_quals; + List *param_quals; Relids required_outer; + ParamPathInfo *param_info; double rows; int width; Cost startup_cost; *************** *** 591,604 **** postgresGetForeignPaths(PlannerInfo *root, if (!is_foreign_expr(root, baserel, rinfo->clause)) continue; - /* - * OK, get a cost estimate from the remote, and make a path. - */ - join_quals = list_make1(rinfo); - estimate_path_cost_size(root, baserel, join_quals, - &rows, &width, - &startup_cost, &total_cost); - /* Must calculate required outer rels for this path */ required_outer = bms_union(rinfo->clause_relids, baserel->lateral_relids); --- 594,599 ---- *************** *** 608,613 **** postgresGetForeignPaths(PlannerInfo *root, --- 603,622 ---- if (bms_is_empty(required_outer)) required_outer = NULL; + /* + * OK, get a cost estimate from the remote, and make a path. + */ + join_quals = list_make1(rinfo); + param_info = get_baserel_parampathinfo(root, baserel, required_outer); + param_quals = list_copy(param_info->ppi_clauses); + estimate_path_cost_size(root, baserel, join_quals, param_quals, + &rows, &width, + &startup_cost, &total_cost); + + /* Mark the path with the correct row estimate */ + if (param_info) + rows = param_info->ppi_rows; + path = create_foreignscan_path(root, baserel, rows, startup_cost, *************** *** 667,686 **** postgresGetForeignPaths(PlannerInfo *root, if (!is_foreign_expr(root, baserel, rinfo->clause)) continue; /* * OK, get a cost estimate from the remote, and make a path. */ join_quals = list_make1(rinfo); ! estimate_path_cost_size(root, baserel, join_quals, &rows, &width, &startup_cost, &total_cost); ! /* Must calculate required outer rels for this path */ ! required_outer = bms_union(rinfo->clause_relids, ! baserel->lateral_relids); ! required_outer = bms_del_member(required_outer, baserel->relid); ! if (bms_is_empty(required_outer)) ! required_outer = NULL; path = create_foreignscan_path(root, baserel, rows, --- 676,702 ---- if (!is_foreign_expr(root, baserel, rinfo->clause)) continue; + /* Must calculate required outer rels for this path */ + required_outer = bms_union(rinfo->clause_relids, + baserel->lateral_relids); + required_outer = bms_del_member(required_outer, baserel->relid); + if (bms_is_empty(required_outer)) + required_outer = NULL; + /* * OK, get a cost estimate from the remote, and make a path. */ join_quals = list_make1(rinfo); ! param_info = get_baserel_parampathinfo(root, baserel, ! required_outer); ! param_quals = list_copy(param_info->ppi_clauses); ! estimate_path_cost_size(root, baserel, join_quals, param_quals, &rows, &width, &startup_cost, &total_cost); ! /* Mark the path with the correct row estimate */ ! if (param_info) ! rows = param_info->ppi_rows; path = create_foreignscan_path(root, baserel, rows, *************** *** 1662,1673 **** postgresExplainForeignModify(ModifyTableState *mtstate, * Get cost and size estimates for a foreign scan * * We assume that all the baserestrictinfo clauses will be applied, plus ! * any join clauses listed in join_conds. */ static void estimate_path_cost_size(PlannerInfo *root, RelOptInfo *baserel, List *join_conds, double *p_rows, int *p_width, Cost *p_startup_cost, Cost *p_total_cost) { --- 1678,1691 ---- * Get cost and size estimates for a foreign scan * * We assume that all the baserestrictinfo clauses will be applied, plus ! * any join clauses listed in join_conds and all the extra join clauses ! * appearing in param_conds. */ static void estimate_path_cost_size(PlannerInfo *root, RelOptInfo *baserel, List *join_conds, + List *param_conds, double *p_rows, int *p_width, Cost *p_startup_cost, Cost *p_total_cost) { *************** *** 1723,1728 **** estimate_path_cost_size(PlannerInfo *root, --- 1741,1764 ---- /* Add in the eval cost of the local_conds */ startup_cost += fpinfo->local_conds_cost.startup; total_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows; + + /* Add in the eval cost of extra join clauses in the param_conds */ + if (param_conds) + { + List *extra_conds; + QualCost extra_conds_cost; + + /* + * We approximate the list of all the extra join clauses as + * param_conds minus join_conds. (We assume that pointer + * equality is enough to recognize duplicate RestrictInfos.) + */ + extra_conds = list_difference_ptr(param_conds, join_conds); + cost_qual_eval(&extra_conds_cost, extra_conds, root); + + startup_cost += extra_conds_cost.startup; + total_cost += extra_conds_cost.per_tuple * retrieved_rows; + } } else { *************** *** 1731,1736 **** estimate_path_cost_size(PlannerInfo *root, --- 1767,1773 ---- * parameterized paths can be made). */ Assert(join_conds == NIL); + Assert(param_conds == NIL); /* Use rows/width estimates made by set_baserel_size_estimates. */ rows = baserel->rows;