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(
660 since = "52.2.0",
661 note = "Use `GenericByteViewArray::compare_unchecked` instead"
662)]
663pub unsafe fn compare_byte_view_unchecked<T: ByteViewType>(
664 left: &GenericByteViewArray<T>,
665 left_idx: usize,
666 right: &GenericByteViewArray<T>,
667 right_idx: usize,
668) -> std::cmp::Ordering {
669 let l_view = left.views().get_unchecked(left_idx);
670 let l_len = *l_view as u32;
671
672 let r_view = right.views().get_unchecked(right_idx);
673 let r_len = *r_view as u32;
674
675 if l_len <= 12 && r_len <= 12 {
676 let l_data = unsafe { GenericByteViewArray::<T>::inline_value(l_view, l_len as usize) };
677 let r_data = unsafe { GenericByteViewArray::<T>::inline_value(r_view, r_len as usize) };
678 return l_data.cmp(r_data);
679 }
680
681 let l_inlined_data = unsafe { GenericByteViewArray::<T>::inline_value(l_view, 4) };
684 let r_inlined_data = unsafe { GenericByteViewArray::<T>::inline_value(r_view, 4) };
685 if r_inlined_data != l_inlined_data {
686 return l_inlined_data.cmp(r_inlined_data);
687 }
688
689 let l_full_data: &[u8] = unsafe { left.value_unchecked(left_idx).as_ref() };
691 let r_full_data: &[u8] = unsafe { right.value_unchecked(right_idx).as_ref() };
692
693 l_full_data.cmp(r_full_data)
694}
695
696#[cfg(test)]
697mod tests {
698 use std::sync::Arc;
699
700 use arrow_array::{DictionaryArray, Int32Array, Scalar, StringArray};
701
702 use super::*;
703
704 #[test]
705 fn test_null_dict() {
706 let a = DictionaryArray::new(Int32Array::new_null(10), Arc::new(Int32Array::new_null(0)));
707 let r = eq(&a, &a).unwrap();
708 assert_eq!(r.null_count(), 10);
709
710 let a = DictionaryArray::new(
711 Int32Array::from(vec![1, 2, 3, 4, 5, 6]),
712 Arc::new(Int32Array::new_null(10)),
713 );
714 let r = eq(&a, &a).unwrap();
715 assert_eq!(r.null_count(), 6);
716
717 let scalar =
718 DictionaryArray::new(Int32Array::new_null(1), Arc::new(Int32Array::new_null(0)));
719 let r = eq(&a, &Scalar::new(&scalar)).unwrap();
720 assert_eq!(r.null_count(), 6);
721
722 let scalar =
723 DictionaryArray::new(Int32Array::new_null(1), Arc::new(Int32Array::new_null(0)));
724 let r = eq(&Scalar::new(&scalar), &Scalar::new(&scalar)).unwrap();
725 assert_eq!(r.null_count(), 1);
726
727 let a = DictionaryArray::new(
728 Int32Array::from(vec![0, 1, 2]),
729 Arc::new(Int32Array::from(vec![3, 2, 1])),
730 );
731 let r = eq(&a, &Scalar::new(&scalar)).unwrap();
732 assert_eq!(r.null_count(), 3);
733 }
734
735 #[test]
736 fn is_distinct_from_non_nulls() {
737 let left_int_array = Int32Array::from(vec![0, 1, 2, 3, 4]);
738 let right_int_array = Int32Array::from(vec![4, 3, 2, 1, 0]);
739
740 assert_eq!(
741 BooleanArray::from(vec![true, true, false, true, true,]),
742 distinct(&left_int_array, &right_int_array).unwrap()
743 );
744 assert_eq!(
745 BooleanArray::from(vec![false, false, true, false, false,]),
746 not_distinct(&left_int_array, &right_int_array).unwrap()
747 );
748 }
749
750 #[test]
751 fn is_distinct_from_nulls() {
752 let left_int_array = Int32Array::new(
754 vec![0, 0, 1, 3, 0, 0].into(),
755 Some(NullBuffer::from(vec![true, true, false, true, true, true])),
756 );
757 let right_int_array = Int32Array::new(
759 vec![0; 6].into(),
760 Some(NullBuffer::from(vec![
761 true, false, false, false, true, false,
762 ])),
763 );
764
765 assert_eq!(
766 BooleanArray::from(vec![false, true, false, true, false, true,]),
767 distinct(&left_int_array, &right_int_array).unwrap()
768 );
769
770 assert_eq!(
771 BooleanArray::from(vec![true, false, true, false, true, false,]),
772 not_distinct(&left_int_array, &right_int_array).unwrap()
773 );
774 }
775
776 #[test]
777 fn test_distinct_scalar() {
778 let a = Int32Array::new_scalar(12);
779 let b = Int32Array::new_scalar(12);
780 assert!(!distinct(&a, &b).unwrap().value(0));
781 assert!(not_distinct(&a, &b).unwrap().value(0));
782
783 let a = Int32Array::new_scalar(12);
784 let b = Int32Array::new_null(1);
785 assert!(distinct(&a, &b).unwrap().value(0));
786 assert!(!not_distinct(&a, &b).unwrap().value(0));
787 assert!(distinct(&b, &a).unwrap().value(0));
788 assert!(!not_distinct(&b, &a).unwrap().value(0));
789
790 let b = Scalar::new(b);
791 assert!(distinct(&a, &b).unwrap().value(0));
792 assert!(!not_distinct(&a, &b).unwrap().value(0));
793
794 assert!(!distinct(&b, &b).unwrap().value(0));
795 assert!(not_distinct(&b, &b).unwrap().value(0));
796
797 let a = Int32Array::new(
798 vec![0, 1, 2, 3].into(),
799 Some(vec![false, false, true, true].into()),
800 );
801 let expected = BooleanArray::from(vec![false, false, true, true]);
802 assert_eq!(distinct(&a, &b).unwrap(), expected);
803 assert_eq!(distinct(&b, &a).unwrap(), expected);
804
805 let expected = BooleanArray::from(vec![true, true, false, false]);
806 assert_eq!(not_distinct(&a, &b).unwrap(), expected);
807 assert_eq!(not_distinct(&b, &a).unwrap(), expected);
808
809 let b = Int32Array::new_scalar(1);
810 let expected = BooleanArray::from(vec![true; 4]);
811 assert_eq!(distinct(&a, &b).unwrap(), expected);
812 assert_eq!(distinct(&b, &a).unwrap(), expected);
813 let expected = BooleanArray::from(vec![false; 4]);
814 assert_eq!(not_distinct(&a, &b).unwrap(), expected);
815 assert_eq!(not_distinct(&b, &a).unwrap(), expected);
816
817 let b = Int32Array::new_scalar(3);
818 let expected = BooleanArray::from(vec![true, true, true, false]);
819 assert_eq!(distinct(&a, &b).unwrap(), expected);
820 assert_eq!(distinct(&b, &a).unwrap(), expected);
821 let expected = BooleanArray::from(vec![false, false, false, true]);
822 assert_eq!(not_distinct(&a, &b).unwrap(), expected);
823 assert_eq!(not_distinct(&b, &a).unwrap(), expected);
824 }
825
826 #[test]
827 fn test_scalar_negation() {
828 let a = Int32Array::new_scalar(54);
829 let b = Int32Array::new_scalar(54);
830 let r = eq(&a, &b).unwrap();
831 assert!(r.value(0));
832
833 let r = neq(&a, &b).unwrap();
834 assert!(!r.value(0))
835 }
836
837 #[test]
838 fn test_scalar_empty() {
839 let a = Int32Array::new_null(0);
840 let b = Int32Array::new_scalar(23);
841 let r = eq(&a, &b).unwrap();
842 assert_eq!(r.len(), 0);
843 let r = eq(&b, &a).unwrap();
844 assert_eq!(r.len(), 0);
845 }
846
847 #[test]
848 fn test_dictionary_nulls() {
849 let values = StringArray::from(vec![Some("us-west"), Some("us-east")]);
850 let nulls = NullBuffer::from(vec![false, true, true]);
851
852 let key_values = vec![100i32, 1i32, 0i32].into();
853 let keys = Int32Array::new(key_values, Some(nulls));
854 let col = DictionaryArray::try_new(keys, Arc::new(values)).unwrap();
855
856 neq(&col.slice(0, col.len() - 1), &col.slice(1, col.len() - 1)).unwrap();
857 }
858}