@@ -92,6 +92,7 @@ use arrow::util::display::{ArrayFormatter, FormatOptions, array_value_to_string}
9292use cache:: { get_or_create_cached_key_array, get_or_create_cached_null_array} ;
9393use chrono:: { Duration , NaiveDate } ;
9494use half:: f16;
95+ use num_traits:: ToPrimitive ;
9596pub use struct_builder:: ScalarStructBuilder ;
9697
9798const SECONDS_PER_DAY : i64 = 86_400 ;
@@ -2585,63 +2586,107 @@ impl ScalarValue {
25852586 /// distance is greater than [`usize::MAX`]. If the type is a float, then the distance will be
25862587 /// rounded to the nearest integer.
25872588 ///
2588- ///
25892589 /// Note: the datatype itself must support subtraction.
25902590 pub fn distance ( & self , other : & ScalarValue ) -> Option < usize > {
2591+ self . distance_u64 ( other)
2592+ . and_then ( |d| usize:: try_from ( d) . ok ( ) )
2593+ }
2594+
2595+ /// Helper to convert a rounded float distance to u64, returning None if it exceeds u64::MAX, is negative, or is not finite.
2596+ fn rounded_float_distance_u64 ( diff : f64 ) -> Option < u64 > {
2597+ if diff. is_finite ( ) && diff >= 0.0 && diff < u64:: MAX as f64 {
2598+ Some ( diff as u64 )
2599+ } else {
2600+ None
2601+ }
2602+ }
2603+
2604+ /// Absolute distance between two numeric values (of the same type). This method will return
2605+ /// None if either one of the arguments are null. It might also return None if the resulting
2606+ /// distance is greater than [`u64::MAX`]. If the type is a float, then the distance will be
2607+ /// rounded to the nearest integer.
2608+ ///
2609+ /// Note: the datatype itself must support subtraction.
2610+ pub fn distance_u64 ( & self , other : & ScalarValue ) -> Option < u64 > {
25912611 match ( self , other) {
2592- ( Self :: Int8 ( Some ( l) ) , Self :: Int8 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2593- ( Self :: Int16 ( Some ( l) ) , Self :: Int16 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2594- ( Self :: Int32 ( Some ( l) ) , Self :: Int32 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2595- ( Self :: Int64 ( Some ( l) ) , Self :: Int64 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2596- ( Self :: UInt8 ( Some ( l) ) , Self :: UInt8 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2597- ( Self :: UInt16 ( Some ( l) ) , Self :: UInt16 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2598- ( Self :: UInt32 ( Some ( l) ) , Self :: UInt32 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2599- ( Self :: UInt64 ( Some ( l) ) , Self :: UInt64 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2612+ ( Self :: Int8 ( Some ( l) ) , Self :: Int8 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2613+ ( Self :: Int16 ( Some ( l) ) , Self :: Int16 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2614+ ( Self :: Int32 ( Some ( l) ) , Self :: Int32 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2615+ ( Self :: Int64 ( Some ( l) ) , Self :: Int64 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) ) ,
2616+ ( Self :: UInt8 ( Some ( l) ) , Self :: UInt8 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2617+ ( Self :: UInt16 ( Some ( l) ) , Self :: UInt16 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2618+ ( Self :: UInt32 ( Some ( l) ) , Self :: UInt32 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2619+ ( Self :: UInt64 ( Some ( l) ) , Self :: UInt64 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) ) ,
26002620 // TODO: we might want to look into supporting ceil/floor here for floats.
26012621 ( Self :: Float16 ( Some ( l) ) , Self :: Float16 ( Some ( r) ) ) => {
2602- Some ( ( f16:: to_f32 ( * l) - f16:: to_f32 ( * r) ) . abs ( ) . round ( ) as _ )
2622+ let diff = ( f16:: to_f32 ( * l) - f16:: to_f32 ( * r) ) . abs ( ) . round ( ) ;
2623+ Self :: rounded_float_distance_u64 ( diff as f64 )
26032624 }
26042625 ( Self :: Float32 ( Some ( l) ) , Self :: Float32 ( Some ( r) ) ) => {
2605- Some ( ( l - r) . abs ( ) . round ( ) as _ )
2626+ let diff = ( l - r) . abs ( ) . round ( ) ;
2627+ Self :: rounded_float_distance_u64 ( diff as f64 )
26062628 }
26072629 ( Self :: Float64 ( Some ( l) ) , Self :: Float64 ( Some ( r) ) ) => {
2608- Some ( ( l - r) . abs ( ) . round ( ) as _ )
2630+ let diff = ( l - r) . abs ( ) . round ( ) ;
2631+ Self :: rounded_float_distance_u64 ( diff)
26092632 }
2610- ( Self :: Date32 ( Some ( l) ) , Self :: Date32 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2611- ( Self :: Date64 ( Some ( l) ) , Self :: Date64 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as _ ) ,
2633+ ( Self :: Date32 ( Some ( l) ) , Self :: Date32 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) as u64 ) ,
2634+ ( Self :: Date64 ( Some ( l) ) , Self :: Date64 ( Some ( r) ) ) => Some ( l. abs_diff ( * r) ) ,
26122635 // Timestamp values are stored as epoch ticks regardless of timezone
26132636 // annotation, so the distance is tz-independent (tz is display metadata).
26142637 ( Self :: TimestampSecond ( Some ( l) , _) , Self :: TimestampSecond ( Some ( r) , _) ) => {
2615- Some ( l. abs_diff ( * r) as _ )
2638+ Some ( l. abs_diff ( * r) )
26162639 }
26172640 (
26182641 Self :: TimestampMillisecond ( Some ( l) , _) ,
26192642 Self :: TimestampMillisecond ( Some ( r) , _) ,
2620- ) => Some ( l. abs_diff ( * r) as _ ) ,
2643+ ) => Some ( l. abs_diff ( * r) ) ,
26212644 (
26222645 Self :: TimestampMicrosecond ( Some ( l) , _) ,
26232646 Self :: TimestampMicrosecond ( Some ( r) , _) ,
2624- ) => Some ( l. abs_diff ( * r) as _ ) ,
2647+ ) => Some ( l. abs_diff ( * r) ) ,
26252648 (
26262649 Self :: TimestampNanosecond ( Some ( l) , _) ,
26272650 Self :: TimestampNanosecond ( Some ( r) , _) ,
2628- ) => Some ( l. abs_diff ( * r) as _ ) ,
2651+ ) => Some ( l. abs_diff ( * r) ) ,
2652+ (
2653+ Self :: Decimal32 ( Some ( l) , _, lscale) ,
2654+ Self :: Decimal32 ( Some ( r) , _, rscale) ,
2655+ ) => {
2656+ // In order to be aligned with PartialOrd we only
2657+ // check for equal scale, ignoring precision
2658+ if lscale == rscale {
2659+ Some ( l. abs_diff ( * r) as u64 )
2660+ } else {
2661+ None
2662+ }
2663+ }
2664+ (
2665+ Self :: Decimal64 ( Some ( l) , _, lscale) ,
2666+ Self :: Decimal64 ( Some ( r) , _, rscale) ,
2667+ ) => {
2668+ if lscale == rscale {
2669+ Some ( l. abs_diff ( * r) )
2670+ } else {
2671+ None
2672+ }
2673+ }
26292674 (
2630- Self :: Decimal128 ( Some ( l) , lprecision , lscale) ,
2631- Self :: Decimal128 ( Some ( r) , rprecision , rscale) ,
2675+ Self :: Decimal128 ( Some ( l) , _ , lscale) ,
2676+ Self :: Decimal128 ( Some ( r) , _ , rscale) ,
26322677 ) => {
2633- if lprecision == rprecision && lscale == rscale {
2634- l. checked_sub ( * r) ?. checked_abs ( ) ?. to_usize ( )
2678+ if lscale == rscale {
2679+ l. checked_sub ( * r) ?. checked_abs ( ) ?. to_u64 ( )
26352680 } else {
26362681 None
26372682 }
26382683 }
26392684 (
2640- Self :: Decimal256 ( Some ( l) , lprecision , lscale) ,
2641- Self :: Decimal256 ( Some ( r) , rprecision , rscale) ,
2685+ Self :: Decimal256 ( Some ( l) , _ , lscale) ,
2686+ Self :: Decimal256 ( Some ( r) , _ , rscale) ,
26422687 ) => {
2643- if lprecision == rprecision && lscale == rscale {
2644- l. checked_sub ( * r) ?. checked_abs ( ) ?. to_usize ( )
2688+ if lscale == rscale {
2689+ l. checked_sub ( * r) ?. checked_abs ( ) ?. to_u64 ( )
26452690 } else {
26462691 None
26472692 }
@@ -9444,8 +9489,8 @@ mod tests {
94449489 ) ,
94459490 ] ;
94469491 for ( lhs, rhs, expected) in cases. iter ( ) {
9447- let distance = lhs. distance ( rhs) . unwrap ( ) ;
9448- assert_eq ! ( distance, * expected) ;
9492+ let distance = lhs. distance_u64 ( rhs) . unwrap ( ) ;
9493+ assert_eq ! ( distance, * expected as u64 ) ;
94499494 }
94509495 }
94519496
@@ -9462,7 +9507,7 @@ mod tests {
94629507 ) ,
94639508 ] ;
94649509 for ( lhs, rhs) in cases. iter ( ) {
9465- let distance = lhs. distance ( rhs) ;
9510+ let distance = lhs. distance_u64 ( rhs) ;
94669511 assert ! ( distance. is_none( ) , "{lhs} vs {rhs}" ) ;
94679512 }
94689513 }
@@ -9508,13 +9553,9 @@ mod tests {
95089553 ScalarValue :: Decimal128 ( Some ( 123 ) , 5 , 5 ) ,
95099554 ScalarValue :: Decimal128 ( Some ( 120 ) , 5 , 3 ) ,
95109555 ) ,
9511- (
9512- ScalarValue :: Decimal128 ( Some ( 123 ) , 5 , 5 ) ,
9513- ScalarValue :: Decimal128 ( Some ( 120 ) , 3 , 5 ) ,
9514- ) ,
95159556 (
95169557 ScalarValue :: Decimal256 ( Some ( 123 . into ( ) ) , 5 , 5 ) ,
9517- ScalarValue :: Decimal256 ( Some ( 120 . into ( ) ) , 3 , 5 ) ,
9558+ ScalarValue :: Decimal256 ( Some ( 120 . into ( ) ) , 5 , 3 ) ,
95189559 ) ,
95199560 // Distance 2 * 2^50 is larger than usize
95209561 (
@@ -9536,11 +9577,124 @@ mod tests {
95369577 ) ,
95379578 ] ;
95389579 for ( lhs, rhs) in cases {
9539- let distance = lhs. distance ( & rhs) ;
9580+ let distance = lhs. distance_u64 ( & rhs) ;
95409581 assert ! ( distance. is_none( ) ) ;
95419582 }
95429583 }
95439584
9585+ #[ test]
9586+ fn test_scalar_distance_u64_boundaries ( ) {
9587+ // 1. Full-domain integer ranges
9588+ // i64::MIN to i64::MAX -> distance is u64::MAX
9589+ let lhs = ScalarValue :: Int64 ( Some ( i64:: MIN ) ) ;
9590+ let rhs = ScalarValue :: Int64 ( Some ( i64:: MAX ) ) ;
9591+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( u64 :: MAX ) ) ;
9592+ assert_eq ! ( rhs. distance_u64( & lhs) , Some ( u64 :: MAX ) ) ;
9593+
9594+ // u64::MIN to u64::MAX -> distance is u64::MAX
9595+ let lhs = ScalarValue :: UInt64 ( Some ( u64:: MIN ) ) ;
9596+ let rhs = ScalarValue :: UInt64 ( Some ( u64:: MAX ) ) ;
9597+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( u64 :: MAX ) ) ;
9598+ assert_eq ! ( rhs. distance_u64( & lhs) , Some ( u64 :: MAX ) ) ;
9599+
9600+ // 2. Decimal128 overflow edges (around u64::MAX)
9601+ // distance equal to u64::MAX fits
9602+ let lhs = ScalarValue :: Decimal128 ( Some ( 0 ) , 20 , 0 ) ;
9603+ let rhs = ScalarValue :: Decimal128 ( Some ( u64:: MAX as i128 ) , 20 , 0 ) ;
9604+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( u64 :: MAX ) ) ;
9605+
9606+ // distance greater than u64::MAX overflows
9607+ let lhs = ScalarValue :: Decimal128 ( Some ( 0 ) , 20 , 0 ) ;
9608+ let rhs = ScalarValue :: Decimal128 ( Some ( u64:: MAX as i128 + 1 ) , 20 , 0 ) ;
9609+ assert_eq ! ( lhs. distance_u64( & rhs) , None ) ;
9610+
9611+ // 3. Decimal256 overflow edges (around u64::MAX)
9612+ // distance equal to u64::MAX fits
9613+ let lhs = ScalarValue :: Decimal256 ( Some ( i256:: from_parts ( 0 , 0 ) ) , 20 , 0 ) ;
9614+ let rhs =
9615+ ScalarValue :: Decimal256 ( Some ( i256:: from_parts ( u64:: MAX as u128 , 0 ) ) , 20 , 0 ) ;
9616+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( u64 :: MAX ) ) ;
9617+
9618+ // distance greater than u64::MAX overflows
9619+ let lhs = ScalarValue :: Decimal256 ( Some ( i256:: from_parts ( 0 , 0 ) ) , 20 , 0 ) ;
9620+ let rhs = ScalarValue :: Decimal256 (
9621+ Some ( i256:: from_parts ( u64:: MAX as u128 + 1 , 0 ) ) ,
9622+ 20 ,
9623+ 0 ,
9624+ ) ;
9625+ assert_eq ! ( lhs. distance_u64( & rhs) , None ) ;
9626+
9627+ // 4. Float64 overflow edges (around u64::MAX)
9628+ let lhs = ScalarValue :: Float64 ( Some ( 0.0 ) ) ;
9629+ let val: f64 = 18446744073709500000.0 ;
9630+ let rhs = ScalarValue :: Float64 ( Some ( val) ) ;
9631+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( 18446744073709500416 ) ) ;
9632+
9633+ // float value > u64::MAX overflows
9634+ let rhs = ScalarValue :: Float64 ( Some ( 1.9e19 ) ) ;
9635+ assert_eq ! ( lhs. distance_u64( & rhs) , None ) ;
9636+
9637+ // exact 2^64 boundary (18446744073709551616.0) is greater than u64::MAX, so it should return None
9638+ let exact_2_64_f64 = ScalarValue :: Float64 ( Some ( 18446744073709551616.0 ) ) ;
9639+ assert_eq ! ( lhs. distance_u64( & exact_2_64_f64) , None ) ;
9640+
9641+ // exact 2^64 boundary as Float32 should also return None
9642+ let lhs_f32 = ScalarValue :: Float32 ( Some ( 0.0 ) ) ;
9643+ let exact_2_64_f32 = ScalarValue :: Float32 ( Some ( 18446744073709551616.0 ) ) ;
9644+ assert_eq ! ( lhs_f32. distance_u64( & exact_2_64_f32) , None ) ;
9645+
9646+ // largest float32 value below 2^64 (2^64 - 2^41 = 18446741874686296064.0) should fit
9647+ let below_2_64_f32 = ScalarValue :: Float32 ( Some ( 18446741874686296064.0 ) ) ;
9648+ assert_eq ! (
9649+ lhs_f32. distance_u64( & below_2_64_f32) ,
9650+ Some ( 18446741874686296064 )
9651+ ) ;
9652+
9653+ // Inf, NegInf, NaN
9654+ let inf = ScalarValue :: Float64 ( Some ( f64:: INFINITY ) ) ;
9655+ let neg_inf = ScalarValue :: Float64 ( Some ( f64:: NEG_INFINITY ) ) ;
9656+ let nan = ScalarValue :: Float64 ( Some ( f64:: NAN ) ) ;
9657+ assert_eq ! ( lhs. distance_u64( & inf) , None ) ;
9658+ assert_eq ! ( lhs. distance_u64( & neg_inf) , None ) ;
9659+ assert_eq ! ( lhs. distance_u64( & nan) , None ) ;
9660+
9661+ let inf_f32 = ScalarValue :: Float32 ( Some ( f32:: INFINITY ) ) ;
9662+ let neg_inf_f32 = ScalarValue :: Float32 ( Some ( f32:: NEG_INFINITY ) ) ;
9663+ let nan_f32 = ScalarValue :: Float32 ( Some ( f32:: NAN ) ) ;
9664+ assert_eq ! ( lhs_f32. distance_u64( & inf_f32) , None ) ;
9665+ assert_eq ! ( lhs_f32. distance_u64( & neg_inf_f32) , None ) ;
9666+ assert_eq ! ( lhs_f32. distance_u64( & nan_f32) , None ) ;
9667+
9668+ let lhs_f16 = ScalarValue :: Float16 ( Some ( f16:: ZERO ) ) ;
9669+ let inf_f16 = ScalarValue :: Float16 ( Some ( f16:: INFINITY ) ) ;
9670+ let neg_inf_f16 = ScalarValue :: Float16 ( Some ( f16:: NEG_INFINITY ) ) ;
9671+ let nan_f16 = ScalarValue :: Float16 ( Some ( f16:: NAN ) ) ;
9672+ assert_eq ! ( lhs_f16. distance_u64( & inf_f16) , None ) ;
9673+ assert_eq ! ( lhs_f16. distance_u64( & neg_inf_f16) , None ) ;
9674+ assert_eq ! ( lhs_f16. distance_u64( & nan_f16) , None ) ;
9675+
9676+ // 5. Date and Timestamp boundaries
9677+ // Date32: i32::MIN to i32::MAX
9678+ let lhs = ScalarValue :: Date32 ( Some ( i32:: MIN ) ) ;
9679+ let rhs = ScalarValue :: Date32 ( Some ( i32:: MAX ) ) ;
9680+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( u32 :: MAX as u64 ) ) ;
9681+
9682+ // TimestampSecond: i64::MIN to i64::MAX
9683+ let lhs = ScalarValue :: TimestampSecond ( Some ( i64:: MIN ) , None ) ;
9684+ let rhs = ScalarValue :: TimestampSecond ( Some ( i64:: MAX ) , None ) ;
9685+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( u64 :: MAX ) ) ;
9686+
9687+ // 6. Decimal scale matching (ignoring precision)
9688+ let lhs = ScalarValue :: Decimal128 ( Some ( 100 ) , 10 , 2 ) ;
9689+ let rhs = ScalarValue :: Decimal128 ( Some ( 150 ) , 15 , 2 ) ;
9690+ assert_eq ! ( lhs. distance_u64( & rhs) , Some ( 50 ) ) ;
9691+ assert_eq ! ( rhs. distance_u64( & lhs) , Some ( 50 ) ) ;
9692+
9693+ let lhs = ScalarValue :: Decimal128 ( Some ( 100 ) , 10 , 2 ) ;
9694+ let rhs = ScalarValue :: Decimal128 ( Some ( 150 ) , 10 , 3 ) ;
9695+ assert_eq ! ( lhs. distance_u64( & rhs) , None ) ;
9696+ }
9697+
95449698 #[ test]
95459699 fn test_scalar_interval_negate ( ) {
95469700 let cases = [
0 commit comments