## Coverage Report

#### Created: 2025-08-26 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-arith/src/numeric.rs

    Line
    Count
    Source
    1
    // Licensed to the Apache Software Foundation (ASF) under one
    2
    // or more contributor license agreements.  See the NOTICE file
    3
    // distributed with this work for additional information
    4
    // regarding copyright ownership.  The ASF licenses this file
    5
    // to you under the Apache License, Version 2.0 (the
    6
    // "License"); you may not use this file except in compliance
    7
    // with the License.  You may obtain a copy of the License at
    8
    //
    9
    //   http://www.apache.org/licenses/LICENSE-2.0
    10
    //
    11
    // Unless required by applicable law or agreed to in writing,
    12
    // software distributed under the License is distributed on an
    13
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14
    // KIND, either express or implied.  See the License for the
    15
    // specific language governing permissions and limitations
    16
    // under the License.
    17
    18
    //! Defines numeric arithmetic kernels on [`PrimitiveArray`], such as [`add`]
    19
    20
    use std::cmp::Ordering;
    21
    use std::fmt::Formatter;
    22
    use std::sync::Arc;
    23
    24
    use arrow_array::cast::AsArray;
    25
    use arrow_array::timezone::Tz;
    26
    use arrow_array::types::*;
    27
    use arrow_array::*;
    28
    use arrow_buffer::{ArrowNativeType, IntervalDayTime, IntervalMonthDayNano};
    29
    use arrow_schema::{ArrowError, DataType, IntervalUnit, TimeUnit};
    30
    31
    use crate::arity::{binary, try_binary};
    32
    33
    /// Perform `lhs + rhs`, returning an error on overflow
    34
    0
    pub fn add(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    35
    0
        arithmetic_op(Op::Add, lhs, rhs)
    36
    0
    }
    37
    38
    /// Perform `lhs + rhs`, wrapping on overflow for [`DataType::is_integer`]
    39
    0
    pub fn add_wrapping(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    40
    0
        arithmetic_op(Op::AddWrapping, lhs, rhs)
    41
    0
    }
    42
    43
    /// Perform `lhs - rhs`, returning an error on overflow
    44
    0
    pub fn sub(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    45
    0
        arithmetic_op(Op::Sub, lhs, rhs)
    46
    0
    }
    47
    48
    /// Perform `lhs - rhs`, wrapping on overflow for [`DataType::is_integer`]
    49
    0
    pub fn sub_wrapping(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    50
    0
        arithmetic_op(Op::SubWrapping, lhs, rhs)
    51
    0
    }
    52
    53
    /// Perform `lhs * rhs`, returning an error on overflow
    54
    0
    pub fn mul(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    55
    0
        arithmetic_op(Op::Mul, lhs, rhs)
    56
    0
    }
    57
    58
    /// Perform `lhs * rhs`, wrapping on overflow for [`DataType::is_integer`]
    59
    0
    pub fn mul_wrapping(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    60
    0
        arithmetic_op(Op::MulWrapping, lhs, rhs)
    61
    0
    }
    62
    63
    /// Perform `lhs / rhs`
    64
    ///
    65
    /// Overflow or division by zero will result in an error, with exception to
    66
    /// floating point numbers, which instead follow the IEEE 754 rules
    67
    0
    pub fn div(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    68
    0
        arithmetic_op(Op::Div, lhs, rhs)
    69
    0
    }
    70
    71
    /// Perform `lhs % rhs`
    72
    ///
    73
    /// Division by zero will result in an error, with exception to
    74
    /// floating point numbers, which instead follow the IEEE 754 rules
    75
    ///
    76
    /// `signed_integer::MIN % -1` will not result in an error but return 0
    77
    0
    pub fn rem(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    78
    0
        arithmetic_op(Op::Rem, lhs, rhs)
    79
    0
    }
    80
    81
    macro_rules! neg_checked {
    82
        ($t:ty, $a:ident) => {{
    83
            let array = $a
    84
                .as_primitive::<$t>()
    85
    0
                .try_unary::<_, $t, _>(|x| x.neg_checked())?;
    86
            Ok(Arc::new(array))
    87
        }};
    88
    }
    89
    90
    macro_rules! neg_wrapping {
    91
        ($t:ty, $a:ident) => {{
    92
    0
            let array = $a.as_primitive::<$t>().unary::<_, $t>(|x| x.neg_wrapping());
    93
            Ok(Arc::new(array))
    94
        }};
    95
    }
    96
    97
    /// Negates each element of  `array`, returning an error on overflow
    98
    ///
    99
    /// Note: negation of unsigned arrays is not supported and will return in an error,
    100
    /// for wrapping unsigned negation consider using [`neg_wrapping`][neg_wrapping()]
    101
    0
    pub fn neg(array: &dyn Array) -> Result<ArrayRef, ArrowError> {
    102
        use DataType::*;
    103
        use IntervalUnit::*;
    104
        use TimeUnit::*;
    105
    106
    0
        match array.data_type() {
    107
    0
            Int8 => neg_checked!(Int8Type, array),
    108
    0
            Int16 => neg_checked!(Int16Type, array),
    109
    0
            Int32 => neg_checked!(Int32Type, array),
    110
    0
            Int64 => neg_checked!(Int64Type, array),
    111
    0
            Float16 => neg_wrapping!(Float16Type, array),
    112
    0
            Float32 => neg_wrapping!(Float32Type, array),
    113
    0
            Float64 => neg_wrapping!(Float64Type, array),
    114
    0
            Decimal32(p, s) => {
    115
    0
                let a = array
    116
    0
                    .as_primitive::<Decimal32Type>()
    117
    0
                    .try_unary::<_, Decimal32Type, _>(|x| x.neg_checked())?;
    118
    119
    0
                Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
    120
            }
    121
    0
            Decimal64(p, s) => {
    122
    0
                let a = array
    123
    0
                    .as_primitive::<Decimal64Type>()
    124
    0
                    .try_unary::<_, Decimal64Type, _>(|x| x.neg_checked())?;
    125
    126
    0
                Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
    127
            }
    128
    0
            Decimal128(p, s) => {
    129
    0
                let a = array
    130
    0
                    .as_primitive::<Decimal128Type>()
    131
    0
                    .try_unary::<_, Decimal128Type, _>(|x| x.neg_checked())?;
    132
    133
    0
                Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
    134
            }
    135
    0
            Decimal256(p, s) => {
    136
    0
                let a = array
    137
    0
                    .as_primitive::<Decimal256Type>()
    138
    0
                    .try_unary::<_, Decimal256Type, _>(|x| x.neg_checked())?;
    139
    140
    0
                Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
    141
            }
    142
    0
            Duration(Second) => neg_checked!(DurationSecondType, array),
    143
    0
            Duration(Millisecond) => neg_checked!(DurationMillisecondType, array),
    144
    0
            Duration(Microsecond) => neg_checked!(DurationMicrosecondType, array),
    145
    0
            Duration(Nanosecond) => neg_checked!(DurationNanosecondType, array),
    146
    0
            Interval(YearMonth) => neg_checked!(IntervalYearMonthType, array),
    147
            Interval(DayTime) => {
    148
    0
                let a = array
    149
    0
                    .as_primitive::<IntervalDayTimeType>()
    150
    0
                    .try_unary::<_, IntervalDayTimeType, ArrowError>(|x| {
    151
    0
                        let (days, ms) = IntervalDayTimeType::to_parts(x);
    152
    0
                        Ok(IntervalDayTimeType::make_value(
    153
    0
                            days.neg_checked()?,
    154
    0
                            ms.neg_checked()?,
    155
                        ))
    156
    0
                    })?;
    157
    0
                Ok(Arc::new(a))
    158
            }
    159
            Interval(MonthDayNano) => {
    160
    0
                let a = array
    161
    0
                    .as_primitive::<IntervalMonthDayNanoType>()
    162
    0
                    .try_unary::<_, IntervalMonthDayNanoType, ArrowError>(|x| {
    163
    0
                        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(x);
    164
    0
                        Ok(IntervalMonthDayNanoType::make_value(
    165
    0
                            months.neg_checked()?,
    166
    0
                            days.neg_checked()?,
    167
    0
                            nanos.neg_checked()?,
    168
                        ))
    169
    0
                    })?;
    170
    0
                Ok(Arc::new(a))
    171
            }
    172
    0
            t => Err(ArrowError::InvalidArgumentError(format!(
    173
    0
                "Invalid arithmetic operation: !{t}"
    174
    0
            ))),
    175
        }
    176
    0
    }
    177
    178
    /// Negates each element of  `array`, wrapping on overflow for [`DataType::is_integer`]
    179
    0
    pub fn neg_wrapping(array: &dyn Array) -> Result<ArrayRef, ArrowError> {
    180
    0
        downcast_integer! {
    181
    0
            array.data_type() => (neg_wrapping, array),
    182
    0
            _ => neg(array),
    183
        }
    184
    0
    }
    185
    186
    /// An enumeration of arithmetic operations
    187
    ///
    188
    /// This allows sharing the type dispatch logic across the various kernels
    189
    #[derive(Debug, Copy, Clone)]
    190
    enum Op {
    191
        AddWrapping,
    192
        Add,
    193
        SubWrapping,
    194
        Sub,
    195
        MulWrapping,
    196
        Mul,
    197
        Div,
    198
        Rem,
    199
    }
    200
    201
    impl std::fmt::Display for Op {
    202
    0
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    203
    0
            match self {
    204
    0
                Op::AddWrapping | Op::Add => write!(f, "+"),
    205
    0
                Op::SubWrapping | Op::Sub => write!(f, "-"),
    206
    0
                Op::MulWrapping | Op::Mul => write!(f, "*"),
    207
    0
                Op::Div => write!(f, "/"),
    208
    0
                Op::Rem => write!(f, "%"),
    209
            }
    210
    0
        }
    211
    }
    212
    213
    impl Op {
    214
    0
        fn commutative(&self) -> bool {
    215
    0
            matches!(self, Self::Add | Self::AddWrapping)
    216
    0
        }
    217
    }
    218
    219
    /// Dispatch the given `op` to the appropriate specialized kernel
    220
    0
    fn arithmetic_op(op: Op, lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
    221
        use DataType::*;
    222
        use IntervalUnit::*;
    223
        use TimeUnit::*;
    224
    225
        macro_rules! integer_helper {
    226
            ($t:ty, $op:ident, $l:ident, $l_scalar:ident, $r:ident, $r_scalar:ident) => {
    227
                integer_op::<$t>($op, $l, $l_scalar, $r, $r_scalar)
    228
            };
    229
        }
    230
    231
    0
        let (l, l_scalar) = lhs.get();
    232
    0
        let (r, r_scalar) = rhs.get();
    233
    0
        downcast_integer! {
    234
    0
            l.data_type(), r.data_type() => (integer_helper, op, l, l_scalar, r, r_scalar),
    235
    0
            (Float16, Float16) => float_op::<Float16Type>(op, l, l_scalar, r, r_scalar),
    236
    0
            (Float32, Float32) => float_op::<Float32Type>(op, l, l_scalar, r, r_scalar),
    237
    0
            (Float64, Float64) => float_op::<Float64Type>(op, l, l_scalar, r, r_scalar),
    238
    0
            (Timestamp(Second, _), _) => timestamp_op::<TimestampSecondType>(op, l, l_scalar, r, r_scalar),
    239
    0
            (Timestamp(Millisecond, _), _) => timestamp_op::<TimestampMillisecondType>(op, l, l_scalar, r, r_scalar),
    240
    0
            (Timestamp(Microsecond, _), _) => timestamp_op::<TimestampMicrosecondType>(op, l, l_scalar, r, r_scalar),
    241
    0
            (Timestamp(Nanosecond, _), _) => timestamp_op::<TimestampNanosecondType>(op, l, l_scalar, r, r_scalar),
    242
    0
            (Duration(Second), Duration(Second)) => duration_op::<DurationSecondType>(op, l, l_scalar, r, r_scalar),
    243
    0
            (Duration(Millisecond), Duration(Millisecond)) => duration_op::<DurationMillisecondType>(op, l, l_scalar, r, r_scalar),
    244
    0
            (Duration(Microsecond), Duration(Microsecond)) => duration_op::<DurationMicrosecondType>(op, l, l_scalar, r, r_scalar),
    245
    0
            (Duration(Nanosecond), Duration(Nanosecond)) => duration_op::<DurationNanosecondType>(op, l, l_scalar, r, r_scalar),
    246
    0
            (Interval(YearMonth), Interval(YearMonth)) => interval_op::<IntervalYearMonthType>(op, l, l_scalar, r, r_scalar),
    247
    0
            (Interval(DayTime), Interval(DayTime)) => interval_op::<IntervalDayTimeType>(op, l, l_scalar, r, r_scalar),
    248
    0
            (Interval(MonthDayNano), Interval(MonthDayNano)) => interval_op::<IntervalMonthDayNanoType>(op, l, l_scalar, r, r_scalar),
    249
    0
            (Date32, _) => date_op::<Date32Type>(op, l, l_scalar, r, r_scalar),
    250
    0
            (Date64, _) => date_op::<Date64Type>(op, l, l_scalar, r, r_scalar),
    251
    0
            (Decimal32(_, _), Decimal32(_, _)) => decimal_op::<Decimal32Type>(op, l, l_scalar, r, r_scalar),
    252
    0
            (Decimal64(_, _), Decimal64(_, _)) => decimal_op::<Decimal64Type>(op, l, l_scalar, r, r_scalar),
    253
    0
            (Decimal128(_, _), Decimal128(_, _)) => decimal_op::<Decimal128Type>(op, l, l_scalar, r, r_scalar),
    254
    0
            (Decimal256(_, _), Decimal256(_, _)) => decimal_op::<Decimal256Type>(op, l, l_scalar, r, r_scalar),
    255
    0
            (l_t, r_t) => match (l_t, r_t) {
    256
    0
                (Duration(_) | Interval(_), Date32 | Date64 | Timestamp(_, _)) if op.commutative() => {
    257
    0
                    arithmetic_op(op, rhs, lhs)
    258
                }
    259
    0
                _ => Err(ArrowError::InvalidArgumentError(
    260
    0
                  format!("Invalid arithmetic operation: {l_t} {op} {r_t}")
    261
    0
                ))
    262
            }
    263
        }
    264
    0
    }
    265
    266
    /// Perform an infallible binary operation on potentially scalar inputs
    267
    macro_rules! op {
    268
        ($l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {
    269
            match ($l_s, $r_s) {
    270
                (true, true) | (false, false) => binary($l, $r, |$l, $r| $op)?,
    271
    0
                (true, false) => match ($l.null_count() == 0).then(|| $l.value(0)) {
    272
                    None => PrimitiveArray::new_null($r.len()),
    273
                    Some($l) => $r.unary(|$r| $op),
    274
                },
    275
    0
                (false, true) => match ($r.null_count() == 0).then(|| $r.value(0)) {
    276
                    None => PrimitiveArray::new_null($l.len()),
    277
                    Some($r) => $l.unary(|$l| $op),
    278
                },
    279
            }
    280
        };
    281
    }
    282
    283
    /// Same as `op` but with a type hint for the returned array
    284
    macro_rules! op_ref {
    285
        ($t:ty, $l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {{
    286
            let array: PrimitiveArray<$t> = op!($l, $l_s, $r, $r_s, $op);
    287
            Arc::new(array)
    288
        }};
    289
    }
    290
    291
    /// Perform a fallible binary operation on potentially scalar inputs
    292
    macro_rules! try_op {
    293
        ($l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {
    294
            match ($l_s, $r_s) {
    295
                (true, true) | (false, false) => try_binary($l, $r, |$l, $r| $op)?,
    296
    0
                (true, false) => match ($l.null_count() == 0).then(|| $l.value(0)) {
    297
                    None => PrimitiveArray::new_null($r.len()),
    298
                    Some($l) => $r.try_unary(|$r| $op)?,
    299
                },
    300
    0
                (false, true) => match ($r.null_count() == 0).then(|| $r.value(0)) {
    301
                    None => PrimitiveArray::new_null($l.len()),
    302
                    Some($r) => $l.try_unary(|$l| $op)?,
    303
                },
    304
            }
    305
        };
    306
    }
    307
    308
    /// Same as `try_op` but with a type hint for the returned array
    309
    macro_rules! try_op_ref {
    310
        ($t:ty, $l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {{
    311
            let array: PrimitiveArray<$t> = try_op!($l, $l_s, $r, $r_s, $op);
    312
            Arc::new(array)
    313
        }};
    314
    }
    315
    316
    /// Perform an arithmetic operation on integers
    317
    0
    fn integer_op<T: ArrowPrimitiveType>(
    318
    0
        op: Op,
    319
    0
        l: &dyn Array,
    320
    0
        l_s: bool,
    321
    0
        r: &dyn Array,
    322
    0
        r_s: bool,
    323
    0
    ) -> Result<ArrayRef, ArrowError> {
    324
    0
        let l = l.as_primitive::<T>();
    325
    0
        let r = r.as_primitive::<T>();
    326
    0
        let array: PrimitiveArray<T> = match op {
    327
    0
            Op::AddWrapping => op!(l, l_s, r, r_s, l.add_wrapping(r)),
    328
    0
            Op::Add => try_op!(l, l_s, r, r_s, l.add_checked(r)),
    329
    0
            Op::SubWrapping => op!(l, l_s, r, r_s, l.sub_wrapping(r)),
    330
    0
            Op::Sub => try_op!(l, l_s, r, r_s, l.sub_checked(r)),
    331
    0
            Op::MulWrapping => op!(l, l_s, r, r_s, l.mul_wrapping(r)),
    332
    0
            Op::Mul => try_op!(l, l_s, r, r_s, l.mul_checked(r)),
    333
    0
            Op::Div => try_op!(l, l_s, r, r_s, l.div_checked(r)),
    334
    0
            Op::Rem => try_op!(l, l_s, r, r_s, {
    335
    0
                if r.is_zero() {
    336
    0
                    Err(ArrowError::DivideByZero)
    337
                } else {
    338
    0
                    Ok(l.mod_wrapping(r))
    339
                }
    340
            }),
    341
        };
    342
    0
        Ok(Arc::new(array))
    343
    0
    }
    344
    345
    /// Perform an arithmetic operation on floats
    346
    0
    fn float_op<T: ArrowPrimitiveType>(
    347
    0
        op: Op,
    348
    0
        l: &dyn Array,
    349
    0
        l_s: bool,
    350
    0
        r: &dyn Array,
    351
    0
        r_s: bool,
    352
    0
    ) -> Result<ArrayRef, ArrowError> {
    353
    0
        let l = l.as_primitive::<T>();
    354
    0
        let r = r.as_primitive::<T>();
    355
    0
        let array: PrimitiveArray<T> = match op {
    356
    0
            Op::AddWrapping | Op::Add => op!(l, l_s, r, r_s, l.add_wrapping(r)),
    357
    0
            Op::SubWrapping | Op::Sub => op!(l, l_s, r, r_s, l.sub_wrapping(r)),
    358
    0
            Op::MulWrapping | Op::Mul => op!(l, l_s, r, r_s, l.mul_wrapping(r)),
    359
    0
            Op::Div => op!(l, l_s, r, r_s, l.div_wrapping(r)),
    360
    0
            Op::Rem => op!(l, l_s, r, r_s, l.mod_wrapping(r)),
    361
        };
    362
    0
        Ok(Arc::new(array))
    363
    0
    }
    364
    365
    /// Arithmetic trait for timestamp arrays
    366
    trait TimestampOp: ArrowTimestampType {
    367
        type Duration: ArrowPrimitiveType<Native = i64>;
    368
    369
        fn add_year_month(timestamp: i64, delta: i32, tz: Tz) -> Option<i64>;
    370
        fn add_day_time(timestamp: i64, delta: IntervalDayTime, tz: Tz) -> Option<i64>;
    371
        fn add_month_day_nano(timestamp: i64, delta: IntervalMonthDayNano, tz: Tz) -> Option<i64>;
    372
    373
        fn sub_year_month(timestamp: i64, delta: i32, tz: Tz) -> Option<i64>;
    374
        fn sub_day_time(timestamp: i64, delta: IntervalDayTime, tz: Tz) -> Option<i64>;
    375
        fn sub_month_day_nano(timestamp: i64, delta: IntervalMonthDayNano, tz: Tz) -> Option<i64>;
    376
    }
    377
    378
    macro_rules! timestamp {
    379
        ($t:ty, $d:ty) => {
    380
            impl TimestampOp for $t {
    381
                type Duration = $d;
    382
    383
    0
                fn add_year_month(left: i64, right: i32, tz: Tz) -> Option<i64> {
    384
    0
                    Self::add_year_months(left, right, tz)
    385
    0
                }
    386
    387
    0
                fn add_day_time(left: i64, right: IntervalDayTime, tz: Tz) -> Option<i64> {
    388
    0
                    Self::add_day_time(left, right, tz)
    389
    0
                }
    390
    391
    0
                fn add_month_day_nano(left: i64, right: IntervalMonthDayNano, tz: Tz) -> Option<i64> {
    392
    0
                    Self::add_month_day_nano(left, right, tz)
    393
    0
                }
    394
    395
    0
                fn sub_year_month(left: i64, right: i32, tz: Tz) -> Option<i64> {
    396
    0
                    Self::subtract_year_months(left, right, tz)
    397
    0
                }
    398
    399
    0
                fn sub_day_time(left: i64, right: IntervalDayTime, tz: Tz) -> Option<i64> {
    400
    0
                    Self::subtract_day_time(left, right, tz)
    401
    0
                }
    402
    403
    0
                fn sub_month_day_nano(left: i64, right: IntervalMonthDayNano, tz: Tz) -> Option<i64> {
    404
    0
                    Self::subtract_month_day_nano(left, right, tz)
    405
    0
                }
    406
            }
    407
        };
    408
    }
    409
    timestamp!(TimestampSecondType, DurationSecondType);
    410
    timestamp!(TimestampMillisecondType, DurationMillisecondType);
    411
    timestamp!(TimestampMicrosecondType, DurationMicrosecondType);
    412
    timestamp!(TimestampNanosecondType, DurationNanosecondType);
    413
    414
    /// Perform arithmetic operation on a timestamp array
    415
    0
    fn timestamp_op<T: TimestampOp>(
    416
    0
        op: Op,
    417
    0
        l: &dyn Array,
    418
    0
        l_s: bool,
    419
    0
        r: &dyn Array,
    420
    0
        r_s: bool,
    421
    0
    ) -> Result<ArrayRef, ArrowError> {
    422
        use DataType::*;
    423
        use IntervalUnit::*;
    424
    425
    0
        let l = l.as_primitive::<T>();
    426
    0
        let l_tz: Tz = l.timezone().unwrap_or("+00:00").parse()?;
    427
    428
    0
        let array: PrimitiveArray<T> = match (op, r.data_type()) {
    429
    0
            (Op::Sub | Op::SubWrapping, Timestamp(unit, _)) if unit == &T::UNIT => {
    430
    0
                let r = r.as_primitive::<T>();
    431
    0
                return Ok(try_op_ref!(T::Duration, l, l_s, r, r_s, l.sub_checked(r)));
    432
            }
    433
    434
    0
            (Op::Add | Op::AddWrapping, Duration(unit)) if unit == &T::UNIT => {
    435
    0
                let r = r.as_primitive::<T::Duration>();
    436
    0
                try_op!(l, l_s, r, r_s, l.add_checked(r))
    437
            }
    438
    0
            (Op::Sub | Op::SubWrapping, Duration(unit)) if unit == &T::UNIT => {
    439
    0
                let r = r.as_primitive::<T::Duration>();
    440
    0
                try_op!(l, l_s, r, r_s, l.sub_checked(r))
    441
            }
    442
    443
            (Op::Add | Op::AddWrapping, Interval(YearMonth)) => {
    444
    0
                let r = r.as_primitive::<IntervalYearMonthType>();
    445
    0
                try_op!(
    446
                    l,
    447
    0
                    l_s,
    448
                    r,
    449
    0
                    r_s,
    450
    0
                    T::add_year_month(l, r, l_tz).ok_or(ArrowError::ComputeError(
    451
    0
                        "Timestamp out of range".to_string()
    452
    0
                    ))
    453
                )
    454
            }
    455
            (Op::Sub | Op::SubWrapping, Interval(YearMonth)) => {
    456
    0
                let r = r.as_primitive::<IntervalYearMonthType>();
    457
    0
                try_op!(
    458
                    l,
    459
    0
                    l_s,
    460
                    r,
    461
    0
                    r_s,
    462
    0
                    T::sub_year_month(l, r, l_tz).ok_or(ArrowError::ComputeError(
    463
    0
                        "Timestamp out of range".to_string()
    464
    0
                    ))
    465
                )
    466
            }
    467
    468
            (Op::Add | Op::AddWrapping, Interval(DayTime)) => {
    469
    0
                let r = r.as_primitive::<IntervalDayTimeType>();
    470
    0
                try_op!(
    471
                    l,
    472
    0
                    l_s,
    473
                    r,
    474
    0
                    r_s,
    475
    0
                    T::add_day_time(l, r, l_tz).ok_or(ArrowError::ComputeError(
    476
    0
                        "Timestamp out of range".to_string()
    477
    0
                    ))
    478
                )
    479
            }
    480
            (Op::Sub | Op::SubWrapping, Interval(DayTime)) => {
    481
    0
                let r = r.as_primitive::<IntervalDayTimeType>();
    482
    0
                try_op!(
    483
                    l,
    484
    0
                    l_s,
    485
                    r,
    486
    0
                    r_s,
    487
    0
                    T::sub_day_time(l, r, l_tz).ok_or(ArrowError::ComputeError(
    488
    0
                        "Timestamp out of range".to_string()
    489
    0
                    ))
    490
                )
    491
            }
    492
    493
            (Op::Add | Op::AddWrapping, Interval(MonthDayNano)) => {
    494
    0
                let r = r.as_primitive::<IntervalMonthDayNanoType>();
    495
    0
                try_op!(
    496
                    l,
    497
    0
                    l_s,
    498
                    r,
    499
    0
                    r_s,
    500
    0
                    T::add_month_day_nano(l, r, l_tz).ok_or(ArrowError::ComputeError(
    501
    0
                        "Timestamp out of range".to_string()
    502
    0
                    ))
    503
                )
    504
            }
    505
            (Op::Sub | Op::SubWrapping, Interval(MonthDayNano)) => {
    506
    0
                let r = r.as_primitive::<IntervalMonthDayNanoType>();
    507
    0
                try_op!(
    508
                    l,
    509
    0
                    l_s,
    510
                    r,
    511
    0
                    r_s,
    512
    0
                    T::sub_month_day_nano(l, r, l_tz).ok_or(ArrowError::ComputeError(
    513
    0
                        "Timestamp out of range".to_string()
    514
    0
                    ))
    515
                )
    516
            }
    517
            _ => {
    518
    0
                return Err(ArrowError::InvalidArgumentError(format!(
    519
    0
                    "Invalid timestamp arithmetic operation: {} {op} {}",
    520
    0
                    l.data_type(),
    521
    0
                    r.data_type()
    522
    0
                )))
    523
            }
    524
        };
    525
    0
        Ok(Arc::new(array.with_timezone_opt(l.timezone())))
    526
    0
    }
    527
    528
    /// Arithmetic trait for date arrays
    529
    trait DateOp: ArrowTemporalType {
    530
        fn add_year_month(timestamp: Self::Native, delta: i32) -> Result<Self::Native, ArrowError>;
    531
        fn add_day_time(
    532
            timestamp: Self::Native,
    533
            delta: IntervalDayTime,
    534
        ) -> Result<Self::Native, ArrowError>;
    535
        fn add_month_day_nano(
    536
            timestamp: Self::Native,
    537
            delta: IntervalMonthDayNano,
    538
        ) -> Result<Self::Native, ArrowError>;
    539
    540
        fn sub_year_month(timestamp: Self::Native, delta: i32) -> Result<Self::Native, ArrowError>;
    541
        fn sub_day_time(
    542
            timestamp: Self::Native,
    543
            delta: IntervalDayTime,
    544
        ) -> Result<Self::Native, ArrowError>;
    545
        fn sub_month_day_nano(
    546
            timestamp: Self::Native,
    547
            delta: IntervalMonthDayNano,
    548
        ) -> Result<Self::Native, ArrowError>;
    549
    }
    550
    551
    impl DateOp for Date32Type {
    552
    0
        fn add_year_month(left: Self::Native, right: i32) -> Result<Self::Native, ArrowError> {
    553
            // Date32Type functions don't have _opt variants and should be safe
    554
    0
            Ok(Self::add_year_months(left, right))
    555
    0
        }
    556
    557
    0
        fn add_day_time(
    558
    0
            left: Self::Native,
    559
    0
            right: IntervalDayTime,
    560
    0
        ) -> Result<Self::Native, ArrowError> {
    561
    0
            Ok(Self::add_day_time(left, right))
    562
    0
        }
    563
    564
    0
        fn add_month_day_nano(
    565
    0
            left: Self::Native,
    566
    0
            right: IntervalMonthDayNano,
    567
    0
        ) -> Result<Self::Native, ArrowError> {
    568
    0
            Ok(Self::add_month_day_nano(left, right))
    569
    0
        }
    570
    571
    0
        fn sub_year_month(left: Self::Native, right: i32) -> Result<Self::Native, ArrowError> {
    572
    0
            Ok(Self::subtract_year_months(left, right))
    573
    0
        }
    574
    575
    0
        fn sub_day_time(
    576
    0
            left: Self::Native,
    577
    0
            right: IntervalDayTime,
    578
    0
        ) -> Result<Self::Native, ArrowError> {
    579
    0
            Ok(Self::subtract_day_time(left, right))
    580
    0
        }
    581
    582
    0
        fn sub_month_day_nano(
    583
    0
            left: Self::Native,
    584
    0
            right: IntervalMonthDayNano,
    585
    0
        ) -> Result<Self::Native, ArrowError> {
    586
    0
            Ok(Self::subtract_month_day_nano(left, right))
    587
    0
        }
    588
    }
    589
    590
    impl DateOp for Date64Type {
    591
    0
        fn add_year_month(left: Self::Native, right: i32) -> Result<Self::Native, ArrowError> {
    592
    0
            Self::add_year_months_opt(left, right).ok_or_else(|| {
    593
    0
                ArrowError::ComputeError(format!("Date arithmetic overflow: {left} + {right} months",))
    594
    0
            })
    595
    0
        }
    596
    597
    0
        fn add_day_time(
    598
    0
            left: Self::Native,
    599
    0
            right: IntervalDayTime,
    600
    0
        ) -> Result<Self::Native, ArrowError> {
    601
    0
            Self::add_day_time_opt(left, right).ok_or_else(|| {
    602
    0
                ArrowError::ComputeError(format!("Date arithmetic overflow: {left} + {right:?}"))
    603
    0
            })
    604
    0
        }
    605
    606
    0
        fn add_month_day_nano(
    607
    0
            left: Self::Native,
    608
    0
            right: IntervalMonthDayNano,
    609
    0
        ) -> Result<Self::Native, ArrowError> {
    610
    0
            Self::add_month_day_nano_opt(left, right).ok_or_else(|| {
    611
    0
                ArrowError::ComputeError(format!("Date arithmetic overflow: {left} + {right:?}"))
    612
    0
            })
    613
    0
        }
    614
    615
    0
        fn sub_year_month(left: Self::Native, right: i32) -> Result<Self::Native, ArrowError> {
    616
    0
            Self::subtract_year_months_opt(left, right).ok_or_else(|| {
    617
    0
                ArrowError::ComputeError(format!("Date arithmetic overflow: {left} - {right} months",))
    618
    0
            })
    619
    0
        }
    620
    621
    0
        fn sub_day_time(
    622
    0
            left: Self::Native,
    623
    0
            right: IntervalDayTime,
    624
    0
        ) -> Result<Self::Native, ArrowError> {
    625
    0
            Self::subtract_day_time_opt(left, right).ok_or_else(|| {
    626
    0
                ArrowError::ComputeError(format!("Date arithmetic overflow: {left} - {right:?}"))
    627
    0
            })
    628
    0
        }
    629
    630
    0
        fn sub_month_day_nano(
    631
    0
            left: Self::Native,
    632
    0
            right: IntervalMonthDayNano,
    633
    0
        ) -> Result<Self::Native, ArrowError> {
    634
    0
            Self::subtract_month_day_nano_opt(left, right).ok_or_else(|| {
    635
    0
                ArrowError::ComputeError(format!("Date arithmetic overflow: {left} - {right:?}"))
    636
    0
            })
    637
    0
        }
    638
    }
    639
    640
    /// Arithmetic trait for interval arrays
    641
    trait IntervalOp: ArrowPrimitiveType {
    642
        fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError>;
    643
        fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError>;
    644
    }
    645
    646
    impl IntervalOp for IntervalYearMonthType {
    647
    0
        fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
    648
    0
            left.add_checked(right)
    649
    0
        }
    650
    651
    0
        fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
    652
    0
            left.sub_checked(right)
    653
    0
        }
    654
    }
    655
    656
    impl IntervalOp for IntervalDayTimeType {
    657
    0
        fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
    658
    0
            let (l_days, l_ms) = Self::to_parts(left);
    659
    0
            let (r_days, r_ms) = Self::to_parts(right);
    660
    0
            let days = l_days.add_checked(r_days)?;
    661
    0
            let ms = l_ms.add_checked(r_ms)?;
    662
    0
            Ok(Self::make_value(days, ms))
    663
    0
        }
    664
    665
    0
        fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
    666
    0
            let (l_days, l_ms) = Self::to_parts(left);
    667
    0
            let (r_days, r_ms) = Self::to_parts(right);
    668
    0
            let days = l_days.sub_checked(r_days)?;
    669
    0
            let ms = l_ms.sub_checked(r_ms)?;
    670
    0
            Ok(Self::make_value(days, ms))
    671
    0
        }
    672
    }
    673
    674
    impl IntervalOp for IntervalMonthDayNanoType {
    675
    0
        fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
    676
    0
            let (l_months, l_days, l_nanos) = Self::to_parts(left);
    677
    0
            let (r_months, r_days, r_nanos) = Self::to_parts(right);
    678
    0
            let months = l_months.add_checked(r_months)?;
    679
    0
            let days = l_days.add_checked(r_days)?;
    680
    0
            let nanos = l_nanos.add_checked(r_nanos)?;
    681
    0
            Ok(Self::make_value(months, days, nanos))
    682
    0
        }
    683
    684
    0
        fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
    685
    0
            let (l_months, l_days, l_nanos) = Self::to_parts(left);
    686
    0
            let (r_months, r_days, r_nanos) = Self::to_parts(right);
    687
    0
            let months = l_months.sub_checked(r_months)?;
    688
    0
            let days = l_days.sub_checked(r_days)?;
    689
    0
            let nanos = l_nanos.sub_checked(r_nanos)?;
    690
    0
            Ok(Self::make_value(months, days, nanos))
    691
    0
        }
    692
    }
    693
    694
    /// Perform arithmetic operation on an interval array
    695
    0
    fn interval_op<T: IntervalOp>(
    696
    0
        op: Op,
    697
    0
        l: &dyn Array,
    698
    0
        l_s: bool,
    699
    0
        r: &dyn Array,
    700
    0
        r_s: bool,
    701
    0
    ) -> Result<ArrayRef, ArrowError> {
    702
    0
        let l = l.as_primitive::<T>();
    703
    0
        let r = r.as_primitive::<T>();
    704
    0
        match op {
    705
    0
            Op::Add | Op::AddWrapping => Ok(try_op_ref!(T, l, l_s, r, r_s, T::add(l, r))),
    706
    0
            Op::Sub | Op::SubWrapping => Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub(l, r))),
    707
    0
            _ => Err(ArrowError::InvalidArgumentError(format!(
    708
    0
                "Invalid interval arithmetic operation: {} {op} {}",
    709
    0
                l.data_type(),
    710
    0
                r.data_type()
    711
    0
            ))),
    712
        }
    713
    0
    }
    714
    715
    0
    fn duration_op<T: ArrowPrimitiveType>(
    716
    0
        op: Op,
    717
    0
        l: &dyn Array,
    718
    0
        l_s: bool,
    719
    0
        r: &dyn Array,
    720
    0
        r_s: bool,
    721
    0
    ) -> Result<ArrayRef, ArrowError> {
    722
    0
        let l = l.as_primitive::<T>();
    723
    0
        let r = r.as_primitive::<T>();
    724
    0
        match op {
    725
    0
            Op::Add | Op::AddWrapping => Ok(try_op_ref!(T, l, l_s, r, r_s, l.add_checked(r))),
    726
    0
            Op::Sub | Op::SubWrapping => Ok(try_op_ref!(T, l, l_s, r, r_s, l.sub_checked(r))),
    727
    0
            _ => Err(ArrowError::InvalidArgumentError(format!(
    728
    0
                "Invalid duration arithmetic operation: {} {op} {}",
    729
    0
                l.data_type(),
    730
    0
                r.data_type()
    731
    0
            ))),
    732
        }
    733
    0
    }
    734
    735
    /// Perform arithmetic operation on a date array
    736
    0
    fn date_op<T: DateOp>(
    737
    0
        op: Op,
    738
    0
        l: &dyn Array,
    739
    0
        l_s: bool,
    740
    0
        r: &dyn Array,
    741
    0
        r_s: bool,
    742
    0
    ) -> Result<ArrayRef, ArrowError> {
    743
        use DataType::*;
    744
        use IntervalUnit::*;
    745
    746
        const NUM_SECONDS_IN_DAY: i64 = 60 * 60 * 24;
    747
    748
    0
        let r_t = r.data_type();
    749
    0
        match (T::DATA_TYPE, op, r_t) {
    750
            (Date32, Op::Sub | Op::SubWrapping, Date32) => {
    751
    0
                let l = l.as_primitive::<Date32Type>();
    752
    0
                let r = r.as_primitive::<Date32Type>();
    753
    0
                return Ok(op_ref!(
    754
                    DurationSecondType,
    755
                    l,
    756
    0
                    l_s,
    757
                    r,
    758
    0
                    r_s,
    759
    0
                    ((l as i64) - (r as i64)) * NUM_SECONDS_IN_DAY
    760
                ));
    761
            }
    762
            (Date64, Op::Sub | Op::SubWrapping, Date64) => {
    763
    0
                let l = l.as_primitive::<Date64Type>();
    764
    0
                let r = r.as_primitive::<Date64Type>();
    765
    0
                let result = try_op_ref!(DurationMillisecondType, l, l_s, r, r_s, l.sub_checked(r));
    766
    0
                return Ok(result);
    767
            }
    768
    0
            _ => {}
    769
        }
    770
    771
    0
        let l = l.as_primitive::<T>();
    772
    0
        match (op, r_t) {
    773
            (Op::Add | Op::AddWrapping, Interval(YearMonth)) => {
    774
    0
                let r = r.as_primitive::<IntervalYearMonthType>();
    775
    0
                Ok(try_op_ref!(T, l, l_s, r, r_s, T::add_year_month(l, r)))
    776
            }
    777
            (Op::Sub | Op::SubWrapping, Interval(YearMonth)) => {
    778
    0
                let r = r.as_primitive::<IntervalYearMonthType>();
    779
    0
                Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub_year_month(l, r)))
    780
            }
    781
    782
            (Op::Add | Op::AddWrapping, Interval(DayTime)) => {
    783
    0
                let r = r.as_primitive::<IntervalDayTimeType>();
    784
    0
                Ok(try_op_ref!(T, l, l_s, r, r_s, T::add_day_time(l, r)))
    785
            }
    786
            (Op::Sub | Op::SubWrapping, Interval(DayTime)) => {
    787
    0
                let r = r.as_primitive::<IntervalDayTimeType>();
    788
    0
                Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub_day_time(l, r)))
    789
            }
    790
    791
            (Op::Add | Op::AddWrapping, Interval(MonthDayNano)) => {
    792
    0
                let r = r.as_primitive::<IntervalMonthDayNanoType>();
    793
    0
                Ok(try_op_ref!(T, l, l_s, r, r_s, T::add_month_day_nano(l, r)))
    794
            }
    795
            (Op::Sub | Op::SubWrapping, Interval(MonthDayNano)) => {
    796
    0
                let r = r.as_primitive::<IntervalMonthDayNanoType>();
    797
    0
                Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub_month_day_nano(l, r)))
    798
            }
    799
    800
    0
            _ => Err(ArrowError::InvalidArgumentError(format!(
    801
    0
                "Invalid date arithmetic operation: {} {op} {}",
    802
    0
                l.data_type(),
    803
    0
                r.data_type()
    804
    0
            ))),
    805
        }
    806
    0
    }
    807
    808
    /// Perform arithmetic operation on decimal arrays
    809
    0
    fn decimal_op<T: DecimalType>(
    810
    0
        op: Op,
    811
    0
        l: &dyn Array,
    812
    0
        l_s: bool,
    813
    0
        r: &dyn Array,
    814
    0
        r_s: bool,
    815
    0
    ) -> Result<ArrayRef, ArrowError> {
    816
    0
        let l = l.as_primitive::<T>();
    817
    0
        let r = r.as_primitive::<T>();
    818
    819
    0
        let (p1, s1, p2, s2) = match (l.data_type(), r.data_type()) {
    820
    0
            (DataType::Decimal32(p1, s1), DataType::Decimal32(p2, s2)) => (p1, s1, p2, s2),
    821
    0
            (DataType::Decimal64(p1, s1), DataType::Decimal64(p2, s2)) => (p1, s1, p2, s2),
    822
    0
            (DataType::Decimal128(p1, s1), DataType::Decimal128(p2, s2)) => (p1, s1, p2, s2),
    823
    0
            (DataType::Decimal256(p1, s1), DataType::Decimal256(p2, s2)) => (p1, s1, p2, s2),
    824
    0
            _ => unreachable!(),
    825
        };
    826
    827
        // Follow the Hive decimal arithmetic rules
    828
        // https://cwiki.apache.org/confluence/download/attachments/27362075/Hive_Decimal_Precision_Scale_Support.pdf
    829
    0
        let array: PrimitiveArray<T> = match op {
    830
            Op::Add | Op::AddWrapping | Op::Sub | Op::SubWrapping => {
    831
                // max(s1, s2)
    832
    0
                let result_scale = *s1.max(s2);
    833
    834
                // max(s1, s2) + max(p1-s1, p2-s2) + 1
    835
    0
                let result_precision =
    836
    0
                    (result_scale.saturating_add((*p1 as i8 - s1).max(*p2 as i8 - s2)) as u8)
    837
    0
                        .saturating_add(1)
    838
    0
                        .min(T::MAX_PRECISION);
    839
    840
    0
                let l_mul = T::Native::usize_as(10).pow_checked((result_scale - s1) as _)?;
    841
    0
                let r_mul = T::Native::usize_as(10).pow_checked((result_scale - s2) as _)?;
    842
    843
    0
                match op {
    844
                    Op::Add | Op::AddWrapping => {
    845
    0
                        try_op!(
    846
                            l,
    847
    0
                            l_s,
    848
                            r,
    849
    0
                            r_s,
    850
    0
                            l.mul_checked(l_mul)?.add_checked(r.mul_checked(r_mul)?)
    851
                        )
    852
                    }
    853
                    Op::Sub | Op::SubWrapping => {
    854
    0
                        try_op!(
    855
                            l,
    856
    0
                            l_s,
    857
                            r,
    858
    0
                            r_s,
    859
    0
                            l.mul_checked(l_mul)?.sub_checked(r.mul_checked(r_mul)?)
    860
                        )
    861
                    }
    862
    0
                    _ => unreachable!(),
    863
                }
    864
    0
                .with_precision_and_scale(result_precision, result_scale)?
    865
            }
    866
            Op::Mul | Op::MulWrapping => {
    867
    0
                let result_precision = p1.saturating_add(p2 + 1).min(T::MAX_PRECISION);
    868
    0
                let result_scale = s1.saturating_add(*s2);
    869
    0
                if result_scale > T::MAX_SCALE {
    870
                    // SQL standard says that if the resulting scale of a multiply operation goes
    871
                    // beyond the maximum, rounding is not acceptable and thus an error occurs
    872
    0
                    return Err(ArrowError::InvalidArgumentError(format!(
    873
    0
                        "Output scale of {} {op} {} would exceed max scale of {}",
    874
    0
                        l.data_type(),
    875
    0
                        r.data_type(),
    876
    0
                        T::MAX_SCALE
    877
    0
                    )));
    878
    0
                }
    879
    880
    0
                try_op!(l, l_s, r, r_s, l.mul_checked(r))
    881
    0
                    .with_precision_and_scale(result_precision, result_scale)?
    882
            }
    883
    884
            Op::Div => {
    885
                // Follow postgres and MySQL adding a fixed scale increment of 4
    886
                // s1 + 4
    887
    0
                let result_scale = s1.saturating_add(4).min(T::MAX_SCALE);
    888
    0
                let mul_pow = result_scale - s1 + s2;
    889
    890
                // p1 - s1 + s2 + result_scale
    891
    0
                let result_precision = (mul_pow.saturating_add(*p1 as i8) as u8).min(T::MAX_PRECISION);
    892
    893
    0
                let (l_mul, r_mul) = match mul_pow.cmp(&0) {
    894
                    Ordering::Greater => (
    895
    0
                        T::Native::usize_as(10).pow_checked(mul_pow as _)?,
    896
                        T::Native::ONE,
    897
                    ),
    898
    0
                    Ordering::Equal => (T::Native::ONE, T::Native::ONE),
    899
                    Ordering::Less => (
    900
                        T::Native::ONE,
    901
    0
                        T::Native::usize_as(10).pow_checked(mul_pow.neg_wrapping() as _)?,
    902
                    ),
    903
                };
    904
    905
    0
                try_op!(
    906
                    l,
    907
    0
                    l_s,
    908
                    r,
    909
    0
                    r_s,
    910
    0
                    l.mul_checked(l_mul)?.div_checked(r.mul_checked(r_mul)?)
    911
                )
    912
    0
                .with_precision_and_scale(result_precision, result_scale)?
    913
            }
    914
    915
            Op::Rem => {
    916
                // max(s1, s2)
    917
    0
                let result_scale = *s1.max(s2);
    918
                // min(p1-s1, p2 -s2) + max( s1,s2 )
    919
    0
                let result_precision =
    920
    0
                    (result_scale.saturating_add((*p1 as i8 - s1).min(*p2 as i8 - s2)) as u8)
    921
    0
                        .min(T::MAX_PRECISION);
    922
    923
    0
                let l_mul = T::Native::usize_as(10).pow_wrapping((result_scale - s1) as _);
    924
    0
                let r_mul = T::Native::usize_as(10).pow_wrapping((result_scale - s2) as _);
    925
    926
    0
                try_op!(
    927
                    l,
    928
    0
                    l_s,
    929
                    r,
    930
    0
                    r_s,
    931
    0
                    l.mul_checked(l_mul)?.mod_checked(r.mul_checked(r_mul)?)
    932
                )
    933
    0
                .with_precision_and_scale(result_precision, result_scale)?
    934
            }
    935
        };
    936
    937
    0
        Ok(Arc::new(array))
    938
    0
    }
    939
    940
    #[cfg(test)]
    941
    mod tests {
    942
        use super::*;
    943
        use arrow_array::temporal_conversions::{as_date, as_datetime};
    944
        use arrow_buffer::{i256, ScalarBuffer};
    945
        use chrono::{DateTime, NaiveDate};
    946
    947
        fn test_neg_primitive<T: ArrowPrimitiveType>(
    948
            input: &[T::Native],
    949
            out: Result<&[T::Native], &str>,
    950
        ) {
    951
            let a = PrimitiveArray::<T>::new(ScalarBuffer::from(input.to_vec()), None);
    952
            match out {
    953
                Ok(expected) => {
    954
                    let result = neg(&a).unwrap();
    955
                    assert_eq!(result.as_primitive::<T>().values(), expected);
    956
                }
    957
                Err(e) => {
    958
                    let err = neg(&a).unwrap_err().to_string();
    959
                    assert_eq!(e, err);
    960
                }
    961
            }
    962
        }
    963
    964
        #[test]
    965
        fn test_neg() {
    966
            let input = &[1, -5, 2, 693, 3929];
    967
            let output = &[-1, 5, -2, -693, -3929];
    968
            test_neg_primitive::<Int32Type>(input, Ok(output));
    969
    970
            let input = &[1, -5, 2, 693, 3929];
    971
            let output = &[-1, 5, -2, -693, -3929];
    972
            test_neg_primitive::<Int64Type>(input, Ok(output));
    973
            test_neg_primitive::<DurationSecondType>(input, Ok(output));
    974
            test_neg_primitive::<DurationMillisecondType>(input, Ok(output));
    975
            test_neg_primitive::<DurationMicrosecondType>(input, Ok(output));
    976
            test_neg_primitive::<DurationNanosecondType>(input, Ok(output));
    977
    978
            let input = &[f32::MAX, f32::MIN, f32::INFINITY, 1.3, 0.5];
    979
            let output = &[f32::MIN, f32::MAX, f32::NEG_INFINITY, -1.3, -0.5];
    980
            test_neg_primitive::<Float32Type>(input, Ok(output));
    981
    982
            test_neg_primitive::<Int32Type>(
    983
                &[i32::MIN],
    984
                Err("Arithmetic overflow: Overflow happened on: - -2147483648"),
    985
            );
    986
            test_neg_primitive::<Int64Type>(
    987
                &[i64::MIN],
    988
                Err("Arithmetic overflow: Overflow happened on: - -9223372036854775808"),
    989
            );
    990
            test_neg_primitive::<DurationSecondType>(
    991
                &[i64::MIN],
    992
                Err("Arithmetic overflow: Overflow happened on: - -9223372036854775808"),
    993
            );
    994
    995
            let r = neg_wrapping(&Int32Array::from(vec![i32::MIN])).unwrap();
    996
            assert_eq!(r.as_primitive::<Int32Type>().value(0), i32::MIN);
    997
    998
            let r = neg_wrapping(&Int64Array::from(vec![i64::MIN])).unwrap();
    999
            assert_eq!(r.as_primitive::<Int64Type>().value(0), i64::MIN);
    1000
    1001
            let err = neg_wrapping(&DurationSecondArray::from(vec![i64::MIN]))
    1002
                .unwrap_err()
    1003
                .to_string();
    1004
    1005
            assert_eq!(
    1006
                err,
    1007
                "Arithmetic overflow: Overflow happened on: - -9223372036854775808"
    1008
            );
    1009
    1010
            let a = Decimal32Array::from(vec![1, 3, -44, 2, 4])
    1011
                .with_precision_and_scale(9, 6)
    1012
                .unwrap();
    1013
    1014
            let r = neg(&a).unwrap();
    1015
            assert_eq!(r.data_type(), a.data_type());
    1016
            assert_eq!(
    1017
                r.as_primitive::<Decimal32Type>().values(),
    1018
                &[-1, -3, 44, -2, -4]
    1019
            );
    1020
    1021
            let a = Decimal64Array::from(vec![1, 3, -44, 2, 4])
    1022
                .with_precision_and_scale(9, 6)
    1023
                .unwrap();
    1024
    1025
            let r = neg(&a).unwrap();
    1026
            assert_eq!(r.data_type(), a.data_type());
    1027
            assert_eq!(
    1028
                r.as_primitive::<Decimal64Type>().values(),
    1029
                &[-1, -3, 44, -2, -4]
    1030
            );
    1031
    1032
            let a = Decimal128Array::from(vec![1, 3, -44, 2, 4])
    1033
                .with_precision_and_scale(9, 6)
    1034
                .unwrap();
    1035
    1036
            let r = neg(&a).unwrap();
    1037
            assert_eq!(r.data_type(), a.data_type());
    1038
            assert_eq!(
    1039
                r.as_primitive::<Decimal128Type>().values(),
    1040
                &[-1, -3, 44, -2, -4]
    1041
            );
    1042
    1043
            let a = Decimal256Array::from(vec![
    1044
                i256::from_i128(342),
    1045
                i256::from_i128(-4949),
    1046
                i256::from_i128(3),
    1047
            ])
    1048
            .with_precision_and_scale(9, 6)
    1049
            .unwrap();
    1050
    1051
            let r = neg(&a).unwrap();
    1052
            assert_eq!(r.data_type(), a.data_type());
    1053
            assert_eq!(
    1054
                r.as_primitive::<Decimal256Type>().values(),
    1055
                &[
    1056
                    i256::from_i128(-342),
    1057
                    i256::from_i128(4949),
    1058
                    i256::from_i128(-3),
    1059
                ]
    1060
            );
    1061
    1062
            let a = IntervalYearMonthArray::from(vec![
    1063
                IntervalYearMonthType::make_value(2, 4),
    1064
                IntervalYearMonthType::make_value(2, -4),
    1065
                IntervalYearMonthType::make_value(-3, -5),
    1066
            ]);
    1067
            let r = neg(&a).unwrap();
    1068
            assert_eq!(
    1069
                r.as_primitive::<IntervalYearMonthType>().values(),
    1070
                &[
    1071
                    IntervalYearMonthType::make_value(-2, -4),
    1072
                    IntervalYearMonthType::make_value(-2, 4),
    1073
                    IntervalYearMonthType::make_value(3, 5),
    1074
                ]
    1075
            );
    1076
    1077
            let a = IntervalDayTimeArray::from(vec![
    1078
                IntervalDayTimeType::make_value(2, 4),
    1079
                IntervalDayTimeType::make_value(2, -4),
    1080
                IntervalDayTimeType::make_value(-3, -5),
    1081
            ]);
    1082
            let r = neg(&a).unwrap();
    1083
            assert_eq!(
    1084
                r.as_primitive::<IntervalDayTimeType>().values(),
    1085
                &[
    1086
                    IntervalDayTimeType::make_value(-2, -4),
    1087
                    IntervalDayTimeType::make_value(-2, 4),
    1088
                    IntervalDayTimeType::make_value(3, 5),
    1089
                ]
    1090
            );
    1091
    1092
            let a = IntervalMonthDayNanoArray::from(vec![
    1093
                IntervalMonthDayNanoType::make_value(2, 4, 5953394),
    1094
                IntervalMonthDayNanoType::make_value(2, -4, -45839),
    1095
                IntervalMonthDayNanoType::make_value(-3, -5, 6944),
    1096
            ]);
    1097
            let r = neg(&a).unwrap();
    1098
            assert_eq!(
    1099
                r.as_primitive::<IntervalMonthDayNanoType>().values(),
    1100
                &[
    1101
                    IntervalMonthDayNanoType::make_value(-2, -4, -5953394),
    1102
                    IntervalMonthDayNanoType::make_value(-2, 4, 45839),
    1103
                    IntervalMonthDayNanoType::make_value(3, 5, -6944),
    1104
                ]
    1105
            );
    1106
        }
    1107
    1108
        #[test]
    1109
        fn test_integer() {
    1110
            let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
    1111
            let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
    1112
            let result = add(&a, &b).unwrap();
    1113
            assert_eq!(
    1114
                result.as_ref(),
    1115
                &Int32Array::from(vec![10, 5, 10, -13, 103])
    1116
            );
    1117
            let result = sub(&a, &b).unwrap();
    1118
            assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
    1119
            let result = div(&a, &b).unwrap();
    1120
            assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
    1121
            let result = mul(&a, &b).unwrap();
    1122
            assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 300]));
    1123
            let result = rem(&a, &b).unwrap();
    1124
            assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
    1125
    1126
            let a = Int8Array::from(vec![Some(2), None, Some(45)]);
    1127
            let b = Int8Array::from(vec![Some(5), Some(3), None]);
    1128
            let result = add(&a, &b).unwrap();
    1129
            assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, None]));
    1130
    1131
            let a = UInt8Array::from(vec![56, 5, 3]);
    1132
            let b = UInt8Array::from(vec![200, 2, 5]);
    1133
            let err = add(&a, &b).unwrap_err().to_string();
    1134
            assert_eq!(err, "Arithmetic overflow: Overflow happened on: 56 + 200");
    1135
            let result = add_wrapping(&a, &b).unwrap();
    1136
            assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
    1137
    1138
            let a = UInt8Array::from(vec![34, 5, 3]);
    1139
            let b = UInt8Array::from(vec![200, 2, 5]);
    1140
            let err = sub(&a, &b).unwrap_err().to_string();
    1141
            assert_eq!(err, "Arithmetic overflow: Overflow happened on: 34 - 200");
    1142
            let result = sub_wrapping(&a, &b).unwrap();
    1143
            assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
    1144
    1145
            let a = UInt8Array::from(vec![34, 5, 3]);
    1146
            let b = UInt8Array::from(vec![200, 2, 5]);
    1147
            let err = mul(&a, &b).unwrap_err().to_string();
    1148
            assert_eq!(err, "Arithmetic overflow: Overflow happened on: 34 * 200");
    1149
            let result = mul_wrapping(&a, &b).unwrap();
    1150
            assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
    1151
    1152
            let a = Int16Array::from(vec![i16::MIN]);
    1153
            let b = Int16Array::from(vec![-1]);
    1154
            let err = div(&a, &b).unwrap_err().to_string();
    1155
            assert_eq!(
    1156
                err,
    1157
                "Arithmetic overflow: Overflow happened on: -32768 / -1"
    1158
            );
    1159
    1160
            let a = Int16Array::from(vec![i16::MIN]);
    1161
            let b = Int16Array::from(vec![-1]);
    1162
            let result = rem(&a, &b).unwrap();
    1163
            assert_eq!(result.as_ref(), &Int16Array::from(vec![0]));
    1164
    1165
            let a = Int16Array::from(vec![21]);
    1166
            let b = Int16Array::from(vec![0]);
    1167
            let err = div(&a, &b).unwrap_err().to_string();
    1168
            assert_eq!(err, "Divide by zero error");
    1169
    1170
            let a = Int16Array::from(vec![21]);
    1171
            let b = Int16Array::from(vec![0]);
    1172
            let err = rem(&a, &b).unwrap_err().to_string();
    1173
            assert_eq!(err, "Divide by zero error");
    1174
        }
    1175
    1176
        #[test]
    1177
        fn test_float() {
    1178
            let a = Float32Array::from(vec![1., f32::MAX, 6., -4., -1., 0.]);
    1179
            let b = Float32Array::from(vec![1., f32::MAX, f32::MAX, -3., 45., 0.]);
    1180
            let result = add(&a, &b).unwrap();
    1181
            assert_eq!(
    1182
                result.as_ref(),
    1183
                &Float32Array::from(vec![2., f32::INFINITY, f32::MAX, -7., 44.0, 0.])
    1184
            );
    1185
    1186
            let result = sub(&a, &b).unwrap();
    1187
            assert_eq!(
    1188
                result.as_ref(),
    1189
                &Float32Array::from(vec![0., 0., f32::MIN, -1., -46., 0.])
    1190
            );
    1191
    1192
            let result = mul(&a, &b).unwrap();
    1193
            assert_eq!(
    1194
                result.as_ref(),
    1195
                &Float32Array::from(vec![1., f32::INFINITY, f32::INFINITY, 12., -45., 0.])
    1196
            );
    1197
    1198
            let result = div(&a, &b).unwrap();
    1199
            let r = result.as_primitive::<Float32Type>();
    1200
            assert_eq!(r.value(0), 1.);
    1201
            assert_eq!(r.value(1), 1.);
    1202
            assert!(r.value(2) < f32::EPSILON);
    1203
            assert_eq!(r.value(3), -4. / -3.);
    1204
            assert!(r.value(5).is_nan());
    1205
    1206
            let result = rem(&a, &b).unwrap();
    1207
            let r = result.as_primitive::<Float32Type>();
    1208
            assert_eq!(&r.values()[..5], &[0., 0., 6., -1., -1.]);
    1209
            assert!(r.value(5).is_nan());
    1210
        }
    1211
    1212
        #[test]
    1213
        fn test_decimal() {
    1214
            // 0.015 7.842 -0.577 0.334 -0.078 0.003
    1215
            let a = Decimal128Array::from(vec![15, 0, -577, 334, -78, 3])
    1216
                .with_precision_and_scale(12, 3)
    1217
                .unwrap();
    1218
    1219
            // 5.4 0 -35.6 0.3 0.6 7.45
    1220
            let b = Decimal128Array::from(vec![54, 34, -356, 3, 6, 745])
    1221
                .with_precision_and_scale(12, 1)
    1222
                .unwrap();
    1223
    1224
            let result = add(&a, &b).unwrap();
    1225
            assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
    1226
            assert_eq!(
    1227
                result.as_primitive::<Decimal128Type>().values(),
    1228
                &[5415, 3400, -36177, 634, 522, 74503]
    1229
            );
    1230
    1231
            let result = sub(&a, &b).unwrap();
    1232
            assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
    1233
            assert_eq!(
    1234
                result.as_primitive::<Decimal128Type>().values(),
    1235
                &[-5385, -3400, 35023, 34, -678, -74497]
    1236
            );
    1237
    1238
            let result = mul(&a, &b).unwrap();
    1239
            assert_eq!(result.data_type(), &DataType::Decimal128(25, 4));
    1240
            assert_eq!(
    1241
                result.as_primitive::<Decimal128Type>().values(),
    1242
                &[810, 0, 205412, 1002, -468, 2235]
    1243
            );
    1244
    1245
            let result = div(&a, &b).unwrap();
    1246
            assert_eq!(result.data_type(), &DataType::Decimal128(17, 7));
    1247
            assert_eq!(
    1248
                result.as_primitive::<Decimal128Type>().values(),
    1249
                &[27777, 0, 162078, 11133333, -1300000, 402]
    1250
            );
    1251
    1252
            let result = rem(&a, &b).unwrap();
    1253
            assert_eq!(result.data_type(), &DataType::Decimal128(12, 3));
    1254
            assert_eq!(
    1255
                result.as_primitive::<Decimal128Type>().values(),
    1256
                &[15, 0, -577, 34, -78, 3]
    1257
            );
    1258
    1259
            let a = Decimal128Array::from(vec![1])
    1260
                .with_precision_and_scale(3, 3)
    1261
                .unwrap();
    1262
            let b = Decimal128Array::from(vec![1])
    1263
                .with_precision_and_scale(37, 37)
    1264
                .unwrap();
    1265
            let err = mul(&a, &b).unwrap_err().to_string();
    1266
            assert_eq!(err, "Invalid argument error: Output scale of Decimal128(3, 3) * Decimal128(37, 37) would exceed max scale of 38");
    1267
    1268
            let a = Decimal128Array::from(vec![1])
    1269
                .with_precision_and_scale(3, -2)
    1270
                .unwrap();
    1271
            let err = add(&a, &b).unwrap_err().to_string();
    1272
            assert_eq!(err, "Arithmetic overflow: Overflow happened on: 10 ^ 39");
    1273
    1274
            let a = Decimal128Array::from(vec![10])
    1275
                .with_precision_and_scale(3, -1)
    1276
                .unwrap();
    1277
            let err = add(&a, &b).unwrap_err().to_string();
    1278
            assert_eq!(
    1279
                err,
    1280
                "Arithmetic overflow: Overflow happened on: 10 * 100000000000000000000000000000000000000"
    1281
            );
    1282
    1283
            let b = Decimal128Array::from(vec![0])
    1284
                .with_precision_and_scale(1, 1)
    1285
                .unwrap();
    1286
            let err = div(&a, &b).unwrap_err().to_string();
    1287
            assert_eq!(err, "Divide by zero error");
    1288
            let err = rem(&a, &b).unwrap_err().to_string();
    1289
            assert_eq!(err, "Divide by zero error");
    1290
        }
    1291
    1292
        fn test_timestamp_impl<T: TimestampOp>() {
    1293
            let a = PrimitiveArray::<T>::new(vec![2000000, 434030324, 53943340].into(), None);
    1294
            let b = PrimitiveArray::<T>::new(vec![329593, 59349, 694994].into(), None);
    1295
    1296
            let result = sub(&a, &b).unwrap();
    1297
            assert_eq!(
    1298
                result.as_primitive::<T::Duration>().values(),
    1299
                &[1670407, 433970975, 53248346]
    1300
            );
    1301
    1302
            let r2 = add(&b, &result.as_ref()).unwrap();
    1303
            assert_eq!(r2.as_ref(), &a);
    1304
    1305
            let r3 = add(&result.as_ref(), &b).unwrap();
    1306
            assert_eq!(r3.as_ref(), &a);
    1307
    1308
            let format_array = |x: &dyn Array| -> Vec<String> {
    1309
                x.as_primitive::<T>()
    1310
                    .values()
    1311
                    .into_iter()
    1312
                    .map(|x| as_datetime::<T>(*x).unwrap().to_string())
    1313
                    .collect()
    1314
            };
    1315
    1316
            let values = vec![
    1317
                "1970-01-01T00:00:00Z",
    1318
                "2010-04-01T04:00:20Z",
    1319
                "1960-01-30T04:23:20Z",
    1320
            ]
    1321
            .into_iter()
    1322
            .map(|x| T::make_value(DateTime::parse_from_rfc3339(x).unwrap().naive_utc()).unwrap())
    1323
            .collect();
    1324
    1325
            let a = PrimitiveArray::<T>::new(values, None);
    1326
            let b = IntervalYearMonthArray::from(vec![
    1327
                IntervalYearMonthType::make_value(5, 34),
    1328
                IntervalYearMonthType::make_value(-2, 4),
    1329
                IntervalYearMonthType::make_value(7, -4),
    1330
            ]);
    1331
            let r4 = add(&a, &b).unwrap();
    1332
            assert_eq!(
    1333
                &format_array(r4.as_ref()),
    1334
                &[
    1335
                    "1977-11-01 00:00:00".to_string(),
    1336
                    "2008-08-01 04:00:20".to_string(),
    1337
                    "1966-09-30 04:23:20".to_string()
    1338
                ]
    1339
            );
    1340
    1341
            let r5 = sub(&r4, &b).unwrap();
    1342
            assert_eq!(r5.as_ref(), &a);
    1343
    1344
            let b = IntervalDayTimeArray::from(vec![
    1345
                IntervalDayTimeType::make_value(5, 454000),
    1346
                IntervalDayTimeType::make_value(-34, 0),
    1347
                IntervalDayTimeType::make_value(7, -4000),
    1348
            ]);
    1349
            let r6 = add(&a, &b).unwrap();
    1350
            assert_eq!(
    1351
                &format_array(r6.as_ref()),
    1352
                &[
    1353
                    "1970-01-06 00:07:34".to_string(),
    1354
                    "2010-02-26 04:00:20".to_string(),
    1355
                    "1960-02-06 04:23:16".to_string()
    1356
                ]
    1357
            );
    1358
    1359
            let r7 = sub(&r6, &b).unwrap();
    1360
            assert_eq!(r7.as_ref(), &a);
    1361
    1362
            let b = IntervalMonthDayNanoArray::from(vec![
    1363
                IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000),
    1364
                IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000),
    1365
                IntervalMonthDayNanoType::make_value(5, 2, 493_000_000_000),
    1366
            ]);
    1367
            let r8 = add(&a, &b).unwrap();
    1368
            assert_eq!(
    1369
                &format_array(r8.as_ref()),
    1370
                &[
    1371
                    "1998-10-04 23:59:17".to_string(),
    1372
                    "1960-09-29 04:00:33".to_string(),
    1373
                    "1960-07-02 04:31:33".to_string()
    1374
                ]
    1375
            );
    1376
    1377
            let r9 = sub(&r8, &b).unwrap();
    1378
            // Note: subtraction is not the inverse of addition for intervals
    1379
            assert_eq!(
    1380
                &format_array(r9.as_ref()),
    1381
                &[
    1382
                    "1970-01-02 00:00:00".to_string(),
    1383
                    "2010-04-02 04:00:20".to_string(),
    1384
                    "1960-01-31 04:23:20".to_string()
    1385
                ]
    1386
            );
    1387
        }
    1388
    1389
        #[test]
    1390
        fn test_timestamp() {
    1391
            test_timestamp_impl::<TimestampSecondType>();
    1392
            test_timestamp_impl::<TimestampMillisecondType>();
    1393
            test_timestamp_impl::<TimestampMicrosecondType>();
    1394
            test_timestamp_impl::<TimestampNanosecondType>();
    1395
        }
    1396
    1397
        #[test]
    1398
        fn test_interval() {
    1399
            let a = IntervalYearMonthArray::from(vec![
    1400
                IntervalYearMonthType::make_value(32, 4),
    1401
                IntervalYearMonthType::make_value(32, 4),
    1402
            ]);
    1403
            let b = IntervalYearMonthArray::from(vec![
    1404
                IntervalYearMonthType::make_value(-4, 6),
    1405
                IntervalYearMonthType::make_value(-3, 23),
    1406
            ]);
    1407
            let result = add(&a, &b).unwrap();
    1408
            assert_eq!(
    1409
                result.as_ref(),
    1410
                &IntervalYearMonthArray::from(vec![
    1411
                    IntervalYearMonthType::make_value(28, 10),
    1412
                    IntervalYearMonthType::make_value(29, 27)
    1413
                ])
    1414
            );
    1415
            let result = sub(&a, &b).unwrap();
    1416
            assert_eq!(
    1417
                result.as_ref(),
    1418
                &IntervalYearMonthArray::from(vec![
    1419
                    IntervalYearMonthType::make_value(36, -2),
    1420
                    IntervalYearMonthType::make_value(35, -19)
    1421
                ])
    1422
            );
    1423
    1424
            let a = IntervalDayTimeArray::from(vec![
    1425
                IntervalDayTimeType::make_value(32, 4),
    1426
                IntervalDayTimeType::make_value(32, 4),
    1427
            ]);
    1428
            let b = IntervalDayTimeArray::from(vec![
    1429
                IntervalDayTimeType::make_value(-4, 6),
    1430
                IntervalDayTimeType::make_value(-3, 23),
    1431
            ]);
    1432
            let result = add(&a, &b).unwrap();
    1433
            assert_eq!(
    1434
                result.as_ref(),
    1435
                &IntervalDayTimeArray::from(vec![
    1436
                    IntervalDayTimeType::make_value(28, 10),
    1437
                    IntervalDayTimeType::make_value(29, 27)
    1438
                ])
    1439
            );
    1440
            let result = sub(&a, &b).unwrap();
    1441
            assert_eq!(
    1442
                result.as_ref(),
    1443
                &IntervalDayTimeArray::from(vec![
    1444
                    IntervalDayTimeType::make_value(36, -2),
    1445
                    IntervalDayTimeType::make_value(35, -19)
    1446
                ])
    1447
            );
    1448
            let a = IntervalMonthDayNanoArray::from(vec![
    1449
                IntervalMonthDayNanoType::make_value(32, 4, 4000000000000),
    1450
                IntervalMonthDayNanoType::make_value(32, 4, 45463000000000000),
    1451
            ]);
    1452
            let b = IntervalMonthDayNanoArray::from(vec![
    1453
                IntervalMonthDayNanoType::make_value(-4, 6, 46000000000000),
    1454
                IntervalMonthDayNanoType::make_value(-3, 23, 3564000000000000),
    1455
            ]);
    1456
            let result = add(&a, &b).unwrap();
    1457
            assert_eq!(
    1458
                result.as_ref(),
    1459
                &IntervalMonthDayNanoArray::from(vec![
    1460
                    IntervalMonthDayNanoType::make_value(28, 10, 50000000000000),
    1461
                    IntervalMonthDayNanoType::make_value(29, 27, 49027000000000000)
    1462
                ])
    1463
            );
    1464
            let result = sub(&a, &b).unwrap();
    1465
            assert_eq!(
    1466
                result.as_ref(),
    1467
                &IntervalMonthDayNanoArray::from(vec![
    1468
                    IntervalMonthDayNanoType::make_value(36, -2, -42000000000000),
    1469
                    IntervalMonthDayNanoType::make_value(35, -19, 41899000000000000)
    1470
                ])
    1471
            );
    1472
            let a = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNano::MAX]);
    1473
            let b = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNano::ONE]);
    1474
            let err = add(&a, &b).unwrap_err().to_string();
    1475
            assert_eq!(
    1476
                err,
    1477
                "Arithmetic overflow: Overflow happened on: 2147483647 + 1"
    1478
            );
    1479
        }
    1480
    1481
        fn test_duration_impl<T: ArrowPrimitiveType<Native = i64>>() {
    1482
            let a = PrimitiveArray::<T>::new(vec![1000, 4394, -3944].into(), None);
    1483
            let b = PrimitiveArray::<T>::new(vec![4, -5, -243].into(), None);
    1484
    1485
            let result = add(&a, &b).unwrap();
    1486
            assert_eq!(result.as_primitive::<T>().values(), &[1004, 4389, -4187]);
    1487
            let result = sub(&a, &b).unwrap();
    1488
            assert_eq!(result.as_primitive::<T>().values(), &[996, 4399, -3701]);
    1489
    1490
            let err = mul(&a, &b).unwrap_err().to_string();
    1491
            assert!(
    1492
                err.contains("Invalid duration arithmetic operation"),
    1493
                "{err}"
    1494
            );
    1495
    1496
            let err = div(&a, &b).unwrap_err().to_string();
    1497
            assert!(
    1498
                err.contains("Invalid duration arithmetic operation"),
    1499
                "{err}"
    1500
            );
    1501
    1502
            let err = rem(&a, &b).unwrap_err().to_string();
    1503
            assert!(
    1504
                err.contains("Invalid duration arithmetic operation"),
    1505
                "{err}"
    1506
            );
    1507
    1508
            let a = PrimitiveArray::<T>::new(vec![i64::MAX].into(), None);
    1509
            let b = PrimitiveArray::<T>::new(vec![1].into(), None);
    1510
            let err = add(&a, &b).unwrap_err().to_string();
    1511
            assert_eq!(
    1512
                err,
    1513
                "Arithmetic overflow: Overflow happened on: 9223372036854775807 + 1"
    1514
            );
    1515
        }
    1516
    1517
        #[test]
    1518
        fn test_duration() {
    1519
            test_duration_impl::<DurationSecondType>();
    1520
            test_duration_impl::<DurationMillisecondType>();
    1521
            test_duration_impl::<DurationMicrosecondType>();
    1522
            test_duration_impl::<DurationNanosecondType>();
    1523
        }
    1524
    1525
        fn test_date_impl<T: ArrowPrimitiveType, F>(f: F)
    1526
        where
    1527
            F: Fn(NaiveDate) -> T::Native,
    1528
            T::Native: TryInto<i64>,
    1529
        {
    1530
            let a = PrimitiveArray::<T>::new(
    1531
                vec![
    1532
                    f(NaiveDate::from_ymd_opt(1979, 1, 30).unwrap()),
    1533
                    f(NaiveDate::from_ymd_opt(2010, 4, 3).unwrap()),
    1534
                    f(NaiveDate::from_ymd_opt(2008, 2, 29).unwrap()),
    1535
                ]
    1536
                .into(),
    1537
                None,
    1538
            );
    1539
    1540
            let b = IntervalYearMonthArray::from(vec![
    1541
                IntervalYearMonthType::make_value(34, 2),
    1542
                IntervalYearMonthType::make_value(3, -3),
    1543
                IntervalYearMonthType::make_value(-12, 4),
    1544
            ]);
    1545
    1546
            let format_array = |x: &dyn Array| -> Vec<String> {
    1547
                x.as_primitive::<T>()
    1548
                    .values()
    1549
                    .into_iter()
    1550
                    .map(|x| {
    1551
                        as_date::<T>((*x).try_into().ok().unwrap())
    1552
                            .unwrap()
    1553
                            .to_string()
    1554
                    })
    1555
                    .collect()
    1556
            };
    1557
    1558
            let result = add(&a, &b).unwrap();
    1559
            assert_eq!(
    1560
                &format_array(result.as_ref()),
    1561
                &[
    1562
                    "2013-03-30".to_string(),
    1563
                    "2013-01-03".to_string(),
    1564
                    "1996-06-29".to_string(),
    1565
                ]
    1566
            );
    1567
            let result = sub(&result, &b).unwrap();
    1568
            assert_eq!(result.as_ref(), &a);
    1569
    1570
            let b = IntervalDayTimeArray::from(vec![
    1571
                IntervalDayTimeType::make_value(34, 2),
    1572
                IntervalDayTimeType::make_value(3, -3),
    1573
                IntervalDayTimeType::make_value(-12, 4),
    1574
            ]);
    1575
    1576
            let result = add(&a, &b).unwrap();
    1577
            assert_eq!(
    1578
                &format_array(result.as_ref()),
    1579
                &[
    1580
                    "1979-03-05".to_string(),
    1581
                    "2010-04-06".to_string(),
    1582
                    "2008-02-17".to_string(),
    1583
                ]
    1584
            );
    1585
            let result = sub(&result, &b).unwrap();
    1586
            assert_eq!(result.as_ref(), &a);
    1587
    1588
            let b = IntervalMonthDayNanoArray::from(vec![
    1589
                IntervalMonthDayNanoType::make_value(34, 2, -34353534),
    1590
                IntervalMonthDayNanoType::make_value(3, -3, 2443),
    1591
                IntervalMonthDayNanoType::make_value(-12, 4, 2323242423232),
    1592
            ]);
    1593
    1594
            let result = add(&a, &b).unwrap();
    1595
            assert_eq!(
    1596
                &format_array(result.as_ref()),
    1597
                &[
    1598
                    "1981-12-02".to_string(),
    1599
                    "2010-06-30".to_string(),
    1600
                    "2007-03-04".to_string(),
    1601
                ]
    1602
            );
    1603
            let result = sub(&result, &b).unwrap();
    1604
            assert_eq!(
    1605
                &format_array(result.as_ref()),
    1606
                &[
    1607
                    "1979-01-31".to_string(),
    1608
                    "2010-04-02".to_string(),
    1609
                    "2008-02-29".to_string(),
    1610
                ]
    1611
            );
    1612
        }
    1613
    1614
        #[test]
    1615
        fn test_date() {
    1616
            test_date_impl::<Date32Type, _>(Date32Type::from_naive_date);
    1617
            test_date_impl::<Date64Type, _>(Date64Type::from_naive_date);
    1618
    1619
            let a = Date32Array::from(vec![i32::MIN, i32::MAX, 23, 7684]);
    1620
            let b = Date32Array::from(vec![i32::MIN, i32::MIN, -2, 45]);
    1621
            let result = sub(&a, &b).unwrap();
    1622
            assert_eq!(
    1623
                result.as_primitive::<DurationSecondType>().values(),
    1624
                &[0, 371085174288000, 2160000, 660009600]
    1625
            );
    1626
    1627
            let a = Date64Array::from(vec![4343, 76676, 3434]);
    1628
            let b = Date64Array::from(vec![3, -5, 5]);
    1629
            let result = sub(&a, &b).unwrap();
    1630
            assert_eq!(
    1631
                result.as_primitive::<DurationMillisecondType>().values(),
    1632
                &[4340, 76681, 3429]
    1633
            );
    1634
    1635
            let a = Date64Array::from(vec![i64::MAX]);
    1636
            let b = Date64Array::from(vec![-1]);
    1637
            let err = sub(&a, &b).unwrap_err().to_string();
    1638
            assert_eq!(
    1639
                err,
    1640
                "Arithmetic overflow: Overflow happened on: 9223372036854775807 - -1"
    1641
            );
    1642
        }
    1643
    1644
        #[test]
    1645
        fn test_date64_to_naive_date_opt_boundary_values() {
    1646
            use arrow_array::types::Date64Type;
    1647
    1648
            // Date64Type::to_naive_date_opt has boundaries determined by NaiveDate's supported range.
    1649
            // The valid date range is from January 1, -262143 to December 31, 262142 (Gregorian calendar).
    1650
    1651
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    1652
            let ms_per_day = 24 * 60 * 60 * 1000i64;
    1653
    1654
            // Define the boundary dates using NaiveDate::from_ymd_opt
    1655
            let max_valid_date = NaiveDate::from_ymd_opt(262142, 12, 31).unwrap();
    1656
            let min_valid_date = NaiveDate::from_ymd_opt(-262143, 1, 1).unwrap();
    1657
    1658
            // Calculate their millisecond values from epoch
    1659
            let max_valid_millis = (max_valid_date - epoch).num_milliseconds();
    1660
            let min_valid_millis = (min_valid_date - epoch).num_milliseconds();
    1661
    1662
            // Verify these match the expected boundaries in milliseconds
    1663
            assert_eq!(
    1664
                max_valid_millis, 8210266790400000i64,
    1665
                "December 31, 262142 should be 8210266790400000 ms from epoch"
    1666
            );
    1667
            assert_eq!(
    1668
                min_valid_millis, -8334601228800000i64,
    1669
                "January 1, -262143 should be -8334601228800000 ms from epoch"
    1670
            );
    1671
    1672
            // Test that the boundary dates work
    1673
            assert!(
    1674
                Date64Type::to_naive_date_opt(max_valid_millis).is_some(),
    1675
                "December 31, 262142 should return Some"
    1676
            );
    1677
            assert!(
    1678
                Date64Type::to_naive_date_opt(min_valid_millis).is_some(),
    1679
                "January 1, -262143 should return Some"
    1680
            );
    1681
    1682
            // Test that one day beyond the boundaries fails
    1683
            assert!(
    1684
                Date64Type::to_naive_date_opt(max_valid_millis + ms_per_day).is_none(),
    1685
                "January 1, 262143 should return None"
    1686
            );
    1687
            assert!(
    1688
                Date64Type::to_naive_date_opt(min_valid_millis - ms_per_day).is_none(),
    1689
                "December 31, -262144 should return None"
    1690
            );
    1691
    1692
            // Test some values well within the valid range
    1693
            assert!(
    1694
                Date64Type::to_naive_date_opt(0).is_some(),
    1695
                "Epoch (1970-01-01) should return Some"
    1696
            );
    1697
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    1698
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    1699
            assert!(
    1700
                Date64Type::to_naive_date_opt(year_2000_millis).is_some(),
    1701
                "Year 2000 should return Some"
    1702
            );
    1703
    1704
            // Test extreme values that definitely fail due to Duration constraints
    1705
            assert!(
    1706
                Date64Type::to_naive_date_opt(i64::MAX).is_none(),
    1707
                "i64::MAX should return None"
    1708
            );
    1709
            assert!(
    1710
                Date64Type::to_naive_date_opt(i64::MIN).is_none(),
    1711
                "i64::MIN should return None"
    1712
            );
    1713
        }
    1714
    1715
        #[test]
    1716
        fn test_date64_add_year_months_opt_boundary_values() {
    1717
            use arrow_array::types::Date64Type;
    1718
    1719
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    1720
    1721
            // Test normal case within valid range
    1722
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    1723
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    1724
            assert!(
    1725
                Date64Type::add_year_months_opt(year_2000_millis, 120).is_some(),
    1726
                "Adding 10 years to year 2000 should succeed"
    1727
            );
    1728
    1729
            // Test with moderate years that are within chrono's safe range
    1730
            let large_year = NaiveDate::from_ymd_opt(5000, 1, 1).unwrap();
    1731
            let large_year_millis = (large_year - epoch).num_milliseconds();
    1732
            assert!(
    1733
                Date64Type::add_year_months_opt(large_year_millis, 12).is_some(),
    1734
                "Adding 12 months to year 5000 should succeed"
    1735
            );
    1736
    1737
            let neg_year = NaiveDate::from_ymd_opt(-5000, 12, 31).unwrap();
    1738
            let neg_year_millis = (neg_year - epoch).num_milliseconds();
    1739
            assert!(
    1740
                Date64Type::add_year_months_opt(neg_year_millis, -12).is_some(),
    1741
                "Subtracting 12 months from year -5000 should succeed"
    1742
            );
    1743
    1744
            // Test with extreme input values that would cause overflow
    1745
            assert!(
    1746
                Date64Type::add_year_months_opt(i64::MAX, 1).is_none(),
    1747
                "Adding months to i64::MAX should fail"
    1748
            );
    1749
            assert!(
    1750
                Date64Type::add_year_months_opt(i64::MIN, -1).is_none(),
    1751
                "Subtracting months from i64::MIN should fail"
    1752
            );
    1753
    1754
            // Test edge case: adding zero should always work for valid dates
    1755
            assert!(
    1756
                Date64Type::add_year_months_opt(year_2000_millis, 0).is_some(),
    1757
                "Adding zero months should always succeed for valid dates"
    1758
            );
    1759
        }
    1760
    1761
        #[test]
    1762
        fn test_date64_add_day_time_opt_boundary_values() {
    1763
            use arrow_array::types::Date64Type;
    1764
            use arrow_buffer::IntervalDayTime;
    1765
    1766
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    1767
    1768
            // Test with a date far from the boundary but still testing the function
    1769
            let near_max_date = NaiveDate::from_ymd_opt(200000, 12, 1).unwrap();
    1770
            let near_max_millis = (near_max_date - epoch).num_milliseconds();
    1771
    1772
            // Adding 30 days should succeed
    1773
            let interval_30_days = IntervalDayTime::new(30, 0);
    1774
            assert!(
    1775
                Date64Type::add_day_time_opt(near_max_millis, interval_30_days).is_some(),
    1776
                "Adding 30 days to large year should succeed"
    1777
            );
    1778
    1779
            // Adding a very large number of days should fail
    1780
            let interval_large_days = IntervalDayTime::new(100000000, 0);
    1781
            assert!(
    1782
                Date64Type::add_day_time_opt(near_max_millis, interval_large_days).is_none(),
    1783
                "Adding 100M days to large year should fail"
    1784
            );
    1785
    1786
            // Test with a date far from the boundary in the negative direction
    1787
            let near_min_date = NaiveDate::from_ymd_opt(-200000, 2, 1).unwrap();
    1788
            let near_min_millis = (near_min_date - epoch).num_milliseconds();
    1789
    1790
            // Subtracting 30 days should succeed
    1791
            let interval_minus_30_days = IntervalDayTime::new(-30, 0);
    1792
            assert!(
    1793
                Date64Type::add_day_time_opt(near_min_millis, interval_minus_30_days).is_some(),
    1794
                "Subtracting 30 days from large negative year should succeed"
    1795
            );
    1796
    1797
            // Subtracting a very large number of days should fail
    1798
            let interval_minus_large_days = IntervalDayTime::new(-100000000, 0);
    1799
            assert!(
    1800
                Date64Type::add_day_time_opt(near_min_millis, interval_minus_large_days).is_none(),
    1801
                "Subtracting 100M days from large negative year should fail"
    1802
            );
    1803
    1804
            // Test normal case within valid range
    1805
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    1806
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    1807
            let interval_1000_days = IntervalDayTime::new(1000, 12345);
    1808
            assert!(
    1809
                Date64Type::add_day_time_opt(year_2000_millis, interval_1000_days).is_some(),
    1810
                "Adding 1000 days and time to year 2000 should succeed"
    1811
            );
    1812
    1813
            // Test with extreme input values that would cause overflow
    1814
            let interval_one_day = IntervalDayTime::new(1, 0);
    1815
            assert!(
    1816
                Date64Type::add_day_time_opt(i64::MAX, interval_one_day).is_none(),
    1817
                "Adding interval to i64::MAX should fail"
    1818
            );
    1819
            assert!(
    1820
                Date64Type::add_day_time_opt(i64::MIN, IntervalDayTime::new(-1, 0)).is_none(),
    1821
                "Subtracting interval from i64::MIN should fail"
    1822
            );
    1823
    1824
            // Test with extreme interval values
    1825
            let max_interval = IntervalDayTime::new(i32::MAX, i32::MAX);
    1826
            assert!(
    1827
                Date64Type::add_day_time_opt(0, max_interval).is_none(),
    1828
                "Adding extreme interval should fail"
    1829
            );
    1830
    1831
            let min_interval = IntervalDayTime::new(i32::MIN, i32::MIN);
    1832
            assert!(
    1833
                Date64Type::add_day_time_opt(0, min_interval).is_none(),
    1834
                "Adding extreme negative interval should fail"
    1835
            );
    1836
    1837
            // Test millisecond overflow within a day
    1838
            let large_ms_interval = IntervalDayTime::new(0, i32::MAX);
    1839
            assert!(
    1840
                Date64Type::add_day_time_opt(year_2000_millis, large_ms_interval).is_some(),
    1841
                "Adding large milliseconds within valid range should succeed"
    1842
            );
    1843
        }
    1844
    1845
        #[test]
    1846
        fn test_date64_add_month_day_nano_opt_boundary_values() {
    1847
            use arrow_array::types::Date64Type;
    1848
            use arrow_buffer::IntervalMonthDayNano;
    1849
    1850
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    1851
    1852
            // Test with a large year that is still within chrono's safe range
    1853
            let near_max_date = NaiveDate::from_ymd_opt(5000, 11, 1).unwrap();
    1854
            let near_max_millis = (near_max_date - epoch).num_milliseconds();
    1855
    1856
            // Adding 1 month and 30 days should succeed
    1857
            let interval_safe = IntervalMonthDayNano::new(1, 30, 0);
    1858
            assert!(
    1859
                Date64Type::add_month_day_nano_opt(near_max_millis, interval_safe).is_some(),
    1860
                "Adding 1 month 30 days to large year should succeed"
    1861
            );
    1862
    1863
            // Test normal case within valid range
    1864
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    1865
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    1866
    1867
            // Test edge case: adding zero should always work for valid dates
    1868
            let zero_interval = IntervalMonthDayNano::new(0, 0, 0);
    1869
            assert!(
    1870
                Date64Type::add_month_day_nano_opt(year_2000_millis, zero_interval).is_some(),
    1871
                "Adding zero interval should always succeed for valid dates"
    1872
            );
    1873
    1874
            // Test with a negative year that is still within chrono's safe range
    1875
            let near_min_date = NaiveDate::from_ymd_opt(-5000, 2, 28).unwrap();
    1876
            let near_min_millis = (near_min_date - epoch).num_milliseconds();
    1877
    1878
            // Subtracting 1 month and 30 days should succeed
    1879
            let interval_safe_neg = IntervalMonthDayNano::new(-1, -30, 0);
    1880
            assert!(
    1881
                Date64Type::add_month_day_nano_opt(near_min_millis, interval_safe_neg).is_some(),
    1882
                "Subtracting 1 month 30 days from large negative year should succeed"
    1883
            );
    1884
    1885
            // Test with extreme input values that would cause overflow
    1886
            assert!(
    1887
                Date64Type::add_month_day_nano_opt(i64::MAX, IntervalMonthDayNano::new(1, 0, 0))
    1888
                    .is_none(),
    1889
                "Adding interval to i64::MAX should fail"
    1890
            );
    1891
    1892
            let interval_normal = IntervalMonthDayNano::new(2, 10, 123_456_789_000);
    1893
            assert!(
    1894
                Date64Type::add_month_day_nano_opt(year_2000_millis, interval_normal).is_some(),
    1895
                "Adding 2 months, 10 days, and nanos to year 2000 should succeed"
    1896
            );
    1897
    1898
            // Test with extreme input values that would cause overflow
    1899
            assert!(
    1900
                Date64Type::add_month_day_nano_opt(i64::MAX, IntervalMonthDayNano::new(1, 0, 0))
    1901
                    .is_none(),
    1902
                "Adding interval to i64::MAX should fail"
    1903
            );
    1904
            assert!(
    1905
                Date64Type::add_month_day_nano_opt(i64::MIN, IntervalMonthDayNano::new(-1, 0, 0))
    1906
                    .is_none(),
    1907
                "Subtracting interval from i64::MIN should fail"
    1908
            );
    1909
    1910
            // Test with invalid timestamp input (the _opt function should handle these gracefully)
    1911
    1912
            // Test nanosecond precision (should not affect boundary since it's < 1ms)
    1913
            let nano_interval = IntervalMonthDayNano::new(0, 0, 999_999_999);
    1914
            assert!(
    1915
                Date64Type::add_month_day_nano_opt(year_2000_millis, nano_interval).is_some(),
    1916
                "Adding nanoseconds within valid range should succeed"
    1917
            );
    1918
    1919
            // Test large nanosecond values that convert to milliseconds
    1920
            let large_nano_interval = IntervalMonthDayNano::new(0, 0, 86_400_000_000_000); // 1 day in nanos
    1921
            assert!(
    1922
                Date64Type::add_month_day_nano_opt(year_2000_millis, large_nano_interval).is_some(),
    1923
                "Adding 1 day worth of nanoseconds should succeed"
    1924
            );
    1925
        }
    1926
    1927
        #[test]
    1928
        fn test_date64_subtract_year_months_opt_boundary_values() {
    1929
            use arrow_array::types::Date64Type;
    1930
    1931
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    1932
    1933
            // Test with a negative year that is still within chrono's safe range
    1934
            let near_min_date = NaiveDate::from_ymd_opt(-5000, 12, 31).unwrap();
    1935
            let near_min_millis = (near_min_date - epoch).num_milliseconds();
    1936
    1937
            // Subtracting 12 months should succeed
    1938
            assert!(
    1939
                Date64Type::subtract_year_months_opt(near_min_millis, 12).is_some(),
    1940
                "Subtracting 12 months from year -5000 should succeed"
    1941
            );
    1942
    1943
            // Test normal case within valid range
    1944
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    1945
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    1946
    1947
            // Test edge case: subtracting zero should always work for valid dates
    1948
            assert!(
    1949
                Date64Type::subtract_year_months_opt(year_2000_millis, 0).is_some(),
    1950
                "Subtracting zero months should always succeed for valid dates"
    1951
            );
    1952
    1953
            // Test with a large year that is still within chrono's safe range
    1954
            let near_max_date = NaiveDate::from_ymd_opt(5000, 1, 1).unwrap();
    1955
            let near_max_millis = (near_max_date - epoch).num_milliseconds();
    1956
    1957
            // Adding 12 months (subtracting negative) should succeed
    1958
            assert!(
    1959
                Date64Type::subtract_year_months_opt(near_max_millis, -12).is_some(),
    1960
                "Adding 12 months to year 5000 should succeed"
    1961
            );
    1962
    1963
            // Test with extreme input values that would cause overflow
    1964
            assert!(
    1965
                Date64Type::subtract_year_months_opt(i64::MAX, -1).is_none(),
    1966
                "Adding months to i64::MAX should fail"
    1967
            );
    1968
    1969
            assert!(
    1970
                Date64Type::subtract_year_months_opt(year_2000_millis, 12).is_some(),
    1971
                "Subtracting 1 year from year 2000 should succeed"
    1972
            );
    1973
    1974
            // Test with extreme input values that would cause overflow
    1975
            assert!(
    1976
                Date64Type::subtract_year_months_opt(i64::MAX, -1).is_none(),
    1977
                "Adding months to i64::MAX should fail"
    1978
            );
    1979
            assert!(
    1980
                Date64Type::subtract_year_months_opt(i64::MIN, 1).is_none(),
    1981
                "Subtracting months from i64::MIN should fail"
    1982
            );
    1983
    1984
            // Test edge case: subtracting zero should always work for valid dates
    1985
            let valid_date = NaiveDate::from_ymd_opt(2020, 6, 15).unwrap();
    1986
            let valid_millis = (valid_date - epoch).num_milliseconds();
    1987
            assert!(
    1988
                Date64Type::subtract_year_months_opt(valid_millis, 0).is_some(),
    1989
                "Subtracting zero months should always succeed for valid dates"
    1990
            );
    1991
        }
    1992
    1993
        #[test]
    1994
        fn test_date64_subtract_day_time_opt_boundary_values() {
    1995
            use arrow_array::types::Date64Type;
    1996
            use arrow_buffer::IntervalDayTime;
    1997
    1998
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    1999
    2000
            // Test with a date far from the boundary in the negative direction
    2001
            let near_min_date = NaiveDate::from_ymd_opt(-200000, 2, 1).unwrap();
    2002
            let near_min_millis = (near_min_date - epoch).num_milliseconds();
    2003
    2004
            // Subtracting 30 days should succeed
    2005
            let interval_30_days = IntervalDayTime::new(30, 0);
    2006
            assert!(
    2007
                Date64Type::subtract_day_time_opt(near_min_millis, interval_30_days).is_some(),
    2008
                "Subtracting 30 days from large negative year should succeed"
    2009
            );
    2010
    2011
            // Subtracting a very large number of days should fail
    2012
            let interval_large_days = IntervalDayTime::new(100000000, 0);
    2013
            assert!(
    2014
                Date64Type::subtract_day_time_opt(near_min_millis, interval_large_days).is_none(),
    2015
                "Subtracting 100M days from large negative year should fail"
    2016
            );
    2017
    2018
            // Test with a date far from the boundary but still testing the function
    2019
            let near_max_date = NaiveDate::from_ymd_opt(200000, 12, 1).unwrap();
    2020
            let near_max_millis = (near_max_date - epoch).num_milliseconds();
    2021
    2022
            // Adding 30 days (subtracting negative) should succeed
    2023
            let interval_minus_30_days = IntervalDayTime::new(-30, 0);
    2024
            assert!(
    2025
                Date64Type::subtract_day_time_opt(near_max_millis, interval_minus_30_days).is_some(),
    2026
                "Adding 30 days to large year should succeed"
    2027
            );
    2028
    2029
            // Adding a very large number of days should fail
    2030
            let interval_minus_large_days = IntervalDayTime::new(-100000000, 0);
    2031
            assert!(
    2032
                Date64Type::subtract_day_time_opt(near_max_millis, interval_minus_large_days).is_none(),
    2033
                "Adding 100M days to large year should fail"
    2034
            );
    2035
    2036
            // Test normal case within valid range
    2037
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    2038
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    2039
            let interval_1000_days = IntervalDayTime::new(1000, 12345);
    2040
            assert!(
    2041
                Date64Type::subtract_day_time_opt(year_2000_millis, interval_1000_days).is_some(),
    2042
                "Subtracting 1000 days and time from year 2000 should succeed"
    2043
            );
    2044
    2045
            // Test with extreme input values that would cause overflow
    2046
            let interval_one_day = IntervalDayTime::new(1, 0);
    2047
            assert!(
    2048
                Date64Type::subtract_day_time_opt(i64::MIN, interval_one_day).is_none(),
    2049
                "Subtracting interval from i64::MIN should fail"
    2050
            );
    2051
            assert!(
    2052
                Date64Type::subtract_day_time_opt(i64::MAX, IntervalDayTime::new(-1, 0)).is_none(),
    2053
                "Adding interval to i64::MAX should fail"
    2054
            );
    2055
    2056
            // Test with extreme interval values
    2057
            let max_interval = IntervalDayTime::new(i32::MAX, i32::MAX);
    2058
            assert!(
    2059
                Date64Type::subtract_day_time_opt(0, max_interval).is_none(),
    2060
                "Subtracting extreme interval should fail"
    2061
            );
    2062
    2063
            let min_interval = IntervalDayTime::new(i32::MIN, i32::MIN);
    2064
            assert!(
    2065
                Date64Type::subtract_day_time_opt(0, min_interval).is_none(),
    2066
                "Subtracting extreme negative interval should fail"
    2067
            );
    2068
    2069
            // Test millisecond precision
    2070
            let large_ms_interval = IntervalDayTime::new(0, i32::MAX);
    2071
            assert!(
    2072
                Date64Type::subtract_day_time_opt(year_2000_millis, large_ms_interval).is_some(),
    2073
                "Subtracting large milliseconds within valid range should succeed"
    2074
            );
    2075
    2076
            // Test edge case: subtracting zero should always work for valid dates
    2077
            let zero_interval = IntervalDayTime::new(0, 0);
    2078
            let valid_date = NaiveDate::from_ymd_opt(2020, 6, 15).unwrap();
    2079
            let valid_millis = (valid_date - epoch).num_milliseconds();
    2080
            assert!(
    2081
                Date64Type::subtract_day_time_opt(valid_millis, zero_interval).is_some(),
    2082
                "Subtracting zero interval should always succeed for valid dates"
    2083
            );
    2084
        }
    2085
    2086
        #[test]
    2087
        fn test_date64_subtract_month_day_nano_opt_boundary_values() {
    2088
            use arrow_array::types::Date64Type;
    2089
            use arrow_buffer::IntervalMonthDayNano;
    2090
    2091
            let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    2092
    2093
            // Test with a negative year that is still within chrono's safe range
    2094
            let near_min_date = NaiveDate::from_ymd_opt(-5000, 2, 28).unwrap();
    2095
            let near_min_millis = (near_min_date - epoch).num_milliseconds();
    2096
    2097
            // Subtracting 1 month and 30 days should succeed
    2098
            let interval_safe = IntervalMonthDayNano::new(1, 30, 0);
    2099
            assert!(
    2100
                Date64Type::subtract_month_day_nano_opt(near_min_millis, interval_safe).is_some(),
    2101
                "Subtracting 1 month 30 days from large negative year should succeed"
    2102
            );
    2103
    2104
            // Test normal case within valid range
    2105
            let year_2000 = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
    2106
            let year_2000_millis = (year_2000 - epoch).num_milliseconds();
    2107
    2108
            // Test edge case: subtracting zero should always work for valid dates
    2109
            let zero_interval = IntervalMonthDayNano::new(0, 0, 0);
    2110
            assert!(
    2111
                Date64Type::subtract_month_day_nano_opt(year_2000_millis, zero_interval).is_some(),
    2112
                "Subtracting zero interval should always succeed for valid dates"
    2113
            );
    2114
    2115
            // Test with a large year that is still within chrono's safe range
    2116
            let near_max_date = NaiveDate::from_ymd_opt(5000, 11, 1).unwrap();
    2117
            let near_max_millis = (near_max_date - epoch).num_milliseconds();
    2118
    2119
            // Adding 1 month and 30 days (subtracting negative) should succeed
    2120
            let interval_safe_neg = IntervalMonthDayNano::new(-1, -30, 0);
    2121
            assert!(
    2122
                Date64Type::subtract_month_day_nano_opt(near_max_millis, interval_safe_neg).is_some(),
    2123
                "Adding 1 month 30 days to large year should succeed"
    2124
            );
    2125
    2126
            // Test with extreme input values that would cause overflow
    2127
            assert!(
    2128
                Date64Type::subtract_month_day_nano_opt(i64::MIN, IntervalMonthDayNano::new(1, 0, 0))
    2129
                    .is_none(),
    2130
                "Subtracting interval from i64::MIN should fail"
    2131
            );
    2132
    2133
            let interval_normal = IntervalMonthDayNano::new(2, 10, 123_456_789_000);
    2134
            assert!(
    2135
                Date64Type::subtract_month_day_nano_opt(year_2000_millis, interval_normal).is_some(),
    2136
                "Subtracting 2 months, 10 days, and nanos from year 2000 should succeed"
    2137
            );
    2138
    2139
            // Test with extreme input values that would cause overflow
    2140
            assert!(
    2141
                Date64Type::subtract_month_day_nano_opt(i64::MIN, IntervalMonthDayNano::new(1, 0, 0))
    2142
                    .is_none(),
    2143
                "Subtracting interval from i64::MIN should fail"
    2144
            );
    2145
            assert!(
    2146
                Date64Type::subtract_month_day_nano_opt(i64::MAX, IntervalMonthDayNano::new(-1, 0, 0))
    2147
                    .is_none(),
    2148
                "Adding interval to i64::MAX should fail"
    2149
            );
    2150
    2151
            // Test nanosecond precision (should not affect boundary since it's < 1ms)
    2152
            let nano_interval = IntervalMonthDayNano::new(0, 0, 999_999_999);
    2153
            assert!(
    2154
                Date64Type::subtract_month_day_nano_opt(year_2000_millis, nano_interval).is_some(),
    2155
                "Subtracting nanoseconds within valid range should succeed"
    2156
            );
    2157
    2158
            // Test large nanosecond values that convert to milliseconds
    2159
            let large_nano_interval = IntervalMonthDayNano::new(0, 0, 86_400_000_000_000); // 1 day in nanos
    2160
            assert!(
    2161
                Date64Type::subtract_month_day_nano_opt(year_2000_millis, large_nano_interval)
    2162
                    .is_some(),
    2163
                "Subtracting 1 day worth of nanoseconds should succeed"
    2164
            );
    2165
    2166
            // Test edge case: subtracting zero should always work for valid dates
    2167
            let zero_interval = IntervalMonthDayNano::new(0, 0, 0);
    2168
            let valid_date = NaiveDate::from_ymd_opt(2020, 6, 15).unwrap();
    2169
            let valid_millis = (valid_date - epoch).num_milliseconds();
    2170
            assert!(
    2171
                Date64Type::subtract_month_day_nano_opt(valid_millis, zero_interval).is_some(),
    2172
                "Subtracting zero interval should always succeed for valid dates"
    2173
            );
    2174
        }
    2175
    }