Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions datafusion/core/tests/sqllogictests/test_files/interval.slt
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,17 @@ select interval '5' nanoseconds
----
0 years 0 mons 0 days 0 hours 0 mins 0.000000005 secs

# Interval with string literal addition
Comment thread
aprimadi marked this conversation as resolved.
query ?
select interval '1 month' + '1 month'
----
0 years 2 mons 0 days 0 hours 0 mins 0.000000000 secs

# Interval with string literal addition and leading field
query ?
select interval '1' + '1' month
----
0 years 2 mons 0 days 0 hours 0 mins 0.000000000 secs



Expand Down Expand Up @@ -378,5 +389,11 @@ select '1 month'::interval - d from t;
query error DataFusion error: type_coercion\ncaused by\nError during planning: Interval\(MonthDayNano\) \- Timestamp\(Nanosecond, None\) can't be evaluated because there isn't a common type to coerce the types to
select '1 month'::interval - ts from t;

# interval + date
query D
select interval '1 month' + '2012-01-01'::date;
----
2012-02-01

statement ok
drop table t
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ SELECT '2023-05-01 12:30:00'::timestamp - interval '1 month';

# TODO: https://github.com/apache/arrow-datafusion/issues/6180
Comment thread
aprimadi marked this conversation as resolved.
Outdated
# interval - date
query error DataFusion error: This feature is not implemented: Unsupported interval argument\. Expected string literal, got: BinaryOp \{ left: Value\(SingleQuotedString\("1 month"\)\), op: Minus, right: Cast \{ expr: Value\(SingleQuotedString\("2023\-05\-01"\)\), data_type: Date \} \}
query error DataFusion error: type_coercion
select interval '1 month' - '2023-05-01'::date;

# TODO: https://github.com/apache/arrow-datafusion/issues/6180
# interval - timestamp
query error DataFusion error: This feature is not implemented: Unsupported interval argument\. Expected string literal, got: BinaryOp \{ left: Value\(SingleQuotedString\("1 month"\)\), op: Minus, right: Cast \{ expr: Value\(SingleQuotedString\("2023\-05\-01 12:30:00"\)\), data_type: Timestamp\(None, None\) \} \}
query error DataFusion error: type_coercion
SELECT interval '1 month' - '2023-05-01 12:30:00'::timestamp;
2 changes: 2 additions & 0 deletions datafusion/sql/src/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
fractional_seconds_precision,
} => self.sql_interval_to_expr(
*value,
schema,
planner_context,
leading_field,
leading_precision,
last_field,
Expand Down
83 changes: 81 additions & 2 deletions datafusion/sql/src/expr/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ use crate::planner::{ContextProvider, PlannerContext, SqlToRel};
use arrow::compute::kernels::cast_utils::parse_interval_month_day_nano;
use arrow_schema::DataType;
use datafusion_common::{DFSchema, DataFusionError, Result, ScalarValue};
use datafusion_expr::{lit, Expr};
use datafusion_expr::expr::BinaryExpr;
use datafusion_expr::{lit, Expr, Operator};
use log::debug;
use sqlparser::ast::{DateTimeField, Expr as SQLExpr, Value};
use sqlparser::ast::{BinaryOperator, DateTimeField, Expr as SQLExpr, Value};
use sqlparser::parser::ParserError::ParserError;
use std::collections::HashSet;

Expand Down Expand Up @@ -160,9 +161,17 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
}
}

/// Convert a SQL interval expression to a DataFusion logical plan
/// expression
///
/// Waiting for this issue to be resolved:
/// https://github.com/sqlparser-rs/sqlparser-rs/issues/869
#[allow(clippy::too_many_arguments)]
Comment thread
aprimadi marked this conversation as resolved.
pub(super) fn sql_interval_to_expr(
&self,
value: SQLExpr,
schema: &DFSchema,
planner_context: &mut PlannerContext,
leading_field: Option<DateTimeField>,
leading_precision: Option<u64>,
last_field: Option<DateTimeField>,
Expand Down Expand Up @@ -191,6 +200,76 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
SQLExpr::Value(
Value::SingleQuotedString(s) | Value::DoubleQuotedString(s),
) => s,
SQLExpr::BinaryOp { left, op, right } => {
Comment thread
aprimadi marked this conversation as resolved.
let df_op = match op {
BinaryOperator::Plus => Operator::Plus,
BinaryOperator::Minus => Operator::Minus,
_ => {
return Err(DataFusionError::NotImplemented(format!(
"Unsupported interval operator: {op:?}"
)));
}
};
match (leading_field, left.as_ref(), right.as_ref()) {
(_, SQLExpr::Value(_), SQLExpr::Value(_)) => {
let left_expr = self.sql_interval_to_expr(
*left,
schema,
planner_context,
leading_field,
None,
None,
None,
)?;
let right_expr = self.sql_interval_to_expr(
*right,
schema,
planner_context,
leading_field,
None,
None,
None,
)?;
return Ok(Expr::BinaryExpr(BinaryExpr::new(
Box::new(left_expr),
df_op,
Box::new(right_expr),
)));
}
// In this case, the left node is part of the interval
// expr and the right node is an independent expr.
//
// Leading field is not supported when either the left or
// right is not a value.
(None, _, _) => {
let left_expr = self.sql_interval_to_expr(
*left,
schema,
planner_context,
None,
None,
None,
None,
)?;
let right_expr = self.sql_expr_to_logical_expr(
*right,
schema,
planner_context,
)?;
return Ok(Expr::BinaryExpr(BinaryExpr::new(
Box::new(left_expr),
df_op,
Box::new(right_expr),
)));
}
_ => {
let value = SQLExpr::BinaryOp { left, op, right };
return Err(DataFusionError::NotImplemented(format!(
"Unsupported interval argument. Expected string literal, got: {value:?}"
)));
}
}
}
_ => {
return Err(DataFusionError::NotImplemented(format!(
"Unsupported interval argument. Expected string literal, got: {value:?}"
Expand Down