From 4502c00a468594873c7e5929b9aeced206f2d937 Mon Sep 17 00:00:00 2001 From: xiedeyantu Date: Sun, 17 May 2026 22:37:47 +0800 Subject: [PATCH 1/4] fix ^ evaluates as bitwise XOR instead of exponentiation --- datafusion/sql/src/expr/mod.rs | 17 +++++++++++++++++ datafusion/sqllogictest/test_files/scalar.slt | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs index daf092ecd4cf9..83e15b4704ecc 100644 --- a/datafusion/sql/src/expr/mod.rs +++ b/datafusion/sql/src/expr/mod.rs @@ -142,6 +142,23 @@ impl SqlToRel<'_, S> { } let RawBinaryExpr { op, left, right } = binary_expr; + if op == BinaryOperator::PGExp { + let fun_name = "power"; + let fun = self + .context_provider + .get_function_meta(fun_name) + .ok_or_else(|| { + internal_datafusion_err!( + "Unable to find expected '{fun_name}' function" + ) + })?; + + return Ok(Expr::ScalarFunction(ScalarFunction::new_udf( + fun, + vec![left, right], + ))); + } + Ok(Expr::BinaryExpr(BinaryExpr::new( Box::new(left), self.parse_sql_binary_op(&op)?, diff --git a/datafusion/sqllogictest/test_files/scalar.slt b/datafusion/sqllogictest/test_files/scalar.slt index 89ae30e3c047b..2ac7a9ef364c4 100644 --- a/datafusion/sqllogictest/test_files/scalar.slt +++ b/datafusion/sqllogictest/test_files/scalar.slt @@ -1300,6 +1300,12 @@ NULL -32 statement ok set datafusion.sql_parser.dialect = postgresql; +# postgresql exponentiation uses caret +query R +select 2 ^ 3; +---- +8 + # postgresql bitwise xor with column and scalar query I rowsort select c # 856 from signed_integers; From 7d9e28c0ca99c3463d53c632eebce42046e88dce Mon Sep 17 00:00:00 2001 From: xiedeyantu Date: Mon, 18 May 2026 18:28:02 +0800 Subject: [PATCH 2/4] fix --- datafusion/sql/src/expr/binary_op.rs | 34 +++++++++++++++++++++++++++- datafusion/sql/src/expr/mod.rs | 23 +------------------ 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/datafusion/sql/src/expr/binary_op.rs b/datafusion/sql/src/expr/binary_op.rs index 4e9025e02e0c7..ca747587f6df3 100644 --- a/datafusion/sql/src/expr/binary_op.rs +++ b/datafusion/sql/src/expr/binary_op.rs @@ -16,8 +16,10 @@ // under the License. use crate::planner::{ContextProvider, SqlToRel}; -use datafusion_common::{Result, not_impl_err}; +use datafusion_common::{Result, internal_datafusion_err, not_impl_err}; use datafusion_expr::Operator; +use datafusion_expr::expr::ScalarFunction; +use datafusion_expr::{BinaryExpr, Expr}; use sqlparser::ast::BinaryOperator; impl SqlToRel<'_, S> { @@ -72,4 +74,34 @@ impl SqlToRel<'_, S> { _ => not_impl_err!("Unsupported binary operator: {:?}", op), } } + + pub(crate) fn build_binary_expr( + &self, + op: BinaryOperator, + left: Expr, + right: Expr, + ) -> Result { + if op == BinaryOperator::PGExp { + let fun_name = "power"; + let fun = self + .context_provider + .get_function_meta(fun_name) + .ok_or_else(|| { + internal_datafusion_err!( + "Unable to find expected '{fun_name}' function" + ) + })?; + + return Ok(Expr::ScalarFunction(ScalarFunction::new_udf( + fun, + vec![left, right], + ))); + } + + Ok(Expr::BinaryExpr(BinaryExpr::new( + Box::new(left), + self.parse_sql_binary_op(&op)?, + Box::new(right), + ))) + } } diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs index 83e15b4704ecc..1d375a500acd9 100644 --- a/datafusion/sql/src/expr/mod.rs +++ b/datafusion/sql/src/expr/mod.rs @@ -142,28 +142,7 @@ impl SqlToRel<'_, S> { } let RawBinaryExpr { op, left, right } = binary_expr; - if op == BinaryOperator::PGExp { - let fun_name = "power"; - let fun = self - .context_provider - .get_function_meta(fun_name) - .ok_or_else(|| { - internal_datafusion_err!( - "Unable to find expected '{fun_name}' function" - ) - })?; - - return Ok(Expr::ScalarFunction(ScalarFunction::new_udf( - fun, - vec![left, right], - ))); - } - - Ok(Expr::BinaryExpr(BinaryExpr::new( - Box::new(left), - self.parse_sql_binary_op(&op)?, - Box::new(right), - ))) + self.build_binary_expr(op, left, right) } pub fn sql_to_expr_with_alias( From 996e34cbbfaffdc1b77cc1a98b2b114624aa3a66 Mon Sep 17 00:00:00 2001 From: Zhen Chen Date: Mon, 18 May 2026 22:19:09 +0800 Subject: [PATCH 3/4] Change binary operator parameter to reference --- datafusion/sql/src/expr/binary_op.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datafusion/sql/src/expr/binary_op.rs b/datafusion/sql/src/expr/binary_op.rs index ca747587f6df3..f50a614723454 100644 --- a/datafusion/sql/src/expr/binary_op.rs +++ b/datafusion/sql/src/expr/binary_op.rs @@ -77,7 +77,7 @@ impl SqlToRel<'_, S> { pub(crate) fn build_binary_expr( &self, - op: BinaryOperator, + op: &BinaryOperator, left: Expr, right: Expr, ) -> Result { From a8ab1ec2e8859125878085713a18359bf5bc614c Mon Sep 17 00:00:00 2001 From: xiedeyantu Date: Tue, 19 May 2026 07:18:27 +0800 Subject: [PATCH 4/4] update --- datafusion/sql/src/expr/binary_op.rs | 4 ++-- datafusion/sql/src/expr/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/datafusion/sql/src/expr/binary_op.rs b/datafusion/sql/src/expr/binary_op.rs index f50a614723454..c3e7939370e85 100644 --- a/datafusion/sql/src/expr/binary_op.rs +++ b/datafusion/sql/src/expr/binary_op.rs @@ -81,7 +81,7 @@ impl SqlToRel<'_, S> { left: Expr, right: Expr, ) -> Result { - if op == BinaryOperator::PGExp { + if matches!(op, BinaryOperator::PGExp) { let fun_name = "power"; let fun = self .context_provider @@ -100,7 +100,7 @@ impl SqlToRel<'_, S> { Ok(Expr::BinaryExpr(BinaryExpr::new( Box::new(left), - self.parse_sql_binary_op(&op)?, + self.parse_sql_binary_op(op)?, Box::new(right), ))) } diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs index 1d375a500acd9..29b75243ea09c 100644 --- a/datafusion/sql/src/expr/mod.rs +++ b/datafusion/sql/src/expr/mod.rs @@ -142,7 +142,7 @@ impl SqlToRel<'_, S> { } let RawBinaryExpr { op, left, right } = binary_expr; - self.build_binary_expr(op, left, right) + self.build_binary_expr(&op, left, right) } pub fn sql_to_expr_with_alias(