From 5ca611841bcd37c7ee8448c46c8398ef8d8edcc4 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 26 Jun 2015 09:40:47 -0400 Subject: [PATCH] Improve handling of CustomPath/CustomPlan(State) children. Allow CustomPath to have a list of paths, CustomPlan a list of plans, and CustomPlanState a list of planstates known to the core system, so that custom path/plan providers can more reasonably use this infrastructure for nodes with multiple children. KaiGai Kohei, per a design suggestion from Tom Lane, with some further kibitzing by me. --- doc/src/sgml/custom-scan.sgml | 10 +++++++++- src/backend/commands/explain.c | 22 ++++++++++++++++++++++ src/backend/optimizer/plan/createplan.c | 13 ++++++++++++- src/backend/optimizer/plan/setrefs.c | 8 ++++++++ src/backend/optimizer/plan/subselect.c | 25 +++++++++++++++++++++---- src/include/nodes/execnodes.h | 1 + src/include/nodes/plannodes.h | 1 + src/include/nodes/relation.h | 4 +++- 8 files changed, 77 insertions(+), 7 deletions(-) diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml index 62a8a3305b..dc327b11b2 100644 --- a/doc/src/sgml/custom-scan.sgml +++ b/doc/src/sgml/custom-scan.sgml @@ -60,6 +60,7 @@ typedef struct CustomPath { Path path; uint32 flags; + List *custom_paths; List *custom_private; const CustomPathMethods *methods; } CustomPath; @@ -73,6 +74,9 @@ typedef struct CustomPath CUSTOMPATH_SUPPORT_BACKWARD_SCAN if the custom path can support a backward scan and CUSTOMPATH_SUPPORT_MARK_RESTORE if it can support mark and restore. Both capabilities are optional. + An optional custom_paths is a list of Path + nodes used by this custom-path node; these will be transformed into + Plan nodes by planner. custom_private can be used to store the custom path's private data. Private data should be stored in a form that can be handled by nodeToString, so that debugging routines that attempt to @@ -112,7 +116,8 @@ Plan *(*PlanCustomPath) (PlannerInfo *root, RelOptInfo *rel, CustomPath *best_path, List *tlist, - List *clauses); + List *clauses, + List *custom_plans); Convert a custom path to a finished plan. The return value will generally be a CustomScan object, which the callback must allocate and @@ -145,6 +150,7 @@ typedef struct CustomScan { Scan scan; uint32 flags; + List *custom_plans; List *custom_exprs; List *custom_private; List *custom_scan_tlist; @@ -159,6 +165,8 @@ typedef struct CustomScan estimated costs, target lists, qualifications, and so on. flags is a bitmask with the same meaning as in CustomPath. + custom_plans can be used to store child + Plan nodes. custom_exprs should be used to store expression trees that will need to be fixed up by setrefs.c and subselect.c, while diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a82c6ff7b4..0d1ecc2a3e 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -115,6 +115,8 @@ static void ExplainMemberNodes(List *plans, PlanState **planstates, List *ancestors, ExplainState *es); static void ExplainSubPlans(List *plans, List *ancestors, const char *relationship, ExplainState *es); +static void ExplainCustomChildren(CustomScanState *css, + List *ancestors, ExplainState *es); static void ExplainProperty(const char *qlabel, const char *value, bool numeric, ExplainState *es); static void ExplainOpenGroup(const char *objtype, const char *labelname, @@ -1624,6 +1626,8 @@ ExplainNode(PlanState *planstate, List *ancestors, IsA(plan, BitmapAnd) || IsA(plan, BitmapOr) || IsA(plan, SubqueryScan) || + (IsA(planstate, CustomScanState) && + ((CustomScanState *) planstate)->custom_ps != NIL) || planstate->subPlan; if (haschildren) { @@ -1678,6 +1682,10 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors, "Subquery", NULL, es); break; + case T_CustomScan: + ExplainCustomChildren((CustomScanState *) planstate, + ancestors, es); + break; default: break; } @@ -2647,6 +2655,20 @@ ExplainSubPlans(List *plans, List *ancestors, } } +/* + * Explain a list of children of a CustomScan. + */ +static void +ExplainCustomChildren(CustomScanState *css, List *ancestors, ExplainState *es) +{ + ListCell *cell; + const char *label = + (list_length(css->custom_ps) != 1 ? "children" : "child"); + + foreach (cell, css->custom_ps) + ExplainNode((PlanState *) lfirst(cell), ancestors, label, NULL, es); +} + /* * Explain a property, such as sort keys or targets, that takes the form of * a list of unlabeled items. "data" is a list of C strings. diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a3482def64..dc2dcbf93f 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -2157,6 +2157,16 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path, { CustomScan *cplan; RelOptInfo *rel = best_path->path.parent; + List *custom_plans = NIL; + ListCell *lc; + + /* Recursively transform child paths. */ + foreach (lc, best_path->custom_paths) + { + Plan *plan = create_plan_recurse(root, (Path *) lfirst(lc)); + + custom_plans = lappend(custom_plans, plan); + } /* * Sort clauses into the best execution order, although custom-scan @@ -2172,7 +2182,8 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path, rel, best_path, tlist, - scan_clauses); + scan_clauses, + custom_plans); Assert(IsA(cplan, CustomScan)); /* diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index a7f65dd529..c0641a7cfb 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1151,6 +1151,8 @@ set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset) { + ListCell *lc; + /* Adjust scanrelid if it's valid */ if (cscan->scan.scanrelid > 0) cscan->scan.scanrelid += rtoffset; @@ -1194,6 +1196,12 @@ set_customscan_references(PlannerInfo *root, fix_scan_list(root, cscan->custom_exprs, rtoffset); } + /* Adjust child plan-nodes recursively, if needed */ + foreach (lc, cscan->custom_plans) + { + lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset); + } + /* Adjust custom_relids if needed */ if (rtoffset > 0) { diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index f80abb494c..4708b87f33 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2373,10 +2373,27 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, break; case T_CustomScan: - finalize_primnode((Node *) ((CustomScan *) plan)->custom_exprs, - &context); - /* We assume custom_scan_tlist cannot contain Params */ - context.paramids = bms_add_members(context.paramids, scan_params); + { + CustomScan *cscan = (CustomScan *) plan; + ListCell *lc; + + finalize_primnode((Node *) cscan->custom_exprs, + &context); + /* We assume custom_scan_tlist cannot contain Params */ + context.paramids = + bms_add_members(context.paramids, scan_params); + + /* child nodes if any */ + foreach (lc, cscan->custom_plans) + { + context.paramids = + bms_add_members(context.paramids, + finalize_plan(root, + (Plan *) lfirst(lc), + valid_params, + scan_params)); + } + } break; case T_ModifyTable: diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index db5bd7faf0..541ee18735 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1616,6 +1616,7 @@ typedef struct CustomScanState { ScanState ss; uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */ + List *custom_ps; /* list of child PlanState nodes, if any */ const CustomExecMethods *methods; } CustomScanState; diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index d967219c0b..5f538f3e8c 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -550,6 +550,7 @@ typedef struct CustomScan { Scan scan; uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */ + List *custom_plans; /* list of Plan nodes, if any */ List *custom_exprs; /* expressions that custom code may evaluate */ List *custom_private; /* private data for custom code */ List *custom_scan_tlist; /* optional tlist describing scan diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 33b0874570..cb916ea8e1 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -929,7 +929,8 @@ typedef struct CustomPathMethods RelOptInfo *rel, struct CustomPath *best_path, List *tlist, - List *clauses); + List *clauses, + List *custom_plans); /* Optional: print additional fields besides "private" */ void (*TextOutCustomPath) (StringInfo str, const struct CustomPath *node); @@ -939,6 +940,7 @@ typedef struct CustomPath { Path path; uint32 flags; /* mask of CUSTOMPATH_* flags, see above */ + List *custom_paths; /* list of child Path nodes, if any */ List *custom_private; const CustomPathMethods *methods; } CustomPath;