1use std::borrow::Cow;
72use std::cmp::Ordering;
73
74use rudb_common::{Error, LogicalType, Result, Value, interval_micros};
75use rudb_vector::{Data, Form, 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 let (Some(one), Some(value)) = (left.data(), right.constant_value()) {
383 let column = readied(held, left.logical_type(), value)?;
384 let other = column.data()?;
385 return dispatch(op, len, one, map, other, first, left_valid, right_valid, map);
386 }
387 if let (Some(value), Some(other)) = (left.constant_value(), right.data()) {
388 let column = readied(held, right.logical_type(), value)?;
390 let one = column.data()?;
391 return dispatch(op.swapped(), len, other, map, one, first, right_valid, left_valid, map);
392 }
393 if let (Some((codes, values)), Some(value)) = (left.positions(), right.constant_value()) {
394 let one = values.data()?;
395 let column = readied(held, left.logical_type(), value)?;
396 let other = column.data()?;
397 let at = |index: usize| codes[map(index)] as usize;
398 return dispatch(op, len, one, at, other, first, left_valid, right_valid, map);
399 }
400 if let (Some(value), Some((codes, values))) = (left.constant_value(), right.positions()) {
401 let other = values.data()?;
402 let column = readied(held, right.logical_type(), value)?;
403 let one = column.data()?;
404 let at = |index: usize| codes[map(index)] as usize;
405 return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid, map);
406 }
407 if let (Some((codes, values)), Some(other)) = (left.positions(), right.data()) {
413 let one = values.data()?;
414 let at = |index: usize| codes[map(index)] as usize;
415 return dispatch(op, len, one, at, other, map, left_valid, right_valid, map);
416 }
417 if let (Some(one), Some((codes, values))) = (left.data(), right.positions()) {
418 let other = values.data()?;
419 let at = |index: usize| codes[map(index)] as usize;
420 return dispatch(op.swapped(), len, other, at, one, map, right_valid, left_valid, map);
421 }
422 None
423}
424
425#[expect(
431 clippy::too_many_arguments,
432 reason = "two sides with an index each, the operator, the length and two validities, all of \
433 which the loop needs and none of which is worth a struct that exists for one call"
434)]
435fn dispatch<L, R, V>(
436 op: Comparison,
437 len: usize,
438 left: &Data,
439 at_left: L,
440 right: &Data,
441 at_right: R,
442 left_valid: &Validity,
443 right_valid: &Validity,
444 at_valid: V,
445) -> Option<Vec<bool>>
446where
447 L: Fn(usize) -> usize,
448 R: Fn(usize) -> usize,
449 V: Fn(usize) -> usize,
450{
451 macro_rules! layouts {
452 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
453 match (left, right) {
454 $(
455 (Data::$variant(one), Data::$variant(other)) => Some(sweep(
456 op,
457 len,
458 |index| one[at_left(index)].cmp(&other[at_right(index)]),
459 left_valid,
460 right_valid,
461 &at_valid,
462 )),
463 )+
464 (Data::Float32(one), Data::Float32(other)) => Some(sweep(
467 op,
468 len,
469 |index| {
470 float_order(
471 f64::from(one[at_left(index)]),
472 f64::from(other[at_right(index)]),
473 )
474 },
475 left_valid,
476 right_valid,
477 &at_valid,
478 )),
479 (Data::Float64(one), Data::Float64(other)) => Some(sweep(
480 op,
481 len,
482 |index| float_order(one[at_left(index)], other[at_right(index)]),
483 left_valid,
484 right_valid,
485 &at_valid,
486 )),
487 (Data::Interval(one), Data::Interval(other)) => Some(sweep(
490 op,
491 len,
492 |index| {
493 let (months, days, micros) = one[at_left(index)];
494 let (bm, bd, bu) = other[at_right(index)];
495 interval_micros(months, days, micros).cmp(&interval_micros(bm, bd, bu))
496 },
497 left_valid,
498 right_valid,
499 &at_valid,
500 )),
501 (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
502 op,
503 len,
504 |index| string_order(one, at_left(index), other, at_right(index)),
505 left_valid,
506 right_valid,
507 &at_valid,
508 )),
509 _ => None,
510 }
511 };
512 }
513 rudb_vector::for_each_layout!(ordered, layouts)
514}
515
516fn readied<'a>(held: Option<&'a Held>, ty: &LogicalType, value: &Value) -> Option<Cow<'a, Vector>> {
522 match held {
523 Some(held) if held.matches(ty, value) => Some(Cow::Borrowed(held.single())),
524 _ => Some(Cow::Owned(single(ty, value)?)),
525 }
526}
527
528fn string_order(
536 left: &StringColumn,
537 at_left: usize,
538 right: &StringColumn,
539 at_right: usize,
540) -> Ordering {
541 let (Some(one), Some(other)) = (left.views().get(at_left), right.views().get(at_right)) else {
542 return Ordering::Equal;
543 };
544 let (prefix, against) = (one.prefix(), other.prefix());
545 if prefix != against {
546 return prefix.cmp(&against);
547 }
548 let bytes = left.bytes(at_left).unwrap_or_default();
553 let against_bytes = right.bytes(at_right).unwrap_or_default();
554 bytes.cmp(against_bytes)
555}
556
557fn sweep<O, V>(
563 op: Comparison,
564 len: usize,
565 order_at: O,
566 left_valid: &Validity,
567 right_valid: &Validity,
568 at_valid: V,
569) -> Vec<bool>
570where
571 O: Fn(usize) -> Ordering,
572 V: Fn(usize) -> usize,
573{
574 let mut answers = vec![false; len];
575 match op {
576 Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
577 Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
578 Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
579 Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
580 Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
581 Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
582 Comparison::DistinctFrom => {
583 total(&mut answers, order_at, left_valid, right_valid, at_valid);
584 for answer in &mut answers {
585 *answer = !*answer;
586 }
587 }
588 Comparison::NotDistinctFrom => {
589 total(&mut answers, order_at, left_valid, right_valid, at_valid);
590 }
591 }
592 answers
593}
594
595#[inline]
597fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
598where
599 O: Fn(usize) -> Ordering,
600 H: Fn(Ordering) -> bool,
601{
602 for (index, answer) in answers.iter_mut().enumerate() {
603 *answer = held(order_at(index));
604 }
605}
606
607fn total<O, V>(
614 answers: &mut [bool],
615 order_at: O,
616 left_valid: &Validity,
617 right_valid: &Validity,
618 at_valid: V,
619) where
620 O: Fn(usize) -> Ordering,
621 V: Fn(usize) -> usize,
622{
623 if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
624 fill(answers, order_at, |o| o == Ordering::Equal);
625 return;
626 }
627 for (index, answer) in answers.iter_mut().enumerate() {
628 let row = at_valid(index);
629 *answer = match (left_valid.is_valid(row), right_valid.is_valid(row)) {
630 (true, true) => order_at(index) == Ordering::Equal,
631 (false, false) => true,
632 _ => false,
633 };
634 }
635}
636
637pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
643 if op.is_total() {
644 let same = match (left.is_null(), right.is_null()) {
645 (true, true) => true,
646 (true, false) | (false, true) => false,
647 (false, false) => order(left, right)? == Ordering::Equal,
648 };
649 return Ok(Value::Boolean(match op {
650 Comparison::NotDistinctFrom => same,
651 _ => !same,
652 }));
653 }
654 if left.is_null() || right.is_null() {
655 return Ok(Value::Null);
656 }
657 let ordering = order(left, right)?;
658 let held = match op {
659 Comparison::Equal => ordering == Ordering::Equal,
660 Comparison::NotEqual => ordering != Ordering::Equal,
661 Comparison::Less => ordering == Ordering::Less,
662 Comparison::LessOrEqual => ordering != Ordering::Greater,
663 Comparison::Greater => ordering == Ordering::Greater,
664 Comparison::GreaterOrEqual => ordering != Ordering::Less,
665 Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
666 return Err(Error::internal("a total comparison reached the ordered path"));
667 }
668 };
669 Ok(Value::Boolean(held))
670}
671
672pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
683 match (left, right) {
684 (Value::Null, _) | (_, Value::Null) => {
685 Err(Error::internal("a null reached the ordering path"))
686 }
687 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
688 (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
689 (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
690 (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
691 (Value::Time(a), Value::Time(b)) | (Value::Timestamp(a), Value::Timestamp(b)) => {
692 Ok(a.cmp(b))
693 }
694 (
695 Value::Interval { months: am, days: ad, micros: au },
696 Value::Interval { months: bm, days: bd, micros: bu },
697 ) => Ok(interval_micros(*am, *ad, *au).cmp(&interval_micros(*bm, *bd, *bu))),
698 _ => numeric_order(left, right),
699 }
700}
701
702fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
704 if let (Some(a), Some(b)) = (integral(left), integral(right)) {
705 return Ok(a.cmp(&b));
706 }
707 if let (
708 Value::Decimal { unscaled: a, scale: sa, .. },
709 Value::Decimal { unscaled: b, scale: sb, .. },
710 ) = (left, right)
711 {
712 if sa == sb {
713 return Ok(a.cmp(b));
714 }
715 }
716 match (approximate(left), approximate(right)) {
717 (Some(a), Some(b)) => Ok(float_order(a, b)),
718 _ => Err(Error::not_implemented(format!(
719 "comparing {} with {}",
720 left.logical_type(),
721 right.logical_type()
722 ))),
723 }
724}
725
726fn float_order(left: f64, right: f64) -> Ordering {
728 if left == right {
729 return Ordering::Equal;
730 }
731 match (left.is_nan(), right.is_nan()) {
732 (true, true) => Ordering::Equal,
733 (true, false) => Ordering::Greater,
734 (false, true) => Ordering::Less,
735 (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
736 }
737}
738
739pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
748 match (left.is_null(), right.is_null()) {
749 (true, true) => Ok(Ordering::Equal),
750 (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
751 (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
752 (false, false) => order(left, right),
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use super::*;
759
760 fn compared(op: Comparison, left: Value, right: Value) -> Value {
761 compare_values(op, &left, &right).expect("these types compare")
762 }
763
764 const EVERY: [Comparison; 8] = [
766 Comparison::Equal,
767 Comparison::NotEqual,
768 Comparison::Less,
769 Comparison::LessOrEqual,
770 Comparison::Greater,
771 Comparison::GreaterOrEqual,
772 Comparison::DistinctFrom,
773 Comparison::NotDistinctFrom,
774 ];
775
776 fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
782 let values: Vec<Value> = (0..left.len())
783 .map(|index| {
784 compare_values(op, &left.value_at(index), &right.value_at(index))
785 .expect("the oracle is only asked about types that compare")
786 })
787 .collect();
788 Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
789 }
790
791 fn agrees(op: Comparison, left: &Vector, right: &Vector) {
795 let fast = compare(op, left, right).expect("compares");
796 let slow = oracle(op, left, right);
797 assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
798 }
799
800 struct Rng(u64);
803
804 impl Rng {
805 fn next(&mut self) -> u64 {
806 self.0 ^= self.0 << 13;
807 self.0 ^= self.0 >> 7;
808 self.0 ^= self.0 << 17;
809 self.0
810 }
811
812 fn below(&mut self, bound: u64) -> u64 {
813 self.next() % bound
814 }
815 }
816
817 #[test]
818 fn an_ordinary_comparison_is_null_when_either_side_is() {
819 assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
820 assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
821 }
822
823 #[test]
824 fn a_total_comparison_is_never_null() {
825 assert_eq!(
826 compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
827 Value::Boolean(true)
828 );
829 assert_eq!(
830 compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
831 Value::Boolean(false)
832 );
833 assert_eq!(
834 compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
835 Value::Boolean(true)
836 );
837 }
838
839 #[test]
840 fn a_string_compares_by_bytes() {
841 assert_eq!(
842 compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
843 Value::Boolean(true)
844 );
845 assert_eq!(
846 compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
847 Value::Boolean(true)
848 );
849 }
850
851 #[test]
854 fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
855 assert_eq!(
856 compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
857 Value::Boolean(true)
858 );
859 assert_eq!(
860 compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
861 Value::Boolean(true)
862 );
863 }
864
865 #[test]
866 fn zero_has_one_value_however_it_is_signed() {
867 assert_eq!(
868 compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
869 Value::Boolean(true)
870 );
871 }
872
873 #[test]
878 fn two_intervals_of_the_same_length_are_one_value() {
879 let day = Value::Interval { months: 0, days: 1, micros: 0 };
880 let hours = Value::Interval { months: 0, days: 0, micros: 86_400_000_000 };
881 let month = Value::Interval { months: 1, days: 0, micros: 0 };
882 let thirty = Value::Interval { months: 0, days: 30, micros: 0 };
883 let long_day = Value::Interval { months: 0, days: 0, micros: 90_000_000_000 };
884 assert_eq!(compared(Comparison::Equal, day.clone(), hours), Value::Boolean(true));
885 assert_eq!(compared(Comparison::Equal, month, thirty), Value::Boolean(true));
886 assert_eq!(compared(Comparison::Greater, long_day, day), Value::Boolean(true));
887 }
888
889 #[test]
890 fn a_number_compares_the_same_however_it_is_stored() {
891 assert_eq!(
892 compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
893 Value::Boolean(true)
894 );
895 assert_eq!(
896 compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
897 Value::Boolean(true)
898 );
899 }
900
901 #[test]
902 fn nulls_go_where_the_query_asked_for_them() {
903 assert_eq!(
904 order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
905 Ordering::Less
906 );
907 assert_eq!(
908 order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
909 Ordering::Greater
910 );
911 }
912
913 #[test]
914 fn two_constant_vectors_cost_one_comparison() {
915 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
916 let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
917 let result = compare(Comparison::Less, &left, &right).expect("compares");
918 assert_eq!(result.form(), Form::Constant);
919 assert_eq!(result.value_at(500), Value::Boolean(true));
920 }
921
922 #[test]
923 fn a_comparison_of_two_vectors_is_one_answer_per_row() {
924 let left = Vector::from_values(
925 LogicalType::Integer,
926 &[Value::Integer(1), Value::Integer(5), Value::Null],
927 )
928 .expect("three rows");
929 let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
930 let result = compare(Comparison::Greater, &left, &right).expect("compares");
931 assert_eq!(result.value_at(0), Value::Boolean(false));
932 assert_eq!(result.value_at(1), Value::Boolean(true));
933 assert_eq!(result.value_at(2), Value::Null);
934 }
935
936 #[test]
937 fn two_vectors_of_different_lengths_are_caught() {
938 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
939 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
940 let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
941 assert!(error.message().contains("4 row vector"), "{error}");
942 }
943
944 #[test]
945 fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
946 for op in EVERY {
947 let left = Value::Integer(3);
948 let right = Value::Integer(7);
949 assert_eq!(
950 compare_values(op, &left, &right).expect("compares"),
951 compare_values(op.swapped(), &right, &left).expect("compares"),
952 "{op:?}"
953 );
954 }
955 }
956
957 #[test]
960 fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
961 let mut rng = Rng(0x5eed_1234_9876_4321);
962 let types: [LogicalType; 11] = [
963 LogicalType::Boolean,
964 LogicalType::TinyInt,
965 LogicalType::SmallInt,
966 LogicalType::Integer,
967 LogicalType::BigInt,
968 LogicalType::HugeInt,
969 LogicalType::UInteger,
970 LogicalType::Float,
971 LogicalType::Double,
972 LogicalType::Varchar,
973 LogicalType::Interval,
974 ];
975 for ty in &types {
976 for nulls in [0u64, 1, 3] {
977 let len = 37;
978 let make = |rng: &mut Rng| {
979 let values: Vec<Value> = (0..len)
980 .map(|_| {
981 if nulls > 0 && rng.below(nulls + 1) == 0 {
982 Value::Null
983 } else {
984 sample(ty, rng)
985 }
986 })
987 .collect();
988 Vector::from_values(ty.clone(), &values).expect("a flat vector")
989 };
990 let left = make(&mut rng);
991 let right = make(&mut rng);
992 let literal = sample(ty, &mut rng);
993 let constant = Vector::constant(ty.clone(), literal, len);
994 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
995 let codes: Vec<u32> =
996 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
997 let dictionary =
998 Vector::dictionary(codes, left.clone()).expect("codes are in range");
999 let ends: Vec<u32> = (1..=left.len())
1002 .map(|run| ((run * len) / left.len()).max(run) as u32)
1003 .collect();
1004 let runs = Vector::runs(ends, left.clone()).expect("one value for each run");
1005
1006 for op in EVERY {
1007 agrees(op, &left, &right);
1008 agrees(op, &left, &constant);
1009 agrees(op, &constant, &left);
1010 agrees(op, &left, &null_constant);
1011 agrees(op, &null_constant, &left);
1012 agrees(op, &dictionary, &constant);
1013 agrees(op, &constant, &dictionary);
1014 agrees(op, &dictionary, &right);
1018 agrees(op, &right, &dictionary);
1019 agrees(op, &runs, &constant);
1023 agrees(op, &constant, &runs);
1024 agrees(op, &runs, &right);
1025 agrees(op, &right, &runs);
1026 }
1027 }
1028 }
1029 }
1030
1031 fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
1033 let mut out = Vec::new();
1034 for &row in kept.indices() {
1035 let index = row as usize;
1036 let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
1037 .expect("the oracle is only asked about types that compare");
1038 if is_true(&answer) {
1039 out.push(row);
1040 }
1041 }
1042 Selection::from_indices(out)
1043 }
1044
1045 fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
1046 let fast = refine(op, left, right, kept).expect("compares");
1047 assert_eq!(
1048 fast,
1049 refined(op, left, right, kept),
1050 "{op:?} on a {:?} against a {:?} over {} rows",
1051 left.form(),
1052 right.form(),
1053 kept.len()
1054 );
1055 }
1056
1057 #[test]
1061 fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
1062 let mut rng = Rng(0x5eed_4321_1234_9876);
1063 let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
1064 for ty in &types {
1065 for nulls in [0u64, 1, 3] {
1066 let len = 37;
1067 let make = |rng: &mut Rng| {
1068 let values: Vec<Value> = (0..len)
1069 .map(|_| {
1070 if nulls > 0 && rng.below(nulls + 1) == 0 {
1071 Value::Null
1072 } else {
1073 sample(ty, rng)
1074 }
1075 })
1076 .collect();
1077 Vector::from_values(ty.clone(), &values).expect("a flat vector")
1078 };
1079 let left = make(&mut rng);
1080 let right = make(&mut rng);
1081 let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
1082 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1083 let codes: Vec<u32> =
1084 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1085 let dictionary =
1086 Vector::dictionary(codes, left.clone()).expect("codes are in range");
1087
1088 let selections = [
1092 Selection::identity(len),
1093 Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
1094 Selection::from_indices(vec![2, 5, 6, 17, 36]),
1095 Selection::empty(),
1096 ];
1097 for op in EVERY {
1098 for kept in &selections {
1099 threads(op, &left, &right, kept);
1100 threads(op, &left, &constant, kept);
1101 threads(op, &constant, &left, kept);
1102 threads(op, &left, &null_constant, kept);
1103 threads(op, &null_constant, &left, kept);
1104 threads(op, &constant, &null_constant, kept);
1105 threads(op, &dictionary, &constant, kept);
1106 threads(op, &constant, &dictionary, kept);
1107 threads(op, &dictionary, &right, kept);
1108 threads(op, &right, &dictionary, kept);
1109 }
1110 }
1111 }
1112 }
1113 }
1114
1115 #[test]
1119 fn a_second_conjunct_reads_only_what_the_first_one_left() {
1120 let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
1121 let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
1122 let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
1123 let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
1124
1125 let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
1126 .expect("compares");
1127 let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
1128
1129 let expected: Vec<u32> = (0..64)
1130 .filter(|row| {
1131 let value = row % 10;
1132 value > 3 && value < 7
1133 })
1134 .collect();
1135 assert_eq!(both.indices(), expected.as_slice());
1136 assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
1137 }
1138
1139 #[test]
1143 fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
1144 let column = Vector::from_values(
1145 LogicalType::Integer,
1146 &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
1147 )
1148 .expect("four rows");
1149 let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
1150 let all = Selection::identity(4);
1151 assert_eq!(
1152 refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
1153 &[0]
1154 );
1155 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
1157 assert_eq!(
1158 refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
1159 &[1, 3]
1160 );
1161 }
1162
1163 #[test]
1164 fn a_selection_past_the_end_is_caught() {
1165 let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1166 let past = Selection::from_indices(vec![0, 4]);
1167 let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
1168 assert!(error.message().contains("4 row vector"), "{error}");
1169 }
1170
1171 fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
1173 match ty {
1174 LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
1175 LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
1176 LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
1177 LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
1178 LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
1179 LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
1180 LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
1181 LogicalType::Float => Value::Float(match rng.below(5) {
1184 0 => f32::NAN,
1185 1 => -0.0,
1186 other => other as f32 - 2.0,
1187 }),
1188 LogicalType::Double => Value::Double(match rng.below(5) {
1189 0 => f64::NAN,
1190 1 => -0.0,
1191 other => other as f64 - 2.0,
1192 }),
1193 LogicalType::Interval => match rng.below(6) {
1197 0 => Value::Interval { months: 0, days: 1, micros: 0 },
1198 1 => Value::Interval { months: 0, days: 0, micros: 86_400_000_000 },
1199 2 => Value::Interval { months: 1, days: -29, micros: 86_400_000_000 },
1200 3 => Value::Interval { months: 1, days: 0, micros: 0 },
1201 4 => Value::Interval { months: 0, days: 0, micros: 90_000_000_000 },
1202 _ => Value::Interval { months: -1, days: 0, micros: 0 },
1203 },
1204 LogicalType::Varchar => Value::Varchar(
1207 match rng.below(6) {
1208 0 => "",
1209 1 => "ab",
1210 2 => "abc",
1211 3 => "abcdefghijkl",
1212 4 => "abcdefghijklm",
1213 _ => "abcdefghijklmnopqrstuvwxyz",
1214 }
1215 .to_owned(),
1216 ),
1217 other => panic!("the generator has no values for {other}"),
1218 }
1219 }
1220
1221 #[test]
1225 fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
1226 let words =
1227 ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
1228 let mut column = StringColumn::new();
1229 for word in words {
1230 column.push(word);
1231 }
1232 for (i, one) in words.iter().enumerate() {
1233 for (j, other) in words.iter().enumerate() {
1234 assert_eq!(
1235 string_order(&column, i, &column, j),
1236 one.as_bytes().cmp(other.as_bytes()),
1237 "{one:?} against {other:?}"
1238 );
1239 }
1240 }
1241 }
1242
1243 #[test]
1246 fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
1247 let values = Vector::from_values(
1248 LogicalType::Integer,
1249 &[Value::Integer(1), Value::Null, Value::Integer(9)],
1250 )
1251 .expect("three values");
1252 let dictionary =
1253 Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
1254 let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
1255 let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
1256 assert_eq!(result.value_at(0), Value::Boolean(true));
1257 assert_eq!(result.value_at(1), Value::Null);
1258 assert_eq!(result.value_at(2), Value::Boolean(false));
1259 assert_eq!(result.value_at(3), Value::Null);
1260 assert_eq!(result.value_at(4), Value::Boolean(true));
1261 }
1262
1263 #[test]
1266 fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
1267 let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
1269 let sequence = Vector::sequence(10, 1, 4);
1270 let flat = Vector::from_values(
1271 LogicalType::BigInt,
1272 &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
1273 )
1274 .expect("four rows");
1275 let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
1276 assert_eq!(result.value_at(0), Value::Boolean(false));
1277 assert_eq!(result.value_at(1), Value::Boolean(false));
1278 assert_eq!(result.value_at(2), Value::Boolean(false));
1279 assert_eq!(result.value_at(3), Value::Null);
1280 assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
1281 }
1282
1283 #[test]
1293 fn a_second_level_of_codes_does_not_turn_the_loops_off() {
1294 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
1295 let values = Vector::from_values(
1296 LogicalType::Integer,
1297 &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
1298 )
1299 .expect("three rows");
1300 let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
1301 let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
1302 let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
1303 let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
1304 assert_eq!(result.value_at(0), Value::Boolean(true));
1305 assert_eq!(result.value_at(1), Value::Boolean(false));
1306 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
1307 }
1308
1309 #[test]
1313 fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
1314 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
1315 let flat = Vector::from_values(
1316 LogicalType::Integer,
1317 &[
1318 Value::Integer(1),
1319 Value::Integer(2),
1320 Value::Integer(3),
1321 Value::Integer(4),
1322 Value::Integer(5),
1323 Value::Integer(6),
1324 ],
1325 )
1326 .expect("six rows");
1327 agrees(Comparison::Less, &nulls, &flat);
1328 agrees(Comparison::Equal, &flat, &nulls);
1329 assert_eq!(
1330 compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
1331 &Validity::AllInvalid
1332 );
1333 }
1334
1335 #[test]
1338 fn an_empty_comparison_is_an_empty_answer() {
1339 let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
1340 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
1341 let result = compare(Comparison::Equal, &left, &right).expect("compares");
1342 assert_eq!(result.len(), 0);
1343 }
1344
1345 fn words() -> Vector {
1348 Vector::from_values(
1349 LogicalType::Varchar,
1350 &[
1351 Value::Varchar("http://a".into()),
1352 Value::Varchar("http://b".into()),
1353 Value::Null,
1354 Value::Varchar("ab".into()),
1355 Value::Varchar("http://a".into()),
1356 Value::Varchar("z".into()),
1357 ],
1358 )
1359 .expect("six rows")
1360 }
1361
1362 #[test]
1368 fn a_literal_built_early_answers_what_one_built_here_answers() {
1369 let column = words();
1370 let value = Value::Varchar("http://b".into());
1371 let constant = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
1372 let held = Held::of(&LogicalType::Varchar, &value).expect("a varchar has a column");
1373 let kept = Selection::from_indices(vec![0, 1, 3, 5]);
1374 for op in [
1375 Comparison::Equal,
1376 Comparison::NotEqual,
1377 Comparison::Less,
1378 Comparison::LessOrEqual,
1379 Comparison::Greater,
1380 Comparison::GreaterOrEqual,
1381 Comparison::DistinctFrom,
1382 Comparison::NotDistinctFrom,
1383 ] {
1384 let prepared = compare_prepared(op, &column, &constant, Some(&held)).expect("compares");
1385 assert_eq!(prepared, compare(op, &column, &constant).expect("compares"), "{op:?}");
1386 let flipped = compare_prepared(op, &constant, &column, Some(&held)).expect("compares");
1388 assert_eq!(flipped, compare(op, &constant, &column).expect("compares"), "{op:?}");
1389 let refined =
1390 refine_prepared(op, &column, &constant, &kept, Some(&held)).expect("refines");
1391 assert_eq!(refined, refine(op, &column, &constant, &kept).expect("refines"), "{op:?}");
1392 }
1393 }
1394
1395 #[test]
1402 fn a_literal_built_for_another_value_is_ignored() {
1403 let column = words();
1404 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("z".into()), 6);
1405 let wrong = Held::of(&LogicalType::Varchar, &Value::Varchar("ab".into()))
1406 .expect("a varchar has a column");
1407 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&wrong))
1408 .expect("compares");
1409 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1410 let other = Held::of(&LogicalType::Integer, &Value::Integer(1)).expect("an integer column");
1413 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&other))
1414 .expect("compares");
1415 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1416 }
1417}