From 5864d6a4b62ada2ad60a8c456b4ee62972a9c10d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 14 Mar 2016 19:23:29 -0400 Subject: [PATCH] Provide a planner hook at a suitable place for creating upper-rel Paths. In the initial revision of the upper-planner pathification work, the only available way for an FDW or custom-scan provider to inject Paths representing post-scan-join processing was to insert them during scan-level GetForeignPaths or similar processing. While that's not impossible, it'd require quite a lot of duplicative processing to look forward and see if the extension would be capable of implementing the whole query. To improve matters for custom-scan providers, provide a hook function at the point where the core code is about to start filling in upperrel Paths. At this point Paths are available for the whole scan/join tree, which should reduce the amount of redundant effort considerably. (An alternative design that was suggested was to provide a separate hook for each post-scan-join processing step, but that seems messy and not clearly more useful.) Following our time-honored tradition, there's no documentation for this hook outside the source code. As-is, this hook is only meant for custom scan providers, which we can't assume very much about. A followon patch will implement an FDW callback to let FDWs do the same thing in a somewhat more structured fashion. --- src/backend/optimizer/plan/planner.c | 26 +++++++++++++++++++++++ src/backend/optimizer/prep/prepjointree.c | 1 + src/include/nodes/relation.h | 3 +++ src/include/optimizer/planner.h | 5 +++++ 4 files changed, 35 insertions(+) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index f3a0a44fd8..d11f44e64d 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -62,6 +62,9 @@ int force_parallel_mode = FORCE_PARALLEL_OFF; /* Hook for plugins to get control in planner() */ planner_hook_type planner_hook = NULL; +/* Hook for plugins to get control before grouping_planner plans upper rels */ +create_upper_paths_hook_type create_upper_paths_hook = NULL; + /* Expression kind codes for preprocess_expression */ #define EXPRKIND_QUAL 0 @@ -459,6 +462,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, root->append_rel_list = NIL; root->rowMarks = NIL; memset(root->upper_rels, 0, sizeof(root->upper_rels)); + memset(root->upper_targets, 0, sizeof(root->upper_targets)); root->processed_tlist = NIL; root->grouping_map = NULL; root->minmax_aggs = NIL; @@ -1736,6 +1740,28 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, } } + /* + * Save the various upper-rel PathTargets we just computed into + * root->upper_targets[]. The core code doesn't use this, but it + * provides a convenient place for extensions to get at the info. For + * consistency, we save all the intermediate targets, even though some + * of the corresponding upperrels might not be needed for this query. + */ + root->upper_targets[UPPERREL_FINAL] = final_target; + root->upper_targets[UPPERREL_WINDOW] = sort_input_target; + root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target; + + /* + * Let extensions, particularly CustomScan providers, consider + * injecting extension Paths into the query's upperrels, where they + * will compete with the Paths we create below. We pass the final + * scan/join rel because that's not so easily findable from the + * PlannerInfo struct; anything else the hook wants to know should be + * obtainable via "root". + */ + if (create_upper_paths_hook) + (*create_upper_paths_hook) (root, current_rel); + /* * If we have grouping and/or aggregation, consider ways to implement * that. We build a new upperrel representing the output of this diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index c8d5c66b39..75577bce2c 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -909,6 +909,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, subroot->append_rel_list = NIL; subroot->rowMarks = NIL; memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels)); + memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets)); subroot->processed_tlist = NIL; subroot->grouping_map = NULL; subroot->minmax_aggs = NIL; diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index b48a6183dc..503269693b 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -263,6 +263,9 @@ typedef struct PlannerInfo /* Use fetch_upper_rel() to get any particular upper rel */ List *upper_rels[UPPERREL_FINAL + 1]; /* upper-rel RelOptInfos */ + /* Result tlists chosen by grouping_planner for upper-stage processing */ + struct PathTarget *upper_targets[UPPERREL_FINAL + 1]; + /* * grouping_planner passes back its final processed targetlist here, for * use in relabeling the topmost tlist of the finished Plan. diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index 3fb7cb58cb..a95e73fa93 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -24,6 +24,11 @@ typedef PlannedStmt *(*planner_hook_type) (Query *parse, ParamListInfo boundParams); extern PGDLLIMPORT planner_hook_type planner_hook; +/* Hook for plugins to get control before grouping_planner plans upper rels */ +typedef void (*create_upper_paths_hook_type) (PlannerInfo *root, + RelOptInfo *scan_join_rel); +extern PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook; + extern PlannedStmt *planner(Query *parse, int cursorOptions, ParamListInfo boundParams); -- 2.40.0