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.
This commit is contained in:
parent
4b8e24b9ad
commit
5ca611841b
@ -60,6 +60,7 @@ typedef struct CustomPath
|
|||||||
{
|
{
|
||||||
Path path;
|
Path path;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
List *custom_paths;
|
||||||
List *custom_private;
|
List *custom_private;
|
||||||
const CustomPathMethods *methods;
|
const CustomPathMethods *methods;
|
||||||
} CustomPath;
|
} CustomPath;
|
||||||
@ -73,6 +74,9 @@ typedef struct CustomPath
|
|||||||
<literal>CUSTOMPATH_SUPPORT_BACKWARD_SCAN</> if the custom path can support
|
<literal>CUSTOMPATH_SUPPORT_BACKWARD_SCAN</> if the custom path can support
|
||||||
a backward scan and <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</> if it
|
a backward scan and <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</> if it
|
||||||
can support mark and restore. Both capabilities are optional.
|
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
|
<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
|
private data. Private data should be stored in a form that can be handled
|
||||||
by <literal>nodeToString</>, so that debugging routines that attempt to
|
by <literal>nodeToString</>, so that debugging routines that attempt to
|
||||||
@ -112,7 +116,8 @@ Plan *(*PlanCustomPath) (PlannerInfo *root,
|
|||||||
RelOptInfo *rel,
|
RelOptInfo *rel,
|
||||||
CustomPath *best_path,
|
CustomPath *best_path,
|
||||||
List *tlist,
|
List *tlist,
|
||||||
List *clauses);
|
List *clauses,
|
||||||
|
List *custom_plans);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
Convert a custom path to a finished plan. The return value will generally
|
Convert a custom path to a finished plan. The return value will generally
|
||||||
be a <literal>CustomScan</> object, which the callback must allocate and
|
be a <literal>CustomScan</> object, which the callback must allocate and
|
||||||
@ -145,6 +150,7 @@ typedef struct CustomScan
|
|||||||
{
|
{
|
||||||
Scan scan;
|
Scan scan;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
List *custom_plans;
|
||||||
List *custom_exprs;
|
List *custom_exprs;
|
||||||
List *custom_private;
|
List *custom_private;
|
||||||
List *custom_scan_tlist;
|
List *custom_scan_tlist;
|
||||||
@ -159,6 +165,8 @@ typedef struct CustomScan
|
|||||||
estimated costs, target lists, qualifications, and so on.
|
estimated costs, target lists, qualifications, and so on.
|
||||||
<structfield>flags</> is a bitmask with the same meaning as in
|
<structfield>flags</> is a bitmask with the same meaning as in
|
||||||
<structname>CustomPath</>.
|
<structname>CustomPath</>.
|
||||||
|
<structfield>custom_plans</> can be used to store child
|
||||||
|
<structname>Plan</> nodes.
|
||||||
<structfield>custom_exprs</> should be used to
|
<structfield>custom_exprs</> should be used to
|
||||||
store expression trees that will need to be fixed up by
|
store expression trees that will need to be fixed up by
|
||||||
<filename>setrefs.c</> and <filename>subselect.c</>, while
|
<filename>setrefs.c</> and <filename>subselect.c</>, while
|
||||||
|
@ -115,6 +115,8 @@ static void ExplainMemberNodes(List *plans, PlanState **planstates,
|
|||||||
List *ancestors, ExplainState *es);
|
List *ancestors, ExplainState *es);
|
||||||
static void ExplainSubPlans(List *plans, List *ancestors,
|
static void ExplainSubPlans(List *plans, List *ancestors,
|
||||||
const char *relationship, ExplainState *es);
|
const char *relationship, ExplainState *es);
|
||||||
|
static void ExplainCustomChildren(CustomScanState *css,
|
||||||
|
List *ancestors, ExplainState *es);
|
||||||
static void ExplainProperty(const char *qlabel, const char *value,
|
static void ExplainProperty(const char *qlabel, const char *value,
|
||||||
bool numeric, ExplainState *es);
|
bool numeric, ExplainState *es);
|
||||||
static void ExplainOpenGroup(const char *objtype, const char *labelname,
|
static void ExplainOpenGroup(const char *objtype, const char *labelname,
|
||||||
@ -1624,6 +1626,8 @@ ExplainNode(PlanState *planstate, List *ancestors,
|
|||||||
IsA(plan, BitmapAnd) ||
|
IsA(plan, BitmapAnd) ||
|
||||||
IsA(plan, BitmapOr) ||
|
IsA(plan, BitmapOr) ||
|
||||||
IsA(plan, SubqueryScan) ||
|
IsA(plan, SubqueryScan) ||
|
||||||
|
(IsA(planstate, CustomScanState) &&
|
||||||
|
((CustomScanState *) planstate)->custom_ps != NIL) ||
|
||||||
planstate->subPlan;
|
planstate->subPlan;
|
||||||
if (haschildren)
|
if (haschildren)
|
||||||
{
|
{
|
||||||
@ -1678,6 +1682,10 @@ ExplainNode(PlanState *planstate, List *ancestors,
|
|||||||
ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
|
ExplainNode(((SubqueryScanState *) planstate)->subplan, ancestors,
|
||||||
"Subquery", NULL, es);
|
"Subquery", NULL, es);
|
||||||
break;
|
break;
|
||||||
|
case T_CustomScan:
|
||||||
|
ExplainCustomChildren((CustomScanState *) planstate,
|
||||||
|
ancestors, es);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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
|
* 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.
|
* a list of unlabeled items. "data" is a list of C strings.
|
||||||
|
@ -2157,6 +2157,16 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
|
|||||||
{
|
{
|
||||||
CustomScan *cplan;
|
CustomScan *cplan;
|
||||||
RelOptInfo *rel = best_path->path.parent;
|
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
|
* Sort clauses into the best execution order, although custom-scan
|
||||||
@ -2172,7 +2182,8 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
|
|||||||
rel,
|
rel,
|
||||||
best_path,
|
best_path,
|
||||||
tlist,
|
tlist,
|
||||||
scan_clauses);
|
scan_clauses,
|
||||||
|
custom_plans);
|
||||||
Assert(IsA(cplan, CustomScan));
|
Assert(IsA(cplan, CustomScan));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1151,6 +1151,8 @@ set_customscan_references(PlannerInfo *root,
|
|||||||
CustomScan *cscan,
|
CustomScan *cscan,
|
||||||
int rtoffset)
|
int rtoffset)
|
||||||
{
|
{
|
||||||
|
ListCell *lc;
|
||||||
|
|
||||||
/* Adjust scanrelid if it's valid */
|
/* Adjust scanrelid if it's valid */
|
||||||
if (cscan->scan.scanrelid > 0)
|
if (cscan->scan.scanrelid > 0)
|
||||||
cscan->scan.scanrelid += rtoffset;
|
cscan->scan.scanrelid += rtoffset;
|
||||||
@ -1194,6 +1196,12 @@ set_customscan_references(PlannerInfo *root,
|
|||||||
fix_scan_list(root, cscan->custom_exprs, rtoffset);
|
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 */
|
/* Adjust custom_relids if needed */
|
||||||
if (rtoffset > 0)
|
if (rtoffset > 0)
|
||||||
{
|
{
|
||||||
|
@ -2373,10 +2373,27 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_CustomScan:
|
case T_CustomScan:
|
||||||
finalize_primnode((Node *) ((CustomScan *) plan)->custom_exprs,
|
{
|
||||||
&context);
|
CustomScan *cscan = (CustomScan *) plan;
|
||||||
/* We assume custom_scan_tlist cannot contain Params */
|
ListCell *lc;
|
||||||
context.paramids = bms_add_members(context.paramids, scan_params);
|
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
case T_ModifyTable:
|
case T_ModifyTable:
|
||||||
|
@ -1616,6 +1616,7 @@ typedef struct CustomScanState
|
|||||||
{
|
{
|
||||||
ScanState ss;
|
ScanState ss;
|
||||||
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
|
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
|
||||||
|
List *custom_ps; /* list of child PlanState nodes, if any */
|
||||||
const CustomExecMethods *methods;
|
const CustomExecMethods *methods;
|
||||||
} CustomScanState;
|
} CustomScanState;
|
||||||
|
|
||||||
|
@ -550,6 +550,7 @@ typedef struct CustomScan
|
|||||||
{
|
{
|
||||||
Scan scan;
|
Scan scan;
|
||||||
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
|
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_exprs; /* expressions that custom code may evaluate */
|
||||||
List *custom_private; /* private data for custom code */
|
List *custom_private; /* private data for custom code */
|
||||||
List *custom_scan_tlist; /* optional tlist describing scan
|
List *custom_scan_tlist; /* optional tlist describing scan
|
||||||
|
@ -929,7 +929,8 @@ typedef struct CustomPathMethods
|
|||||||
RelOptInfo *rel,
|
RelOptInfo *rel,
|
||||||
struct CustomPath *best_path,
|
struct CustomPath *best_path,
|
||||||
List *tlist,
|
List *tlist,
|
||||||
List *clauses);
|
List *clauses,
|
||||||
|
List *custom_plans);
|
||||||
/* Optional: print additional fields besides "private" */
|
/* Optional: print additional fields besides "private" */
|
||||||
void (*TextOutCustomPath) (StringInfo str,
|
void (*TextOutCustomPath) (StringInfo str,
|
||||||
const struct CustomPath *node);
|
const struct CustomPath *node);
|
||||||
@ -939,6 +940,7 @@ typedef struct CustomPath
|
|||||||
{
|
{
|
||||||
Path path;
|
Path path;
|
||||||
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
|
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
|
||||||
|
List *custom_paths; /* list of child Path nodes, if any */
|
||||||
List *custom_private;
|
List *custom_private;
|
||||||
const CustomPathMethods *methods;
|
const CustomPathMethods *methods;
|
||||||
} CustomPath;
|
} CustomPath;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user