1use arrow_array::cast::AsArray;
27use arrow_array::types::{ByteArrayType, ByteViewType};
28use arrow_array::{
29 downcast_primitive_array, AnyDictionaryArray, Array, ArrowNativeTypeOp, BooleanArray, Datum,
30 FixedSizeBinaryArray, GenericByteArray, GenericByteViewArray,
31};
32use arrow_buffer::bit_util::ceil;
33use arrow_buffer::{BooleanBuffer, MutableBuffer, NullBuffer};
34use arrow_schema::ArrowError;
35use arrow_select::take::take;
36use std::ops::Not;
37
38#[derive(Debug, Copy, Clone)]
39enum Op {
40 Equal,
41 NotEqual,
42 Less,
43 LessEqual,
44 Greater,
45 GreaterEqual,
46 Distinct,
47 NotDistinct,
48}
49
50impl std::fmt::Display for Op {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 match self {
53 Op::Equal => write!(f, "=="),
54 Op::NotEqual => write!(f, "!="),
55 Op::Less => write!(f, "<"),
56 Op::LessEqual => write!(f, "<="),
57 Op::Greater => write!(f, ">"),
58 Op::GreaterEqual => write!(f, ">="),
59 Op::Distinct => write!(f, "IS DISTINCT FROM"),
60 Op::NotDistinct => write!(f, "IS NOT DISTINCT FROM"),
61 }
62 }
63}
64
65pub fn eq(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
79 compare_op(Op::Equal, lhs, rhs)
80}
81
82pub fn neq(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
96 compare_op(Op::NotEqual, lhs, rhs)
97}
98
99pub fn lt(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
113 compare_op(Op::Less, lhs, rhs)
114}
115
116pub fn lt_eq(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
130 compare_op(Op::LessEqual, lhs, rhs)
131}
132
133pub fn gt(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
147 compare_op(Op::Greater, lhs, rhs)
148}
149
150pub fn gt_eq(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
164 compare_op(Op::GreaterEqual, lhs, rhs)
165}
166
167pub fn distinct(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
182 compare_op(Op::Distinct, lhs, rhs)
183}
184
185pub fn not_distinct(lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
200 compare_op(Op::NotDistinct, lhs, rhs)
201}
202
203#[inline(never)]
205fn compare_op(op: Op, lhs: &dyn Datum, rhs: &dyn Datum) -> Result<BooleanArray, ArrowError> {
206 use arrow_schema::DataType::*;
207 let (l, l_s) = lhs.get();
208 let (r, r_s) = rhs.get();
209
210 let l_len = l.len();
211 let r_len = r.len();
212
213 if l_len != r_len && !l_s && !r_s {
214 return Err(ArrowError::InvalidArgumentError(format!(
215 "Cannot compare arrays of different lengths, got {l_len} vs {r_len}"
216 )));
217 }
218
219 let len = match l_s {
220 true => r_len,
221 false => l_len,
222 };
223
224 let l_nulls = l.logical_nulls();
225 let r_nulls = r.logical_nulls();
226
227 let l_v = l.as_any_dictionary_opt();
228 let l = l_v.map(|x| x.values().as_ref()).unwrap_or(l);
229 let l_t = l.data_type();
230
231 let r_v = r.as_any_dictionary_opt();
232 let r = r_v.map(|x| x.values().as_ref()).unwrap_or(r);
233 let r_t = r.data_type();
234
235 if r_t.is_nested() || l_t.is_nested() {
236 return Err(ArrowError::InvalidArgumentError(format!(
237 "Nested comparison: {l_t} {op} {r_t} (hint: use make_comparator instead)"
238 )));
239 } else if l_t != r_t {
240 return Err(ArrowError::InvalidArgumentError(format!(
241 "Invalid comparison operation: {l_t} {op} {r_t}"
242 )));
243 }
244
245 let values = || -> BooleanBuffer {
247 let d = downcast_primitive_array! {
248 (l, r) => apply(op, l.values().as_ref(), l_s, l_v, r.values().as_ref(), r_s, r_v),
249 (Boolean, Boolean) => apply(op, l.as_boolean(), l_s, l_v, r.as_boolean(), r_s, r_v),
250 (Utf8, Utf8) => apply(op, l.as_string::<i32>(), l_s, l_v, r.as_string::<i32>(), r_s, r_v),
251 (Utf8View, Utf8View) => apply(op, l.as_string_view(), l_s, l_v, r.as_string_view(), r_s, r_v),
252 (LargeUtf8, LargeUtf8) => apply(op, l.as_string::<i64>(), l_s, l_v, r.as_string::<i64>(), r_s, r_v),
253 (Binary, Binary) => apply(op, l.as_binary::<i32>(), l_s, l_v, r.as_binary::<i32>(), r_s, r_v),
254 (BinaryView, BinaryView) => apply(op, l.as_binary_view(), l_s, l_v, r.as_binary_view(), r_s, r_v),
255 (LargeBinary, LargeBinary) => apply(op, l.as_binary::<i64>(), l_s, l_v, r.as_binary::<i64>(), r_s, r_v),
256 (FixedSizeBinary(_), FixedSizeBinary(_)) => apply(op, l.as_fixed_size_binary(), l_s, l_v, r.as_fixed_size_binary(), r_s, r_v),
257 (Null, Null) => None,
258 _ => unreachable!(),
259 };
260 d.unwrap_or_else(|| BooleanBuffer::new_unset(len))
261 };
262
263 let l_nulls = l_nulls.filter(|n| n.null_count() > 0);
264 let r_nulls = r_nulls.filter(|n| n.null_count() > 0);
265 Ok(match (l_nulls, l_s, r_nulls, r_s) {
266 (Some(l), true, Some(r), true) | (Some(l), false, Some(r), false) => {
267 match op {
269 Op::Distinct => {
270 let values = values();
271 let l = l.inner().bit_chunks().iter_padded();
272 let r = r.inner().bit_chunks().iter_padded();
273 let ne = values.bit_chunks().iter_padded();
274
275 let c = |((l, r), n)| ((l ^ r) | (l & r & n));
276 let buffer = l.zip(r).zip(ne).map(c).collect();
277 BooleanBuffer::new(buffer, 0, len).into()
278 }
279 Op::NotDistinct => {
280 let values = values();
281 let l = l.inner().bit_chunks().iter_padded();
282 let r = r.inner().bit_chunks().iter_padded();
283 let e = values.bit_chunks().iter_padded();
284
285 let c = |((l, r), e)| u64::not(l | r) | (l & r & e);
286 let buffer = l.zip(r).zip(e).map(c).collect();
287 BooleanBuffer::new(buffer, 0, len).into()
288 }
289 _ => BooleanArray::new(values(), NullBuffer::union(Some(&l), Some(&r))),
290 }
291 }
292 (Some(_), true, Some(a), false) | (Some(a), false, Some(_), true) => {
293 match op {
295 Op::Distinct => a.into_inner().into(),
296 Op::NotDistinct => a.into_inner().not().into(),
297 _ => BooleanArray::new_null(len),
298 }
299 }
300 (Some(nulls), is_scalar, None, _) | (None, _, Some(nulls), is_scalar) => {
301 match is_scalar {
303 true => match op {
304 Op::Distinct => BooleanBuffer::new_set(len).into(),
306 Op::NotDistinct => BooleanBuffer::new_unset(len).into(),
307 _ => BooleanArray::new_null(len),
308 },
309 false => match op {
310 Op::Distinct => {
311 let values = values();
312 let l = nulls.inner().bit_chunks().iter_padded();
313 let ne = values.bit_chunks().iter_padded();
314 let c = |(l, n)| u64::not(l) | n;
315 let buffer = l.zip(ne).map(c).collect();
316 BooleanBuffer::new(buffer, 0, len).into()
317 }
318 Op::NotDistinct => (nulls.inner() & &values()).into(),
319 _ => BooleanArray::new(values(), Some(nulls)),
320 },
321 }
322 }
323 (None, _, None, _) => BooleanArray::new(values(), None),
325 })
326}
327
328fn apply<T: ArrayOrd>(
330 op: Op,
331 l: T,
332 l_s: bool,
333 l_v: Option<&dyn AnyDictionaryArray>,
334 r: T,
335 r_s: bool,
336 r_v: Option<&dyn AnyDictionaryArray>,
337) -> Option<BooleanBuffer> {
338 if l.len() == 0 || r.len() == 0 {
339 return None; }
341
342 if !l_s && !r_s && (l_v.is_some() || r_v.is_some()) {
343 let l_v = l_v
345 .map(|x| x.normalized_keys())
346 .unwrap_or_else(|| (0..l.len()).collect());
347
348 let r_v = r_v
349 .map(|x| x.normalized_keys())
350 .unwrap_or_else(|| (0..r.len()).collect());
351
352 assert_eq!(l_v.len(), r_v.len()); Some(match op {
355 Op::Equal | Op::NotDistinct => apply_op_vectored(l, &l_v, r, &r_v, false, T::is_eq),
356 Op::NotEqual | Op::Distinct => apply_op_vectored(l, &l_v, r, &r_v, true, T::is_eq),
357 Op::Less => apply_op_vectored(l, &l_v, r, &r_v, false, T::is_lt),
358 Op::LessEqual => apply_op_vectored(r, &r_v, l, &l_v, true, T::is_lt),
359 Op::Greater => apply_op_vectored(r, &r_v, l, &l_v, false, T::is_lt),
360 Op::GreaterEqual => apply_op_vectored(l, &l_v, r, &r_v, true, T::is_lt),
361 })
362 } else {
363 let l_s = l_s.then(|| l_v.map(|x| x.normalized_keys()[0]).unwrap_or_default());
364 let r_s = r_s.then(|| r_v.map(|x| x.normalized_keys()[0]).unwrap_or_default());
365
366 let buffer = match op {
367 Op::Equal | Op::NotDistinct => apply_op(l, l_s, r, r_s, false, T::is_eq),
368 Op::NotEqual | Op::Distinct => apply_op(l, l_s, r, r_s, true, T::is_eq),
369 Op::Less => apply_op(l, l_s, r, r_s, false, T::is_lt),
370 Op::LessEqual => apply_op(r, r_s, l, l_s, true, T::is_lt),
371 Op::Greater => apply_op(r, r_s, l, l_s, false, T::is_lt),
372 Op::GreaterEqual => apply_op(l, l_s, r, r_s, true, T::is_lt),
373 };
374
375 Some(match (l_v, r_v) {
377 (Some(l_v), _) if l_s.is_none() => take_bits(l_v, buffer),
378 (_, Some(r_v)) if r_s.is_none() => take_bits(r_v, buffer),
379 _ => buffer,
380 })
381 }
382}
383
384fn take_bits(v: &dyn AnyDictionaryArray, buffer: BooleanBuffer) -> BooleanBuffer {
386 let array = take(&BooleanArray::new(buffer, None), v.keys(), None).unwrap();
387 array.as_boolean().values().clone()
388}
389
390fn collect_bool(len: usize, neg: bool, f: impl Fn(usize) -> bool) -> BooleanBuffer {
395 let mut buffer = MutableBuffer::new(ceil(len, 64) * 8);
396
397 let chunks = len / 64;
398 let remainder = len % 64;
399 for chunk in 0..chunks {
400 let mut packed = 0;
401 for bit_idx in 0..64 {
402 let i = bit_idx + chunk * 64;
403 packed |= (f(i) as u64) << bit_idx;
404 }
405 if neg {
406 packed = !packed
407 }
408
409 unsafe { buffer.push_unchecked(packed) }
411 }
412
413 if remainder != 0 {
414 let mut packed = 0;
415 for bit_idx in 0..remainder {
416 let i = bit_idx + chunks * 64;
417 packed |= (f(i) as u64) << bit_idx;
418 }
419 if neg {
420 packed = !packed
421 }
422
423 unsafe { buffer.push_unchecked(packed) }
425 }
426 BooleanBuffer::new(buffer.into(), 0, len)
427}
428
429fn apply_op<T: ArrayOrd>(
436 l: T,
437 l_s: Option<usize>,
438 r: T,
439 r_s: Option<usize>,
440 neg: bool,
441 op: impl Fn(T::Item, T::Item) -> bool,
442) -> BooleanBuffer {
443 match (l_s, r_s) {
444 (None, None) => {
445 assert_eq!(l.len(), r.len());
446 collect_bool(l.len(), neg, |idx| unsafe {
447 op(l.value_unchecked(idx), r.value_unchecked(idx))
448 })
449 }
450 (Some(l_s), Some(r_s)) => {
451 let a = l.value(l_s);
452 let b = r.value(r_s);
453 std::iter::once(op(a, b) ^ neg).collect()
454 }
455 (Some(l_s), None) => {
456 let v = l.value(l_s);
457 collect_bool(r.len(), neg, |idx| op(v, unsafe { r.value_unchecked(idx) }))
458 }
459 (None, Some(r_s)) => {
460 let v = r.value(r_s);
461 collect_bool(l.len(), neg, |idx| op(unsafe { l.value_unchecked(idx) }, v))
462 }
463 }
464}
465
466fn apply_op_vectored<T: ArrayOrd>(
468 l: T,
469 l_v: &[usize],
470 r: T,
471 r_v: &[usize],
472 neg: bool,
473 op: impl Fn(T::Item, T::Item) -> bool,
474) -> BooleanBuffer {
475 assert_eq!(l_v.len(), r_v.len());
476 collect_bool(l_v.len(), neg, |idx| unsafe {
477 let l_idx = *l_v.get_unchecked(idx);
478 let r_idx = *r_v.get_unchecked(idx);
479 op(l.value_unchecked(l_idx), r.value_unchecked(r_idx))
480 })
481}
482
483trait ArrayOrd {
484 type Item: Copy;
485
486 fn len(&self) -> usize;
487
488 fn value(&self, idx: usize) -> Self::Item {
489 assert!(idx < self.len());
490 unsafe { self.value_unchecked(idx) }
491 }
492
493 unsafe fn value_unchecked(&self, idx: usize) -> Self::Item;
497
498 fn is_eq(l: Self::Item, r: Self::Item) -> bool;
499
500 fn is_lt(l: Self::Item, r: Self::Item) -> bool;
501}
502
503impl ArrayOrd for &BooleanArray {
504 type Item = bool;
505
506 fn len(&self) -> usize {
507 Array::len(self)
508 }
509
510 unsafe fn value_unchecked(&self, idx: usize) -> Self::Item {
511 BooleanArray::value_unchecked(self, idx)
512 }
513
514 fn is_eq(l: Self::Item, r: Self::Item) -> bool {
515 l == r
516 }
517
518 fn is_lt(l: Self::Item, r: Self::Item) -> bool {
519 !l & r
520 }
521}
522
523impl<T: ArrowNativeTypeOp> ArrayOrd for &[T] {
524 type Item = T;
525
526 fn len(&self) -> usize {
527 (*self).len()
528 }
529
530 unsafe fn value_unchecked(&self, idx: usize) -> Self::Item {
531 *self.get_unchecked(idx)
532 }
533
534 fn is_eq(l: Self::Item, r: Self::Item) -> bool {
535 l.is_eq(r)
536 }
537
538 fn is_lt(l: Self::Item, r: Self::Item) -> bool {
539 l.is_lt(r)
540 }
541}
542
543impl<'a, T: ByteArrayType> ArrayOrd for &'a GenericByteArray<T> {
544 type Item = &'a [u8];
545
546 fn len(&self) -> usize {
547 Array::len(self)
548 }
549
550 unsafe fn value_unchecked(&self, idx: usize) -> Self::Item {
551 GenericByteArray::value_unchecked(self, idx).as_ref()
552 }
553
554 fn is_eq(l: Self::Item, r: Self::Item) -> bool {
555 l == r
556 }
557
558 fn is_lt(l: Self::Item, r: Self::Item) -> bool {
559 l < r
560 }
561}
562
563impl<'a, T: ByteViewType> ArrayOrd for &'a GenericByteViewArray<T> {
564 type Item = (&'a GenericByteViewArray<T>, usize);
567
568 fn is_eq(l: Self::Item, r: Self::Item) -> bool {
569 let l_view = unsafe { l.0.views().get_unchecked(l.1) };
572 let l_len = *l_view as u32;
573
574 let r_view = unsafe { r.0.views().get_unchecked(r.1) };
575 let r_len = *r_view as u32;
576 if l_len != r_len {
579 return false;
580 }
581
582 unsafe { GenericByteViewArray::compare_unchecked(l.0, l.1, r.0, r.1).is_eq() }
583 }
584
585 fn is_lt(l: Self::Item, r: Self::Item) -> bool {
586 unsafe { GenericByteViewArray::compare_unchecked(l.0, l.1, r.0, r.1).is_lt() }
589 }
590
591 fn len(&self) -> usize {
592 Array::len(self)
593 }
594
595 unsafe fn value_unchecked(&self, idx: usize) -> Self::Item {
596 (self, idx)
597 }
598}
599
600impl<'a> ArrayOrd for &'a FixedSizeBinaryArray {
601 type Item = &'a [u8];
602
603 fn len(&self) -> usize {
604 Array::len(self)
605 }
606
607 unsafe fn value_unchecked(&self, idx: usize) -> Self::Item {
608 FixedSizeBinaryArray::value_unchecked(self, idx)
609 }
610
611 fn is_eq(l: Self::Item, r: Self::Item) -> bool {
612 l == r
613 }
614
615 fn is_lt(l: Self::Item, r: Self::Item) -> bool {
616 l < r
617 }
618}
619
620pub fn compare_byte_view<T: ByteViewType>(
622 left: &GenericByteViewArray<T>,
623 left_idx: usize,
624 right: &GenericByteViewArray<T>,
625 right_idx: usize,
626) -> std::cmp::Ordering {
627 assert!(left_idx < left.len());
628 assert!(right_idx < right.len());
629 unsafe { GenericByteViewArray::compare_unchecked(left, left_idx, right, right_idx) }
630}
631
632#[deprecated(note = "Use `GenericByteViewArray::compare_unchecked` instead")]
660pub unsafe fn compare_byte_view_unchecked<T: ByteViewType>(
661 left: &GenericByteViewArray<T>,
662 left_idx: usize,
663 right: &GenericByteViewArray<T>,
664 right_idx: usize,
665) -> std::cmp::Ordering {
666 let l_view = left.views().get_unchecked(left_idx);
667 let l_len = *l_view as u32;
668
669 let r_view = right.views().get_unchecked(right_idx);
670 let r_len = *r_view as u32;
671
672 if l_len <= 12 && r_len <= 12 {
673 let l_data = unsafe { GenericByteViewArray::<T>::inline_value(l_view, l_len as usize) };
674 let r_data = unsafe { GenericByteViewArray::<T>::inline_value(r_view, r_len as usize) };
675 return l_data.cmp(r_data);
676 }
677
678 let l_inlined_data = unsafe { GenericByteViewArray::<T>::inline_value(l_view, 4) };
681 let r_inlined_data = unsafe { GenericByteViewArray::<T>::inline_value(r_view, 4) };
682 if r_inlined_data != l_inlined_data {
683 return l_inlined_data.cmp(r_inlined_data);
684 }
685
686 let l_full_data: &[u8] = unsafe { left.value_unchecked(left_idx).as_ref() };
688 let r_full_data: &[u8] = unsafe { right.value_unchecked(right_idx).as_ref() };
689
690 l_full_data.cmp(r_full_data)
691}
692
693#[cfg(test)]
694mod tests {
695 use std::sync::Arc;
696
697 use arrow_array::{DictionaryArray, Int32Array, Scalar, StringArray};
698
699 use super::*;
700
701 #[test]
702 fn test_null_dict() {
703 let a = DictionaryArray::new(Int32Array::new_null(10), Arc::new(Int32Array::new_null(0)));
704 let r = eq(&a, &a).unwrap();
705 assert_eq!(r.null_count(), 10);
706
707 let a = DictionaryArray::new(
708 Int32Array::from(vec![1, 2, 3, 4, 5, 6]),
709 Arc::new(Int32Array::new_null(10)),
710 );
711 let r = eq(&a, &a).unwrap();
712 assert_eq!(r.null_count(), 6);
713
714 let scalar =
715 DictionaryArray::new(Int32Array::new_null(1), Arc::new(Int32Array::new_null(0)));
716 let r = eq(&a, &Scalar::new(&scalar)).unwrap();
717 assert_eq!(r.null_count(), 6);
718
719 let scalar =
720 DictionaryArray::new(Int32Array::new_null(1), Arc::new(Int32Array::new_null(0)));
721 let r = eq(&Scalar::new(&scalar), &Scalar::new(&scalar)).unwrap();
722 assert_eq!(r.null_count(), 1);
723
724 let a = DictionaryArray::new(
725 Int32Array::from(vec![0, 1, 2]),
726 Arc::new(Int32Array::from(vec![3, 2, 1])),
727 );
728 let r = eq(&a, &Scalar::new(&scalar)).unwrap();
729 assert_eq!(r.null_count(), 3);
730 }
731
732 #[test]
733 fn is_distinct_from_non_nulls() {
734 let left_int_array = Int32Array::from(vec![0, 1, 2, 3, 4]);
735 let right_int_array = Int32Array::from(vec![4, 3, 2, 1, 0]);
736
737 assert_eq!(
738 BooleanArray::from(vec![true, true, false, true, true,]),
739 distinct(&left_int_array, &right_int_array).unwrap()
740 );
741 assert_eq!(
742 BooleanArray::from(vec![false, false, true, false, false,]),
743 not_distinct(&left_int_array, &right_int_array).unwrap()
744 );
745 }
746
747 #[test]
748 fn is_distinct_from_nulls() {
749 let left_int_array = Int32Array::new(
751 vec![0, 0, 1, 3, 0, 0].into(),
752 Some(NullBuffer::from(vec![true, true, false, true, true, true])),
753 );
754 let right_int_array = Int32Array::new(
756 vec![0; 6].into(),
757 Some(NullBuffer::from(vec![
758 true, false, false, false, true, false,
759 ])),
760 );
761
762 assert_eq!(
763 BooleanArray::from(vec![false, true, false, true, false, true,]),
764 distinct(&left_int_array, &right_int_array).unwrap()
765 );
766
767 assert_eq!(
768 BooleanArray::from(vec![true, false, true, false, true, false,]),
769 not_distinct(&left_int_array, &right_int_array).unwrap()
770 );
771 }
772
773 #[test]
774 fn test_distinct_scalar() {
775 let a = Int32Array::new_scalar(12);
776 let b = Int32Array::new_scalar(12);
777 assert!(!distinct(&a, &b).unwrap().value(0));
778 assert!(not_distinct(&a, &b).unwrap().value(0));
779
780 let a = Int32Array::new_scalar(12);
781 let b = Int32Array::new_null(1);
782 assert!(distinct(&a, &b).unwrap().value(0));
783 assert!(!not_distinct(&a, &b).unwrap().value(0));
784 assert!(distinct(&b, &a).unwrap().value(0));
785 assert!(!not_distinct(&b, &a).unwrap().value(0));
786
787 let b = Scalar::new(b);
788 assert!(distinct(&a, &b).unwrap().value(0));
789 assert!(!not_distinct(&a, &b).unwrap().value(0));
790
791 assert!(!distinct(&b, &b).unwrap().value(0));
792 assert!(not_distinct(&b, &b).unwrap().value(0));
793
794 let a = Int32Array::new(
795 vec![0, 1, 2, 3].into(),
796 Some(vec![false, false, true, true].into()),
797 );
798 let expected = BooleanArray::from(vec![false, false, true, true]);
799 assert_eq!(distinct(&a, &b).unwrap(), expected);
800 assert_eq!(distinct(&b, &a).unwrap(), expected);
801
802 let expected = BooleanArray::from(vec![true, true, false, false]);
803 assert_eq!(not_distinct(&a, &b).unwrap(), expected);
804 assert_eq!(not_distinct(&b, &a).unwrap(), expected);
805
806 let b = Int32Array::new_scalar(1);
807 let expected = BooleanArray::from(vec![true; 4]);
808 assert_eq!(distinct(&a, &b).unwrap(), expected);
809 assert_eq!(distinct(&b, &a).unwrap(), expected);
810 let expected = BooleanArray::from(vec![false; 4]);
811 assert_eq!(not_distinct(&a, &b).unwrap(), expected);
812 assert_eq!(not_distinct(&b, &a).unwrap(), expected);
813
814 let b = Int32Array::new_scalar(3);
815 let expected = BooleanArray::from(vec![true, true, true, false]);
816 assert_eq!(distinct(&a, &b).unwrap(), expected);
817 assert_eq!(distinct(&b, &a).unwrap(), expected);
818 let expected = BooleanArray::from(vec![false, false, false, true]);
819 assert_eq!(not_distinct(&a, &b).unwrap(), expected);
820 assert_eq!(not_distinct(&b, &a).unwrap(), expected);
821 }
822
823 #[test]
824 fn test_scalar_negation() {
825 let a = Int32Array::new_scalar(54);
826 let b = Int32Array::new_scalar(54);
827 let r = eq(&a, &b).unwrap();
828 assert!(r.value(0));
829
830 let r = neq(&a, &b).unwrap();
831 assert!(!r.value(0))
832 }
833
834 #[test]
835 fn test_scalar_empty() {
836 let a = Int32Array::new_null(0);
837 let b = Int32Array::new_scalar(23);
838 let r = eq(&a, &b).unwrap();
839 assert_eq!(r.len(), 0);
840 let r = eq(&b, &a).unwrap();
841 assert_eq!(r.len(), 0);
842 }
843
844 #[test]
845 fn test_dictionary_nulls() {
846 let values = StringArray::from(vec![Some("us-west"), Some("us-east")]);
847 let nulls = NullBuffer::from(vec![false, true, true]);
848
849 let key_values = vec![100i32, 1i32, 0i32].into();
850 let keys = Int32Array::new(key_values, Some(nulls));
851 let col = DictionaryArray::try_new(keys, Arc::new(values)).unwrap();
852
853 neq(&col.slice(0, col.len() - 1), &col.slice(1, col.len() - 1)).unwrap();
854 }
855}