Skip to content

Commit 9ae676c

Browse files
committed
support to unparse ScalarValue::IntervalMonthDayNano to String
1 parent 2daadb7 commit 9ae676c

File tree

2 files changed

+127
-6
lines changed

2 files changed

+127
-6
lines changed

datafusion/expr/src/expr_fn.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ use crate::{
3131
Signature, Volatility,
3232
};
3333
use crate::{AggregateUDFImpl, ColumnarValue, ScalarUDFImpl, WindowUDF, WindowUDFImpl};
34+
use arrow::compute::kernels::cast_utils::parse_interval_month_day_nano;
3435
use arrow::datatypes::{DataType, Field};
35-
use datafusion_common::{Column, Result};
36+
use datafusion_common::{Column, Result, ScalarValue};
3637
use std::any::Any;
3738
use std::fmt::Debug;
3839
use std::ops::Not;
@@ -670,6 +671,11 @@ impl WindowUDFImpl for SimpleWindowUDF {
670671
}
671672
}
672673

674+
pub fn interval_month_day_nano_lit(value: &str) -> Expr {
675+
let interval = parse_interval_month_day_nano(value).ok();
676+
Expr::Literal(ScalarValue::IntervalMonthDayNano(interval))
677+
}
678+
673679
#[cfg(test)]
674680
mod test {
675681
use super::*;

datafusion/sql/src/unparser/expr.rs

Lines changed: 120 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ use std::{fmt::Display, vec};
2020

2121
use arrow_array::{Date32Array, Date64Array};
2222
use arrow_schema::DataType;
23+
use sqlparser::ast::Value::SingleQuotedString;
2324
use sqlparser::ast::{
24-
self, Expr as AstExpr, Function, FunctionArg, Ident, UnaryOperator,
25+
self, Expr as AstExpr, Function, FunctionArg, Ident, Interval, UnaryOperator,
2526
};
2627

2728
use datafusion_common::{
@@ -825,8 +826,26 @@ impl Unparser<'_> {
825826
not_impl_err!("Unsupported scalar: {v:?}")
826827
}
827828
ScalarValue::IntervalDayTime(None) => Ok(ast::Expr::Value(ast::Value::Null)),
828-
ScalarValue::IntervalMonthDayNano(Some(_i)) => {
829-
not_impl_err!("Unsupported scalar: {v:?}")
829+
ScalarValue::IntervalMonthDayNano(Some(i)) => {
830+
let mut s = vec![];
831+
if i.months != 0 {
832+
s.push(format!("{} MONTH", i.months));
833+
}
834+
if i.days != 0 {
835+
s.push(format!("{} DAY", i.days));
836+
}
837+
if i.nanoseconds != 0 {
838+
s.push(Self::process_interval_nanosecond(i.nanoseconds));
839+
}
840+
841+
let interval = Interval {
842+
value: Box::new(ast::Expr::Value(SingleQuotedString(s.join(" ")))),
843+
leading_field: None,
844+
leading_precision: None,
845+
last_field: None,
846+
fractional_seconds_precision: None,
847+
};
848+
Ok(ast::Expr::Interval(interval))
830849
}
831850
ScalarValue::IntervalMonthDayNano(None) => {
832851
Ok(ast::Expr::Value(ast::Value::Null))
@@ -859,6 +878,35 @@ impl Unparser<'_> {
859878
}
860879
}
861880

881+
fn process_interval_nanosecond(nano: i64) -> String {
882+
let mut s = vec![];
883+
let hour = nano / 3_600_000_000_000;
884+
let minute = nano / 60_000_000_000 % 60;
885+
let second = nano / 1_000_000_000 % 60;
886+
let millisecond = nano / 1_000_000 % 1_000;
887+
let microsecond = nano / 1_000 % 1_000;
888+
let nanosecond = nano % 1_000;
889+
if hour != 0 {
890+
s.push(format!("{} HOUR", hour));
891+
}
892+
if minute != 0 {
893+
s.push(format!("{} MINUTE", minute));
894+
}
895+
if second != 0 {
896+
s.push(format!("{} SECOND", second));
897+
}
898+
if millisecond != 0 {
899+
s.push(format!("{} MILLISECOND", millisecond));
900+
}
901+
if microsecond != 0 {
902+
s.push(format!("{} MICROSECOND", microsecond));
903+
}
904+
if nanosecond != 0 {
905+
s.push(format!("{} NANOSECOND", nanosecond));
906+
}
907+
s.join(" ")
908+
}
909+
862910
fn arrow_dtype_to_ast_dtype(&self, data_type: &DataType) -> Result<ast::DataType> {
863911
match data_type {
864912
DataType::Null => {
@@ -954,19 +1002,19 @@ impl Unparser<'_> {
9541002

9551003
#[cfg(test)]
9561004
mod tests {
1005+
use std::ops::{Add, Sub};
9571006
use std::{any::Any, sync::Arc, vec};
9581007

9591008
use arrow::datatypes::{Field, Schema};
9601009
use arrow_schema::DataType::Int8;
961-
9621010
use datafusion_common::TableReference;
963-
use datafusion_expr::AggregateExt;
9641011
use datafusion_expr::{
9651012
case, col, cube, exists, grouping_set, lit, not, not_exists, out_ref_col,
9661013
placeholder, rollup, table_scan, try_cast, when, wildcard, ColumnarValue,
9671014
ScalarUDF, ScalarUDFImpl, Signature, Volatility, WindowFrame,
9681015
WindowFunctionDefinition,
9691016
};
1017+
use datafusion_expr::{interval_month_day_nano_lit, AggregateExt};
9701018
use datafusion_functions_aggregate::count::count_udaf;
9711019
use datafusion_functions_aggregate::expr_fn::sum;
9721020

@@ -1256,6 +1304,73 @@ mod tests {
12561304
),
12571305
(col("need-quoted").eq(lit(1)), r#"("need-quoted" = 1)"#),
12581306
(col("need quoted").eq(lit(1)), r#"("need quoted" = 1)"#),
1307+
(
1308+
interval_month_day_nano_lit("3 NANOSECOND"),
1309+
r#"INTERVAL '3 NANOSECOND'"#,
1310+
),
1311+
(
1312+
interval_month_day_nano_lit("1000 NANOSECOND"),
1313+
r#"INTERVAL '1 MICROSECOND'"#,
1314+
),
1315+
(
1316+
interval_month_day_nano_lit("1000000 NANOSECOND"),
1317+
r#"INTERVAL '1 MILLISECOND'"#,
1318+
),
1319+
(
1320+
interval_month_day_nano_lit("1000000000 NANOSECOND"),
1321+
r#"INTERVAL '1 SECOND'"#,
1322+
),
1323+
(
1324+
interval_month_day_nano_lit("1001001001 NANOSECOND"),
1325+
r#"INTERVAL '1 SECOND 1 MILLISECOND 1 MICROSECOND 1 NANOSECOND'"#,
1326+
),
1327+
(
1328+
interval_month_day_nano_lit("3 SECOND"),
1329+
r#"INTERVAL '3 SECOND'"#,
1330+
),
1331+
(
1332+
interval_month_day_nano_lit("3 MINUTE"),
1333+
r#"INTERVAL '3 MINUTE'"#,
1334+
),
1335+
(
1336+
interval_month_day_nano_lit("3 HOUR"),
1337+
r#"INTERVAL '3 HOUR'"#,
1338+
),
1339+
(
1340+
interval_month_day_nano_lit("3 HOUR 10 MINUTE 20 SECOND"),
1341+
r#"INTERVAL '3 HOUR 10 MINUTE 20 SECOND'"#,
1342+
),
1343+
(interval_month_day_nano_lit("3 DAY"), r#"INTERVAL '3 DAY'"#),
1344+
(
1345+
interval_month_day_nano_lit("3 MONTH"),
1346+
r#"INTERVAL '3 MONTH'"#,
1347+
),
1348+
(
1349+
interval_month_day_nano_lit("1 MONTH 1 DAY 10 SECOND"),
1350+
r#"INTERVAL '1 MONTH 1 DAY 10 SECOND'"#,
1351+
),
1352+
(
1353+
interval_month_day_nano_lit("15 MONTH"),
1354+
r#"INTERVAL '15 MONTH'"#,
1355+
),
1356+
(
1357+
interval_month_day_nano_lit("1.5 MONTH"),
1358+
r#"INTERVAL '1 MONTH 15 DAY'"#,
1359+
),
1360+
(
1361+
interval_month_day_nano_lit("-3 MONTH"),
1362+
r#"INTERVAL '-3 MONTH'"#,
1363+
),
1364+
(
1365+
interval_month_day_nano_lit("1 MONTH")
1366+
.add(interval_month_day_nano_lit("1 DAY")),
1367+
r#"(INTERVAL '1 MONTH' + INTERVAL '1 DAY')"#,
1368+
),
1369+
(
1370+
interval_month_day_nano_lit("1 MONTH")
1371+
.sub(interval_month_day_nano_lit("1 DAY")),
1372+
r#"(INTERVAL '1 MONTH' - INTERVAL '1 DAY')"#,
1373+
),
12591374
];
12601375

12611376
for (expr, expected) in tests {

0 commit comments

Comments
 (0)