]> granicus.if.org Git - postgresql/commitdiff
Improve handling of CustomPath/CustomPlan(State) children.
authorRobert Haas <rhaas@postgresql.org>
Fri, 26 Jun 2015 13:40:47 +0000 (09:40 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 26 Jun 2015 13:40:47 +0000 (09:40 -0400)
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
src/backend/commands/explain.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/plan/subselect.c
src/include/nodes/execnodes.h
src/include/nodes/plannodes.h
src/include/nodes/relation.h

index 62a8a3305bb29a5e7e405a8a1c5b391e1c8299eb..dc327b11b21b860a89b9ce1d8fa913c8e6b521de 100644 (file)
@@ -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
     <literal>CUSTOMPATH_SUPPORT_BACKWARD_SCAN</> if the custom path can support
     a backward scan and <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</> if it
     can support mark and restore.  Both capabilities are optional.
+    An optional <structfield>custom_paths</> is a list of <structname>Path</>
+    nodes used by this custom-path node; these will be transformed into
+    <structname>Plan</> nodes by planner.
     <structfield>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 <literal>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);
 </programlisting>
     Convert a custom path to a finished plan.  The return value will generally
     be a <literal>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.
     <structfield>flags</> is a bitmask with the same meaning as in
     <structname>CustomPath</>.
+    <structfield>custom_plans</> can be used to store child
+    <structname>Plan</> nodes.
     <structfield>custom_exprs</> should be used to
     store expression trees that will need to be fixed up by
     <filename>setrefs.c</> and <filename>subselect.c</>, while
index a82c6ff7b4de9241e56aa1f1ea1a27f001e75e9e..0d1ecc2a3edbb85276c3e707ad7b90840e5fd35f 100644 (file)
@@ -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.
index a3482def6435335ae9c81af41e1ae4728f3c4a66..dc2dcbf93f7a1dfc18452b9f2a7195214d75392a 100644 (file)
@@ -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));
 
        /*
index a7f65dd529f2cfa1137a4080d864d0d15e402a08..c0641a7cfb0f22d1b42729925f65fc83e0f34171 100644 (file)
@@ -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)
        {
index f80abb494c7e1b7470e313859929044a53f71a18..4708b87f330b6145505afeac4a0be5eb00d441cb 100644 (file)
@@ -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:
index db5bd7faf047027e2b29eae2068afd5d1db23df6..541ee187356850c69da8e26fc2615cb968f1a62d 100644 (file)
@@ -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;
 
index d967219c0b52cf29d66be95bef85a7918e5762db..5f538f3e8ccb5a9298af8d2a836d3c08fc8d611d 100644 (file)
@@ -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
index 33b08745702adf4d95f8f7b3ea56595659d771d6..cb916ea8e14e923fb772334b40bf3f166ca5e7d6 100644 (file)
@@ -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;