1use std::cmp::Ordering;
66
67use rudb_common::{Error, LogicalType, Result, Value};
68use rudb_vector::{Data, Form, StringColumn, Validity, Vector};
69
70use crate::fallback::{self, Kernel};
71use crate::number::{approximate, integral};
72use crate::shape::{first, identity, nulls_of, single};
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
76pub enum Comparison {
77 Equal,
79 NotEqual,
81 Less,
83 LessOrEqual,
85 Greater,
87 GreaterOrEqual,
89 DistinctFrom,
91 NotDistinctFrom,
93}
94
95impl Comparison {
96 #[must_use]
98 pub fn is_total(self) -> bool {
99 matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
100 }
101
102 #[must_use]
109 pub fn swapped(self) -> Self {
110 match self {
111 Self::Less => Self::Greater,
112 Self::LessOrEqual => Self::GreaterOrEqual,
113 Self::Greater => Self::Less,
114 Self::GreaterOrEqual => Self::LessOrEqual,
115 same => same,
116 }
117 }
118}
119
120pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
126 if left.len() != right.len() {
127 return Err(Error::internal(format!(
128 "a comparison of a {} row vector with a {} row one",
129 left.len(),
130 right.len()
131 )));
132 }
133 let len = left.len();
134 if left.form() == Form::Constant && right.form() == Form::Constant && len > 0 {
135 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
136 return Ok(Vector::constant(LogicalType::Boolean, single, len));
137 }
138
139 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
140 if !op.is_total()
144 && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
145 && len > 0
146 {
147 return boolean(vec![false; len], Validity::AllInvalid, len);
148 }
149
150 if let Some(answers) = specialized(op, left, right, &left_valid, &right_valid) {
151 let validity =
152 if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
153 return boolean(blank_the_nulls(answers, &validity), validity, len);
154 }
155
156 fallback::record(Kernel::Compare, left.form(), right.form());
157 let mut values = Vec::with_capacity(len);
158 for index in 0..len {
161 values.push(compare_values(op, &left.value_at(index), &right.value_at(index))?);
162 }
163 Vector::from_values(LogicalType::Boolean, &values)
164}
165
166fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
168 let validity = if len == 0 { Validity::AllValid } else { validity.normalize(len) };
172 Ok(Vector::flat(LogicalType::Boolean, Data::Bool(answers.into()))?.with_validity(validity))
173}
174
175fn blank_the_nulls(mut answers: Vec<bool>, validity: &Validity) -> Vec<bool> {
183 if let Validity::Mask(mask) = validity {
184 for (index, answer) in answers.iter_mut().enumerate() {
185 if !mask.get(index) {
186 *answer = false;
187 }
188 }
189 }
190 answers
191}
192
193fn specialized(
195 op: Comparison,
196 left: &Vector,
197 right: &Vector,
198 left_valid: &Validity,
199 right_valid: &Validity,
200) -> Option<Vec<bool>> {
201 if left.logical_type() != right.logical_type() {
205 return None;
206 }
207 let len = left.len();
208
209 if let (Some(one), Some(other)) = (left.data(), right.data()) {
210 return dispatch(op, len, one, identity, other, identity, left_valid, right_valid);
211 }
212 if let (Some(one), Some(value)) = (left.data(), right.constant_value()) {
213 let held = single(left.logical_type(), value)?;
214 let other = held.data()?;
215 return dispatch(op, len, one, identity, other, first, left_valid, right_valid);
216 }
217 if let (Some(value), Some(other)) = (left.constant_value(), right.data()) {
218 let held = single(right.logical_type(), value)?;
220 let one = held.data()?;
221 return dispatch(op.swapped(), len, other, identity, one, first, right_valid, left_valid);
222 }
223 if let (Some((codes, values)), Some(value)) = (left.dictionary_parts(), right.constant_value())
224 {
225 let one = values.data()?;
226 let held = single(left.logical_type(), value)?;
227 let other = held.data()?;
228 let at = |index: usize| codes[index] as usize;
229 return dispatch(op, len, one, at, other, first, left_valid, right_valid);
230 }
231 if let (Some(value), Some((codes, values))) = (left.constant_value(), right.dictionary_parts())
232 {
233 let other = values.data()?;
234 let held = single(right.logical_type(), value)?;
235 let one = held.data()?;
236 let at = |index: usize| codes[index] as usize;
237 return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid);
238 }
239 None
240}
241
242#[expect(
248 clippy::too_many_arguments,
249 reason = "two sides with an index each, the operator, the length and two validities, all of \
250 which the loop needs and none of which is worth a struct that exists for one call"
251)]
252fn dispatch<L, R>(
253 op: Comparison,
254 len: usize,
255 left: &Data,
256 at_left: L,
257 right: &Data,
258 at_right: R,
259 left_valid: &Validity,
260 right_valid: &Validity,
261) -> Option<Vec<bool>>
262where
263 L: Fn(usize) -> usize,
264 R: Fn(usize) -> usize,
265{
266 macro_rules! layouts {
270 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
271 match (left, right) {
272 $(
273 (Data::$variant(one), Data::$variant(other)) => Some(sweep(
274 op,
275 len,
276 |index| one[at_left(index)].cmp(&other[at_right(index)]),
277 left_valid,
278 right_valid,
279 )),
280 )+
281 (Data::Float32(one), Data::Float32(other)) => Some(sweep(
284 op,
285 len,
286 |index| {
287 float_order(
288 f64::from(one[at_left(index)]),
289 f64::from(other[at_right(index)]),
290 )
291 },
292 left_valid,
293 right_valid,
294 )),
295 (Data::Float64(one), Data::Float64(other)) => Some(sweep(
296 op,
297 len,
298 |index| float_order(one[at_left(index)], other[at_right(index)]),
299 left_valid,
300 right_valid,
301 )),
302 (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
303 op,
304 len,
305 |index| string_order(one, at_left(index), other, at_right(index)),
306 left_valid,
307 right_valid,
308 )),
309 _ => None,
310 }
311 };
312 }
313 rudb_vector::for_each_layout!(ordered, layouts)
314}
315
316fn string_order(
324 left: &StringColumn,
325 at_left: usize,
326 right: &StringColumn,
327 at_right: usize,
328) -> Ordering {
329 let (Some(one), Some(other)) = (left.views().get(at_left), right.views().get(at_right)) else {
330 return Ordering::Equal;
331 };
332 let (prefix, against) = (one.prefix(), other.prefix());
333 if prefix != against {
334 return prefix.cmp(&against);
335 }
336 let bytes = left.bytes(at_left).unwrap_or_default();
341 let against_bytes = right.bytes(at_right).unwrap_or_default();
342 bytes.cmp(against_bytes)
343}
344
345fn sweep<O>(
351 op: Comparison,
352 len: usize,
353 order_at: O,
354 left_valid: &Validity,
355 right_valid: &Validity,
356) -> Vec<bool>
357where
358 O: Fn(usize) -> Ordering,
359{
360 let mut answers = vec![false; len];
361 match op {
362 Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
363 Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
364 Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
365 Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
366 Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
367 Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
368 Comparison::DistinctFrom => {
369 total(&mut answers, order_at, left_valid, right_valid);
370 for answer in &mut answers {
371 *answer = !*answer;
372 }
373 }
374 Comparison::NotDistinctFrom => total(&mut answers, order_at, left_valid, right_valid),
375 }
376 answers
377}
378
379#[inline]
381fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
382where
383 O: Fn(usize) -> Ordering,
384 H: Fn(Ordering) -> bool,
385{
386 for (index, answer) in answers.iter_mut().enumerate() {
387 *answer = held(order_at(index));
388 }
389}
390
391fn total<O>(answers: &mut [bool], order_at: O, left_valid: &Validity, right_valid: &Validity)
398where
399 O: Fn(usize) -> Ordering,
400{
401 if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
402 fill(answers, order_at, |o| o == Ordering::Equal);
403 return;
404 }
405 for (index, answer) in answers.iter_mut().enumerate() {
406 *answer = match (left_valid.is_valid(index), right_valid.is_valid(index)) {
407 (true, true) => order_at(index) == Ordering::Equal,
408 (false, false) => true,
409 _ => false,
410 };
411 }
412}
413
414pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
420 if op.is_total() {
421 let same = match (left.is_null(), right.is_null()) {
422 (true, true) => true,
423 (true, false) | (false, true) => false,
424 (false, false) => order(left, right)? == Ordering::Equal,
425 };
426 return Ok(Value::Boolean(match op {
427 Comparison::NotDistinctFrom => same,
428 _ => !same,
429 }));
430 }
431 if left.is_null() || right.is_null() {
432 return Ok(Value::Null);
433 }
434 let ordering = order(left, right)?;
435 let held = match op {
436 Comparison::Equal => ordering == Ordering::Equal,
437 Comparison::NotEqual => ordering != Ordering::Equal,
438 Comparison::Less => ordering == Ordering::Less,
439 Comparison::LessOrEqual => ordering != Ordering::Greater,
440 Comparison::Greater => ordering == Ordering::Greater,
441 Comparison::GreaterOrEqual => ordering != Ordering::Less,
442 Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
443 return Err(Error::internal("a total comparison reached the ordered path"));
444 }
445 };
446 Ok(Value::Boolean(held))
447}
448
449pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
460 match (left, right) {
461 (Value::Null, _) | (_, Value::Null) => {
462 Err(Error::internal("a null reached the ordering path"))
463 }
464 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
465 (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
466 (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
467 (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
468 (Value::Time(a), Value::Time(b)) | (Value::Timestamp(a), Value::Timestamp(b)) => {
469 Ok(a.cmp(b))
470 }
471 (
472 Value::Interval { months: am, days: ad, micros: au },
473 Value::Interval { months: bm, days: bd, micros: bu },
474 ) => Ok((am, ad, au).cmp(&(bm, bd, bu))),
475 _ => numeric_order(left, right),
476 }
477}
478
479fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
481 if let (Some(a), Some(b)) = (integral(left), integral(right)) {
482 return Ok(a.cmp(&b));
483 }
484 if let (
485 Value::Decimal { unscaled: a, scale: sa, .. },
486 Value::Decimal { unscaled: b, scale: sb, .. },
487 ) = (left, right)
488 {
489 if sa == sb {
490 return Ok(a.cmp(b));
491 }
492 }
493 match (approximate(left), approximate(right)) {
494 (Some(a), Some(b)) => Ok(float_order(a, b)),
495 _ => Err(Error::not_implemented(format!(
496 "comparing {} with {}",
497 left.logical_type(),
498 right.logical_type()
499 ))),
500 }
501}
502
503fn float_order(left: f64, right: f64) -> Ordering {
505 if left == right {
506 return Ordering::Equal;
507 }
508 match (left.is_nan(), right.is_nan()) {
509 (true, true) => Ordering::Equal,
510 (true, false) => Ordering::Greater,
511 (false, true) => Ordering::Less,
512 (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
513 }
514}
515
516pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
525 match (left.is_null(), right.is_null()) {
526 (true, true) => Ok(Ordering::Equal),
527 (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
528 (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
529 (false, false) => order(left, right),
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use super::*;
536
537 fn compared(op: Comparison, left: Value, right: Value) -> Value {
538 compare_values(op, &left, &right).expect("these types compare")
539 }
540
541 const EVERY: [Comparison; 8] = [
543 Comparison::Equal,
544 Comparison::NotEqual,
545 Comparison::Less,
546 Comparison::LessOrEqual,
547 Comparison::Greater,
548 Comparison::GreaterOrEqual,
549 Comparison::DistinctFrom,
550 Comparison::NotDistinctFrom,
551 ];
552
553 fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
559 let values: Vec<Value> = (0..left.len())
560 .map(|index| {
561 compare_values(op, &left.value_at(index), &right.value_at(index))
562 .expect("the oracle is only asked about types that compare")
563 })
564 .collect();
565 Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
566 }
567
568 fn agrees(op: Comparison, left: &Vector, right: &Vector) {
572 let fast = compare(op, left, right).expect("compares");
573 let slow = oracle(op, left, right);
574 assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
575 }
576
577 struct Rng(u64);
580
581 impl Rng {
582 fn next(&mut self) -> u64 {
583 self.0 ^= self.0 << 13;
584 self.0 ^= self.0 >> 7;
585 self.0 ^= self.0 << 17;
586 self.0
587 }
588
589 fn below(&mut self, bound: u64) -> u64 {
590 self.next() % bound
591 }
592 }
593
594 #[test]
595 fn an_ordinary_comparison_is_null_when_either_side_is() {
596 assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
597 assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
598 }
599
600 #[test]
601 fn a_total_comparison_is_never_null() {
602 assert_eq!(
603 compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
604 Value::Boolean(true)
605 );
606 assert_eq!(
607 compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
608 Value::Boolean(false)
609 );
610 assert_eq!(
611 compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
612 Value::Boolean(true)
613 );
614 }
615
616 #[test]
617 fn a_string_compares_by_bytes() {
618 assert_eq!(
619 compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
620 Value::Boolean(true)
621 );
622 assert_eq!(
623 compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
624 Value::Boolean(true)
625 );
626 }
627
628 #[test]
631 fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
632 assert_eq!(
633 compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
634 Value::Boolean(true)
635 );
636 assert_eq!(
637 compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
638 Value::Boolean(true)
639 );
640 }
641
642 #[test]
643 fn zero_has_one_value_however_it_is_signed() {
644 assert_eq!(
645 compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
646 Value::Boolean(true)
647 );
648 }
649
650 #[test]
651 fn a_number_compares_the_same_however_it_is_stored() {
652 assert_eq!(
653 compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
654 Value::Boolean(true)
655 );
656 assert_eq!(
657 compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
658 Value::Boolean(true)
659 );
660 }
661
662 #[test]
663 fn nulls_go_where_the_query_asked_for_them() {
664 assert_eq!(
665 order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
666 Ordering::Less
667 );
668 assert_eq!(
669 order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
670 Ordering::Greater
671 );
672 }
673
674 #[test]
675 fn two_constant_vectors_cost_one_comparison() {
676 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
677 let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
678 let result = compare(Comparison::Less, &left, &right).expect("compares");
679 assert_eq!(result.form(), Form::Constant);
680 assert_eq!(result.value_at(500), Value::Boolean(true));
681 }
682
683 #[test]
684 fn a_comparison_of_two_vectors_is_one_answer_per_row() {
685 let left = Vector::from_values(
686 LogicalType::Integer,
687 &[Value::Integer(1), Value::Integer(5), Value::Null],
688 )
689 .expect("three rows");
690 let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
691 let result = compare(Comparison::Greater, &left, &right).expect("compares");
692 assert_eq!(result.value_at(0), Value::Boolean(false));
693 assert_eq!(result.value_at(1), Value::Boolean(true));
694 assert_eq!(result.value_at(2), Value::Null);
695 }
696
697 #[test]
698 fn two_vectors_of_different_lengths_are_caught() {
699 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
700 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
701 let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
702 assert!(error.message().contains("4 row vector"), "{error}");
703 }
704
705 #[test]
706 fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
707 for op in EVERY {
708 let left = Value::Integer(3);
709 let right = Value::Integer(7);
710 assert_eq!(
711 compare_values(op, &left, &right).expect("compares"),
712 compare_values(op.swapped(), &right, &left).expect("compares"),
713 "{op:?}"
714 );
715 }
716 }
717
718 #[test]
721 fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
722 let mut rng = Rng(0x5eed_1234_9876_4321);
723 let types: [LogicalType; 10] = [
724 LogicalType::Boolean,
725 LogicalType::TinyInt,
726 LogicalType::SmallInt,
727 LogicalType::Integer,
728 LogicalType::BigInt,
729 LogicalType::HugeInt,
730 LogicalType::UInteger,
731 LogicalType::Float,
732 LogicalType::Double,
733 LogicalType::Varchar,
734 ];
735 for ty in &types {
736 for nulls in [0u64, 1, 3] {
737 let len = 37;
738 let make = |rng: &mut Rng| {
739 let values: Vec<Value> = (0..len)
740 .map(|_| {
741 if nulls > 0 && rng.below(nulls + 1) == 0 {
742 Value::Null
743 } else {
744 sample(ty, rng)
745 }
746 })
747 .collect();
748 Vector::from_values(ty.clone(), &values).expect("a flat vector")
749 };
750 let left = make(&mut rng);
751 let right = make(&mut rng);
752 let literal = sample(ty, &mut rng);
753 let constant = Vector::constant(ty.clone(), literal, len);
754 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
755 let codes: Vec<u32> =
756 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
757 let dictionary =
758 Vector::dictionary(codes, left.clone()).expect("codes are in range");
759
760 for op in EVERY {
761 agrees(op, &left, &right);
762 agrees(op, &left, &constant);
763 agrees(op, &constant, &left);
764 agrees(op, &left, &null_constant);
765 agrees(op, &null_constant, &left);
766 agrees(op, &dictionary, &constant);
767 agrees(op, &constant, &dictionary);
768 }
769 }
770 }
771 }
772
773 fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
775 match ty {
776 LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
777 LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
778 LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
779 LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
780 LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
781 LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
782 LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
783 LogicalType::Float => Value::Float(match rng.below(5) {
786 0 => f32::NAN,
787 1 => -0.0,
788 other => other as f32 - 2.0,
789 }),
790 LogicalType::Double => Value::Double(match rng.below(5) {
791 0 => f64::NAN,
792 1 => -0.0,
793 other => other as f64 - 2.0,
794 }),
795 LogicalType::Varchar => Value::Varchar(
798 match rng.below(6) {
799 0 => "",
800 1 => "ab",
801 2 => "abc",
802 3 => "abcdefghijkl",
803 4 => "abcdefghijklm",
804 _ => "abcdefghijklmnopqrstuvwxyz",
805 }
806 .to_owned(),
807 ),
808 other => panic!("the generator has no values for {other}"),
809 }
810 }
811
812 #[test]
816 fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
817 let words =
818 ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
819 let mut column = StringColumn::new();
820 for word in words {
821 column.push(word);
822 }
823 for (i, one) in words.iter().enumerate() {
824 for (j, other) in words.iter().enumerate() {
825 assert_eq!(
826 string_order(&column, i, &column, j),
827 one.as_bytes().cmp(other.as_bytes()),
828 "{one:?} against {other:?}"
829 );
830 }
831 }
832 }
833
834 #[test]
837 fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
838 let values = Vector::from_values(
839 LogicalType::Integer,
840 &[Value::Integer(1), Value::Null, Value::Integer(9)],
841 )
842 .expect("three values");
843 let dictionary =
844 Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
845 let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
846 let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
847 assert_eq!(result.value_at(0), Value::Boolean(true));
848 assert_eq!(result.value_at(1), Value::Null);
849 assert_eq!(result.value_at(2), Value::Boolean(false));
850 assert_eq!(result.value_at(3), Value::Null);
851 assert_eq!(result.value_at(4), Value::Boolean(true));
852 }
853
854 #[test]
857 fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
858 let _turn = fallback::TURN.lock().expect("no test panics while holding this");
861 let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
862 let sequence = Vector::sequence(10, 1, 4);
863 let flat = Vector::from_values(
864 LogicalType::BigInt,
865 &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
866 )
867 .expect("four rows");
868 let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
869 assert_eq!(result.value_at(0), Value::Boolean(false));
870 assert_eq!(result.value_at(1), Value::Boolean(false));
871 assert_eq!(result.value_at(2), Value::Boolean(false));
872 assert_eq!(result.value_at(3), Value::Null);
873 assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
874 }
875
876 #[test]
886 fn a_second_level_of_codes_does_not_turn_the_loops_off() {
887 let _turn = fallback::TURN.lock().expect("no test panics while holding this");
888 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
889 let values = Vector::from_values(
890 LogicalType::Integer,
891 &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
892 )
893 .expect("three rows");
894 let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
895 let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
896 let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
897 let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
898 assert_eq!(result.value_at(0), Value::Boolean(true));
899 assert_eq!(result.value_at(1), Value::Boolean(false));
900 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
901 }
902
903 #[test]
907 fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
908 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
909 let flat = Vector::from_values(
910 LogicalType::Integer,
911 &[
912 Value::Integer(1),
913 Value::Integer(2),
914 Value::Integer(3),
915 Value::Integer(4),
916 Value::Integer(5),
917 Value::Integer(6),
918 ],
919 )
920 .expect("six rows");
921 agrees(Comparison::Less, &nulls, &flat);
922 agrees(Comparison::Equal, &flat, &nulls);
923 assert_eq!(
924 compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
925 &Validity::AllInvalid
926 );
927 }
928
929 #[test]
932 fn an_empty_comparison_is_an_empty_answer() {
933 let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
934 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
935 let result = compare(Comparison::Equal, &left, &right).expect("compares");
936 assert_eq!(result.len(), 0);
937 }
938}