@@ -20,8 +20,9 @@ use std::{fmt::Display, vec};
2020
2121use arrow_array:: { Date32Array , Date64Array } ;
2222use arrow_schema:: DataType ;
23+ use sqlparser:: ast:: Value :: SingleQuotedString ;
2324use sqlparser:: ast:: {
24- self , Expr as AstExpr , Function , FunctionArg , Ident , UnaryOperator ,
25+ self , Expr as AstExpr , Function , FunctionArg , Ident , Interval , UnaryOperator ,
2526} ;
2627
2728use 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) ]
9561004mod 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