diff --git a/datafusion/physical-plan/src/display.rs b/datafusion/physical-plan/src/display.rs index 98ba3e1fd9a0..59d5e60ca939 100644 --- a/datafusion/physical-plan/src/display.rs +++ b/datafusion/physical-plan/src/display.rs @@ -52,14 +52,18 @@ pub enum DisplayFormatType { /// information for understanding a plan. It should NOT contain the same level /// of detail information as the [`Self::Default`] format. /// - /// In this mode, each line contains a key=value pair. - /// Everything before the first `=` is treated as the key, and everything after the - /// first `=` is treated as the value. + /// In this mode, each line has one of two formats: + /// + /// 1. A string without a `=`, which is printed in its own line + /// + /// 2. A string with a `=` that is treated as a `key=value pair`. Everything + /// before the first `=` is treated as the key, and everything after the + /// first `=` is treated as the value. /// /// For example, if the output of `TreeRender` is this: /// ```text + /// Parquet /// partition_sizes=[1] - /// partitions=1 /// ``` /// /// It is rendered in the center of a box in the following way: @@ -69,7 +73,7 @@ pub enum DisplayFormatType { /// │ DataSourceExec │ /// │ -------------------- │ /// │ partition_sizes: [1] │ - /// │ partitions: 1 │ + /// │ Parquet │ /// └───────────────────────────┘ /// ``` TreeRender, @@ -857,22 +861,24 @@ impl TreeRenderVisitor<'_, '_> { let sorted_extra_info: BTreeMap<_, _> = extra_info.iter().collect(); for (key, value) in sorted_extra_info { let mut str = Self::remove_padding(value); - if str.is_empty() { - continue; - } let mut is_inlined = false; let available_width = Self::NODE_RENDER_WIDTH - 7; let total_size = key.len() + str.len() + 2; let is_multiline = str.contains('\n'); - if !is_multiline && total_size < available_width { + + if str.is_empty() { + str = key.to_string(); + } else if !is_multiline && total_size < available_width { str = format!("{}: {}", key, str); is_inlined = true; } else { str = format!("{}:\n{}", key, str); } + if is_inlined && was_inlined { requires_padding = false; } + if requires_padding { result.push(String::new()); } diff --git a/datafusion/physical-plan/src/joins/cross_join.rs b/datafusion/physical-plan/src/joins/cross_join.rs index e0998862bdd8..35c8961065a5 100644 --- a/datafusion/physical-plan/src/joins/cross_join.rs +++ b/datafusion/physical-plan/src/joins/cross_join.rs @@ -237,11 +237,13 @@ impl DisplayAs for CrossJoinExec { f: &mut std::fmt::Formatter, ) -> std::fmt::Result { match t { - DisplayFormatType::Default - | DisplayFormatType::Verbose - | DisplayFormatType::TreeRender => { + DisplayFormatType::Default | DisplayFormatType::Verbose => { write!(f, "CrossJoinExec") } + DisplayFormatType::TreeRender => { + // no extra info to display + Ok(()) + } } } } diff --git a/datafusion/physical-plan/src/render_tree.rs b/datafusion/physical-plan/src/render_tree.rs index 5f8da76a89b4..f86e4c55e7b0 100644 --- a/datafusion/physical-plan/src/render_tree.rs +++ b/datafusion/physical-plan/src/render_tree.rs @@ -198,9 +198,12 @@ fn create_tree_recursive( let mut extra_info = HashMap::new(); // Parse the key-value pairs from the formatted string. + // See DisplayFormatType::TreeRender for details for line in display_info.lines() { if let Some((key, value)) = line.split_once('=') { extra_info.insert(key.to_string(), value.to_string()); + } else { + extra_info.insert(line.to_string(), "".to_string()); } } diff --git a/datafusion/physical-plan/src/sorts/partial_sort.rs b/datafusion/physical-plan/src/sorts/partial_sort.rs index 4cff0fedfaa6..5277a50b85ca 100644 --- a/datafusion/physical-plan/src/sorts/partial_sort.rs +++ b/datafusion/physical-plan/src/sorts/partial_sort.rs @@ -228,11 +228,11 @@ impl DisplayAs for PartialSortExec { } DisplayFormatType::TreeRender => match self.fetch { Some(fetch) => { - writeln!(f, "limit={fetch}")?; - writeln!(f, "sort keys={}", self.expr) + writeln!(f, "{}", self.expr)?; + writeln!(f, "limit={fetch}") } None => { - writeln!(f, "sort keys={}", self.expr) + writeln!(f, "{}", self.expr) } }, } diff --git a/datafusion/physical-plan/src/sorts/sort.rs b/datafusion/physical-plan/src/sorts/sort.rs index 0b629254267c..3d2323eb4336 100644 --- a/datafusion/physical-plan/src/sorts/sort.rs +++ b/datafusion/physical-plan/src/sorts/sort.rs @@ -1007,11 +1007,11 @@ impl DisplayAs for SortExec { } DisplayFormatType::TreeRender => match self.fetch { Some(fetch) => { - writeln!(f, "limit={fetch}")?; - writeln!(f, "sort keys=[{}]", self.expr) + writeln!(f, "{}", self.expr)?; + writeln!(f, "limit={fetch}") } None => { - writeln!(f, "sort keys=[{}]", self.expr) + writeln!(f, "{}", self.expr) } }, } diff --git a/datafusion/sqllogictest/test_files/explain_tree.slt b/datafusion/sqllogictest/test_files/explain_tree.slt index d81d83ea42fc..be926c0fc9c0 100644 --- a/datafusion/sqllogictest/test_files/explain_tree.slt +++ b/datafusion/sqllogictest/test_files/explain_tree.slt @@ -674,17 +674,16 @@ physical_plan 23)┌─────────────┴─────────────┐ 24)│ SortExec │ 25)│ -------------------- │ -26)│ sort keys: │ -27)│ [v1@0 ASC NULLS LAST] │ -28)└─────────────┬─────────────┘ -29)┌─────────────┴─────────────┐ -30)│ ProjectionExec │ -31)│ -------------------- │ -32)│ v1: value@0 │ -33)└─────────────┬─────────────┘ -34)┌─────────────┴─────────────┐ -35)│ LazyMemoryExec │ -36)└───────────────────────────┘ +26)│ v1@0 ASC NULLS LAST │ +27)└─────────────┬─────────────┘ +28)┌─────────────┴─────────────┐ +29)│ ProjectionExec │ +30)│ -------------------- │ +31)│ v1: value@0 │ +32)└─────────────┬─────────────┘ +33)┌─────────────┴─────────────┐ +34)│ LazyMemoryExec │ +35)└───────────────────────────┘ query TT explain select @@ -745,16 +744,14 @@ physical_plan 01)┌───────────────────────────┐ 02)│ SortExec │ 03)│ -------------------- │ -04)│ sort keys: │ -05)│ [string_col@1 ASC NULLS │ -06)│ LAST] │ -07)└─────────────┬─────────────┘ -08)┌─────────────┴─────────────┐ -09)│ DataSourceExec │ -10)│ -------------------- │ -11)│ files: 1 │ -12)│ format: csv │ -13)└───────────────────────────┘ +04)│string_col@1 ASC NULLS LAST│ +05)└─────────────┬─────────────┘ +06)┌─────────────┴─────────────┐ +07)│ DataSourceExec │ +08)│ -------------------- │ +09)│ files: 1 │ +10)│ format: csv │ +11)└───────────────────────────┘ # Query for sort with limit. query TT @@ -769,16 +766,14 @@ physical_plan 03)│ -------------------- │ 04)│ limit: 1 │ 05)│ │ -06)│ sort keys: │ -07)│ [string_col@1 ASC NULLS │ -08)│ LAST] │ -09)└─────────────┬─────────────┘ -10)┌─────────────┴─────────────┐ -11)│ DataSourceExec │ -12)│ -------------------- │ -13)│ files: 1 │ -14)│ format: csv │ -15)└───────────────────────────┘ +06)│string_col@1 ASC NULLS LAST│ +07)└─────────────┬─────────────┘ +08)┌─────────────┴─────────────┐ +09)│ DataSourceExec │ +10)│ -------------------- │ +11)│ files: 1 │ +12)│ format: csv │ +13)└───────────────────────────┘ # Query with projection on csv query TT @@ -865,33 +860,31 @@ physical_plan 41)┌─────────────┴─────────────┐ 42)│ SortExec │ 43)│ -------------------- │ -44)│ sort keys: │ -45)│ [int_col@0 ASC NULLS LAST]│ -46)└─────────────┬─────────────┘ -47)┌─────────────┴─────────────┐ -48)│ BoundedWindowAggExec │ -49)│ -------------------- │ -50)│ mode: Sorted │ -51)│ │ -52)│ select_list: │ -53)│ rank() ORDER BY [table1 │ -54)│ .int_col DESC NULLS │ -55)│ FIRST] RANGE BETWEEN │ -56)│ UNBOUNDED PRECEDING AND │ -57)│ CURRENT ROW │ -58)└─────────────┬─────────────┘ -59)┌─────────────┴─────────────┐ -60)│ SortExec │ -61)│ -------------------- │ -62)│ sort keys: │ -63)│ [int_col@0 DESC] │ -64)└─────────────┬─────────────┘ -65)┌─────────────┴─────────────┐ -66)│ DataSourceExec │ -67)│ -------------------- │ -68)│ files: 1 │ -69)│ format: csv │ -70)└───────────────────────────┘ +44)│ int_col@0 ASC NULLS LAST │ +45)└─────────────┬─────────────┘ +46)┌─────────────┴─────────────┐ +47)│ BoundedWindowAggExec │ +48)│ -------------------- │ +49)│ mode: Sorted │ +50)│ │ +51)│ select_list: │ +52)│ rank() ORDER BY [table1 │ +53)│ .int_col DESC NULLS │ +54)│ FIRST] RANGE BETWEEN │ +55)│ UNBOUNDED PRECEDING AND │ +56)│ CURRENT ROW │ +57)└─────────────┬─────────────┘ +58)┌─────────────┴─────────────┐ +59)│ SortExec │ +60)│ -------------------- │ +61)│ int_col@0 DESC │ +62)└─────────────┬─────────────┘ +63)┌─────────────┴─────────────┐ +64)│ DataSourceExec │ +65)│ -------------------- │ +66)│ files: 1 │ +67)│ format: csv │ +68)└───────────────────────────┘ # Query with projection on parquet query TT @@ -1025,17 +1018,16 @@ physical_plan 01)┌───────────────────────────┐ 02)│ PartialSortExec │ 03)│ -------------------- │ -04)│ sort keys: │ -05)│ a@1 ASC NULLS LAST, b@2 │ -06)│ ASC NULLS LAST, d@4 │ -07)│ ASC NULLS LAST │ -08)└─────────────┬─────────────┘ -09)┌─────────────┴─────────────┐ -10)│ StreamingTableExec │ -11)│ -------------------- │ -12)│ infinite: true │ -13)│ limit: None │ -14)└───────────────────────────┘ +04)│ a@1 ASC NULLS LAST, b@2 │ +05)│ ASC NULLS LAST, d@4 │ +06)│ ASC NULLS LAST │ +07)└─────────────┬─────────────┘ +08)┌─────────────┴─────────────┐ +09)│ StreamingTableExec │ +10)│ -------------------- │ +11)│ infinite: true │ +12)│ limit: None │ +13)└───────────────────────────┘ query TT EXPLAIN SELECT * @@ -1050,19 +1042,18 @@ physical_plan 01)┌───────────────────────────┐ 02)│ PartialSortExec │ 03)│ -------------------- │ -04)│ limit: 50 │ -05)│ │ -06)│ sort keys: │ -07)│ a@1 ASC NULLS LAST, b@2 │ -08)│ ASC NULLS LAST, d@4 │ -09)│ ASC NULLS LAST │ -10)└─────────────┬─────────────┘ -11)┌─────────────┴─────────────┐ -12)│ StreamingTableExec │ -13)│ -------------------- │ -14)│ infinite: true │ -15)│ limit: None │ -16)└───────────────────────────┘ +04)│ a@1 ASC NULLS LAST, b@2 │ +05)│ ASC NULLS LAST, d@4 │ +06)│ ASC NULLS LAST │ +07)│ │ +08)│ limit: 50 │ +09)└─────────────┬─────────────┘ +10)┌─────────────┴─────────────┐ +11)│ StreamingTableExec │ +12)│ -------------------- │ +13)│ infinite: true │ +14)│ limit: None │ +15)└───────────────────────────┘ # Query with hash join. query TT @@ -1270,7 +1261,7 @@ physical_plan 06)┌─────────────┴─────────────┐┌─────────────┴─────────────┐ 07)│ SortExec ││ SortExec │ 08)│ -------------------- ││ -------------------- │ -09)│ sort keys: [c1@0 ASC] ││ sort keys: [c1@0 ASC] │ +09)│ c1@0 ASC ││ c1@0 ASC │ 10)└─────────────┬─────────────┘└─────────────┬─────────────┘ 11)┌─────────────┴─────────────┐┌─────────────┴─────────────┐ 12)│ DataSourceExec ││ DataSourceExec │