Skip to content

Commit a0ce581

Browse files
authored
feat: Allow tree explain format width to be customizable (#16827)
- Also fix a bug in the tree format.
1 parent 4d1db63 commit a0ce581

File tree

6 files changed

+273
-5
lines changed

6 files changed

+273
-5
lines changed

datafusion/common/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,10 @@ config_namespace! {
840840
/// Display format of explain. Default is "indent".
841841
/// When set to "tree", it will print the plan in a tree-rendered format.
842842
pub format: String, default = "indent".to_string()
843+
844+
/// (format=tree only) Maximum total width of the rendered tree.
845+
/// When set to 0, the tree will have no width limit.
846+
pub tree_maximum_render_width: usize, default = 240
843847
}
844848
}
845849

datafusion/core/src/physical_planner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,7 @@ impl DefaultPhysicalPlanner {
18561856
stringified_plans.push(StringifiedPlan::new(
18571857
FinalPhysicalPlan,
18581858
displayable(optimized_plan.as_ref())
1859+
.set_tree_maximum_render_width(config.tree_maximum_render_width)
18591860
.tree_render()
18601861
.to_string(),
18611862
));

datafusion/physical-plan/src/display.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ pub struct DisplayableExecutionPlan<'a> {
120120
show_statistics: bool,
121121
/// If schema should be displayed. See [`Self::set_show_schema`]
122122
show_schema: bool,
123+
// (TreeRender) Maximum total width of the rendered tree
124+
tree_maximum_render_width: usize,
123125
}
124126

125127
impl<'a> DisplayableExecutionPlan<'a> {
@@ -131,6 +133,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
131133
show_metrics: ShowMetrics::None,
132134
show_statistics: false,
133135
show_schema: false,
136+
tree_maximum_render_width: 240,
134137
}
135138
}
136139

@@ -143,6 +146,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
143146
show_metrics: ShowMetrics::Aggregated,
144147
show_statistics: false,
145148
show_schema: false,
149+
tree_maximum_render_width: 240,
146150
}
147151
}
148152

@@ -155,6 +159,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
155159
show_metrics: ShowMetrics::Full,
156160
show_statistics: false,
157161
show_schema: false,
162+
tree_maximum_render_width: 240,
158163
}
159164
}
160165

@@ -173,6 +178,12 @@ impl<'a> DisplayableExecutionPlan<'a> {
173178
self
174179
}
175180

181+
/// Set the maximum render width for the tree format
182+
pub fn set_tree_maximum_render_width(mut self, width: usize) -> Self {
183+
self.tree_maximum_render_width = width;
184+
self
185+
}
186+
176187
/// Return a `format`able structure that produces a single line
177188
/// per node.
178189
///
@@ -270,14 +281,21 @@ impl<'a> DisplayableExecutionPlan<'a> {
270281
pub fn tree_render(&self) -> impl fmt::Display + 'a {
271282
struct Wrapper<'a> {
272283
plan: &'a dyn ExecutionPlan,
284+
maximum_render_width: usize,
273285
}
274286
impl fmt::Display for Wrapper<'_> {
275287
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
276-
let mut visitor = TreeRenderVisitor { f };
288+
let mut visitor = TreeRenderVisitor {
289+
f,
290+
maximum_render_width: self.maximum_render_width,
291+
};
277292
visitor.visit(self.plan)
278293
}
279294
}
280-
Wrapper { plan: self.inner }
295+
Wrapper {
296+
plan: self.inner,
297+
maximum_render_width: self.tree_maximum_render_width,
298+
}
281299
}
282300

283301
/// Return a single-line summary of the root of the plan
@@ -540,6 +558,8 @@ impl ExecutionPlanVisitor for GraphvizVisitor<'_, '_> {
540558
struct TreeRenderVisitor<'a, 'b> {
541559
/// Write to this formatter
542560
f: &'a mut Formatter<'b>,
561+
/// Maximum total width of the rendered tree
562+
maximum_render_width: usize,
543563
}
544564

545565
impl TreeRenderVisitor<'_, '_> {
@@ -557,7 +577,6 @@ impl TreeRenderVisitor<'_, '_> {
557577
const HORIZONTAL: &'static str = "─"; // Horizontal line
558578

559579
// TODO: Make these variables configurable.
560-
const MAXIMUM_RENDER_WIDTH: usize = 240; // Maximum total width of the rendered tree
561580
const NODE_RENDER_WIDTH: usize = 29; // Width of each node's box
562581
const MAX_EXTRA_LINES: usize = 30; // Maximum number of extra info lines per node
563582

@@ -592,6 +611,12 @@ impl TreeRenderVisitor<'_, '_> {
592611
y: usize,
593612
) -> Result<(), fmt::Error> {
594613
for x in 0..root.width {
614+
if self.maximum_render_width > 0
615+
&& x * Self::NODE_RENDER_WIDTH >= self.maximum_render_width
616+
{
617+
break;
618+
}
619+
595620
if root.has_node(x, y) {
596621
write!(self.f, "{}", Self::LTCORNER)?;
597622
write!(
@@ -662,7 +687,9 @@ impl TreeRenderVisitor<'_, '_> {
662687
// Render the actual node.
663688
for render_y in 0..=extra_height {
664689
for (x, _) in root.nodes.iter().enumerate().take(root.width) {
665-
if x * Self::NODE_RENDER_WIDTH >= Self::MAXIMUM_RENDER_WIDTH {
690+
if self.maximum_render_width > 0
691+
&& x * Self::NODE_RENDER_WIDTH >= self.maximum_render_width
692+
{
666693
break;
667694
}
668695

@@ -780,7 +807,9 @@ impl TreeRenderVisitor<'_, '_> {
780807
y: usize,
781808
) -> Result<(), fmt::Error> {
782809
for x in 0..=root.width {
783-
if x * Self::NODE_RENDER_WIDTH >= Self::MAXIMUM_RENDER_WIDTH {
810+
if self.maximum_render_width > 0
811+
&& x * Self::NODE_RENDER_WIDTH >= self.maximum_render_width
812+
{
784813
break;
785814
}
786815
let mut has_adjacent_nodes = false;

0 commit comments

Comments
 (0)