Skip to content

Commit

Permalink
timestamp fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
comphead committed Nov 15, 2023
1 parent abb2ae7 commit 619de48
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 24 deletions.
3 changes: 3 additions & 0 deletions datafusion/common/src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,9 @@ impl ScalarValue {
ScalarValue::Decimal256(Some(v), precision, scale) => Ok(
ScalarValue::Decimal256(Some(v.neg_wrapping()), *precision, *scale),
),
ScalarValue::TimestampSecond(Some(v), tz) => {
Ok(ScalarValue::TimestampSecond(Some(-v), tz.clone()))
}
value => _internal_err!(
"Can not run arithmetic negative on scalar value {value:?}"
),
Expand Down
7 changes: 5 additions & 2 deletions datafusion/physical-expr/src/expressions/negative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use arrow::{
};
use datafusion_common::{internal_err, DataFusionError, Result};
use datafusion_expr::{
type_coercion::{is_interval, is_null, is_signed_numeric},
type_coercion::{is_interval, is_null, is_signed_numeric, is_timestamp},
ColumnarValue,
};

Expand Down Expand Up @@ -155,7 +155,10 @@ pub fn negative(
let data_type = arg.data_type(input_schema)?;
if is_null(&data_type) {
Ok(arg)
} else if !is_signed_numeric(&data_type) && !is_interval(&data_type) {
} else if !is_signed_numeric(&data_type)
&& !is_interval(&data_type)
&& !is_timestamp(&data_type)
{
internal_err!(
"Can't create negative physical expr for (- '{arg:?}'), the type of child expr is {data_type}, not signed numeric"
)
Expand Down
42 changes: 29 additions & 13 deletions datafusion/sql/src/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod value;

use crate::planner::{ContextProvider, PlannerContext, SqlToRel};
use arrow_schema::DataType;
use arrow_schema::TimeUnit;
use datafusion_common::{
internal_err, not_impl_err, plan_err, Column, DFSchema, DataFusionError, Result,
ScalarValue,
Expand All @@ -39,7 +40,10 @@ use datafusion_expr::{
col, expr, lit, AggregateFunction, Between, BinaryExpr, BuiltinScalarFunction, Cast,
Expr, ExprSchemable, GetFieldAccess, GetIndexedField, Like, Operator, TryCast,
};
use sqlparser::ast::{ArrayAgg, Expr as SQLExpr, JsonOperator, TrimWhereField, Value};
use sqlparser::ast::{
ArrayAgg, Expr as SQLExpr, JsonOperator, TrimWhereField,
Value,
};
use sqlparser::parser::ParserError::ParserError;

impl<'a, S: ContextProvider> SqlToRel<'a, S> {
Expand Down Expand Up @@ -224,14 +228,23 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {

SQLExpr::Cast {
expr, data_type, ..
} => Ok(Expr::Cast(Cast::new(
Box::new(self.sql_expr_to_logical_expr(
*expr,
schema,
planner_context,
)?),
self.convert_data_type(&data_type)?,
))),
} => {
let mut dt = self.convert_data_type(&data_type)?;
let expr =
self.sql_expr_to_logical_expr(*expr, schema, planner_context)?;

// int/floats should come as seconds rather as nanoseconds
dt = match &dt {
DataType::Timestamp(TimeUnit::Nanosecond, tz)
if expr.get_type(schema)? == DataType::Int64 =>
{
DataType::Timestamp(TimeUnit::Second, tz.clone())
}
_ => dt,
};

Ok(Expr::Cast(Cast::new(Box::new(expr), dt)))
}

SQLExpr::TryCast {
expr, data_type, ..
Expand All @@ -244,10 +257,13 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
self.convert_data_type(&data_type)?,
))),

SQLExpr::TypedString { data_type, value } => Ok(Expr::Cast(Cast::new(
Box::new(lit(value)),
self.convert_data_type(&data_type)?,
))),
SQLExpr::TypedString { data_type, value } => {
dbg!("TypedString");
Ok(Expr::Cast(Cast::new(
Box::new(lit(value)),
self.convert_data_type(&data_type)?,
)))
}

SQLExpr::IsNull(expr) => Ok(Expr::IsNull(Box::new(
self.sql_expr_to_logical_expr(*expr, schema, planner_context)?,
Expand Down
2 changes: 1 addition & 1 deletion datafusion/sql/tests/sql_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ fn test_timestamp_filter() {
let sql = "SELECT state FROM person WHERE birth_date < CAST (158412331400600000 as timestamp)";

let expected = "Projection: person.state\
\n Filter: person.birth_date < CAST(Int64(158412331400600000) AS Timestamp(Nanosecond, None))\
\n Filter: person.birth_date < CAST(Int64(158412331400600000) AS Timestamp(Second, None))\
\n TableScan: person";

quick_test(sql, expected);
Expand Down
18 changes: 18 additions & 0 deletions datafusion/sqllogictest/test_files/timestamps.slt
Original file line number Diff line number Diff line change
Expand Up @@ -1793,3 +1793,21 @@ query PPPPP
SELECT to_timestamp(null), to_timestamp(-62125747200), to_timestamp(0), to_timestamp(1926632005177), to_timestamp(1926632005)
----
NULL 0001-04-25T00:00:00 1970-01-01T00:00:00 +63022-07-16T12:59:37 2031-01-19T23:33:25

# verify to_timestamp edge cases to be in sync with postgresql
query PPPPPPPP
SELECT to_timestamp(null), to_timestamp(-62125747200), to_timestamp(0), to_timestamp(1926632005177), to_timestamp(1926632005), to_timestamp(1), to_timestamp(-1), to_timestamp(0-1)
----
NULL 0001-04-25T00:00:00 1970-01-01T00:00:00 +63022-07-16T12:59:37 2031-01-19T23:33:25 1970-01-01T00:00:01 1969-12-31T23:59:59 1969-12-31T23:59:59

# verify timestamp cast from i64 is in sync with to_timestamp(i64)
query PPPPPPPP
SELECT null::timestamp, -62125747200::timestamp, 0::timestamp, 1926632005177::timestamp, 1926632005::timestamp, 1::timestamp, -1::timestamp, (0-1)::timestamp
----
NULL 0001-04-25T00:00:00 1970-01-01T00:00:00 +63022-07-16T12:59:37 2031-01-19T23:33:25 1970-01-01T00:00:01 1969-12-31T23:59:59 1969-12-31T23:59:59

# verify timestamp cast from i64 is in sync with to_timestamp(i64) using CAST syntax
query PPPPPPP
SELECT cast(null as timestamp), cast(-62125747200 as timestamp), cast(0 as timestamp), cast(1926632005177 as timestamp), cast(1926632005 as timestamp), cast(1 as timestamp), cast(-1 as timestamp), cast(0-1 as timestamp)
----
NULL 0001-04-25T00:00:00 1970-01-01T00:00:00 +63022-07-16T12:59:37 2031-01-19T23:33:25 1970-01-01T00:00:01 1969-12-31T23:59:59 1969-12-31T23:59:59
16 changes: 8 additions & 8 deletions datafusion/sqllogictest/test_files/window.slt
Original file line number Diff line number Diff line change
Expand Up @@ -895,14 +895,14 @@ SELECT

statement ok
create table temp as values
(1664264591000000000),
(1664264592000000000),
(1664264592000000000),
(1664264593000000000),
(1664264594000000000),
(1664364594000000000),
(1664464594000000000),
(1664564594000000000);
(1664264591),
(1664264592),
(1664264592),
(1664264593),
(1664264594),
(1664364594),
(1664464594),
(1664564594);

statement ok
create table t as select cast(column1 as timestamp) as ts from temp;
Expand Down

0 comments on commit 619de48

Please sign in to comment.