This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new b9bf6c9ec4 Fix `Duration` vs `Interval` comparisons and `Interval` as
LHS (#11876)
b9bf6c9ec4 is described below
commit b9bf6c9ec4698aa7a383a936328ef7df22e8fbb3
Author: Samuel Colvin <[email protected]>
AuthorDate: Thu Aug 8 17:51:37 2024 +0100
Fix `Duration` vs `Interval` comparisons and `Interval` as LHS (#11876)
* fix duration vs. interval and interval as LHS
* add more operators to "interval vs. duration comparison" slt tests
---
datafusion/expr/src/type_coercion/binary.rs | 4 +-
datafusion/sql/src/expr/value.rs | 6 +++
datafusion/sql/tests/cases/plan_to_sql.rs | 31 ++++++++++++
datafusion/sqllogictest/test_files/timestamps.slt | 62 +++++++++++++++++++++++
4 files changed, 102 insertions(+), 1 deletion(-)
diff --git a/datafusion/expr/src/type_coercion/binary.rs
b/datafusion/expr/src/type_coercion/binary.rs
index 8da33081d6..6de0118f6b 100644
--- a/datafusion/expr/src/type_coercion/binary.rs
+++ b/datafusion/expr/src/type_coercion/binary.rs
@@ -1130,7 +1130,9 @@ fn temporal_coercion(lhs_type: &DataType, rhs_type:
&DataType) -> Option<DataTyp
use arrow::datatypes::TimeUnit::*;
match (lhs_type, rhs_type) {
- (Interval(_), Interval(_)) => Some(Interval(MonthDayNano)),
+ (Interval(_) | Duration(_), Interval(_) | Duration(_)) => {
+ Some(Interval(MonthDayNano))
+ }
(Date64, Date32) | (Date32, Date64) => Some(Date64),
(Timestamp(_, None), Date64) | (Date64, Timestamp(_, None)) => {
Some(Timestamp(Nanosecond, None))
diff --git a/datafusion/sql/src/expr/value.rs b/datafusion/sql/src/expr/value.rs
index 1564f06fe4..afcd182fa3 100644
--- a/datafusion/sql/src/expr/value.rs
+++ b/datafusion/sql/src/expr/value.rs
@@ -227,6 +227,12 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
let df_op = match op {
BinaryOperator::Plus => Operator::Plus,
BinaryOperator::Minus => Operator::Minus,
+ BinaryOperator::Eq => Operator::Eq,
+ BinaryOperator::NotEq => Operator::NotEq,
+ BinaryOperator::Gt => Operator::Gt,
+ BinaryOperator::GtEq => Operator::GtEq,
+ BinaryOperator::Lt => Operator::Lt,
+ BinaryOperator::LtEq => Operator::LtEq,
_ => {
return not_impl_err!("Unsupported interval operator:
{op:?}");
}
diff --git a/datafusion/sql/tests/cases/plan_to_sql.rs
b/datafusion/sql/tests/cases/plan_to_sql.rs
index 8f9f1dd78f..2ac3034873 100644
--- a/datafusion/sql/tests/cases/plan_to_sql.rs
+++ b/datafusion/sql/tests/cases/plan_to_sql.rs
@@ -549,3 +549,34 @@ fn test_pretty_roundtrip() -> Result<()> {
Ok(())
}
+
+fn sql_round_trip(query: &str, expect: &str) {
+ let statement = Parser::new(&GenericDialect {})
+ .try_with_sql(query)
+ .unwrap()
+ .parse_statement()
+ .unwrap();
+
+ let context = MockContextProvider::default();
+ let sql_to_rel = SqlToRel::new(&context);
+ let plan = sql_to_rel.sql_statement_to_plan(statement).unwrap();
+
+ let roundtrip_statement = plan_to_sql(&plan).unwrap();
+ assert_eq!(roundtrip_statement.to_string(), expect);
+}
+
+#[test]
+fn test_interval_lhs_eq() {
+ sql_round_trip(
+ "select interval '2 seconds' = interval '2 seconds'",
+ "SELECT (INTERVAL '0 YEARS 0 MONS 0 DAYS 0 HOURS 0 MINS 2.000000000
SECS' = INTERVAL '0 YEARS 0 MONS 0 DAYS 0 HOURS 0 MINS 2.000000000 SECS')",
+ );
+}
+
+#[test]
+fn test_interval_lhs_lt() {
+ sql_round_trip(
+ "select interval '2 seconds' < interval '2 seconds'",
+ "SELECT (INTERVAL '0 YEARS 0 MONS 0 DAYS 0 HOURS 0 MINS 2.000000000
SECS' < INTERVAL '0 YEARS 0 MONS 0 DAYS 0 HOURS 0 MINS 2.000000000 SECS')",
+ );
+}
diff --git a/datafusion/sqllogictest/test_files/timestamps.slt
b/datafusion/sqllogictest/test_files/timestamps.slt
index b63aad49d1..fb0fd8397f 100644
--- a/datafusion/sqllogictest/test_files/timestamps.slt
+++ b/datafusion/sqllogictest/test_files/timestamps.slt
@@ -3109,6 +3109,68 @@ SELECT * FROM VALUES
2024-02-01T08:00:00Z
2023-12-31T23:00:00Z
+# interval vs. duration comparison
+query B
+select (now() - now()) < interval '1 seconds';
+----
+true
+
+query B
+select (now() - now()) <= interval '1 seconds';
+----
+true
+
+query B
+select (now() - now()) = interval '0 seconds';
+----
+true
+
+query B
+select (now() - now()) != interval '1 seconds';
+----
+true
+
+query B
+select (now() - now()) > interval '-1 seconds';
+----
+true
+
+query B
+select (now() - now()) >= interval '-1 seconds';
+----
+true
+
+query B
+select arrow_cast(123, 'Duration(Nanosecond)') < interval '200 nanoseconds';
+----
+true
+
+query B
+select arrow_cast(123, 'Duration(Nanosecond)') < interval '100 nanoseconds';
+----
+false
+
+query B
+select arrow_cast(123, 'Duration(Nanosecond)') < interval '1 seconds';
+----
+true
+
+query B
+select interval '1 seconds' < arrow_cast(123, 'Duration(Nanosecond)')
+----
+false
+
+# interval as LHS
+query B
+select interval '2 seconds' = interval '2 seconds';
+----
+true
+
+query B
+select interval '1 seconds' < interval '2 seconds';
+----
+true
+
statement ok
drop table t;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]