Skip to content

feat: Allow tree explain format width to be customizable #16827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions datafusion/common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,10 @@ config_namespace! {
/// Display format of explain. Default is "indent".
/// When set to "tree", it will print the plan in a tree-rendered format.
pub format: String, default = "indent".to_string()

/// (format=tree only) Maximum total width of the rendered tree.
/// When set to 0, the tree will have no width limit.
pub tree_maximum_render_width: usize, default = 240
}
}

Expand Down
1 change: 1 addition & 0 deletions datafusion/core/src/physical_planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,7 @@ impl DefaultPhysicalPlanner {
stringified_plans.push(StringifiedPlan::new(
FinalPhysicalPlan,
displayable(optimized_plan.as_ref())
.set_tree_maximum_render_width(config.tree_maximum_render_width)
.tree_render()
.to_string(),
));
Expand Down
39 changes: 34 additions & 5 deletions datafusion/physical-plan/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ pub struct DisplayableExecutionPlan<'a> {
show_statistics: bool,
/// If schema should be displayed. See [`Self::set_show_schema`]
show_schema: bool,
// (TreeRender) Maximum total width of the rendered tree
tree_maximum_render_width: usize,
}

impl<'a> DisplayableExecutionPlan<'a> {
Expand All @@ -131,6 +133,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
show_metrics: ShowMetrics::None,
show_statistics: false,
show_schema: false,
tree_maximum_render_width: 240,
}
}

Expand All @@ -143,6 +146,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
show_metrics: ShowMetrics::Aggregated,
show_statistics: false,
show_schema: false,
tree_maximum_render_width: 240,
}
}

Expand All @@ -155,6 +159,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
show_metrics: ShowMetrics::Full,
show_statistics: false,
show_schema: false,
tree_maximum_render_width: 240,
}
}

Expand All @@ -173,6 +178,12 @@ impl<'a> DisplayableExecutionPlan<'a> {
self
}

/// Set the maximum render width for the tree format
pub fn set_tree_maximum_render_width(mut self, width: usize) -> Self {
self.tree_maximum_render_width = width;
self
}

/// Return a `format`able structure that produces a single line
/// per node.
///
Expand Down Expand Up @@ -270,14 +281,21 @@ impl<'a> DisplayableExecutionPlan<'a> {
pub fn tree_render(&self) -> impl fmt::Display + 'a {
struct Wrapper<'a> {
plan: &'a dyn ExecutionPlan,
maximum_render_width: usize,
}
impl fmt::Display for Wrapper<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let mut visitor = TreeRenderVisitor { f };
let mut visitor = TreeRenderVisitor {
f,
maximum_render_width: self.maximum_render_width,
};
visitor.visit(self.plan)
}
}
Wrapper { plan: self.inner }
Wrapper {
plan: self.inner,
maximum_render_width: self.tree_maximum_render_width,
}
}

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

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

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

Expand Down Expand Up @@ -592,6 +611,12 @@ impl TreeRenderVisitor<'_, '_> {
y: usize,
) -> Result<(), fmt::Error> {
for x in 0..root.width {
if self.maximum_render_width > 0
&& x * Self::NODE_RENDER_WIDTH >= self.maximum_render_width
{
break;
}

if root.has_node(x, y) {
write!(self.f, "{}", Self::LTCORNER)?;
write!(
Expand Down Expand Up @@ -662,7 +687,9 @@ impl TreeRenderVisitor<'_, '_> {
// Render the actual node.
for render_y in 0..=extra_height {
for (x, _) in root.nodes.iter().enumerate().take(root.width) {
if x * Self::NODE_RENDER_WIDTH >= Self::MAXIMUM_RENDER_WIDTH {
if self.maximum_render_width > 0
&& x * Self::NODE_RENDER_WIDTH >= self.maximum_render_width
{
break;
}

Expand Down Expand Up @@ -780,7 +807,9 @@ impl TreeRenderVisitor<'_, '_> {
y: usize,
) -> Result<(), fmt::Error> {
for x in 0..=root.width {
if x * Self::NODE_RENDER_WIDTH >= Self::MAXIMUM_RENDER_WIDTH {
if self.maximum_render_width > 0
&& x * Self::NODE_RENDER_WIDTH >= self.maximum_render_width
{
break;
}
let mut has_adjacent_nodes = false;
Expand Down
Loading