From c2ea2285e978d9289084846a3343cef7d261d880 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 21 Nov 2014 14:05:46 -0500 Subject: [PATCH] Simplify API for initially hooking custom-path providers into the planner. Instead of register_custom_path_provider and a CreateCustomScanPath callback, let's just provide a standard function hook in set_rel_pathlist. This is more flexible than what was previously committed, is more like the usual conventions for planner hooks, and requires less support code in the core. We had discussed this design (including centralizing the set_cheapest() calls) back in March or so, so I'm not sure why it wasn't done like this already. --- src/backend/optimizer/path/allpaths.c | 48 +++++++++++---------------- src/backend/optimizer/util/pathnode.c | 48 --------------------------- src/include/nodes/relation.h | 3 -- src/include/optimizer/pathnode.h | 9 ----- src/include/optimizer/paths.h | 7 ++++ 5 files changed, 27 insertions(+), 88 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 8b42e36b6d..c97355e8fd 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -54,6 +54,9 @@ typedef struct pushdown_safety_info bool enable_geqo = false; /* just in case GUC doesn't set it */ int geqo_threshold; +/* Hook for plugins to get control in set_rel_pathlist() */ +set_rel_pathlist_hook_type set_rel_pathlist_hook = NULL; + /* Hook for plugins to replace standard_join_search() */ join_search_hook_type join_search_hook = NULL; @@ -355,6 +358,17 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, } } + /* + * Allow a plugin to editorialize on the set of Paths for this base + * relation. It could add new paths (such as CustomPaths) by calling + * add_path(), or delete or modify paths added by the core code. + */ + if (set_rel_pathlist_hook) + (*set_rel_pathlist_hook) (root, rel, rti, rte); + + /* Now find the cheapest of the paths for this rel */ + set_cheapest(rel); + #ifdef OPTIMIZER_DEBUG debug_print_rel(root, rel); #endif @@ -401,12 +415,6 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* Consider TID scans */ create_tidscan_paths(root, rel); - - /* Consider custom scans, if any */ - create_customscan_paths(root, rel, rte); - - /* Now find the cheapest of the paths for this rel */ - set_cheapest(rel); } /* @@ -432,9 +440,6 @@ set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { /* Call the FDW's GetForeignPaths function to generate path(s) */ rel->fdwroutine->GetForeignPaths(root, rel, rte->relid); - - /* Select cheapest path */ - set_cheapest(rel); } /* @@ -857,9 +862,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, add_path(rel, (Path *) create_append_path(rel, subpaths, required_outer)); } - - /* Select cheapest paths */ - set_cheapest(rel); } /* @@ -1087,7 +1089,12 @@ set_dummy_rel_pathlist(RelOptInfo *rel) add_path(rel, (Path *) create_append_path(rel, NIL, NULL)); - /* Select cheapest path (pretty easy in this case...) */ + /* + * We set the cheapest path immediately, to ensure that IS_DUMMY_REL() + * will recognize the relation as dummy if anyone asks. This is redundant + * when we're called from set_rel_size(), but not when called from + * elsewhere, and doing it twice is harmless anyway. + */ set_cheapest(rel); } @@ -1275,9 +1282,6 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, /* Generate appropriate path */ add_path(rel, create_subqueryscan_path(root, rel, pathkeys, required_outer)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); } /* @@ -1346,9 +1350,6 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* Generate appropriate path */ add_path(rel, create_functionscan_path(root, rel, pathkeys, required_outer)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); } /* @@ -1369,9 +1370,6 @@ set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* Generate appropriate path */ add_path(rel, create_valuesscan_path(root, rel, required_outer)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); } /* @@ -1438,9 +1436,6 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* Generate appropriate path */ add_path(rel, create_ctescan_path(root, rel, required_outer)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); } /* @@ -1491,9 +1486,6 @@ set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* Generate appropriate path */ add_path(rel, create_worktablescan_path(root, rel, required_outer)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); } /* diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 121b9ff3e4..319e8b2c37 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -27,7 +27,6 @@ #include "optimizer/var.h" #include "parser/parsetree.h" #include "utils/lsyscache.h" -#include "utils/memutils.h" #include "utils/selfuncs.h" @@ -1927,50 +1926,3 @@ reparameterize_path(PlannerInfo *root, Path *path, } return NULL; } - -/***************************************************************************** - * creation of custom-plan paths - *****************************************************************************/ - -static List *custom_path_providers = NIL; - -/* - * register_custom_path_provider - * - * Register a table of callback functions which implements a custom-path - * provider. This allows extension to provide additional (hopefully faster) - * methods of scanning a relation. - */ -void -register_custom_path_provider(const CustomPathMethods *cpp_methods) -{ - MemoryContext oldcxt; - - oldcxt = MemoryContextSwitchTo(TopMemoryContext); - custom_path_providers = lappend(custom_path_providers, - (void *) cpp_methods); - MemoryContextSwitchTo(oldcxt); -} - -/* - * create_customscan_paths - * - * Invoke custom path provider callbacks. If the callback determines that - * the custom-path provider can handle this relation, it can add one or more - * paths using add_path(). - */ -void -create_customscan_paths(PlannerInfo *root, - RelOptInfo *baserel, - RangeTblEntry *rte) -{ - ListCell *cell; - - foreach(cell, custom_path_providers) - { - const CustomPathMethods *cpp_methods = lfirst(cell); - - if (cpp_methods->CreateCustomScanPath) - cpp_methods->CreateCustomScanPath(root, baserel, rte); - } -} diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 7953bf7ed6..bd5e8ce5c1 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -906,9 +906,6 @@ typedef struct CustomPathMethods { const char *CustomName; - void (*CreateCustomScanPath) (PlannerInfo *root, - RelOptInfo *baserel, - RangeTblEntry *rte); struct Plan *(*PlanCustomPath) (PlannerInfo *root, RelOptInfo *rel, struct CustomPath *best_path, diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 0f2882986c..26b17f5f7a 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -128,15 +128,6 @@ extern Path *reparameterize_path(PlannerInfo *root, Path *path, Relids required_outer, double loop_count); -/* - * Interface definition of custom-scan providers - */ -extern void register_custom_path_provider(const CustomPathMethods *cpp_methods); - -extern void create_customscan_paths(PlannerInfo *root, - RelOptInfo *baserel, - RangeTblEntry *rte); - /* * prototypes for relnode.c */ diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 9b22fda1ef..afa5f9bcd0 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -23,6 +23,13 @@ extern bool enable_geqo; extern int geqo_threshold; +/* Hook for plugins to get control in set_rel_pathlist() */ +typedef void (*set_rel_pathlist_hook_type) (PlannerInfo *root, + RelOptInfo *rel, + Index rti, + RangeTblEntry *rte); +extern PGDLLIMPORT set_rel_pathlist_hook_type set_rel_pathlist_hook; + /* Hook for plugins to replace standard_join_search() */ typedef RelOptInfo *(*join_search_hook_type) (PlannerInfo *root, int levels_needed,