@@ -78,8 +78,9 @@ use datafusion_expr::expr::{
7878use datafusion_expr:: expr_rewriter:: unnormalize_cols;
7979use datafusion_expr:: logical_plan:: builder:: wrap_projection_for_join_if_necessary;
8080use datafusion_expr:: {
81- DescribeTable , DmlStatement , Extension , FetchType , Filter , JoinType , RecursiveQuery ,
82- SkipType , SortExpr , StringifiedPlan , WindowFrame , WindowFrameBound , WriteOp ,
81+ Analyze , DescribeTable , DmlStatement , Explain , Extension , FetchType , Filter ,
82+ JoinType , RecursiveQuery , SkipType , SortExpr , StringifiedPlan , WindowFrame ,
83+ WindowFrameBound , WriteOp ,
8384} ;
8485use datafusion_physical_expr:: aggregate:: { AggregateExprBuilder , AggregateFunctionExpr } ;
8586use datafusion_physical_expr:: expressions:: Literal ;
@@ -177,16 +178,17 @@ impl PhysicalPlanner for DefaultPhysicalPlanner {
177178 logical_plan : & LogicalPlan ,
178179 session_state : & SessionState ,
179180 ) -> Result < Arc < dyn ExecutionPlan > > {
180- match self . handle_explain ( logical_plan, session_state) . await ? {
181- Some ( plan) => Ok ( plan) ,
182- None => {
183- let plan = self
184- . create_initial_plan ( logical_plan, session_state)
185- . await ?;
186-
187- self . optimize_physical_plan ( plan, session_state, |_, _| { } )
188- }
181+ if let Some ( plan) = self
182+ . handle_explain_or_analyze ( logical_plan, session_state)
183+ . await ?
184+ {
185+ return Ok ( plan) ;
189186 }
187+ let plan = self
188+ . create_initial_plan ( logical_plan, session_state)
189+ . await ?;
190+
191+ self . optimize_physical_plan ( plan, session_state, |_, _| { } )
190192 }
191193
192194 /// Create a physical expression from a logical expression
@@ -1715,167 +1717,179 @@ impl DefaultPhysicalPlanner {
17151717 /// Returns
17161718 /// Some(plan) if optimized, and None if logical_plan was not an
17171719 /// explain (and thus needs to be optimized as normal)
1718- async fn handle_explain (
1720+ async fn handle_explain_or_analyze (
17191721 & self ,
17201722 logical_plan : & LogicalPlan ,
17211723 session_state : & SessionState ,
17221724 ) -> Result < Option < Arc < dyn ExecutionPlan > > > {
1723- if let LogicalPlan :: Explain ( e) = logical_plan {
1724- use PlanType :: * ;
1725- let mut stringified_plans = vec ! [ ] ;
1725+ let execution_plan = match logical_plan {
1726+ LogicalPlan :: Explain ( e) => self . handle_explain ( e, session_state) . await ?,
1727+ LogicalPlan :: Analyze ( a) => self . handle_analyze ( a, session_state) . await ?,
1728+ _ => return Ok ( None ) ,
1729+ } ;
1730+ Ok ( Some ( execution_plan) )
1731+ }
1732+
1733+ /// Planner for `LogicalPlan::Explain`
1734+ async fn handle_explain (
1735+ & self ,
1736+ e : & Explain ,
1737+ session_state : & SessionState ,
1738+ ) -> Result < Arc < dyn ExecutionPlan > > {
1739+ use PlanType :: * ;
1740+ let mut stringified_plans = vec ! [ ] ;
17261741
1727- let config = & session_state. config_options ( ) . explain ;
1728- let explain_format = DisplayFormatType :: from_str ( & config. format ) ?;
1742+ let config = & session_state. config_options ( ) . explain ;
1743+ let explain_format = DisplayFormatType :: from_str ( & config. format ) ?;
17291744
1730- let skip_logical_plan = config . physical_plan_only
1731- || explain_format == DisplayFormatType :: TreeRender ;
1745+ let skip_logical_plan =
1746+ config . physical_plan_only || explain_format == DisplayFormatType :: TreeRender ;
17321747
1733- if !skip_logical_plan {
1734- stringified_plans. clone_from ( & e. stringified_plans ) ;
1735- if e. logical_optimization_succeeded {
1736- stringified_plans. push ( e. plan . to_stringified ( FinalLogicalPlan ) ) ;
1737- }
1748+ if !skip_logical_plan {
1749+ stringified_plans. clone_from ( & e. stringified_plans ) ;
1750+ if e. logical_optimization_succeeded {
1751+ stringified_plans. push ( e. plan . to_stringified ( FinalLogicalPlan ) ) ;
17381752 }
1753+ }
17391754
1740- if !config. logical_plan_only && e. logical_optimization_succeeded {
1741- match self
1742- . create_initial_plan ( e. plan . as_ref ( ) , session_state)
1743- . await
1744- {
1745- Ok ( input) => {
1746- // Include statistics / schema if enabled
1747- stringified_plans. push (
1748- displayable ( input. as_ref ( ) )
1749- . set_show_statistics ( config. show_statistics )
1750- . set_show_schema ( config. show_schema )
1751- . to_stringified (
1752- e. verbose ,
1753- InitialPhysicalPlan ,
1754- explain_format,
1755- ) ,
1756- ) ;
1755+ if !config. logical_plan_only && e. logical_optimization_succeeded {
1756+ match self
1757+ . create_initial_plan ( e. plan . as_ref ( ) , session_state)
1758+ . await
1759+ {
1760+ Ok ( input) => {
1761+ // Include statistics / schema if enabled
1762+ stringified_plans. push (
1763+ displayable ( input. as_ref ( ) )
1764+ . set_show_statistics ( config. show_statistics )
1765+ . set_show_schema ( config. show_schema )
1766+ . to_stringified (
1767+ e. verbose ,
1768+ InitialPhysicalPlan ,
1769+ explain_format,
1770+ ) ,
1771+ ) ;
17571772
1758- // Show statistics + schema in verbose output even if not
1759- // explicitly requested
1760- if e. verbose {
1761- if !config. show_statistics {
1762- stringified_plans. push (
1763- displayable ( input. as_ref ( ) )
1764- . set_show_statistics ( true )
1765- . to_stringified (
1766- e. verbose ,
1767- InitialPhysicalPlanWithStats ,
1768- explain_format,
1769- ) ,
1770- ) ;
1771- }
1772- if !config. show_schema {
1773- stringified_plans. push (
1774- displayable ( input. as_ref ( ) )
1775- . set_show_schema ( true )
1776- . to_stringified (
1777- e. verbose ,
1778- InitialPhysicalPlanWithSchema ,
1779- explain_format,
1780- ) ,
1781- ) ;
1782- }
1773+ // Show statistics + schema in verbose output even if not
1774+ // explicitly requested
1775+ if e. verbose {
1776+ if !config. show_statistics {
1777+ stringified_plans. push (
1778+ displayable ( input. as_ref ( ) )
1779+ . set_show_statistics ( true )
1780+ . to_stringified (
1781+ e. verbose ,
1782+ InitialPhysicalPlanWithStats ,
1783+ explain_format,
1784+ ) ,
1785+ ) ;
17831786 }
1787+ if !config. show_schema {
1788+ stringified_plans. push (
1789+ displayable ( input. as_ref ( ) )
1790+ . set_show_schema ( true )
1791+ . to_stringified (
1792+ e. verbose ,
1793+ InitialPhysicalPlanWithSchema ,
1794+ explain_format,
1795+ ) ,
1796+ ) ;
1797+ }
1798+ }
17841799
1785- let optimized_plan = self . optimize_physical_plan (
1786- input,
1787- session_state,
1788- |plan, optimizer| {
1789- let optimizer_name = optimizer. name ( ) . to_string ( ) ;
1790- let plan_type = OptimizedPhysicalPlan { optimizer_name } ;
1791- stringified_plans. push (
1792- displayable ( plan)
1793- . set_show_statistics ( config. show_statistics )
1794- . set_show_schema ( config. show_schema )
1795- . to_stringified (
1796- e. verbose ,
1797- plan_type,
1798- explain_format,
1799- ) ,
1800- ) ;
1801- } ,
1802- ) ;
1803- match optimized_plan {
1804- Ok ( input) => {
1805- // This plan will includes statistics if show_statistics is on
1806- stringified_plans. push (
1807- displayable ( input. as_ref ( ) )
1808- . set_show_statistics ( config. show_statistics )
1809- . set_show_schema ( config. show_schema )
1810- . to_stringified (
1811- e. verbose ,
1812- FinalPhysicalPlan ,
1813- explain_format,
1814- ) ,
1815- ) ;
1816-
1817- // Show statistics + schema in verbose output even if not
1818- // explicitly requested
1819- if e. verbose {
1820- if !config. show_statistics {
1821- stringified_plans. push (
1822- displayable ( input. as_ref ( ) )
1823- . set_show_statistics ( true )
1824- . to_stringified (
1825- e. verbose ,
1826- FinalPhysicalPlanWithStats ,
1827- explain_format,
1828- ) ,
1829- ) ;
1830- }
1831- if !config. show_schema {
1832- stringified_plans. push (
1833- displayable ( input. as_ref ( ) )
1834- . set_show_schema ( true )
1835- . to_stringified (
1836- e. verbose ,
1837- FinalPhysicalPlanWithSchema ,
1838- explain_format,
1839- ) ,
1840- ) ;
1841- }
1800+ let optimized_plan = self . optimize_physical_plan (
1801+ input,
1802+ session_state,
1803+ |plan, optimizer| {
1804+ let optimizer_name = optimizer. name ( ) . to_string ( ) ;
1805+ let plan_type = OptimizedPhysicalPlan { optimizer_name } ;
1806+ stringified_plans. push (
1807+ displayable ( plan)
1808+ . set_show_statistics ( config. show_statistics )
1809+ . set_show_schema ( config. show_schema )
1810+ . to_stringified ( e. verbose , plan_type, explain_format) ,
1811+ ) ;
1812+ } ,
1813+ ) ;
1814+ match optimized_plan {
1815+ Ok ( input) => {
1816+ // This plan will includes statistics if show_statistics is on
1817+ stringified_plans. push (
1818+ displayable ( input. as_ref ( ) )
1819+ . set_show_statistics ( config. show_statistics )
1820+ . set_show_schema ( config. show_schema )
1821+ . to_stringified (
1822+ e. verbose ,
1823+ FinalPhysicalPlan ,
1824+ explain_format,
1825+ ) ,
1826+ ) ;
1827+
1828+ // Show statistics + schema in verbose output even if not
1829+ // explicitly requested
1830+ if e. verbose {
1831+ if !config. show_statistics {
1832+ stringified_plans. push (
1833+ displayable ( input. as_ref ( ) )
1834+ . set_show_statistics ( true )
1835+ . to_stringified (
1836+ e. verbose ,
1837+ FinalPhysicalPlanWithStats ,
1838+ explain_format,
1839+ ) ,
1840+ ) ;
1841+ }
1842+ if !config. show_schema {
1843+ stringified_plans. push (
1844+ displayable ( input. as_ref ( ) )
1845+ . set_show_schema ( true )
1846+ . to_stringified (
1847+ e. verbose ,
1848+ FinalPhysicalPlanWithSchema ,
1849+ explain_format,
1850+ ) ,
1851+ ) ;
18421852 }
18431853 }
1844- Err ( DataFusionError :: Context ( optimizer_name, e) ) => {
1845- let plan_type = OptimizedPhysicalPlan { optimizer_name } ;
1846- stringified_plans
1847- . push ( StringifiedPlan :: new ( plan_type, e. to_string ( ) ) )
1848- }
1849- Err ( e) => return Err ( e) ,
18501854 }
1851- }
1852- Err ( err ) => {
1853- stringified_plans. push ( StringifiedPlan :: new (
1854- PhysicalPlanError ,
1855- err . strip_backtrace ( ) ,
1856- ) ) ;
1855+ Err ( DataFusionError :: Context ( optimizer_name , e ) ) => {
1856+ let plan_type = OptimizedPhysicalPlan { optimizer_name } ;
1857+ stringified_plans
1858+ . push ( StringifiedPlan :: new ( plan_type , e . to_string ( ) ) )
1859+ }
1860+ Err ( e ) => return Err ( e ) ,
18571861 }
18581862 }
1863+ Err ( err) => {
1864+ stringified_plans. push ( StringifiedPlan :: new (
1865+ PhysicalPlanError ,
1866+ err. strip_backtrace ( ) ,
1867+ ) ) ;
1868+ }
18591869 }
1860-
1861- Ok ( Some ( Arc :: new ( ExplainExec :: new (
1862- SchemaRef :: new ( e. schema . as_ref ( ) . to_owned ( ) . into ( ) ) ,
1863- stringified_plans,
1864- e. verbose ,
1865- ) ) ) )
1866- } else if let LogicalPlan :: Analyze ( a) = logical_plan {
1867- let input = self . create_physical_plan ( & a. input , session_state) . await ?;
1868- let schema = SchemaRef :: new ( ( * a. schema ) . clone ( ) . into ( ) ) ;
1869- let show_statistics = session_state. config_options ( ) . explain . show_statistics ;
1870- Ok ( Some ( Arc :: new ( AnalyzeExec :: new (
1871- a. verbose ,
1872- show_statistics,
1873- input,
1874- schema,
1875- ) ) ) )
1876- } else {
1877- Ok ( None )
18781870 }
1871+
1872+ Ok ( Arc :: new ( ExplainExec :: new (
1873+ Arc :: clone ( e. schema . inner ( ) ) ,
1874+ stringified_plans,
1875+ e. verbose ,
1876+ ) ) )
1877+ }
1878+
1879+ async fn handle_analyze (
1880+ & self ,
1881+ a : & Analyze ,
1882+ session_state : & SessionState ,
1883+ ) -> Result < Arc < dyn ExecutionPlan > > {
1884+ let input = self . create_physical_plan ( & a. input , session_state) . await ?;
1885+ let schema = SchemaRef :: new ( ( * a. schema ) . clone ( ) . into ( ) ) ;
1886+ let show_statistics = session_state. config_options ( ) . explain . show_statistics ;
1887+ Ok ( Arc :: new ( AnalyzeExec :: new (
1888+ a. verbose ,
1889+ show_statistics,
1890+ input,
1891+ schema,
1892+ ) ) )
18791893 }
18801894
18811895 /// Optimize a physical plan by applying each physical optimizer,
0 commit comments