This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 90145dfc6c Optionally display schema in explain plan (#11177)
90145dfc6c is described below

commit 90145dfc6c502bcd67f4510eb3c1b746d4ceafbd
Author: Andrew Lamb <[email protected]>
AuthorDate: Sun Jun 30 06:27:54 2024 -0400

    Optionally display schema in explain plan (#11177)
---
 datafusion/common/src/config.rs                    |  3 +
 datafusion/common/src/display/mod.rs               | 12 +++-
 datafusion/core/src/physical_planner.rs            | 71 +++++++++++++++-------
 datafusion/physical-plan/src/display.rs            | 51 ++++++++++++++--
 datafusion/proto/proto/datafusion.proto            |  2 +
 datafusion/proto/src/generated/pbjson.rs           | 26 ++++++++
 datafusion/proto/src/generated/prost.rs            |  9 ++-
 datafusion/proto/src/logical_plan/from_proto.rs    |  5 ++
 datafusion/proto/src/logical_plan/to_proto.rs      | 12 +++-
 datafusion/sqllogictest/test_files/explain.slt     | 30 +++++++++
 .../sqllogictest/test_files/information_schema.slt |  2 +
 docs/source/user-guide/configs.md                  |  1 +
 12 files changed, 193 insertions(+), 31 deletions(-)

diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs
index 1ecdb0efd2..1d2a9589ad 100644
--- a/datafusion/common/src/config.rs
+++ b/datafusion/common/src/config.rs
@@ -613,6 +613,9 @@ config_namespace! {
 
         /// When set to true, the explain statement will print the partition 
sizes
         pub show_sizes: bool, default = true
+
+        /// When set to true, the explain statement will print schema 
information
+        pub show_schema: bool, default = false
     }
 }
 
diff --git a/datafusion/common/src/display/mod.rs 
b/datafusion/common/src/display/mod.rs
index 4d1d48bf9f..732f6a73e1 100644
--- a/datafusion/common/src/display/mod.rs
+++ b/datafusion/common/src/display/mod.rs
@@ -49,6 +49,8 @@ pub enum PlanType {
     InitialPhysicalPlan,
     /// The initial physical plan with stats, prepared for execution
     InitialPhysicalPlanWithStats,
+    /// The initial physical plan with schema, prepared for execution
+    InitialPhysicalPlanWithSchema,
     /// The ExecutionPlan which results from applying an optimizer pass
     OptimizedPhysicalPlan {
         /// The name of the optimizer which produced this plan
@@ -56,8 +58,10 @@ pub enum PlanType {
     },
     /// The final, fully optimized physical which would be executed
     FinalPhysicalPlan,
-    /// The final with stats, fully optimized physical which would be executed
+    /// The final with stats, fully optimized physical plan which would be 
executed
     FinalPhysicalPlanWithStats,
+    /// The final with stats, fully optimized physical plan which would be 
executed
+    FinalPhysicalPlanWithSchema,
 }
 
 impl Display for PlanType {
@@ -76,11 +80,17 @@ impl Display for PlanType {
             PlanType::InitialPhysicalPlanWithStats => {
                 write!(f, "initial_physical_plan_with_stats")
             }
+            PlanType::InitialPhysicalPlanWithSchema => {
+                write!(f, "initial_physical_plan_with_schema")
+            }
             PlanType::OptimizedPhysicalPlan { optimizer_name } => {
                 write!(f, "physical_plan after {optimizer_name}")
             }
             PlanType::FinalPhysicalPlan => write!(f, "physical_plan"),
             PlanType::FinalPhysicalPlanWithStats => write!(f, 
"physical_plan_with_stats"),
+            PlanType::FinalPhysicalPlanWithSchema => {
+                write!(f, "physical_plan_with_schema")
+            }
         }
     }
 }
diff --git a/datafusion/core/src/physical_planner.rs 
b/datafusion/core/src/physical_planner.rs
index a0390cf16c..6aad4d5755 100644
--- a/datafusion/core/src/physical_planner.rs
+++ b/datafusion/core/src/physical_planner.rs
@@ -1983,23 +1983,37 @@ impl DefaultPhysicalPlanner {
                     .await
                 {
                     Ok(input) => {
-                        // This plan will includes statistics if 
show_statistics is on
+                        // Include statistics / schema if enabled
                         stringified_plans.push(
                             displayable(input.as_ref())
                                 .set_show_statistics(config.show_statistics)
+                                .set_show_schema(config.show_schema)
                                 .to_stringified(e.verbose, 
InitialPhysicalPlan),
                         );
 
-                        // If the show_statisitcs is off, add another line to 
show statsitics in the case of explain verbose
-                        if e.verbose && !config.show_statistics {
-                            stringified_plans.push(
-                                displayable(input.as_ref())
-                                    .set_show_statistics(true)
-                                    .to_stringified(
-                                        e.verbose,
-                                        InitialPhysicalPlanWithStats,
-                                    ),
-                            );
+                        // Show statistics + schema in verbose output even if 
not
+                        // explicitly requested
+                        if e.verbose {
+                            if !config.show_statistics {
+                                stringified_plans.push(
+                                    displayable(input.as_ref())
+                                        .set_show_statistics(true)
+                                        .to_stringified(
+                                            e.verbose,
+                                            InitialPhysicalPlanWithStats,
+                                        ),
+                                );
+                            }
+                            if !config.show_schema {
+                                stringified_plans.push(
+                                    displayable(input.as_ref())
+                                        .set_show_schema(true)
+                                        .to_stringified(
+                                            e.verbose,
+                                            InitialPhysicalPlanWithSchema,
+                                        ),
+                                );
+                            }
                         }
 
                         let optimized_plan = self.optimize_internal(
@@ -2011,6 +2025,7 @@ impl DefaultPhysicalPlanner {
                                 stringified_plans.push(
                                     displayable(plan)
                                         
.set_show_statistics(config.show_statistics)
+                                        .set_show_schema(config.show_schema)
                                         .to_stringified(e.verbose, plan_type),
                                 );
                             },
@@ -2021,19 +2036,33 @@ impl DefaultPhysicalPlanner {
                                 stringified_plans.push(
                                     displayable(input.as_ref())
                                         
.set_show_statistics(config.show_statistics)
+                                        .set_show_schema(config.show_schema)
                                         .to_stringified(e.verbose, 
FinalPhysicalPlan),
                                 );
 
-                                // If the show_statisitcs is off, add another 
line to show statsitics in the case of explain verbose
-                                if e.verbose && !config.show_statistics {
-                                    stringified_plans.push(
-                                        displayable(input.as_ref())
-                                            .set_show_statistics(true)
-                                            .to_stringified(
-                                                e.verbose,
-                                                FinalPhysicalPlanWithStats,
-                                            ),
-                                    );
+                                // Show statistics + schema in verbose output 
even if not
+                                // explicitly requested
+                                if e.verbose {
+                                    if !config.show_statistics {
+                                        stringified_plans.push(
+                                            displayable(input.as_ref())
+                                                .set_show_statistics(true)
+                                                .to_stringified(
+                                                    e.verbose,
+                                                    FinalPhysicalPlanWithStats,
+                                                ),
+                                        );
+                                    }
+                                    if !config.show_schema {
+                                        stringified_plans.push(
+                                            displayable(input.as_ref())
+                                                .set_show_schema(true)
+                                                .to_stringified(
+                                                    e.verbose,
+                                                    
FinalPhysicalPlanWithSchema,
+                                                ),
+                                        );
+                                    }
                                 }
                             }
                             Err(DataFusionError::Context(optimizer_name, e)) 
=> {
diff --git a/datafusion/physical-plan/src/display.rs 
b/datafusion/physical-plan/src/display.rs
index ed85c80251..7f4ae5797d 100644
--- a/datafusion/physical-plan/src/display.rs
+++ b/datafusion/physical-plan/src/display.rs
@@ -21,12 +21,14 @@
 use std::fmt;
 use std::fmt::Formatter;
 
-use super::{accept, ExecutionPlan, ExecutionPlanVisitor};
-
 use arrow_schema::SchemaRef;
+
 use datafusion_common::display::{GraphvizBuilder, PlanType, StringifiedPlan};
+use datafusion_expr::display_schema;
 use datafusion_physical_expr::{LexOrdering, PhysicalSortExpr};
 
+use super::{accept, ExecutionPlan, ExecutionPlanVisitor};
+
 /// Options for controlling how each [`ExecutionPlan`] should format itself
 #[derive(Debug, Clone, Copy)]
 pub enum DisplayFormatType {
@@ -37,12 +39,15 @@ pub enum DisplayFormatType {
 }
 
 /// Wraps an `ExecutionPlan` with various ways to display this plan
+#[derive(Debug, Clone)]
 pub struct DisplayableExecutionPlan<'a> {
     inner: &'a dyn ExecutionPlan,
     /// How to show metrics
     show_metrics: ShowMetrics,
     /// If statistics should be displayed
     show_statistics: bool,
+    /// If schema should be displayed. See [`Self::set_show_schema`]
+    show_schema: bool,
 }
 
 impl<'a> DisplayableExecutionPlan<'a> {
@@ -53,6 +58,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
             inner,
             show_metrics: ShowMetrics::None,
             show_statistics: false,
+            show_schema: false,
         }
     }
 
@@ -64,6 +70,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
             inner,
             show_metrics: ShowMetrics::Aggregated,
             show_statistics: false,
+            show_schema: false,
         }
     }
 
@@ -75,9 +82,19 @@ impl<'a> DisplayableExecutionPlan<'a> {
             inner,
             show_metrics: ShowMetrics::Full,
             show_statistics: false,
+            show_schema: false,
         }
     }
 
+    /// Enable display of schema
+    ///
+    /// If true, plans will be displayed with schema information at the end
+    /// of each line. The format is `schema=[[a:Int32;N, b:Int32;N, 
c:Int32;N]]`
+    pub fn set_show_schema(mut self, show_schema: bool) -> Self {
+        self.show_schema = show_schema;
+        self
+    }
+
     /// Enable display of statistics
     pub fn set_show_statistics(mut self, show_statistics: bool) -> Self {
         self.show_statistics = show_statistics;
@@ -105,6 +122,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
             plan: &'a dyn ExecutionPlan,
             show_metrics: ShowMetrics,
             show_statistics: bool,
+            show_schema: bool,
         }
         impl<'a> fmt::Display for Wrapper<'a> {
             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -114,6 +132,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
                     indent: 0,
                     show_metrics: self.show_metrics,
                     show_statistics: self.show_statistics,
+                    show_schema: self.show_schema,
                 };
                 accept(self.plan, &mut visitor)
             }
@@ -123,6 +142,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
             plan: self.inner,
             show_metrics: self.show_metrics,
             show_statistics: self.show_statistics,
+            show_schema: self.show_schema,
         }
     }
 
@@ -179,6 +199,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
             plan: &'a dyn ExecutionPlan,
             show_metrics: ShowMetrics,
             show_statistics: bool,
+            show_schema: bool,
         }
 
         impl<'a> fmt::Display for Wrapper<'a> {
@@ -189,6 +210,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
                     indent: 0,
                     show_metrics: self.show_metrics,
                     show_statistics: self.show_statistics,
+                    show_schema: self.show_schema,
                 };
                 visitor.pre_visit(self.plan)?;
                 Ok(())
@@ -199,6 +221,7 @@ impl<'a> DisplayableExecutionPlan<'a> {
             plan: self.inner,
             show_metrics: self.show_metrics,
             show_statistics: self.show_statistics,
+            show_schema: self.show_schema,
         }
     }
 
@@ -221,6 +244,14 @@ enum ShowMetrics {
 }
 
 /// Formats plans with a single line per node.
+///
+/// # Example
+///
+/// ```text
+/// ProjectionExec: expr=[column1@0 + 2 as column1 + Int64(2)]
+///   FilterExec: column1@0 = 5
+///     ValuesExec
+/// ```
 struct IndentVisitor<'a, 'b> {
     /// How to format each node
     t: DisplayFormatType,
@@ -232,6 +263,8 @@ struct IndentVisitor<'a, 'b> {
     show_metrics: ShowMetrics,
     /// If statistics should be displayed
     show_statistics: bool,
+    /// If schema should be displayed
+    show_schema: bool,
 }
 
 impl<'a, 'b> ExecutionPlanVisitor for IndentVisitor<'a, 'b> {
@@ -265,6 +298,13 @@ impl<'a, 'b> ExecutionPlanVisitor for IndentVisitor<'a, 
'b> {
             let stats = plan.statistics().map_err(|_e| fmt::Error)?;
             write!(self.f, ", statistics=[{}]", stats)?;
         }
+        if self.show_schema {
+            write!(
+                self.f,
+                ", schema={}",
+                display_schema(plan.schema().as_ref())
+            )?;
+        }
         writeln!(self.f)?;
         self.indent += 1;
         Ok(true)
@@ -465,12 +505,13 @@ mod tests {
     use std::fmt::Write;
     use std::sync::Arc;
 
-    use super::DisplayableExecutionPlan;
-    use crate::{DisplayAs, ExecutionPlan, PlanProperties};
-
     use datafusion_common::{DataFusionError, Result, Statistics};
     use datafusion_execution::{SendableRecordBatchStream, TaskContext};
 
+    use crate::{DisplayAs, ExecutionPlan, PlanProperties};
+
+    use super::DisplayableExecutionPlan;
+
     #[derive(Debug, Clone, Copy)]
     enum TestStatsExecPlan {
         Panic,
diff --git a/datafusion/proto/proto/datafusion.proto 
b/datafusion/proto/proto/datafusion.proto
index 004d7320e2..7f4d6b9d92 100644
--- a/datafusion/proto/proto/datafusion.proto
+++ b/datafusion/proto/proto/datafusion.proto
@@ -669,9 +669,11 @@ message PlanType {
     datafusion_common.EmptyMessage FinalLogicalPlan = 3;
     datafusion_common.EmptyMessage InitialPhysicalPlan = 4;
     datafusion_common.EmptyMessage InitialPhysicalPlanWithStats = 9;
+    datafusion_common.EmptyMessage InitialPhysicalPlanWithSchema = 11;
     OptimizedPhysicalPlanType OptimizedPhysicalPlan = 5;
     datafusion_common.EmptyMessage FinalPhysicalPlan = 6;
     datafusion_common.EmptyMessage FinalPhysicalPlanWithStats = 10;
+    datafusion_common.EmptyMessage FinalPhysicalPlanWithSchema = 12;
   }
 }
 
diff --git a/datafusion/proto/src/generated/pbjson.rs 
b/datafusion/proto/src/generated/pbjson.rs
index ebfa783f85..33cd634c4a 100644
--- a/datafusion/proto/src/generated/pbjson.rs
+++ b/datafusion/proto/src/generated/pbjson.rs
@@ -16140,6 +16140,9 @@ impl serde::Serialize for PlanType {
                 plan_type::PlanTypeEnum::InitialPhysicalPlanWithStats(v) => {
                     struct_ser.serialize_field("InitialPhysicalPlanWithStats", 
v)?;
                 }
+                plan_type::PlanTypeEnum::InitialPhysicalPlanWithSchema(v) => {
+                    
struct_ser.serialize_field("InitialPhysicalPlanWithSchema", v)?;
+                }
                 plan_type::PlanTypeEnum::OptimizedPhysicalPlan(v) => {
                     struct_ser.serialize_field("OptimizedPhysicalPlan", v)?;
                 }
@@ -16149,6 +16152,9 @@ impl serde::Serialize for PlanType {
                 plan_type::PlanTypeEnum::FinalPhysicalPlanWithStats(v) => {
                     struct_ser.serialize_field("FinalPhysicalPlanWithStats", 
v)?;
                 }
+                plan_type::PlanTypeEnum::FinalPhysicalPlanWithSchema(v) => {
+                    struct_ser.serialize_field("FinalPhysicalPlanWithSchema", 
v)?;
+                }
             }
         }
         struct_ser.end()
@@ -16168,9 +16174,11 @@ impl<'de> serde::Deserialize<'de> for PlanType {
             "FinalLogicalPlan",
             "InitialPhysicalPlan",
             "InitialPhysicalPlanWithStats",
+            "InitialPhysicalPlanWithSchema",
             "OptimizedPhysicalPlan",
             "FinalPhysicalPlan",
             "FinalPhysicalPlanWithStats",
+            "FinalPhysicalPlanWithSchema",
         ];
 
         #[allow(clippy::enum_variant_names)]
@@ -16182,9 +16190,11 @@ impl<'de> serde::Deserialize<'de> for PlanType {
             FinalLogicalPlan,
             InitialPhysicalPlan,
             InitialPhysicalPlanWithStats,
+            InitialPhysicalPlanWithSchema,
             OptimizedPhysicalPlan,
             FinalPhysicalPlan,
             FinalPhysicalPlanWithStats,
+            FinalPhysicalPlanWithSchema,
         }
         impl<'de> serde::Deserialize<'de> for GeneratedField {
             fn deserialize<D>(deserializer: D) -> 
std::result::Result<GeneratedField, D::Error>
@@ -16213,9 +16223,11 @@ impl<'de> serde::Deserialize<'de> for PlanType {
                             "FinalLogicalPlan" => 
Ok(GeneratedField::FinalLogicalPlan),
                             "InitialPhysicalPlan" => 
Ok(GeneratedField::InitialPhysicalPlan),
                             "InitialPhysicalPlanWithStats" => 
Ok(GeneratedField::InitialPhysicalPlanWithStats),
+                            "InitialPhysicalPlanWithSchema" => 
Ok(GeneratedField::InitialPhysicalPlanWithSchema),
                             "OptimizedPhysicalPlan" => 
Ok(GeneratedField::OptimizedPhysicalPlan),
                             "FinalPhysicalPlan" => 
Ok(GeneratedField::FinalPhysicalPlan),
                             "FinalPhysicalPlanWithStats" => 
Ok(GeneratedField::FinalPhysicalPlanWithStats),
+                            "FinalPhysicalPlanWithSchema" => 
Ok(GeneratedField::FinalPhysicalPlanWithSchema),
                             _ => Err(serde::de::Error::unknown_field(value, 
FIELDS)),
                         }
                     }
@@ -16285,6 +16297,13 @@ impl<'de> serde::Deserialize<'de> for PlanType {
                                 return 
Err(serde::de::Error::duplicate_field("InitialPhysicalPlanWithStats"));
                             }
                             plan_type_enum__ = 
map_.next_value::<::std::option::Option<_>>()?.map(plan_type::PlanTypeEnum::InitialPhysicalPlanWithStats)
+;
+                        }
+                        GeneratedField::InitialPhysicalPlanWithSchema => {
+                            if plan_type_enum__.is_some() {
+                                return 
Err(serde::de::Error::duplicate_field("InitialPhysicalPlanWithSchema"));
+                            }
+                            plan_type_enum__ = 
map_.next_value::<::std::option::Option<_>>()?.map(plan_type::PlanTypeEnum::InitialPhysicalPlanWithSchema)
 ;
                         }
                         GeneratedField::OptimizedPhysicalPlan => {
@@ -16306,6 +16325,13 @@ impl<'de> serde::Deserialize<'de> for PlanType {
                                 return 
Err(serde::de::Error::duplicate_field("FinalPhysicalPlanWithStats"));
                             }
                             plan_type_enum__ = 
map_.next_value::<::std::option::Option<_>>()?.map(plan_type::PlanTypeEnum::FinalPhysicalPlanWithStats)
+;
+                        }
+                        GeneratedField::FinalPhysicalPlanWithSchema => {
+                            if plan_type_enum__.is_some() {
+                                return 
Err(serde::de::Error::duplicate_field("FinalPhysicalPlanWithSchema"));
+                            }
+                            plan_type_enum__ = 
map_.next_value::<::std::option::Option<_>>()?.map(plan_type::PlanTypeEnum::FinalPhysicalPlanWithSchema)
 ;
                         }
                     }
diff --git a/datafusion/proto/src/generated/prost.rs 
b/datafusion/proto/src/generated/prost.rs
index 1a3514dbd4..83b8b738c4 100644
--- a/datafusion/proto/src/generated/prost.rs
+++ b/datafusion/proto/src/generated/prost.rs
@@ -947,7 +947,10 @@ pub struct OptimizedPhysicalPlanType {
 #[allow(clippy::derive_partial_eq_without_eq)]
 #[derive(Clone, PartialEq, ::prost::Message)]
 pub struct PlanType {
-    #[prost(oneof = "plan_type::PlanTypeEnum", tags = "1, 7, 8, 2, 3, 4, 9, 5, 
6, 10")]
+    #[prost(
+        oneof = "plan_type::PlanTypeEnum",
+        tags = "1, 7, 8, 2, 3, 4, 9, 11, 5, 6, 10, 12"
+    )]
     pub plan_type_enum: ::core::option::Option<plan_type::PlanTypeEnum>,
 }
 /// Nested message and enum types in `PlanType`.
@@ -969,12 +972,16 @@ pub mod plan_type {
         InitialPhysicalPlan(super::super::datafusion_common::EmptyMessage),
         #[prost(message, tag = "9")]
         
InitialPhysicalPlanWithStats(super::super::datafusion_common::EmptyMessage),
+        #[prost(message, tag = "11")]
+        
InitialPhysicalPlanWithSchema(super::super::datafusion_common::EmptyMessage),
         #[prost(message, tag = "5")]
         OptimizedPhysicalPlan(super::OptimizedPhysicalPlanType),
         #[prost(message, tag = "6")]
         FinalPhysicalPlan(super::super::datafusion_common::EmptyMessage),
         #[prost(message, tag = "10")]
         
FinalPhysicalPlanWithStats(super::super::datafusion_common::EmptyMessage),
+        #[prost(message, tag = "12")]
+        
FinalPhysicalPlanWithSchema(super::super::datafusion_common::EmptyMessage),
     }
 }
 #[allow(clippy::derive_partial_eq_without_eq)]
