*** a/contrib/file_fdw/file_fdw.c --- b/contrib/file_fdw/file_fdw.c *************** *** 74,87 **** static const struct FileFdwOption valid_options[] = { }; /* ! * FDW-specific information for RelOptInfo.fdw_private. */ typedef struct FileFdwPlanState { char *filename; /* file to read */ List *options; /* merged COPY options, excluding filename */ - BlockNumber pages; /* estimate of file's physical size */ - double ntuples; /* estimate of number of rows in file */ } FileFdwPlanState; /* --- 74,85 ---- }; /* ! * FDW-specific information for RelOptInfo.fdw_state. */ typedef struct FileFdwPlanState { char *filename; /* file to read */ List *options; /* merged COPY options, excluding filename */ } FileFdwPlanState; /* *************** *** 132,140 **** static void fileGetOptions(Oid foreigntableid, char **filename, List **other_options); static List *get_file_fdw_attribute_options(Oid relid); static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, ! FileFdwPlanState *fdw_private); static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, - FileFdwPlanState *fdw_private, Cost *startup_cost, Cost *total_cost); --- 130,137 ---- char **filename, List **other_options); static List *get_file_fdw_attribute_options(Oid relid); static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, ! FileFdwPlanState *fpstate); static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, Cost *startup_cost, Cost *total_cost); *************** *** 415,433 **** fileGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid) { ! FileFdwPlanState *fdw_private; /* * Fetch options. We only need filename at this point, but we might * as well get everything and not need to re-fetch it later in planning. */ ! fdw_private = (FileFdwPlanState *) palloc(sizeof(FileFdwPlanState)); ! fileGetOptions(foreigntableid, ! &fdw_private->filename, &fdw_private->options); ! baserel->fdw_private = (void *) fdw_private; /* Estimate relation size */ ! estimate_size(root, baserel, fdw_private); } /* --- 412,429 ---- RelOptInfo *baserel, Oid foreigntableid) { ! FileFdwPlanState *fpstate; /* * Fetch options. We only need filename at this point, but we might * as well get everything and not need to re-fetch it later in planning. */ ! fpstate = (FileFdwPlanState *) palloc(sizeof(FileFdwPlanState)); ! fileGetOptions(foreigntableid, &fpstate->filename, &fpstate->options); ! baserel->fdw_state = (void *) fpstate; /* Estimate relation size */ ! estimate_size(root, baserel, fpstate); } /* *************** *** 443,455 **** fileGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid) { - FileFdwPlanState *fdw_private = (FileFdwPlanState *) baserel->fdw_private; Cost startup_cost; Cost total_cost; /* Estimate costs */ ! estimate_costs(root, baserel, fdw_private, ! &startup_cost, &total_cost); /* Create a ForeignPath node and add it as only possible path */ add_path(baserel, (Path *) --- 439,449 ---- RelOptInfo *baserel, Oid foreigntableid) { Cost startup_cost; Cost total_cost; /* Estimate costs */ ! estimate_costs(root, baserel, &startup_cost, &total_cost); /* Create a ForeignPath node and add it as only possible path */ add_path(baserel, (Path *) *************** *** 647,659 **** fileReScanForeignScan(ForeignScanState *node) /* * Estimate size of a foreign table. * ! * The main result is returned in baserel->rows. We also set ! * fdw_private->pages and fdw_private->ntuples for later use in the cost ! * calculation. */ static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, ! FileFdwPlanState *fdw_private) { struct stat stat_buf; BlockNumber pages; --- 641,652 ---- /* * Estimate size of a foreign table. * ! * The main result is returned in baserel->rows. We also set baserel->pages ! * and baserel->tuples for later use in the cost calculation. */ static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, ! FileFdwPlanState *fpstate) { struct stat stat_buf; BlockNumber pages; *************** *** 665,671 **** estimate_size(PlannerInfo *root, RelOptInfo *baserel, * Get size of the file. It might not be there at plan time, though, in * which case we have to use a default estimate. */ ! if (stat(fdw_private->filename, &stat_buf) < 0) stat_buf.st_size = 10 * BLCKSZ; /* --- 658,664 ---- * Get size of the file. It might not be there at plan time, though, in * which case we have to use a default estimate. */ ! if (stat(fpstate->filename, &stat_buf) < 0) stat_buf.st_size = 10 * BLCKSZ; /* *************** *** 675,681 **** estimate_size(PlannerInfo *root, RelOptInfo *baserel, if (pages < 1) pages = 1; ! fdw_private->pages = pages; /* * Estimate the number of tuples in the file. We back into this estimate --- 668,674 ---- if (pages < 1) pages = 1; ! baserel->pages = pages; /* * Estimate the number of tuples in the file. We back into this estimate *************** *** 688,694 **** estimate_size(PlannerInfo *root, RelOptInfo *baserel, ntuples = clamp_row_est((double) stat_buf.st_size / (double) tuple_width); ! fdw_private->ntuples = ntuples; /* * Now estimate the number of rows returned by the scan after applying the --- 681,687 ---- ntuples = clamp_row_est((double) stat_buf.st_size / (double) tuple_width); ! baserel->tuples = ntuples; /* * Now estimate the number of rows returned by the scan after applying the *************** *** 715,725 **** estimate_size(PlannerInfo *root, RelOptInfo *baserel, */ static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, - FileFdwPlanState *fdw_private, Cost *startup_cost, Cost *total_cost) { ! BlockNumber pages = fdw_private->pages; ! double ntuples = fdw_private->ntuples; Cost run_cost = 0; Cost cpu_per_tuple; --- 708,717 ---- */ static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, Cost *startup_cost, Cost *total_cost) { ! BlockNumber pages = baserel->pages; ! double ntuples = baserel->tuples; Cost run_cost = 0; Cost cpu_per_tuple; *** a/doc/src/sgml/fdwhandler.sgml --- b/doc/src/sgml/fdwhandler.sgml *************** *** 126,132 **** GetForeignRelSize (PlannerInfo *root, ! baserel->fdw_private is a void pointer that is available for use by FDW planning functions. It can be used to pass information forward from GetForeignRelSize to GetForeignPaths and/or GetForeignPaths to --- 126,132 ---- ! baserel->fdw_state is a void pointer that is available for use by FDW planning functions. It can be used to pass information forward from GetForeignRelSize to GetForeignPaths and/or GetForeignPaths to *** a/src/backend/optimizer/util/relnode.c --- b/src/backend/optimizer/util/relnode.c *************** *** 114,120 **** build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) 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; --- 114,120 ---- rel->subplan = NULL; rel->subroot = NULL; rel->fdwroutine = NULL; ! rel->fdw_state = NULL; rel->baserestrictinfo = NIL; rel->baserestrictcost.startup = 0; rel->baserestrictcost.per_tuple = 0; *************** *** 369,375 **** build_join_rel(PlannerInfo *root, 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; --- 369,375 ---- joinrel->subplan = NULL; joinrel->subroot = NULL; joinrel->fdwroutine = NULL; ! joinrel->fdw_state = NULL; joinrel->baserestrictinfo = NIL; joinrel->baserestrictcost.startup = 0; joinrel->baserestrictcost.per_tuple = 0; *** a/src/include/nodes/relation.h --- b/src/include/nodes/relation.h *************** *** 422,428 **** typedef struct RelOptInfo PlannerInfo *subroot; /* if subquery */ /* use "struct FdwRoutine" to avoid including fdwapi.h here */ struct FdwRoutine *fdwroutine; /* if foreign table */ ! void *fdw_private; /* if foreign table */ /* used by various scans and joins: */ List *baserestrictinfo; /* RestrictInfo structures (if base --- 422,428 ---- PlannerInfo *subroot; /* if subquery */ /* use "struct FdwRoutine" to avoid including fdwapi.h here */ struct FdwRoutine *fdwroutine; /* if foreign table */ ! void *fdw_state; /* if foreign table */ /* used by various scans and joins: */ List *baserestrictinfo; /* RestrictInfo structures (if base