diff --git a/datafusion/core/tests/sql/expr.rs b/datafusion/core/tests/sql/expr.rs index 12344e4703d3..bb9f69dffc27 100644 --- a/datafusion/core/tests/sql/expr.rs +++ b/datafusion/core/tests/sql/expr.rs @@ -646,6 +646,24 @@ async fn test_not_expressions() -> Result<()> { Ok(()) } +#[tokio::test] +async fn test_negative_expressions() -> Result<()> { + let ctx = SessionContext::new(); + + let sql = "SELECT null, -null"; + let actual = execute_to_batches(&ctx, sql).await; + let expected = vec![ + "+------+----------+", + "| NULL | (- NULL) |", + "+------+----------+", + "| | |", + "+------+----------+", + ]; + + assert_batches_eq!(expected, &actual); + Ok(()) +} + #[tokio::test] async fn test_boolean_expressions() -> Result<()> { test_expression!("true", "true"); diff --git a/datafusion/expr/src/type_coercion.rs b/datafusion/expr/src/type_coercion.rs index 41eeb3c650b1..4a006ad87a27 100644 --- a/datafusion/expr/src/type_coercion.rs +++ b/datafusion/expr/src/type_coercion.rs @@ -48,6 +48,11 @@ pub fn is_signed_numeric(dt: &DataType) -> bool { ) } +// Determine if a DataType is Null or not +pub fn is_null(dt: &DataType) -> bool { + *dt == DataType::Null +} + /// Determine if a DataType is numeric or not pub fn is_numeric(dt: &DataType) -> bool { is_signed_numeric(dt) diff --git a/datafusion/physical-expr/src/expressions/negative.rs b/datafusion/physical-expr/src/expressions/negative.rs index 233ad42547ca..4f4def99e821 100644 --- a/datafusion/physical-expr/src/expressions/negative.rs +++ b/datafusion/physical-expr/src/expressions/negative.rs @@ -30,7 +30,10 @@ use arrow::{ use crate::PhysicalExpr; use datafusion_common::{DataFusionError, Result}; -use datafusion_expr::{type_coercion::is_signed_numeric, ColumnarValue}; +use datafusion_expr::{ + type_coercion::{is_null, is_signed_numeric}, + ColumnarValue, +}; /// Invoke a compute kernel on array(s) macro_rules! compute_op { @@ -119,7 +122,9 @@ pub fn negative( input_schema: &Schema, ) -> Result> { let data_type = arg.data_type(input_schema)?; - if !is_signed_numeric(&data_type) { + if is_null(&data_type) { + Ok(arg) + } else if !is_signed_numeric(&data_type) { Err(DataFusionError::Internal( format!("Can't create negative physical expr for (- '{:?}'), the type of child expr is {}, not signed numeric", arg, data_type), ))