diff --git a/datafusion/proto/src/logical_plan/from_proto.rs 
b/datafusion/proto/src/logical_plan/from_proto.rs
index 21331a94c1..609cbc1a28 100644
--- a/datafusion/proto/src/logical_plan/from_proto.rs
+++ b/datafusion/proto/src/logical_plan/from_proto.rs
@@ -36,6 +36,9 @@ use datafusion_expr::{
 };
 use datafusion_proto_common::{from_proto::FromOptionalField, FromProtoError as 
Error};
 
+use crate::protobuf::plan_type::PlanTypeEnum::{
+    FinalPhysicalPlanWithSchema, InitialPhysicalPlanWithSchema,
+};
 use crate::protobuf::{
     self,
     plan_type::PlanTypeEnum::{
@@ -121,6 +124,7 @@ impl From<&protobuf::StringifiedPlan> for StringifiedPlan {
                 FinalLogicalPlan(_) => PlanType::FinalLogicalPlan,
                 InitialPhysicalPlan(_) => PlanType::InitialPhysicalPlan,
                 InitialPhysicalPlanWithStats(_) => 
PlanType::InitialPhysicalPlanWithStats,
+                InitialPhysicalPlanWithSchema(_) => 
PlanType::InitialPhysicalPlanWithSchema,
                 OptimizedPhysicalPlan(OptimizedPhysicalPlanType { 
optimizer_name }) => {
                     PlanType::OptimizedPhysicalPlan {
                         optimizer_name: optimizer_name.clone(),
@@ -128,6 +132,7 @@ impl From<&protobuf::StringifiedPlan> for StringifiedPlan {
                 }
                 FinalPhysicalPlan(_) => PlanType::FinalPhysicalPlan,
                 FinalPhysicalPlanWithStats(_) => 
PlanType::FinalPhysicalPlanWithStats,
+                FinalPhysicalPlanWithSchema(_) => 
PlanType::FinalPhysicalPlanWithSchema,
             },
             plan: Arc::new(stringified_plan.plan.clone()),
         }
diff --git a/datafusion/proto/src/logical_plan/to_proto.rs 
b/datafusion/proto/src/logical_plan/to_proto.rs
index 3a1db1defd..ccc64119c8 100644
--- a/datafusion/proto/src/logical_plan/to_proto.rs
+++ b/datafusion/proto/src/logical_plan/to_proto.rs
@@ -34,9 +34,9 @@ use crate::protobuf::{
     self,
     plan_type::PlanTypeEnum::{
         AnalyzedLogicalPlan, FinalAnalyzedLogicalPlan, FinalLogicalPlan,
-        FinalPhysicalPlan, FinalPhysicalPlanWithStats, InitialLogicalPlan,
-        InitialPhysicalPlan, InitialPhysicalPlanWithStats, 
OptimizedLogicalPlan,
-        OptimizedPhysicalPlan,
+        FinalPhysicalPlan, FinalPhysicalPlanWithSchema, 
FinalPhysicalPlanWithStats,
+        InitialLogicalPlan, InitialPhysicalPlan, InitialPhysicalPlanWithSchema,
+        InitialPhysicalPlanWithStats, OptimizedLogicalPlan, 
OptimizedPhysicalPlan,
     },
     AnalyzedLogicalPlanType, CubeNode, EmptyMessage, GroupingSetNode, 
LogicalExprList,
     OptimizedLogicalPlanType, OptimizedPhysicalPlanType, PlaceholderNode, 
RollupNode,
@@ -96,9 +96,15 @@ impl From<&StringifiedPlan> for protobuf::StringifiedPlan {
                 PlanType::InitialPhysicalPlanWithStats => 
Some(protobuf::PlanType {
                     plan_type_enum: 
Some(InitialPhysicalPlanWithStats(EmptyMessage {})),
                 }),
+                PlanType::InitialPhysicalPlanWithSchema => 
Some(protobuf::PlanType {
+                    plan_type_enum: 
Some(InitialPhysicalPlanWithSchema(EmptyMessage {})),
+                }),
                 PlanType::FinalPhysicalPlanWithStats => 
Some(protobuf::PlanType {
                     plan_type_enum: 
Some(FinalPhysicalPlanWithStats(EmptyMessage {})),
                 }),
+                PlanType::FinalPhysicalPlanWithSchema => 
Some(protobuf::PlanType {
+                    plan_type_enum: 
Some(FinalPhysicalPlanWithSchema(EmptyMessage {})),
+                }),
             },
             plan: stringified_plan.plan.to_string(),
         }
diff --git a/datafusion/sqllogictest/test_files/explain.slt 
b/datafusion/sqllogictest/test_files/explain.slt
index 96e73a5916..b850760b87 100644
--- a/datafusion/sqllogictest/test_files/explain.slt
+++ b/datafusion/sqllogictest/test_files/explain.slt
@@ -241,6 +241,7 @@ logical_plan after optimize_projections SAME TEXT AS ABOVE
 logical_plan TableScan: simple_explain_test projection=[a, b, c]
 initial_physical_plan CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true
 initial_physical_plan_with_stats CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true, statistics=[Rows=Absent, Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:)]]
+initial_physical_plan_with_schema CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true, schema=[a:Int32;N, b:Int32;N, c:Int32;N]
 physical_plan after OutputRequirements
 01)OutputRequirementExec
 02)--CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true
