From 62b3f7d20505408c8668cff706bca72d696da1da Mon Sep 17 00:00:00 2001 From: Nils Dijk Date: Fri, 24 Dec 2021 12:31:32 +0000 Subject: [PATCH 3/3] add path_compare_hook to let extensions compare paths --- src/backend/optimizer/util/pathnode.c | 24 ++++++++++++++++++++++++ src/include/optimizer/pathnode.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index f333069872..96247f2029 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -42,6 +42,8 @@ typedef enum CONTINUE /* compare with next path */ } AddPathDecision; +path_compare_hook_type path_compare_hook = NULL; + /* * STD_FUZZ_FACTOR is the normal fuzz factor for compare_path_costs_fuzzily. * XXX is it worth making this user-controllable? It provides a tradeoff @@ -507,6 +509,14 @@ path_compare(Path *path1, Path *path2) if (cmp == PATHS_DIFFERENT) return cmp; + if (unlikely(path_compare_hook)) + { + /* since we combine a result form an extension use a safe combine */ + cmp = path_comparison_combine(cmp, path_compare_hook(path1, path2)); + if (cmp == PATHS_DIFFERENT) + return cmp; + } + /* Keep compatibility with the original decision tree from add_path */ if (cmp != PATHS_EQUAL) { @@ -746,6 +756,20 @@ add_path_precheck(RelOptInfo *parent_rel, bool consider_startup; ListCell *p1; + if (path_compare_hook) + { + /* + * When an extension has installed a hook for comparing paths we can't + * perform any precheck to quickly decline a hypothetical path. If we + * would reject a path based on the parameters passed in we don't + * allow extensions to make a differentiation on alternative + * dimensions. + * + * Instead we return early and allow the path to be created. + */ + return true; + } + /* Pretend parameterized paths have no pathkeys, per add_path policy */ new_path_pathkeys = required_outer ? NIL : pathkeys; diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 1ee4a91ab8..87b89e9dce 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -29,6 +29,20 @@ typedef enum PATHS_DIFFERENT = 3 /* no path is better on all dimensions */ } PathComparison; +/* mask of bits used to express the state of PathComparison */ +#define PATH_COMPARISON_MASK 3 + +static inline PathComparison +path_comparison_combine(PathComparison c1, PathComparison c2) +{ + /* safely combine path comparisons and keep them within expected range */ + return (c1 | c2) & PATH_COMPARISON_MASK; +} + +/* Hook for plugins to get control in add_paths_to_joinrel() */ +typedef PathComparison(*path_compare_hook_type) (Path *path1, Path *path2); +extern PGDLLIMPORT path_compare_hook_type path_compare_hook; + extern int compare_path_costs(Path *path1, Path *path2, CostSelector criterion); extern int compare_fractional_path_costs(Path *path1, Path *path2, -- 2.32.0 (Apple Git-132)