@@ -307,6 +307,15 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
307307
308308 let mut intermediate_plan = input;
309309 let mut intermediate_select_exprs = select_exprs;
310+ // Fast path: If there is are no unnests in the select_exprs, wrap the plan in a projection
311+ if !intermediate_select_exprs
312+ . iter ( )
313+ . any ( has_unnest_expr_recursively)
314+ {
315+ return LogicalPlanBuilder :: from ( intermediate_plan)
316+ . project ( intermediate_select_exprs) ?
317+ . build ( ) ;
318+ }
310319
311320 // Each expr in select_exprs can contains multiple unnest stage
312321 // The transformation happen bottom up, one at a time for each iteration
@@ -374,6 +383,12 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
374383
375384 fn try_process_aggregate_unnest ( & self , input : LogicalPlan ) -> Result < LogicalPlan > {
376385 match input {
386+ // Fast path if there are no unnest in group by
387+ LogicalPlan :: Aggregate ( ref agg)
388+ if !& agg. group_expr . iter ( ) . any ( has_unnest_expr_recursively) =>
389+ {
390+ Ok ( input)
391+ }
377392 LogicalPlan :: Aggregate ( agg) => {
378393 let agg_expr = agg. aggr_expr . clone ( ) ;
379394 let ( new_input, new_group_by_exprs) =
@@ -939,3 +954,17 @@ fn check_conflicting_windows(window_defs: &[NamedWindowDefinition]) -> Result<()
939954 }
940955 Ok ( ( ) )
941956}
957+
958+ /// Returns true if the expression recursively contains an `Expr::Unnest` expression
959+ fn has_unnest_expr_recursively ( expr : & Expr ) -> bool {
960+ let mut has_unnest = false ;
961+ let _ = expr. apply ( |e| {
962+ if let Expr :: Unnest ( _) = e {
963+ has_unnest = true ;
964+ Ok ( TreeNodeRecursion :: Stop )
965+ } else {
966+ Ok ( TreeNodeRecursion :: Continue )
967+ }
968+ } ) ;
969+ has_unnest
970+ }
0 commit comments