@@ -259,6 +260,23 @@ physical_plan after ProjectionPushdown SAME TEXT AS ABOVE
 physical_plan after PipelineChecker SAME TEXT AS ABOVE
 physical_plan CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true
 physical_plan_with_stats CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true, statistics=[Rows=Absent, Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:)]]
+physical_plan_with_schema CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true, schema=[a:Int32;N, b:Int32;N, c:Int32;N]
+
+### tests for EXPLAIN with display schema enabled
+
+statement ok
+set datafusion.explain.show_schema = true;
+
+# test EXPLAIN VERBOSE
+query TT
+EXPLAIN SELECT a, b, c FROM simple_explain_test;
+----
+logical_plan TableScan: simple_explain_test projection=[a, b, c]
+physical_plan CsvExec: file_groups={1 group: 
[[WORKSPACE_ROOT/datafusion/core/tests/data/example.csv]]}, projection=[a, b, 
c], has_header=true, schema=[a:Int32;N, b:Int32;N, c:Int32;N]
+
+
+statement ok
+set datafusion.explain.show_schema = false;
 
 
 ### tests for EXPLAIN with display statistics enabled
@@ -297,6 +315,9 @@ EXPLAIN VERBOSE SELECT * FROM alltypes_plain limit 10;
 initial_physical_plan
 01)GlobalLimitExec: skip=0, fetch=10, statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
 02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
