Repository navigation
Description
Describe the bug
#[tokio::test]
async fn test_unary_negation_on_string_error() -> Result<()> {
let ctx = SessionContext::new();
let res = ctx.sql("SELECT -'a';").await;
assert!(res.is_err());
Ok(())
}Negation operator can't work on Utf8 should be reported at planning phase, but this test failed.
Root Cause
It invokes Expr::to_field to check types and get filed of each expressions in query while generating logical plan . However, in the Expr::Negative bench it only returns the field of its inner expression:
datafusion/datafusion/expr/src/expr_schema.rs
Line 452 in 7d217b1
| Expr::Negative(expr) => expr.to_field(schema).map(|(_, f)| f), |
Similarly, it also returns the types of its inner expression in Expr::get_type, which cause it also escape checks in type_coercion.
datafusion/datafusion/expr/src/expr_schema.rs
Line 119 in 7d217b1
| Expr::Negative(expr) => expr.get_type(schema), |
Finally, it will be caught while generating physical plan (in some code like df.show());
datafusion/datafusion/physical-expr/src/expressions/negative.rs
Lines 188 to 199 in 7d217b1
| pub fn negative( | |
| arg: Arc<dyn PhysicalExpr>, | |
| input_schema: &Schema, | |
| ) -> Result<Arc<dyn PhysicalExpr>> { | |
| let data_type = arg.data_type(input_schema)?; | |
| if data_type.is_null() { | |
| Ok(arg) | |
| } else if !is_signed_numeric(&data_type) | |
| && !is_interval(&data_type) | |
| && !is_timestamp(&data_type) | |
| { | |
| plan_err!("Negation only supports numeric, interval and timestamp types") |
Fix
It's quite strightforward, I'll open a pr soon.
Activity
Acfboy commentedon Feb 14, 2026
take
u70b3 commentedon Jul 20, 2026
Verified on current main (1e58928): this no longer reproduces.
SELECT -'a';is now rejected during planning withError during planning: Unary operator '-' only supports signed numeric, interval and timestamp types— exactly the behavior requested in the issue. Suggest closing.