Skip to content

Commit 3bf6eb9

Browse files
authored
Fix: Issue 2721 : binary function should not panic but return error when array lengths are unequal (#2750)
1 parent 5e83ef9 commit 3bf6eb9

File tree

3 files changed

+28
-31
lines changed

3 files changed

+28
-31
lines changed

arrow/src/compute/kernels/arithmetic.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,7 @@ where
6969
RT: ArrowNumericType,
7070
F: Fn(LT::Native, RT::Native) -> LT::Native,
7171
{
72-
if left.len() != right.len() {
73-
return Err(ArrowError::ComputeError(
74-
"Cannot perform math operation on arrays of different length".to_string(),
75-
));
76-
}
77-
78-
Ok(binary(left, right, op))
72+
binary(left, right, op)
7973
}
8074

8175
/// Helper function for operations where a valid `0` on the right array should
@@ -1128,13 +1122,13 @@ where
11281122
T: ArrowNumericType,
11291123
T::Native: ArrowNativeTypeOp + Zero + One,
11301124
{
1131-
Ok(binary_opt(left, right, |a, b| {
1125+
binary_opt(left, right, |a, b| {
11321126
if b.is_zero() {
11331127
None
11341128
} else {
11351129
Some(a.div_wrapping(b))
11361130
}
1137-
}))
1131+
})
11381132
}
11391133

11401134
/// Perform `left / right` operation on two arrays. If either left or right value is null
@@ -1670,7 +1664,7 @@ mod tests {
16701664
let b = Int32Array::from(vec![6, 7, 8]);
16711665
let e = add(&a, &b).expect_err("should have failed due to different lengths");
16721666
assert_eq!(
1673-
"ComputeError(\"Cannot perform math operation on arrays of different length\")",
1667+
"ComputeError(\"Cannot perform binary operation on arrays of different length\")",
16741668
format!("{:?}", e)
16751669
);
16761670
}

arrow/src/compute/kernels/arity.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -235,25 +235,29 @@ where
235235
/// especially when the operation can be vectorised, however, requires `op` to be infallible
236236
/// for all possible values of its inputs
237237
///
238-
/// # Panic
238+
/// # Error
239239
///
240-
/// Panics if the arrays have different lengths
240+
/// This function gives error if the arrays have different lengths
241241
pub fn binary<A, B, F, O>(
242242
a: &PrimitiveArray<A>,
243243
b: &PrimitiveArray<B>,
244244
op: F,
245-
) -> PrimitiveArray<O>
245+
) -> Result<PrimitiveArray<O>>
246246
where
247247
A: ArrowPrimitiveType,
248248
B: ArrowPrimitiveType,
249249
O: ArrowPrimitiveType,
250250
F: Fn(A::Native, B::Native) -> O::Native,
251251
{
252-
assert_eq!(a.len(), b.len());
252+
if a.len() != b.len() {
253+
return Err(ArrowError::ComputeError(
254+
"Cannot perform binary operation on arrays of different length".to_string(),
255+
));
256+
}
253257
let len = a.len();
254258

255259
if a.is_empty() {
256-
return PrimitiveArray::from(ArrayData::new_empty(&O::DATA_TYPE));
260+
return Ok(PrimitiveArray::from(ArrayData::new_empty(&O::DATA_TYPE)));
257261
}
258262

259263
let null_buffer = combine_option_bitmap(&[a.data(), b.data()], len).unwrap();
@@ -270,7 +274,7 @@ where
270274
// `values` is an iterator with a known size from a PrimitiveArray
271275
let buffer = unsafe { Buffer::from_trusted_len_iter(values) };
272276

273-
unsafe { build_primitive_array(len, buffer, null_count, null_buffer) }
277+
Ok(unsafe { build_primitive_array(len, buffer, null_count, null_buffer) })
274278
}
275279

276280
/// Applies the provided fallible binary operation across `a` and `b`, returning any error,
@@ -344,32 +348,36 @@ where
344348
///
345349
/// The function is only evaluated for non-null indices
346350
///
347-
/// # Panic
351+
/// # Error
348352
///
349-
/// Panics if the arrays have different lengths
353+
/// This function gives error if the arrays have different lengths
350354
pub(crate) fn binary_opt<A, B, F, O>(
351355
a: &PrimitiveArray<A>,
352356
b: &PrimitiveArray<B>,
353357
op: F,
354-
) -> PrimitiveArray<O>
358+
) -> Result<PrimitiveArray<O>>
355359
where
356360
A: ArrowPrimitiveType,
357361
B: ArrowPrimitiveType,
358362
O: ArrowPrimitiveType,
359363
F: Fn(A::Native, B::Native) -> Option<O::Native>,
360364
{
361-
assert_eq!(a.len(), b.len());
365+
if a.len() != b.len() {
366+
return Err(ArrowError::ComputeError(
367+
"Cannot perform binary operation on arrays of different length".to_string(),
368+
));
369+
}
362370

363371
if a.is_empty() {
364-
return PrimitiveArray::from(ArrayData::new_empty(&O::DATA_TYPE));
372+
return Ok(PrimitiveArray::from(ArrayData::new_empty(&O::DATA_TYPE)));
365373
}
366374

367375
if a.null_count() == 0 && b.null_count() == 0 {
368-
a.values()
376+
Ok(a.values()
369377
.iter()
370378
.zip(b.values().iter())
371379
.map(|(a, b)| op(*a, *b))
372-
.collect()
380+
.collect())
373381
} else {
374382
let iter_a = ArrayIter::new(a);
375383
let iter_b = ArrayIter::new(b);
@@ -386,7 +394,7 @@ where
386394
}
387395
});
388396

389-
values.collect()
397+
Ok(values.collect())
390398
}
391399
}
392400

arrow/src/compute/kernels/bitwise.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use crate::array::PrimitiveArray;
1919
use crate::compute::{binary, unary};
2020
use crate::datatypes::ArrowNumericType;
21-
use crate::error::{ArrowError, Result};
21+
use crate::error::Result;
2222
use std::ops::{BitAnd, BitOr, BitXor, Not};
2323

2424
// The helper function for bitwise operation with two array
@@ -31,12 +31,7 @@ where
3131
T: ArrowNumericType,
3232
F: Fn(T::Native, T::Native) -> T::Native,
3333
{
34-
if left.len() != right.len() {
35-
return Err(ArrowError::ComputeError(
36-
"Cannot perform bitwise operation on arrays of different length".to_string(),
37-
));
38-
}
39-
Ok(binary(left, right, op))
34+
binary(left, right, op)
4035
}
4136

4237
/// Perform `left & right` operation on two arrays. If either left or right value is null

0 commit comments

Comments
 (0)