diff options
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/path/allpaths.c | 3 | ||||
| -rw-r--r-- | src/backend/optimizer/path/costsize.c | 2 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 60 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 26 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 21 | ||||
| -rw-r--r-- | src/backend/optimizer/util/pathnode.c | 47 |
6 files changed, 153 insertions, 6 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c81efe93a47..8b42e36b6d4 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -402,6 +402,9 @@ 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); } diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 0cdb7905a2f..659daa20265 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -2266,7 +2266,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, * it off does not entitle us to deliver an invalid plan. */ else if (innersortkeys == NIL && - !ExecSupportsMarkRestore(inner_path->pathtype)) + !ExecSupportsMarkRestore(inner_path)) path->materialize_inner = true; /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 4b641a2ca1f..8d9237ccac4 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -77,13 +77,15 @@ static WorkTableScan *create_worktablescan_plan(PlannerInfo *root, Path *best_pa List *tlist, List *scan_clauses); static ForeignScan *create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, List *tlist, List *scan_clauses); +static Plan *create_customscan_plan(PlannerInfo *root, + CustomPath *best_path, + List *tlist, List *scan_clauses); static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path, Plan *outer_plan, Plan *inner_plan); static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path, Plan *outer_plan, Plan *inner_plan); static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path, Plan *outer_plan, Plan *inner_plan); -static Node *replace_nestloop_params(PlannerInfo *root, Node *expr); static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root); static void process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params); @@ -233,6 +235,7 @@ create_plan_recurse(PlannerInfo *root, Path *best_path) case T_CteScan: case T_WorkTableScan: case T_ForeignScan: + case T_CustomScan: plan = create_scan_plan(root, best_path); break; case T_HashJoin: @@ -409,6 +412,13 @@ create_scan_plan(PlannerInfo *root, Path *best_path) scan_clauses); break; + case T_CustomScan: + plan = create_customscan_plan(root, + (CustomPath *) best_path, + tlist, + scan_clauses); + break; + default: elog(ERROR, "unrecognized node type: %d", (int) best_path->pathtype); @@ -1072,6 +1082,52 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path) return plan; } +/* + * create_custom_plan + * + * Transform a CustomPath into a Plan. + */ +static Plan * +create_customscan_plan(PlannerInfo *root, CustomPath *best_path, + List *tlist, List *scan_clauses) +{ + Plan *plan; + RelOptInfo *rel = best_path->path.parent; + + /* + * Right now, all we can support is CustomScan node which is associated + * with a particular base relation to be scanned. + */ + Assert(rel && rel->reloptkind == RELOPT_BASEREL); + + /* + * Sort clauses into the best execution order, although custom-scan + * provider can reorder them again. + */ + scan_clauses = order_qual_clauses(root, scan_clauses); + + /* + * Create a CustomScan (or its inheritance) node according to + * the supplied CustomPath. + */ + plan = best_path->methods->PlanCustomPath(root, rel, best_path, tlist, + scan_clauses); + + /* + * NOTE: unlike create_foreignscan_plan(), it is responsibility of + * the custom plan provider to replace outer-relation variables + * with nestloop params, because we cannot know how many expression + * trees are held in the private fields. + */ + + /* + * Copy cost data from Path to Plan; no need to make custom-plan + * providers do this + */ + copy_path_costsize(plan, &best_path->path); + + return plan; +} /***************************************************************************** * @@ -2540,7 +2596,7 @@ create_hashjoin_plan(PlannerInfo *root, * root->curOuterRels are replaced by Params, and entries are added to * root->curOuterParams if not already present. */ -static Node * +Node * replace_nestloop_params(PlannerInfo *root, Node *expr) { /* No setup needed for tree walk, so away we go */ diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 9ddc8adcf98..bbc68a05a6c 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -94,7 +94,6 @@ static Plan *set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset); static bool trivial_subqueryscan(SubqueryScan *plan); -static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset); static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context); static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context); static void set_join_references(PlannerInfo *root, Join *join, int rtoffset); @@ -579,6 +578,27 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } break; + case T_CustomScan: + { + CustomScan *cscan = (CustomScan *) plan; + + cscan->scan.scanrelid += rtoffset; + cscan->scan.plan.targetlist = + fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset); + cscan->scan.plan.qual = + fix_scan_list(root, cscan->scan.plan.qual, rtoffset); + /* + * The core implementation applies the routine to fixup + * varno on the target-list and scan qualifier. + * If custom-scan has additional expression nodes on its + * private fields, it has to apply same fixup on them. + * Otherwise, the custom-plan provider can skip this callback. + */ + if (cscan->methods->SetCustomScanRef) + cscan->methods->SetCustomScanRef(root, cscan, rtoffset); + } + break; + case T_NestLoop: case T_MergeJoin: case T_HashJoin: @@ -1063,7 +1083,7 @@ copyVar(Var *var) * We assume it's okay to update opcode info in-place. So this could possibly * scribble on the planner's input data structures, but it's OK. */ -static void +void fix_expr_common(PlannerInfo *root, Node *node) { /* We assume callers won't call us on a NULL pointer */ @@ -1161,7 +1181,7 @@ fix_param_node(PlannerInfo *root, Param *p) * looking up operator opcode info for OpExpr and related nodes, * and adding OIDs from regclass Const nodes into root->glob->relationOids. */ -static Node * +Node * fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset) { fix_scan_expr_context context; diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 3e7dc851579..4200ec0a5a7 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2283,6 +2283,27 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, context.paramids = bms_add_members(context.paramids, scan_params); break; + case T_CustomScan: + { + CustomScan *custom_scan = (CustomScan *) plan; + + context.paramids = bms_add_members(context.paramids, + scan_params); + /* + * custom-scan provider is responsible to apply + * finalize_primnode() on the expression node of + * its private fields, but no need to apply it + * on the tlist and qual of Plan node because it + * is already done above. + */ + if (custom_scan->methods->FinalizeCustomScan) + custom_scan->methods->FinalizeCustomScan(root, + custom_scan, + finalize_primnode, + (void *)&context); + } + break; + case T_ModifyTable: { ModifyTable *mtplan = (ModifyTable *) plan; diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 319e8b2c379..6f1c6cfb2aa 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -27,6 +27,7 @@ #include "optimizer/var.h" #include "parser/parsetree.h" #include "utils/lsyscache.h" +#include "utils/memutils.h" #include "utils/selfuncs.h" @@ -1926,3 +1927,49 @@ 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(CustomPathMethods *cpp_methods) +{ + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + custom_path_providers = lappend(custom_path_providers, 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); + } +} |
