summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c3
-rw-r--r--src/backend/optimizer/path/costsize.c2
-rw-r--r--src/backend/optimizer/plan/createplan.c60
-rw-r--r--src/backend/optimizer/plan/setrefs.c26
-rw-r--r--src/backend/optimizer/plan/subselect.c21
-rw-r--r--src/backend/optimizer/util/pathnode.c47
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);
+ }
+}