From f53c3090ecff3757b886ef9a415f46308e701ebe Mon Sep 17 00:00:00 2001 From: Raphael Taylor-Davies Date: Sun, 30 Jul 2023 21:16:27 +0100 Subject: [PATCH] Remove deprecated arithmetic kernels (#4481) --- arrow-arith/src/arithmetic.rs | 3160 +-------------------------------- arrow-arith/src/arity.rs | 71 - 2 files changed, 69 insertions(+), 3162 deletions(-) diff --git a/arrow-arith/src/arithmetic.rs b/arrow-arith/src/arithmetic.rs index f8c855af0183..8635ce0ddd80 100644 --- a/arrow-arith/src/arithmetic.rs +++ b/arrow-arith/src/arithmetic.rs @@ -31,552 +31,6 @@ use arrow_schema::*; use std::cmp::min; use std::sync::Arc; -/// Helper function to perform math lambda function on values from two arrays. If either -/// left or right value is null then the output value is also null, so `1 + null` is -/// `null`. -/// -/// # Errors -/// -/// This function errors if the arrays have different lengths -#[deprecated(note = "Use arrow_arith::arity::binary")] -pub fn math_op( - left: &PrimitiveArray, - right: &PrimitiveArray, - op: F, -) -> Result, ArrowError> -where - LT: ArrowNumericType, - RT: ArrowNumericType, - F: Fn(LT::Native, RT::Native) -> LT::Native, -{ - binary(left, right, op) -} - -/// Calculates the modulus operation `left % right` on two SIMD inputs. -/// The lower-most bits of `valid_mask` specify which vector lanes are considered as valid. -/// -/// # Errors -/// -/// This function returns a [`ArrowError::DivideByZero`] if a valid element in `right` is `0` -#[cfg(feature = "simd")] -#[inline] -fn simd_checked_modulus( - valid_mask: Option, - left: T::Simd, - right: T::Simd, -) -> Result { - let zero = T::init(T::Native::ZERO); - let one = T::init(T::Native::ONE); - - let right_no_invalid_zeros = match valid_mask { - Some(mask) => { - let simd_mask = T::mask_from_u64(mask); - // select `1` for invalid lanes, which will be a no-op during division later - T::mask_select(simd_mask, right, one) - } - None => right, - }; - - let zero_mask = T::eq(right_no_invalid_zeros, zero); - - if T::mask_any(zero_mask) { - Err(ArrowError::DivideByZero) - } else { - Ok(T::bin_op(left, right_no_invalid_zeros, |a, b| a % b)) - } -} - -/// Calculates the division operation `left / right` on two SIMD inputs. -/// The lower-most bits of `valid_mask` specify which vector lanes are considered as valid. -/// -/// # Errors -/// -/// This function returns a [`ArrowError::DivideByZero`] if a valid element in `right` is `0` -#[cfg(feature = "simd")] -#[inline] -fn simd_checked_divide( - valid_mask: Option, - left: T::Simd, - right: T::Simd, -) -> Result { - let zero = T::init(T::Native::ZERO); - let one = T::init(T::Native::ONE); - - let right_no_invalid_zeros = match valid_mask { - Some(mask) => { - let simd_mask = T::mask_from_u64(mask); - // select `1` for invalid lanes, which will be a no-op during division later - T::mask_select(simd_mask, right, one) - } - None => right, - }; - - let zero_mask = T::eq(right_no_invalid_zeros, zero); - - if T::mask_any(zero_mask) { - Err(ArrowError::DivideByZero) - } else { - Ok(T::bin_op(left, right_no_invalid_zeros, |a, b| a / b)) - } -} - -/// Applies `op` on the remainder elements of two input chunks and writes the result into -/// the remainder elements of `result_chunks`. -/// The lower-most bits of `valid_mask` specify which elements are considered as valid. -/// -/// # Errors -/// -/// This function returns a [`ArrowError::DivideByZero`] if a valid element in `right` is `0` -#[cfg(feature = "simd")] -#[inline] -fn simd_checked_divide_op_remainder( - valid_mask: Option, - left_chunks: std::slice::ChunksExact, - right_chunks: std::slice::ChunksExact, - result_chunks: std::slice::ChunksExactMut, - op: F, -) -> Result<(), ArrowError> -where - T: ArrowNumericType, - F: Fn(T::Native, T::Native) -> T::Native, -{ - let result_remainder = result_chunks.into_remainder(); - let left_remainder = left_chunks.remainder(); - let right_remainder = right_chunks.remainder(); - - result_remainder - .iter_mut() - .zip(left_remainder.iter().zip(right_remainder.iter())) - .enumerate() - .try_for_each(|(i, (result_scalar, (left_scalar, right_scalar)))| { - if valid_mask.map(|mask| mask & (1 << i) != 0).unwrap_or(true) { - if right_scalar.is_zero() { - return Err(ArrowError::DivideByZero); - } - *result_scalar = op(*left_scalar, *right_scalar); - } else { - *result_scalar = T::default_value(); - } - Ok(()) - })?; - - Ok(()) -} - -/// Creates a new PrimitiveArray by applying `simd_op` to the `left` and `right` input array. -/// If the length of the arrays is not multiple of the number of vector lanes -/// then the remainder of the array will be calculated using `scalar_op`. -/// Any operation on a `NULL` value will result in a `NULL` value in the output. -/// -/// # Errors -/// -/// This function errors if: -/// * the arrays have different lengths -/// * there is an element where both left and right values are valid and the right value is `0` -#[cfg(feature = "simd")] -fn simd_checked_divide_op( - left: &PrimitiveArray, - right: &PrimitiveArray, - simd_op: SI, - scalar_op: SC, -) -> Result, ArrowError> -where - T: ArrowNumericType, - SI: Fn(Option, T::Simd, T::Simd) -> Result, - SC: Fn(T::Native, T::Native) -> T::Native, -{ - if left.len() != right.len() { - return Err(ArrowError::ComputeError( - "Cannot perform math operation on arrays of different length".to_string(), - )); - } - - // Create the combined `Bitmap` - let nulls = arrow_buffer::NullBuffer::union(left.nulls(), right.nulls()); - - let lanes = T::lanes(); - let buffer_size = left.len() * std::mem::size_of::(); - let mut result = - arrow_buffer::MutableBuffer::new(buffer_size).with_bitset(buffer_size, false); - - match &nulls { - Some(b) => { - let valid_chunks = b.inner().bit_chunks(); - - // process data in chunks of 64 elements since we also get 64 bits of validity information at a time - - let mut result_chunks = result.typed_data_mut().chunks_exact_mut(64); - let mut left_chunks = left.values().chunks_exact(64); - let mut right_chunks = right.values().chunks_exact(64); - - valid_chunks - .iter() - .zip((&mut result_chunks).zip((&mut left_chunks).zip(&mut right_chunks))) - .try_for_each( - |(mut mask, (result_slice, (left_slice, right_slice)))| { - // split chunks further into slices corresponding to the vector length - // the compiler is able to unroll this inner loop and remove bounds checks - // since the outer chunk size (64) is always a multiple of the number of lanes - result_slice - .chunks_exact_mut(lanes) - .zip(left_slice.chunks_exact(lanes).zip(right_slice.chunks_exact(lanes))) - .try_for_each(|(result_slice, (left_slice, right_slice))| -> Result<(), ArrowError> { - let simd_left = T::load(left_slice); - let simd_right = T::load(right_slice); - - let simd_result = simd_op(Some(mask), simd_left, simd_right)?; - - T::write(simd_result, result_slice); - - // skip the shift and avoid overflow for u8 type, which uses 64 lanes. - mask >>= T::lanes() % 64; - - Ok(()) - }) - }, - )?; - - let valid_remainder = valid_chunks.remainder_bits(); - - simd_checked_divide_op_remainder::( - Some(valid_remainder), - left_chunks, - right_chunks, - result_chunks, - scalar_op, - )?; - } - None => { - let mut result_chunks = result.typed_data_mut().chunks_exact_mut(lanes); - let mut left_chunks = left.values().chunks_exact(lanes); - let mut right_chunks = right.values().chunks_exact(lanes); - - (&mut result_chunks) - .zip((&mut left_chunks).zip(&mut right_chunks)) - .try_for_each( - |(result_slice, (left_slice, right_slice))| -> Result<(), ArrowError> { - let simd_left = T::load(left_slice); - let simd_right = T::load(right_slice); - - let simd_result = simd_op(None, simd_left, simd_right)?; - - T::write(simd_result, result_slice); - - Ok(()) - }, - )?; - - simd_checked_divide_op_remainder::( - None, - left_chunks, - right_chunks, - result_chunks, - scalar_op, - )?; - } - } - - Ok(PrimitiveArray::new(result.into(), nulls)) -} - -fn math_safe_divide_op( - left: &PrimitiveArray, - right: &PrimitiveArray, - op: F, -) -> Result -where - LT: ArrowNumericType, - RT: ArrowNumericType, - F: Fn(LT::Native, RT::Native) -> Option, -{ - let array: PrimitiveArray = binary_opt::<_, _, _, LT>(left, right, op)?; - Ok(Arc::new(array) as ArrayRef) -} - -/// Perform `left + right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `add_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::add_wrapping")] -pub fn add( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - binary(left, right, |a, b| a.add_wrapping(b)) -} - -/// Perform `left + right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `add` instead. -#[deprecated(note = "Use arrow_arith::numeric::add")] -pub fn add_checked( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - try_binary(left, right, |a, b| a.add_checked(b)) -} - -/// Perform `left + right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `add_dyn_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::add_wrapping")] -pub fn add_dyn(left: &dyn Array, right: &dyn Array) -> Result { - crate::numeric::add_wrapping(&left, &right) -} - -/// Perform `left + right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `add_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::add")] -pub fn add_dyn_checked( - left: &dyn Array, - right: &dyn Array, -) -> Result { - crate::numeric::add(&left, &right) -} - -/// Add every value in an array by a scalar. If any value in the array is null then the -/// result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `add_scalar_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::add_wrapping")] -pub fn add_scalar( - array: &PrimitiveArray, - scalar: T::Native, -) -> Result, ArrowError> { - Ok(unary(array, |value| value.add_wrapping(scalar))) -} - -/// Add every value in an array by a scalar. If any value in the array is null then the -/// result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `add_scalar` instead. -#[deprecated(note = "Use arrow_arith::numeric::add")] -pub fn add_scalar_checked( - array: &PrimitiveArray, - scalar: T::Native, -) -> Result, ArrowError> { - try_unary(array, |value| value.add_checked(scalar)) -} - -/// Add every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type same as -/// the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `add_scalar_checked_dyn` instead. -/// -/// This returns an `Err` when the input array is not supported for adding operation. -#[deprecated(note = "Use arrow_arith::numeric::add_wrapping")] -pub fn add_scalar_dyn( - array: &dyn Array, - scalar: T::Native, -) -> Result { - unary_dyn::<_, T>(array, |value| value.add_wrapping(scalar)) -} - -/// Add every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type same as -/// the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `add_scalar_dyn` instead. -/// -/// As this kernel has the branching costs and also prevents LLVM from vectorising it correctly, -/// it is usually much slower than non-checking variant. -#[deprecated(note = "Use arrow_arith::numeric::add")] -pub fn add_scalar_checked_dyn( - array: &dyn Array, - scalar: T::Native, -) -> Result { - try_unary_dyn::<_, T>(array, |value| value.add_checked(scalar)) - .map(|a| Arc::new(a) as ArrayRef) -} - -/// Perform `left - right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `subtract_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub_wrapping")] -pub fn subtract( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - binary(left, right, |a, b| a.sub_wrapping(b)) -} - -/// Perform `left - right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `subtract` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub")] -pub fn subtract_checked( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - try_binary(left, right, |a, b| a.sub_checked(b)) -} - -/// Perform `left - right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `subtract_dyn_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub_wrapping")] -pub fn subtract_dyn(left: &dyn Array, right: &dyn Array) -> Result { - crate::numeric::sub_wrapping(&left, &right) -} - -/// Perform `left - right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `subtract_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub")] -pub fn subtract_dyn_checked( - left: &dyn Array, - right: &dyn Array, -) -> Result { - crate::numeric::sub(&left, &right) -} - -/// Subtract every value in an array by a scalar. If any value in the array is null then the -/// result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `subtract_scalar_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub_wrapping")] -pub fn subtract_scalar( - array: &PrimitiveArray, - scalar: T::Native, -) -> Result, ArrowError> { - Ok(unary(array, |value| value.sub_wrapping(scalar))) -} - -/// Subtract every value in an array by a scalar. If any value in the array is null then the -/// result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `subtract_scalar` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub")] -pub fn subtract_scalar_checked( - array: &PrimitiveArray, - scalar: T::Native, -) -> Result, ArrowError> { - try_unary(array, |value| value.sub_checked(scalar)) -} - -/// Subtract every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type same as -/// the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `subtract_scalar_checked_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub_wrapping")] -pub fn subtract_scalar_dyn( - array: &dyn Array, - scalar: T::Native, -) -> Result { - unary_dyn::<_, T>(array, |value| value.sub_wrapping(scalar)) -} - -/// Subtract every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type same as -/// the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `subtract_scalar_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::sub")] -pub fn subtract_scalar_checked_dyn( - array: &dyn Array, - scalar: T::Native, -) -> Result { - try_unary_dyn::<_, T>(array, |value| value.sub_checked(scalar)) - .map(|a| Arc::new(a) as ArrayRef) -} - -/// Perform `-` operation on an array. If value is null then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `negate_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::neg_wrapping")] -pub fn negate( - array: &PrimitiveArray, -) -> Result, ArrowError> { - Ok(unary(array, |x| x.neg_wrapping())) -} - -/// Perform `-` operation on an array. If value is null then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `negate` instead. -#[deprecated(note = "Use arrow_arith::numeric::neg")] -pub fn negate_checked( - array: &PrimitiveArray, -) -> Result, ArrowError> { - try_unary(array, |value| value.neg_checked()) -} - -/// Perform `left * right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `multiply_check` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul_wrapping")] -pub fn multiply( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - binary(left, right, |a, b| a.mul_wrapping(b)) -} - -/// Perform `left * right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `multiply` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul")] -pub fn multiply_checked( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - try_binary(left, right, |a, b| a.mul_checked(b)) -} - -/// Perform `left * right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `multiply_dyn_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul_wrapping")] -pub fn multiply_dyn(left: &dyn Array, right: &dyn Array) -> Result { - crate::numeric::mul_wrapping(&left, &right) -} - -/// Perform `left * right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `multiply_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul")] -pub fn multiply_dyn_checked( - left: &dyn Array, - right: &dyn Array, -) -> Result { - crate::numeric::mul(&left, &right) -} - /// Returns the precision and scale of the result of a multiplication of two decimal types, /// and the divisor for fixed point multiplication. fn get_fixed_point_info( @@ -740,1861 +194,81 @@ where } } -/// Multiply every value in an array by a scalar. If any value in the array is null then the -/// result is also null. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `multiply_scalar_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul_wrapping")] -pub fn multiply_scalar( - array: &PrimitiveArray, - scalar: T::Native, -) -> Result, ArrowError> { - Ok(unary(array, |value| value.mul_wrapping(scalar))) -} +#[cfg(test)] +mod tests { + use super::*; + use crate::numeric::mul; -/// Multiply every value in an array by a scalar. If any value in the array is null then the -/// result is also null. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `multiply_scalar` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul")] -pub fn multiply_scalar_checked( - array: &PrimitiveArray, - scalar: T::Native, -) -> Result, ArrowError> { - try_unary(array, |value| value.mul_checked(scalar)) -} + #[test] + fn test_decimal_multiply_allow_precision_loss() { + // Overflow happening as i128 cannot hold multiplying result. + // [123456789] + let a = Decimal128Array::from(vec![123456789000000000000000000]) + .with_precision_and_scale(38, 18) + .unwrap(); -/// Multiply every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type same as -/// the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `multiply_scalar_checked_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul_wrapping")] -pub fn multiply_scalar_dyn( - array: &dyn Array, - scalar: T::Native, -) -> Result { - unary_dyn::<_, T>(array, |value| value.mul_wrapping(scalar)) -} + // [10] + let b = Decimal128Array::from(vec![10000000000000000000]) + .with_precision_and_scale(38, 18) + .unwrap(); -/// Subtract every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type same as -/// the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `multiply_scalar_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::mul")] -pub fn multiply_scalar_checked_dyn( - array: &dyn Array, - scalar: T::Native, -) -> Result { - try_unary_dyn::<_, T>(array, |value| value.mul_checked(scalar)) - .map(|a| Arc::new(a) as ArrayRef) -} + let err = mul(&a, &b).unwrap_err(); + assert!(err.to_string().contains( + "Overflow happened on: 123456789000000000000000000 * 10000000000000000000" + )); -/// Perform `left % right` operation on two arrays. If either left or right value is null -/// then the result is also null. If any right hand value is zero then the result of this -/// operation will be `Err(ArrowError::DivideByZero)`. -#[deprecated(note = "Use arrow_arith::numeric::rem")] -pub fn modulus( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - #[cfg(feature = "simd")] - return simd_checked_divide_op(&left, &right, simd_checked_modulus::, |a, b| { - a.mod_wrapping(b) - }); - #[cfg(not(feature = "simd"))] - return try_binary(left, right, |a, b| { - if b.is_zero() { - Err(ArrowError::DivideByZero) - } else { - Ok(a.mod_wrapping(b)) - } - }); -} + // Allow precision loss. + let result = multiply_fixed_point_checked(&a, &b, 28).unwrap(); + // [1234567890] + let expected = + Decimal128Array::from(vec![12345678900000000000000000000000000000]) + .with_precision_and_scale(38, 28) + .unwrap(); -/// Perform `left % right` operation on two arrays. If either left or right value is null -/// then the result is also null. If any right hand value is zero then the result of this -/// operation will be `Err(ArrowError::DivideByZero)`. -#[deprecated(note = "Use arrow_arith::numeric::rem")] -pub fn modulus_dyn(left: &dyn Array, right: &dyn Array) -> Result { - crate::numeric::rem(&left, &right) -} + assert_eq!(&expected, &result); + assert_eq!( + result.value_as_string(0), + "1234567890.0000000000000000000000000000" + ); -/// Perform `left / right` operation on two arrays. If either left or right value is null -/// then the result is also null. If any right hand value is zero then the result of this -/// operation will be `Err(ArrowError::DivideByZero)`. -/// -/// When `simd` feature is not enabled. This detects overflow and returns an `Err` for that. -/// For an non-overflow-checking variant, use `divide` instead. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_checked( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - #[cfg(feature = "simd")] - return simd_checked_divide_op(&left, &right, simd_checked_divide::, |a, b| { - a.div_wrapping(b) - }); - #[cfg(not(feature = "simd"))] - return try_binary(left, right, |a, b| a.div_checked(b)); -} + // Rounding case + // [0.000000000000000001, 123456789.555555555555555555, 1.555555555555555555] + let a = Decimal128Array::from(vec![ + 1, + 123456789555555555555555555, + 1555555555555555555, + ]) + .with_precision_and_scale(38, 18) + .unwrap(); -/// Perform `left / right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// If any right hand value is zero, the operation value will be replaced with null in the -/// result. -/// -/// Unlike [`divide`] or [`divide_checked`], division by zero will yield a null value in the -/// result instead of returning an `Err`. -/// -/// For floating point types overflow will saturate at INF or -INF -/// preserving the expected sign value. -/// -/// For integer types overflow will wrap around. -/// -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_opt( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - binary_opt(left, right, |a, b| { - if b.is_zero() { - None - } else { - Some(a.div_wrapping(b)) - } - }) -} + // [1.555555555555555555, 11.222222222222222222, 0.000000000000000001] + let b = Decimal128Array::from(vec![1555555555555555555, 11222222222222222222, 1]) + .with_precision_and_scale(38, 18) + .unwrap(); -/// Perform `left / right` operation on two arrays. If either left or right value is null -/// then the result is also null. If any right hand value is zero then the result of this -/// operation will be `Err(ArrowError::DivideByZero)`. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `divide_dyn_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_dyn(left: &dyn Array, right: &dyn Array) -> Result { - fn divide_op( - left: &PrimitiveArray, - right: &PrimitiveArray, - ) -> Result, ArrowError> { - try_binary(left, right, |a, b| { - if b.is_zero() { - Err(ArrowError::DivideByZero) - } else { - Ok(a.div_wrapping(b)) - } - }) - } + let result = multiply_fixed_point_checked(&a, &b, 28).unwrap(); + // [ + // 0.0000000000000000015555555556, + // 1385459527.2345679012071330528765432099, + // 0.0000000000000000015555555556 + // ] + let expected = Decimal128Array::from(vec![ + 15555555556, + 13854595272345679012071330528765432099, + 15555555556, + ]) + .with_precision_and_scale(38, 28) + .unwrap(); - downcast_primitive_array!( - (left, right) => divide_op(left, right).map(|a| Arc::new(a) as ArrayRef), - _ => Err(ArrowError::CastError(format!( - "Unsupported data type {}, {}", - left.data_type(), right.data_type() - ))) - ) -} + assert_eq!(&expected, &result); -/// Perform `left / right` operation on two arrays. If either left or right value is null -/// then the result is also null. If any right hand value is zero then the result of this -/// operation will be `Err(ArrowError::DivideByZero)`. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `divide_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_dyn_checked( - left: &dyn Array, - right: &dyn Array, -) -> Result { - crate::numeric::div(&left, &right) -} - -/// Perform `left / right` operation on two arrays. If either left or right value is null -/// then the result is also null. -/// -/// If any right hand value is zero, the operation value will be replaced with null in the -/// result. -/// -/// Unlike `divide_dyn` or `divide_dyn_checked`, division by zero will get a null value instead -/// returning an `Err`, this also doesn't check overflowing, overflowing will just wrap -/// the result around. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_dyn_opt( - left: &dyn Array, - right: &dyn Array, -) -> Result { - downcast_primitive_array!( - (left, right) => { - math_safe_divide_op(left, right, |a, b| { - if b.is_zero() { - None - } else { - Some(a.div_wrapping(b)) - } - }) - } - _ => Err(ArrowError::CastError(format!( - "Unsupported data type {}, {}", - left.data_type(), right.data_type() - ))) - ) -} - -/// Perform `left / right` operation on two arrays without checking for -/// division by zero or overflow. -/// -/// For floating point types, overflow and division by zero follows normal floating point rules -/// -/// For integer types overflow will wrap around. Division by zero will currently panic, although -/// this may be subject to change see -/// -/// If either left or right value is null then the result is also null. -/// -/// For an overflow-checking variant, use `divide_checked` instead. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide( - left: &PrimitiveArray, - right: &PrimitiveArray, -) -> Result, ArrowError> { - // TODO: This is incorrect as div_wrapping has side-effects for integer types - // and so may panic on null values (#2647) - binary(left, right, |a, b| a.div_wrapping(b)) -} - -/// Modulus every value in an array by a scalar. If any value in the array is null then the -/// result is also null. If the scalar is zero then the result of this operation will be -/// `Err(ArrowError::DivideByZero)`. -#[deprecated(note = "Use arrow_arith::numeric::rem")] -pub fn modulus_scalar( - array: &PrimitiveArray, - modulo: T::Native, -) -> Result, ArrowError> { - if modulo.is_zero() { - return Err(ArrowError::DivideByZero); - } - - Ok(unary(array, |a| a.mod_wrapping(modulo))) -} - -/// Modulus every value in an array by a scalar. If any value in the array is null then the -/// result is also null. If the scalar is zero then the result of this operation will be -/// `Err(ArrowError::DivideByZero)`. -#[deprecated(note = "Use arrow_arith::numeric::rem")] -pub fn modulus_scalar_dyn( - array: &dyn Array, - modulo: T::Native, -) -> Result { - if modulo.is_zero() { - return Err(ArrowError::DivideByZero); - } - unary_dyn::<_, T>(array, |value| value.mod_wrapping(modulo)) -} - -/// Divide every value in an array by a scalar. If any value in the array is null then the -/// result is also null. If the scalar is zero then the result of this operation will be -/// `Err(ArrowError::DivideByZero)`. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_scalar( - array: &PrimitiveArray, - divisor: T::Native, -) -> Result, ArrowError> { - if divisor.is_zero() { - return Err(ArrowError::DivideByZero); - } - Ok(unary(array, |a| a.div_wrapping(divisor))) -} - -/// Divide every value in an array by a scalar. If any value in the array is null then the -/// result is also null. If the scalar is zero then the result of this operation will be -/// `Err(ArrowError::DivideByZero)`. The given array must be a `PrimitiveArray` of the type -/// same as the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This doesn't detect overflow. Once overflowing, the result will wrap around. -/// For an overflow-checking variant, use `divide_scalar_checked_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_scalar_dyn( - array: &dyn Array, - divisor: T::Native, -) -> Result { - if divisor.is_zero() { - return Err(ArrowError::DivideByZero); - } - unary_dyn::<_, T>(array, |value| value.div_wrapping(divisor)) -} - -/// Divide every value in an array by a scalar. If any value in the array is null then the -/// result is also null. If the scalar is zero then the result of this operation will be -/// `Err(ArrowError::DivideByZero)`. The given array must be a `PrimitiveArray` of the type -/// same as the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// This detects overflow and returns an `Err` for that. For an non-overflow-checking variant, -/// use `divide_scalar_dyn` instead. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_scalar_checked_dyn( - array: &dyn Array, - divisor: T::Native, -) -> Result { - if divisor.is_zero() { - return Err(ArrowError::DivideByZero); - } - - try_unary_dyn::<_, T>(array, |value| value.div_checked(divisor)) - .map(|a| Arc::new(a) as ArrayRef) -} - -/// Divide every value in an array by a scalar. If any value in the array is null then the -/// result is also null. The given array must be a `PrimitiveArray` of the type -/// same as the scalar, or a `DictionaryArray` of the value type same as the scalar. -/// -/// If any right hand value is zero, the operation value will be replaced with null in the -/// result. -/// -/// Unlike `divide_scalar_dyn` or `divide_scalar_checked_dyn`, division by zero will get a -/// null value instead returning an `Err`, this also doesn't check overflowing, overflowing -/// will just wrap the result around. -#[deprecated(note = "Use arrow_arith::numeric::div")] -pub fn divide_scalar_opt_dyn( - array: &dyn Array, - divisor: T::Native, -) -> Result { - if divisor.is_zero() { - match array.data_type() { - DataType::Dictionary(_, value_type) => { - return Ok(new_null_array(value_type.as_ref(), array.len())) - } - _ => return Ok(new_null_array(array.data_type(), array.len())), - } - } - - unary_dyn::<_, T>(array, |value| value.div_wrapping(divisor)) -} - -#[cfg(test)] -#[allow(deprecated)] -mod tests { - use super::*; - use arrow_array::builder::{ - BooleanBufferBuilder, BufferBuilder, PrimitiveDictionaryBuilder, - }; - use arrow_array::cast::AsArray; - use arrow_array::temporal_conversions::SECONDS_IN_DAY; - use arrow_buffer::buffer::NullBuffer; - use arrow_buffer::i256; - use arrow_data::ArrayDataBuilder; - use chrono::NaiveDate; - use half::f16; - - #[test] - fn test_primitive_array_add() { - let a = Int32Array::from(vec![5, 6, 7, 8, 9]); - let b = Int32Array::from(vec![6, 7, 8, 9, 8]); - let c = add(&a, &b).unwrap(); - assert_eq!(11, c.value(0)); - assert_eq!(13, c.value(1)); - assert_eq!(15, c.value(2)); - assert_eq!(17, c.value(3)); - assert_eq!(17, c.value(4)); - } - - #[test] - fn test_date32_month_add() { - let a = Date32Array::from(vec![Date32Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(), - )]); - let b = - IntervalYearMonthArray::from(vec![IntervalYearMonthType::make_value(1, 2)]); - let c = add_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2001, 3, 1).unwrap()) - ); - - let c = add_dyn(&b, &a).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2001, 3, 1).unwrap()) - ); - } - - #[test] - fn test_date32_day_time_add() { - let a = Date32Array::from(vec![Date32Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(), - )]); - let b = IntervalDayTimeArray::from(vec![IntervalDayTimeType::make_value(1, 2)]); - let c = add_dyn(&a, &b).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 1, 2).unwrap()) - ); - - let c = add_dyn(&b, &a).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 1, 2).unwrap()) - ); - } - - #[test] - fn test_date32_month_day_nano_add() { - let a = Date32Array::from(vec![Date32Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(), - )]); - let b = - IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value( - 1, 2, 3, - )]); - let c = add_dyn(&a, &b).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 2, 3).unwrap()) - ); - - let c = add_dyn(&b, &a).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 2, 3).unwrap()) - ); - } - - #[test] - fn test_date64_month_add() { - let a = Date64Array::from(vec![Date64Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(), - )]); - let b = - IntervalYearMonthArray::from(vec![IntervalYearMonthType::make_value(1, 2)]); - let c = add_dyn(&a, &b).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2001, 3, 1).unwrap()) - ); - - let c = add_dyn(&b, &a).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2001, 3, 1).unwrap()) - ); - } - - #[test] - fn test_date64_day_time_add() { - let a = Date64Array::from(vec![Date64Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(), - )]); - let b = IntervalDayTimeArray::from(vec![IntervalDayTimeType::make_value(1, 2)]); - let c = add_dyn(&a, &b).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 1, 2).unwrap()) - ); - - let c = add_dyn(&b, &a).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 1, 2).unwrap()) - ); - } - - #[test] - fn test_date64_month_day_nano_add() { - let a = Date64Array::from(vec![Date64Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(), - )]); - let b = - IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value( - 1, 2, 3, - )]); - let c = add_dyn(&a, &b).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 2, 3).unwrap()) - ); - - let c = add_dyn(&b, &a).unwrap(); - assert_eq!( - c.as_primitive::().value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2000, 2, 3).unwrap()) - ); - } - - #[test] - fn test_primitive_array_add_dyn() { - let a = Int32Array::from(vec![Some(5), Some(6), Some(7), Some(8), Some(9)]); - let b = Int32Array::from(vec![Some(6), Some(7), Some(8), None, Some(8)]); - let c = add_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(11, c.value(0)); - assert_eq!(13, c.value(1)); - assert_eq!(15, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(17, c.value(4)); - } - - #[test] - fn test_primitive_array_add_scalar_dyn() { - let a = Int32Array::from(vec![Some(5), Some(6), Some(7), None, Some(9)]); - let b = 1_i32; - let c = add_scalar_dyn::(&a, b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(6, c.value(0)); - assert_eq!(7, c.value(1)); - assert_eq!(8, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(10, c.value(4)); - - let mut builder = PrimitiveDictionaryBuilder::::new(); - builder.append(5).unwrap(); - builder.append_null(); - builder.append(7).unwrap(); - builder.append(8).unwrap(); - builder.append(9).unwrap(); - let a = builder.finish(); - let b = -1_i32; - - let c = add_scalar_dyn::(&a, b).unwrap(); - let c = c - .as_any() - .downcast_ref::>() - .unwrap(); - let values = c - .values() - .as_any() - .downcast_ref::>() - .unwrap(); - assert_eq!(4, values.value(c.key(0).unwrap())); - assert!(c.is_null(1)); - assert_eq!(6, values.value(c.key(2).unwrap())); - assert_eq!(7, values.value(c.key(3).unwrap())); - assert_eq!(8, values.value(c.key(4).unwrap())); - } - - #[test] - fn test_primitive_array_subtract_dyn() { - let a = Int32Array::from(vec![Some(51), Some(6), Some(15), Some(8), Some(9)]); - let b = Int32Array::from(vec![Some(6), Some(7), Some(8), None, Some(8)]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(45, c.value(0)); - assert_eq!(-1, c.value(1)); - assert_eq!(7, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(1, c.value(4)); - } - - #[test] - fn test_date32_month_subtract() { - let a = Date32Array::from(vec![Date32Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 7, 1).unwrap(), - )]); - let b = - IntervalYearMonthArray::from(vec![IntervalYearMonthType::make_value(6, 3)]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(1994, 4, 1).unwrap()) - ); - } - - #[test] - fn test_date32_day_time_subtract() { - let a = Date32Array::from(vec![Date32Type::from_naive_date( - NaiveDate::from_ymd_opt(2023, 3, 29).unwrap(), - )]); - let b = - IntervalDayTimeArray::from(vec![IntervalDayTimeType::make_value(1, 86500)]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2023, 3, 28).unwrap()) - ); - } - - #[test] - fn test_date32_month_day_nano_subtract() { - let a = Date32Array::from(vec![Date32Type::from_naive_date( - NaiveDate::from_ymd_opt(2023, 3, 15).unwrap(), - )]); - let b = - IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value( - 1, 2, 0, - )]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date32Type::from_naive_date(NaiveDate::from_ymd_opt(2023, 2, 13).unwrap()) - ); - } - - #[test] - fn test_date64_month_subtract() { - let a = Date64Array::from(vec![Date64Type::from_naive_date( - NaiveDate::from_ymd_opt(2000, 7, 1).unwrap(), - )]); - let b = - IntervalYearMonthArray::from(vec![IntervalYearMonthType::make_value(6, 3)]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(1994, 4, 1).unwrap()) - ); - } - - #[test] - fn test_date64_day_time_subtract() { - let a = Date64Array::from(vec![Date64Type::from_naive_date( - NaiveDate::from_ymd_opt(2023, 3, 29).unwrap(), - )]); - let b = - IntervalDayTimeArray::from(vec![IntervalDayTimeType::make_value(1, 86500)]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2023, 3, 28).unwrap()) - ); - } - - #[test] - fn test_date64_month_day_nano_subtract() { - let a = Date64Array::from(vec![Date64Type::from_naive_date( - NaiveDate::from_ymd_opt(2023, 3, 15).unwrap(), - )]); - let b = - IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNanoType::make_value( - 1, 2, 0, - )]); - let c = subtract_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!( - c.value(0), - Date64Type::from_naive_date(NaiveDate::from_ymd_opt(2023, 2, 13).unwrap()) - ); - } - - #[test] - fn test_primitive_array_subtract_scalar_dyn() { - let a = Int32Array::from(vec![Some(5), Some(6), Some(7), None, Some(9)]); - let b = 1_i32; - let c = subtract_scalar_dyn::(&a, b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(4, c.value(0)); - assert_eq!(5, c.value(1)); - assert_eq!(6, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(8, c.value(4)); - - let mut builder = PrimitiveDictionaryBuilder::::new(); - builder.append(5).unwrap(); - builder.append_null(); - builder.append(7).unwrap(); - builder.append(8).unwrap(); - builder.append(9).unwrap(); - let a = builder.finish(); - let b = -1_i32; - - let c = subtract_scalar_dyn::(&a, b).unwrap(); - let c = c - .as_any() - .downcast_ref::>() - .unwrap(); - let values = c - .values() - .as_any() - .downcast_ref::>() - .unwrap(); - assert_eq!(6, values.value(c.key(0).unwrap())); - assert!(c.is_null(1)); - assert_eq!(8, values.value(c.key(2).unwrap())); - assert_eq!(9, values.value(c.key(3).unwrap())); - assert_eq!(10, values.value(c.key(4).unwrap())); - } - - #[test] - fn test_primitive_array_multiply_dyn() { - let a = Int32Array::from(vec![Some(5), Some(6), Some(7), Some(8), Some(9)]); - let b = Int32Array::from(vec![Some(6), Some(7), Some(8), None, Some(8)]); - let c = multiply_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(30, c.value(0)); - assert_eq!(42, c.value(1)); - assert_eq!(56, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(72, c.value(4)); - } - - #[test] - fn test_primitive_array_divide_dyn() { - let a = Int32Array::from(vec![Some(15), Some(6), Some(1), Some(8), Some(9)]); - let b = Int32Array::from(vec![Some(5), Some(3), Some(1), None, Some(3)]); - let c = divide_dyn(&a, &b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(3, c.value(0)); - assert_eq!(2, c.value(1)); - assert_eq!(1, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(3, c.value(4)); - } - - #[test] - fn test_primitive_array_multiply_scalar_dyn() { - let a = Int32Array::from(vec![Some(5), Some(6), Some(7), None, Some(9)]); - let b = 2_i32; - let c = multiply_scalar_dyn::(&a, b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(10, c.value(0)); - assert_eq!(12, c.value(1)); - assert_eq!(14, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(18, c.value(4)); - - let mut builder = PrimitiveDictionaryBuilder::::new(); - builder.append(5).unwrap(); - builder.append_null(); - builder.append(7).unwrap(); - builder.append(8).unwrap(); - builder.append(9).unwrap(); - let a = builder.finish(); - let b = -1_i32; - - let c = multiply_scalar_dyn::(&a, b).unwrap(); - let c = c - .as_any() - .downcast_ref::>() - .unwrap(); - let values = c - .values() - .as_any() - .downcast_ref::>() - .unwrap(); - assert_eq!(-5, values.value(c.key(0).unwrap())); - assert!(c.is_null(1)); - assert_eq!(-7, values.value(c.key(2).unwrap())); - assert_eq!(-8, values.value(c.key(3).unwrap())); - assert_eq!(-9, values.value(c.key(4).unwrap())); - } - - #[test] - fn test_primitive_array_add_sliced() { - let a = Int32Array::from(vec![0, 0, 0, 5, 6, 7, 8, 9, 0]); - let b = Int32Array::from(vec![0, 0, 0, 6, 7, 8, 9, 8, 0]); - let a = a.slice(3, 5); - let b = b.slice(3, 5); - let a = a.as_any().downcast_ref::().unwrap(); - let b = b.as_any().downcast_ref::().unwrap(); - - assert_eq!(5, a.value(0)); - assert_eq!(6, b.value(0)); - - let c = add(a, b).unwrap(); - assert_eq!(5, c.len()); - assert_eq!(11, c.value(0)); - assert_eq!(13, c.value(1)); - assert_eq!(15, c.value(2)); - assert_eq!(17, c.value(3)); - assert_eq!(17, c.value(4)); - } - - #[test] - fn test_primitive_array_add_mismatched_length() { - let a = Int32Array::from(vec![5, 6, 7, 8, 9]); - let b = Int32Array::from(vec![6, 7, 8]); - let e = add(&a, &b).expect_err("should have failed due to different lengths"); - assert_eq!( - "ComputeError(\"Cannot perform binary operation on arrays of different length\")", - format!("{e:?}") - ); - } - - #[test] - fn test_primitive_array_add_scalar() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = 3; - let c = add_scalar(&a, b).unwrap(); - let expected = Int32Array::from(vec![18, 17, 12, 11, 4]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_array_add_scalar_sliced() { - let a = Int32Array::from(vec![Some(15), None, Some(9), Some(8), None]); - let a = a.slice(1, 4); - let actual = add_scalar(&a, 3).unwrap(); - let expected = Int32Array::from(vec![None, Some(12), Some(11), None]); - assert_eq!(actual, expected); - } - - #[test] - fn test_primitive_array_subtract() { - let a = Int32Array::from(vec![1, 2, 3, 4, 5]); - let b = Int32Array::from(vec![5, 4, 3, 2, 1]); - let c = subtract(&a, &b).unwrap(); - assert_eq!(-4, c.value(0)); - assert_eq!(-2, c.value(1)); - assert_eq!(0, c.value(2)); - assert_eq!(2, c.value(3)); - assert_eq!(4, c.value(4)); - } - - #[test] - fn test_primitive_array_subtract_scalar() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = 3; - let c = subtract_scalar(&a, b).unwrap(); - let expected = Int32Array::from(vec![12, 11, 6, 5, -2]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_array_subtract_scalar_sliced() { - let a = Int32Array::from(vec![Some(15), None, Some(9), Some(8), None]); - let a = a.slice(1, 4); - let actual = subtract_scalar(&a, 3).unwrap(); - let expected = Int32Array::from(vec![None, Some(6), Some(5), None]); - assert_eq!(actual, expected); - } - - #[test] - fn test_primitive_array_multiply() { - let a = Int32Array::from(vec![5, 6, 7, 8, 9]); - let b = Int32Array::from(vec![6, 7, 8, 9, 8]); - let c = multiply(&a, &b).unwrap(); - assert_eq!(30, c.value(0)); - assert_eq!(42, c.value(1)); - assert_eq!(56, c.value(2)); - assert_eq!(72, c.value(3)); - assert_eq!(72, c.value(4)); - } - - #[test] - fn test_primitive_array_multiply_scalar() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = 3; - let c = multiply_scalar(&a, b).unwrap(); - let expected = Int32Array::from(vec![45, 42, 27, 24, 3]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_array_multiply_scalar_sliced() { - let a = Int32Array::from(vec![Some(15), None, Some(9), Some(8), None]); - let a = a.slice(1, 4); - let actual = multiply_scalar(&a, 3).unwrap(); - let expected = Int32Array::from(vec![None, Some(27), Some(24), None]); - assert_eq!(actual, expected); - } - - #[test] - fn test_primitive_array_divide() { - let a = Int32Array::from(vec![15, 15, 8, 1, 9]); - let b = Int32Array::from(vec![5, 6, 8, 9, 1]); - let c = divide(&a, &b).unwrap(); - assert_eq!(3, c.value(0)); - assert_eq!(2, c.value(1)); - assert_eq!(1, c.value(2)); - assert_eq!(0, c.value(3)); - assert_eq!(9, c.value(4)); - } - - #[test] - fn test_int_array_modulus() { - let a = Int32Array::from(vec![15, 15, 8, 1, 9]); - let b = Int32Array::from(vec![5, 6, 8, 9, 1]); - let c = modulus(&a, &b).unwrap(); - assert_eq!(0, c.value(0)); - assert_eq!(3, c.value(1)); - assert_eq!(0, c.value(2)); - assert_eq!(1, c.value(3)); - assert_eq!(0, c.value(4)); - - let c = modulus_dyn(&a, &b).unwrap(); - let c = c.as_primitive::(); - assert_eq!(0, c.value(0)); - assert_eq!(3, c.value(1)); - assert_eq!(0, c.value(2)); - assert_eq!(1, c.value(3)); - assert_eq!(0, c.value(4)); - } - - #[test] - #[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: DivideByZero" - )] - fn test_int_array_modulus_divide_by_zero() { - let a = Int32Array::from(vec![1]); - let b = Int32Array::from(vec![0]); - modulus(&a, &b).unwrap(); - } - - #[test] - #[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: DivideByZero" - )] - fn test_int_array_modulus_dyn_divide_by_zero() { - let a = Int32Array::from(vec![1]); - let b = Int32Array::from(vec![0]); - modulus_dyn(&a, &b).unwrap(); - } - - #[test] - fn test_int_array_modulus_overflow_wrapping() { - let a = Int32Array::from(vec![i32::MIN]); - let b = Int32Array::from(vec![-1]); - let result = modulus(&a, &b).unwrap(); - assert_eq!(0, result.value(0)) - } - - #[test] - fn test_primitive_array_divide_scalar() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = 3; - let c = divide_scalar(&a, b).unwrap(); - let expected = Int32Array::from(vec![5, 4, 3, 2, 0]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_array_divide_scalar_dyn() { - let a = Int32Array::from(vec![Some(5), Some(6), Some(7), None, Some(9)]); - let b = 2_i32; - let c = divide_scalar_dyn::(&a, b).unwrap(); - let c = c.as_any().downcast_ref::().unwrap(); - assert_eq!(2, c.value(0)); - assert_eq!(3, c.value(1)); - assert_eq!(3, c.value(2)); - assert!(c.is_null(3)); - assert_eq!(4, c.value(4)); - - let mut builder = PrimitiveDictionaryBuilder::::new(); - builder.append(5).unwrap(); - builder.append_null(); - builder.append(7).unwrap(); - builder.append(8).unwrap(); - builder.append(9).unwrap(); - let a = builder.finish(); - let b = -2_i32; - - let c = divide_scalar_dyn::(&a, b).unwrap(); - let c = c - .as_any() - .downcast_ref::>() - .unwrap(); - let values = c - .values() - .as_any() - .downcast_ref::>() - .unwrap(); - assert_eq!(-2, values.value(c.key(0).unwrap())); - assert!(c.is_null(1)); - assert_eq!(-3, values.value(c.key(2).unwrap())); - assert_eq!(-4, values.value(c.key(3).unwrap())); - assert_eq!(-4, values.value(c.key(4).unwrap())); - - let e = divide_scalar_dyn::(&a, 0_i32) - .expect_err("should have failed due to divide by zero"); - assert_eq!("DivideByZero", format!("{e:?}")); - } - - #[test] - fn test_primitive_array_divide_scalar_sliced() { - let a = Int32Array::from(vec![Some(15), None, Some(9), Some(8), None]); - let a = a.slice(1, 4); - let actual = divide_scalar(&a, 3).unwrap(); - let expected = Int32Array::from(vec![None, Some(3), Some(2), None]); - assert_eq!(actual, expected); - } - - #[test] - fn test_int_array_modulus_scalar() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = 3; - let c = modulus_scalar(&a, b).unwrap(); - let expected = Int32Array::from(vec![0, 2, 0, 2, 1]); - assert_eq!(c, expected); - - let c = modulus_scalar_dyn::(&a, b).unwrap(); - let c = c.as_primitive::(); - let expected = Int32Array::from(vec![0, 2, 0, 2, 1]); - assert_eq!(c, &expected); - } - - #[test] - fn test_int_array_modulus_scalar_sliced() { - let a = Int32Array::from(vec![Some(15), None, Some(9), Some(8), None]); - let a = a.slice(1, 4); - let actual = modulus_scalar(&a, 3).unwrap(); - let expected = Int32Array::from(vec![None, Some(0), Some(2), None]); - assert_eq!(actual, expected); - - let actual = modulus_scalar_dyn::(&a, 3).unwrap(); - let actual = actual.as_primitive::(); - let expected = Int32Array::from(vec![None, Some(0), Some(2), None]); - assert_eq!(actual, &expected); - } - - #[test] - #[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: DivideByZero" - )] - fn test_int_array_modulus_scalar_divide_by_zero() { - let a = Int32Array::from(vec![1]); - modulus_scalar(&a, 0).unwrap(); - } - - #[test] - fn test_int_array_modulus_scalar_overflow_wrapping() { - let a = Int32Array::from(vec![i32::MIN]); - let result = modulus_scalar(&a, -1).unwrap(); - assert_eq!(0, result.value(0)); - - let result = modulus_scalar_dyn::(&a, -1).unwrap(); - let result = result.as_primitive::(); - assert_eq!(0, result.value(0)); - } - - #[test] - fn test_primitive_array_divide_sliced() { - let a = Int32Array::from(vec![0, 0, 0, 15, 15, 8, 1, 9, 0]); - let b = Int32Array::from(vec![0, 0, 0, 5, 6, 8, 9, 1, 0]); - let a = a.slice(3, 5); - let b = b.slice(3, 5); - let a = a.as_any().downcast_ref::().unwrap(); - let b = b.as_any().downcast_ref::().unwrap(); - - let c = divide(a, b).unwrap(); - assert_eq!(5, c.len()); - assert_eq!(3, c.value(0)); - assert_eq!(2, c.value(1)); - assert_eq!(1, c.value(2)); - assert_eq!(0, c.value(3)); - assert_eq!(9, c.value(4)); - } - - #[test] - fn test_primitive_array_modulus_sliced() { - let a = Int32Array::from(vec![0, 0, 0, 15, 15, 8, 1, 9, 0]); - let b = Int32Array::from(vec![0, 0, 0, 5, 6, 8, 9, 1, 0]); - let a = a.slice(3, 5); - let b = b.slice(3, 5); - let a = a.as_any().downcast_ref::().unwrap(); - let b = b.as_any().downcast_ref::().unwrap(); - - let c = modulus(a, b).unwrap(); - assert_eq!(5, c.len()); - assert_eq!(0, c.value(0)); - assert_eq!(3, c.value(1)); - assert_eq!(0, c.value(2)); - assert_eq!(1, c.value(3)); - assert_eq!(0, c.value(4)); - } - - #[test] - fn test_primitive_array_divide_with_nulls() { - let a = Int32Array::from(vec![Some(15), None, Some(8), Some(1), Some(9), None]); - let b = Int32Array::from(vec![Some(5), Some(6), Some(8), Some(9), None, None]); - let c = divide_checked(&a, &b).unwrap(); - assert_eq!(3, c.value(0)); - assert!(c.is_null(1)); - assert_eq!(1, c.value(2)); - assert_eq!(0, c.value(3)); - assert!(c.is_null(4)); - assert!(c.is_null(5)); - } - - #[test] - fn test_primitive_array_modulus_with_nulls() { - let a = Int32Array::from(vec![Some(15), None, Some(8), Some(1), Some(9), None]); - let b = Int32Array::from(vec![Some(5), Some(6), Some(8), Some(9), None, None]); - let c = modulus(&a, &b).unwrap(); - assert_eq!(0, c.value(0)); - assert!(c.is_null(1)); - assert_eq!(0, c.value(2)); - assert_eq!(1, c.value(3)); - assert!(c.is_null(4)); - assert!(c.is_null(5)); - } - - #[test] - fn test_primitive_array_divide_scalar_with_nulls() { - let a = Int32Array::from(vec![Some(15), None, Some(8), Some(1), Some(9), None]); - let b = 3; - let c = divide_scalar(&a, b).unwrap(); - let expected = - Int32Array::from(vec![Some(5), None, Some(2), Some(0), Some(3), None]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_array_modulus_scalar_with_nulls() { - let a = Int32Array::from(vec![Some(15), None, Some(8), Some(1), Some(9), None]); - let b = 3; - let c = modulus_scalar(&a, b).unwrap(); - let expected = - Int32Array::from(vec![Some(0), None, Some(2), Some(1), Some(0), None]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_array_divide_with_nulls_sliced() { - let a = Int32Array::from(vec![ - None, - None, - None, - None, - None, - None, - None, - None, - Some(15), - None, - Some(8), - Some(1), - Some(9), - None, - None, - ]); - let b = Int32Array::from(vec![ - None, - None, - None, - None, - None, - None, - None, - None, - Some(5), - Some(6), - Some(8), - Some(9), - None, - None, - None, - ]); - - let a = a.slice(8, 6); - let a = a.as_any().downcast_ref::().unwrap(); - - let b = b.slice(8, 6); - let b = b.as_any().downcast_ref::().unwrap(); - - let c = divide_checked(a, b).unwrap(); - assert_eq!(6, c.len()); - assert_eq!(3, c.value(0)); - assert!(c.is_null(1)); - assert_eq!(1, c.value(2)); - assert_eq!(0, c.value(3)); - assert!(c.is_null(4)); - assert!(c.is_null(5)); - } - - #[test] - fn test_primitive_array_modulus_with_nulls_sliced() { - let a = Int32Array::from(vec![ - None, - None, - None, - None, - None, - None, - None, - None, - Some(15), - None, - Some(8), - Some(1), - Some(9), - None, - None, - ]); - let b = Int32Array::from(vec![ - None, - None, - None, - None, - None, - None, - None, - None, - Some(5), - Some(6), - Some(8), - Some(9), - None, - None, - None, - ]); - - let a = a.slice(8, 6); - let a = a.as_any().downcast_ref::().unwrap(); - - let b = b.slice(8, 6); - let b = b.as_any().downcast_ref::().unwrap(); - - let c = modulus(a, b).unwrap(); - assert_eq!(6, c.len()); - assert_eq!(0, c.value(0)); - assert!(c.is_null(1)); - assert_eq!(0, c.value(2)); - assert_eq!(1, c.value(3)); - assert!(c.is_null(4)); - assert!(c.is_null(5)); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_int_array_divide_by_zero_with_checked() { - let a = Int32Array::from(vec![15]); - let b = Int32Array::from(vec![0]); - divide_checked(&a, &b).unwrap(); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_f32_array_divide_by_zero_with_checked() { - let a = Float32Array::from(vec![15.0]); - let b = Float32Array::from(vec![0.0]); - divide_checked(&a, &b).unwrap(); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn test_int_array_divide_by_zero() { - let a = Int32Array::from(vec![15]); - let b = Int32Array::from(vec![0]); - divide(&a, &b).unwrap(); - } - - #[test] - fn test_f32_array_divide_by_zero() { - let a = Float32Array::from(vec![1.5, 0.0, -1.5]); - let b = Float32Array::from(vec![0.0, 0.0, 0.0]); - let result = divide(&a, &b).unwrap(); - assert_eq!(result.value(0), f32::INFINITY); - assert!(result.value(1).is_nan()); - assert_eq!(result.value(2), f32::NEG_INFINITY); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_int_array_divide_dyn_by_zero() { - let a = Int32Array::from(vec![15]); - let b = Int32Array::from(vec![0]); - divide_dyn(&a, &b).unwrap(); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_f32_array_divide_dyn_by_zero() { - let a = Float32Array::from(vec![1.5]); - let b = Float32Array::from(vec![0.0]); - divide_dyn(&a, &b).unwrap(); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_i32_array_modulus_by_zero() { - let a = Int32Array::from(vec![15]); - let b = Int32Array::from(vec![0]); - modulus(&a, &b).unwrap(); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_i32_array_modulus_dyn_by_zero() { - let a = Int32Array::from(vec![15]); - let b = Int32Array::from(vec![0]); - modulus_dyn(&a, &b).unwrap(); - } - - #[test] - #[should_panic(expected = "DivideByZero")] - fn test_f32_array_modulus_by_zero() { - let a = Float32Array::from(vec![1.5]); - let b = Float32Array::from(vec![0.0]); - modulus(&a, &b).unwrap(); - } - - #[test] - fn test_f32_array_modulus_dyn_by_zero() { - let a = Float32Array::from(vec![1.5]); - let b = Float32Array::from(vec![0.0]); - let result = modulus_dyn(&a, &b).unwrap(); - assert!(result.as_primitive::().value(0).is_nan()); - } - - #[test] - fn test_f64_array_divide() { - let a = Float64Array::from(vec![15.0, 15.0, 8.0]); - let b = Float64Array::from(vec![5.0, 6.0, 8.0]); - let c = divide(&a, &b).unwrap(); - assert_eq!(3.0, c.value(0)); - assert_eq!(2.5, c.value(1)); - assert_eq!(1.0, c.value(2)); - } - - #[test] - fn test_primitive_array_add_with_nulls() { - let a = Int32Array::from(vec![Some(5), None, Some(7), None]); - let b = Int32Array::from(vec![None, None, Some(6), Some(7)]); - let c = add(&a, &b).unwrap(); - assert!(c.is_null(0)); - assert!(c.is_null(1)); - assert!(!c.is_null(2)); - assert!(c.is_null(3)); - assert_eq!(13, c.value(2)); - } - - #[test] - fn test_primitive_array_negate() { - let a: Int64Array = (0..100).map(Some).collect(); - let actual = negate(&a).unwrap(); - let expected: Int64Array = (0..100).map(|i| Some(-i)).collect(); - assert_eq!(expected, actual); - } - - #[test] - fn test_primitive_array_negate_checked_overflow() { - let a = Int32Array::from(vec![i32::MIN]); - let actual = negate(&a).unwrap(); - let expected = Int32Array::from(vec![i32::MIN]); - assert_eq!(expected, actual); - - let err = negate_checked(&a); - err.expect_err("negate_checked should detect overflow"); - } - - #[test] - fn test_arithmetic_kernel_should_not_rely_on_padding() { - let a: UInt8Array = (0..128_u8).map(Some).collect(); - let a = a.slice(63, 65); - let a = a.as_any().downcast_ref::().unwrap(); - - let b: UInt8Array = (0..128_u8).map(Some).collect(); - let b = b.slice(63, 65); - let b = b.as_any().downcast_ref::().unwrap(); - - let actual = add(a, b).unwrap(); - let actual: Vec> = actual.iter().collect(); - let expected: Vec> = - (63..63_u8 + 65_u8).map(|i| Some(i + i)).collect(); - assert_eq!(expected, actual); - } - - #[test] - fn test_primitive_add_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - let b = Int32Array::from(vec![1, 1]); - - let wrapped = add(&a, &b); - let expected = Int32Array::from(vec![-2147483648, -2147483647]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = add_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_subtract_wrapping_overflow() { - let a = Int32Array::from(vec![-2]); - let b = Int32Array::from(vec![i32::MAX]); - - let wrapped = subtract(&a, &b); - let expected = Int32Array::from(vec![i32::MAX]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = subtract_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_mul_wrapping_overflow() { - let a = Int32Array::from(vec![10]); - let b = Int32Array::from(vec![i32::MAX]); - - let wrapped = multiply(&a, &b); - let expected = Int32Array::from(vec![-10]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = multiply_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - #[cfg(not(feature = "simd"))] - fn test_primitive_div_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MIN]); - let b = Int32Array::from(vec![-1]); - - let wrapped = divide(&a, &b); - let expected = Int32Array::from(vec![-2147483648]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = divide_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_add_scalar_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - - let wrapped = add_scalar(&a, 1); - let expected = Int32Array::from(vec![-2147483648, -2147483647]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = add_scalar_checked(&a, 1); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_subtract_scalar_wrapping_overflow() { - let a = Int32Array::from(vec![-2]); - - let wrapped = subtract_scalar(&a, i32::MAX); - let expected = Int32Array::from(vec![i32::MAX]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = subtract_scalar_checked(&a, i32::MAX); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_mul_scalar_wrapping_overflow() { - let a = Int32Array::from(vec![10]); - - let wrapped = multiply_scalar(&a, i32::MAX); - let expected = Int32Array::from(vec![-10]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = multiply_scalar_checked(&a, i32::MAX); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_add_scalar_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - - let wrapped = add_scalar_dyn::(&a, 1).unwrap(); - let expected = - Arc::new(Int32Array::from(vec![-2147483648, -2147483647])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = add_scalar_checked_dyn::(&a, 1); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_subtract_scalar_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![-2]); - - let wrapped = subtract_scalar_dyn::(&a, i32::MAX).unwrap(); - let expected = Arc::new(Int32Array::from(vec![i32::MAX])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = subtract_scalar_checked_dyn::(&a, i32::MAX); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_mul_scalar_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![10]); - - let wrapped = multiply_scalar_dyn::(&a, i32::MAX).unwrap(); - let expected = Arc::new(Int32Array::from(vec![-10])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = multiply_scalar_checked_dyn::(&a, i32::MAX); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_div_scalar_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MIN]); - - let wrapped = divide_scalar_dyn::(&a, -1).unwrap(); - let expected = Arc::new(Int32Array::from(vec![-2147483648])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = divide_scalar_checked_dyn::(&a, -1); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_div_opt_overflow_division_by_zero() { - let a = Int32Array::from(vec![i32::MIN]); - let b = Int32Array::from(vec![-1]); - - let wrapped = divide(&a, &b); - let expected = Int32Array::from(vec![-2147483648]); - assert_eq!(expected, wrapped.unwrap()); - - let overflow = divide_opt(&a, &b); - let expected = Int32Array::from(vec![-2147483648]); - assert_eq!(expected, overflow.unwrap()); - - let b = Int32Array::from(vec![0]); - let overflow = divide_opt(&a, &b); - let expected = Int32Array::from(vec![None]); - assert_eq!(expected, overflow.unwrap()); - } - - #[test] - fn test_primitive_add_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - let b = Int32Array::from(vec![1, 1]); - - let wrapped = add_dyn(&a, &b).unwrap(); - let expected = - Arc::new(Int32Array::from(vec![-2147483648, -2147483647])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = add_dyn_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_subtract_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![-2]); - let b = Int32Array::from(vec![i32::MAX]); - - let wrapped = subtract_dyn(&a, &b).unwrap(); - let expected = Arc::new(Int32Array::from(vec![i32::MAX])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = subtract_dyn_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_mul_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![10]); - let b = Int32Array::from(vec![i32::MAX]); - - let wrapped = multiply_dyn(&a, &b).unwrap(); - let expected = Arc::new(Int32Array::from(vec![-10])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = multiply_dyn_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_div_dyn_wrapping_overflow() { - let a = Int32Array::from(vec![i32::MIN]); - let b = Int32Array::from(vec![-1]); - - let wrapped = divide_dyn(&a, &b).unwrap(); - let expected = Arc::new(Int32Array::from(vec![-2147483648])) as ArrayRef; - assert_eq!(&expected, &wrapped); - - let overflow = divide_dyn_checked(&a, &b); - overflow.expect_err("overflow should be detected"); - } - - #[test] - fn test_decimal128() { - let a = Decimal128Array::from_iter_values([1, 2, 4, 5]); - let b = Decimal128Array::from_iter_values([7, -3, 6, 3]); - let e = Decimal128Array::from_iter_values([8, -1, 10, 8]); - let r = add(&a, &b).unwrap(); - assert_eq!(e, r); - - let e = Decimal128Array::from_iter_values([-6, 5, -2, 2]); - let r = subtract(&a, &b).unwrap(); - assert_eq!(e, r); - - let e = Decimal128Array::from_iter_values([7, -6, 24, 15]); - let r = multiply(&a, &b).unwrap(); - assert_eq!(e, r); - - let a = Decimal128Array::from_iter_values([23, 56, 32, 55]); - let b = Decimal128Array::from_iter_values([1, -2, 4, 5]); - let e = Decimal128Array::from_iter_values([23, -28, 8, 11]); - let r = divide(&a, &b).unwrap(); - assert_eq!(e, r); - } - - #[test] - fn test_decimal256() { - let a = Decimal256Array::from_iter_values( - [1, 2, 4, 5].into_iter().map(i256::from_i128), - ); - let b = Decimal256Array::from_iter_values( - [7, -3, 6, 3].into_iter().map(i256::from_i128), - ); - let e = Decimal256Array::from_iter_values( - [8, -1, 10, 8].into_iter().map(i256::from_i128), - ); - let r = add(&a, &b).unwrap(); - assert_eq!(e, r); - - let e = Decimal256Array::from_iter_values( - [-6, 5, -2, 2].into_iter().map(i256::from_i128), - ); - let r = subtract(&a, &b).unwrap(); - assert_eq!(e, r); - - let e = Decimal256Array::from_iter_values( - [7, -6, 24, 15].into_iter().map(i256::from_i128), - ); - let r = multiply(&a, &b).unwrap(); - assert_eq!(e, r); - - let a = Decimal256Array::from_iter_values( - [23, 56, 32, 55].into_iter().map(i256::from_i128), - ); - let b = Decimal256Array::from_iter_values( - [1, -2, 4, 5].into_iter().map(i256::from_i128), - ); - let e = Decimal256Array::from_iter_values( - [23, -28, 8, 11].into_iter().map(i256::from_i128), - ); - let r = divide(&a, &b).unwrap(); - assert_eq!(e, r); - } - - #[test] - fn test_div_scalar_dyn_opt_overflow_division_by_zero() { - let a = Int32Array::from(vec![i32::MIN]); - - let division_by_zero = divide_scalar_opt_dyn::(&a, 0); - let expected = Arc::new(Int32Array::from(vec![None])) as ArrayRef; - assert_eq!(&expected, &division_by_zero.unwrap()); - - let mut builder = - PrimitiveDictionaryBuilder::::with_capacity(1, 1); - builder.append(i32::MIN).unwrap(); - let a = builder.finish(); - - let division_by_zero = divide_scalar_opt_dyn::(&a, 0); - assert_eq!(&expected, &division_by_zero.unwrap()); - } - - #[test] - fn test_sum_f16() { - let a = Float16Array::from_iter_values([ - f16::from_f32(0.1), - f16::from_f32(0.2), - f16::from_f32(1.5), - f16::from_f32(-0.1), - ]); - let b = Float16Array::from_iter_values([ - f16::from_f32(5.1), - f16::from_f32(6.2), - f16::from_f32(-1.), - f16::from_f32(-2.1), - ]); - let expected = Float16Array::from_iter_values( - a.values().iter().zip(b.values()).map(|(a, b)| a + b), - ); - - let c = add(&a, &b).unwrap(); - assert_eq!(c, expected); - } - - #[test] - fn test_resize_builder() { - let mut null_buffer_builder = BooleanBufferBuilder::new(16); - null_buffer_builder.append_slice(&[ - false, false, false, false, false, false, false, false, false, false, false, - false, false, true, true, true, - ]); - // `resize` resizes the buffer length to the ceil of byte numbers. - // So the underlying buffer is not changed. - null_buffer_builder.resize(13); - assert_eq!(null_buffer_builder.len(), 13); - - let nulls = null_buffer_builder.finish(); - assert_eq!(nulls.count_set_bits(), 0); - let nulls = NullBuffer::new(nulls); - assert_eq!(nulls.null_count(), 13); - - let mut data_buffer_builder = BufferBuilder::::new(13); - data_buffer_builder.append_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - let data_buffer = data_buffer_builder.finish(); - - let arg1: Int32Array = ArrayDataBuilder::new(DataType::Int32) - .len(13) - .nulls(Some(nulls)) - .buffers(vec![data_buffer]) - .build() - .unwrap() - .into(); - - assert_eq!(arg1.null_count(), 13); - - let mut data_buffer_builder = BufferBuilder::::new(13); - data_buffer_builder.append_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - let data_buffer = data_buffer_builder.finish(); - - let arg2: Int32Array = ArrayDataBuilder::new(DataType::Int32) - .len(13) - .buffers(vec![data_buffer]) - .build() - .unwrap() - .into(); - - assert_eq!(arg2.null_count(), 0); - - let result_dyn = add_dyn(&arg1, &arg2).unwrap(); - let result = result_dyn.as_any().downcast_ref::().unwrap(); - - assert_eq!(result.len(), 13); - assert_eq!(result.null_count(), 13); - } - - #[test] - fn test_primitive_array_add_mut_by_binary_mut() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = Int32Array::from(vec![Some(1), None, Some(3), None, Some(5)]); - - let c = binary_mut(a, &b, |a, b| a.add_wrapping(b)) - .unwrap() - .unwrap(); - let expected = Int32Array::from(vec![Some(16), None, Some(12), None, Some(6)]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_add_mut_wrapping_overflow_by_try_binary_mut() { - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - let b = Int32Array::from(vec![1, 1]); - - let wrapped = binary_mut(a, &b, |a, b| a.add_wrapping(b)) - .unwrap() - .unwrap(); - let expected = Int32Array::from(vec![-2147483648, -2147483647]); - assert_eq!(expected, wrapped); - - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - let b = Int32Array::from(vec![1, 1]); - let overflow = try_binary_mut(a, &b, |a, b| a.add_checked(b)); - let _ = overflow.unwrap().expect_err("overflow should be detected"); - } - - #[test] - fn test_primitive_add_scalar_by_unary_mut() { - let a = Int32Array::from(vec![15, 14, 9, 8, 1]); - let b = 3; - let c = unary_mut(a, |value| value.add_wrapping(b)).unwrap(); - let expected = Int32Array::from(vec![18, 17, 12, 11, 4]); - assert_eq!(c, expected); - } - - #[test] - fn test_primitive_add_scalar_overflow_by_try_unary_mut() { - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - - let wrapped = unary_mut(a, |value| value.add_wrapping(1)).unwrap(); - let expected = Int32Array::from(vec![-2147483648, -2147483647]); - assert_eq!(expected, wrapped); - - let a = Int32Array::from(vec![i32::MAX, i32::MIN]); - let overflow = try_unary_mut(a, |value| value.add_checked(1)); - let _ = overflow.unwrap().expect_err("overflow should be detected"); - } - - #[test] - fn test_decimal_add_scalar_dyn() { - let a = Decimal128Array::from(vec![100, 210, 320]) - .with_precision_and_scale(38, 2) - .unwrap(); - - let result = add_scalar_dyn::(&a, 1).unwrap(); - let result = result - .as_primitive::() - .clone() - .with_precision_and_scale(38, 2) - .unwrap(); - let expected = Decimal128Array::from(vec![101, 211, 321]) - .with_precision_and_scale(38, 2) - .unwrap(); - - assert_eq!(&expected, &result); - } - - #[test] - fn test_decimal_multiply_allow_precision_loss() { - // Overflow happening as i128 cannot hold multiplying result. - // [123456789] - let a = Decimal128Array::from(vec![123456789000000000000000000]) - .with_precision_and_scale(38, 18) - .unwrap(); - - // [10] - let b = Decimal128Array::from(vec![10000000000000000000]) - .with_precision_and_scale(38, 18) - .unwrap(); - - let err = multiply_dyn_checked(&a, &b).unwrap_err(); - assert!(err.to_string().contains( - "Overflow happened on: 123456789000000000000000000 * 10000000000000000000" - )); - - // Allow precision loss. - let result = multiply_fixed_point_checked(&a, &b, 28).unwrap(); - // [1234567890] - let expected = - Decimal128Array::from(vec![12345678900000000000000000000000000000]) - .with_precision_and_scale(38, 28) - .unwrap(); - - assert_eq!(&expected, &result); - assert_eq!( - result.value_as_string(0), - "1234567890.0000000000000000000000000000" - ); - - // Rounding case - // [0.000000000000000001, 123456789.555555555555555555, 1.555555555555555555] - let a = Decimal128Array::from(vec![ - 1, - 123456789555555555555555555, - 1555555555555555555, - ]) - .with_precision_and_scale(38, 18) - .unwrap(); - - // [1.555555555555555555, 11.222222222222222222, 0.000000000000000001] - let b = Decimal128Array::from(vec![1555555555555555555, 11222222222222222222, 1]) - .with_precision_and_scale(38, 18) - .unwrap(); - - let result = multiply_fixed_point_checked(&a, &b, 28).unwrap(); - // [ - // 0.0000000000000000015555555556, - // 1385459527.2345679012071330528765432099, - // 0.0000000000000000015555555556 - // ] - let expected = Decimal128Array::from(vec![ - 15555555556, - 13854595272345679012071330528765432099, - 15555555556, - ]) - .with_precision_and_scale(38, 28) - .unwrap(); - - assert_eq!(&expected, &result); - - // Rounded the value "1385459527.234567901207133052876543209876543210". - assert_eq!( - result.value_as_string(1), - "1385459527.2345679012071330528765432099" - ); - assert_eq!(result.value_as_string(0), "0.0000000000000000015555555556"); - assert_eq!(result.value_as_string(2), "0.0000000000000000015555555556"); + // Rounded the value "1385459527.234567901207133052876543209876543210". + assert_eq!( + result.value_as_string(1), + "1385459527.2345679012071330528765432099" + ); + assert_eq!(result.value_as_string(0), "0.0000000000000000015555555556"); + assert_eq!(result.value_as_string(2), "0.0000000000000000015555555556"); let a = Decimal128Array::from(vec![1230]) .with_precision_and_scale(4, 2) @@ -2609,11 +283,8 @@ mod tests { assert_eq!(result.precision(), 9); assert_eq!(result.scale(), 4); - let expected = multiply_checked(&a, &b) - .unwrap() - .with_precision_and_scale(9, 4) - .unwrap(); - assert_eq!(&expected, &result); + let expected = mul(&a, &b).unwrap(); + assert_eq!(expected.as_ref(), &result); // Required scale cannot be larger than the product of the input scales. let result = multiply_fixed_point_checked(&a, &b, 5).unwrap_err(); @@ -2661,12 +332,8 @@ mod tests { .unwrap(); // `multiply` overflows on this case. - let result = multiply(&a, &b).unwrap(); - let expected = - Decimal128Array::from(vec![-16672482290199102048610367863168958464]) - .with_precision_and_scale(38, 10) - .unwrap(); - assert_eq!(&expected, &result); + let err = mul(&a, &b).unwrap_err(); + assert_eq!(err.to_string(), "Compute error: Overflow happened on: 123456789000000000000000000 * 10000000000000000000"); // Avoid overflow by reducing the scale. let result = multiply_fixed_point(&a, &b, 28).unwrap(); @@ -2682,693 +349,4 @@ mod tests { "1234567890.0000000000000000000000000000" ); } - - #[test] - fn test_timestamp_second_add_interval() { - // timestamp second + interval year month - let a = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampSecondArray::from(vec![ - 1 + SECONDS_IN_DAY * (365 + 31 + 28), - 2 + SECONDS_IN_DAY * (365 + 31 + 28), - 3 + SECONDS_IN_DAY * (365 + 31 + 28), - 4 + SECONDS_IN_DAY * (365 + 31 + 28), - 5 + SECONDS_IN_DAY * (365 + 31 + 28), - ]); - assert_eq!(result, &expected); - - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp second + interval day time - let a = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampSecondArray::from(vec![ - 1 + SECONDS_IN_DAY, - 2 + SECONDS_IN_DAY, - 3 + SECONDS_IN_DAY, - 4 + SECONDS_IN_DAY, - 5 + SECONDS_IN_DAY, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp second + interval month day nanosecond - let a = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampSecondArray::from(vec![ - 1 + SECONDS_IN_DAY, - 2 + SECONDS_IN_DAY, - 3 + SECONDS_IN_DAY, - 4 + SECONDS_IN_DAY, - 5 + SECONDS_IN_DAY, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - } - - #[test] - fn test_timestamp_second_subtract_interval() { - // timestamp second + interval year month - let a = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampSecondArray::from(vec![ - 1 - SECONDS_IN_DAY * (31 + 30 + 365), - 2 - SECONDS_IN_DAY * (31 + 30 + 365), - 3 - SECONDS_IN_DAY * (31 + 30 + 365), - 4 - SECONDS_IN_DAY * (31 + 30 + 365), - 5 - SECONDS_IN_DAY * (31 + 30 + 365), - ]); - assert_eq!(&expected, result); - - // timestamp second + interval day time - let a = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampSecondArray::from(vec![ - 1 - SECONDS_IN_DAY, - 2 - SECONDS_IN_DAY, - 3 - SECONDS_IN_DAY, - 4 - SECONDS_IN_DAY, - 5 - SECONDS_IN_DAY, - ]); - assert_eq!(&expected, result); - - // timestamp second + interval month day nanosecond - let a = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampSecondArray::from(vec![ - 1 - SECONDS_IN_DAY, - 2 - SECONDS_IN_DAY, - 3 - SECONDS_IN_DAY, - 4 - SECONDS_IN_DAY, - 5 - SECONDS_IN_DAY, - ]); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_millisecond_add_interval() { - // timestamp millisecond + interval year month - let a = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMillisecondArray::from(vec![ - 1 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000, - 2 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000, - 3 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000, - 4 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000, - 5 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000, - ]); - assert_eq!(result, &expected); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp millisecond + interval day time - let a = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMillisecondArray::from(vec![ - 1 + SECONDS_IN_DAY * 1_000, - 2 + SECONDS_IN_DAY * 1_000, - 3 + SECONDS_IN_DAY * 1_000, - 4 + SECONDS_IN_DAY * 1_000, - 5 + SECONDS_IN_DAY * 1_000, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp millisecond + interval month day nanosecond - let a = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMillisecondArray::from(vec![ - 1 + SECONDS_IN_DAY * 1_000, - 2 + SECONDS_IN_DAY * 1_000, - 3 + SECONDS_IN_DAY * 1_000, - 4 + SECONDS_IN_DAY * 1_000, - 5 + SECONDS_IN_DAY * 1_000, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - } - - #[test] - fn test_timestamp_millisecond_subtract_interval() { - // timestamp millisecond + interval year month - let a = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMillisecondArray::from(vec![ - 1 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000, - 2 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000, - 3 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000, - 4 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000, - 5 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000, - ]); - assert_eq!(&expected, result); - - // timestamp millisecond + interval day time - let a = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMillisecondArray::from(vec![ - 1 - SECONDS_IN_DAY * 1_000, - 2 - SECONDS_IN_DAY * 1_000, - 3 - SECONDS_IN_DAY * 1_000, - 4 - SECONDS_IN_DAY * 1_000, - 5 - SECONDS_IN_DAY * 1_000, - ]); - assert_eq!(&expected, result); - - // timestamp millisecond + interval month day nanosecond - let a = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMillisecondArray::from(vec![ - 1 - SECONDS_IN_DAY * 1_000, - 2 - SECONDS_IN_DAY * 1_000, - 3 - SECONDS_IN_DAY * 1_000, - 4 - SECONDS_IN_DAY * 1_000, - 5 - SECONDS_IN_DAY * 1_000, - ]); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_microsecond_add_interval() { - // timestamp microsecond + interval year month - let a = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMicrosecondArray::from(vec![ - 1 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000, - 2 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000, - 3 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000, - 4 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000, - 5 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000, - ]); - assert_eq!(result, &expected); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp microsecond + interval day time - let a = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMicrosecondArray::from(vec![ - 1 + SECONDS_IN_DAY * 1_000_000, - 2 + SECONDS_IN_DAY * 1_000_000, - 3 + SECONDS_IN_DAY * 1_000_000, - 4 + SECONDS_IN_DAY * 1_000_000, - 5 + SECONDS_IN_DAY * 1_000_000, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp microsecond + interval month day nanosecond - let a = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMicrosecondArray::from(vec![ - 1 + SECONDS_IN_DAY * 1_000_000, - 2 + SECONDS_IN_DAY * 1_000_000, - 3 + SECONDS_IN_DAY * 1_000_000, - 4 + SECONDS_IN_DAY * 1_000_000, - 5 + SECONDS_IN_DAY * 1_000_000, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - } - - #[test] - fn test_timestamp_microsecond_subtract_interval() { - // timestamp microsecond + interval year month - let a = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMicrosecondArray::from(vec![ - 1 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000, - 2 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000, - 3 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000, - 4 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000, - 5 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000, - ]); - assert_eq!(&expected, result); - - // timestamp microsecond + interval day time - let a = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMicrosecondArray::from(vec![ - 1 - SECONDS_IN_DAY * 1_000_000, - 2 - SECONDS_IN_DAY * 1_000_000, - 3 - SECONDS_IN_DAY * 1_000_000, - 4 - SECONDS_IN_DAY * 1_000_000, - 5 - SECONDS_IN_DAY * 1_000_000, - ]); - assert_eq!(&expected, result); - - // timestamp microsecond + interval month day nanosecond - let a = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampMicrosecondArray::from(vec![ - 1 - SECONDS_IN_DAY * 1_000_000, - 2 - SECONDS_IN_DAY * 1_000_000, - 3 - SECONDS_IN_DAY * 1_000_000, - 4 - SECONDS_IN_DAY * 1_000_000, - 5 - SECONDS_IN_DAY * 1_000_000, - ]); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_nanosecond_add_interval() { - // timestamp nanosecond + interval year month - let a = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampNanosecondArray::from(vec![ - 1 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000_000, - 2 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000_000, - 3 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000_000, - 4 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000_000, - 5 + SECONDS_IN_DAY * (31 + 28 + 365) * 1_000_000_000, - ]); - assert_eq!(result, &expected); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp nanosecond + interval day time - let a = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampNanosecondArray::from(vec![ - 1 + SECONDS_IN_DAY * 1_000_000_000, - 2 + SECONDS_IN_DAY * 1_000_000_000, - 3 + SECONDS_IN_DAY * 1_000_000_000, - 4 + SECONDS_IN_DAY * 1_000_000_000, - 5 + SECONDS_IN_DAY * 1_000_000_000, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - - // timestamp nanosecond + interval month day nanosecond - let a = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = add_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampNanosecondArray::from(vec![ - 1 + SECONDS_IN_DAY * 1_000_000_000, - 2 + SECONDS_IN_DAY * 1_000_000_000, - 3 + SECONDS_IN_DAY * 1_000_000_000, - 4 + SECONDS_IN_DAY * 1_000_000_000, - 5 + SECONDS_IN_DAY * 1_000_000_000, - ]); - assert_eq!(&expected, result); - let result = add_dyn(&b, &a).unwrap(); - let result = result.as_primitive::(); - assert_eq!(result, &expected); - } - - #[test] - fn test_timestamp_nanosecond_subtract_interval() { - // timestamp nanosecond + interval year month - let a = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalYearMonthArray::from(vec![ - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - Some(IntervalYearMonthType::make_value(1, 2)), - ]); - - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampNanosecondArray::from(vec![ - 1 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000_000, - 2 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000_000, - 3 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000_000, - 4 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000_000, - 5 - SECONDS_IN_DAY * (31 + 30 + 365) * 1_000_000_000, - ]); - assert_eq!(&expected, result); - - // timestamp nanosecond + interval day time - let a = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalDayTimeArray::from(vec![ - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - Some(IntervalDayTimeType::make_value(1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampNanosecondArray::from(vec![ - 1 - SECONDS_IN_DAY * 1_000_000_000, - 2 - SECONDS_IN_DAY * 1_000_000_000, - 3 - SECONDS_IN_DAY * 1_000_000_000, - 4 - SECONDS_IN_DAY * 1_000_000_000, - 5 - SECONDS_IN_DAY * 1_000_000_000, - ]); - assert_eq!(&expected, result); - - // timestamp nanosecond + interval month day nanosecond - let a = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let b = IntervalMonthDayNanoArray::from(vec![ - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - Some(IntervalMonthDayNanoType::make_value(0, 1, 0)), - ]); - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - - let expected = TimestampNanosecondArray::from(vec![ - 1 - SECONDS_IN_DAY * 1_000_000_000, - 2 - SECONDS_IN_DAY * 1_000_000_000, - 3 - SECONDS_IN_DAY * 1_000_000_000, - 4 - SECONDS_IN_DAY * 1_000_000_000, - 5 - SECONDS_IN_DAY * 1_000_000_000, - ]); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_second_subtract_timestamp() { - let a = TimestampSecondArray::from(vec![0, 2, 4, 6, 8]); - let b = TimestampSecondArray::from(vec![1, 2, 3, 4, 5]); - let expected = DurationSecondArray::from(vec![-1, 0, 1, 2, 3]); - - // unchecked - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - - // checked - let result = subtract_dyn_checked(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_second_subtract_timestamp_overflow() { - let a = TimestampSecondArray::from(vec![ - ::Native::MAX, - ]); - let b = TimestampSecondArray::from(vec![ - ::Native::MIN, - ]); - - // checked - let result = subtract_dyn_checked(&a, &b); - assert!(&result.is_err()); - } - - #[test] - fn test_timestamp_microsecond_subtract_timestamp() { - let a = TimestampMicrosecondArray::from(vec![0, 2, 4, 6, 8]); - let b = TimestampMicrosecondArray::from(vec![1, 2, 3, 4, 5]); - let expected = DurationMicrosecondArray::from(vec![-1, 0, 1, 2, 3]); - - // unchecked - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - - // checked - let result = subtract_dyn_checked(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_microsecond_subtract_timestamp_overflow() { - let a = TimestampMicrosecondArray::from(vec![i64::MAX]); - let b = TimestampMicrosecondArray::from(vec![i64::MIN]); - - // checked - let result = subtract_dyn_checked(&a, &b); - assert!(&result.is_err()); - } - - #[test] - fn test_timestamp_millisecond_subtract_timestamp() { - let a = TimestampMillisecondArray::from(vec![0, 2, 4, 6, 8]); - let b = TimestampMillisecondArray::from(vec![1, 2, 3, 4, 5]); - let expected = DurationMillisecondArray::from(vec![-1, 0, 1, 2, 3]); - - // unchecked - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - - // checked - let result = subtract_dyn_checked(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_millisecond_subtract_timestamp_overflow() { - let a = TimestampMillisecondArray::from(vec![i64::MAX]); - let b = TimestampMillisecondArray::from(vec![i64::MIN]); - - // checked - let result = subtract_dyn_checked(&a, &b); - assert!(&result.is_err()); - } - - #[test] - fn test_timestamp_nanosecond_subtract_timestamp() { - let a = TimestampNanosecondArray::from(vec![0, 2, 4, 6, 8]); - let b = TimestampNanosecondArray::from(vec![1, 2, 3, 4, 5]); - let expected = DurationNanosecondArray::from(vec![-1, 0, 1, 2, 3]); - - // unchecked - let result = subtract_dyn(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - - // checked - let result = subtract_dyn_checked(&a, &b).unwrap(); - let result = result.as_primitive::(); - assert_eq!(&expected, result); - } - - #[test] - fn test_timestamp_nanosecond_subtract_timestamp_overflow() { - let a = TimestampNanosecondArray::from(vec![ - ::Native::MAX, - ]); - let b = TimestampNanosecondArray::from(vec![ - ::Native::MIN, - ]); - - // checked - let result = subtract_dyn_checked(&a, &b); - assert!(&result.is_err()); - } } diff --git a/arrow-arith/src/arity.rs b/arrow-arith/src/arity.rs index ce766aff66f7..2dac33a4f28b 100644 --- a/arrow-arith/src/arity.rs +++ b/arrow-arith/src/arity.rs @@ -18,7 +18,6 @@ //! Defines kernels suitable to perform operations to primitive arrays. use arrow_array::builder::BufferBuilder; -use arrow_array::iterator::ArrayIter; use arrow_array::types::ArrowDictionaryKeyType; use arrow_array::*; use arrow_buffer::buffer::NullBuffer; @@ -425,76 +424,6 @@ where Ok(Ok(builder.finish())) } -#[inline(never)] -fn try_binary_opt_no_nulls( - len: usize, - a: A, - b: B, - op: F, -) -> Result, ArrowError> -where - O: ArrowPrimitiveType, - F: Fn(A::Item, B::Item) -> Option, -{ - let mut buffer = Vec::with_capacity(10); - for idx in 0..len { - unsafe { - buffer.push(op(a.value_unchecked(idx), b.value_unchecked(idx))); - }; - } - Ok(buffer.iter().collect()) -} - -/// Applies the provided binary operation across `a` and `b`, collecting the optional results -/// into a [`PrimitiveArray`]. If any index is null in either `a` or `b`, the corresponding -/// index in the result will also be null. The binary operation could return `None` which -/// results in a new null in the collected [`PrimitiveArray`]. -/// -/// The function is only evaluated for non-null indices -/// -/// # Error -/// -/// This function gives error if the arrays have different lengths -pub(crate) fn binary_opt( - a: A, - b: B, - op: F, -) -> Result, ArrowError> -where - O: ArrowPrimitiveType, - F: Fn(A::Item, B::Item) -> Option, -{ - if a.len() != b.len() { - return Err(ArrowError::ComputeError( - "Cannot perform binary operation on arrays of different length".to_string(), - )); - } - - if a.is_empty() { - return Ok(PrimitiveArray::from(ArrayData::new_empty(&O::DATA_TYPE))); - } - - if a.null_count() == 0 && b.null_count() == 0 { - return try_binary_opt_no_nulls(a.len(), a, b, op); - } - - let iter_a = ArrayIter::new(a); - let iter_b = ArrayIter::new(b); - - let values = iter_a - .into_iter() - .zip(iter_b.into_iter()) - .map(|(item_a, item_b)| { - if let (Some(a), Some(b)) = (item_a, item_b) { - op(a, b) - } else { - None - } - }); - - Ok(values.collect()) -} - #[cfg(test)] mod tests { use super::*;