+initial_physical_plan_with_schema
+01)GlobalLimitExec: skip=0, fetch=10, schema=[id:Int32;N, bool_col:Boolean;N, 
tinyint_col:Int32;N, smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, 
float_col:Float32;N, double_col:Float64;N, date_string_col:Binary;N, 
string_col:Binary;N, timestamp_col:Timestamp(Nanosecond, None);N]
+02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
schema=[id:Int32;N, bool_col:Boolean;N, tinyint_col:Int32;N, 
smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, float_col:Float32;N, 
double_col:Float64;N, date_string_col:Binary;N, string_col:Binary;N, 
timestamp_col:Timestamp(N [...]
 physical_plan after OutputRequirements
 01)OutputRequirementExec, statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
 02)--GlobalLimitExec: skip=0, fetch=10, statistics=[Rows=Exact(8), 
Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
@@ -319,6 +340,9 @@ physical_plan after PipelineChecker SAME TEXT AS ABOVE
 physical_plan
 01)GlobalLimitExec: skip=0, fetch=10, statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
 02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
+physical_plan_with_schema
+01)GlobalLimitExec: skip=0, fetch=10, schema=[id:Int32;N, bool_col:Boolean;N, 
tinyint_col:Int32;N, smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, 
float_col:Float32;N, double_col:Float64;N, date_string_col:Binary;N, 
string_col:Binary;N, timestamp_col:Timestamp(Nanosecond, None);N]
+02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
schema=[id:Int32;N, bool_col:Boolean;N, tinyint_col:Int32;N, 
smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, float_col:Float32;N, 
double_col:Float64;N, date_string_col:Binary;N, string_col:Binary;N, 
timestamp_col:Timestamp(N [...]
 
 
 statement ok
@@ -334,6 +358,9 @@ initial_physical_plan
 initial_physical_plan_with_stats
 01)GlobalLimitExec: skip=0, fetch=10, statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
 02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
+initial_physical_plan_with_schema
+01)GlobalLimitExec: skip=0, fetch=10, schema=[id:Int32;N, bool_col:Boolean;N, 
tinyint_col:Int32;N, smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, 
float_col:Float32;N, double_col:Float64;N, date_string_col:Binary;N, 
string_col:Binary;N, timestamp_col:Timestamp(Nanosecond, None);N]
+02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
schema=[id:Int32;N, bool_col:Boolean;N, tinyint_col:Int32;N, 
smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, float_col:Float32;N, 
double_col:Float64;N, date_string_col:Binary;N, string_col:Binary;N, 
timestamp_col:Timestamp(N [...]
 physical_plan after OutputRequirements
 01)OutputRequirementExec
 02)--GlobalLimitExec: skip=0, fetch=10
