1515// specific language governing permissions and limitations
1616// under the License.
1717
18+ use std:: fmt:: { self , Display } ;
19+ use std:: str:: FromStr ;
20+
1821use arrow:: compute:: CastOptions ;
1922use arrow:: util:: display:: { DurationFormat , FormatOptions } ;
2023
24+ use crate :: config:: { ConfigField , Visit } ;
25+ use crate :: error:: { DataFusionError , Result } ;
26+
2127/// The default [`FormatOptions`] to use within DataFusion
2228/// Also see [`crate::config::FormatOptions`]
2329pub const DEFAULT_FORMAT_OPTIONS : FormatOptions < ' static > =
@@ -28,3 +34,174 @@ pub const DEFAULT_CAST_OPTIONS: CastOptions<'static> = CastOptions {
2834 safe : false ,
2935 format_options : DEFAULT_FORMAT_OPTIONS ,
3036} ;
37+
38+ /// Output formats for controlling for Explain plans
39+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
40+ pub enum ExplainFormat {
41+ /// Indent mode
42+ ///
43+ /// Example:
44+ /// ```text
45+ /// > explain format indent select x from values (1) t(x);
46+ /// +---------------+-----------------------------------------------------+
47+ /// | plan_type | plan |
48+ /// +---------------+-----------------------------------------------------+
49+ /// | logical_plan | SubqueryAlias: t |
50+ /// | | Projection: column1 AS x |
51+ /// | | Values: (Int64(1)) |
52+ /// | physical_plan | ProjectionExec: expr=[column1@0 as x] |
53+ /// | | DataSourceExec: partitions=1, partition_sizes=[1] |
54+ /// | | |
55+ /// +---------------+-----------------------------------------------------+
56+ /// ```
57+ Indent ,
58+ /// Tree mode
59+ ///
60+ /// Example:
61+ /// ```text
62+ /// > explain format tree select x from values (1) t(x);
63+ /// +---------------+-------------------------------+
64+ /// | plan_type | plan |
65+ /// +---------------+-------------------------------+
66+ /// | physical_plan | ┌───────────────────────────┐ |
67+ /// | | │ ProjectionExec │ |
68+ /// | | │ -------------------- │ |
69+ /// | | │ x: column1@0 │ |
70+ /// | | └─────────────┬─────────────┘ |
71+ /// | | ┌─────────────┴─────────────┐ |
72+ /// | | │ DataSourceExec │ |
73+ /// | | │ -------------------- │ |
74+ /// | | │ bytes: 128 │ |
75+ /// | | │ format: memory │ |
76+ /// | | │ rows: 1 │ |
77+ /// | | └───────────────────────────┘ |
78+ /// | | |
79+ /// +---------------+-------------------------------+
80+ /// ```
81+ Tree ,
82+ /// Postgres Json mode
83+ ///
84+ /// A displayable structure that produces plan in postgresql JSON format.
85+ ///
86+ /// Users can use this format to visualize the plan in existing plan
87+ /// visualization tools, for example [dalibo](https://explain.dalibo.com/)
88+ ///
89+ /// Example:
90+ /// ```text
91+ /// > explain format pgjson select x from values (1) t(x);
92+ /// +--------------+--------------------------------------+
93+ /// | plan_type | plan |
94+ /// +--------------+--------------------------------------+
95+ /// | logical_plan | [ |
96+ /// | | { |
97+ /// | | "Plan": { |
98+ /// | | "Alias": "t", |
99+ /// | | "Node Type": "Subquery", |
100+ /// | | "Output": [ |
101+ /// | | "x" |
102+ /// | | ], |
103+ /// | | "Plans": [ |
104+ /// | | { |
105+ /// | | "Expressions": [ |
106+ /// | | "column1 AS x" |
107+ /// | | ], |
108+ /// | | "Node Type": "Projection", |
109+ /// | | "Output": [ |
110+ /// | | "x" |
111+ /// | | ], |
112+ /// | | "Plans": [ |
113+ /// | | { |
114+ /// | | "Node Type": "Values", |
115+ /// | | "Output": [ |
116+ /// | | "column1" |
117+ /// | | ], |
118+ /// | | "Plans": [], |
119+ /// | | "Values": "(Int64(1))" |
120+ /// | | } |
121+ /// | | ] |
122+ /// | | } |
123+ /// | | ] |
124+ /// | | } |
125+ /// | | } |
126+ /// | | ] |
127+ /// +--------------+--------------------------------------+
128+ /// ```
129+ PostgresJSON ,
130+ /// Graphviz mode
131+ ///
132+ /// Example:
133+ /// ```text
134+ /// > explain format graphviz select x from values (1) t(x);
135+ /// +--------------+------------------------------------------------------------------------+
136+ /// | plan_type | plan |
137+ /// +--------------+------------------------------------------------------------------------+
138+ /// | logical_plan | |
139+ /// | | // Begin DataFusion GraphViz Plan, |
140+ /// | | // display it online here: https://dreampuf.github.io/GraphvizOnline |
141+ /// | | |
142+ /// | | digraph { |
143+ /// | | subgraph cluster_1 |
144+ /// | | { |
145+ /// | | graph[label="LogicalPlan"] |
146+ /// | | 2[shape=box label="SubqueryAlias: t"] |
147+ /// | | 3[shape=box label="Projection: column1 AS x"] |
148+ /// | | 2 -> 3 [arrowhead=none, arrowtail=normal, dir=back] |
149+ /// | | 4[shape=box label="Values: (Int64(1))"] |
150+ /// | | 3 -> 4 [arrowhead=none, arrowtail=normal, dir=back] |
151+ /// | | } |
152+ /// | | subgraph cluster_5 |
153+ /// | | { |
154+ /// | | graph[label="Detailed LogicalPlan"] |
155+ /// | | 6[shape=box label="SubqueryAlias: t\nSchema: [x:Int64;N]"] |
156+ /// | | 7[shape=box label="Projection: column1 AS x\nSchema: [x:Int64;N]"] |
157+ /// | | 6 -> 7 [arrowhead=none, arrowtail=normal, dir=back] |
158+ /// | | 8[shape=box label="Values: (Int64(1))\nSchema: [column1:Int64;N]"] |
159+ /// | | 7 -> 8 [arrowhead=none, arrowtail=normal, dir=back] |
160+ /// | | } |
161+ /// | | } |
162+ /// | | // End DataFusion GraphViz Plan |
163+ /// | | |
164+ /// +--------------+------------------------------------------------------------------------+
165+ /// ```
166+ Graphviz ,
167+ }
168+
169+ /// Implement parsing strings to `ExplainFormat`
170+ impl FromStr for ExplainFormat {
171+ type Err = DataFusionError ;
172+
173+ fn from_str ( format : & str ) -> Result < Self , Self :: Err > {
174+ match format. to_lowercase ( ) . as_str ( ) {
175+ "indent" => Ok ( ExplainFormat :: Indent ) ,
176+ "tree" => Ok ( ExplainFormat :: Tree ) ,
177+ "pgjson" => Ok ( ExplainFormat :: PostgresJSON ) ,
178+ "graphviz" => Ok ( ExplainFormat :: Graphviz ) ,
179+ _ => {
180+ Err ( DataFusionError :: Configuration ( format ! ( "Invalid explain format. Expected 'indent', 'tree', 'pgjson' or 'graphviz'. Got '{format}'" ) ) )
181+ }
182+ }
183+ }
184+ }
185+
186+ impl Display for ExplainFormat {
187+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
188+ let s = match self {
189+ ExplainFormat :: Indent => "indent" ,
190+ ExplainFormat :: Tree => "tree" ,
191+ ExplainFormat :: PostgresJSON => "pgjson" ,
192+ ExplainFormat :: Graphviz => "graphviz" ,
193+ } ;
194+ write ! ( f, "{s}" )
195+ }
196+ }
197+
198+ impl ConfigField for ExplainFormat {
199+ fn visit < V : Visit > ( & self , v : & mut V , key : & str , description : & ' static str ) {
200+ v. some ( key, self , description)
201+ }
202+
203+ fn set ( & mut self , _: & str , value : & str ) -> Result < ( ) > {
204+ * self = ExplainFormat :: from_str ( value) ?;
205+ Ok ( ( ) )
206+ }
207+ }
0 commit comments