@@ -319,20 +319,97 @@ fn date_bin_single(stride: i64, source: i64, origin: i64) -> i64 {
319319
320320/// DATE_BIN sql function
321321pub fn date_bin ( args : & [ ColumnarValue ] ) -> Result < ColumnarValue > {
322- if args. len ( ) != 2 && args. len ( ) != 3 {
323- return Err ( DataFusionError :: Execution (
322+ if args. len ( ) == 2 {
323+ date_bin_2args ( args)
324+ } else if args. len ( ) == 3 {
325+ date_bin_3args ( args)
326+ } else {
327+ Err ( DataFusionError :: Execution (
324328 "DATE_BIN expected two or three arguments" . to_string ( ) ,
325- ) ) ;
329+ ) )
326330 }
331+ }
327332
328- let ( stride, array) = ( & args[ 0 ] , & args[ 1 ] ) ;
333+ fn date_bin_3args ( args : & [ ColumnarValue ] ) -> Result < ColumnarValue > {
334+ let ( stride, array, origin) = ( & args[ 0 ] , & args[ 1 ] , & args[ 2 ] ) ;
329335
330- // If the origin is not provided, use the Unix epoch
331- let origin = ColumnarValue :: Scalar ( ScalarValue :: TimestampNanosecond (
336+ let stride = match stride {
337+ ColumnarValue :: Scalar ( ScalarValue :: IntervalDayTime ( Some ( v) ) ) => {
338+ let ( days, ms) = IntervalDayTimeType :: to_parts ( * v) ;
339+ let nanos = ( Duration :: days ( days as i64 ) + Duration :: milliseconds ( ms as i64 ) )
340+ . num_nanoseconds ( ) ;
341+ match nanos {
342+ Some ( v) => v,
343+ _ => {
344+ return Err ( DataFusionError :: Execution (
345+ "DATE_BIN stride argument is too large" . to_string ( ) ,
346+ ) )
347+ }
348+ }
349+ }
350+ ColumnarValue :: Scalar ( v) => {
351+ return Err ( DataFusionError :: Execution ( format ! (
352+ "DATE_BIN expects stride argument to be an INTERVAL but got {}" ,
353+ v. get_datatype( )
354+ ) ) )
355+ }
356+ ColumnarValue :: Array ( _) => return Err ( DataFusionError :: NotImplemented (
357+ "DATE_BIN only supports literal values for the stride argument, not arrays"
358+ . to_string ( ) ,
359+ ) ) ,
360+ } ;
361+
362+ let origin = match origin {
363+ ColumnarValue :: Scalar ( ScalarValue :: TimestampNanosecond ( Some ( v) , _) ) => * v,
364+ ColumnarValue :: Scalar ( v) => {
365+ return Err ( DataFusionError :: Execution ( format ! (
366+ "DATE_BIN expects origin argument to be a TIMESTAMP but got {}" ,
367+ v. get_datatype( )
368+ ) ) )
369+ }
370+ ColumnarValue :: Array ( _) => return Err ( DataFusionError :: NotImplemented (
371+ "DATE_BIN only supports literal values for the origin argument, not arrays"
372+ . to_string ( ) ,
373+ ) ) ,
374+ } ;
375+
376+ let f = |x : Option < i64 > | x. map ( |x| date_bin_single ( stride, x, origin) ) ;
377+
378+ Ok ( match array {
379+ ColumnarValue :: Scalar ( ScalarValue :: TimestampNanosecond ( v, tz_opt) ) => {
380+ ColumnarValue :: Scalar ( ScalarValue :: TimestampNanosecond ( f ( * v) , tz_opt. clone ( ) ) )
381+ }
382+ ColumnarValue :: Array ( array) => match array. data_type ( ) {
383+ DataType :: Timestamp ( TimeUnit :: Nanosecond , _) => {
384+ let array = as_timestamp_nanosecond_array ( array) ?
385+ . iter ( )
386+ . map ( f)
387+ . collect :: < TimestampNanosecondArray > ( ) ;
388+
389+ ColumnarValue :: Array ( Arc :: new ( array) )
390+ }
391+ _ => {
392+ return Err ( DataFusionError :: Execution ( format ! (
393+ "DATE_BIN expects source argument to be a TIMESTAMP but got {}" ,
394+ array. data_type( )
395+ ) ) )
396+ }
397+ } ,
398+ _ => {
399+ return Err ( DataFusionError :: Execution (
400+ "DATE_BIN expects source argument to be a TIMESTAMP scalar or array"
401+ . to_string ( ) ,
402+ ) ) ;
403+ }
404+ } )
405+ }
406+
407+ fn date_bin_2args ( args : & [ ColumnarValue ] ) -> Result < ColumnarValue > {
408+ let origin = & ColumnarValue :: Scalar ( ScalarValue :: TimestampNanosecond (
332409 Some ( 0 ) ,
333410 Some ( "+00:00" . to_owned ( ) ) ,
334411 ) ) ;
335- let origin = if args . len ( ) == 3 { & args[ 2 ] } else { & origin } ;
412+ let ( stride , array ) = ( & args[ 0 ] , & args [ 1 ] ) ;
336413
337414 let stride = match stride {
338415 ColumnarValue :: Scalar ( ScalarValue :: IntervalDayTime ( Some ( v) ) ) => {
0 commit comments