Skip to main content

arrow_arith/
numeric.rs

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
20use std::cmp::Ordering;
21use std::fmt::Formatter;
22use std::sync::Arc;
23
24use arrow_array::cast::AsArray;
25use arrow_array::temporal_conversions::{NANOSECONDS, SECONDS_IN_DAY};
26use arrow_array::timezone::Tz;
27use arrow_array::types::*;
28use arrow_array::*;
29use arrow_buffer::{ArrowNativeType, IntervalDayTime, IntervalMonthDayNano};
30use arrow_schema::{ArrowError, DataType, IntervalUnit, TimeUnit};
31use num_traits::{CheckedMul, ToPrimitive};
32
33use crate::arity::{binary, try_binary};
34
35/// Perform `lhs + rhs`, returning an error on overflow
36pub fn add(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
37    arithmetic_op(Op::Add, lhs, rhs)
38}
39
40/// Perform `lhs + rhs`, wrapping on overflow for [`DataType::is_integer`]
41pub fn add_wrapping(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
42    arithmetic_op(Op::AddWrapping, lhs, rhs)
43}
44
45/// Perform `lhs - rhs`, returning an error on overflow
46pub fn sub(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
47    arithmetic_op(Op::Sub, lhs, rhs)
48}
49
50/// Perform `lhs - rhs`, wrapping on overflow for [`DataType::is_integer`]
51pub fn sub_wrapping(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
52    arithmetic_op(Op::SubWrapping, lhs, rhs)
53}
54
55/// Perform `lhs * rhs`, returning an error on overflow
56pub fn mul(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
57    arithmetic_op(Op::Mul, lhs, rhs)
58}
59
60/// Perform `lhs * rhs`, wrapping on overflow for [`DataType::is_integer`]
61pub fn mul_wrapping(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
62    arithmetic_op(Op::MulWrapping, lhs, rhs)
63}
64
65/// Perform `lhs / rhs`
66///
67/// Overflow or division by zero will result in an error, with exception to
68/// floating point numbers, which instead follow the IEEE 754 rules
69pub fn div(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
70    arithmetic_op(Op::Div, lhs, rhs)
71}
72
73/// Perform `lhs % rhs`
74///
75/// Division by zero will result in an error, with exception to
76/// floating point numbers, which instead follow the IEEE 754 rules
77///
78/// `signed_integer::MIN % -1` will not result in an error but return 0
79pub fn rem(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
80    arithmetic_op(Op::Rem, lhs, rhs)
81}
82
83macro_rules! neg_checked {
84    ($t:ty, $a:ident) => {{
85        let array = $a
86            .as_primitive::<$t>()
87            .try_unary::<_, $t, _>(|x| x.neg_checked())?;
88        Ok(Arc::new(array))
89    }};
90}
91
92macro_rules! neg_wrapping {
93    ($t:ty, $a:ident) => {{
94        let array = $a.as_primitive::<$t>().unary::<_, $t>(|x| x.neg_wrapping());
95        Ok(Arc::new(array))
96    }};
97}
98
99/// Negates each element of  `array`, returning an error on overflow
100///
101/// Note: negation of unsigned arrays is not supported and will return in an error,
102/// for wrapping unsigned negation consider using [`neg_wrapping`][neg_wrapping()]
103pub fn neg(array: &dyn Array) -> Result<ArrayRef, ArrowError> {
104    use DataType::*;
105    use IntervalUnit::*;
106    use TimeUnit::*;
107
108    match array.data_type() {
109        Int8 => neg_checked!(Int8Type, array),
110        Int16 => neg_checked!(Int16Type, array),
111        Int32 => neg_checked!(Int32Type, array),
112        Int64 => neg_checked!(Int64Type, array),
113        Float16 => neg_wrapping!(Float16Type, array),
114        Float32 => neg_wrapping!(Float32Type, array),
115        Float64 => neg_wrapping!(Float64Type, array),
116        Decimal32(p, s) => {
117            let a = array
118                .as_primitive::<Decimal32Type>()
119                .try_unary::<_, Decimal32Type, _>(|x| x.neg_checked())?;
120
121            Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
122        }
123        Decimal64(p, s) => {
124            let a = array
125                .as_primitive::<Decimal64Type>()
126                .try_unary::<_, Decimal64Type, _>(|x| x.neg_checked())?;
127
128            Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
129        }
130        Decimal128(p, s) => {
131            let a = array
132                .as_primitive::<Decimal128Type>()
133                .try_unary::<_, Decimal128Type, _>(|x| x.neg_checked())?;
134
135            Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
136        }
137        Decimal256(p, s) => {
138            let a = array
139                .as_primitive::<Decimal256Type>()
140                .try_unary::<_, Decimal256Type, _>(|x| x.neg_checked())?;
141
142            Ok(Arc::new(a.with_precision_and_scale(*p, *s)?))
143        }
144        Duration(Second) => neg_checked!(DurationSecondType, array),
145        Duration(Millisecond) => neg_checked!(DurationMillisecondType, array),
146        Duration(Microsecond) => neg_checked!(DurationMicrosecondType, array),
147        Duration(Nanosecond) => neg_checked!(DurationNanosecondType, array),
148        Interval(YearMonth) => neg_checked!(IntervalYearMonthType, array),
149        Interval(DayTime) => {
150            let a = array
151                .as_primitive::<IntervalDayTimeType>()
152                .try_unary::<_, IntervalDayTimeType, ArrowError>(|x| {
153                    let (days, ms) = IntervalDayTimeType::to_parts(x);
154                    Ok(IntervalDayTimeType::make_value(
155                        days.neg_checked()?,
156                        ms.neg_checked()?,
157                    ))
158                })?;
159            Ok(Arc::new(a))
160        }
161        Interval(MonthDayNano) => {
162            let a = array
163                .as_primitive::<IntervalMonthDayNanoType>()
164                .try_unary::<_, IntervalMonthDayNanoType, ArrowError>(|x| {
165                    let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(x);
166                    Ok(IntervalMonthDayNanoType::make_value(
167                        months.neg_checked()?,
168                        days.neg_checked()?,
169                        nanos.neg_checked()?,
170                    ))
171                })?;
172            Ok(Arc::new(a))
173        }
174        t => Err(ArrowError::InvalidArgumentError(format!(
175            "Invalid arithmetic operation: !{t}"
176        ))),
177    }
178}
179
180/// Negates each element of  `array`, wrapping on overflow for [`DataType::is_integer`]
181pub fn neg_wrapping(array: &dyn Array) -> Result<ArrayRef, ArrowError> {
182    downcast_integer! {
183        array.data_type() => (neg_wrapping, array),
184        _ => neg(array),
185    }
186}
187
188/// An enumeration of arithmetic operations
189///
190/// This allows sharing the type dispatch logic across the various kernels
191#[derive(Debug, Copy, Clone)]
192enum Op {
193    AddWrapping,
194    Add,
195    SubWrapping,
196    Sub,
197    MulWrapping,
198    Mul,
199    Div,
200    Rem,
201}
202
203impl std::fmt::Display for Op {
204    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
205        match self {
206            Op::AddWrapping | Op::Add => write!(f, "+"),
207            Op::SubWrapping | Op::Sub => write!(f, "-"),
208            Op::MulWrapping | Op::Mul => write!(f, "*"),
209            Op::Div => write!(f, "/"),
210            Op::Rem => write!(f, "%"),
211        }
212    }
213}
214
215impl Op {
216    fn commutative(&self) -> bool {
217        matches!(
218            self,
219            Self::Add | Self::AddWrapping | Self::Mul | Self::MulWrapping
220        )
221    }
222}
223
224/// Dispatch the given `op` to the appropriate specialized kernel
225fn arithmetic_op(op: Op, lhs: &dyn Datum, rhs: &dyn Datum) -> Result<ArrayRef, ArrowError> {
226    use DataType::*;
227    use IntervalUnit::*;
228    use TimeUnit::*;
229
230    macro_rules! integer_helper {
231        ($t:ty, $op:ident, $l:ident, $l_scalar:ident, $r:ident, $r_scalar:ident) => {
232            integer_op::<$t>($op, $l, $l_scalar, $r, $r_scalar)
233        };
234    }
235
236    let (l, l_scalar) = lhs.get();
237    let (r, r_scalar) = rhs.get();
238    downcast_integer! {
239        l.data_type(), r.data_type() => (integer_helper, op, l, l_scalar, r, r_scalar),
240        (Float16, Float16) => float_op::<Float16Type>(op, l, l_scalar, r, r_scalar),
241        (Float32, Float32) => float_op::<Float32Type>(op, l, l_scalar, r, r_scalar),
242        (Float64, Float64) => float_op::<Float64Type>(op, l, l_scalar, r, r_scalar),
243        (Timestamp(Second, _), _) => timestamp_op::<TimestampSecondType>(op, l, l_scalar, r, r_scalar),
244        (Timestamp(Millisecond, _), _) => timestamp_op::<TimestampMillisecondType>(op, l, l_scalar, r, r_scalar),
245        (Timestamp(Microsecond, _), _) => timestamp_op::<TimestampMicrosecondType>(op, l, l_scalar, r, r_scalar),
246        (Timestamp(Nanosecond, _), _) => timestamp_op::<TimestampNanosecondType>(op, l, l_scalar, r, r_scalar),
247        (Duration(Second), Duration(Second)) => duration_op::<DurationSecondType>(op, l, l_scalar, r, r_scalar),
248        (Duration(Millisecond), Duration(Millisecond)) => duration_op::<DurationMillisecondType>(op, l, l_scalar, r, r_scalar),
249        (Duration(Microsecond), Duration(Microsecond)) => duration_op::<DurationMicrosecondType>(op, l, l_scalar, r, r_scalar),
250        (Duration(Nanosecond), Duration(Nanosecond)) => duration_op::<DurationNanosecondType>(op, l, l_scalar, r, r_scalar),
251        (Interval(YearMonth), Interval(YearMonth) | Int64) => interval_op::<IntervalYearMonthType>(op, l, l_scalar, r, r_scalar),
252        (Interval(DayTime), Interval(DayTime) | Int64) => interval_op::<IntervalDayTimeType>(op, l, l_scalar, r, r_scalar),
253        (Interval(MonthDayNano), Interval(MonthDayNano) | Int64) => interval_op::<IntervalMonthDayNanoType>(op, l, l_scalar, r, r_scalar),
254        (Interval(MonthDayNano), Float64) => interval_f64_op(op, l, l_scalar, r, r_scalar),
255        (Date32, _) => date_op::<Date32Type>(op, l, l_scalar, r, r_scalar),
256        (Date64, _) => date_op::<Date64Type>(op, l, l_scalar, r, r_scalar),
257        (Decimal32(_, _), Decimal32(_, _)) => decimal_op::<Decimal32Type>(op, l, l_scalar, r, r_scalar),
258        (Decimal64(_, _), Decimal64(_, _)) => decimal_op::<Decimal64Type>(op, l, l_scalar, r, r_scalar),
259        (Decimal128(_, _), Decimal128(_, _)) => decimal_op::<Decimal128Type>(op, l, l_scalar, r, r_scalar),
260        (Decimal256(_, _), Decimal256(_, _)) => decimal_op::<Decimal256Type>(op, l, l_scalar, r, r_scalar),
261        (l_t, r_t) => match (l_t, r_t) {
262            (Duration(_) | Interval(_), Date32 | Date64 | Timestamp(_, _)) if op.commutative() => {
263                arithmetic_op(op, rhs, lhs)
264            }
265            (Int64, Interval(_)) | (Float64, Interval(MonthDayNano))
266                if matches!(op, Op::Mul) =>
267            {
268                arithmetic_op(op, rhs, lhs)
269            }
270            _ => Err(ArrowError::InvalidArgumentError(
271              format!("Invalid arithmetic operation: {l_t} {op} {r_t}")
272            ))
273        }
274    }
275}
276
277/// Perform an infallible binary operation on potentially scalar inputs
278macro_rules! op {
279    ($l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {
280        match ($l_s, $r_s) {
281            (true, true) | (false, false) => binary($l, $r, |$l, $r| $op)?,
282            (true, false) => match ($l.null_count() == 0).then(|| $l.value(0)) {
283                None => PrimitiveArray::new_null($r.len()),
284                Some($l) => $r.unary(|$r| $op),
285            },
286            (false, true) => match ($r.null_count() == 0).then(|| $r.value(0)) {
287                None => PrimitiveArray::new_null($l.len()),
288                Some($r) => $l.unary(|$l| $op),
289            },
290        }
291    };
292}
293
294/// Same as `op` but with a type hint for the returned array
295macro_rules! op_ref {
296    ($t:ty, $l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {{
297        let array: PrimitiveArray<$t> = op!($l, $l_s, $r, $r_s, $op);
298        Arc::new(array)
299    }};
300}
301
302/// Perform a fallible binary operation on potentially scalar inputs
303macro_rules! try_op {
304    ($l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {
305        match ($l_s, $r_s) {
306            (true, true) | (false, false) => try_binary($l, $r, |$l, $r| $op)?,
307            (true, false) => match ($l.null_count() == 0).then(|| $l.value(0)) {
308                None => PrimitiveArray::new_null($r.len()),
309                Some($l) => $r.try_unary(|$r| $op)?,
310            },
311            (false, true) => match ($r.null_count() == 0).then(|| $r.value(0)) {
312                None => PrimitiveArray::new_null($l.len()),
313                Some($r) => $l.try_unary(|$l| $op)?,
314            },
315        }
316    };
317}
318
319/// Same as `try_op` but with a type hint for the returned array
320macro_rules! try_op_ref {
321    ($t:ty, $l:ident, $l_s:expr, $r:ident, $r_s:expr, $op:expr) => {{
322        let array: PrimitiveArray<$t> = try_op!($l, $l_s, $r, $r_s, $op);
323        Arc::new(array)
324    }};
325}
326
327/// Perform an arithmetic operation on integers
328fn integer_op<T: ArrowPrimitiveType>(
329    op: Op,
330    l: &dyn Array,
331    l_s: bool,
332    r: &dyn Array,
333    r_s: bool,
334) -> Result<ArrayRef, ArrowError> {
335    let l = l.as_primitive::<T>();
336    let r = r.as_primitive::<T>();
337    let array: PrimitiveArray<T> = match op {
338        Op::AddWrapping => op!(l, l_s, r, r_s, l.add_wrapping(r)),
339        Op::Add => try_op!(l, l_s, r, r_s, l.add_checked(r)),
340        Op::SubWrapping => op!(l, l_s, r, r_s, l.sub_wrapping(r)),
341        Op::Sub => try_op!(l, l_s, r, r_s, l.sub_checked(r)),
342        Op::MulWrapping => op!(l, l_s, r, r_s, l.mul_wrapping(r)),
343        Op::Mul => try_op!(l, l_s, r, r_s, l.mul_checked(r)),
344        Op::Div => try_op!(l, l_s, r, r_s, l.div_checked(r)),
345        Op::Rem => try_op!(l, l_s, r, r_s, {
346            if r.is_zero() {
347                Err(ArrowError::DivideByZero)
348            } else {
349                Ok(l.mod_wrapping(r))
350            }
351        }),
352    };
353    Ok(Arc::new(array))
354}
355
356/// Perform an arithmetic operation on floats
357fn float_op<T: ArrowPrimitiveType>(
358    op: Op,
359    l: &dyn Array,
360    l_s: bool,
361    r: &dyn Array,
362    r_s: bool,
363) -> Result<ArrayRef, ArrowError> {
364    let l = l.as_primitive::<T>();
365    let r = r.as_primitive::<T>();
366    let array: PrimitiveArray<T> = match op {
367        Op::AddWrapping | Op::Add => op!(l, l_s, r, r_s, l.add_wrapping(r)),
368        Op::SubWrapping | Op::Sub => op!(l, l_s, r, r_s, l.sub_wrapping(r)),
369        Op::MulWrapping | Op::Mul => op!(l, l_s, r, r_s, l.mul_wrapping(r)),
370        Op::Div => op!(l, l_s, r, r_s, l.div_wrapping(r)),
371        Op::Rem => op!(l, l_s, r, r_s, l.mod_wrapping(r)),
372    };
373    Ok(Arc::new(array))
374}
375
376/// Arithmetic trait for timestamp arrays
377trait TimestampOp: ArrowTimestampType {
378    type Duration: ArrowPrimitiveType<Native = i64>;
379
380    fn add_year_month(timestamp: i64, delta: i32, tz: Tz) -> Option<i64>;
381    fn add_day_time(timestamp: i64, delta: IntervalDayTime, tz: Tz) -> Option<i64>;
382    fn add_month_day_nano(timestamp: i64, delta: IntervalMonthDayNano, tz: Tz) -> Option<i64>;
383
384    fn sub_year_month(timestamp: i64, delta: i32, tz: Tz) -> Option<i64>;
385    fn sub_day_time(timestamp: i64, delta: IntervalDayTime, tz: Tz) -> Option<i64>;
386    fn sub_month_day_nano(timestamp: i64, delta: IntervalMonthDayNano, tz: Tz) -> Option<i64>;
387}
388
389macro_rules! timestamp {
390    ($t:ty, $d:ty) => {
391        impl TimestampOp for $t {
392            type Duration = $d;
393
394            fn add_year_month(left: i64, right: i32, tz: Tz) -> Option<i64> {
395                Self::add_year_months(left, right, tz)
396            }
397
398            fn add_day_time(left: i64, right: IntervalDayTime, tz: Tz) -> Option<i64> {
399                Self::add_day_time(left, right, tz)
400            }
401
402            fn add_month_day_nano(left: i64, right: IntervalMonthDayNano, tz: Tz) -> Option<i64> {
403                Self::add_month_day_nano(left, right, tz)
404            }
405
406            fn sub_year_month(left: i64, right: i32, tz: Tz) -> Option<i64> {
407                Self::subtract_year_months(left, right, tz)
408            }
409
410            fn sub_day_time(left: i64, right: IntervalDayTime, tz: Tz) -> Option<i64> {
411                Self::subtract_day_time(left, right, tz)
412            }
413
414            fn sub_month_day_nano(left: i64, right: IntervalMonthDayNano, tz: Tz) -> Option<i64> {
415                Self::subtract_month_day_nano(left, right, tz)
416            }
417        }
418    };
419}
420timestamp!(TimestampSecondType, DurationSecondType);
421timestamp!(TimestampMillisecondType, DurationMillisecondType);
422timestamp!(TimestampMicrosecondType, DurationMicrosecondType);
423timestamp!(TimestampNanosecondType, DurationNanosecondType);
424
425/// Perform arithmetic operation on a timestamp array
426fn timestamp_op<T: TimestampOp>(
427    op: Op,
428    l: &dyn Array,
429    l_s: bool,
430    r: &dyn Array,
431    r_s: bool,
432) -> Result<ArrayRef, ArrowError> {
433    use DataType::*;
434    use IntervalUnit::*;
435
436    let l = l.as_primitive::<T>();
437    let l_tz: Tz = l.timezone().unwrap_or("+00:00").parse()?;
438
439    let array: PrimitiveArray<T> = match (op, r.data_type()) {
440        (Op::Sub | Op::SubWrapping, Timestamp(unit, _)) if unit == &T::UNIT => {
441            let r = r.as_primitive::<T>();
442            return Ok(try_op_ref!(T::Duration, l, l_s, r, r_s, l.sub_checked(r)));
443        }
444
445        (Op::Add | Op::AddWrapping, Duration(unit)) if unit == &T::UNIT => {
446            let r = r.as_primitive::<T::Duration>();
447            try_op!(l, l_s, r, r_s, l.add_checked(r))
448        }
449        (Op::Sub | Op::SubWrapping, Duration(unit)) if unit == &T::UNIT => {
450            let r = r.as_primitive::<T::Duration>();
451            try_op!(l, l_s, r, r_s, l.sub_checked(r))
452        }
453
454        (Op::Add | Op::AddWrapping, Interval(YearMonth)) => {
455            let r = r.as_primitive::<IntervalYearMonthType>();
456            try_op!(
457                l,
458                l_s,
459                r,
460                r_s,
461                T::add_year_month(l, r, l_tz).ok_or(ArrowError::ComputeError(
462                    "Timestamp out of range".to_string()
463                ))
464            )
465        }
466        (Op::Sub | Op::SubWrapping, Interval(YearMonth)) => {
467            let r = r.as_primitive::<IntervalYearMonthType>();
468            try_op!(
469                l,
470                l_s,
471                r,
472                r_s,
473                T::sub_year_month(l, r, l_tz).ok_or(ArrowError::ComputeError(
474                    "Timestamp out of range".to_string()
475                ))
476            )
477        }
478
479        (Op::Add | Op::AddWrapping, Interval(DayTime)) => {
480            let r = r.as_primitive::<IntervalDayTimeType>();
481            try_op!(
482                l,
483                l_s,
484                r,
485                r_s,
486                T::add_day_time(l, r, l_tz).ok_or(ArrowError::ComputeError(
487                    "Timestamp out of range".to_string()
488                ))
489            )
490        }
491        (Op::Sub | Op::SubWrapping, Interval(DayTime)) => {
492            let r = r.as_primitive::<IntervalDayTimeType>();
493            try_op!(
494                l,
495                l_s,
496                r,
497                r_s,
498                T::sub_day_time(l, r, l_tz).ok_or(ArrowError::ComputeError(
499                    "Timestamp out of range".to_string()
500                ))
501            )
502        }
503
504        (Op::Add | Op::AddWrapping, Interval(MonthDayNano)) => {
505            let r = r.as_primitive::<IntervalMonthDayNanoType>();
506            try_op!(
507                l,
508                l_s,
509                r,
510                r_s,
511                T::add_month_day_nano(l, r, l_tz).ok_or(ArrowError::ComputeError(
512                    "Timestamp out of range".to_string()
513                ))
514            )
515        }
516        (Op::Sub | Op::SubWrapping, Interval(MonthDayNano)) => {
517            let r = r.as_primitive::<IntervalMonthDayNanoType>();
518            try_op!(
519                l,
520                l_s,
521                r,
522                r_s,
523                T::sub_month_day_nano(l, r, l_tz).ok_or(ArrowError::ComputeError(
524                    "Timestamp out of range".to_string()
525                ))
526            )
527        }
528        _ => {
529            return Err(ArrowError::InvalidArgumentError(format!(
530                "Invalid timestamp arithmetic operation: {} {op} {}",
531                l.data_type(),
532                r.data_type()
533            )));
534        }
535    };
536    Ok(Arc::new(array.with_timezone_opt(l.timezone())))
537}
538
539/// Arithmetic trait for date arrays
540trait DateOp: ArrowTemporalType {
541    fn add_year_month(timestamp: Self::Native, delta: i32) -> Result<Self::Native, ArrowError>;
542    fn add_day_time(
543        timestamp: Self::Native,
544        delta: IntervalDayTime,
545    ) -> Result<Self::Native, ArrowError>;
546    fn add_month_day_nano(
547        timestamp: Self::Native,
548        delta: IntervalMonthDayNano,
549    ) -> Result<Self::Native, ArrowError>;
550
551    fn sub_year_month(timestamp: Self::Native, delta: i32) -> Result<Self::Native, ArrowError>;
552    fn sub_day_time(
553        timestamp: Self::Native,
554        delta: IntervalDayTime,
555    ) -> Result<Self::Native, ArrowError>;
556    fn sub_month_day_nano(
557        timestamp: Self::Native,
558        delta: IntervalMonthDayNano,
559    ) -> Result<Self::Native, ArrowError>;
560}
561
562macro_rules! date {
563    ($t:ty) => {
564        impl DateOp for $t {
565            fn add_year_month(left: Self::Native, right: i32) -> Result<Self::Native, ArrowError> {
566                Self::add_year_months_opt(left, right).ok_or_else(|| {
567                    ArrowError::ComputeError(format!(
568                        "Date arithmetic overflow: {left} + {right} months"
569                    ))
570                })
571            }
572
573            fn add_day_time(
574                left: Self::Native,
575                right: IntervalDayTime,
576            ) -> Result<Self::Native, ArrowError> {
577                Self::add_day_time_opt(left, right).ok_or_else(|| {
578                    ArrowError::ComputeError(format!(
579                        "Date arithmetic overflow: {left} + {right:?}"
580                    ))
581                })
582            }
583
584            fn add_month_day_nano(
585                left: Self::Native,
586                right: IntervalMonthDayNano,
587            ) -> Result<Self::Native, ArrowError> {
588                Self::add_month_day_nano_opt(left, right).ok_or_else(|| {
589                    ArrowError::ComputeError(format!(
590                        "Date arithmetic overflow: {left} + {right:?}"
591                    ))
592                })
593            }
594
595            fn sub_year_month(left: Self::Native, right: i32) -> Result<Self::Native, ArrowError> {
596                Self::subtract_year_months_opt(left, right).ok_or_else(|| {
597                    ArrowError::ComputeError(format!(
598                        "Date arithmetic overflow: {left} - {right} months"
599                    ))
600                })
601            }
602
603            fn sub_day_time(
604                left: Self::Native,
605                right: IntervalDayTime,
606            ) -> Result<Self::Native, ArrowError> {
607                Self::subtract_day_time_opt(left, right).ok_or_else(|| {
608                    ArrowError::ComputeError(format!(
609                        "Date arithmetic overflow: {left} - {right:?}"
610                    ))
611                })
612            }
613
614            fn sub_month_day_nano(
615                left: Self::Native,
616                right: IntervalMonthDayNano,
617            ) -> Result<Self::Native, ArrowError> {
618                Self::subtract_month_day_nano_opt(left, right).ok_or_else(|| {
619                    ArrowError::ComputeError(format!(
620                        "Date arithmetic overflow: {left} - {right:?}"
621                    ))
622                })
623            }
624        }
625    };
626}
627
628date!(Date32Type);
629date!(Date64Type);
630
631/// Arithmetic trait for interval arrays
632trait IntervalOp: ArrowPrimitiveType {
633    fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError>;
634    fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError>;
635    fn mul_i64(left: Self::Native, right: i64) -> Result<Self::Native, ArrowError>;
636}
637
638fn mul_i32_i64(left: i32, right: i64) -> Result<i32, ArrowError> {
639    let value = i64::from(left).mul_checked(right)?;
640    i32::try_from(value).map_err(|_| {
641        ArrowError::ArithmeticOverflow(format!("Overflow happened on: {left} * {right}"))
642    })
643}
644
645impl IntervalOp for IntervalYearMonthType {
646    fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
647        left.add_checked(right)
648    }
649
650    fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
651        left.sub_checked(right)
652    }
653
654    fn mul_i64(left: Self::Native, right: i64) -> Result<Self::Native, ArrowError> {
655        mul_i32_i64(left, right)
656    }
657}
658
659impl IntervalOp for IntervalDayTimeType {
660    fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
661        let (l_days, l_ms) = Self::to_parts(left);
662        let (r_days, r_ms) = Self::to_parts(right);
663        let days = l_days.add_checked(r_days)?;
664        let ms = l_ms.add_checked(r_ms)?;
665        Ok(Self::make_value(days, ms))
666    }
667
668    fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
669        let (l_days, l_ms) = Self::to_parts(left);
670        let (r_days, r_ms) = Self::to_parts(right);
671        let days = l_days.sub_checked(r_days)?;
672        let ms = l_ms.sub_checked(r_ms)?;
673        Ok(Self::make_value(days, ms))
674    }
675
676    fn mul_i64(left: Self::Native, right: i64) -> Result<Self::Native, ArrowError> {
677        let (days, ms) = Self::to_parts(left);
678        Ok(Self::make_value(
679            mul_i32_i64(days, right)?,
680            mul_i32_i64(ms, right)?,
681        ))
682    }
683}
684
685impl IntervalOp for IntervalMonthDayNanoType {
686    fn add(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
687        let (l_months, l_days, l_nanos) = Self::to_parts(left);
688        let (r_months, r_days, r_nanos) = Self::to_parts(right);
689        let months = l_months.add_checked(r_months)?;
690        let days = l_days.add_checked(r_days)?;
691        let nanos = l_nanos.add_checked(r_nanos)?;
692        Ok(Self::make_value(months, days, nanos))
693    }
694
695    fn sub(left: Self::Native, right: Self::Native) -> Result<Self::Native, ArrowError> {
696        let (l_months, l_days, l_nanos) = Self::to_parts(left);
697        let (r_months, r_days, r_nanos) = Self::to_parts(right);
698        let months = l_months.sub_checked(r_months)?;
699        let days = l_days.sub_checked(r_days)?;
700        let nanos = l_nanos.sub_checked(r_nanos)?;
701        Ok(Self::make_value(months, days, nanos))
702    }
703
704    fn mul_i64(left: Self::Native, right: i64) -> Result<Self::Native, ArrowError> {
705        let (months, days, nanos) = Self::to_parts(left);
706        Ok(Self::make_value(
707            mul_i32_i64(months, right)?,
708            mul_i32_i64(days, right)?,
709            nanos.mul_checked(right)?,
710        ))
711    }
712}
713
714fn interval_mul_op<T: IntervalOp>(
715    interval: &dyn Array,
716    interval_scalar: bool,
717    factor: &dyn Array,
718    factor_scalar: bool,
719) -> Result<ArrayRef, ArrowError> {
720    let interval = interval.as_primitive::<T>();
721    let factor = factor.as_primitive::<Int64Type>();
722    Ok(try_op_ref!(
723        T,
724        interval,
725        interval_scalar,
726        factor,
727        factor_scalar,
728        T::mul_i64(interval, factor)
729    ))
730}
731
732/// Multiplies an `IntervalMonthDayNano` by an `f64`, mirroring DuckDB's
733/// `interval_t` layout of months, days, and a sub-day component (nanoseconds in
734/// Arrow, microseconds in DuckDB).
735/// <https://github.com/duckdb/duckdb/blob/21aca0424f1faf78b593b1e6fbfdd4846624c987/src/include/duckdb/common/types/interval.hpp#L24-L27>
736///
737/// Algorithm:
738///
739/// 1. use checked integer multiplication when `factor` fits in `i64` (early return).
740/// 2. multiply months and days separately
741/// 3. cascade remainders: convert fractional months to days using 30
742///    days per month, then fractional days to a sub-day value using 24 hours
743///    per day.
744/// 4. combine the cascaded remainder with the scaled input nanoseconds and round ties-to-even at nanosecond precision.
745/// 5. return an overflow error if any output component is out of
746///    range.
747fn interval_mul_f64(
748    interval: IntervalMonthDayNano,
749    factor: f64,
750) -> Result<IntervalMonthDayNano, ArrowError> {
751    const DAYS_PER_MONTH: f64 = 30.;
752    const NANOS_PER_SECOND: f64 = NANOSECONDS as f64;
753    const SECONDS_PER_DAY: f64 = SECONDS_IN_DAY as f64;
754
755    // Keep integral factors exact instead of round-tripping i64 nanoseconds through f64.
756    if factor.fract() == 0.
757        && let Some(factor) = ToPrimitive::to_i64(&factor)
758    {
759        return IntervalMonthDayNanoType::mul_i64(interval, factor);
760    }
761
762    // Based on DuckDB's INTERVAL * DOUBLE implementation, which is referenced from PostgreSQL's interval_mul:
763    // https://github.com/duckdb/duckdb/blob/21aca0424f1faf78b593b1e6fbfdd4846624c987/src/function/scalar/operator/multiply.cpp#L48-L123
764    // PostgreSQL's interval_mul:
765    // https://github.com/postgres/postgres/blob/78758d37306cd89ab060f00cb06f249018d5b8da/src/backend/utils/adt/timestamp.c#L3627-L3744
766    let overflow =
767        |component| ArrowError::ArithmeticOverflow(format!("Overflow in interval {component}"));
768    let timestamp_round =
769        |value: f64| (value * NANOS_PER_SECOND).round_ties_even() / NANOS_PER_SECOND;
770
771    let months_product = f64::from(interval.months) * factor;
772    if !months_product.is_finite()
773        || months_product < f64::from(i32::MIN)
774        || months_product > f64::from(i32::MAX)
775    {
776        return Err(overflow("months"));
777    }
778    let months = months_product.to_i32().ok_or_else(|| overflow("months"))?;
779
780    let days_product = f64::from(interval.days) * factor;
781    if !days_product.is_finite()
782        || days_product < f64::from(i32::MIN)
783        || days_product > f64::from(i32::MAX)
784    {
785        return Err(overflow("days"));
786    }
787    let mut days = days_product.to_i32().ok_or_else(|| overflow("days"))?;
788
789    let month_remainder = timestamp_round(months_product.fract() * DAYS_PER_MONTH);
790    let month_remainder_days = month_remainder
791        .to_i32()
792        .ok_or_else(|| overflow("month remainder"))?;
793    let mut seconds_remainder =
794        timestamp_round((days_product.fract() + month_remainder.fract()) * SECONDS_PER_DAY);
795
796    if seconds_remainder.abs() >= SECONDS_PER_DAY {
797        let remainder_days = (seconds_remainder / SECONDS_PER_DAY)
798            .to_i32()
799            .ok_or_else(|| overflow("day remainder"))?;
800        days = days
801            .checked_add(remainder_days)
802            .ok_or_else(|| overflow("days"))?;
803        seconds_remainder -= f64::from(remainder_days) * SECONDS_PER_DAY;
804    }
805    days = days
806        .checked_add(month_remainder_days)
807        .ok_or_else(|| overflow("days"))?;
808
809    let nanoseconds = ((interval.nanoseconds as f64) * factor
810        + seconds_remainder * NANOS_PER_SECOND)
811        .round_ties_even();
812    let nanoseconds = ToPrimitive::to_i64(&nanoseconds).ok_or_else(|| {
813        ArrowError::ArithmeticOverflow(format!("Overflow in interval nanoseconds: {nanoseconds}"))
814    })?;
815
816    Ok(IntervalMonthDayNano::new(months, days, nanoseconds))
817}
818
819fn interval_f64_op(
820    op: Op,
821    interval: &dyn Array,
822    interval_scalar: bool,
823    factor: &dyn Array,
824    factor_scalar: bool,
825) -> Result<ArrayRef, ArrowError> {
826    let interval = interval.as_primitive::<IntervalMonthDayNanoType>();
827    let factor = factor.as_primitive::<Float64Type>();
828    Ok(try_op_ref!(
829        IntervalMonthDayNanoType,
830        interval,
831        interval_scalar,
832        factor,
833        factor_scalar,
834        {
835            match op {
836                Op::Mul => interval_mul_f64(interval, factor),
837                Op::Div if factor == 0. => Err(ArrowError::DivideByZero),
838                // DuckDB defines interval division as multiplication by the reciprocal:
839                // https://github.com/duckdb/duckdb/blob/21aca0424f1faf78b593b1e6fbfdd4846624c987/src/function/scalar/operator/arithmetic.cpp#L1102-L1110
840                Op::Div => interval_mul_f64(interval, 1. / factor),
841                _ => Err(ArrowError::InvalidArgumentError(format!(
842                    "Invalid interval arithmetic operation: Interval(MonthDayNano) {op} Float64"
843                ))),
844            }
845        }
846    ))
847}
848
849/// Perform arithmetic operation on an interval array
850fn interval_op<T: IntervalOp>(
851    op: Op,
852    l: &dyn Array,
853    l_s: bool,
854    r: &dyn Array,
855    r_s: bool,
856) -> Result<ArrayRef, ArrowError> {
857    match (op, r.data_type()) {
858        (Op::Add | Op::AddWrapping, data_type) if data_type == l.data_type() => {
859            let l = l.as_primitive::<T>();
860            let r = r.as_primitive::<T>();
861            Ok(try_op_ref!(T, l, l_s, r, r_s, T::add(l, r)))
862        }
863        (Op::Sub | Op::SubWrapping, data_type) if data_type == l.data_type() => {
864            let l = l.as_primitive::<T>();
865            let r = r.as_primitive::<T>();
866            Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub(l, r)))
867        }
868        (Op::Mul, DataType::Int64) => interval_mul_op::<T>(l, l_s, r, r_s),
869        _ => Err(ArrowError::InvalidArgumentError(format!(
870            "Invalid interval arithmetic operation: {} {op} {}",
871            l.data_type(),
872            r.data_type()
873        ))),
874    }
875}
876
877fn duration_op<T: ArrowPrimitiveType>(
878    op: Op,
879    l: &dyn Array,
880    l_s: bool,
881    r: &dyn Array,
882    r_s: bool,
883) -> Result<ArrayRef, ArrowError> {
884    let l = l.as_primitive::<T>();
885    let r = r.as_primitive::<T>();
886    match op {
887        Op::Add | Op::AddWrapping => Ok(try_op_ref!(T, l, l_s, r, r_s, l.add_checked(r))),
888        Op::Sub | Op::SubWrapping => Ok(try_op_ref!(T, l, l_s, r, r_s, l.sub_checked(r))),
889        _ => Err(ArrowError::InvalidArgumentError(format!(
890            "Invalid duration arithmetic operation: {} {op} {}",
891            l.data_type(),
892            r.data_type()
893        ))),
894    }
895}
896
897/// Perform arithmetic operation on a date array
898fn date_op<T: DateOp>(
899    op: Op,
900    l: &dyn Array,
901    l_s: bool,
902    r: &dyn Array,
903    r_s: bool,
904) -> Result<ArrayRef, ArrowError> {
905    use DataType::*;
906    use IntervalUnit::*;
907
908    const NUM_SECONDS_IN_DAY: i64 = 60 * 60 * 24;
909
910    let r_t = r.data_type();
911    match (T::DATA_TYPE, op, r_t) {
912        (Date32, Op::Sub | Op::SubWrapping, Date32) => {
913            let l = l.as_primitive::<Date32Type>();
914            let r = r.as_primitive::<Date32Type>();
915            return Ok(op_ref!(
916                DurationSecondType,
917                l,
918                l_s,
919                r,
920                r_s,
921                ((l as i64) - (r as i64)) * NUM_SECONDS_IN_DAY
922            ));
923        }
924        (Date64, Op::Sub | Op::SubWrapping, Date64) => {
925            let l = l.as_primitive::<Date64Type>();
926            let r = r.as_primitive::<Date64Type>();
927            let result = try_op_ref!(DurationMillisecondType, l, l_s, r, r_s, l.sub_checked(r));
928            return Ok(result);
929        }
930        _ => {}
931    }
932
933    let l = l.as_primitive::<T>();
934    match (op, r_t) {
935        (Op::Add | Op::AddWrapping, Interval(YearMonth)) => {
936            let r = r.as_primitive::<IntervalYearMonthType>();
937            Ok(try_op_ref!(T, l, l_s, r, r_s, T::add_year_month(l, r)))
938        }
939        (Op::Sub | Op::SubWrapping, Interval(YearMonth)) => {
940            let r = r.as_primitive::<IntervalYearMonthType>();
941            Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub_year_month(l, r)))
942        }
943
944        (Op::Add | Op::AddWrapping, Interval(DayTime)) => {
945            let r = r.as_primitive::<IntervalDayTimeType>();
946            Ok(try_op_ref!(T, l, l_s, r, r_s, T::add_day_time(l, r)))
947        }
948        (Op::Sub | Op::SubWrapping, Interval(DayTime)) => {
949            let r = r.as_primitive::<IntervalDayTimeType>();
950            Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub_day_time(l, r)))
951        }
952
953        (Op::Add | Op::AddWrapping, Interval(MonthDayNano)) => {
954            let r = r.as_primitive::<IntervalMonthDayNanoType>();
955            Ok(try_op_ref!(T, l, l_s, r, r_s, T::add_month_day_nano(l, r)))
956        }
957        (Op::Sub | Op::SubWrapping, Interval(MonthDayNano)) => {
958            let r = r.as_primitive::<IntervalMonthDayNanoType>();
959            Ok(try_op_ref!(T, l, l_s, r, r_s, T::sub_month_day_nano(l, r)))
960        }
961
962        _ => Err(ArrowError::InvalidArgumentError(format!(
963            "Invalid date arithmetic operation: {} {op} {}",
964            l.data_type(),
965            r.data_type()
966        ))),
967    }
968}
969
970/// Divides `l * 10^mul_pow` by `r` a digit at a time, without forming the scaled numerator.
971/// Used when scaling `l` would overflow `T::Native`, which it does well before the quotient
972/// does.
973///
974/// Runs on magnitudes and restores the sign last, so it truncates toward zero.
975fn scaled_div<T: DecimalType>(
976    l: T::Native,
977    r: T::Native,
978    mul_pow: i8,
979) -> Result<T::Native, ArrowError> {
980    let zero = T::Native::ZERO;
981    let negative = l.is_lt(zero) != r.is_lt(zero);
982    let dividend = abs_checked::<T>(l)?;
983    let divisor = abs_checked::<T>(r)?;
984
985    let (mut quotient, mut remainder) = dividend.div_rem_checked(divisor)?;
986    for _ in 0..mul_pow {
987        // `remainder * 10` overflows for divisors near `T::Native::MAX`, so add the remainder
988        // ten times and take the divisor off whenever the running sum reaches it.
989        let mut carried = zero;
990        let mut digit = zero;
991        for _ in 0..10 {
992            let headroom = divisor.sub_wrapping(remainder);
993            if carried.is_lt(headroom) {
994                carried = carried.add_wrapping(remainder);
995            } else {
996                carried = carried.sub_wrapping(headroom);
997                digit = digit.add_wrapping(T::Native::ONE);
998            }
999        }
1000        quotient = quotient
1001            .mul_checked(T::Native::usize_as(10))?
1002            .add_checked(digit)?;
1003        remainder = carried;
1004    }
1005
1006    if negative {
1007        quotient.neg_checked()
1008    } else {
1009        Ok(quotient)
1010    }
1011}
1012
1013fn abs_checked<T: DecimalType>(value: T::Native) -> Result<T::Native, ArrowError> {
1014    if value.is_lt(T::Native::ZERO) {
1015        value.neg_checked()
1016    } else {
1017        Ok(value)
1018    }
1019}
1020
1021/// Perform arithmetic operation on decimal arrays
1022fn decimal_op<T: DecimalType>(
1023    op: Op,
1024    l: &dyn Array,
1025    l_s: bool,
1026    r: &dyn Array,
1027    r_s: bool,
1028) -> Result<ArrayRef, ArrowError>
1029where
1030    T::Native: CheckedMul,
1031{
1032    let l = l.as_primitive::<T>();
1033    let r = r.as_primitive::<T>();
1034
1035    let (p1, s1, p2, s2) = match (l.data_type(), r.data_type()) {
1036        (DataType::Decimal32(p1, s1), DataType::Decimal32(p2, s2)) => (p1, s1, p2, s2),
1037        (DataType::Decimal64(p1, s1), DataType::Decimal64(p2, s2)) => (p1, s1, p2, s2),
1038        (DataType::Decimal128(p1, s1), DataType::Decimal128(p2, s2)) => (p1, s1, p2, s2),
1039        (DataType::Decimal256(p1, s1), DataType::Decimal256(p2, s2)) => (p1, s1, p2, s2),
1040        _ => unreachable!(),
1041    };
1042
1043    // Follow the Hive decimal arithmetic rules
1044    // https://cwiki.apache.org/confluence/download/attachments/27362075/Hive_Decimal_Precision_Scale_Support.pdf
1045    let array: PrimitiveArray<T> = match op {
1046        Op::Add | Op::AddWrapping | Op::Sub | Op::SubWrapping => {
1047            let (p1, s1, p2, s2) = (*p1 as i16, *s1 as i16, *p2 as i16, *s2 as i16);
1048            // max(s1, s2)
1049            let result_scale = s1.max(s2);
1050
1051            // max(s1, s2) + max(p1-s1, p2-s2) + 1
1052            let result_precision =
1053                (result_scale + (p1 - s1).max(p2 - s2) + 1).min(T::MAX_PRECISION as i16) as u8;
1054
1055            let l_mul = T::Native::usize_as(10).pow_checked((result_scale - s1) as _)?;
1056            let r_mul = T::Native::usize_as(10).pow_checked((result_scale - s2) as _)?;
1057
1058            match op {
1059                // Equal scales make both decimal multipliers one.
1060                Op::Add | Op::AddWrapping if s1 == s2 => {
1061                    try_op!(l, l_s, r, r_s, l.add_checked(r))
1062                }
1063                Op::Sub | Op::SubWrapping if s1 == s2 => {
1064                    try_op!(l, l_s, r, r_s, l.sub_checked(r))
1065                }
1066                Op::Add | Op::AddWrapping => {
1067                    try_op!(
1068                        l,
1069                        l_s,
1070                        r,
1071                        r_s,
1072                        l.mul_checked(l_mul)?.add_checked(r.mul_checked(r_mul)?)
1073                    )
1074                }
1075                Op::Sub | Op::SubWrapping => {
1076                    try_op!(
1077                        l,
1078                        l_s,
1079                        r,
1080                        r_s,
1081                        l.mul_checked(l_mul)?.sub_checked(r.mul_checked(r_mul)?)
1082                    )
1083                }
1084                _ => unreachable!(),
1085            }
1086            .with_precision_and_scale(result_precision, result_scale as i8)?
1087        }
1088        Op::Mul | Op::MulWrapping => {
1089            let result_precision = p1.saturating_add(p2 + 1).min(T::MAX_PRECISION);
1090            let result_scale = *s1 as i16 + *s2 as i16;
1091            if result_scale > T::MAX_SCALE as i16 {
1092                // SQL standard says that if the resulting scale of a multiply operation goes
1093                // beyond the maximum, rounding is not acceptable and thus an error occurs
1094                return Err(ArrowError::InvalidArgumentError(format!(
1095                    "Output scale of {} {op} {} would exceed max scale of {}",
1096                    l.data_type(),
1097                    r.data_type(),
1098                    T::MAX_SCALE
1099                )));
1100            }
1101            let result_scale = i8::try_from(result_scale).map_err(|_| {
1102                ArrowError::InvalidArgumentError(format!(
1103                    "Output scale of {} {op} {} would be less than min scale of {}",
1104                    l.data_type(),
1105                    r.data_type(),
1106                    i8::MIN
1107                ))
1108            })?;
1109
1110            try_op!(l, l_s, r, r_s, l.mul_checked(r))
1111                .with_precision_and_scale(result_precision, result_scale)?
1112        }
1113
1114        Op::Div => {
1115            // Follow postgres and MySQL adding a fixed scale increment of 4
1116            // s1 + 4
1117            let result_scale = s1.saturating_add(4).min(T::MAX_SCALE);
1118            let mul_pow = result_scale - s1 + s2;
1119
1120            // p1 - s1 + s2 + result_scale
1121            // Precision must be positive and at least the output scale.
1122            let result_precision = (mul_pow as i16 + *p1 as i16)
1123                .clamp(result_scale.max(1) as i16, T::MAX_PRECISION as i16)
1124                as u8;
1125
1126            let (l_mul, r_mul) = match mul_pow.cmp(&0) {
1127                Ordering::Greater => (
1128                    T::Native::usize_as(10).pow_checked(mul_pow as _)?,
1129                    T::Native::ONE,
1130                ),
1131                Ordering::Equal => (T::Native::ONE, T::Native::ONE),
1132                Ordering::Less => (
1133                    T::Native::ONE,
1134                    T::Native::usize_as(10).pow_checked(mul_pow.neg_wrapping() as _)?,
1135                ),
1136            };
1137
1138            try_op!(
1139                l,
1140                l_s,
1141                r,
1142                r_s,
1143                match l.checked_mul(&l_mul) {
1144                    Some(scaled) => scaled.div_checked(r.mul_checked(r_mul)?),
1145                    None => scaled_div::<T>(l, r, mul_pow),
1146                }
1147            )
1148            .with_precision_and_scale(result_precision, result_scale)?
1149        }
1150
1151        Op::Rem => {
1152            let (p1, s1, p2, s2) = (*p1 as i16, *s1 as i16, *p2 as i16, *s2 as i16);
1153            // max(s1, s2)
1154            let result_scale = s1.max(s2);
1155            // min(p1-s1, p2 -s2) + max( s1,s2 )
1156            let result_precision =
1157                (result_scale + (p1 - s1).min(p2 - s2)).min(T::MAX_PRECISION as i16) as u8;
1158
1159            let l_mul = T::Native::usize_as(10).pow_checked((result_scale - s1) as _)?;
1160            let r_mul = T::Native::usize_as(10).pow_checked((result_scale - s2) as _)?;
1161
1162            try_op!(
1163                l,
1164                l_s,
1165                r,
1166                r_s,
1167                l.mul_checked(l_mul)?.mod_checked(r.mul_checked(r_mul)?)
1168            )
1169            .with_precision_and_scale(result_precision, result_scale as i8)?
1170        }
1171    };
1172
1173    Ok(Arc::new(array))
1174}
1175
1176#[cfg(test)]
1177mod tests {
1178    use super::*;
1179    use arrow_array::temporal_conversions::{as_date, as_datetime};
1180    use arrow_buffer::{ScalarBuffer, i256};
1181    use chrono::{DateTime, NaiveDate};
1182
1183    // The valid date range of NaiveDate is from January 1, -262143 to December 31, 262142 (Gregorian calendar).
1184    const MAX_VALID_DATE: NaiveDate = NaiveDate::from_ymd_opt(262142, 12, 31).unwrap();
1185    const MIN_VALID_DATE: NaiveDate = NaiveDate::from_ymd_opt(-262143, 1, 1).unwrap();
1186    const MAX_VALID_MILLIS: i64 = date_to_millis(MAX_VALID_DATE);
1187    const MIN_VALID_MILLIS: i64 = date_to_millis(MIN_VALID_DATE);
1188    const MAX_VALID_DAYS: i32 = date_to_days(MAX_VALID_DATE);
1189    const MIN_VALID_DAYS: i32 = date_to_days(MIN_VALID_DATE);
1190    const EPOCH: NaiveDate = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
1191    const YEAR_2000: NaiveDate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
1192
1193    const fn date_to_millis(date: NaiveDate) -> i64 {
1194        date.signed_duration_since(EPOCH).num_milliseconds()
1195    }
1196
1197    const fn date_to_days(date: NaiveDate) -> i32 {
1198        date.signed_duration_since(EPOCH).num_days() as i32
1199    }
1200
1201    fn test_neg_primitive<T: ArrowPrimitiveType>(
1202        input: &[T::Native],
1203        out: Result<&[T::Native], &str>,
1204    ) {
1205        let a = PrimitiveArray::<T>::new(ScalarBuffer::from(input.to_vec()), None);
1206        match out {
1207            Ok(expected) => {
1208                let result = neg(&a).unwrap();
1209                assert_eq!(result.as_primitive::<T>().values(), expected);
1210            }
1211            Err(e) => {
1212                let err = neg(&a).unwrap_err().to_string();
1213                assert_eq!(e, err);
1214            }
1215        }
1216    }
1217
1218    #[test]
1219    fn test_neg() {
1220        let input = &[1, -5, 2, 693, 3929];
1221        let output = &[-1, 5, -2, -693, -3929];
1222        test_neg_primitive::<Int32Type>(input, Ok(output));
1223
1224        let input = &[1, -5, 2, 693, 3929];
1225        let output = &[-1, 5, -2, -693, -3929];
1226        test_neg_primitive::<Int64Type>(input, Ok(output));
1227        test_neg_primitive::<DurationSecondType>(input, Ok(output));
1228        test_neg_primitive::<DurationMillisecondType>(input, Ok(output));
1229        test_neg_primitive::<DurationMicrosecondType>(input, Ok(output));
1230        test_neg_primitive::<DurationNanosecondType>(input, Ok(output));
1231
1232        let input = &[f32::MAX, f32::MIN, f32::INFINITY, 1.3, 0.5];
1233        let output = &[f32::MIN, f32::MAX, f32::NEG_INFINITY, -1.3, -0.5];
1234        test_neg_primitive::<Float32Type>(input, Ok(output));
1235
1236        test_neg_primitive::<Int32Type>(
1237            &[i32::MIN],
1238            Err("Arithmetic overflow: Overflow happened on: - -2147483648"),
1239        );
1240        test_neg_primitive::<Int64Type>(
1241            &[i64::MIN],
1242            Err("Arithmetic overflow: Overflow happened on: - -9223372036854775808"),
1243        );
1244        test_neg_primitive::<DurationSecondType>(
1245            &[i64::MIN],
1246            Err("Arithmetic overflow: Overflow happened on: - -9223372036854775808"),
1247        );
1248
1249        let r = neg_wrapping(&Int32Array::from(vec![i32::MIN])).unwrap();
1250        assert_eq!(r.as_primitive::<Int32Type>().value(0), i32::MIN);
1251
1252        let r = neg_wrapping(&Int64Array::from(vec![i64::MIN])).unwrap();
1253        assert_eq!(r.as_primitive::<Int64Type>().value(0), i64::MIN);
1254
1255        let err = neg_wrapping(&DurationSecondArray::from(vec![i64::MIN]))
1256            .unwrap_err()
1257            .to_string();
1258
1259        assert_eq!(
1260            err,
1261            "Arithmetic overflow: Overflow happened on: - -9223372036854775808"
1262        );
1263
1264        let a = Decimal32Array::from(vec![1, 3, -44, 2, 4])
1265            .with_precision_and_scale(9, 6)
1266            .unwrap();
1267
1268        let r = neg(&a).unwrap();
1269        assert_eq!(r.data_type(), a.data_type());
1270        assert_eq!(
1271            r.as_primitive::<Decimal32Type>().values(),
1272            &[-1, -3, 44, -2, -4]
1273        );
1274
1275        let a = Decimal64Array::from(vec![1, 3, -44, 2, 4])
1276            .with_precision_and_scale(9, 6)
1277            .unwrap();
1278
1279        let r = neg(&a).unwrap();
1280        assert_eq!(r.data_type(), a.data_type());
1281        assert_eq!(
1282            r.as_primitive::<Decimal64Type>().values(),
1283            &[-1, -3, 44, -2, -4]
1284        );
1285
1286        let a = Decimal128Array::from(vec![1, 3, -44, 2, 4])
1287            .with_precision_and_scale(9, 6)
1288            .unwrap();
1289
1290        let r = neg(&a).unwrap();
1291        assert_eq!(r.data_type(), a.data_type());
1292        assert_eq!(
1293            r.as_primitive::<Decimal128Type>().values(),
1294            &[-1, -3, 44, -2, -4]
1295        );
1296
1297        let a = Decimal256Array::from(vec![
1298            i256::from_i128(342),
1299            i256::from_i128(-4949),
1300            i256::from_i128(3),
1301        ])
1302        .with_precision_and_scale(9, 6)
1303        .unwrap();
1304
1305        let r = neg(&a).unwrap();
1306        assert_eq!(r.data_type(), a.data_type());
1307        assert_eq!(
1308            r.as_primitive::<Decimal256Type>().values(),
1309            &[
1310                i256::from_i128(-342),
1311                i256::from_i128(4949),
1312                i256::from_i128(-3),
1313            ]
1314        );
1315
1316        let a = IntervalYearMonthArray::from(vec![
1317            IntervalYearMonthType::make_value(2, 4),
1318            IntervalYearMonthType::make_value(2, -4),
1319            IntervalYearMonthType::make_value(-3, -5),
1320        ]);
1321        let r = neg(&a).unwrap();
1322        assert_eq!(
1323            r.as_primitive::<IntervalYearMonthType>().values(),
1324            &[
1325                IntervalYearMonthType::make_value(-2, -4),
1326                IntervalYearMonthType::make_value(-2, 4),
1327                IntervalYearMonthType::make_value(3, 5),
1328            ]
1329        );
1330
1331        let a = IntervalDayTimeArray::from(vec![
1332            IntervalDayTimeType::make_value(2, 4),
1333            IntervalDayTimeType::make_value(2, -4),
1334            IntervalDayTimeType::make_value(-3, -5),
1335        ]);
1336        let r = neg(&a).unwrap();
1337        assert_eq!(
1338            r.as_primitive::<IntervalDayTimeType>().values(),
1339            &[
1340                IntervalDayTimeType::make_value(-2, -4),
1341                IntervalDayTimeType::make_value(-2, 4),
1342                IntervalDayTimeType::make_value(3, 5),
1343            ]
1344        );
1345
1346        let a = IntervalMonthDayNanoArray::from(vec![
1347            IntervalMonthDayNanoType::make_value(2, 4, 5953394),
1348            IntervalMonthDayNanoType::make_value(2, -4, -45839),
1349            IntervalMonthDayNanoType::make_value(-3, -5, 6944),
1350        ]);
1351        let r = neg(&a).unwrap();
1352        assert_eq!(
1353            r.as_primitive::<IntervalMonthDayNanoType>().values(),
1354            &[
1355                IntervalMonthDayNanoType::make_value(-2, -4, -5953394),
1356                IntervalMonthDayNanoType::make_value(-2, 4, 45839),
1357                IntervalMonthDayNanoType::make_value(3, 5, -6944),
1358            ]
1359        );
1360    }
1361
1362    #[test]
1363    fn test_integer() {
1364        let a = Int32Array::from(vec![4, 3, 5, -6, 100]);
1365        let b = Int32Array::from(vec![6, 2, 5, -7, 3]);
1366        let result = add(&a, &b).unwrap();
1367        assert_eq!(
1368            result.as_ref(),
1369            &Int32Array::from(vec![10, 5, 10, -13, 103])
1370        );
1371        let result = sub(&a, &b).unwrap();
1372        assert_eq!(result.as_ref(), &Int32Array::from(vec![-2, 1, 0, 1, 97]));
1373        let result = div(&a, &b).unwrap();
1374        assert_eq!(result.as_ref(), &Int32Array::from(vec![0, 1, 1, 0, 33]));
1375        let result = mul(&a, &b).unwrap();
1376        assert_eq!(result.as_ref(), &Int32Array::from(vec![24, 6, 25, 42, 300]));
1377        let result = rem(&a, &b).unwrap();
1378        assert_eq!(result.as_ref(), &Int32Array::from(vec![4, 1, 0, -6, 1]));
1379
1380        let a = Int8Array::from(vec![Some(2), None, Some(45)]);
1381        let b = Int8Array::from(vec![Some(5), Some(3), None]);
1382        let result = add(&a, &b).unwrap();
1383        assert_eq!(result.as_ref(), &Int8Array::from(vec![Some(7), None, None]));
1384
1385        let a = UInt8Array::from(vec![56, 5, 3]);
1386        let b = UInt8Array::from(vec![200, 2, 5]);
1387        let err = add(&a, &b).unwrap_err().to_string();
1388        assert_eq!(err, "Arithmetic overflow: Overflow happened on: 56 + 200");
1389        let result = add_wrapping(&a, &b).unwrap();
1390        assert_eq!(result.as_ref(), &UInt8Array::from(vec![0, 7, 8]));
1391
1392        let a = UInt8Array::from(vec![34, 5, 3]);
1393        let b = UInt8Array::from(vec![200, 2, 5]);
1394        let err = sub(&a, &b).unwrap_err().to_string();
1395        assert_eq!(err, "Arithmetic overflow: Overflow happened on: 34 - 200");
1396        let result = sub_wrapping(&a, &b).unwrap();
1397        assert_eq!(result.as_ref(), &UInt8Array::from(vec![90, 3, 254]));
1398
1399        let a = UInt8Array::from(vec![34, 5, 3]);
1400        let b = UInt8Array::from(vec![200, 2, 5]);
1401        let err = mul(&a, &b).unwrap_err().to_string();
1402        assert_eq!(err, "Arithmetic overflow: Overflow happened on: 34 * 200");
1403        let result = mul_wrapping(&a, &b).unwrap();
1404        assert_eq!(result.as_ref(), &UInt8Array::from(vec![144, 10, 15]));
1405
1406        let a = Int16Array::from(vec![i16::MIN]);
1407        let b = Int16Array::from(vec![-1]);
1408        let err = div(&a, &b).unwrap_err().to_string();
1409        assert_eq!(
1410            err,
1411            "Arithmetic overflow: Overflow happened on: -32768 / -1"
1412        );
1413
1414        let a = Int16Array::from(vec![i16::MIN]);
1415        let b = Int16Array::from(vec![-1]);
1416        let result = rem(&a, &b).unwrap();
1417        assert_eq!(result.as_ref(), &Int16Array::from(vec![0]));
1418
1419        let a = Int16Array::from(vec![21]);
1420        let b = Int16Array::from(vec![0]);
1421        let err = div(&a, &b).unwrap_err().to_string();
1422        assert_eq!(err, "Divide by zero error");
1423
1424        let a = Int16Array::from(vec![21]);
1425        let b = Int16Array::from(vec![0]);
1426        let err = rem(&a, &b).unwrap_err().to_string();
1427        assert_eq!(err, "Divide by zero error");
1428    }
1429
1430    #[test]
1431    fn test_float() {
1432        let a = Float32Array::from(vec![1., f32::MAX, 6., -4., -1., 0.]);
1433        let b = Float32Array::from(vec![1., f32::MAX, f32::MAX, -3., 45., 0.]);
1434        let result = add(&a, &b).unwrap();
1435        assert_eq!(
1436            result.as_ref(),
1437            &Float32Array::from(vec![2., f32::INFINITY, f32::MAX, -7., 44.0, 0.])
1438        );
1439
1440        let result = sub(&a, &b).unwrap();
1441        assert_eq!(
1442            result.as_ref(),
1443            &Float32Array::from(vec![0., 0., f32::MIN, -1., -46., 0.])
1444        );
1445
1446        let result = mul(&a, &b).unwrap();
1447        assert_eq!(
1448            result.as_ref(),
1449            &Float32Array::from(vec![1., f32::INFINITY, f32::INFINITY, 12., -45., 0.])
1450        );
1451
1452        let result = div(&a, &b).unwrap();
1453        let r = result.as_primitive::<Float32Type>();
1454        assert_eq!(r.value(0), 1.);
1455        assert_eq!(r.value(1), 1.);
1456        assert!(r.value(2) < f32::EPSILON);
1457        assert_eq!(r.value(3), -4. / -3.);
1458        assert!(r.value(5).is_nan());
1459
1460        let result = rem(&a, &b).unwrap();
1461        let r = result.as_primitive::<Float32Type>();
1462        assert_eq!(&r.values()[..5], &[0., 0., 6., -1., -1.]);
1463        assert!(r.value(5).is_nan());
1464    }
1465
1466    #[test]
1467    fn test_decimal() {
1468        // 0.015 7.842 -0.577 0.334 -0.078 0.003
1469        let a = Decimal128Array::from(vec![15, 0, -577, 334, -78, 3])
1470            .with_precision_and_scale(12, 3)
1471            .unwrap();
1472
1473        // 5.4 0 -35.6 0.3 0.6 7.45
1474        let b = Decimal128Array::from(vec![54, 34, -356, 3, 6, 745])
1475            .with_precision_and_scale(12, 1)
1476            .unwrap();
1477
1478        let result = add(&a, &b).unwrap();
1479        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
1480        assert_eq!(
1481            result.as_primitive::<Decimal128Type>().values(),
1482            &[5415, 3400, -36177, 634, 522, 74503]
1483        );
1484
1485        let result = sub(&a, &b).unwrap();
1486        assert_eq!(result.data_type(), &DataType::Decimal128(15, 3));
1487        assert_eq!(
1488            result.as_primitive::<Decimal128Type>().values(),
1489            &[-5385, -3400, 35023, 34, -678, -74497]
1490        );
1491
1492        let result = mul(&a, &b).unwrap();
1493        assert_eq!(result.data_type(), &DataType::Decimal128(25, 4));
1494        assert_eq!(
1495            result.as_primitive::<Decimal128Type>().values(),
1496            &[810, 0, 205412, 1002, -468, 2235]
1497        );
1498
1499        let result = div(&a, &b).unwrap();
1500        assert_eq!(result.data_type(), &DataType::Decimal128(17, 7));
1501        assert_eq!(
1502            result.as_primitive::<Decimal128Type>().values(),
1503            &[27777, 0, 162078, 11133333, -1300000, 402]
1504        );
1505
1506        let result = rem(&a, &b).unwrap();
1507        assert_eq!(result.data_type(), &DataType::Decimal128(12, 3));
1508        assert_eq!(
1509            result.as_primitive::<Decimal128Type>().values(),
1510            &[15, 0, -577, 34, -78, 3]
1511        );
1512
1513        let a = Decimal128Array::from(vec![1])
1514            .with_precision_and_scale(3, 3)
1515            .unwrap();
1516        let b = Decimal128Array::from(vec![1])
1517            .with_precision_and_scale(37, 37)
1518            .unwrap();
1519        let err = mul(&a, &b).unwrap_err().to_string();
1520        assert_eq!(
1521            err,
1522            "Invalid argument error: Output scale of Decimal128(3, 3) * Decimal128(37, 37) would exceed max scale of 38"
1523        );
1524
1525        let a = Decimal128Array::from(vec![1])
1526            .with_precision_and_scale(3, -2)
1527            .unwrap();
1528        let err = add(&a, &b).unwrap_err().to_string();
1529        assert_eq!(err, "Arithmetic overflow: Overflow happened on: 10 ^ 39");
1530
1531        let a = Decimal128Array::from(vec![10])
1532            .with_precision_and_scale(3, -1)
1533            .unwrap();
1534        let err = add(&a, &b).unwrap_err().to_string();
1535        assert_eq!(
1536            err,
1537            "Arithmetic overflow: Overflow happened on: 10 * 100000000000000000000000000000000000000"
1538        );
1539
1540        let b = Decimal128Array::from(vec![0])
1541            .with_precision_and_scale(1, 1)
1542            .unwrap();
1543        let err = div(&a, &b).unwrap_err().to_string();
1544        assert_eq!(err, "Divide by zero error");
1545        let err = rem(&a, &b).unwrap_err().to_string();
1546        assert_eq!(err, "Divide by zero error");
1547    }
1548
1549    #[test]
1550    fn test_decimal256_add_sub_negative_scale_metadata() {
1551        let a = Decimal256Array::from(vec![Some(i256::ONE), Some(i256::MINUS_ONE), None])
1552            .with_precision_and_scale(76, -52)
1553            .unwrap();
1554        let b = Decimal256Array::from(vec![i256::from_i128(2), i256::ONE, i256::ONE])
1555            .with_precision_and_scale(76, -52)
1556            .unwrap();
1557        let expected =
1558            Decimal256Array::from(vec![Some(i256::from_i128(3)), Some(i256::ZERO), None])
1559                .with_precision_and_scale(76, -52)
1560                .unwrap();
1561        assert_eq!(add(&a, &b).unwrap().as_ref(), &expected);
1562
1563        let expected =
1564            Decimal256Array::from(vec![Some(i256::MINUS_ONE), Some(i256::from_i128(-2)), None])
1565                .with_precision_and_scale(76, -52)
1566                .unwrap();
1567        assert_eq!(sub(&a, &b).unwrap().as_ref(), &expected);
1568    }
1569
1570    #[test]
1571    fn test_decimal256_add_sub_minimum_scale() {
1572        let a = Decimal256Array::from(vec![i256::ONE])
1573            .with_precision_and_scale(20, i8::MIN)
1574            .unwrap();
1575        let b = Decimal256Array::from(vec![i256::from_i128(2)])
1576            .with_precision_and_scale(20, i8::MIN)
1577            .unwrap();
1578        let expected = Decimal256Array::from(vec![i256::from_i128(3)])
1579            .with_precision_and_scale(21, i8::MIN)
1580            .unwrap();
1581        assert_eq!(add(&a, &b).unwrap().as_ref(), &expected);
1582
1583        let expected = Decimal256Array::from(vec![i256::MINUS_ONE])
1584            .with_precision_and_scale(21, i8::MIN)
1585            .unwrap();
1586        assert_eq!(sub(&a, &b).unwrap().as_ref(), &expected);
1587    }
1588
1589    #[test]
1590    fn test_decimal256_remainder_negative_scale_metadata() {
1591        let a = Decimal256Array::from(vec![Some(i256::ONE), Some(i256::MINUS_ONE), None])
1592            .with_precision_and_scale(76, -52)
1593            .unwrap();
1594        let b = Decimal256Array::from(vec![i256::from_i128(2), i256::ONE, i256::ONE])
1595            .with_precision_and_scale(76, -52)
1596            .unwrap();
1597        let expected = Decimal256Array::from(vec![Some(i256::ONE), Some(i256::ZERO), None])
1598            .with_precision_and_scale(76, -52)
1599            .unwrap();
1600        assert_eq!(rem(&a, &b).unwrap().as_ref(), &expected);
1601    }
1602
1603    #[test]
1604    fn test_decimal256_adjacent_minimum_scales() {
1605        let a = Decimal256Array::from(vec![i256::ONE])
1606            .with_precision_and_scale(20, i8::MIN)
1607            .unwrap();
1608        let b = Decimal256Array::from(vec![i256::from_i128(2)])
1609            .with_precision_and_scale(20, i8::MIN + 1)
1610            .unwrap();
1611        let expected = Decimal256Array::from(vec![i256::from_i128(12)])
1612            .with_precision_and_scale(22, -127)
1613            .unwrap();
1614        assert_eq!(add(&a, &b).unwrap().as_ref(), &expected);
1615
1616        let expected = Decimal256Array::from(vec![i256::from_i128(8)])
1617            .with_precision_and_scale(22, -127)
1618            .unwrap();
1619        assert_eq!(sub(&a, &b).unwrap().as_ref(), &expected);
1620
1621        let expected = Decimal256Array::from(vec![i256::ZERO])
1622            .with_precision_and_scale(20, -127)
1623            .unwrap();
1624        assert_eq!(rem(&a, &b).unwrap().as_ref(), &expected);
1625    }
1626
1627    #[test]
1628    fn test_decimal256_extreme_scale_difference_overflow() {
1629        let a = Decimal256Array::from(vec![i256::ONE])
1630            .with_precision_and_scale(20, i8::MIN)
1631            .unwrap();
1632        let b = Decimal256Array::from(vec![i256::from_i128(2)])
1633            .with_precision_and_scale(76, 76)
1634            .unwrap();
1635        let expected = "Arithmetic overflow: Overflow happened on: 10 ^ 204";
1636        assert_eq!(add(&a, &b).unwrap_err().to_string(), expected);
1637        assert_eq!(sub(&a, &b).unwrap_err().to_string(), expected);
1638        assert_eq!(rem(&a, &b).unwrap_err().to_string(), expected);
1639    }
1640
1641    #[test]
1642    fn test_decimal256_multiply_minimum_scale() {
1643        let a = Decimal256Array::from(vec![i256::ONE])
1644            .with_precision_and_scale(76, -64)
1645            .unwrap();
1646        let expected = Decimal256Array::from(vec![i256::ONE])
1647            .with_precision_and_scale(76, i8::MIN)
1648            .unwrap();
1649        assert_eq!(mul(&a, &a).unwrap().as_ref(), &expected);
1650
1651        let b = a.clone().with_precision_and_scale(76, -65).unwrap();
1652        assert_eq!(
1653            mul(&a, &b).unwrap_err().to_string(),
1654            "Invalid argument error: Output scale of Decimal256(76, -64) * Decimal256(76, -65) would be less than min scale of -128"
1655        );
1656    }
1657
1658    #[test]
1659    fn test_decimal_div_precision_at_least_scale() {
1660        fn check<T: DecimalType>()
1661        where
1662            T::Native: From<i32>,
1663        {
1664            let a: PrimitiveArray<T> = [Some(1), Some(-1), Some(0), None]
1665                .into_iter()
1666                .map(|v| v.map(T::Native::from))
1667                .collect();
1668            let a = a.with_precision_and_scale(1, 1).unwrap();
1669            for (scale, coefficient) in [(0, 10000), (-1, 1000), (-4, 1), (-5, 0), (-6, 0)] {
1670                let b = PrimitiveArray::<T>::from_iter_values(
1671                    [1, 1, 1, 0].into_iter().map(T::Native::from),
1672                )
1673                .with_precision_and_scale(1, scale)
1674                .unwrap();
1675                let expected: PrimitiveArray<T> =
1676                    [Some(coefficient), Some(-coefficient), Some(0), None]
1677                        .into_iter()
1678                        .map(|v| v.map(T::Native::from))
1679                        .collect();
1680                let expected = expected.with_precision_and_scale(5, 5).unwrap();
1681                assert_eq!(div(&a, &b).unwrap().as_ref(), &expected);
1682            }
1683        }
1684        check::<Decimal32Type>();
1685        check::<Decimal64Type>();
1686        check::<Decimal128Type>();
1687        check::<Decimal256Type>();
1688    }
1689
1690    #[test]
1691    fn test_decimal_div_precision_at_least_one() {
1692        fn check<T: DecimalType>()
1693        where
1694            T::Native: From<i32>,
1695        {
1696            for scale in [-4, -5] {
1697                let a: PrimitiveArray<T> = [Some(1), Some(-1), Some(0), None]
1698                    .into_iter()
1699                    .map(|v| v.map(T::Native::from))
1700                    .collect();
1701                let a = a.with_precision_and_scale(1, scale).unwrap();
1702                for (divisor_scale, coefficient) in [(-4, 1), (-5, 0), (-6, 0)] {
1703                    let b = PrimitiveArray::<T>::from_iter_values(
1704                        [1, 1, 1, 0].into_iter().map(T::Native::from),
1705                    )
1706                    .with_precision_and_scale(1, divisor_scale)
1707                    .unwrap();
1708                    let expected: PrimitiveArray<T> =
1709                        [Some(coefficient), Some(-coefficient), Some(0), None]
1710                            .into_iter()
1711                            .map(|v| v.map(T::Native::from))
1712                            .collect();
1713                    let expected = expected.with_precision_and_scale(1, scale + 4).unwrap();
1714                    assert_eq!(div(&a, &b).unwrap().as_ref(), &expected);
1715                }
1716            }
1717        }
1718        check::<Decimal32Type>();
1719        check::<Decimal64Type>();
1720        check::<Decimal128Type>();
1721        check::<Decimal256Type>();
1722    }
1723
1724    #[test]
1725    fn test_decimal_div_scaling_overflow_boundary() {
1726        // `div` scales `l` by 10^6, which overflows just past `MAX / 10^6` and `MIN / 10^6`.
1727        // Dividing by 10^6 returns each value, on either side of the boundary.
1728        fn check<T: DecimalType>() {
1729            let one = T::Native::ONE;
1730            let pow = T::Native::usize_as(1_000_000);
1731            let max = T::Native::MAX_TOTAL_ORDER.div_wrapping(pow);
1732            let min = T::Native::MIN_TOTAL_ORDER.div_wrapping(pow);
1733            let values = [
1734                max,
1735                max.add_wrapping(one),
1736                min,
1737                min.sub_wrapping(one),
1738                T::Native::MAX_TOTAL_ORDER,
1739                T::Native::MIN_TOTAL_ORDER.add_wrapping(one),
1740            ];
1741            let a = PrimitiveArray::<T>::from_iter_values(values)
1742                .with_precision_and_scale(T::MAX_PRECISION, 2)
1743                .unwrap();
1744            for (divisor, negate) in [(pow, false), (pow.neg_wrapping(), true)] {
1745                let b = PrimitiveArray::<T>::from_iter_values([divisor])
1746                    .with_precision_and_scale(T::MAX_PRECISION, 2)
1747                    .unwrap();
1748                let result = div(&a, &Scalar::new(b)).unwrap();
1749                let expected = values.map(|v| if negate { v.neg_wrapping() } else { v });
1750                assert_eq!(result.as_primitive::<T>().values().as_ref(), expected);
1751            }
1752        }
1753        check::<Decimal32Type>();
1754        check::<Decimal64Type>();
1755        check::<Decimal128Type>();
1756        check::<Decimal256Type>();
1757    }
1758
1759    #[test]
1760    fn test_decimal256_div_wide_intermediate() {
1761        // Dividing two scale-37 values needs l * 10^41, which is 79 digits and does not
1762        // fit in an i256, even though the 41-digit quotient does.
1763        let a = Decimal256Array::from(vec![i256::from_i128(
1764            60096743305738933273387748827369321010i128,
1765        )])
1766        .with_precision_and_scale(38, 37)
1767        .unwrap();
1768        let b = Decimal256Array::from(vec![i256::from_i128(
1769            60096763826458053191384497987259478584i128,
1770        )])
1771        .with_precision_and_scale(38, 37)
1772        .unwrap();
1773
1774        let result = div(&a, &b).unwrap();
1775        assert_eq!(result.data_type(), &DataType::Decimal256(76, 41));
1776        assert_eq!(
1777            result.as_primitive::<Decimal256Type>().value(0),
1778            i256::from_string("99999965853869970143724273117679321341339").unwrap()
1779        );
1780
1781        // Truncation stays toward zero on either side of the fallback.
1782        let neg_a = neg(&a).unwrap();
1783        let result = div(neg_a.as_primitive::<Decimal256Type>(), &b).unwrap();
1784        assert_eq!(
1785            result.as_primitive::<Decimal256Type>().value(0),
1786            i256::from_string("-99999965853869970143724273117679321341339").unwrap()
1787        );
1788
1789        let neg_b = neg(&b).unwrap();
1790        let result = div(&a, neg_b.as_primitive::<Decimal256Type>()).unwrap();
1791        assert_eq!(
1792            result.as_primitive::<Decimal256Type>().value(0),
1793            i256::from_string("-99999965853869970143724273117679321341339").unwrap()
1794        );
1795
1796        let zero = Decimal256Array::from(vec![i256::ZERO])
1797            .with_precision_and_scale(38, 37)
1798            .unwrap();
1799        let err = div(&a, &zero).unwrap_err().to_string();
1800        assert_eq!(err, "Divide by zero error");
1801    }
1802
1803    #[test]
1804    fn test_decimal256_div_divisor_near_max() {
1805        // A divisor past i256::MAX / 10 leaves no room to scale the running remainder either.
1806        let a = Decimal256Array::from(vec![
1807            i256::from_string(
1808                "5900000000000000000000000000000000000000000000000000000000000000000000000000",
1809            )
1810            .unwrap(),
1811        ])
1812        .with_precision_and_scale(76, 37)
1813        .unwrap();
1814        let b = Decimal256Array::from(vec![
1815            i256::from_string(
1816                "6000000000000000000000000000000000000000000000000000000000000000000000000000",
1817            )
1818            .unwrap(),
1819        ])
1820        .with_precision_and_scale(76, 37)
1821        .unwrap();
1822
1823        let result = div(&a, &b).unwrap();
1824        assert_eq!(
1825            result.as_primitive::<Decimal256Type>().value(0),
1826            i256::from_string("98333333333333333333333333333333333333333").unwrap()
1827        );
1828    }
1829
1830    #[test]
1831    fn test_decimal128_div_wide_intermediate() {
1832        // Same overflow one type down: 3.0 / 6.0 at scale 37 needs l * 10^38, 76 digits in i128.
1833        let a = Decimal128Array::from(vec![30000000000000000000000000000000000000i128])
1834            .with_precision_and_scale(38, 37)
1835            .unwrap();
1836        let b = Decimal128Array::from(vec![60000000000000000000000000000000000000i128])
1837            .with_precision_and_scale(38, 37)
1838            .unwrap();
1839
1840        let result = div(&a, &b).unwrap();
1841        assert_eq!(result.data_type(), &DataType::Decimal128(38, 38));
1842        assert_eq!(
1843            result.as_primitive::<Decimal128Type>().value(0),
1844            50000000000000000000000000000000000000i128
1845        );
1846    }
1847
1848    #[test]
1849    fn test_scaled_div_agrees_with_direct_division() {
1850        for (l, r, mul_pow) in [
1851            (7i128, 3i128, 4i8),
1852            (-7, 3, 4),
1853            (7, -3, 4),
1854            (-7, -3, 4),
1855            (1, 999_999_999, 9),
1856            (i128::MAX / 10, 7, 1),
1857            (i128::MAX / 10, -i128::MAX / 11, 1),
1858            (0, 5, 6),
1859        ] {
1860            let scaled = l * 10i128.pow(mul_pow as u32);
1861            assert_eq!(
1862                scaled_div::<Decimal128Type>(l, r, mul_pow).unwrap(),
1863                scaled / r,
1864                "{l} * 10^{mul_pow} / {r}"
1865            );
1866        }
1867    }
1868
1869    #[test]
1870    fn test_decimal256_same_scale_add_sub() {
1871        let lhs = Decimal256Array::from(vec![
1872            Some(i256::from_parts(u128::MAX, 0)),
1873            Some(i256::MINUS_ONE),
1874            None,
1875        ])
1876        .with_precision_and_scale(70, 2)
1877        .unwrap();
1878        let rhs = Decimal256Array::from(vec![Some(i256::ONE), Some(i256::ONE), Some(i256::MAX)])
1879            .with_precision_and_scale(70, 2)
1880            .unwrap();
1881
1882        let expected =
1883            Decimal256Array::from(vec![Some(i256::from_parts(0, 1)), Some(i256::ZERO), None])
1884                .with_precision_and_scale(71, 2)
1885                .unwrap();
1886        for operation in [add, add_wrapping] {
1887            let result = operation(&lhs, &rhs).unwrap();
1888            assert_eq!(result.as_primitive::<Decimal256Type>(), &expected);
1889        }
1890
1891        let expected = Decimal256Array::from(vec![
1892            Some(i256::from_parts(u128::MAX - 1, 0)),
1893            Some(i256::from_i128(-2)),
1894            None,
1895        ])
1896        .with_precision_and_scale(71, 2)
1897        .unwrap();
1898        for operation in [sub, sub_wrapping] {
1899            let result = operation(&lhs, &rhs).unwrap();
1900            assert_eq!(result.as_primitive::<Decimal256Type>(), &expected);
1901        }
1902
1903        let lhs = Decimal256Array::from(vec![i256::MAX])
1904            .with_precision_and_scale(76, 0)
1905            .unwrap();
1906        let rhs = Decimal256Array::from(vec![i256::ONE])
1907            .with_precision_and_scale(76, 0)
1908            .unwrap();
1909        for operation in [add, add_wrapping] {
1910            assert_eq!(
1911                operation(&lhs, &rhs).unwrap_err().to_string(),
1912                format!(
1913                    "Arithmetic overflow: Overflow happened on: {:?} + {:?}",
1914                    i256::MAX,
1915                    i256::ONE
1916                )
1917            );
1918        }
1919
1920        let lhs = Decimal256Array::from(vec![i256::MIN])
1921            .with_precision_and_scale(76, 0)
1922            .unwrap();
1923        for operation in [sub, sub_wrapping] {
1924            assert_eq!(
1925                operation(&lhs, &rhs).unwrap_err().to_string(),
1926                format!(
1927                    "Arithmetic overflow: Overflow happened on: {:?} - {:?}",
1928                    i256::MIN,
1929                    i256::ONE
1930                )
1931            );
1932        }
1933    }
1934
1935    fn test_timestamp_impl<T: TimestampOp>() {
1936        let a = PrimitiveArray::<T>::new(vec![2000000, 434030324, 53943340].into(), None);
1937        let b = PrimitiveArray::<T>::new(vec![329593, 59349, 694994].into(), None);
1938
1939        let result = sub(&a, &b).unwrap();
1940        assert_eq!(
1941            result.as_primitive::<T::Duration>().values(),
1942            &[1670407, 433970975, 53248346]
1943        );
1944
1945        let r2 = add(&b, &result.as_ref()).unwrap();
1946        assert_eq!(r2.as_ref(), &a);
1947
1948        let r3 = add(&result.as_ref(), &b).unwrap();
1949        assert_eq!(r3.as_ref(), &a);
1950
1951        let format_array = |x: &dyn Array| -> Vec<String> {
1952            x.as_primitive::<T>()
1953                .values()
1954                .into_iter()
1955                .map(|x| as_datetime::<T>(*x).unwrap().to_string())
1956                .collect()
1957        };
1958
1959        let values = vec![
1960            "1970-01-01T00:00:00Z",
1961            "2010-04-01T04:00:20Z",
1962            "1960-01-30T04:23:20Z",
1963        ]
1964        .into_iter()
1965        .map(|x| {
1966            T::from_naive_datetime(DateTime::parse_from_rfc3339(x).unwrap().naive_utc(), None)
1967                .unwrap()
1968        })
1969        .collect();
1970
1971        let a = PrimitiveArray::<T>::new(values, None);
1972        let b = IntervalYearMonthArray::from(vec![
1973            IntervalYearMonthType::make_value(5, 34),
1974            IntervalYearMonthType::make_value(-2, 4),
1975            IntervalYearMonthType::make_value(7, -4),
1976        ]);
1977        let r4 = add(&a, &b).unwrap();
1978        assert_eq!(
1979            &format_array(r4.as_ref()),
1980            &[
1981                "1977-11-01 00:00:00".to_string(),
1982                "2008-08-01 04:00:20".to_string(),
1983                "1966-09-30 04:23:20".to_string()
1984            ]
1985        );
1986
1987        let r5 = sub(&r4, &b).unwrap();
1988        assert_eq!(r5.as_ref(), &a);
1989
1990        let b = IntervalDayTimeArray::from(vec![
1991            IntervalDayTimeType::make_value(5, 454000),
1992            IntervalDayTimeType::make_value(-34, 0),
1993            IntervalDayTimeType::make_value(7, -4000),
1994        ]);
1995        let r6 = add(&a, &b).unwrap();
1996        assert_eq!(
1997            &format_array(r6.as_ref()),
1998            &[
1999                "1970-01-06 00:07:34".to_string(),
2000                "2010-02-26 04:00:20".to_string(),
2001                "1960-02-06 04:23:16".to_string()
2002            ]
2003        );
2004
2005        let r7 = sub(&r6, &b).unwrap();
2006        assert_eq!(r7.as_ref(), &a);
2007
2008        let b = IntervalMonthDayNanoArray::from(vec![
2009            IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000),
2010            IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000),
2011            IntervalMonthDayNanoType::make_value(5, 2, 493_000_000_000),
2012        ]);
2013        let r8 = add(&a, &b).unwrap();
2014        assert_eq!(
2015            &format_array(r8.as_ref()),
2016            &[
2017                "1998-10-04 23:59:17".to_string(),
2018                "1960-09-29 04:00:33".to_string(),
2019                "1960-07-02 04:31:33".to_string()
2020            ]
2021        );
2022
2023        let r9 = sub(&r8, &b).unwrap();
2024        // Note: subtraction is not the inverse of addition for intervals
2025        assert_eq!(
2026            &format_array(r9.as_ref()),
2027            &[
2028                "1970-01-02 00:00:00".to_string(),
2029                "2010-04-02 04:00:20".to_string(),
2030                "1960-01-31 04:23:20".to_string()
2031            ]
2032        );
2033    }
2034
2035    #[test]
2036    fn test_timestamp() {
2037        test_timestamp_impl::<TimestampSecondType>();
2038        test_timestamp_impl::<TimestampMillisecondType>();
2039        test_timestamp_impl::<TimestampMicrosecondType>();
2040        test_timestamp_impl::<TimestampNanosecondType>();
2041    }
2042
2043    #[test]
2044    fn test_interval() {
2045        let a = IntervalYearMonthArray::from(vec![
2046            IntervalYearMonthType::make_value(32, 4),
2047            IntervalYearMonthType::make_value(32, 4),
2048        ]);
2049        let b = IntervalYearMonthArray::from(vec![
2050            IntervalYearMonthType::make_value(-4, 6),
2051            IntervalYearMonthType::make_value(-3, 23),
2052        ]);
2053        let result = add(&a, &b).unwrap();
2054        assert_eq!(
2055            result.as_ref(),
2056            &IntervalYearMonthArray::from(vec![
2057                IntervalYearMonthType::make_value(28, 10),
2058                IntervalYearMonthType::make_value(29, 27)
2059            ])
2060        );
2061        let result = sub(&a, &b).unwrap();
2062        assert_eq!(
2063            result.as_ref(),
2064            &IntervalYearMonthArray::from(vec![
2065                IntervalYearMonthType::make_value(36, -2),
2066                IntervalYearMonthType::make_value(35, -19)
2067            ])
2068        );
2069
2070        let a = IntervalDayTimeArray::from(vec![
2071            IntervalDayTimeType::make_value(32, 4),
2072            IntervalDayTimeType::make_value(32, 4),
2073        ]);
2074        let b = IntervalDayTimeArray::from(vec![
2075            IntervalDayTimeType::make_value(-4, 6),
2076            IntervalDayTimeType::make_value(-3, 23),
2077        ]);
2078        let result = add(&a, &b).unwrap();
2079        assert_eq!(
2080            result.as_ref(),
2081            &IntervalDayTimeArray::from(vec![
2082                IntervalDayTimeType::make_value(28, 10),
2083                IntervalDayTimeType::make_value(29, 27)
2084            ])
2085        );
2086        let result = sub(&a, &b).unwrap();
2087        assert_eq!(
2088            result.as_ref(),
2089            &IntervalDayTimeArray::from(vec![
2090                IntervalDayTimeType::make_value(36, -2),
2091                IntervalDayTimeType::make_value(35, -19)
2092            ])
2093        );
2094        let a = IntervalMonthDayNanoArray::from(vec![
2095            IntervalMonthDayNanoType::make_value(32, 4, 4000000000000),
2096            IntervalMonthDayNanoType::make_value(32, 4, 45463000000000000),
2097        ]);
2098        let b = IntervalMonthDayNanoArray::from(vec![
2099            IntervalMonthDayNanoType::make_value(-4, 6, 46000000000000),
2100            IntervalMonthDayNanoType::make_value(-3, 23, 3564000000000000),
2101        ]);
2102        let result = add(&a, &b).unwrap();
2103        assert_eq!(
2104            result.as_ref(),
2105            &IntervalMonthDayNanoArray::from(vec![
2106                IntervalMonthDayNanoType::make_value(28, 10, 50000000000000),
2107                IntervalMonthDayNanoType::make_value(29, 27, 49027000000000000)
2108            ])
2109        );
2110        let result = sub(&a, &b).unwrap();
2111        assert_eq!(
2112            result.as_ref(),
2113            &IntervalMonthDayNanoArray::from(vec![
2114                IntervalMonthDayNanoType::make_value(36, -2, -42000000000000),
2115                IntervalMonthDayNanoType::make_value(35, -19, 41899000000000000)
2116            ])
2117        );
2118        let a = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNano::MAX]);
2119        let b = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNano::ONE]);
2120        let err = add(&a, &b).unwrap_err().to_string();
2121        assert_eq!(
2122            err,
2123            "Arithmetic overflow: Overflow happened on: 2147483647 + 1"
2124        );
2125    }
2126
2127    #[test]
2128    fn test_interval_mul_i64() {
2129        let interval = IntervalYearMonthArray::from(vec![16, 5, 0]);
2130        let factor = Int64Array::from(vec![3, -2, i64::MAX]);
2131        let expected = IntervalYearMonthArray::from(vec![48, -10, 0]);
2132        assert_eq!(mul(&interval, &factor).unwrap().as_ref(), &expected);
2133        assert_eq!(mul(&factor, &interval).unwrap().as_ref(), &expected);
2134
2135        let interval = IntervalDayTimeArray::from(vec![
2136            Some(IntervalDayTimeType::make_value(10, 2 * 60 * 60 * 1000)),
2137            None,
2138        ]);
2139        let factor = Int64Array::new_scalar(3);
2140        let expected = IntervalDayTimeArray::from(vec![
2141            Some(IntervalDayTimeType::make_value(30, 6 * 60 * 60 * 1000)),
2142            None,
2143        ]);
2144        assert_eq!(mul(&interval, &factor).unwrap().as_ref(), &expected);
2145        assert_eq!(mul(&factor, &interval).unwrap().as_ref(), &expected);
2146
2147        let null_factor = Scalar::new(Int64Array::new_null(1));
2148        let expected = IntervalDayTimeArray::new_null(interval.len());
2149        assert_eq!(mul(&interval, &null_factor).unwrap().as_ref(), &expected);
2150        assert_eq!(mul(&null_factor, &interval).unwrap().as_ref(), &expected);
2151
2152        let interval = IntervalMonthDayNanoArray::new_scalar(IntervalMonthDayNanoType::make_value(
2153            12,
2154            15,
2155            5_000_000_000,
2156        ));
2157        let factor = Int64Array::from(vec![2, 0, -1]);
2158        let expected = IntervalMonthDayNanoArray::from(vec![
2159            IntervalMonthDayNanoType::make_value(24, 30, 10_000_000_000),
2160            IntervalMonthDayNanoType::make_value(0, 0, 0),
2161            IntervalMonthDayNanoType::make_value(-12, -15, -5_000_000_000),
2162        ]);
2163        assert_eq!(mul(&interval, &factor).unwrap().as_ref(), &expected);
2164        assert_eq!(mul(&factor, &interval).unwrap().as_ref(), &expected);
2165
2166        let float_factor = Float64Array::new_scalar(2.);
2167        assert!(mul_wrapping(&float_factor, &interval).is_err());
2168        assert!(mul_wrapping(&factor, &interval).is_err());
2169    }
2170
2171    #[test]
2172    fn test_interval_mul_div_f64() {
2173        const HOUR_NANOS: i64 = 3_600_000_000_000;
2174        const MINUTE_NANOS: i64 = 60_000_000_000;
2175
2176        // Adapted from DuckDB's interval multiplication tests:
2177        // https://github.com/duckdb/duckdb/blob/21aca0424f1faf78b593b1e6fbfdd4846624c987/test/sql/function/interval/test_interval_muldiv.test#L1-L99
2178        // DuckDB's cases come from PostgreSQL's interval regression tests:
2179        // https://github.com/postgres/postgres/blob/78758d37306cd89ab060f00cb06f249018d5b8da/src/test/regress/sql/interval.sql#L118-L164
2180        let interval = IntervalMonthDayNanoArray::from(vec![
2181            IntervalMonthDayNanoType::make_value(41, 12, 360 * HOUR_NANOS),
2182            IntervalMonthDayNanoType::make_value(-41, -12, 360 * HOUR_NANOS),
2183            IntervalMonthDayNanoType::make_value(1, 1, 0),
2184            IntervalMonthDayNanoType::make_value(0, 0, 1),
2185            IntervalMonthDayNanoType::make_value(0, 0, 3),
2186            IntervalMonthDayNanoType::make_value(0, 0, -1),
2187            IntervalMonthDayNanoType::make_value(0, 0, -3),
2188        ]);
2189        let factor = Float64Array::from(vec![0.3, 0.3, 1.5, 0.5, 0.5, 0.5, 0.5]);
2190        let expected = IntervalMonthDayNanoArray::from(vec![
2191            IntervalMonthDayNanoType::make_value(12, 12, 122 * HOUR_NANOS + 24 * MINUTE_NANOS),
2192            IntervalMonthDayNanoType::make_value(-12, -12, 93 * HOUR_NANOS + 36 * MINUTE_NANOS),
2193            IntervalMonthDayNanoType::make_value(1, 16, 12 * HOUR_NANOS),
2194            IntervalMonthDayNanoType::make_value(0, 0, 0),
2195            IntervalMonthDayNanoType::make_value(0, 0, 2),
2196            IntervalMonthDayNanoType::make_value(0, 0, 0),
2197            IntervalMonthDayNanoType::make_value(0, 0, -2),
2198        ]);
2199        assert_eq!(mul(&interval, &factor).unwrap().as_ref(), &expected);
2200        assert_eq!(mul(&factor, &interval).unwrap().as_ref(), &expected);
2201
2202        let interval = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value(
2203            9,
2204            -27,
2205            45_296 * NANOSECONDS,
2206        )]);
2207        let factor = Float64Array::new_scalar(0.3);
2208        let expected = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value(
2209            2,
2210            13,
2211            4_948_800_000_000,
2212        )]);
2213        assert_eq!(mul(&interval, &factor).unwrap().as_ref(), &expected);
2214
2215        let interval = IntervalMonthDayNanoArray::from(vec![
2216            IntervalMonthDayNanoType::make_value(0, 1, 0),
2217            IntervalMonthDayNanoType::make_value(4, 0, 0),
2218            IntervalMonthDayNanoType::make_value(1, 1, 0),
2219            IntervalMonthDayNanoType::make_value(0, 0, (1_i64 << 53) - 1),
2220            IntervalMonthDayNanoType::make_value(0, 0, i64::MAX),
2221            IntervalMonthDayNanoType::make_value(1, 1, 1),
2222            IntervalMonthDayNanoType::make_value(1, 1, 1),
2223            IntervalMonthDayNanoType::make_value(1, 0, 0),
2224        ]);
2225        let factor = Float64Array::from(vec![
2226            3.,
2227            5.,
2228            2.,
2229            0.7,
2230            1.,
2231            f64::INFINITY,
2232            f64::NEG_INFINITY,
2233            -2.,
2234        ]);
2235        let expected = IntervalMonthDayNanoArray::from(vec![
2236            IntervalMonthDayNanoType::make_value(0, 0, 8 * HOUR_NANOS),
2237            IntervalMonthDayNanoType::make_value(0, 24, 0),
2238            IntervalMonthDayNanoType::make_value(0, 15, 12 * HOUR_NANOS),
2239            IntervalMonthDayNanoType::make_value(0, 0, 12_867_427_506_772_844),
2240            IntervalMonthDayNanoType::make_value(0, 0, i64::MAX),
2241            IntervalMonthDayNanoType::make_value(0, 0, 0),
2242            IntervalMonthDayNanoType::make_value(0, 0, 0),
2243            IntervalMonthDayNanoType::make_value(0, -15, 0),
2244        ]);
2245        assert_eq!(div(&interval, &factor).unwrap().as_ref(), &expected);
2246
2247        let null_factor = Scalar::new(Float64Array::new_null(1));
2248        assert_eq!(
2249            mul(&interval, &null_factor).unwrap().as_ref(),
2250            &IntervalMonthDayNanoArray::new_null(interval.len())
2251        );
2252    }
2253
2254    #[test]
2255    fn test_interval_mul_div_f64_errors() {
2256        let factor = Float64Array::new_scalar(2.);
2257        let year_month = IntervalYearMonthArray::new_scalar(1);
2258        let day_time = IntervalDayTimeArray::new_scalar(IntervalDayTime::new(1, 1));
2259        for interval in [&year_month as &dyn Datum, &day_time] {
2260            assert!(mul(interval, &factor).is_err());
2261            assert!(mul(&factor, interval).is_err());
2262            assert!(div(interval, &factor).is_err());
2263        }
2264
2265        let interval =
2266            IntervalMonthDayNanoArray::new_scalar(IntervalMonthDayNanoType::make_value(1, 1, 1));
2267
2268        assert!(matches!(
2269            add(&interval, &factor),
2270            Err(ArrowError::InvalidArgumentError(_))
2271        ));
2272
2273        let zero = Float64Array::new_scalar(-0.);
2274        assert!(matches!(
2275            div(&interval, &zero),
2276            Err(ArrowError::DivideByZero)
2277        ));
2278
2279        assert!(div(&factor, &interval).is_err());
2280
2281        for factor in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
2282            let factor = Float64Array::new_scalar(factor);
2283            assert!(matches!(
2284                mul(&interval, &factor),
2285                Err(ArrowError::ArithmeticOverflow(_))
2286            ));
2287        }
2288
2289        let nan = Float64Array::new_scalar(f64::NAN);
2290        assert!(matches!(
2291            div(&interval, &nan),
2292            Err(ArrowError::ArithmeticOverflow(_))
2293        ));
2294
2295        let interval = IntervalMonthDayNanoArray::new_scalar(IntervalMonthDayNanoType::make_value(
2296            i32::MAX,
2297            0,
2298            0,
2299        ));
2300        assert!(matches!(
2301            mul(&interval, &factor),
2302            Err(ArrowError::ArithmeticOverflow(_))
2303        ));
2304
2305        let factor = Float64Array::new_scalar(1.5);
2306        let interval = IntervalMonthDayNanoArray::new_scalar(IntervalMonthDayNanoType::make_value(
2307            0,
2308            0,
2309            i64::MAX,
2310        ));
2311        assert!(matches!(
2312            mul(&interval, &factor),
2313            Err(ArrowError::ArithmeticOverflow(_))
2314        ));
2315
2316        let factor = Float64Array::new_scalar(1.000_000_000_4);
2317        let interval = IntervalMonthDayNanoArray::new_scalar(IntervalMonthDayNanoType::make_value(
2318            i32::MIN,
2319            0,
2320            0,
2321        ));
2322        assert!(matches!(
2323            mul(&interval, &factor),
2324            Err(ArrowError::ArithmeticOverflow(_))
2325        ));
2326
2327        let factor = Float64Array::new_scalar(0.999_999_999);
2328        let interval = IntervalMonthDayNanoArray::new_scalar(IntervalMonthDayNanoType::make_value(
2329            1,
2330            i32::MAX,
2331            0,
2332        ));
2333        assert!(matches!(
2334            mul(&interval, &factor),
2335            Err(ArrowError::ArithmeticOverflow(_))
2336        ));
2337    }
2338
2339    #[test]
2340    fn test_interval_mul_i64_overflow() {
2341        let interval = IntervalYearMonthArray::from(vec![i32::MAX]);
2342        let factor = Int64Array::from(vec![2]);
2343        assert_eq!(
2344            mul(&interval, &factor).unwrap_err().to_string(),
2345            "Arithmetic overflow: Overflow happened on: 2147483647 * 2"
2346        );
2347
2348        let interval = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value(
2349            0,
2350            0,
2351            i64::MAX,
2352        )]);
2353        assert_eq!(
2354            mul(&interval, &factor).unwrap_err().to_string(),
2355            "Arithmetic overflow: Overflow happened on: 9223372036854775807 * 2"
2356        );
2357    }
2358
2359    fn test_duration_impl<T: ArrowPrimitiveType<Native = i64>>() {
2360        let a = PrimitiveArray::<T>::new(vec![1000, 4394, -3944].into(), None);
2361        let b = PrimitiveArray::<T>::new(vec![4, -5, -243].into(), None);
2362
2363        let result = add(&a, &b).unwrap();
2364        assert_eq!(result.as_primitive::<T>().values(), &[1004, 4389, -4187]);
2365        let result = sub(&a, &b).unwrap();
2366        assert_eq!(result.as_primitive::<T>().values(), &[996, 4399, -3701]);
2367
2368        let err = mul(&a, &b).unwrap_err().to_string();
2369        assert!(
2370            err.contains("Invalid duration arithmetic operation"),
2371            "{err}"
2372        );
2373
2374        let err = div(&a, &b).unwrap_err().to_string();
2375        assert!(
2376            err.contains("Invalid duration arithmetic operation"),
2377            "{err}"
2378        );
2379
2380        let err = rem(&a, &b).unwrap_err().to_string();
2381        assert!(
2382            err.contains("Invalid duration arithmetic operation"),
2383            "{err}"
2384        );
2385
2386        let a = PrimitiveArray::<T>::new(vec![i64::MAX].into(), None);
2387        let b = PrimitiveArray::<T>::new(vec![1].into(), None);
2388        let err = add(&a, &b).unwrap_err().to_string();
2389        assert_eq!(
2390            err,
2391            "Arithmetic overflow: Overflow happened on: 9223372036854775807 + 1"
2392        );
2393    }
2394
2395    #[test]
2396    fn test_duration() {
2397        test_duration_impl::<DurationSecondType>();
2398        test_duration_impl::<DurationMillisecondType>();
2399        test_duration_impl::<DurationMicrosecondType>();
2400        test_duration_impl::<DurationNanosecondType>();
2401    }
2402
2403    fn test_date_impl<T: ArrowPrimitiveType, F>(f: F)
2404    where
2405        F: Fn(NaiveDate) -> T::Native,
2406        T::Native: TryInto<i64>,
2407    {
2408        let a = PrimitiveArray::<T>::new(
2409            vec![
2410                f(NaiveDate::from_ymd_opt(1979, 1, 30).unwrap()),
2411                f(NaiveDate::from_ymd_opt(2010, 4, 3).unwrap()),
2412                f(NaiveDate::from_ymd_opt(2008, 2, 29).unwrap()),
2413            ]
2414            .into(),
2415            None,
2416        );
2417
2418        let b = IntervalYearMonthArray::from(vec![
2419            IntervalYearMonthType::make_value(34, 2),
2420            IntervalYearMonthType::make_value(3, -3),
2421            IntervalYearMonthType::make_value(-12, 4),
2422        ]);
2423
2424        let format_array = |x: &dyn Array| -> Vec<String> {
2425            x.as_primitive::<T>()
2426                .values()
2427                .into_iter()
2428                .map(|x| {
2429                    as_date::<T>((*x).try_into().ok().unwrap())
2430                        .unwrap()
2431                        .to_string()
2432                })
2433                .collect()
2434        };
2435
2436        let result = add(&a, &b).unwrap();
2437        assert_eq!(
2438            &format_array(result.as_ref()),
2439            &[
2440                "2013-03-30".to_string(),
2441                "2013-01-03".to_string(),
2442                "1996-06-29".to_string(),
2443            ]
2444        );
2445        let result = sub(&result, &b).unwrap();
2446        assert_eq!(result.as_ref(), &a);
2447
2448        let b = IntervalDayTimeArray::from(vec![
2449            IntervalDayTimeType::make_value(34, 2),
2450            IntervalDayTimeType::make_value(3, -3),
2451            IntervalDayTimeType::make_value(-12, 4),
2452        ]);
2453
2454        let result = add(&a, &b).unwrap();
2455        assert_eq!(
2456            &format_array(result.as_ref()),
2457            &[
2458                "1979-03-05".to_string(),
2459                "2010-04-06".to_string(),
2460                "2008-02-17".to_string(),
2461            ]
2462        );
2463        let result = sub(&result, &b).unwrap();
2464        assert_eq!(result.as_ref(), &a);
2465
2466        let b = IntervalMonthDayNanoArray::from(vec![
2467            IntervalMonthDayNanoType::make_value(34, 2, -34353534),
2468            IntervalMonthDayNanoType::make_value(3, -3, 2443),
2469            IntervalMonthDayNanoType::make_value(-12, 4, 2323242423232),
2470        ]);
2471
2472        let result = add(&a, &b).unwrap();
2473        assert_eq!(
2474            &format_array(result.as_ref()),
2475            &[
2476                "1981-12-02".to_string(),
2477                "2010-06-30".to_string(),
2478                "2007-03-04".to_string(),
2479            ]
2480        );
2481        let result = sub(&result, &b).unwrap();
2482        assert_eq!(
2483            &format_array(result.as_ref()),
2484            &[
2485                "1979-01-31".to_string(),
2486                "2010-04-02".to_string(),
2487                "2008-02-29".to_string(),
2488            ]
2489        );
2490    }
2491
2492    #[test]
2493    fn test_date() {
2494        test_date_impl::<Date32Type, _>(Date32Type::from_naive_date);
2495        test_date_impl::<Date64Type, _>(Date64Type::from_naive_date);
2496
2497        let a = Date32Array::from(vec![i32::MIN, i32::MAX, 23, 7684]);
2498        let b = Date32Array::from(vec![i32::MIN, i32::MIN, -2, 45]);
2499        let result = sub(&a, &b).unwrap();
2500        assert_eq!(
2501            result.as_primitive::<DurationSecondType>().values(),
2502            &[0, 371085174288000, 2160000, 660009600]
2503        );
2504
2505        let a = Date64Array::from(vec![4343, 76676, 3434]);
2506        let b = Date64Array::from(vec![3, -5, 5]);
2507        let result = sub(&a, &b).unwrap();
2508        assert_eq!(
2509            result.as_primitive::<DurationMillisecondType>().values(),
2510            &[4340, 76681, 3429]
2511        );
2512
2513        let a = Date64Array::from(vec![i64::MAX]);
2514        let b = Date64Array::from(vec![-1]);
2515        let err = sub(&a, &b).unwrap_err().to_string();
2516        assert_eq!(
2517            err,
2518            "Arithmetic overflow: Overflow happened on: 9223372036854775807 - -1"
2519        );
2520    }
2521
2522    #[test]
2523    fn test_date32_to_naive_date_opt_boundaries() {
2524        assert_eq!(MAX_VALID_DAYS, 95026236);
2525        assert_eq!(MIN_VALID_DAYS, -96465292);
2526
2527        // Valid boundary dates work
2528        assert!(Date32Type::to_naive_date_opt(MAX_VALID_DAYS).is_some());
2529        assert!(Date32Type::to_naive_date_opt(MIN_VALID_DAYS).is_some());
2530
2531        // Beyond boundaries fail
2532        assert!(Date32Type::to_naive_date_opt(MAX_VALID_DAYS + 1).is_none());
2533        assert!(Date32Type::to_naive_date_opt(MIN_VALID_DAYS - 1).is_none());
2534
2535        // Extreme values fail
2536        assert!(Date32Type::to_naive_date_opt(i32::MAX).is_none());
2537        assert!(Date32Type::to_naive_date_opt(i32::MIN).is_none());
2538
2539        // Common values work
2540        assert!(Date32Type::to_naive_date_opt(0).is_some());
2541        assert!(Date32Type::to_naive_date_opt(date_to_days(YEAR_2000)).is_some());
2542    }
2543
2544    #[test]
2545    fn test_date64_to_naive_date_opt_boundaries() {
2546        const MS_PER_DAY: i64 = 24 * 60 * 60 * 1000;
2547
2548        // Verify boundary millisecond values
2549        assert_eq!(MAX_VALID_MILLIS, 8210266790400000i64);
2550        assert_eq!(MIN_VALID_MILLIS, -8334601228800000i64);
2551
2552        // Valid boundary dates work
2553        assert!(Date64Type::to_naive_date_opt(MAX_VALID_MILLIS).is_some());
2554        assert!(Date64Type::to_naive_date_opt(MIN_VALID_MILLIS).is_some());
2555
2556        // Beyond boundaries fail
2557        assert!(Date64Type::to_naive_date_opt(MAX_VALID_MILLIS + MS_PER_DAY).is_none());
2558        assert!(Date64Type::to_naive_date_opt(MIN_VALID_MILLIS - MS_PER_DAY).is_none());
2559
2560        // Extreme values fail
2561        assert!(Date64Type::to_naive_date_opt(i64::MAX).is_none());
2562        assert!(Date64Type::to_naive_date_opt(i64::MIN).is_none());
2563
2564        // Common values work
2565        assert!(Date64Type::to_naive_date_opt(0).is_some());
2566        assert!(Date64Type::to_naive_date_opt(date_to_millis(YEAR_2000)).is_some());
2567    }
2568
2569    macro_rules! test_year_month_ops {
2570        ($type:ty, $date_fn:expr) => {{
2571            let date = $date_fn(YEAR_2000);
2572
2573            // Normal operations succeed
2574            assert!(
2575                <$type>::add_year_months_opt(date, 120).is_some(),
2576                "add_year_months: normal add"
2577            );
2578            assert!(
2579                <$type>::add_year_months_opt(date, 0).is_some(),
2580                "add_year_months: zero interval"
2581            );
2582            assert!(
2583                <$type>::subtract_year_months_opt(date, 120).is_some(),
2584                "subtract_year_months: normal subtract"
2585            );
2586            assert!(
2587                <$type>::subtract_year_months_opt(date, 0).is_some(),
2588                "subtract_year_months: zero interval"
2589            );
2590
2591            // Large but valid years work
2592            let large_year = $date_fn(NaiveDate::from_ymd_opt(5000, 1, 1).unwrap());
2593            let neg_year = $date_fn(NaiveDate::from_ymd_opt(-5000, 12, 31).unwrap());
2594            assert!(
2595                <$type>::add_year_months_opt(large_year, 12).is_some(),
2596                "add_year_months: large year"
2597            );
2598            assert!(
2599                <$type>::add_year_months_opt(neg_year, -12).is_some(),
2600                "add_year_months: negative year"
2601            );
2602            assert!(
2603                <$type>::subtract_year_months_opt(large_year, 12).is_some(),
2604                "subtract_year_months: large year"
2605            );
2606            assert!(
2607                <$type>::subtract_year_months_opt(neg_year, -12).is_some(),
2608                "subtract_year_months: negative year"
2609            );
2610
2611            // Overflow handling
2612            assert!(
2613                <$type>::subtract_year_months_opt($date_fn(MIN_VALID_DATE), 1).is_none(),
2614                "subtract_year_months: overflow days from min"
2615            );
2616            assert!(
2617                <$type>::subtract_year_months_opt($date_fn(MAX_VALID_DATE), -1).is_none(),
2618                "subtract_year_months: overflow neg days from max"
2619            );
2620            assert!(
2621                <$type>::add_year_months_opt($date_fn(MAX_VALID_DATE), 1).is_none(),
2622                "add_year_months: overflow days"
2623            );
2624            assert!(
2625                <$type>::add_year_months_opt($date_fn(MIN_VALID_DATE), -1).is_none(),
2626                "add_year_months: overflow neg days"
2627            );
2628        }};
2629    }
2630
2631    #[test]
2632    fn test_date_year_month_operations() {
2633        test_year_month_ops!(Date32Type, date_to_days);
2634        test_year_month_ops!(Date64Type, date_to_millis);
2635    }
2636
2637    macro_rules! test_day_time_ops {
2638        ($type:ty, $date_fn:expr) => {{
2639            let date = $date_fn(YEAR_2000);
2640
2641            // Moderate intervals succeed
2642            assert!(
2643                <$type>::add_day_time_opt(date, IntervalDayTime::new(30, 0)).is_some(),
2644                "add_day_time: +30 days"
2645            );
2646            assert!(
2647                <$type>::add_day_time_opt(date, IntervalDayTime::new(-30, 0)).is_some(),
2648                "add_day_time: -30 days"
2649            );
2650            assert!(
2651                <$type>::add_day_time_opt(date, IntervalDayTime::new(1000, 12345)).is_some(),
2652                "add_day_time: normal"
2653            );
2654            assert!(
2655                <$type>::subtract_day_time_opt(date, IntervalDayTime::new(30, 0)).is_some(),
2656                "subtract_day_time: +30 days"
2657            );
2658            assert!(
2659                <$type>::subtract_day_time_opt(date, IntervalDayTime::new(-30, 0)).is_some(),
2660                "subtract_day_time: -30 days"
2661            );
2662            assert!(
2663                <$type>::subtract_day_time_opt(date, IntervalDayTime::new(1000, 12345)).is_some(),
2664                "subtract_day_time: normal"
2665            );
2666
2667            // Overflow handling - subtract
2668            assert!(
2669                <$type>::subtract_day_time_opt(
2670                    $date_fn(MIN_VALID_DATE),
2671                    IntervalDayTime::new(1, 0)
2672                )
2673                .is_none(),
2674                "subtract_day_time: overflow days from min"
2675            );
2676            assert!(
2677                <$type>::subtract_day_time_opt(
2678                    $date_fn(MAX_VALID_DATE),
2679                    IntervalDayTime::new(-1, 0)
2680                )
2681                .is_none(),
2682                "subtract_day_time: overflow neg days from max"
2683            );
2684
2685            // Overflow handling - add
2686            assert!(
2687                <$type>::add_day_time_opt($date_fn(MAX_VALID_DATE), IntervalDayTime::new(1, 0))
2688                    .is_none(),
2689                "add_day_time: overflow days"
2690            );
2691            assert!(
2692                <$type>::add_day_time_opt($date_fn(MIN_VALID_DATE), IntervalDayTime::new(-1, 0))
2693                    .is_none(),
2694                "add_day_time: overflow neg days"
2695            );
2696
2697            // Extreme intervals fail
2698            assert!(
2699                <$type>::add_day_time_opt(
2700                    $date_fn(EPOCH),
2701                    IntervalDayTime::new(i32::MAX, i32::MAX)
2702                )
2703                .is_none(),
2704                "add_day_time: max interval"
2705            );
2706            assert!(
2707                <$type>::add_day_time_opt(
2708                    $date_fn(EPOCH),
2709                    IntervalDayTime::new(i32::MIN, i32::MIN)
2710                )
2711                .is_none(),
2712                "add_day_time: min interval"
2713            );
2714            assert!(
2715                <$type>::subtract_day_time_opt(
2716                    $date_fn(EPOCH),
2717                    IntervalDayTime::new(i32::MAX, i32::MAX)
2718                )
2719                .is_none(),
2720                "subtract_day_time: max interval"
2721            );
2722            assert!(
2723                <$type>::subtract_day_time_opt(
2724                    $date_fn(EPOCH),
2725                    IntervalDayTime::new(i32::MIN, i32::MIN)
2726                )
2727                .is_none(),
2728                "subtract_day_time: min interval"
2729            );
2730        }};
2731    }
2732
2733    #[test]
2734    fn test_date_day_time_operations() {
2735        test_day_time_ops!(Date32Type, date_to_days);
2736        test_day_time_ops!(Date64Type, date_to_millis);
2737    }
2738
2739    macro_rules! test_month_day_nano_ops {
2740        ($type:ty, $date_fn:expr) => {{
2741            let date = $date_fn(YEAR_2000);
2742            let zero = IntervalMonthDayNano::new(0, 0, 0);
2743
2744            // Normal operations succeed
2745            assert!(
2746                <$type>::add_month_day_nano_opt(date, IntervalMonthDayNano::new(1, 30, 0))
2747                    .is_some(),
2748                "add_month_day_nano: +1mo +30d"
2749            );
2750            assert!(
2751                <$type>::add_month_day_nano_opt(date, IntervalMonthDayNano::new(-1, -30, 0))
2752                    .is_some(),
2753                "add_month_day_nano: -1mo -30d"
2754            );
2755            assert!(
2756                <$type>::add_month_day_nano_opt(date, zero).is_some(),
2757                "add_month_day_nano: zero interval"
2758            );
2759            assert!(
2760                <$type>::add_month_day_nano_opt(
2761                    date,
2762                    IntervalMonthDayNano::new(2, 10, 123_456_789_000)
2763                )
2764                .is_some(),
2765                "add_month_day_nano: normal"
2766            );
2767            assert!(
2768                <$type>::subtract_month_day_nano_opt(date, IntervalMonthDayNano::new(1, 30, 0))
2769                    .is_some(),
2770                "subtract_month_day_nano: +1mo +30d"
2771            );
2772            assert!(
2773                <$type>::subtract_month_day_nano_opt(date, IntervalMonthDayNano::new(-1, -30, 0))
2774                    .is_some(),
2775                "subtract_month_day_nano: -1mo -30d"
2776            );
2777            assert!(
2778                <$type>::subtract_month_day_nano_opt(date, zero).is_some(),
2779                "subtract_month_day_nano: zero interval"
2780            );
2781            assert!(
2782                <$type>::subtract_month_day_nano_opt(
2783                    date,
2784                    IntervalMonthDayNano::new(2, 10, 123_456_789_000)
2785                )
2786                .is_some(),
2787                "subtract_month_day_nano: normal"
2788            );
2789
2790            // Overflow handling - subtract
2791            assert!(
2792                <$type>::subtract_month_day_nano_opt(
2793                    $date_fn(MIN_VALID_DATE),
2794                    IntervalMonthDayNano::new(0, 1, 0)
2795                )
2796                .is_none(),
2797                "subtract_month_day_nano: overflow days from min"
2798            );
2799            assert!(
2800                <$type>::subtract_month_day_nano_opt(
2801                    $date_fn(MAX_VALID_DATE),
2802                    IntervalMonthDayNano::new(0, -1, 0)
2803                )
2804                .is_none(),
2805                "subtract_month_day_nano: overflow neg days from max"
2806            );
2807
2808            // Overflow handling - add
2809            assert!(
2810                <$type>::add_month_day_nano_opt(
2811                    $date_fn(MAX_VALID_DATE),
2812                    IntervalMonthDayNano::new(0, 1, 0)
2813                )
2814                .is_none(),
2815                "add_month_day_nano: overflow days"
2816            );
2817            assert!(
2818                <$type>::add_month_day_nano_opt(
2819                    $date_fn(MIN_VALID_DATE),
2820                    IntervalMonthDayNano::new(0, -1, 0)
2821                )
2822                .is_none(),
2823                "add_month_day_nano: overflow neg days"
2824            );
2825
2826            // Nanosecond precision works
2827            assert!(
2828                <$type>::add_month_day_nano_opt(date, IntervalMonthDayNano::new(0, 0, 999_999_999))
2829                    .is_some(),
2830                "add_month_day_nano: nanos"
2831            );
2832            assert!(
2833                <$type>::subtract_month_day_nano_opt(
2834                    date,
2835                    IntervalMonthDayNano::new(0, 0, 999_999_999)
2836                )
2837                .is_some(),
2838                "subtract_month_day_nano: nanos"
2839            );
2840            // 1 day in nanos
2841            assert!(
2842                <$type>::add_month_day_nano_opt(
2843                    date,
2844                    IntervalMonthDayNano::new(0, 0, 86_400_000_000_000)
2845                )
2846                .is_some(),
2847                "add_month_day_nano: 1 day nanos"
2848            );
2849            assert!(
2850                <$type>::subtract_month_day_nano_opt(
2851                    date,
2852                    IntervalMonthDayNano::new(0, 0, 86_400_000_000_000)
2853                )
2854                .is_some(),
2855                "subtract_month_day_nano: 1 day nanos"
2856            );
2857        }};
2858    }
2859
2860    #[test]
2861    fn test_date_month_day_nano_operations() {
2862        test_month_day_nano_ops!(Date32Type, date_to_days);
2863        test_month_day_nano_ops!(Date64Type, date_to_millis);
2864    }
2865
2866    #[test]
2867    fn test_date_sub_interval_min_months() {
2868        // Subtracting i32::MIN months requires negating i32::MIN, which
2869        // overflows i32: the date kernels must return the Date arithmetic
2870        // overflow error instead of panicking in debug builds
2871        // https://github.com/apache/arrow-rs/issues/11600
2872        let dates: [ArrayRef; 2] = [
2873            Arc::new(Date32Array::from(vec![0])),
2874            Arc::new(Date64Array::from(vec![0])),
2875        ];
2876        let year_month = IntervalYearMonthArray::from(vec![i32::MIN]);
2877        let month_day_nano =
2878            IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNano::new(i32::MIN, 0, 0)]);
2879        for dates in &dates {
2880            assert_eq!(
2881                sub(dates, &year_month).unwrap_err().to_string(),
2882                "Compute error: Date arithmetic overflow: 0 - -2147483648 months"
2883            );
2884            assert_eq!(
2885                sub(dates, &month_day_nano).unwrap_err().to_string(),
2886                "Compute error: Date arithmetic overflow: 0 - IntervalMonthDayNano { months: -2147483648, days: 0, nanoseconds: 0 }"
2887            );
2888        }
2889    }
2890}