You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2023/06/19 14:27:54 UTC
[arrow-datafusion] branch main updated: fix: parser for negative intervals (#6698)
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/arrow-datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new d29ab93150 fix: parser for negative intervals (#6698)
d29ab93150 is described below
commit d29ab931506f23d8ef8fcd48ae523adfd3c07d6a
Author: Igor Izvekov <iz...@gmail.com>
AuthorDate: Mon Jun 19 17:27:49 2023 +0300
fix: parser for negative intervals (#6698)
* fix: parser for negative intervals
* fix: use format
* fix: merge main
---
.../tests/sqllogictests/test_files/interval.slt | 8 ++++----
datafusion/sql/src/expr/mod.rs | 1 +
datafusion/sql/src/expr/unary_op.rs | 6 ++++++
datafusion/sql/src/expr/value.rs | 12 ++++++++++-
datafusion/sql/tests/sql_integration.rs | 24 ++++++++++++++++++++++
5 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/datafusion/core/tests/sqllogictests/test_files/interval.slt b/datafusion/core/tests/sqllogictests/test_files/interval.slt
index 911b28c84b..74ddfbf78d 100644
--- a/datafusion/core/tests/sqllogictests/test_files/interval.slt
+++ b/datafusion/core/tests/sqllogictests/test_files/interval.slt
@@ -190,25 +190,25 @@ select interval '1 year' - '1 month' - '1 day' - '1 hour' - '1 minute' - '1 seco
query ?
select -interval '5' - '1' - '2' year;
----
-0 years -24 mons 0 days 0 hours 0 mins 0.000000000 secs
+0 years -96 mons 0 days 0 hours 0 mins 0.000000000 secs
# Interval with nested string literal negation
query ?
select -interval '1 month' + '1 day' + '1 hour';
----
-0 years -1 mons -1 days -1 hours 0 mins 0.000000000 secs
+0 years -1 mons 1 days 1 hours 0 mins 0.000000000 secs
# Interval with nested string literal negation and leading field
query ?
select -interval '10' - '1' - '1' month;
----
-0 years -8 mons 0 days 0 hours 0 mins 0.000000000 secs
+0 years -12 mons 0 days 0 hours 0 mins 0.000000000 secs
# Interval mega nested string literal negation
query ?
select -interval '1 year' - '1 month' - '1 day' - '1 hour' - '1 minute' - '1 second' - '1 millisecond' - '1 microsecond' - '1 nanosecond'
----
-0 years -11 mons 1 days 1 hours 1 mins 1.001001001 secs
+0 years -13 mons -1 days -1 hours -1 mins -1.001001001 secs
# Interval string literal + date
query D
diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs
index 4155484cea..5b490f3b06 100644
--- a/datafusion/sql/src/expr/mod.rs
+++ b/datafusion/sql/src/expr/mod.rs
@@ -162,6 +162,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
SQLExpr::Array(arr) => self.sql_array_literal(arr.elem, schema),
SQLExpr::Interval(interval)=> self.sql_interval_to_expr(
+ false,
interval,
schema,
planner_context,
diff --git a/datafusion/sql/src/expr/unary_op.rs b/datafusion/sql/src/expr/unary_op.rs
index dc7b5abd45..8b9312e84a 100644
--- a/datafusion/sql/src/expr/unary_op.rs
+++ b/datafusion/sql/src/expr/unary_op.rs
@@ -48,6 +48,12 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
"negative operator can be only applied to integer and float operands, got: {n}"))
})?)),
},
+ SQLExpr::Interval(interval) => self.sql_interval_to_expr(
+ true,
+ interval,
+ schema,
+ planner_context,
+ ),
// not a literal, apply negative operator on expression
_ => Ok(Expr::Negative(Box::new(self.sql_expr_to_logical_expr(expr, schema, planner_context)?))),
}
diff --git a/datafusion/sql/src/expr/value.rs b/datafusion/sql/src/expr/value.rs
index 1477bad0df..5a64d36330 100644
--- a/datafusion/sql/src/expr/value.rs
+++ b/datafusion/sql/src/expr/value.rs
@@ -165,6 +165,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
/// expression
pub(super) fn sql_interval_to_expr(
&self,
+ negative: bool,
interval: Interval,
schema: &DFSchema,
planner_context: &mut PlannerContext,
@@ -194,7 +195,13 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
let value = match *interval.value {
SQLExpr::Value(
Value::SingleQuotedString(s) | Value::DoubleQuotedString(s),
- ) => s,
+ ) => {
+ if negative {
+ format!("-{s}")
+ } else {
+ s
+ }
+ }
// Support expressions like `interval '1 month' + date/timestamp`.
// Such expressions are parsed like this by sqlparser-rs
//
@@ -224,6 +231,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
match (interval.leading_field, left.as_ref(), right.as_ref()) {
(_, _, SQLExpr::Value(_)) => {
let left_expr = self.sql_interval_to_expr(
+ negative,
Interval {
value: left,
leading_field: interval.leading_field,
@@ -235,6 +243,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
planner_context,
)?;
let right_expr = self.sql_interval_to_expr(
+ false,
Interval {
value: right,
leading_field: interval.leading_field,
@@ -258,6 +267,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
// is not a value.
(None, _, _) => {
let left_expr = self.sql_interval_to_expr(
+ negative,
Interval {
value: left,
leading_field: None,
diff --git a/datafusion/sql/tests/sql_integration.rs b/datafusion/sql/tests/sql_integration.rs
index 77706ea399..86cc736719 100644
--- a/datafusion/sql/tests/sql_integration.rs
+++ b/datafusion/sql/tests/sql_integration.rs
@@ -2740,6 +2740,30 @@ fn cte_use_same_name_multiple_times() {
assert_eq!(result.to_string(), expected);
}
+#[test]
+fn negative_interval_plus_interval_in_projection() {
+ let sql = "select -interval '2 days' + interval '5 days';";
+ let expected =
+ "Projection: IntervalMonthDayNano(\"79228162477370849446124847104\") + IntervalMonthDayNano(\"92233720368547758080\")\n EmptyRelation";
+ quick_test(sql, expected);
+}
+
+#[test]
+fn complex_interval_expression_in_projection() {
+ let sql = "select -interval '2 days' + interval '5 days'+ (-interval '3 days' + interval '5 days');";
+ let expected =
+ "Projection: IntervalMonthDayNano(\"79228162477370849446124847104\") + IntervalMonthDayNano(\"92233720368547758080\") + IntervalMonthDayNano(\"79228162458924105372415295488\") + IntervalMonthDayNano(\"92233720368547758080\")\n EmptyRelation";
+ quick_test(sql, expected);
+}
+
+#[test]
+fn negative_sum_intervals_in_projection() {
+ let sql = "select -((interval '2 days' + interval '5 days') + -(interval '4 days' + interval '7 days'));";
+ let expected =
+ "Projection: (- IntervalMonthDayNano(\"36893488147419103232\") + IntervalMonthDayNano(\"92233720368547758080\") + (- IntervalMonthDayNano(\"73786976294838206464\") + IntervalMonthDayNano(\"129127208515966861312\")))\n EmptyRelation";
+ quick_test(sql, expected);
+}
+
#[test]
fn date_plus_interval_in_projection() {
let sql = "select t_date32 + interval '5 days' FROM test";