diff --git a/datafusion/expr/src/tree_node/expr.rs b/datafusion/expr/src/tree_node/expr.rs index de407063d78f0..ee775b4012de0 100644 --- a/datafusion/expr/src/tree_node/expr.rs +++ b/datafusion/expr/src/tree_node/expr.rs @@ -17,6 +17,8 @@ //! Tree node implementation for logical expr +use std::mem; + use crate::expr::{ AggregateFunction, AggregateFunctionDefinition, Alias, Between, BinaryExpr, Case, Cast, GetIndexedField, GroupingSet, InList, InSubquery, Like, Placeholder, @@ -429,15 +431,14 @@ impl TreeNode for Expr { } } -fn transform_boxed(boxed_expr: Box, transform: &mut F) -> Result> +fn transform_boxed(mut boxed_expr: Box, transform: &mut F) -> Result> where F: FnMut(Expr) -> Result, { - // TODO: - // It might be possible to avoid an allocation (the Box::new) below by reusing the box. - let expr: Expr = *boxed_expr; - let rewritten_expr = transform(expr)?; - Ok(Box::new(rewritten_expr)) + // We reuse the existing Box to avoid an allocation: + let t = mem::replace(&mut *boxed_expr, Expr::Wildcard { qualifier: None }); + let _ = mem::replace(&mut *boxed_expr, transform(t)?); + Ok(boxed_expr) } fn transform_option_box( @@ -468,9 +469,14 @@ where } /// &mut transform a `Vec` of `Expr`s -fn transform_vec(v: Vec, transform: &mut F) -> Result> +fn transform_vec(mut v: Vec, transform: &mut F) -> Result> where F: FnMut(Expr) -> Result, { - v.into_iter().map(transform).collect() + // Perform an in-place mutation of the Vec to avoid allocation: + for expr in v.iter_mut() { + let t = mem::replace(expr, Expr::Wildcard { qualifier: None }); + let _ = mem::replace(expr, transform(t)?); + } + Ok(v) }