Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb149539

Browse files
committed
Revise FDW planning API, again.
Further reflection shows that a single callback isn't very workable if wedesire to let FDWs generate multiple Paths, because that forces the FDW todo all work necessary to generate a valid Plan node for each Path. Insteadsplit the former PlanForeignScan API into three steps: GetForeignRelSize,GetForeignPaths, GetForeignPlan. We had already bit the bullet of breakingthe 9.1 FDW API for 9.2, so this shouldn't cause very much additional pain,and it's substantially more flexible for complex FDWs.Add an fdw_private field to RelOptInfo so that the new functions can savestate there rather than possibly having to recalculate information two orthree times.In addition, we'd not thought through what would be needed to allow an FDWto set up subexpressions of its choice for runtime execution. We couldtreat ForeignScan.fdw_private as an executable expression but that seemslikely to break existing FDWs unnecessarily (in particular, it wouldrestrict the set of node types allowable in fdw_private to those supportedby expression_tree_walker). Instead, invent a separate field fdw_exprswhich will receive the postprocessing appropriate for expression trees.(One field is enough since it can be a list of expressions; also, we assumethe corresponding expression state tree(s) will be held within fdw_state,so we don't need to add anything to ForeignScanState.)Per review of Hanada Shigeru's pgsql_fdw patch. We may need to tweak thisfurther as we continue to work on that patch, but to me it feels a lotcloser to being right now.
1 parent342baf4 commitb149539

File tree

15 files changed

+436
-112
lines changed

15 files changed

+436
-112
lines changed

‎contrib/file_fdw/file_fdw.c

Lines changed: 128 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include"nodes/makefuncs.h"
2727
#include"optimizer/cost.h"
2828
#include"optimizer/pathnode.h"
29+
#include"optimizer/planmain.h"
30+
#include"optimizer/restrictinfo.h"
2931
#include"utils/rel.h"
3032

3133
PG_MODULE_MAGIC;
@@ -48,7 +50,7 @@ struct FileFdwOption
4850
* Note: If you are adding new option for user mapping, you need to modify
4951
* fileGetOptions(), which currently doesn't bother to look at user mappings.
5052
*/
51-
staticstructFileFdwOptionvalid_options[]= {
53+
staticconststructFileFdwOptionvalid_options[]= {
5254
/* File options */
5355
{"filename",ForeignTableRelationId},
5456

@@ -71,6 +73,17 @@ static struct FileFdwOption valid_options[] = {
7173
{NULL,InvalidOid}
7274
};
7375

76+
/*
77+
* FDW-specific information for RelOptInfo.fdw_private.
78+
*/
79+
typedefstructFileFdwPlanState
80+
{
81+
char*filename;/* file to read */
82+
List*options;/* merged COPY options, excluding filename */
83+
BlockNumberpages;/* estimate of file's physical size */
84+
doublentuples;/* estimate of number of rows in file */
85+
}FileFdwPlanState;
86+
7487
/*
7588
* FDW-specific information for ForeignScanState.fdw_state.
7689
*/
@@ -93,9 +106,18 @@ PG_FUNCTION_INFO_V1(file_fdw_validator);
93106
/*
94107
* FDW callback routines
95108
*/
96-
staticvoidfilePlanForeignScan(Oidforeigntableid,
97-
PlannerInfo*root,
98-
RelOptInfo*baserel);
109+
staticvoidfileGetForeignRelSize(PlannerInfo*root,
110+
RelOptInfo*baserel,
111+
Oidforeigntableid);
112+
staticvoidfileGetForeignPaths(PlannerInfo*root,
113+
RelOptInfo*baserel,
114+
Oidforeigntableid);
115+
staticForeignScan*fileGetForeignPlan(PlannerInfo*root,
116+
RelOptInfo*baserel,
117+
Oidforeigntableid,
118+
ForeignPath*best_path,
119+
List*tlist,
120+
List*scan_clauses);
99121
staticvoidfileExplainForeignScan(ForeignScanState*node,ExplainState*es);
100122
staticvoidfileBeginForeignScan(ForeignScanState*node,inteflags);
101123
staticTupleTableSlot*fileIterateForeignScan(ForeignScanState*node);
@@ -109,8 +131,10 @@ static bool is_valid_option(const char *option, Oid context);
109131
staticvoidfileGetOptions(Oidforeigntableid,
110132
char**filename,List**other_options);
111133
staticList*get_file_fdw_attribute_options(Oidrelid);
134+
staticvoidestimate_size(PlannerInfo*root,RelOptInfo*baserel,
135+
FileFdwPlanState*fdw_private);
112136
staticvoidestimate_costs(PlannerInfo*root,RelOptInfo*baserel,
113-
constchar*filename,
137+
FileFdwPlanState*fdw_private,
114138
Cost*startup_cost,Cost*total_cost);
115139

116140

@@ -123,7 +147,9 @@ file_fdw_handler(PG_FUNCTION_ARGS)
123147
{
124148
FdwRoutine*fdwroutine=makeNode(FdwRoutine);
125149

126-
fdwroutine->PlanForeignScan=filePlanForeignScan;
150+
fdwroutine->GetForeignRelSize=fileGetForeignRelSize;
151+
fdwroutine->GetForeignPaths=fileGetForeignPaths;
152+
fdwroutine->GetForeignPlan=fileGetForeignPlan;
127153
fdwroutine->ExplainForeignScan=fileExplainForeignScan;
128154
fdwroutine->BeginForeignScan=fileBeginForeignScan;
129155
fdwroutine->IterateForeignScan=fileIterateForeignScan;
@@ -177,7 +203,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
177203

178204
if (!is_valid_option(def->defname,catalog))
179205
{
180-
structFileFdwOption*opt;
206+
conststructFileFdwOption*opt;
181207
StringInfoDatabuf;
182208

183209
/*
@@ -249,7 +275,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
249275
staticbool
250276
is_valid_option(constchar*option,Oidcontext)
251277
{
252-
structFileFdwOption*opt;
278+
conststructFileFdwOption*opt;
253279

254280
for (opt=valid_options;opt->optname;opt++)
255281
{
@@ -381,28 +407,48 @@ get_file_fdw_attribute_options(Oid relid)
381407
}
382408

383409
/*
384-
* filePlanForeignScan
410+
* fileGetForeignRelSize
411+
*Obtain relation size estimates for a foreign table
412+
*/
413+
staticvoid
414+
fileGetForeignRelSize(PlannerInfo*root,
415+
RelOptInfo*baserel,
416+
Oidforeigntableid)
417+
{
418+
FileFdwPlanState*fdw_private;
419+
420+
/*
421+
* Fetch options. We only need filename at this point, but we might
422+
* as well get everything and not need to re-fetch it later in planning.
423+
*/
424+
fdw_private= (FileFdwPlanState*)palloc(sizeof(FileFdwPlanState));
425+
fileGetOptions(foreigntableid,
426+
&fdw_private->filename,&fdw_private->options);
427+
baserel->fdw_private= (void*)fdw_private;
428+
429+
/* Estimate relation size */
430+
estimate_size(root,baserel,fdw_private);
431+
}
432+
433+
/*
434+
* fileGetForeignPaths
385435
*Create possible access paths for a scan on the foreign table
386436
*
387437
*Currently we don't support any push-down feature, so there is only one
388438
*possible access path, which simply returns all records in the order in
389439
*the data file.
390440
*/
391441
staticvoid
392-
filePlanForeignScan(Oidforeigntableid,
393-
PlannerInfo*root,
394-
RelOptInfo*baserel)
442+
fileGetForeignPaths(PlannerInfo*root,
443+
RelOptInfo*baserel,
444+
Oidforeigntableid)
395445
{
396-
char*filename;
397-
List*options;
446+
FileFdwPlanState*fdw_private= (FileFdwPlanState*)baserel->fdw_private;
398447
Coststartup_cost;
399448
Costtotal_cost;
400449

401-
/* Fetch options --- we only need filename at this point */
402-
fileGetOptions(foreigntableid,&filename,&options);
403-
404-
/* Estimate costs and update baserel->rows */
405-
estimate_costs(root,baserel,filename,
450+
/* Estimate costs */
451+
estimate_costs(root,baserel,fdw_private,
406452
&startup_cost,&total_cost);
407453

408454
/* Create a ForeignPath node and add it as only possible path */
@@ -422,6 +468,37 @@ filePlanForeignScan(Oid foreigntableid,
422468
*/
423469
}
424470

471+
/*
472+
* fileGetForeignPlan
473+
*Create a ForeignScan plan node for scanning the foreign table
474+
*/
475+
staticForeignScan*
476+
fileGetForeignPlan(PlannerInfo*root,
477+
RelOptInfo*baserel,
478+
Oidforeigntableid,
479+
ForeignPath*best_path,
480+
List*tlist,
481+
List*scan_clauses)
482+
{
483+
Indexscan_relid=baserel->relid;
484+
485+
/*
486+
* We have no native ability to evaluate restriction clauses, so we just
487+
* put all the scan_clauses into the plan node's qual list for the
488+
* executor to check. So all we have to do here is strip RestrictInfo
489+
* nodes from the clauses and ignore pseudoconstants (which will be
490+
* handled elsewhere).
491+
*/
492+
scan_clauses=extract_actual_clauses(scan_clauses, false);
493+
494+
/* Create the ForeignScan node */
495+
returnmake_foreignscan(tlist,
496+
scan_clauses,
497+
scan_relid,
498+
NIL,/* no expressions to evaluate */
499+
NIL);/* no private state either */
500+
}
501+
425502
/*
426503
* fileExplainForeignScan
427504
*Produce extra output for EXPLAIN
@@ -568,38 +645,38 @@ fileReScanForeignScan(ForeignScanState *node)
568645
}
569646

570647
/*
571-
* Estimatecosts of scanning a foreign table.
648+
* Estimatesize of a foreign table.
572649
*
573-
* In addition to setting *startup_cost and *total_cost, this should
574-
* update baserel->rows.
650+
* The main result is returned in baserel->rows. We also set
651+
* fdw_private->pages and fdw_private->ntuples for later use in the cost
652+
* calculation.
575653
*/
576654
staticvoid
577-
estimate_costs(PlannerInfo*root,RelOptInfo*baserel,
578-
constchar*filename,
579-
Cost*startup_cost,Cost*total_cost)
655+
estimate_size(PlannerInfo*root,RelOptInfo*baserel,
656+
FileFdwPlanState*fdw_private)
580657
{
581658
structstatstat_buf;
582659
BlockNumberpages;
583660
inttuple_width;
584661
doublentuples;
585662
doublenrows;
586-
Costrun_cost=0;
587-
Costcpu_per_tuple;
588663

589664
/*
590665
* Get size of the file. It might not be there at plan time, though, in
591666
* which case we have to use a default estimate.
592667
*/
593-
if (stat(filename,&stat_buf)<0)
668+
if (stat(fdw_private->filename,&stat_buf)<0)
594669
stat_buf.st_size=10*BLCKSZ;
595670

596671
/*
597-
* Convert size to pages for use in I/O cost estimatebelow.
672+
* Convert size to pages for use in I/O cost estimatelater.
598673
*/
599674
pages= (stat_buf.st_size+ (BLCKSZ-1)) /BLCKSZ;
600675
if (pages<1)
601676
pages=1;
602677

678+
fdw_private->pages=pages;
679+
603680
/*
604681
* Estimate the number of tuples in the file. We back into this estimate
605682
* using the planner's idea of the relation width; which is bogus if not
@@ -611,6 +688,8 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
611688

612689
ntuples=clamp_row_est((double)stat_buf.st_size / (double)tuple_width);
613690

691+
fdw_private->ntuples=ntuples;
692+
614693
/*
615694
* Now estimate the number of rows returned by the scan after applying the
616695
* baserestrictinfo quals.This is pretty bogus too, since the planner
@@ -627,12 +706,28 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
627706

628707
/* Save the output-rows estimate for the planner */
629708
baserel->rows=nrows;
709+
}
710+
711+
/*
712+
* Estimate costs of scanning a foreign table.
713+
*
714+
* Results are returned in *startup_cost and *total_cost.
715+
*/
716+
staticvoid
717+
estimate_costs(PlannerInfo*root,RelOptInfo*baserel,
718+
FileFdwPlanState*fdw_private,
719+
Cost*startup_cost,Cost*total_cost)
720+
{
721+
BlockNumberpages=fdw_private->pages;
722+
doublentuples=fdw_private->ntuples;
723+
Costrun_cost=0;
724+
Costcpu_per_tuple;
630725

631726
/*
632-
*Now estimate costs.We estimate costs almost the same way as
633-
*cost_seqscan(), thus assumingthat I/O costs are equivalent to a
634-
*regular table file of the same size.However, we take per-tuple CPU
635-
*costs as 10x of a seqscan, to accountfor the cost of parsing records.
727+
* We estimate costs almost the same way as cost_seqscan(), thus assuming
728+
* that I/O costs are equivalent to a regular table file of the same size.
729+
* However, we take per-tuple CPU costs as 10x of a seqscan, to account
730+
* for the cost of parsing records.
636731
*/
637732
run_cost+=seq_page_cost*pages;
638733

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp