diff options
| author | Tom Lane | 2014-11-21 23:21:46 +0000 |
|---|---|---|
| committer | Tom Lane | 2014-11-21 23:21:46 +0000 |
| commit | 447770404cce5ce86174fa4809784c4e5d0a0a76 (patch) | |
| tree | 286179c879751edbebffd9fe314c6878a0559edb /src/backend | |
| parent | c2ea2285e978d9289084846a3343cef7d261d880 (diff) | |
Rearrange CustomScan API.
Make it work more like FDW plans do: instead of assuming that there are
expressions in a CustomScan plan node that the core code doesn't know
about, insist that all subexpressions that need planner attention be in
a "custom_exprs" list in the Plan representation. (Of course, the
custom plugin can break the list apart again at executor initialization.)
This lets us revert the parts of the patch that exposed setrefs.c and
subselect.c processing to the outside world.
Also revert the GetSpecialCustomVar stuff in ruleutils.c; that concept
may work in future, but it's far from fully baked right now.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/nodes/copyfuncs.c | 21 | ||||
| -rw-r--r-- | src/backend/nodes/outfuncs.c | 16 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 49 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 27 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 21 | ||||
| -rw-r--r-- | src/backend/utils/adt/ruleutils.c | 70 |
6 files changed, 70 insertions, 134 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index e76b5b3f633..6b1bf7be19d 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -603,17 +603,24 @@ _copyForeignScan(const ForeignScan *from) static CustomScan * _copyCustomScan(const CustomScan *from) { - CustomScan *newnode; - - newnode = from->methods->CopyCustomScan(from); - Assert(nodeTag(newnode) == nodeTag(from)); + CustomScan *newnode = makeNode(CustomScan); + /* + * copy node superclass fields + */ CopyScanFields((const Scan *) from, (Scan *) newnode); + + /* + * copy remainder of node + */ COPY_SCALAR_FIELD(flags); + COPY_NODE_FIELD(custom_exprs); + COPY_NODE_FIELD(custom_private); + /* - * NOTE: The method field of CustomScan is required to be a pointer - * to a static table of callback functions. So, we don't copy the - * table itself, just reference the original one. + * NOTE: The method field of CustomScan is required to be a pointer to a + * static table of callback functions. So we don't copy the table itself, + * just reference the original one. */ COPY_SCALAR_FIELD(methods); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index cdf1e7ece1f..ca9bd4f7c7f 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -569,10 +569,14 @@ _outCustomScan(StringInfo str, const CustomScan *node) WRITE_NODE_TYPE("CUSTOMSCAN"); _outScanInfo(str, (const Scan *) node); + WRITE_UINT_FIELD(flags); - appendStringInfo(str, " :methods"); + WRITE_NODE_FIELD(custom_exprs); + WRITE_NODE_FIELD(custom_private); + appendStringInfoString(str, " :methods "); _outToken(str, node->methods->CustomName); - node->methods->TextOutCustomScan(str, node); + if (node->methods->TextOutCustomScan) + node->methods->TextOutCustomScan(str, node); } static void @@ -1600,11 +1604,15 @@ static void _outCustomPath(StringInfo str, const CustomPath *node) { WRITE_NODE_TYPE("CUSTOMPATH"); + _outPathInfo(str, (const Path *) node); + WRITE_UINT_FIELD(flags); - appendStringInfo(str, " :methods"); + WRITE_NODE_FIELD(custom_private); + appendStringInfoString(str, " :methods "); _outToken(str, node->methods->CustomName); - node->methods->TextOutCustomPath(str, node); + if (node->methods->TextOutCustomPath) + node->methods->TextOutCustomPath(str, node); } static void diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index e6bd4c326ca..fa478025c1a 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -77,7 +77,7 @@ 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, +static CustomScan *create_customscan_plan(PlannerInfo *root, CustomPath *best_path, List *tlist, List *scan_clauses); static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path, @@ -86,6 +86,7 @@ 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); @@ -413,10 +414,10 @@ create_scan_plan(PlannerInfo *root, Path *best_path) break; case T_CustomScan: - plan = create_customscan_plan(root, - (CustomPath *) best_path, - tlist, - scan_clauses); + plan = (Plan *) create_customscan_plan(root, + (CustomPath *) best_path, + tlist, + scan_clauses); break; default: @@ -2022,11 +2023,11 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, * * Transform a CustomPath into a Plan. */ -static Plan * +static CustomScan * create_customscan_plan(PlannerInfo *root, CustomPath *best_path, List *tlist, List *scan_clauses) { - Plan *plan; + CustomScan *cplan; RelOptInfo *rel = best_path->path.parent; /* @@ -2045,23 +2046,35 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path, * Invoke custom plan provider to create the Plan node represented by the * CustomPath. */ - plan = best_path->methods->PlanCustomPath(root, rel, best_path, tlist, - scan_clauses); + cplan = (CustomScan *) best_path->methods->PlanCustomPath(root, + rel, + best_path, + tlist, + scan_clauses); + Assert(IsA(cplan, CustomScan)); /* - * NOTE: unlike create_foreignscan_plan(), it is the responsibility of the - * custom plan provider to replace outer-relation variables with nestloop - * params, because we cannot know what expression trees may be held in - * private fields. + * Copy cost data from Path to Plan; no need to make custom-plan providers + * do this */ + copy_path_costsize(&cplan->scan.plan, &best_path->path); /* - * Copy cost data from Path to Plan; no need to make custom-plan providers - * do this + * Replace any outer-relation variables with nestloop params in the qual + * and custom_exprs expressions. We do this last so that the custom-plan + * provider doesn't have to be involved. (Note that parts of custom_exprs + * could have come from join clauses, so doing this beforehand on the + * scan_clauses wouldn't work.) */ - copy_path_costsize(plan, &best_path->path); + if (best_path->path.param_info) + { + cplan->scan.plan.qual = (List *) + replace_nestloop_params(root, (Node *) cplan->scan.plan.qual); + cplan->custom_exprs = (List *) + replace_nestloop_params(root, (Node *) cplan->custom_exprs); + } - return plan; + return cplan; } @@ -2598,7 +2611,7 @@ create_hashjoin_plan(PlannerInfo *root, * root->curOuterRels are replaced by Params, and entries are added to * root->curOuterParams if not already present. */ -Node * +static 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 e42972750b9..e630d0b6d81 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -94,6 +94,7 @@ 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); @@ -580,23 +581,15 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) case T_CustomScan: { - CustomScan *cscan = (CustomScan *) plan; + CustomScan *splan = (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); + splan->scan.scanrelid += rtoffset; + splan->scan.plan.targetlist = + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); + splan->scan.plan.qual = + fix_scan_list(root, splan->scan.plan.qual, rtoffset); + splan->custom_exprs = + fix_scan_list(root, splan->custom_exprs, rtoffset); } break; @@ -1182,7 +1175,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. */ -Node * +static 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 4200ec0a5a7..9111b56e92a 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2284,24 +2284,9 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_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); - } + finalize_primnode((Node *) ((CustomScan *) plan)->custom_exprs, + &context); + context.paramids = bms_add_members(context.paramids, scan_params); break; case T_ModifyTable: diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index bf4e81f554a..24ade6cc201 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5493,26 +5493,6 @@ get_utility_query_def(Query *query, deparse_context *context) } } -/* - * GetSpecialCustomVar - * - * If a custom-scan provider uses a special varnode, this function will be - * called when deparsing; it should return an Expr node to be reversed-listed - * in lieu of the special Var. - */ -static Node * -GetSpecialCustomVar(CustomScanState *css, Var *varnode, PlanState **child_ps) -{ - Assert(IsA(css, CustomScanState)); - Assert(IS_SPECIAL_VARNO(varnode->varno)); - - if (!css->methods->GetSpecialCustomVar) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("%s does not support special varno reference", - css->methods->CustomName))); - return (Node *) css->methods->GetSpecialCustomVar(css, varnode, child_ps); -} /* * Display a Var appropriately. @@ -5542,8 +5522,6 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context) int netlevelsup; deparse_namespace *dpns; deparse_columns *colinfo; - PlanState *child_ps = NULL; - Node *expr; char *refname; char *attname; @@ -5568,29 +5546,6 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context) colinfo = deparse_columns_fetch(var->varno, dpns); attnum = var->varattno; } - else if (IS_SPECIAL_VARNO(var->varno) && - IsA(dpns->planstate, CustomScanState) && - (expr = GetSpecialCustomVar((CustomScanState *) dpns->planstate, - var, &child_ps)) != NULL) - { - deparse_namespace save_dpns; - - if (child_ps) - push_child_plan(dpns, child_ps, &save_dpns); - /* - * Force parentheses because our caller probably assumed a Var is a - * simple expression. - */ - if (!IsA(expr, Var)) - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) expr, context, true); - if (!IsA(expr, Var)) - appendStringInfoChar(buf, ')'); - - if (child_ps) - pop_child_plan(dpns, &save_dpns); - return NULL; - } else if (var->varno == OUTER_VAR && dpns->outer_tlist) { TargetEntry *tle; @@ -5805,7 +5760,6 @@ get_name_for_var_field(Var *var, int fieldno, AttrNumber attnum; int netlevelsup; deparse_namespace *dpns; - PlanState *child_ps = NULL; TupleDesc tupleDesc; Node *expr; @@ -5880,30 +5834,6 @@ get_name_for_var_field(Var *var, int fieldno, rte = rt_fetch(var->varno, dpns->rtable); attnum = var->varattno; } - else if (IS_SPECIAL_VARNO(var->varno) && - IsA(dpns->planstate, CustomScanState) && - (expr = GetSpecialCustomVar((CustomScanState *) dpns->planstate, - var, &child_ps)) != NULL) - { - StringInfo saved = context->buf; - StringInfoData temp; - deparse_namespace save_dpns; - - initStringInfo(&temp); - context->buf = &temp; - - if (child_ps) - push_child_plan(dpns, child_ps, &save_dpns); - if (!IsA(expr, Var)) - appendStringInfoChar(context->buf, '('); - get_rule_expr((Node *) expr, context, true); - if (!IsA(expr, Var)) - appendStringInfoChar(context->buf, ')'); - if (child_ps) - pop_child_plan(dpns, &save_dpns); - context->buf = saved; - return temp.data; - } else if (var->varno == OUTER_VAR && dpns->outer_tlist) { TargetEntry *tle; |
