alamb commented on code in PR #4493:
URL: https://github.com/apache/arrow-rs/pull/4493#discussion_r1258164185


##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");

Review Comment:
   👨‍🍳 👌  very nice message



##########
arrow-arith/src/numeric.rs:
##########
@@ -89,6 +90,18 @@ enum Op {
     Rem,
 }
 
+impl std::fmt::Display for Op {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {

Review Comment:
   💯 



##########
arrow-array/src/types.rs:
##########
@@ -457,17 +457,17 @@ impl TimestampSecondType {
         timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
         delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
     ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native, 
ArrowError> {
-        let (days, ms) = IntervalDayTimeType::to_parts(-delta);
+        let (days, ms) = IntervalDayTimeType::to_parts(delta);
         let res = NaiveDateTime::from_timestamp_opt(timestamp, 
0).ok_or_else(|| {
             ArrowError::ComputeError("Timestamp out of range".to_string())
         })?;
         let res = res
-            .checked_add_signed(Duration::days(days as i64))
+            .checked_sub_signed(Duration::days(days as i64))
             .ok_or_else(|| {
                 ArrowError::ComputeError("Timestamp out of range".to_string())
             })?;
         let res = res
-            .checked_add_signed(Duration::microseconds(ms as i64))
+            .checked_sub_signed(Duration::milliseconds(ms as i64))

Review Comment:
   This is a bug fix -- that `IntervalDayTime` stores data in milliseconds not 
microseconds 👍 



##########
arrow-arith/src/numeric.rs:
##########
@@ -570,8 +582,8 @@ fn decimal_op<T: DecimalType>(
                     .saturating_add(1)
                     .min(T::MAX_PRECISION);
 
-            let l_mul = T::Native::usize_as(10).pow_wrapping((result_scale - 
s1) as _);
-            let r_mul = T::Native::usize_as(10).pow_wrapping((result_scale - 
s2) as _);
+            let l_mul = T::Native::usize_as(10).pow_checked((result_scale - 
s1) as _)?;

Review Comment:
   I was a little confused at first about why  both `AddWrapping` and `Add` 
using the same function. Then 
   I realized this is for computing the scale factor
   
   Given `MAX_PRECISION` is a constant, what is the reason to change this to 
`pow_checked`? Maybe it doesn't matter performance wise, I was just curious



##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");
+        let result = add_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = sub(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 - 200");
+        let result = sub_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 * 200");
+        let result = mul_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
+
+        let a = Int16Array::from(vec![i16::MIN]);
+        let b = Int16Array::from(vec![-1]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: -32768 / -1");
+
+        let a = Int16Array::from(vec![21]);
+        let b = Int16Array::from(vec![0]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+    }
+
+    #[test]
+    fn test_float() {
+        let a = Float32Array::from(vec![1., f32::MAX, 6., -4., -1., 0.]);
+        let b = Float32Array::from(vec![1., f32::MAX, f32::MAX, -3., 45., 0.]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![2., f32::INFINITY, f32::MAX, -7., 44.0, 
0.])
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![0., 0., f32::MIN, -1., -46., 0.])
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![1., f32::INFINITY, f32::INFINITY, 12., 
-45., 0.])
+        );
+
+        let result = div(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(r.value(0), 1.);
+        assert_eq!(r.value(1), 1.);
+        assert!(r.value(2) < f32::EPSILON);
+        assert_eq!(r.value(3), -4. / -3.);
+        assert!(r.value(5).is_nan());
+
+        let result = rem(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(&r.values()[..5], &[0., 0., 6., -1., -1.]);
+        assert!(r.value(5).is_nan());
+    }
+
+    #[test]
+    fn test_decimal() {
+        // 0.015 7.842 -0.577 0.334 -0.078 0.003
+        let a = Decimal128Array::from(vec![15, 0, -577, 334, -78, 3])
+            .with_precision_and_scale(12, 3)
+            .unwrap();
+
+        // 5.4 0 -35.6 0.3 0.6 7.45
+        let b = Decimal128Array::from(vec![54, 34, -356, 3, 6, 745])
+            .with_precision_and_scale(12, 1)
+            .unwrap();
+
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[5415, 3400, -36177, 634, 522, 74503]
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[-5385, -3400, 35023, 34, -678, -74497]
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(25, 4));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[810, 0, 205412, 1002, -468, 2235]
+        );
+
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(17, 7));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[27777, 0, 162078, 11133333, -1300000, 402]
+        );
+
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(12, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[15, 0, -577, 34, -78, 3]
+        );
+
+        let a = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(3, 3)
+            .unwrap();
+        let b = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(37, 37)
+            .unwrap();
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Invalid argument error: Output scale of Decimal128(3, 
3) * Decimal128(37, 37) would exceed max scale of 38");
+
+        let a = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(3, -2)
+            .unwrap();
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 10 ^ 39");
+
+        let a = Decimal128Array::from(vec![10])
+            .with_precision_and_scale(3, -1)
+            .unwrap();
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 10 * 
100000000000000000000000000000000000000");
+
+        let b = Decimal128Array::from(vec![0])
+            .with_precision_and_scale(1, 1)
+            .unwrap();
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+        let err = rem(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+    }
+
+    fn test_timestamp_impl<T: TimestampOp>() {
+        let a = PrimitiveArray::<T>::new(vec![2000000, 434030324, 
53943340].into(), None);
+        let b = PrimitiveArray::<T>::new(vec![329593, 59349, 694994].into(), 
None);
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_primitive::<T::Duration>().values(),
+            &[1670407, 433970975, 53248346]
+        );
+
+        let r2 = add(&b, &result.as_ref()).unwrap();
+        assert_eq!(r2.as_ref(), &a);
+
+        let r3 = add(&result.as_ref(), &b).unwrap();
+        assert_eq!(r3.as_ref(), &a);
+
+        let format_array = |x: &dyn Array| -> Vec<String> {
+            x.as_primitive::<T>()
+                .values()
+                .into_iter()
+                .map(|x| as_datetime::<T>(*x).unwrap().to_string())
+                .collect()
+        };
+
+        let values = vec![
+            "1970-01-01T00:00:00Z",
+            "2010-04-01T04:00:20Z",
+            "1960-01-30T04:23:20Z",
+        ]
+        .into_iter()
+        .map(|x| {
+            
T::make_value(DateTime::parse_from_rfc3339(x).unwrap().naive_utc()).unwrap()
+        })
+        .collect();
+
+        let a = PrimitiveArray::<T>::new(values, None);
+        let b = IntervalYearMonthArray::from(vec![
+            IntervalYearMonthType::make_value(5, 34),
+            IntervalYearMonthType::make_value(-2, 4),

Review Comment:
   Can we also add a test for overflow (like subtracting two months from 
`1970-01-01T00:00:00Z`?



##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");
+        let result = add_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = sub(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 - 200");
+        let result = sub_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 * 200");
+        let result = mul_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
+
+        let a = Int16Array::from(vec![i16::MIN]);
+        let b = Int16Array::from(vec![-1]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: -32768 / -1");
+
+        let a = Int16Array::from(vec![21]);
+        let b = Int16Array::from(vec![0]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");

Review Comment:
   I didn't see a test for integer remainder `%`



##########
arrow-arith/src/arithmetic.rs:
##########
@@ -1315,7 +1315,7 @@ mod tests {
         let c = c.as_any().downcast_ref::<Date32Array>().unwrap();
         assert_eq!(
             c.value(0),
-            Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2023, 3, 
27).unwrap())
+            Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2023, 3, 
28).unwrap())

Review Comment:
   Date32: https://docs.rs/arrow/latest/arrow/datatypes/enum.IntervalUnit.html
   
   `86500` is milliseconds so 86.5 seconds before `2023-03-29`
   
   Thus `2023-03-28` seems much more correct to me



##########
arrow-arith/src/numeric.rs:
##########
@@ -89,6 +90,18 @@ enum Op {
     Rem,
 }
 
+impl std::fmt::Display for Op {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {

Review Comment:
   💯 



##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");
+        let result = add_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = sub(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 - 200");
+        let result = sub_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 * 200");
+        let result = mul_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
+
+        let a = Int16Array::from(vec![i16::MIN]);
+        let b = Int16Array::from(vec![-1]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: -32768 / -1");
+
+        let a = Int16Array::from(vec![21]);
+        let b = Int16Array::from(vec![0]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+    }
+
+    #[test]
+    fn test_float() {
+        let a = Float32Array::from(vec![1., f32::MAX, 6., -4., -1., 0.]);
+        let b = Float32Array::from(vec![1., f32::MAX, f32::MAX, -3., 45., 0.]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![2., f32::INFINITY, f32::MAX, -7., 44.0, 
0.])
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![0., 0., f32::MIN, -1., -46., 0.])
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![1., f32::INFINITY, f32::INFINITY, 12., 
-45., 0.])
+        );
+
+        let result = div(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(r.value(0), 1.);
+        assert_eq!(r.value(1), 1.);
+        assert!(r.value(2) < f32::EPSILON);
+        assert_eq!(r.value(3), -4. / -3.);
+        assert!(r.value(5).is_nan());
+
+        let result = rem(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(&r.values()[..5], &[0., 0., 6., -1., -1.]);
+        assert!(r.value(5).is_nan());
+    }
+
+    #[test]
+    fn test_decimal() {
+        // 0.015 7.842 -0.577 0.334 -0.078 0.003
+        let a = Decimal128Array::from(vec![15, 0, -577, 334, -78, 3])
+            .with_precision_and_scale(12, 3)
+            .unwrap();
+
+        // 5.4 0 -35.6 0.3 0.6 7.45
+        let b = Decimal128Array::from(vec![54, 34, -356, 3, 6, 745])
+            .with_precision_and_scale(12, 1)
+            .unwrap();
+
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[5415, 3400, -36177, 634, 522, 74503]
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[-5385, -3400, 35023, 34, -678, -74497]
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(25, 4));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[810, 0, 205412, 1002, -468, 2235]
+        );
+
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(17, 7));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[27777, 0, 162078, 11133333, -1300000, 402]
+        );
+
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(12, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[15, 0, -577, 34, -78, 3]
+        );
+
+        let a = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(3, 3)
+            .unwrap();
+        let b = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(37, 37)
+            .unwrap();
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Invalid argument error: Output scale of Decimal128(3, 
3) * Decimal128(37, 37) would exceed max scale of 38");

Review Comment:
   👍 



##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");

Review Comment:
   👨‍🍳 👌  very nice message



##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");
+        let result = add_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = sub(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 - 200");
+        let result = sub_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 * 200");
+        let result = mul_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
+
+        let a = Int16Array::from(vec![i16::MIN]);
+        let b = Int16Array::from(vec![-1]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: -32768 / -1");
+
+        let a = Int16Array::from(vec![21]);
+        let b = Int16Array::from(vec![0]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+    }
+
+    #[test]
+    fn test_float() {
+        let a = Float32Array::from(vec![1., f32::MAX, 6., -4., -1., 0.]);
+        let b = Float32Array::from(vec![1., f32::MAX, f32::MAX, -3., 45., 0.]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![2., f32::INFINITY, f32::MAX, -7., 44.0, 
0.])
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![0., 0., f32::MIN, -1., -46., 0.])
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![1., f32::INFINITY, f32::INFINITY, 12., 
-45., 0.])
+        );
+
+        let result = div(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(r.value(0), 1.);
+        assert_eq!(r.value(1), 1.);
+        assert!(r.value(2) < f32::EPSILON);
+        assert_eq!(r.value(3), -4. / -3.);
+        assert!(r.value(5).is_nan());
+
+        let result = rem(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(&r.values()[..5], &[0., 0., 6., -1., -1.]);
+        assert!(r.value(5).is_nan());
+    }
+
+    #[test]
+    fn test_decimal() {
+        // 0.015 7.842 -0.577 0.334 -0.078 0.003
+        let a = Decimal128Array::from(vec![15, 0, -577, 334, -78, 3])
+            .with_precision_and_scale(12, 3)
+            .unwrap();
+
+        // 5.4 0 -35.6 0.3 0.6 7.45
+        let b = Decimal128Array::from(vec![54, 34, -356, 3, 6, 745])
+            .with_precision_and_scale(12, 1)
+            .unwrap();
+
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[5415, 3400, -36177, 634, 522, 74503]
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[-5385, -3400, 35023, 34, -678, -74497]
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(25, 4));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[810, 0, 205412, 1002, -468, 2235]
+        );
+
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(17, 7));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[27777, 0, 162078, 11133333, -1300000, 402]
+        );
+
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(12, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[15, 0, -577, 34, -78, 3]
+        );
+
+        let a = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(3, 3)
+            .unwrap();
+        let b = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(37, 37)
+            .unwrap();
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Invalid argument error: Output scale of Decimal128(3, 
3) * Decimal128(37, 37) would exceed max scale of 38");
+
+        let a = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(3, -2)
+            .unwrap();
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 10 ^ 39");
+
+        let a = Decimal128Array::from(vec![10])
+            .with_precision_and_scale(3, -1)
+            .unwrap();
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 10 * 
100000000000000000000000000000000000000");
+
+        let b = Decimal128Array::from(vec![0])
+            .with_precision_and_scale(1, 1)
+            .unwrap();
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+        let err = rem(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+    }
+
+    fn test_timestamp_impl<T: TimestampOp>() {
+        let a = PrimitiveArray::<T>::new(vec![2000000, 434030324, 
53943340].into(), None);
+        let b = PrimitiveArray::<T>::new(vec![329593, 59349, 694994].into(), 
None);
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_primitive::<T::Duration>().values(),
+            &[1670407, 433970975, 53248346]
+        );
+
+        let r2 = add(&b, &result.as_ref()).unwrap();
+        assert_eq!(r2.as_ref(), &a);
+
+        let r3 = add(&result.as_ref(), &b).unwrap();
+        assert_eq!(r3.as_ref(), &a);
+
+        let format_array = |x: &dyn Array| -> Vec<String> {
+            x.as_primitive::<T>()
+                .values()
+                .into_iter()
+                .map(|x| as_datetime::<T>(*x).unwrap().to_string())
+                .collect()
+        };
+
+        let values = vec![
+            "1970-01-01T00:00:00Z",
+            "2010-04-01T04:00:20Z",
+            "1960-01-30T04:23:20Z",
+        ]
+        .into_iter()
+        .map(|x| {
+            
T::make_value(DateTime::parse_from_rfc3339(x).unwrap().naive_utc()).unwrap()
+        })
+        .collect();
+
+        let a = PrimitiveArray::<T>::new(values, None);
+        let b = IntervalYearMonthArray::from(vec![
+            IntervalYearMonthType::make_value(5, 34),
+            IntervalYearMonthType::make_value(-2, 4),
+            IntervalYearMonthType::make_value(7, -4),
+        ]);
+        let r4 = add(&a, &b).unwrap();
+        assert_eq!(
+            &format_array(r4.as_ref()),
+            &[
+                "1977-11-01 00:00:00".to_string(),
+                "2008-08-01 04:00:20".to_string(),
+                "1966-09-30 04:23:20".to_string()
+            ]
+        );
+
+        let r5 = sub(&r4, &b).unwrap();
+        assert_eq!(r5.as_ref(), &a);
+
+        let b = IntervalDayTimeArray::from(vec![
+            IntervalDayTimeType::make_value(5, 454000),
+            IntervalDayTimeType::make_value(-34, 0),
+            IntervalDayTimeType::make_value(7, -4000),
+        ]);
+        let r6 = add(&a, &b).unwrap();
+        assert_eq!(
+            &format_array(r6.as_ref()),
+            &[
+                "1970-01-06 00:07:34".to_string(),
+                "2010-02-26 04:00:20".to_string(),
+                "1960-02-06 04:23:16".to_string()
+            ]
+        );
+
+        let r7 = sub(&r6, &b).unwrap();
+        assert_eq!(r7.as_ref(), &a);
+
+        let b = IntervalMonthDayNanoArray::from(vec![
+            IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000),
+            IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000),
+            IntervalMonthDayNanoType::make_value(5, 2, 493_000_000_000),
+        ]);
+        let r8 = add(&a, &b).unwrap();
+        assert_eq!(
+            &format_array(r8.as_ref()),
+            &[
+                "1998-10-04 23:59:17".to_string(),
+                "1960-09-29 04:00:33".to_string(),
+                "1960-07-02 04:31:33".to_string()
+            ]
+        );
+
+        let r9 = sub(&r8, &b).unwrap();
+        // Note: subtraction is not the inverse of addition for intervals
+        assert_eq!(
+            &format_array(r9.as_ref()),
+            &[
+                "1970-01-02 00:00:00".to_string(),
+                "2010-04-02 04:00:20".to_string(),
+                "1960-01-31 04:23:20".to_string()
+            ]
+        );
+    }
+
+    #[test]
+    fn test_timestamp() {
+        test_timestamp_impl::<TimestampSecondType>();
+        test_timestamp_impl::<TimestampMillisecondType>();
+        test_timestamp_impl::<TimestampMicrosecondType>();
+        test_timestamp_impl::<TimestampNanosecondType>();
+    }
+
+    #[test]
+    fn test_interval() {
+        let a = IntervalYearMonthArray::from(vec![
+            IntervalYearMonthType::make_value(32, 4),
+            IntervalYearMonthType::make_value(32, 4),
+        ]);
+        let b = IntervalYearMonthArray::from(vec![
+            IntervalYearMonthType::make_value(-4, 6),
+            IntervalYearMonthType::make_value(-3, 23),
+        ]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &IntervalYearMonthArray::from(vec![
+                IntervalYearMonthType::make_value(28, 10),
+                IntervalYearMonthType::make_value(29, 27)
+            ])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &IntervalYearMonthArray::from(vec![
+                IntervalYearMonthType::make_value(36, -2),
+                IntervalYearMonthType::make_value(35, -19)
+            ])
+        );
+
+        let a = IntervalDayTimeArray::from(vec![
+            IntervalDayTimeType::make_value(32, 4),
+            IntervalDayTimeType::make_value(32, 4),
+        ]);
+        let b = IntervalDayTimeArray::from(vec![
+            IntervalDayTimeType::make_value(-4, 6),
+            IntervalDayTimeType::make_value(-3, 23),
+        ]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &IntervalDayTimeArray::from(vec![
+                IntervalDayTimeType::make_value(28, 10),
+                IntervalDayTimeType::make_value(29, 27)
+            ])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &IntervalDayTimeArray::from(vec![
+                IntervalDayTimeType::make_value(36, -2),
+                IntervalDayTimeType::make_value(35, -19)
+            ])
+        );
+        let a = IntervalMonthDayNanoArray::from(vec![
+            IntervalMonthDayNanoType::make_value(32, 4, 4000000000000),
+            IntervalMonthDayNanoType::make_value(32, 4, 45463000000000000),
+        ]);
+        let b = IntervalMonthDayNanoArray::from(vec![
+            IntervalMonthDayNanoType::make_value(-4, 6, 46000000000000),
+            IntervalMonthDayNanoType::make_value(-3, 23, 3564000000000000),
+        ]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &IntervalMonthDayNanoArray::from(vec![
+                IntervalMonthDayNanoType::make_value(28, 10, 50000000000000),
+                IntervalMonthDayNanoType::make_value(29, 27, 49027000000000000)
+            ])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &IntervalMonthDayNanoArray::from(vec![
+                IntervalMonthDayNanoType::make_value(36, -2, -42000000000000),
+                IntervalMonthDayNanoType::make_value(35, -19, 
41899000000000000)
+            ])
+        );
+        let a = IntervalMonthDayNanoArray::from(vec![i64::MAX as i128]);
+        let b = IntervalMonthDayNanoArray::from(vec![1]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(
+            err,
+            "Compute error: Overflow happened on: 9223372036854775807 + 1"
+        );
+    }
+
+    fn test_duration_impl<T: ArrowPrimitiveType<Native = i64>>() {
+        let a = PrimitiveArray::<T>::new(vec![1000, 4394, -3944].into(), None);
+        let b = PrimitiveArray::<T>::new(vec![4, -5, -243].into(), None);
+
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_primitive::<T>().values(), &[1004, 4389, -4187]);
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_primitive::<T>().values(), &[996, 4399, -3701]);
+
+        let a = PrimitiveArray::<T>::new(vec![i64::MAX].into(), None);
+        let b = PrimitiveArray::<T>::new(vec![1].into(), None);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(
+            err,
+            "Compute error: Overflow happened on: 9223372036854775807 + 1"
+        );

Review Comment:
   is it worthing adding a test here showing that `*` and `/` are not supported 
for durations?



##########
arrow-arith/src/numeric.rs:
##########
@@ -670,3 +682,490 @@ fn decimal_op<T: DecimalType>(
 
     Ok(Arc::new(array))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use arrow_array::temporal_conversions::{as_date, as_datetime};
+    use chrono::{DateTime, NaiveDate};
+
+    #[test]
+    fn test_integer() {
+        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
+        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Int32Array::from(vec![10, 5, 10, -13, 103])
+        );
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 
300]));
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
+
+        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
+        let b = Int8Array::from(vec![Some(5), Some(3), None]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, 
None]));
+
+        let a = UInt8Array::from(vec![56, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = add(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 56 + 200");
+        let result = add_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = sub(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 - 200");
+        let result = sub_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
+
+        let a = UInt8Array::from(vec![34, 5, 3]);
+        let b = UInt8Array::from(vec![200, 2, 5]);
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: 34 * 200");
+        let result = mul_wrapping(&a, &b).unwrap();
+        assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
+
+        let a = Int16Array::from(vec![i16::MIN]);
+        let b = Int16Array::from(vec![-1]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Compute error: Overflow happened on: -32768 / -1");
+
+        let a = Int16Array::from(vec![21]);
+        let b = Int16Array::from(vec![0]);
+        let err = div(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Divide by zero error");
+    }
+
+    #[test]
+    fn test_float() {
+        let a = Float32Array::from(vec![1., f32::MAX, 6., -4., -1., 0.]);
+        let b = Float32Array::from(vec![1., f32::MAX, f32::MAX, -3., 45., 0.]);
+        let result = add(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![2., f32::INFINITY, f32::MAX, -7., 44.0, 
0.])
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![0., 0., f32::MIN, -1., -46., 0.])
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(
+            result.as_ref(),
+            &Float32Array::from(vec![1., f32::INFINITY, f32::INFINITY, 12., 
-45., 0.])
+        );
+
+        let result = div(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(r.value(0), 1.);
+        assert_eq!(r.value(1), 1.);
+        assert!(r.value(2) < f32::EPSILON);
+        assert_eq!(r.value(3), -4. / -3.);
+        assert!(r.value(5).is_nan());
+
+        let result = rem(&a, &b).unwrap();
+        let r = result.as_primitive::<Float32Type>();
+        assert_eq!(&r.values()[..5], &[0., 0., 6., -1., -1.]);
+        assert!(r.value(5).is_nan());
+    }
+
+    #[test]
+    fn test_decimal() {
+        // 0.015 7.842 -0.577 0.334 -0.078 0.003
+        let a = Decimal128Array::from(vec![15, 0, -577, 334, -78, 3])
+            .with_precision_and_scale(12, 3)
+            .unwrap();
+
+        // 5.4 0 -35.6 0.3 0.6 7.45
+        let b = Decimal128Array::from(vec![54, 34, -356, 3, 6, 745])
+            .with_precision_and_scale(12, 1)
+            .unwrap();
+
+        let result = add(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[5415, 3400, -36177, 634, 522, 74503]
+        );
+
+        let result = sub(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[-5385, -3400, 35023, 34, -678, -74497]
+        );
+
+        let result = mul(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(25, 4));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[810, 0, 205412, 1002, -468, 2235]
+        );
+
+        let result = div(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(17, 7));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[27777, 0, 162078, 11133333, -1300000, 402]
+        );
+
+        let result = rem(&a, &b).unwrap();
+        assert_eq!(result.data_type(), &DataType::Decimal128(12, 3));
+        assert_eq!(
+            result.as_primitive::<Decimal128Type>().values(),
+            &[15, 0, -577, 34, -78, 3]
+        );
+
+        let a = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(3, 3)
+            .unwrap();
+        let b = Decimal128Array::from(vec![1])
+            .with_precision_and_scale(37, 37)
+            .unwrap();
+        let err = mul(&a, &b).unwrap_err().to_string();
+        assert_eq!(err, "Invalid argument error: Output scale of Decimal128(3, 
3) * Decimal128(37, 37) would exceed max scale of 38");

Review Comment:
   👍 



##########
arrow-array/src/types.rs:
##########
@@ -457,17 +457,17 @@ impl TimestampSecondType {
         timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
         delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
     ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native, 
ArrowError> {
-        let (days, ms) = IntervalDayTimeType::to_parts(-delta);
+        let (days, ms) = IntervalDayTimeType::to_parts(delta);
         let res = NaiveDateTime::from_timestamp_opt(timestamp, 
0).ok_or_else(|| {
             ArrowError::ComputeError("Timestamp out of range".to_string())
         })?;
         let res = res
-            .checked_add_signed(Duration::days(days as i64))
+            .checked_sub_signed(Duration::days(days as i64))
             .ok_or_else(|| {
                 ArrowError::ComputeError("Timestamp out of range".to_string())
             })?;
         let res = res
-            .checked_add_signed(Duration::microseconds(ms as i64))
+            .checked_sub_signed(Duration::milliseconds(ms as i64))

Review Comment:
   This is a bug fix -- that `IntervalDayTime` stores data in milliseconds not 
microseconds 👍 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to