@@ -359,6 +386,9 @@ physical_plan
 physical_plan_with_stats
 01)GlobalLimitExec: skip=0, fetch=10, statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
 02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
statistics=[Rows=Exact(8), Bytes=Absent, 
[(Col[0]:),(Col[1]:),(Col[2]:),(Col[3]:),(Col[4]:),(Col[5]:),(Col[6]:),(Col[7]:),(Col[8]:),(Col[9]:),(Col[10]:)]]
+physical_plan_with_schema
+01)GlobalLimitExec: skip=0, fetch=10, schema=[id:Int32;N, bool_col:Boolean;N, 
tinyint_col:Int32;N, smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, 
float_col:Float32;N, double_col:Float64;N, date_string_col:Binary;N, 
string_col:Binary;N, timestamp_col:Timestamp(Nanosecond, None);N]
+02)--ParquetExec: file_groups={1 group: 
[[WORKSPACE_ROOT/parquet-testing/data/alltypes_plain.parquet]]}, 
projection=[id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, 
float_col, double_col, date_string_col, string_col, timestamp_col], limit=10, 
schema=[id:Int32;N, bool_col:Boolean;N, tinyint_col:Int32;N, 
smallint_col:Int32;N, int_col:Int32;N, bigint_col:Int64;N, float_col:Float32;N, 
double_col:Float64;N, date_string_col:Binary;N, string_col:Binary;N, 
timestamp_col:Timestamp(N [...]
 
 
 statement ok
diff --git a/datafusion/sqllogictest/test_files/information_schema.slt 
b/datafusion/sqllogictest/test_files/information_schema.slt
index ee64f77291..acd465a0c0 100644
--- a/datafusion/sqllogictest/test_files/information_schema.slt
+++ b/datafusion/sqllogictest/test_files/information_schema.slt
@@ -213,6 +213,7 @@ datafusion.execution.target_partitions 7
 datafusion.execution.time_zone +00:00
 datafusion.explain.logical_plan_only false
 datafusion.explain.physical_plan_only false
+datafusion.explain.show_schema false
 datafusion.explain.show_sizes true
 datafusion.explain.show_statistics false
 datafusion.optimizer.allow_symmetric_joins_without_pruning true
@@ -296,6 +297,7 @@ datafusion.execution.target_partitions 7 Number of 
partitions for query executio
 datafusion.execution.time_zone +00:00 The default time zone Some functions, 
e.g. `EXTRACT(HOUR from SOME_TIME)`, shift the underlying datetime according to 
this time zone, and then extract the hour
 datafusion.explain.logical_plan_only false When set to true, the explain 
statement will only print logical plans
 datafusion.explain.physical_plan_only false When set to true, the explain 
statement will only print physical plans
+datafusion.explain.show_schema false When set to true, the explain statement 
will print schema information
 datafusion.explain.show_sizes true When set to true, the explain statement 
will print the partition sizes
 datafusion.explain.show_statistics false When set to true, the explain 
statement will print operator statistics for physical plans
 datafusion.optimizer.allow_symmetric_joins_without_pruning true Should 
DataFusion allow symmetric hash joins for unbounded data sources even when its 
inputs do not have any ordering or filtering If the flag is not enabled, the 
SymmetricHashJoin operator will be unable to prune its internal buffers, 
resulting in certain join types - such as Full, Left, LeftAnti, LeftSemi, 
Right, RightAnti, and RightSemi - being produced only at the end of the 
execution. This is not typical in stream proce [...]
diff --git a/docs/source/user-guide/configs.md 
b/docs/source/user-guide/configs.md
index 0f0aa84604..303caef577 100644
--- a/docs/source/user-guide/configs.md
+++ b/docs/source/user-guide/configs.md
@@ -111,6 +111,7 @@ Environment variables are read during `SessionConfig` 
initialisation so they mus
 | datafusion.explain.physical_plan_only                                   | 
false                     | When set to true, the explain statement will only 
print physical plans                                                            
                                                                                
                                                                                
                                                                                
                   [...]
 | datafusion.explain.show_statistics                                      | 
false                     | When set to true, the explain statement will print 
operator statistics for physical plans                                          
                                                                                
                                                                                
                                                                                
                  [...]
 | datafusion.explain.show_sizes                                           | 
true                      | When set to true, the explain statement will print 
the partition sizes                                                             
                                                                                
                                                                                
                                                                                
                  [...]
+| datafusion.explain.show_schema                                          | 
false                     | When set to true, the explain statement will print 
schema information                                                              
                                                                                
                                                                                
                                                                                
                  [...]
 | datafusion.sql_parser.parse_float_as_decimal                            | 
false                     | When set to true, SQL parser will parse float as 
decimal type                                                                    
                                                                                
                                                                                
                                                                                
                    [...]
 | datafusion.sql_parser.enable_ident_normalization                        | 
true                      | When set to true, SQL parser will normalize ident 
(convert ident to lowercase when not quoted)                                    
                                                                                
                                                                                
                                                                                
                   [...]
 | datafusion.sql_parser.dialect                                           | 
generic                   | Configure the SQL dialect used by DataFusion's 
parser; supported values include: Generic, MySQL, PostgreSQL, Hive, SQLite, 
Snowflake, Redshift, MsSQL, ClickHouse, BigQuery, and Ansi.                     
                                                                                
                                                                                
                          [...]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to