1use std::cmp::Ordering;
72
73use rudb_common::{Error, LogicalType, Result, Value};
74use rudb_vector::{Data, Form, Selection, StringColumn, Validity, Vector};
75
76use crate::fallback::{self, Kernel};
77use crate::logic::is_true;
78use crate::number::{approximate, integral};
79use crate::shape::{first, identity, nulls_of, single};
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub enum Comparison {
84 Equal,
86 NotEqual,
88 Less,
90 LessOrEqual,
92 Greater,
94 GreaterOrEqual,
96 DistinctFrom,
98 NotDistinctFrom,
100}
101
102impl Comparison {
103 #[must_use]
105 pub fn is_total(self) -> bool {
106 matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
107 }
108
109 #[must_use]
116 pub fn swapped(self) -> Self {
117 match self {
118 Self::Less => Self::Greater,
119 Self::LessOrEqual => Self::GreaterOrEqual,
120 Self::Greater => Self::Less,
121 Self::GreaterOrEqual => Self::LessOrEqual,
122 same => same,
123 }
124 }
125}
126
127pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
133 if left.len() != right.len() {
134 return Err(Error::internal(format!(
135 "a comparison of a {} row vector with a {} row one",
136 left.len(),
137 right.len()
138 )));
139 }
140 let len = left.len();
141 if left.form() == Form::Constant && right.form() == Form::Constant && len > 0 {
142 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
143 return Ok(Vector::constant(LogicalType::Boolean, single, len));
144 }
145
146 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
147 if !op.is_total()
151 && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
152 && len > 0
153 {
154 return boolean(vec![false; len], Validity::AllInvalid, len);
155 }
156
157 if let Some(answers) = specialized(op, left, right, &left_valid, &right_valid, len, identity) {
158 let validity =
159 if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
160 return boolean(blank_the_nulls(answers, &validity), validity, len);
161 }
162
163 fallback::record(Kernel::Compare, left.form(), right.form());
164 let mut values = Vec::with_capacity(len);
165 for index in 0..len {
168 values.push(compare_values(op, &left.value_at(index), &right.value_at(index))?);
169 }
170 Vector::from_values(LogicalType::Boolean, &values)
171}
172
173pub fn refine(
191 op: Comparison,
192 left: &Vector,
193 right: &Vector,
194 kept: &Selection,
195) -> Result<Selection> {
196 if left.len() != right.len() {
197 return Err(Error::internal(format!(
198 "a comparison of a {} row vector with a {} row one",
199 left.len(),
200 right.len()
201 )));
202 }
203 let len = left.len();
204 if kept.indices().iter().any(|&row| row as usize >= len) {
208 return Err(Error::internal(format!("a selection past the end of a {len} row vector")));
209 }
210 if kept.is_empty() {
211 return Ok(Selection::empty());
212 }
213 if left.form() == Form::Constant && right.form() == Form::Constant {
214 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
215 return Ok(if is_true(&single) { kept.clone() } else { Selection::empty() });
216 }
217
218 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
219 if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
220 {
221 return Ok(Selection::empty());
222 }
223
224 let rows = kept.indices();
225 let map = |slot: usize| rows[slot] as usize;
226 if let Some(answers) = specialized(op, left, right, &left_valid, &right_valid, kept.len(), map)
227 {
228 if op.is_total() || (left_valid == Validity::AllValid && right_valid == Validity::AllValid)
231 {
232 return Ok(narrowed(&answers, rows, |_| true));
233 }
234 return Ok(narrowed(&answers, rows, |slot| {
238 let row = rows[slot] as usize;
239 left_valid.is_valid(row) && right_valid.is_valid(row)
240 }));
241 }
242
243 fallback::record(Kernel::Compare, left.form(), right.form());
244 let mut out = Vec::with_capacity(kept.len());
245 for &row in rows {
248 let index = row as usize;
249 if is_true(&compare_values(op, &left.value_at(index), &right.value_at(index))?) {
250 out.push(row);
251 }
252 }
253 Ok(Selection::from_indices(out))
254}
255
256fn narrowed<L: Fn(usize) -> bool>(answers: &[bool], rows: &[u32], live: L) -> Selection {
263 let mut out = vec![0_u32; answers.len()];
264 let mut count = 0;
265 for (slot, &answer) in answers.iter().enumerate() {
266 out[count] = rows[slot];
267 count += usize::from(answer & live(slot));
269 }
270 out.truncate(count);
271 Selection::from_indices(out)
272}
273
274fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
276 let validity = if len == 0 { Validity::AllValid } else { validity.normalize(len) };
280 Ok(Vector::flat(LogicalType::Boolean, Data::Bool(answers.into()))?.with_validity(validity))
281}
282
283fn blank_the_nulls(mut answers: Vec<bool>, validity: &Validity) -> Vec<bool> {
291 if let Validity::Mask(mask) = validity {
292 for (index, answer) in answers.iter_mut().enumerate() {
293 if !mask.get(index) {
294 *answer = false;
295 }
296 }
297 }
298 answers
299}
300
301fn specialized<M>(
313 op: Comparison,
314 left: &Vector,
315 right: &Vector,
316 left_valid: &Validity,
317 right_valid: &Validity,
318 len: usize,
319 map: M,
320) -> Option<Vec<bool>>
321where
322 M: Fn(usize) -> usize + Copy,
323{
324 if left.logical_type() != right.logical_type() {
328 return None;
329 }
330
331 if let (Some(one), Some(other)) = (left.data(), right.data()) {
332 return dispatch(op, len, one, map, other, map, left_valid, right_valid, map);
333 }
334 if let (Some(one), Some(value)) = (left.data(), right.constant_value()) {
335 let held = single(left.logical_type(), value)?;
336 let other = held.data()?;
337 return dispatch(op, len, one, map, other, first, left_valid, right_valid, map);
338 }
339 if let (Some(value), Some(other)) = (left.constant_value(), right.data()) {
340 let held = single(right.logical_type(), value)?;
342 let one = held.data()?;
343 return dispatch(op.swapped(), len, other, map, one, first, right_valid, left_valid, map);
344 }
345 if let (Some((codes, values)), Some(value)) = (left.dictionary_parts(), right.constant_value())
346 {
347 let one = values.data()?;
348 let held = single(left.logical_type(), value)?;
349 let other = held.data()?;
350 let at = |index: usize| codes[map(index)] as usize;
351 return dispatch(op, len, one, at, other, first, left_valid, right_valid, map);
352 }
353 if let (Some(value), Some((codes, values))) = (left.constant_value(), right.dictionary_parts())
354 {
355 let other = values.data()?;
356 let held = single(right.logical_type(), value)?;
357 let one = held.data()?;
358 let at = |index: usize| codes[map(index)] as usize;
359 return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid, map);
360 }
361 if let (Some((codes, values)), Some(other)) = (left.dictionary_parts(), right.data()) {
367 let one = values.data()?;
368 let at = |index: usize| codes[map(index)] as usize;
369 return dispatch(op, len, one, at, other, map, left_valid, right_valid, map);
370 }
371 if let (Some(one), Some((codes, values))) = (left.data(), right.dictionary_parts()) {
372 let other = values.data()?;
373 let at = |index: usize| codes[map(index)] as usize;
374 return dispatch(op.swapped(), len, other, at, one, map, right_valid, left_valid, map);
375 }
376 None
377}
378
379#[expect(
385 clippy::too_many_arguments,
386 reason = "two sides with an index each, the operator, the length and two validities, all of \
387 which the loop needs and none of which is worth a struct that exists for one call"
388)]
389fn dispatch<L, R, V>(
390 op: Comparison,
391 len: usize,
392 left: &Data,
393 at_left: L,
394 right: &Data,
395 at_right: R,
396 left_valid: &Validity,
397 right_valid: &Validity,
398 at_valid: V,
399) -> Option<Vec<bool>>
400where
401 L: Fn(usize) -> usize,
402 R: Fn(usize) -> usize,
403 V: Fn(usize) -> usize,
404{
405 macro_rules! layouts {
409 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
410 match (left, right) {
411 $(
412 (Data::$variant(one), Data::$variant(other)) => Some(sweep(
413 op,
414 len,
415 |index| one[at_left(index)].cmp(&other[at_right(index)]),
416 left_valid,
417 right_valid,
418 &at_valid,
419 )),
420 )+
421 (Data::Float32(one), Data::Float32(other)) => Some(sweep(
424 op,
425 len,
426 |index| {
427 float_order(
428 f64::from(one[at_left(index)]),
429 f64::from(other[at_right(index)]),
430 )
431 },
432 left_valid,
433 right_valid,
434 &at_valid,
435 )),
436 (Data::Float64(one), Data::Float64(other)) => Some(sweep(
437 op,
438 len,
439 |index| float_order(one[at_left(index)], other[at_right(index)]),
440 left_valid,
441 right_valid,
442 &at_valid,
443 )),
444 (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
445 op,
446 len,
447 |index| string_order(one, at_left(index), other, at_right(index)),
448 left_valid,
449 right_valid,
450 &at_valid,
451 )),
452 _ => None,
453 }
454 };
455 }
456 rudb_vector::for_each_layout!(ordered, layouts)
457}
458
459fn string_order(
467 left: &StringColumn,
468 at_left: usize,
469 right: &StringColumn,
470 at_right: usize,
471) -> Ordering {
472 let (Some(one), Some(other)) = (left.views().get(at_left), right.views().get(at_right)) else {
473 return Ordering::Equal;
474 };
475 let (prefix, against) = (one.prefix(), other.prefix());
476 if prefix != against {
477 return prefix.cmp(&against);
478 }
479 let bytes = left.bytes(at_left).unwrap_or_default();
484 let against_bytes = right.bytes(at_right).unwrap_or_default();
485 bytes.cmp(against_bytes)
486}
487
488fn sweep<O, V>(
494 op: Comparison,
495 len: usize,
496 order_at: O,
497 left_valid: &Validity,
498 right_valid: &Validity,
499 at_valid: V,
500) -> Vec<bool>
501where
502 O: Fn(usize) -> Ordering,
503 V: Fn(usize) -> usize,
504{
505 let mut answers = vec![false; len];
506 match op {
507 Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
508 Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
509 Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
510 Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
511 Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
512 Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
513 Comparison::DistinctFrom => {
514 total(&mut answers, order_at, left_valid, right_valid, at_valid);
515 for answer in &mut answers {
516 *answer = !*answer;
517 }
518 }
519 Comparison::NotDistinctFrom => {
520 total(&mut answers, order_at, left_valid, right_valid, at_valid);
521 }
522 }
523 answers
524}
525
526#[inline]
528fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
529where
530 O: Fn(usize) -> Ordering,
531 H: Fn(Ordering) -> bool,
532{
533 for (index, answer) in answers.iter_mut().enumerate() {
534 *answer = held(order_at(index));
535 }
536}
537
538fn total<O, V>(
545 answers: &mut [bool],
546 order_at: O,
547 left_valid: &Validity,
548 right_valid: &Validity,
549 at_valid: V,
550) where
551 O: Fn(usize) -> Ordering,
552 V: Fn(usize) -> usize,
553{
554 if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
555 fill(answers, order_at, |o| o == Ordering::Equal);
556 return;
557 }
558 for (index, answer) in answers.iter_mut().enumerate() {
559 let row = at_valid(index);
560 *answer = match (left_valid.is_valid(row), right_valid.is_valid(row)) {
561 (true, true) => order_at(index) == Ordering::Equal,
562 (false, false) => true,
563 _ => false,
564 };
565 }
566}
567
568pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
574 if op.is_total() {
575 let same = match (left.is_null(), right.is_null()) {
576 (true, true) => true,
577 (true, false) | (false, true) => false,
578 (false, false) => order(left, right)? == Ordering::Equal,
579 };
580 return Ok(Value::Boolean(match op {
581 Comparison::NotDistinctFrom => same,
582 _ => !same,
583 }));
584 }
585 if left.is_null() || right.is_null() {
586 return Ok(Value::Null);
587 }
588 let ordering = order(left, right)?;
589 let held = match op {
590 Comparison::Equal => ordering == Ordering::Equal,
591 Comparison::NotEqual => ordering != Ordering::Equal,
592 Comparison::Less => ordering == Ordering::Less,
593 Comparison::LessOrEqual => ordering != Ordering::Greater,
594 Comparison::Greater => ordering == Ordering::Greater,
595 Comparison::GreaterOrEqual => ordering != Ordering::Less,
596 Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
597 return Err(Error::internal("a total comparison reached the ordered path"));
598 }
599 };
600 Ok(Value::Boolean(held))
601}
602
603pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
614 match (left, right) {
615 (Value::Null, _) | (_, Value::Null) => {
616 Err(Error::internal("a null reached the ordering path"))
617 }
618 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
619 (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
620 (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
621 (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
622 (Value::Time(a), Value::Time(b)) | (Value::Timestamp(a), Value::Timestamp(b)) => {
623 Ok(a.cmp(b))
624 }
625 (
626 Value::Interval { months: am, days: ad, micros: au },
627 Value::Interval { months: bm, days: bd, micros: bu },
628 ) => Ok((am, ad, au).cmp(&(bm, bd, bu))),
629 _ => numeric_order(left, right),
630 }
631}
632
633fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
635 if let (Some(a), Some(b)) = (integral(left), integral(right)) {
636 return Ok(a.cmp(&b));
637 }
638 if let (
639 Value::Decimal { unscaled: a, scale: sa, .. },
640 Value::Decimal { unscaled: b, scale: sb, .. },
641 ) = (left, right)
642 {
643 if sa == sb {
644 return Ok(a.cmp(b));
645 }
646 }
647 match (approximate(left), approximate(right)) {
648 (Some(a), Some(b)) => Ok(float_order(a, b)),
649 _ => Err(Error::not_implemented(format!(
650 "comparing {} with {}",
651 left.logical_type(),
652 right.logical_type()
653 ))),
654 }
655}
656
657fn float_order(left: f64, right: f64) -> Ordering {
659 if left == right {
660 return Ordering::Equal;
661 }
662 match (left.is_nan(), right.is_nan()) {
663 (true, true) => Ordering::Equal,
664 (true, false) => Ordering::Greater,
665 (false, true) => Ordering::Less,
666 (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
667 }
668}
669
670pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
679 match (left.is_null(), right.is_null()) {
680 (true, true) => Ok(Ordering::Equal),
681 (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
682 (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
683 (false, false) => order(left, right),
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 use super::*;
690
691 fn compared(op: Comparison, left: Value, right: Value) -> Value {
692 compare_values(op, &left, &right).expect("these types compare")
693 }
694
695 const EVERY: [Comparison; 8] = [
697 Comparison::Equal,
698 Comparison::NotEqual,
699 Comparison::Less,
700 Comparison::LessOrEqual,
701 Comparison::Greater,
702 Comparison::GreaterOrEqual,
703 Comparison::DistinctFrom,
704 Comparison::NotDistinctFrom,
705 ];
706
707 fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
713 let values: Vec<Value> = (0..left.len())
714 .map(|index| {
715 compare_values(op, &left.value_at(index), &right.value_at(index))
716 .expect("the oracle is only asked about types that compare")
717 })
718 .collect();
719 Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
720 }
721
722 fn agrees(op: Comparison, left: &Vector, right: &Vector) {
726 let fast = compare(op, left, right).expect("compares");
727 let slow = oracle(op, left, right);
728 assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
729 }
730
731 struct Rng(u64);
734
735 impl Rng {
736 fn next(&mut self) -> u64 {
737 self.0 ^= self.0 << 13;
738 self.0 ^= self.0 >> 7;
739 self.0 ^= self.0 << 17;
740 self.0
741 }
742
743 fn below(&mut self, bound: u64) -> u64 {
744 self.next() % bound
745 }
746 }
747
748 #[test]
749 fn an_ordinary_comparison_is_null_when_either_side_is() {
750 assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
751 assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
752 }
753
754 #[test]
755 fn a_total_comparison_is_never_null() {
756 assert_eq!(
757 compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
758 Value::Boolean(true)
759 );
760 assert_eq!(
761 compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
762 Value::Boolean(false)
763 );
764 assert_eq!(
765 compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
766 Value::Boolean(true)
767 );
768 }
769
770 #[test]
771 fn a_string_compares_by_bytes() {
772 assert_eq!(
773 compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
774 Value::Boolean(true)
775 );
776 assert_eq!(
777 compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
778 Value::Boolean(true)
779 );
780 }
781
782 #[test]
785 fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
786 assert_eq!(
787 compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
788 Value::Boolean(true)
789 );
790 assert_eq!(
791 compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
792 Value::Boolean(true)
793 );
794 }
795
796 #[test]
797 fn zero_has_one_value_however_it_is_signed() {
798 assert_eq!(
799 compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
800 Value::Boolean(true)
801 );
802 }
803
804 #[test]
805 fn a_number_compares_the_same_however_it_is_stored() {
806 assert_eq!(
807 compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
808 Value::Boolean(true)
809 );
810 assert_eq!(
811 compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
812 Value::Boolean(true)
813 );
814 }
815
816 #[test]
817 fn nulls_go_where_the_query_asked_for_them() {
818 assert_eq!(
819 order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
820 Ordering::Less
821 );
822 assert_eq!(
823 order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
824 Ordering::Greater
825 );
826 }
827
828 #[test]
829 fn two_constant_vectors_cost_one_comparison() {
830 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
831 let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
832 let result = compare(Comparison::Less, &left, &right).expect("compares");
833 assert_eq!(result.form(), Form::Constant);
834 assert_eq!(result.value_at(500), Value::Boolean(true));
835 }
836
837 #[test]
838 fn a_comparison_of_two_vectors_is_one_answer_per_row() {
839 let left = Vector::from_values(
840 LogicalType::Integer,
841 &[Value::Integer(1), Value::Integer(5), Value::Null],
842 )
843 .expect("three rows");
844 let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
845 let result = compare(Comparison::Greater, &left, &right).expect("compares");
846 assert_eq!(result.value_at(0), Value::Boolean(false));
847 assert_eq!(result.value_at(1), Value::Boolean(true));
848 assert_eq!(result.value_at(2), Value::Null);
849 }
850
851 #[test]
852 fn two_vectors_of_different_lengths_are_caught() {
853 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
854 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
855 let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
856 assert!(error.message().contains("4 row vector"), "{error}");
857 }
858
859 #[test]
860 fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
861 for op in EVERY {
862 let left = Value::Integer(3);
863 let right = Value::Integer(7);
864 assert_eq!(
865 compare_values(op, &left, &right).expect("compares"),
866 compare_values(op.swapped(), &right, &left).expect("compares"),
867 "{op:?}"
868 );
869 }
870 }
871
872 #[test]
875 fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
876 let mut rng = Rng(0x5eed_1234_9876_4321);
877 let types: [LogicalType; 10] = [
878 LogicalType::Boolean,
879 LogicalType::TinyInt,
880 LogicalType::SmallInt,
881 LogicalType::Integer,
882 LogicalType::BigInt,
883 LogicalType::HugeInt,
884 LogicalType::UInteger,
885 LogicalType::Float,
886 LogicalType::Double,
887 LogicalType::Varchar,
888 ];
889 for ty in &types {
890 for nulls in [0u64, 1, 3] {
891 let len = 37;
892 let make = |rng: &mut Rng| {
893 let values: Vec<Value> = (0..len)
894 .map(|_| {
895 if nulls > 0 && rng.below(nulls + 1) == 0 {
896 Value::Null
897 } else {
898 sample(ty, rng)
899 }
900 })
901 .collect();
902 Vector::from_values(ty.clone(), &values).expect("a flat vector")
903 };
904 let left = make(&mut rng);
905 let right = make(&mut rng);
906 let literal = sample(ty, &mut rng);
907 let constant = Vector::constant(ty.clone(), literal, len);
908 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
909 let codes: Vec<u32> =
910 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
911 let dictionary =
912 Vector::dictionary(codes, left.clone()).expect("codes are in range");
913
914 for op in EVERY {
915 agrees(op, &left, &right);
916 agrees(op, &left, &constant);
917 agrees(op, &constant, &left);
918 agrees(op, &left, &null_constant);
919 agrees(op, &null_constant, &left);
920 agrees(op, &dictionary, &constant);
921 agrees(op, &constant, &dictionary);
922 agrees(op, &dictionary, &right);
926 agrees(op, &right, &dictionary);
927 }
928 }
929 }
930 }
931
932 fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
934 let mut out = Vec::new();
935 for &row in kept.indices() {
936 let index = row as usize;
937 let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
938 .expect("the oracle is only asked about types that compare");
939 if is_true(&answer) {
940 out.push(row);
941 }
942 }
943 Selection::from_indices(out)
944 }
945
946 fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
947 let fast = refine(op, left, right, kept).expect("compares");
948 assert_eq!(
949 fast,
950 refined(op, left, right, kept),
951 "{op:?} on a {:?} against a {:?} over {} rows",
952 left.form(),
953 right.form(),
954 kept.len()
955 );
956 }
957
958 #[test]
962 fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
963 let mut rng = Rng(0x5eed_4321_1234_9876);
964 let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
965 for ty in &types {
966 for nulls in [0u64, 1, 3] {
967 let len = 37;
968 let make = |rng: &mut Rng| {
969 let values: Vec<Value> = (0..len)
970 .map(|_| {
971 if nulls > 0 && rng.below(nulls + 1) == 0 {
972 Value::Null
973 } else {
974 sample(ty, rng)
975 }
976 })
977 .collect();
978 Vector::from_values(ty.clone(), &values).expect("a flat vector")
979 };
980 let left = make(&mut rng);
981 let right = make(&mut rng);
982 let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
983 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
984 let codes: Vec<u32> =
985 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
986 let dictionary =
987 Vector::dictionary(codes, left.clone()).expect("codes are in range");
988
989 let selections = [
993 Selection::identity(len),
994 Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
995 Selection::from_indices(vec![2, 5, 6, 17, 36]),
996 Selection::empty(),
997 ];
998 for op in EVERY {
999 for kept in &selections {
1000 threads(op, &left, &right, kept);
1001 threads(op, &left, &constant, kept);
1002 threads(op, &constant, &left, kept);
1003 threads(op, &left, &null_constant, kept);
1004 threads(op, &null_constant, &left, kept);
1005 threads(op, &constant, &null_constant, kept);
1006 threads(op, &dictionary, &constant, kept);
1007 threads(op, &constant, &dictionary, kept);
1008 threads(op, &dictionary, &right, kept);
1009 threads(op, &right, &dictionary, kept);
1010 }
1011 }
1012 }
1013 }
1014 }
1015
1016 #[test]
1020 fn a_second_conjunct_reads_only_what_the_first_one_left() {
1021 let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
1022 let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
1023 let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
1024 let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
1025
1026 let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
1027 .expect("compares");
1028 let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
1029
1030 let expected: Vec<u32> = (0..64)
1031 .filter(|row| {
1032 let value = row % 10;
1033 value > 3 && value < 7
1034 })
1035 .collect();
1036 assert_eq!(both.indices(), expected.as_slice());
1037 assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
1038 }
1039
1040 #[test]
1044 fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
1045 let column = Vector::from_values(
1046 LogicalType::Integer,
1047 &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
1048 )
1049 .expect("four rows");
1050 let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
1051 let all = Selection::identity(4);
1052 assert_eq!(
1053 refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
1054 &[0]
1055 );
1056 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
1058 assert_eq!(
1059 refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
1060 &[1, 3]
1061 );
1062 }
1063
1064 #[test]
1065 fn a_selection_past_the_end_is_caught() {
1066 let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1067 let past = Selection::from_indices(vec![0, 4]);
1068 let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
1069 assert!(error.message().contains("4 row vector"), "{error}");
1070 }
1071
1072 fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
1074 match ty {
1075 LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
1076 LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
1077 LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
1078 LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
1079 LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
1080 LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
1081 LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
1082 LogicalType::Float => Value::Float(match rng.below(5) {
1085 0 => f32::NAN,
1086 1 => -0.0,
1087 other => other as f32 - 2.0,
1088 }),
1089 LogicalType::Double => Value::Double(match rng.below(5) {
1090 0 => f64::NAN,
1091 1 => -0.0,
1092 other => other as f64 - 2.0,
1093 }),
1094 LogicalType::Varchar => Value::Varchar(
1097 match rng.below(6) {
1098 0 => "",
1099 1 => "ab",
1100 2 => "abc",
1101 3 => "abcdefghijkl",
1102 4 => "abcdefghijklm",
1103 _ => "abcdefghijklmnopqrstuvwxyz",
1104 }
1105 .to_owned(),
1106 ),
1107 other => panic!("the generator has no values for {other}"),
1108 }
1109 }
1110
1111 #[test]
1115 fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
1116 let words =
1117 ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
1118 let mut column = StringColumn::new();
1119 for word in words {
1120 column.push(word);
1121 }
1122 for (i, one) in words.iter().enumerate() {
1123 for (j, other) in words.iter().enumerate() {
1124 assert_eq!(
1125 string_order(&column, i, &column, j),
1126 one.as_bytes().cmp(other.as_bytes()),
1127 "{one:?} against {other:?}"
1128 );
1129 }
1130 }
1131 }
1132
1133 #[test]
1136 fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
1137 let values = Vector::from_values(
1138 LogicalType::Integer,
1139 &[Value::Integer(1), Value::Null, Value::Integer(9)],
1140 )
1141 .expect("three values");
1142 let dictionary =
1143 Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
1144 let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
1145 let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
1146 assert_eq!(result.value_at(0), Value::Boolean(true));
1147 assert_eq!(result.value_at(1), Value::Null);
1148 assert_eq!(result.value_at(2), Value::Boolean(false));
1149 assert_eq!(result.value_at(3), Value::Null);
1150 assert_eq!(result.value_at(4), Value::Boolean(true));
1151 }
1152
1153 #[test]
1156 fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
1157 let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
1159 let sequence = Vector::sequence(10, 1, 4);
1160 let flat = Vector::from_values(
1161 LogicalType::BigInt,
1162 &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
1163 )
1164 .expect("four rows");
1165 let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
1166 assert_eq!(result.value_at(0), Value::Boolean(false));
1167 assert_eq!(result.value_at(1), Value::Boolean(false));
1168 assert_eq!(result.value_at(2), Value::Boolean(false));
1169 assert_eq!(result.value_at(3), Value::Null);
1170 assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
1171 }
1172
1173 #[test]
1183 fn a_second_level_of_codes_does_not_turn_the_loops_off() {
1184 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
1185 let values = Vector::from_values(
1186 LogicalType::Integer,
1187 &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
1188 )
1189 .expect("three rows");
1190 let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
1191 let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
1192 let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
1193 let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
1194 assert_eq!(result.value_at(0), Value::Boolean(true));
1195 assert_eq!(result.value_at(1), Value::Boolean(false));
1196 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
1197 }
1198
1199 #[test]
1203 fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
1204 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
1205 let flat = Vector::from_values(
1206 LogicalType::Integer,
1207 &[
1208 Value::Integer(1),
1209 Value::Integer(2),
1210 Value::Integer(3),
1211 Value::Integer(4),
1212 Value::Integer(5),
1213 Value::Integer(6),
1214 ],
1215 )
1216 .expect("six rows");
1217 agrees(Comparison::Less, &nulls, &flat);
1218 agrees(Comparison::Equal, &flat, &nulls);
1219 assert_eq!(
1220 compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
1221 &Validity::AllInvalid
1222 );
1223 }
1224
1225 #[test]
1228 fn an_empty_comparison_is_an_empty_answer() {
1229 let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
1230 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
1231 let result = compare(Comparison::Equal, &left, &right).expect("compares");
1232 assert_eq!(result.len(), 0);
1233 }
1234}