Skip to content

Commit 975ff15

Browse files
authored
More descriptive error for plus/minus between timestamps/dates (#4662)
1 parent 891a800 commit 975ff15

1 file changed

Lines changed: 33 additions & 5 deletions

File tree

‎datafusion/expr/src/type_coercion/binary.rs‎

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
//! Coercion rules for matching argument types for binary operators
1919
20-
use crate::type_coercion::is_numeric;
20+
use crate::type_coercion::{is_date, is_numeric, is_timestamp};
2121
use crate::Operator;
2222
use arrow::compute::can_cast_types;
2323
use arrow::datatypes::{
@@ -121,14 +121,22 @@ pub fn coerce_types(
121121
Operator::Like | Operator::NotLike | Operator::ILike | Operator::NotILike => {
122122
like_coercion(lhs_type, rhs_type)
123123
}
124-
// date +/- interval returns date
125124
Operator::Plus | Operator::Minus
126-
if (*lhs_type == DataType::Date32
127-
|| *lhs_type == DataType::Date64
128-
|| matches!(lhs_type, DataType::Timestamp(_, _))) =>
125+
if is_date(lhs_type) || is_timestamp(lhs_type) =>
129126
{
130127
match rhs_type {
128+
// timestamp/date +/- interval returns timestamp/date
131129
DataType::Interval(_) => Some(lhs_type.clone()),
130+
// providing more helpful error message
131+
DataType::Date32 | DataType::Date64 | DataType::Timestamp(_, _) => {
132+
return Err(DataFusionError::Plan(
133+
format!(
134+
"'{:?} {} {:?}' is an unsupported operation. \
135+
addition/subtraction on dates/timestamps only supported with interval types",
136+
lhs_type, op, rhs_type
137+
),
138+
));
139+
}
132140
_ => None,
133141
}
134142
}
@@ -672,6 +680,7 @@ mod tests {
672680
use super::*;
673681
use crate::Operator;
674682
use arrow::datatypes::DataType;
683+
use datafusion_common::assert_contains;
675684
use datafusion_common::DataFusionError;
676685
use datafusion_common::Result;
677686

@@ -848,6 +857,25 @@ mod tests {
848857
}};
849858
}
850859

860+
#[test]
861+
fn test_date_timestamp_arithmetic_error() -> Result<()> {
862+
let err = coerce_types(
863+
&DataType::Timestamp(TimeUnit::Nanosecond, None),
864+
&Operator::Minus,
865+
&DataType::Timestamp(TimeUnit::Nanosecond, None),
866+
)
867+
.unwrap_err()
868+
.to_string();
869+
assert_contains!(&err, "'Timestamp(Nanosecond, None) - Timestamp(Nanosecond, None)' is an unsupported operation. addition/subtraction on dates/timestamps only supported with interval types");
870+
871+
let err = coerce_types(&DataType::Date32, &Operator::Plus, &DataType::Date64)
872+
.unwrap_err()
873+
.to_string();
874+
assert_contains!(&err, "'Date32 + Date64' is an unsupported operation. addition/subtraction on dates/timestamps only supported with interval types");
875+
876+
Ok(())
877+
}
878+
851879
#[test]
852880
fn test_type_coercion() -> Result<()> {
853881
test_coercion_binary_rule!(

0 commit comments

Comments
 (0)