diff --git a/datafusion/src/sql/planner.rs b/datafusion/src/sql/planner.rs index 44fc0b2eba6cf..6695d89112a68 100644 --- a/datafusion/src/sql/planner.rs +++ b/datafusion/src/sql/planner.rs @@ -49,7 +49,7 @@ use sqlparser::ast::{ BinaryOperator, DataType as SQLDataType, DateTimeField, Expr as SQLExpr, FunctionArg, Ident, Join, JoinConstraint, JoinOperator, ObjectName, Query, Select, SelectItem, SetExpr, SetOperator, ShowStatementFilter, TableFactor, TableWithJoins, - UnaryOperator, Value, + TrimWhereField, UnaryOperator, Value, }; use sqlparser::ast::{ColumnDef as SQLColumnDef, ColumnOption}; use sqlparser::ast::{OrderByExpr, Statement}; @@ -1275,21 +1275,27 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { } SQLExpr::Trim { expr, trim_where } => { - let fun = match trim_where { - Some((trim_where, _expr)) => { - return Err(DataFusionError::Plan(format!( - "TRIM {} is not yet supported ", - trim_where - ))) + let (fun, where_expr) = match trim_where { + Some((TrimWhereField::Leading, expr)) => { + (functions::BuiltinScalarFunction::Ltrim, Some(expr)) } - None => functions::BuiltinScalarFunction::Trim, + Some((TrimWhereField::Trailing, expr)) => { + (functions::BuiltinScalarFunction::Rtrim, Some(expr)) + } + Some((TrimWhereField::Both, expr)) => { + (functions::BuiltinScalarFunction::Btrim, Some(expr)) + } + None => (functions::BuiltinScalarFunction::Trim, None), }; - let arg = self.sql_expr_to_logical_expr(expr, schema)?; - Ok(Expr::ScalarFunction { - fun, - args: vec![arg], - }) + let args = match where_expr { + Some(to_trim) => { + let to_trim = self.sql_expr_to_logical_expr(to_trim, schema)?; + vec![arg, to_trim] + } + None => vec![arg], + }; + Ok(Expr::ScalarFunction { fun, args }) } SQLExpr::Function(function) => { diff --git a/datafusion/tests/sql.rs b/datafusion/tests/sql.rs index 33788a95d394e..5ddb8dec8351d 100644 --- a/datafusion/tests/sql.rs +++ b/datafusion/tests/sql.rs @@ -3811,6 +3811,15 @@ async fn test_string_expressions() -> Result<()> { test_expression!("to_hex(9223372036854775807)", "7fffffffffffffff"); test_expression!("to_hex(CAST(NULL AS int))", "NULL"); test_expression!("trim(' tom ')", "tom"); + test_expression!("trim(LEADING ' ' FROM ' tom ')", "tom "); + test_expression!("trim(TRAILING ' ' FROM ' tom ')", " tom"); + test_expression!("trim(BOTH ' ' FROM ' tom ')", "tom"); + test_expression!("trim(LEADING 'x' FROM 'xxxtomxxx')", "tomxxx"); + test_expression!("trim(TRAILING 'x' FROM 'xxxtomxxx')", "xxxtom"); + test_expression!("trim(BOTH 'x' FROM 'xxxtomxx')", "tom"); + test_expression!("trim(LEADING 'xy' FROM 'xyxabcxyzdefxyx')", "abcxyzdefxyx"); + test_expression!("trim(TRAILING 'xy' FROM 'xyxabcxyzdefxyx')", "xyxabcxyzdef"); + test_expression!("trim(BOTH 'xy' FROM 'xyxabcxyzdefxyx')", "abcxyzdef"); test_expression!("trim(' tom')", "tom"); test_expression!("trim('')", ""); test_expression!("trim('tom ')", "tom");