Provide a planner hook at a suitable place for creating upper-rel Paths.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Mar 2016 23:23:29 +0000 (19:23 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 14 Mar 2016 23:23:29 +0000 (19:23 -0400)
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
src/backend/optimizer/prep/prepjointree.c
src/include/nodes/relation.h
src/include/optimizer/planner.h

index f3a0a44fd889df7bc87532c205e3263f7c23d3ca..d11f44e64d530cb9bb77486d08d276ac8bffea6c 100644 (file)
@@ -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
index c8d5c66b396cdde4d144d8539c858bdfdf60061d..75577bce2ca02e56cb010d2161c85c8711967e0f 100644 (file)
@@ -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;
index b48a6183dc2cbedb0aa97d7a0846b57c685abbbd..503269693bac3c1ba23b8668dddb1490ea68a3fb 100644 (file)
@@ -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.
index 3fb7cb58cbd77d2eedf6ce00ae40fd048cafb9b2..a95e73fa93b4e36f83dd0c79b8b3b2160ec87729 100644 (file)
@@ -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);