@@ -21,6 +21,7 @@ use std::cmp::Ordering;
2121use std:: collections:: { BTreeMap , HashMap , HashSet } ;
2222use std:: fmt:: { self , Debug , Display , Formatter } ;
2323use std:: hash:: { Hash , Hasher } ;
24+ use std:: str:: FromStr ;
2425use std:: sync:: { Arc , LazyLock } ;
2526
2627use super :: dml:: CopyTo ;
@@ -1084,6 +1085,7 @@ impl LogicalPlan {
10841085 Ok ( LogicalPlan :: Explain ( Explain {
10851086 verbose : e. verbose ,
10861087 plan : Arc :: new ( input) ,
1088+ explain_format : e. explain_format . clone ( ) ,
10871089 stringified_plans : e. stringified_plans . clone ( ) ,
10881090 schema : Arc :: clone ( & e. schema ) ,
10891091 logical_optimization_succeeded : e. logical_optimization_succeeded ,
@@ -2924,12 +2926,167 @@ impl PartialOrd for DescribeTable {
29242926 }
29252927}
29262928
2929+ /// Output formats for controlling for Explain plans
2930+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
2931+ pub enum ExplainFormat {
2932+ /// Indent mode
2933+ ///
2934+ /// Example:
2935+ /// ```text
2936+ /// > explain format indent select x from values (1) t(x);
2937+ /// +---------------+-----------------------------------------------------+
2938+ /// | plan_type | plan |
2939+ /// +---------------+-----------------------------------------------------+
2940+ /// | logical_plan | SubqueryAlias: t |
2941+ /// | | Projection: column1 AS x |
2942+ /// | | Values: (Int64(1)) |
2943+ /// | physical_plan | ProjectionExec: expr=[column1@0 as x] |
2944+ /// | | DataSourceExec: partitions=1, partition_sizes=[1] |
2945+ /// | | |
2946+ /// +---------------+-----------------------------------------------------+
2947+ /// ```
2948+ Indent ,
2949+ /// Tree mode
2950+ ///
2951+ /// Example:
2952+ /// ```text
2953+ /// > explain format tree select x from values (1) t(x);
2954+ /// +---------------+-------------------------------+
2955+ /// | plan_type | plan |
2956+ /// +---------------+-------------------------------+
2957+ /// | physical_plan | ┌───────────────────────────┐ |
2958+ /// | | │ ProjectionExec │ |
2959+ /// | | │ -------------------- │ |
2960+ /// | | │ x: column1@0 │ |
2961+ /// | | └─────────────┬─────────────┘ |
2962+ /// | | ┌─────────────┴─────────────┐ |
2963+ /// | | │ DataSourceExec │ |
2964+ /// | | │ -------------------- │ |
2965+ /// | | │ bytes: 128 │ |
2966+ /// | | │ format: memory │ |
2967+ /// | | │ rows: 1 │ |
2968+ /// | | └───────────────────────────┘ |
2969+ /// | | |
2970+ /// +---------------+-------------------------------+
2971+ /// ```
2972+ Tree ,
2973+ /// Postgres Json mode
2974+ ///
2975+ /// A displayable structure that produces plan in postgresql JSON format.
2976+ ///
2977+ /// Users can use this format to visualize the plan in existing plan
2978+ /// visualization tools, for example [dalibo](https://explain.dalibo.com/)
2979+ ///
2980+ /// Example:
2981+ /// ```text
2982+ /// > explain format pgjson select x from values (1) t(x);
2983+ /// +--------------+--------------------------------------+
2984+ /// | plan_type | plan |
2985+ /// +--------------+--------------------------------------+
2986+ /// | logical_plan | [ |
2987+ /// | | { |
2988+ /// | | "Plan": { |
2989+ /// | | "Alias": "t", |
2990+ /// | | "Node Type": "Subquery", |
2991+ /// | | "Output": [ |
2992+ /// | | "x" |
2993+ /// | | ], |
2994+ /// | | "Plans": [ |
2995+ /// | | { |
2996+ /// | | "Expressions": [ |
2997+ /// | | "column1 AS x" |
2998+ /// | | ], |
2999+ /// | | "Node Type": "Projection", |
3000+ /// | | "Output": [ |
3001+ /// | | "x" |
3002+ /// | | ], |
3003+ /// | | "Plans": [ |
3004+ /// | | { |
3005+ /// | | "Node Type": "Values", |
3006+ /// | | "Output": [ |
3007+ /// | | "column1" |
3008+ /// | | ], |
3009+ /// | | "Plans": [], |
3010+ /// | | "Values": "(Int64(1))" |
3011+ /// | | } |
3012+ /// | | ] |
3013+ /// | | } |
3014+ /// | | ] |
3015+ /// | | } |
3016+ /// | | } |
3017+ /// | | ] |
3018+ /// +--------------+--------------------------------------+
3019+ /// ```
3020+ PostgresJSON ,
3021+ /// Graphviz mode
3022+ ///
3023+ /// Example:
3024+ /// ```text
3025+ /// > explain format graphviz select x from values (1) t(x);
3026+ /// +--------------+------------------------------------------------------------------------+
3027+ /// | plan_type | plan |
3028+ /// +--------------+------------------------------------------------------------------------+
3029+ /// | logical_plan | |
3030+ /// | | // Begin DataFusion GraphViz Plan, |
3031+ /// | | // display it online here: https://dreampuf.github.io/GraphvizOnline |
3032+ /// | | |
3033+ /// | | digraph { |
3034+ /// | | subgraph cluster_1 |
3035+ /// | | { |
3036+ /// | | graph[label="LogicalPlan"] |
3037+ /// | | 2[shape=box label="SubqueryAlias: t"] |
3038+ /// | | 3[shape=box label="Projection: column1 AS x"] |
3039+ /// | | 2 -> 3 [arrowhead=none, arrowtail=normal, dir=back] |
3040+ /// | | 4[shape=box label="Values: (Int64(1))"] |
3041+ /// | | 3 -> 4 [arrowhead=none, arrowtail=normal, dir=back] |
3042+ /// | | } |
3043+ /// | | subgraph cluster_5 |
3044+ /// | | { |
3045+ /// | | graph[label="Detailed LogicalPlan"] |
3046+ /// | | 6[shape=box label="SubqueryAlias: t\nSchema: [x:Int64;N]"] |
3047+ /// | | 7[shape=box label="Projection: column1 AS x\nSchema: [x:Int64;N]"] |
3048+ /// | | 6 -> 7 [arrowhead=none, arrowtail=normal, dir=back] |
3049+ /// | | 8[shape=box label="Values: (Int64(1))\nSchema: [column1:Int64;N]"] |
3050+ /// | | 7 -> 8 [arrowhead=none, arrowtail=normal, dir=back] |
3051+ /// | | } |
3052+ /// | | } |
3053+ /// | | // End DataFusion GraphViz Plan |
3054+ /// | | |
3055+ /// +--------------+------------------------------------------------------------------------+
3056+ /// ```
3057+ Graphviz ,
3058+ }
3059+
3060+ /// Implement parsing strings to `ExplainFormat`
3061+ impl FromStr for ExplainFormat {
3062+ type Err = DataFusionError ;
3063+
3064+ fn from_str ( format : & str ) -> std:: result:: Result < Self , Self :: Err > {
3065+ match format. to_lowercase ( ) . as_str ( ) {
3066+ "indent" => Ok ( ExplainFormat :: Indent ) ,
3067+ "tree" => Ok ( ExplainFormat :: Tree ) ,
3068+ "pgjson" => Ok ( ExplainFormat :: PostgresJSON ) ,
3069+ "graphviz" => Ok ( ExplainFormat :: Graphviz ) ,
3070+ _ => {
3071+ plan_err ! ( "Invalid explain format. Expected 'indent', 'tree', 'pgjson' or 'graphviz'. Got '{format}'" )
3072+ }
3073+ }
3074+ }
3075+ }
3076+
29273077/// Produces a relation with string representations of
29283078/// various parts of the plan
3079+ ///
3080+ /// See [the documentation] for more information
3081+ ///
3082+ /// [the documentation]: https://datafusion.apache.org/user-guide/sql/explain.html
29293083#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
29303084pub struct Explain {
29313085 /// Should extra (detailed, intermediate plans) be included?
29323086 pub verbose : bool ,
3087+ /// Output format for explain, if specified.
3088+ /// If none, defaults to `text`
3089+ pub explain_format : ExplainFormat ,
29333090 /// The logical plan that is being EXPLAIN'd
29343091 pub plan : Arc < LogicalPlan > ,
29353092 /// Represent the various stages plans have gone through
0 commit comments