1use std::borrow::Cow;
72use std::cmp::Ordering;
73
74use rudb_common::{Error, LogicalType, Result, Value, interval_micros};
75use rudb_vector::{Data, Form, Packed, Selection, StringColumn, Validity, Vector};
76
77use crate::fallback::{self, Kernel};
78use crate::logic::is_true;
79use crate::number::{approximate, integral};
80use crate::prepare::Held;
81use crate::shape::{first, identity, nulls_of, single};
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub enum Comparison {
86 Equal,
88 NotEqual,
90 Less,
92 LessOrEqual,
94 Greater,
96 GreaterOrEqual,
98 DistinctFrom,
100 NotDistinctFrom,
102}
103
104impl Comparison {
105 #[must_use]
107 pub fn is_total(self) -> bool {
108 matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
109 }
110
111 #[must_use]
118 pub fn swapped(self) -> Self {
119 match self {
120 Self::Less => Self::Greater,
121 Self::LessOrEqual => Self::GreaterOrEqual,
122 Self::Greater => Self::Less,
123 Self::GreaterOrEqual => Self::LessOrEqual,
124 same => same,
125 }
126 }
127}
128
129pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
135 compare_prepared(op, left, right, None)
136}
137
138pub fn compare_prepared(
148 op: Comparison,
149 left: &Vector,
150 right: &Vector,
151 held: Option<&Held>,
152) -> Result<Vector> {
153 if left.len() != right.len() {
154 return Err(Error::internal(format!(
155 "a comparison of a {} row vector with a {} row one",
156 left.len(),
157 right.len()
158 )));
159 }
160 let len = left.len();
161 if left.form() == Form::Constant && right.form() == Form::Constant && len > 0 {
162 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
163 return Ok(Vector::constant(LogicalType::Boolean, single, len));
164 }
165
166 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
167 if !op.is_total()
171 && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
172 && len > 0
173 {
174 return boolean(vec![false; len], Validity::AllInvalid, len);
175 }
176
177 if let Some(answers) =
178 specialized(op, left, right, &left_valid, &right_valid, len, identity, held)
179 {
180 let validity =
181 if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
182 return boolean(blank_the_nulls(answers, &validity), validity, len);
183 }
184
185 fallback::record(Kernel::Compare, left.form(), right.form());
186 let mut values = Vec::with_capacity(len);
187 for index in 0..len {
190 values.push(compare_values(op, &left.value_at(index), &right.value_at(index))?);
191 }
192 Vector::from_values(LogicalType::Boolean, &values)
193}
194
195pub fn refine(
213 op: Comparison,
214 left: &Vector,
215 right: &Vector,
216 kept: &Selection,
217) -> Result<Selection> {
218 refine_prepared(op, left, right, kept, None)
219}
220
221pub fn refine_prepared(
231 op: Comparison,
232 left: &Vector,
233 right: &Vector,
234 kept: &Selection,
235 held: Option<&Held>,
236) -> Result<Selection> {
237 if left.len() != right.len() {
238 return Err(Error::internal(format!(
239 "a comparison of a {} row vector with a {} row one",
240 left.len(),
241 right.len()
242 )));
243 }
244 let len = left.len();
245 if kept.indices().iter().any(|&row| row as usize >= len) {
249 return Err(Error::internal(format!("a selection past the end of a {len} row vector")));
250 }
251 if kept.is_empty() {
252 return Ok(Selection::empty());
253 }
254 if left.form() == Form::Constant && right.form() == Form::Constant {
255 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
256 return Ok(if is_true(&single) { kept.clone() } else { Selection::empty() });
257 }
258
259 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
260 if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
261 {
262 return Ok(Selection::empty());
263 }
264
265 let rows = kept.indices();
266 let map = |slot: usize| rows[slot] as usize;
267 if let Some(answers) =
268 specialized(op, left, right, &left_valid, &right_valid, kept.len(), map, held)
269 {
270 if op.is_total() || (left_valid == Validity::AllValid && right_valid == Validity::AllValid)
273 {
274 return Ok(narrowed(&answers, rows, |_| true));
275 }
276 return Ok(narrowed(&answers, rows, |slot| {
280 let row = rows[slot] as usize;
281 left_valid.is_valid(row) && right_valid.is_valid(row)
282 }));
283 }
284
285 fallback::record(Kernel::Compare, left.form(), right.form());
286 let mut out = Vec::with_capacity(kept.len());
287 for &row in rows {
290 let index = row as usize;
291 if is_true(&compare_values(op, &left.value_at(index), &right.value_at(index))?) {
292 out.push(row);
293 }
294 }
295 Ok(Selection::from_indices(out))
296}
297
298fn narrowed<L: Fn(usize) -> bool>(answers: &[bool], rows: &[u32], live: L) -> Selection {
305 let mut out = vec![0_u32; answers.len()];
306 let mut count = 0;
307 for (slot, &answer) in answers.iter().enumerate() {
308 out[count] = rows[slot];
309 count += usize::from(answer & live(slot));
311 }
312 out.truncate(count);
313 Selection::from_indices(out)
314}
315
316fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
318 let validity = if len == 0 { Validity::AllValid } else { validity.normalize(len) };
322 Ok(Vector::flat(LogicalType::Boolean, Data::Bool(answers.into()))?.with_validity(validity))
323}
324
325fn blank_the_nulls(mut answers: Vec<bool>, validity: &Validity) -> Vec<bool> {
333 if let Validity::Mask(mask) = validity {
334 for (index, answer) in answers.iter_mut().enumerate() {
335 if !mask.get(index) {
336 *answer = false;
337 }
338 }
339 }
340 answers
341}
342
343#[expect(
355 clippy::too_many_arguments,
356 reason = "two sides, two validities, the operator, the length, the index mapping and the \
357 literal that was built early, all of which the branches below need"
358)]
359fn specialized<M>(
360 op: Comparison,
361 left: &Vector,
362 right: &Vector,
363 left_valid: &Validity,
364 right_valid: &Validity,
365 len: usize,
366 map: M,
367 held: Option<&Held>,
368) -> Option<Vec<bool>>
369where
370 M: Fn(usize) -> usize + Copy,
371{
372 if left.logical_type() != right.logical_type() {
376 return None;
377 }
378
379 if let (Some(one), Some(other)) = (left.data(), right.data()) {
380 return dispatch(op, len, one, map, other, map, left_valid, right_valid, map);
381 }
382 if !op.is_total() {
388 if let (Some(packed), Some(value)) = (left.packed_parts(), right.constant_value()) {
389 let wanted = exact(held, left.logical_type(), value)?;
390 return Some(packed_against(op, &packed, wanted, len, map));
391 }
392 if let (Some(value), Some(packed)) = (left.constant_value(), right.packed_parts()) {
393 let wanted = exact(held, right.logical_type(), value)?;
394 return Some(packed_against(op.swapped(), &packed, wanted, len, map));
395 }
396 }
397 if let (Some(one), Some(value)) = (left.data(), right.constant_value()) {
398 let column = readied(held, left.logical_type(), value)?;
399 let other = column.data()?;
400 return dispatch(op, len, one, map, other, first, left_valid, right_valid, map);
401 }
402 if let (Some(value), Some(other)) = (left.constant_value(), right.data()) {
403 let column = readied(held, right.logical_type(), value)?;
405 let one = column.data()?;
406 return dispatch(op.swapped(), len, other, map, one, first, right_valid, left_valid, map);
407 }
408 if let (Some((codes, values)), Some(value)) = (left.positions(), right.constant_value()) {
409 let one = values.data()?;
410 let column = readied(held, left.logical_type(), value)?;
411 let other = column.data()?;
412 let at = |index: usize| codes[map(index)] as usize;
413 return dispatch(op, len, one, at, other, first, left_valid, right_valid, map);
414 }
415 if let (Some(value), Some((codes, values))) = (left.constant_value(), right.positions()) {
416 let other = values.data()?;
417 let column = readied(held, right.logical_type(), value)?;
418 let one = column.data()?;
419 let at = |index: usize| codes[map(index)] as usize;
420 return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid, map);
421 }
422 if let (Some((codes, values)), Some(other)) = (left.positions(), right.data()) {
428 let one = values.data()?;
429 let at = |index: usize| codes[map(index)] as usize;
430 return dispatch(op, len, one, at, other, map, left_valid, right_valid, map);
431 }
432 if let (Some(one), Some((codes, values))) = (left.data(), right.positions()) {
433 let other = values.data()?;
434 let at = |index: usize| codes[map(index)] as usize;
435 return dispatch(op.swapped(), len, other, at, one, map, right_valid, left_valid, map);
436 }
437 None
438}
439
440fn exact(held: Option<&Held>, ty: &LogicalType, value: &Value) -> Option<i128> {
447 let column = readied(held, ty, value)?;
448 let data = column.data()?;
449 data.signed_at(0).or_else(|| data.unsigned_at(0).and_then(|value| i128::try_from(value).ok()))
450}
451
452fn packed_against<M>(
458 op: Comparison,
459 packed: &Packed<'_>,
460 wanted: i128,
461 len: usize,
462 map: M,
463) -> Vec<bool>
464where
465 M: Fn(usize) -> usize + Copy,
466{
467 let Some(code) = packed.code_of(wanted) else {
468 let above = wanted > packed.ceiling();
471 let same = match op {
472 Comparison::Equal | Comparison::NotDistinctFrom => false,
473 Comparison::NotEqual | Comparison::DistinctFrom => true,
474 Comparison::Less | Comparison::LessOrEqual => above,
475 Comparison::Greater | Comparison::GreaterOrEqual => !above,
476 };
477 return vec![same; len];
478 };
479 let test: fn(u64, u64) -> bool = match op {
482 Comparison::Equal | Comparison::NotDistinctFrom => |found, want| found == want,
483 Comparison::NotEqual | Comparison::DistinctFrom => |found, want| found != want,
484 Comparison::Less => |found, want| found < want,
485 Comparison::LessOrEqual => |found, want| found <= want,
486 Comparison::Greater => |found, want| found > want,
487 Comparison::GreaterOrEqual => |found, want| found >= want,
488 };
489 let mut answers = Vec::with_capacity(len);
490 for row in 0..len {
491 answers.push(test(packed.code(map(row)), code));
492 }
493 answers
494}
495
496#[expect(
502 clippy::too_many_arguments,
503 reason = "two sides with an index each, the operator, the length and two validities, all of \
504 which the loop needs and none of which is worth a struct that exists for one call"
505)]
506fn dispatch<L, R, V>(
507 op: Comparison,
508 len: usize,
509 left: &Data,
510 at_left: L,
511 right: &Data,
512 at_right: R,
513 left_valid: &Validity,
514 right_valid: &Validity,
515 at_valid: V,
516) -> Option<Vec<bool>>
517where
518 L: Fn(usize) -> usize,
519 R: Fn(usize) -> usize,
520 V: Fn(usize) -> usize,
521{
522 macro_rules! layouts {
523 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
524 match (left, right) {
525 $(
526 (Data::$variant(one), Data::$variant(other)) => Some(sweep(
527 op,
528 len,
529 |index| one[at_left(index)].cmp(&other[at_right(index)]),
530 left_valid,
531 right_valid,
532 &at_valid,
533 )),
534 )+
535 (Data::Float32(one), Data::Float32(other)) => Some(sweep(
538 op,
539 len,
540 |index| {
541 float_order(
542 f64::from(one[at_left(index)]),
543 f64::from(other[at_right(index)]),
544 )
545 },
546 left_valid,
547 right_valid,
548 &at_valid,
549 )),
550 (Data::Float64(one), Data::Float64(other)) => Some(sweep(
551 op,
552 len,
553 |index| float_order(one[at_left(index)], other[at_right(index)]),
554 left_valid,
555 right_valid,
556 &at_valid,
557 )),
558 (Data::Interval(one), Data::Interval(other)) => Some(sweep(
561 op,
562 len,
563 |index| {
564 let (months, days, micros) = one[at_left(index)];
565 let (bm, bd, bu) = other[at_right(index)];
566 interval_micros(months, days, micros).cmp(&interval_micros(bm, bd, bu))
567 },
568 left_valid,
569 right_valid,
570 &at_valid,
571 )),
572 (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
573 op,
574 len,
575 |index| string_order(one, at_left(index), other, at_right(index)),
576 left_valid,
577 right_valid,
578 &at_valid,
579 )),
580 _ => None,
581 }
582 };
583 }
584 rudb_vector::for_each_layout!(ordered, layouts)
585}
586
587fn readied<'a>(held: Option<&'a Held>, ty: &LogicalType, value: &Value) -> Option<Cow<'a, Vector>> {
593 match held {
594 Some(held) if held.matches(ty, value) => Some(Cow::Borrowed(held.single())),
595 _ => Some(Cow::Owned(single(ty, value)?)),
596 }
597}
598
599fn string_order(
607 left: &StringColumn,
608 at_left: usize,
609 right: &StringColumn,
610 at_right: usize,
611) -> Ordering {
612 let (Some(one), Some(other)) = (left.views().get(at_left), right.views().get(at_right)) else {
613 return Ordering::Equal;
614 };
615 let (prefix, against) = (one.prefix(), other.prefix());
616 if prefix != against {
617 return prefix.cmp(&against);
618 }
619 let bytes = left.bytes(at_left).unwrap_or_default();
624 let against_bytes = right.bytes(at_right).unwrap_or_default();
625 bytes.cmp(against_bytes)
626}
627
628fn sweep<O, V>(
634 op: Comparison,
635 len: usize,
636 order_at: O,
637 left_valid: &Validity,
638 right_valid: &Validity,
639 at_valid: V,
640) -> Vec<bool>
641where
642 O: Fn(usize) -> Ordering,
643 V: Fn(usize) -> usize,
644{
645 let mut answers = vec![false; len];
646 match op {
647 Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
648 Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
649 Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
650 Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
651 Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
652 Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
653 Comparison::DistinctFrom => {
654 total(&mut answers, order_at, left_valid, right_valid, at_valid);
655 for answer in &mut answers {
656 *answer = !*answer;
657 }
658 }
659 Comparison::NotDistinctFrom => {
660 total(&mut answers, order_at, left_valid, right_valid, at_valid);
661 }
662 }
663 answers
664}
665
666#[inline]
668fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
669where
670 O: Fn(usize) -> Ordering,
671 H: Fn(Ordering) -> bool,
672{
673 for (index, answer) in answers.iter_mut().enumerate() {
674 *answer = held(order_at(index));
675 }
676}
677
678fn total<O, V>(
685 answers: &mut [bool],
686 order_at: O,
687 left_valid: &Validity,
688 right_valid: &Validity,
689 at_valid: V,
690) where
691 O: Fn(usize) -> Ordering,
692 V: Fn(usize) -> usize,
693{
694 if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
695 fill(answers, order_at, |o| o == Ordering::Equal);
696 return;
697 }
698 for (index, answer) in answers.iter_mut().enumerate() {
699 let row = at_valid(index);
700 *answer = match (left_valid.is_valid(row), right_valid.is_valid(row)) {
701 (true, true) => order_at(index) == Ordering::Equal,
702 (false, false) => true,
703 _ => false,
704 };
705 }
706}
707
708pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
714 if op.is_total() {
715 let same = match (left.is_null(), right.is_null()) {
716 (true, true) => true,
717 (true, false) | (false, true) => false,
718 (false, false) => order(left, right)? == Ordering::Equal,
719 };
720 return Ok(Value::Boolean(match op {
721 Comparison::NotDistinctFrom => same,
722 _ => !same,
723 }));
724 }
725 if left.is_null() || right.is_null() {
726 return Ok(Value::Null);
727 }
728 let ordering = order(left, right)?;
729 let held = match op {
730 Comparison::Equal => ordering == Ordering::Equal,
731 Comparison::NotEqual => ordering != Ordering::Equal,
732 Comparison::Less => ordering == Ordering::Less,
733 Comparison::LessOrEqual => ordering != Ordering::Greater,
734 Comparison::Greater => ordering == Ordering::Greater,
735 Comparison::GreaterOrEqual => ordering != Ordering::Less,
736 Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
737 return Err(Error::internal("a total comparison reached the ordered path"));
738 }
739 };
740 Ok(Value::Boolean(held))
741}
742
743pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
754 match (left, right) {
755 (Value::Null, _) | (_, Value::Null) => {
756 Err(Error::internal("a null reached the ordering path"))
757 }
758 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
759 (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
760 (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
761 (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
762 (Value::Time(a), Value::Time(b)) | (Value::Timestamp(a), Value::Timestamp(b)) => {
763 Ok(a.cmp(b))
764 }
765 (
766 Value::Interval { months: am, days: ad, micros: au },
767 Value::Interval { months: bm, days: bd, micros: bu },
768 ) => Ok(interval_micros(*am, *ad, *au).cmp(&interval_micros(*bm, *bd, *bu))),
769 _ => numeric_order(left, right),
770 }
771}
772
773fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
775 if let (Some(a), Some(b)) = (integral(left), integral(right)) {
776 return Ok(a.cmp(&b));
777 }
778 if let (
779 Value::Decimal { unscaled: a, scale: sa, .. },
780 Value::Decimal { unscaled: b, scale: sb, .. },
781 ) = (left, right)
782 {
783 if sa == sb {
784 return Ok(a.cmp(b));
785 }
786 }
787 match (approximate(left), approximate(right)) {
788 (Some(a), Some(b)) => Ok(float_order(a, b)),
789 _ => Err(Error::not_implemented(format!(
790 "comparing {} with {}",
791 left.logical_type(),
792 right.logical_type()
793 ))),
794 }
795}
796
797fn float_order(left: f64, right: f64) -> Ordering {
799 if left == right {
800 return Ordering::Equal;
801 }
802 match (left.is_nan(), right.is_nan()) {
803 (true, true) => Ordering::Equal,
804 (true, false) => Ordering::Greater,
805 (false, true) => Ordering::Less,
806 (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
807 }
808}
809
810pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
819 match (left.is_null(), right.is_null()) {
820 (true, true) => Ok(Ordering::Equal),
821 (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
822 (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
823 (false, false) => order(left, right),
824 }
825}
826
827#[cfg(test)]
828mod tests {
829 use super::*;
830
831 fn compared(op: Comparison, left: Value, right: Value) -> Value {
832 compare_values(op, &left, &right).expect("these types compare")
833 }
834
835 const EVERY: [Comparison; 8] = [
837 Comparison::Equal,
838 Comparison::NotEqual,
839 Comparison::Less,
840 Comparison::LessOrEqual,
841 Comparison::Greater,
842 Comparison::GreaterOrEqual,
843 Comparison::DistinctFrom,
844 Comparison::NotDistinctFrom,
845 ];
846
847 fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
853 let values: Vec<Value> = (0..left.len())
854 .map(|index| {
855 compare_values(op, &left.value_at(index), &right.value_at(index))
856 .expect("the oracle is only asked about types that compare")
857 })
858 .collect();
859 Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
860 }
861
862 fn agrees(op: Comparison, left: &Vector, right: &Vector) {
866 let fast = compare(op, left, right).expect("compares");
867 let slow = oracle(op, left, right);
868 assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
869 }
870
871 struct Rng(u64);
874
875 impl Rng {
876 fn next(&mut self) -> u64 {
877 self.0 ^= self.0 << 13;
878 self.0 ^= self.0 >> 7;
879 self.0 ^= self.0 << 17;
880 self.0
881 }
882
883 fn below(&mut self, bound: u64) -> u64 {
884 self.next() % bound
885 }
886 }
887
888 #[test]
889 fn an_ordinary_comparison_is_null_when_either_side_is() {
890 assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
891 assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
892 }
893
894 #[test]
895 fn a_total_comparison_is_never_null() {
896 assert_eq!(
897 compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
898 Value::Boolean(true)
899 );
900 assert_eq!(
901 compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
902 Value::Boolean(false)
903 );
904 assert_eq!(
905 compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
906 Value::Boolean(true)
907 );
908 }
909
910 #[test]
911 fn a_string_compares_by_bytes() {
912 assert_eq!(
913 compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
914 Value::Boolean(true)
915 );
916 assert_eq!(
917 compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
918 Value::Boolean(true)
919 );
920 }
921
922 #[test]
925 fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
926 assert_eq!(
927 compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
928 Value::Boolean(true)
929 );
930 assert_eq!(
931 compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
932 Value::Boolean(true)
933 );
934 }
935
936 #[test]
937 fn zero_has_one_value_however_it_is_signed() {
938 assert_eq!(
939 compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
940 Value::Boolean(true)
941 );
942 }
943
944 #[test]
949 fn two_intervals_of_the_same_length_are_one_value() {
950 let day = Value::Interval { months: 0, days: 1, micros: 0 };
951 let hours = Value::Interval { months: 0, days: 0, micros: 86_400_000_000 };
952 let month = Value::Interval { months: 1, days: 0, micros: 0 };
953 let thirty = Value::Interval { months: 0, days: 30, micros: 0 };
954 let long_day = Value::Interval { months: 0, days: 0, micros: 90_000_000_000 };
955 assert_eq!(compared(Comparison::Equal, day.clone(), hours), Value::Boolean(true));
956 assert_eq!(compared(Comparison::Equal, month, thirty), Value::Boolean(true));
957 assert_eq!(compared(Comparison::Greater, long_day, day), Value::Boolean(true));
958 }
959
960 #[test]
961 fn a_number_compares_the_same_however_it_is_stored() {
962 assert_eq!(
963 compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
964 Value::Boolean(true)
965 );
966 assert_eq!(
967 compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
968 Value::Boolean(true)
969 );
970 }
971
972 #[test]
973 fn nulls_go_where_the_query_asked_for_them() {
974 assert_eq!(
975 order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
976 Ordering::Less
977 );
978 assert_eq!(
979 order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
980 Ordering::Greater
981 );
982 }
983
984 #[test]
985 fn two_constant_vectors_cost_one_comparison() {
986 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
987 let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
988 let result = compare(Comparison::Less, &left, &right).expect("compares");
989 assert_eq!(result.form(), Form::Constant);
990 assert_eq!(result.value_at(500), Value::Boolean(true));
991 }
992
993 #[test]
994 fn a_comparison_of_two_vectors_is_one_answer_per_row() {
995 let left = Vector::from_values(
996 LogicalType::Integer,
997 &[Value::Integer(1), Value::Integer(5), Value::Null],
998 )
999 .expect("three rows");
1000 let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
1001 let result = compare(Comparison::Greater, &left, &right).expect("compares");
1002 assert_eq!(result.value_at(0), Value::Boolean(false));
1003 assert_eq!(result.value_at(1), Value::Boolean(true));
1004 assert_eq!(result.value_at(2), Value::Null);
1005 }
1006
1007 #[test]
1008 fn two_vectors_of_different_lengths_are_caught() {
1009 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1010 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
1011 let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
1012 assert!(error.message().contains("4 row vector"), "{error}");
1013 }
1014
1015 #[test]
1016 fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
1017 for op in EVERY {
1018 let left = Value::Integer(3);
1019 let right = Value::Integer(7);
1020 assert_eq!(
1021 compare_values(op, &left, &right).expect("compares"),
1022 compare_values(op.swapped(), &right, &left).expect("compares"),
1023 "{op:?}"
1024 );
1025 }
1026 }
1027
1028 #[test]
1031 fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
1032 let mut rng = Rng(0x5eed_1234_9876_4321);
1033 let types: [LogicalType; 11] = [
1034 LogicalType::Boolean,
1035 LogicalType::TinyInt,
1036 LogicalType::SmallInt,
1037 LogicalType::Integer,
1038 LogicalType::BigInt,
1039 LogicalType::HugeInt,
1040 LogicalType::UInteger,
1041 LogicalType::Float,
1042 LogicalType::Double,
1043 LogicalType::Varchar,
1044 LogicalType::Interval,
1045 ];
1046 for ty in &types {
1047 for nulls in [0u64, 1, 3] {
1048 let len = 37;
1049 let make = |rng: &mut Rng| {
1050 let values: Vec<Value> = (0..len)
1051 .map(|_| {
1052 if nulls > 0 && rng.below(nulls + 1) == 0 {
1053 Value::Null
1054 } else {
1055 sample(ty, rng)
1056 }
1057 })
1058 .collect();
1059 Vector::from_values(ty.clone(), &values).expect("a flat vector")
1060 };
1061 let left = make(&mut rng);
1062 let right = make(&mut rng);
1063 let literal = sample(ty, &mut rng);
1064 let constant = Vector::constant(ty.clone(), literal, len);
1065 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1066 let codes: Vec<u32> =
1067 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1068 let dictionary =
1069 Vector::dictionary(codes, left.clone()).expect("codes are in range");
1070 let ends: Vec<u32> = (1..=left.len())
1073 .map(|run| ((run * len) / left.len()).max(run) as u32)
1074 .collect();
1075 let runs = Vector::runs(ends, left.clone()).expect("one value for each run");
1076
1077 for op in EVERY {
1078 agrees(op, &left, &right);
1079 agrees(op, &left, &constant);
1080 agrees(op, &constant, &left);
1081 agrees(op, &left, &null_constant);
1082 agrees(op, &null_constant, &left);
1083 agrees(op, &dictionary, &constant);
1084 agrees(op, &constant, &dictionary);
1085 agrees(op, &dictionary, &right);
1089 agrees(op, &right, &dictionary);
1090 agrees(op, &runs, &constant);
1094 agrees(op, &constant, &runs);
1095 agrees(op, &runs, &right);
1096 agrees(op, &right, &runs);
1097 }
1098 }
1099 }
1100 }
1101
1102 fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
1104 let mut out = Vec::new();
1105 for &row in kept.indices() {
1106 let index = row as usize;
1107 let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
1108 .expect("the oracle is only asked about types that compare");
1109 if is_true(&answer) {
1110 out.push(row);
1111 }
1112 }
1113 Selection::from_indices(out)
1114 }
1115
1116 fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
1117 let fast = refine(op, left, right, kept).expect("compares");
1118 assert_eq!(
1119 fast,
1120 refined(op, left, right, kept),
1121 "{op:?} on a {:?} against a {:?} over {} rows",
1122 left.form(),
1123 right.form(),
1124 kept.len()
1125 );
1126 }
1127
1128 #[test]
1132 fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
1133 let mut rng = Rng(0x5eed_4321_1234_9876);
1134 let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
1135 for ty in &types {
1136 for nulls in [0u64, 1, 3] {
1137 let len = 37;
1138 let make = |rng: &mut Rng| {
1139 let values: Vec<Value> = (0..len)
1140 .map(|_| {
1141 if nulls > 0 && rng.below(nulls + 1) == 0 {
1142 Value::Null
1143 } else {
1144 sample(ty, rng)
1145 }
1146 })
1147 .collect();
1148 Vector::from_values(ty.clone(), &values).expect("a flat vector")
1149 };
1150 let left = make(&mut rng);
1151 let right = make(&mut rng);
1152 let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
1153 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1154 let codes: Vec<u32> =
1155 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1156 let dictionary =
1157 Vector::dictionary(codes, left.clone()).expect("codes are in range");
1158
1159 let selections = [
1163 Selection::identity(len),
1164 Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
1165 Selection::from_indices(vec![2, 5, 6, 17, 36]),
1166 Selection::empty(),
1167 ];
1168 for op in EVERY {
1169 for kept in &selections {
1170 threads(op, &left, &right, kept);
1171 threads(op, &left, &constant, kept);
1172 threads(op, &constant, &left, kept);
1173 threads(op, &left, &null_constant, kept);
1174 threads(op, &null_constant, &left, kept);
1175 threads(op, &constant, &null_constant, kept);
1176 threads(op, &dictionary, &constant, kept);
1177 threads(op, &constant, &dictionary, kept);
1178 threads(op, &dictionary, &right, kept);
1179 threads(op, &right, &dictionary, kept);
1180 }
1181 }
1182 }
1183 }
1184 }
1185
1186 #[test]
1190 fn a_second_conjunct_reads_only_what_the_first_one_left() {
1191 let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
1192 let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
1193 let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
1194 let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
1195
1196 let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
1197 .expect("compares");
1198 let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
1199
1200 let expected: Vec<u32> = (0..64)
1201 .filter(|row| {
1202 let value = row % 10;
1203 value > 3 && value < 7
1204 })
1205 .collect();
1206 assert_eq!(both.indices(), expected.as_slice());
1207 assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
1208 }
1209
1210 #[test]
1214 fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
1215 let column = Vector::from_values(
1216 LogicalType::Integer,
1217 &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
1218 )
1219 .expect("four rows");
1220 let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
1221 let all = Selection::identity(4);
1222 assert_eq!(
1223 refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
1224 &[0]
1225 );
1226 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
1228 assert_eq!(
1229 refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
1230 &[1, 3]
1231 );
1232 }
1233
1234 #[test]
1235 fn a_selection_past_the_end_is_caught() {
1236 let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1237 let past = Selection::from_indices(vec![0, 4]);
1238 let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
1239 assert!(error.message().contains("4 row vector"), "{error}");
1240 }
1241
1242 fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
1244 match ty {
1245 LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
1246 LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
1247 LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
1248 LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
1249 LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
1250 LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
1251 LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
1252 LogicalType::Float => Value::Float(match rng.below(5) {
1255 0 => f32::NAN,
1256 1 => -0.0,
1257 other => other as f32 - 2.0,
1258 }),
1259 LogicalType::Double => Value::Double(match rng.below(5) {
1260 0 => f64::NAN,
1261 1 => -0.0,
1262 other => other as f64 - 2.0,
1263 }),
1264 LogicalType::Interval => match rng.below(6) {
1268 0 => Value::Interval { months: 0, days: 1, micros: 0 },
1269 1 => Value::Interval { months: 0, days: 0, micros: 86_400_000_000 },
1270 2 => Value::Interval { months: 1, days: -29, micros: 86_400_000_000 },
1271 3 => Value::Interval { months: 1, days: 0, micros: 0 },
1272 4 => Value::Interval { months: 0, days: 0, micros: 90_000_000_000 },
1273 _ => Value::Interval { months: -1, days: 0, micros: 0 },
1274 },
1275 LogicalType::Varchar => Value::Varchar(
1278 match rng.below(6) {
1279 0 => "",
1280 1 => "ab",
1281 2 => "abc",
1282 3 => "abcdefghijkl",
1283 4 => "abcdefghijklm",
1284 _ => "abcdefghijklmnopqrstuvwxyz",
1285 }
1286 .to_owned(),
1287 ),
1288 other => panic!("the generator has no values for {other}"),
1289 }
1290 }
1291
1292 #[test]
1296 fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
1297 let words =
1298 ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
1299 let mut column = StringColumn::new();
1300 for word in words {
1301 column.push(word);
1302 }
1303 for (i, one) in words.iter().enumerate() {
1304 for (j, other) in words.iter().enumerate() {
1305 assert_eq!(
1306 string_order(&column, i, &column, j),
1307 one.as_bytes().cmp(other.as_bytes()),
1308 "{one:?} against {other:?}"
1309 );
1310 }
1311 }
1312 }
1313
1314 #[test]
1317 fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
1318 let values = Vector::from_values(
1319 LogicalType::Integer,
1320 &[Value::Integer(1), Value::Null, Value::Integer(9)],
1321 )
1322 .expect("three values");
1323 let dictionary =
1324 Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
1325 let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
1326 let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
1327 assert_eq!(result.value_at(0), Value::Boolean(true));
1328 assert_eq!(result.value_at(1), Value::Null);
1329 assert_eq!(result.value_at(2), Value::Boolean(false));
1330 assert_eq!(result.value_at(3), Value::Null);
1331 assert_eq!(result.value_at(4), Value::Boolean(true));
1332 }
1333
1334 #[test]
1337 fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
1338 let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
1340 let sequence = Vector::sequence(10, 1, 4);
1341 let flat = Vector::from_values(
1342 LogicalType::BigInt,
1343 &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
1344 )
1345 .expect("four rows");
1346 let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
1347 assert_eq!(result.value_at(0), Value::Boolean(false));
1348 assert_eq!(result.value_at(1), Value::Boolean(false));
1349 assert_eq!(result.value_at(2), Value::Boolean(false));
1350 assert_eq!(result.value_at(3), Value::Null);
1351 assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
1352 }
1353
1354 #[test]
1364 fn a_second_level_of_codes_does_not_turn_the_loops_off() {
1365 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
1366 let values = Vector::from_values(
1367 LogicalType::Integer,
1368 &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
1369 )
1370 .expect("three rows");
1371 let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
1372 let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
1373 let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
1374 let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
1375 assert_eq!(result.value_at(0), Value::Boolean(true));
1376 assert_eq!(result.value_at(1), Value::Boolean(false));
1377 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
1378 }
1379
1380 #[test]
1384 fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
1385 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
1386 let flat = Vector::from_values(
1387 LogicalType::Integer,
1388 &[
1389 Value::Integer(1),
1390 Value::Integer(2),
1391 Value::Integer(3),
1392 Value::Integer(4),
1393 Value::Integer(5),
1394 Value::Integer(6),
1395 ],
1396 )
1397 .expect("six rows");
1398 agrees(Comparison::Less, &nulls, &flat);
1399 agrees(Comparison::Equal, &flat, &nulls);
1400 assert_eq!(
1401 compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
1402 &Validity::AllInvalid
1403 );
1404 }
1405
1406 #[test]
1409 fn an_empty_comparison_is_an_empty_answer() {
1410 let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
1411 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
1412 let result = compare(Comparison::Equal, &left, &right).expect("compares");
1413 assert_eq!(result.len(), 0);
1414 }
1415
1416 fn words() -> Vector {
1419 Vector::from_values(
1420 LogicalType::Varchar,
1421 &[
1422 Value::Varchar("http://a".into()),
1423 Value::Varchar("http://b".into()),
1424 Value::Null,
1425 Value::Varchar("ab".into()),
1426 Value::Varchar("http://a".into()),
1427 Value::Varchar("z".into()),
1428 ],
1429 )
1430 .expect("six rows")
1431 }
1432
1433 #[test]
1439 fn a_literal_built_early_answers_what_one_built_here_answers() {
1440 let column = words();
1441 let value = Value::Varchar("http://b".into());
1442 let constant = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
1443 let held = Held::of(&LogicalType::Varchar, &value).expect("a varchar has a column");
1444 let kept = Selection::from_indices(vec![0, 1, 3, 5]);
1445 for op in [
1446 Comparison::Equal,
1447 Comparison::NotEqual,
1448 Comparison::Less,
1449 Comparison::LessOrEqual,
1450 Comparison::Greater,
1451 Comparison::GreaterOrEqual,
1452 Comparison::DistinctFrom,
1453 Comparison::NotDistinctFrom,
1454 ] {
1455 let prepared = compare_prepared(op, &column, &constant, Some(&held)).expect("compares");
1456 assert_eq!(prepared, compare(op, &column, &constant).expect("compares"), "{op:?}");
1457 let flipped = compare_prepared(op, &constant, &column, Some(&held)).expect("compares");
1459 assert_eq!(flipped, compare(op, &constant, &column).expect("compares"), "{op:?}");
1460 let refined =
1461 refine_prepared(op, &column, &constant, &kept, Some(&held)).expect("refines");
1462 assert_eq!(refined, refine(op, &column, &constant, &kept).expect("refines"), "{op:?}");
1463 }
1464 }
1465
1466 #[test]
1473 fn a_literal_built_for_another_value_is_ignored() {
1474 let column = words();
1475 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("z".into()), 6);
1476 let wrong = Held::of(&LogicalType::Varchar, &Value::Varchar("ab".into()))
1477 .expect("a varchar has a column");
1478 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&wrong))
1479 .expect("compares");
1480 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1481 let other = Held::of(&LogicalType::Integer, &Value::Integer(1)).expect("an integer column");
1484 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&other))
1485 .expect("compares");
1486 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1487 }
1488
1489 #[test]
1492 fn a_packed_column_against_a_constant_answers_what_the_oracle_answers() {
1493 let values: Vec<i32> = (0..64).map(|row| 1000 + (row * 37) % 500).collect();
1494 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1495 .expect("integers are an i32 layout");
1496 let packed = flat.bit_packed().expect("a five hundred wide range packs");
1497 assert_eq!(packed.form(), Form::BitPacked);
1498 for literal in [999, 1000, 1200, 1499, 1500, 2000] {
1499 let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 64);
1500 for op in EVERY {
1501 agrees(op, &packed, &constant);
1502 agrees(op, &constant, &packed);
1503 }
1504 }
1505 }
1506
1507 #[test]
1511 fn a_packed_column_with_nulls_answers_what_the_oracle_answers() {
1512 let values: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
1513 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1514 .expect("integers are an i32 layout")
1515 .with_validity(Validity::from_iter(32, |row| row % 5 != 0));
1516 let packed = flat.bit_packed().expect("packs");
1517 let constant = Vector::constant(LogicalType::Integer, Value::Integer(80), 32);
1518 for op in EVERY {
1519 agrees(op, &packed, &constant);
1520 }
1521 }
1522
1523 #[test]
1526 fn a_literal_outside_the_packed_range_answers_the_whole_vector_at_once() {
1527 let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant);
1528 let values: Vec<i32> = (0..16).map(|row| 500 + row).collect();
1529 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1530 .expect("integers are an i32 layout");
1531 let packed = flat.bit_packed().expect("packs");
1532 let literals = [-1, 0, 499, 516, 100_000];
1533 for literal in literals {
1534 let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 16);
1535 for op in EVERY {
1536 agrees(op, &packed, &constant);
1537 }
1538 }
1539 let total = EVERY.iter().filter(|op| op.is_total()).count();
1544 assert_eq!(
1545 fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant) - before,
1546 (literals.len() * total) as u64,
1547 "only the two total comparisons fall through"
1548 );
1549 }
1550
1551 #[test]
1554 fn refining_a_selection_over_a_packed_column_keeps_the_same_rows() {
1555 let values: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
1556 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into()))
1557 .expect("integers are an i32 layout");
1558 let packed = flat.bit_packed().expect("packs");
1559 let kept = Selection::from_predicate(64, |row| row % 3 == 0);
1560 let constant = Vector::constant(LogicalType::Integer, Value::Integer(260), 64);
1561 let packed_rows = refine(Comparison::Greater, &packed, &constant, &kept).expect("refines");
1562 let flat_rows = refine(Comparison::Greater, &flat, &constant, &kept).expect("refines");
1563 assert_eq!(packed_rows.indices(), flat_rows.indices());
1564 assert!(!packed_rows.is_empty(), "the literal is inside the range");
1565 }
1566}