From 63d2681850cf43f2acc3c86b14735352ffee7473 Mon Sep 17 00:00:00 2001 From: Kevin Su Date: Fri, 21 Jun 2024 01:15:42 -0700 Subject: [PATCH 1/2] wip Signed-off-by: Kevin Su --- datafusion/sql/src/unparser/expr.rs | 47 +++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/datafusion/sql/src/unparser/expr.rs b/datafusion/sql/src/unparser/expr.rs index 65481aed64f9..c8010b5ce5c5 100644 --- a/datafusion/sql/src/unparser/expr.rs +++ b/datafusion/sql/src/unparser/expr.rs @@ -19,7 +19,9 @@ use arrow::util::display::array_value_to_string; use core::fmt; use std::{fmt::Display, vec}; -use arrow_array::{Date32Array, Date64Array, TimestampNanosecondArray}; +use arrow_array::{ + Date32Array, Date64Array, TimestampMillisecondArray, TimestampNanosecondArray, +}; use arrow_schema::DataType; use sqlparser::ast::Value::SingleQuotedString; use sqlparser::ast::{ @@ -808,8 +810,36 @@ impl Unparser<'_> { ScalarValue::TimestampSecond(None, _) => { Ok(ast::Expr::Value(ast::Value::Null)) } - ScalarValue::TimestampMillisecond(Some(_ts), _) => { - not_impl_err!("Unsupported scalar: {v:?}") + ScalarValue::TimestampMillisecond(Some(_ts), tz) => { + let result = if let Some(tz) = tz { + v.to_array()? + .as_any() + .downcast_ref::() + .ok_or(internal_datafusion_err!( + "Unable to downcast to TimestampMillisecond from TimestampMillisecond scalar" + ))? + .value_as_datetime_with_tz(0, tz.parse()?) + .ok_or(internal_datafusion_err!( + "Unable to convert TimestampMillisecond to DateTime" + ))?.to_string() + } else { + v.to_array()? + .as_any() + .downcast_ref::() + .ok_or(internal_datafusion_err!( + "Unable to downcast to TimestampMillisecond from TimestampMillisecond scalar" + ))? + .value_as_datetime(0) + .ok_or(internal_datafusion_err!( + "Unable to convert TimestampMillisecond to NaiveDateTime" + ))?.to_string() + }; + Ok(ast::Expr::Cast { + kind: ast::CastKind::Cast, + expr: Box::new(ast::Expr::Value(SingleQuotedString(result))), + data_type: ast::DataType::Timestamp(None, TimezoneInfo::None), + format: None, + }) } ScalarValue::TimestampMillisecond(None, _) => { Ok(ast::Expr::Value(ast::Value::Null)) @@ -1180,6 +1210,17 @@ mod tests { Expr::Literal(ScalarValue::Date32(Some(-1))), r#"CAST('1969-12-31' AS DATE)"#, ), + ( + Expr::Literal(ScalarValue::TimestampMillisecond(Some(10001), None)), + r#"CAST('1970-01-01 00:00:10.001' AS TIMESTAMP)"#, + ), + ( + Expr::Literal(ScalarValue::TimestampMillisecond( + Some(10001), + Some("+08:00".into()), + )), + r#"CAST('1970-01-01 08:00:10.001 +08:00' AS TIMESTAMP)"#, + ), ( Expr::Literal(ScalarValue::TimestampNanosecond(Some(10001), None)), r#"CAST('1970-01-01 00:00:00.000010001' AS TIMESTAMP)"#, From aba3fa486de4bd26d8050da8cc61350d756a2e92 Mon Sep 17 00:00:00 2001 From: Kevin Su Date: Fri, 21 Jun 2024 01:28:42 -0700 Subject: [PATCH 2/2] add a test Signed-off-by: Kevin Su --- datafusion/sql/src/unparser/expr.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/datafusion/sql/src/unparser/expr.rs b/datafusion/sql/src/unparser/expr.rs index c8010b5ce5c5..25e48dcc9086 100644 --- a/datafusion/sql/src/unparser/expr.rs +++ b/datafusion/sql/src/unparser/expr.rs @@ -649,6 +649,15 @@ impl Unparser<'_> { } } + fn timestamp_string_to_sql(&self, ts: String) -> Result { + Ok(ast::Expr::Cast { + kind: ast::CastKind::Cast, + expr: Box::new(ast::Expr::Value(SingleQuotedString(ts))), + data_type: ast::DataType::Timestamp(None, TimezoneInfo::None), + format: None, + }) + } + /// DataFusion ScalarValues sometimes require a ast::Expr to construct. /// For example ScalarValue::Date32(d) corresponds to the ast::Expr CAST('datestr' as DATE) fn scalar_to_sql(&self, v: &ScalarValue) -> Result { @@ -834,12 +843,7 @@ impl Unparser<'_> { "Unable to convert TimestampMillisecond to NaiveDateTime" ))?.to_string() }; - Ok(ast::Expr::Cast { - kind: ast::CastKind::Cast, - expr: Box::new(ast::Expr::Value(SingleQuotedString(result))), - data_type: ast::DataType::Timestamp(None, TimezoneInfo::None), - format: None, - }) + self.timestamp_string_to_sql(result) } ScalarValue::TimestampMillisecond(None, _) => { Ok(ast::Expr::Value(ast::Value::Null)) @@ -874,12 +878,7 @@ impl Unparser<'_> { "Unable to convert TimestampNanosecond to NaiveDateTime" ))?.to_string() }; - Ok(ast::Expr::Cast { - kind: ast::CastKind::Cast, - expr: Box::new(ast::Expr::Value(SingleQuotedString(result))), - data_type: ast::DataType::Timestamp(None, TimezoneInfo::None), - format: None, - }) + self.timestamp_string_to_sql(result) } ScalarValue::TimestampNanosecond(None, _) => { Ok(ast::Expr::Value(ast::Value::Null))