1use std::borrow::Cow;
72use std::cmp::Ordering;
73
74use rudb_common::{Error, LogicalType, Result, Value, interval_micros};
75use rudb_vector::{
76 Coded, Data, Form, Packed, Selection, StringColumn, StringView, Validity, Vector,
77};
78
79use crate::fallback::{self, Kernel};
80use crate::logic::is_true;
81use crate::number::{approximate, integral};
82use crate::prepare::Held;
83use crate::shape::{first, identity, nulls_of, single};
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
87pub enum Comparison {
88 Equal,
90 NotEqual,
92 Less,
94 LessOrEqual,
96 Greater,
98 GreaterOrEqual,
100 DistinctFrom,
102 NotDistinctFrom,
104}
105
106impl Comparison {
107 #[must_use]
109 pub fn is_total(self) -> bool {
110 matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
111 }
112
113 #[must_use]
120 pub fn swapped(self) -> Self {
121 match self {
122 Self::Less => Self::Greater,
123 Self::LessOrEqual => Self::GreaterOrEqual,
124 Self::Greater => Self::Less,
125 Self::GreaterOrEqual => Self::LessOrEqual,
126 same => same,
127 }
128 }
129}
130
131pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
137 compare_prepared(op, left, right, None)
138}
139
140pub fn compare_prepared(
150 op: Comparison,
151 left: &Vector,
152 right: &Vector,
153 held: Option<&Held>,
154) -> Result<Vector> {
155 if left.len() != right.len() {
156 return Err(Error::internal(format!(
157 "a comparison of a {} row vector with a {} row one",
158 left.len(),
159 right.len()
160 )));
161 }
162 let len = left.len();
163 if left.form() == Form::Constant && right.form() == Form::Constant && len > 0 {
164 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
165 return Ok(Vector::constant(LogicalType::Boolean, single, len));
166 }
167
168 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
169 if !op.is_total()
173 && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
174 && len > 0
175 {
176 return boolean(vec![false; len], Validity::AllInvalid, len);
177 }
178
179 if let Some(answers) =
180 specialized(op, left, right, &left_valid, &right_valid, len, identity, held)
181 {
182 let validity =
183 if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
184 return boolean(blank_the_nulls(answers, &validity), validity, len);
185 }
186
187 fallback::record(Kernel::Compare, left.form(), right.form());
188 let mut values = Vec::with_capacity(len);
189 for index in 0..len {
192 values.push(compare_values(op, &left.value_at(index), &right.value_at(index))?);
193 }
194 Vector::from_values(LogicalType::Boolean, &values)
195}
196
197pub fn refine(
215 op: Comparison,
216 left: &Vector,
217 right: &Vector,
218 kept: &Selection,
219) -> Result<Selection> {
220 refine_prepared(op, left, right, kept, None)
221}
222
223pub fn refine_prepared(
233 op: Comparison,
234 left: &Vector,
235 right: &Vector,
236 kept: &Selection,
237 held: Option<&Held>,
238) -> Result<Selection> {
239 if left.len() != right.len() {
240 return Err(Error::internal(format!(
241 "a comparison of a {} row vector with a {} row one",
242 left.len(),
243 right.len()
244 )));
245 }
246 let len = left.len();
247 if kept.indices().iter().any(|&row| row as usize >= len) {
251 return Err(Error::internal(format!("a selection past the end of a {len} row vector")));
252 }
253 if kept.is_empty() {
254 return Ok(Selection::empty());
255 }
256 if left.form() == Form::Constant && right.form() == Form::Constant {
257 let single = compare_values(op, &left.value_at(0), &right.value_at(0))?;
258 return Ok(if is_true(&single) { kept.clone() } else { Selection::empty() });
259 }
260
261 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
262 if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
263 {
264 return Ok(Selection::empty());
265 }
266
267 let rows = kept.indices();
268 let map = |slot: usize| rows[slot] as usize;
269 if let Some(answers) =
270 specialized(op, left, right, &left_valid, &right_valid, kept.len(), map, held)
271 {
272 if op.is_total() || (left_valid == Validity::AllValid && right_valid == Validity::AllValid)
275 {
276 return Ok(narrowed(&answers, rows, |_| true));
277 }
278 return Ok(narrowed(&answers, rows, |slot| {
282 let row = rows[slot] as usize;
283 left_valid.is_valid(row) && right_valid.is_valid(row)
284 }));
285 }
286
287 fallback::record(Kernel::Compare, left.form(), right.form());
288 let mut out = Vec::with_capacity(kept.len());
289 for &row in rows {
292 let index = row as usize;
293 if is_true(&compare_values(op, &left.value_at(index), &right.value_at(index))?) {
294 out.push(row);
295 }
296 }
297 Ok(Selection::from_indices(out))
298}
299
300fn narrowed<L: Fn(usize) -> bool>(answers: &[bool], rows: &[u32], live: L) -> Selection {
307 let mut out = vec![0_u32; answers.len()];
308 let mut count = 0;
309 for (slot, &answer) in answers.iter().enumerate() {
310 out[count] = rows[slot];
311 count += usize::from(answer & live(slot));
313 }
314 out.truncate(count);
315 Selection::from_indices(out)
316}
317
318fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
320 let validity = if len == 0 { Validity::AllValid } else { validity.normalize(len) };
324 Ok(Vector::flat(LogicalType::Boolean, Data::Bool(answers.into()))?.with_validity(validity))
325}
326
327fn blank_the_nulls(mut answers: Vec<bool>, validity: &Validity) -> Vec<bool> {
335 if let Validity::Mask(mask) = validity {
336 for (index, answer) in answers.iter_mut().enumerate() {
337 if !mask.get(index) {
338 *answer = false;
339 }
340 }
341 }
342 answers
343}
344
345#[expect(
357 clippy::too_many_arguments,
358 reason = "two sides, two validities, the operator, the length, the index mapping and the \
359 literal that was built early, all of which the branches below need"
360)]
361fn specialized<M>(
362 op: Comparison,
363 left: &Vector,
364 right: &Vector,
365 left_valid: &Validity,
366 right_valid: &Validity,
367 len: usize,
368 map: M,
369 held: Option<&Held>,
370) -> Option<Vec<bool>>
371where
372 M: Fn(usize) -> usize + Copy,
373{
374 if left.logical_type() != right.logical_type() {
378 return None;
379 }
380
381 if let (Some(one), Some(other)) = (left.data(), right.data()) {
382 return dispatch(op, len, one, map, other, map, left_valid, right_valid, map);
383 }
384 if !op.is_total() {
390 if let (Some(packed), Some(value)) = (left.packed_parts(), right.constant_value()) {
391 let wanted = exact(held, left.logical_type(), value)?;
392 return Some(packed_against(op, &packed, wanted, len, map));
393 }
394 if let (Some(value), Some(packed)) = (left.constant_value(), right.packed_parts()) {
395 let wanted = exact(held, right.logical_type(), value)?;
396 return Some(packed_against(op.swapped(), &packed, wanted, len, map));
397 }
398 }
399 if let (Some(one), Some(value)) = (left.data(), right.constant_value()) {
400 let column = readied(held, left.logical_type(), value)?;
401 let other = column.data()?;
402 return dispatch(op, len, one, map, other, first, left_valid, right_valid, map);
403 }
404 if let (Some(value), Some(other)) = (left.constant_value(), right.data()) {
405 let column = readied(held, right.logical_type(), value)?;
407 let one = column.data()?;
408 return dispatch(op.swapped(), len, other, map, one, first, right_valid, left_valid, map);
409 }
410 if matches!(op, Comparison::Equal | Comparison::NotEqual) {
415 if let (Some(coded), Some(value)) = (left.coded_parts(), right.constant_value()) {
416 let wanted = encoded(&coded, held, left.logical_type(), value)?;
417 return Some(coded_against(op, &coded, &wanted, len, map));
418 }
419 if let (Some(value), Some(coded)) = (left.constant_value(), right.coded_parts()) {
420 let wanted = encoded(&coded, held, right.logical_type(), value)?;
421 return Some(coded_against(op, &coded, &wanted, len, map));
422 }
423 }
424 if let (Some((one, one_arena)), Some((other, other_arena))) =
430 (left.text_parts(), right.text_parts())
431 {
432 return Some(sweep(
433 op,
434 len,
435 |index| view_order(one.get(map(index)), one_arena, other.get(map(index)), other_arena),
436 left_valid,
437 right_valid,
438 map,
439 ));
440 }
441 if let (Some((one, one_arena)), Some(value)) = (left.text_parts(), right.constant_value()) {
445 let column = readied(held, left.logical_type(), value)?;
446 let (other, other_arena) = column.text_parts()?;
447 let wanted = other.first();
448 return Some(sweep(
449 op,
450 len,
451 |index| view_order(one.get(map(index)), one_arena, wanted, other_arena),
452 left_valid,
453 right_valid,
454 map,
455 ));
456 }
457 if let (Some(value), Some((other, other_arena))) = (left.constant_value(), right.text_parts()) {
458 let column = readied(held, right.logical_type(), value)?;
460 let (one, one_arena) = column.text_parts()?;
461 let wanted = one.first();
462 return Some(sweep(
463 op.swapped(),
464 len,
465 |index| view_order(other.get(map(index)), other_arena, wanted, one_arena),
466 right_valid,
467 left_valid,
468 map,
469 ));
470 }
471 if let (Some((codes, values)), Some(value)) = (left.positions(), right.constant_value()) {
472 let one = values.data()?;
473 let column = readied(held, left.logical_type(), value)?;
474 let other = column.data()?;
475 let at = |index: usize| codes[map(index)] as usize;
476 return dispatch(op, len, one, at, other, first, left_valid, right_valid, map);
477 }
478 if let (Some(value), Some((codes, values))) = (left.constant_value(), right.positions()) {
479 let other = values.data()?;
480 let column = readied(held, right.logical_type(), value)?;
481 let one = column.data()?;
482 let at = |index: usize| codes[map(index)] as usize;
483 return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid, map);
484 }
485 if let (Some((codes, values)), Some(other)) = (left.positions(), right.data()) {
491 let one = values.data()?;
492 let at = |index: usize| codes[map(index)] as usize;
493 return dispatch(op, len, one, at, other, map, left_valid, right_valid, map);
494 }
495 if let (Some(one), Some((codes, values))) = (left.data(), right.positions()) {
496 let other = values.data()?;
497 let at = |index: usize| codes[map(index)] as usize;
498 return dispatch(op.swapped(), len, other, at, one, map, right_valid, left_valid, map);
499 }
500 None
501}
502
503fn exact(held: Option<&Held>, ty: &LogicalType, value: &Value) -> Option<i128> {
510 let column = readied(held, ty, value)?;
511 let data = column.data()?;
512 data.signed_at(0).or_else(|| data.unsigned_at(0).and_then(|value| i128::try_from(value).ok()))
513}
514
515fn encoded(
521 coded: &Coded<'_>,
522 held: Option<&Held>,
523 ty: &LogicalType,
524 value: &Value,
525) -> Option<Vec<u8>> {
526 let column = readied(held, ty, value)?;
527 let (views, arena) = column.text_parts()?;
528 Some(coded.encode(views.first()?.bytes_in(arena)?))
529}
530
531fn coded_against<M>(
537 op: Comparison,
538 coded: &Coded<'_>,
539 wanted: &[u8],
540 len: usize,
541 map: M,
542) -> Vec<bool>
543where
544 M: Fn(usize) -> usize + Copy,
545{
546 let same = op == Comparison::Equal;
547 let mut answers = Vec::with_capacity(len);
548 for row in 0..len {
549 answers.push((coded.row(map(row)) == Some(wanted)) == same);
550 }
551 answers
552}
553
554fn packed_against<M>(
560 op: Comparison,
561 packed: &Packed<'_>,
562 wanted: i128,
563 len: usize,
564 map: M,
565) -> Vec<bool>
566where
567 M: Fn(usize) -> usize + Copy,
568{
569 let Some(code) = packed.code_of(wanted) else {
570 let above = wanted > packed.ceiling();
573 let same = match op {
574 Comparison::Equal | Comparison::NotDistinctFrom => false,
575 Comparison::NotEqual | Comparison::DistinctFrom => true,
576 Comparison::Less | Comparison::LessOrEqual => above,
577 Comparison::Greater | Comparison::GreaterOrEqual => !above,
578 };
579 return vec![same; len];
580 };
581 let test: fn(u64, u64) -> bool = match op {
584 Comparison::Equal | Comparison::NotDistinctFrom => |found, want| found == want,
585 Comparison::NotEqual | Comparison::DistinctFrom => |found, want| found != want,
586 Comparison::Less => |found, want| found < want,
587 Comparison::LessOrEqual => |found, want| found <= want,
588 Comparison::Greater => |found, want| found > want,
589 Comparison::GreaterOrEqual => |found, want| found >= want,
590 };
591 let mut answers = Vec::with_capacity(len);
592 for row in 0..len {
593 answers.push(test(packed.code(map(row)), code));
594 }
595 answers
596}
597
598#[expect(
604 clippy::too_many_arguments,
605 reason = "two sides with an index each, the operator, the length and two validities, all of \
606 which the loop needs and none of which is worth a struct that exists for one call"
607)]
608fn dispatch<L, R, V>(
609 op: Comparison,
610 len: usize,
611 left: &Data,
612 at_left: L,
613 right: &Data,
614 at_right: R,
615 left_valid: &Validity,
616 right_valid: &Validity,
617 at_valid: V,
618) -> Option<Vec<bool>>
619where
620 L: Fn(usize) -> usize,
621 R: Fn(usize) -> usize,
622 V: Fn(usize) -> usize,
623{
624 macro_rules! layouts {
625 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
626 match (left, right) {
627 $(
628 (Data::$variant(one), Data::$variant(other)) => Some(sweep(
629 op,
630 len,
631 |index| one[at_left(index)].cmp(&other[at_right(index)]),
632 left_valid,
633 right_valid,
634 &at_valid,
635 )),
636 )+
637 (Data::Float32(one), Data::Float32(other)) => Some(sweep(
640 op,
641 len,
642 |index| {
643 float_order(
644 f64::from(one[at_left(index)]),
645 f64::from(other[at_right(index)]),
646 )
647 },
648 left_valid,
649 right_valid,
650 &at_valid,
651 )),
652 (Data::Float64(one), Data::Float64(other)) => Some(sweep(
653 op,
654 len,
655 |index| float_order(one[at_left(index)], other[at_right(index)]),
656 left_valid,
657 right_valid,
658 &at_valid,
659 )),
660 (Data::Interval(one), Data::Interval(other)) => Some(sweep(
663 op,
664 len,
665 |index| {
666 let (months, days, micros) = one[at_left(index)];
667 let (bm, bd, bu) = other[at_right(index)];
668 interval_micros(months, days, micros).cmp(&interval_micros(bm, bd, bu))
669 },
670 left_valid,
671 right_valid,
672 &at_valid,
673 )),
674 (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
675 op,
676 len,
677 |index| string_order(one, at_left(index), other, at_right(index)),
678 left_valid,
679 right_valid,
680 &at_valid,
681 )),
682 _ => None,
683 }
684 };
685 }
686 rudb_vector::for_each_layout!(ordered, layouts)
687}
688
689fn readied<'a>(held: Option<&'a Held>, ty: &LogicalType, value: &Value) -> Option<Cow<'a, Vector>> {
695 match held {
696 Some(held) if held.matches(ty, value) => Some(Cow::Borrowed(held.single())),
697 _ => Some(Cow::Owned(single(ty, value)?)),
698 }
699}
700
701fn string_order(
709 left: &StringColumn,
710 at_left: usize,
711 right: &StringColumn,
712 at_right: usize,
713) -> Ordering {
714 view_order(left.views().get(at_left), left.arena(), right.views().get(at_right), right.arena())
715}
716
717fn view_order(
723 one: Option<&StringView>,
724 one_arena: &[u8],
725 other: Option<&StringView>,
726 other_arena: &[u8],
727) -> Ordering {
728 let (Some(one), Some(other)) = (one, other) else {
729 return Ordering::Equal;
730 };
731 let (prefix, against) = (one.prefix(), other.prefix());
732 if prefix != against {
733 return prefix.cmp(&against);
734 }
735 let bytes = one.bytes_in(one_arena).unwrap_or_default();
740 let against_bytes = other.bytes_in(other_arena).unwrap_or_default();
741 bytes.cmp(against_bytes)
742}
743
744fn sweep<O, V>(
750 op: Comparison,
751 len: usize,
752 order_at: O,
753 left_valid: &Validity,
754 right_valid: &Validity,
755 at_valid: V,
756) -> Vec<bool>
757where
758 O: Fn(usize) -> Ordering,
759 V: Fn(usize) -> usize,
760{
761 let mut answers = vec![false; len];
762 match op {
763 Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
764 Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
765 Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
766 Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
767 Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
768 Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
769 Comparison::DistinctFrom => {
770 total(&mut answers, order_at, left_valid, right_valid, at_valid);
771 for answer in &mut answers {
772 *answer = !*answer;
773 }
774 }
775 Comparison::NotDistinctFrom => {
776 total(&mut answers, order_at, left_valid, right_valid, at_valid);
777 }
778 }
779 answers
780}
781
782#[inline]
784fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
785where
786 O: Fn(usize) -> Ordering,
787 H: Fn(Ordering) -> bool,
788{
789 for (index, answer) in answers.iter_mut().enumerate() {
790 *answer = held(order_at(index));
791 }
792}
793
794fn total<O, V>(
801 answers: &mut [bool],
802 order_at: O,
803 left_valid: &Validity,
804 right_valid: &Validity,
805 at_valid: V,
806) where
807 O: Fn(usize) -> Ordering,
808 V: Fn(usize) -> usize,
809{
810 if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
811 fill(answers, order_at, |o| o == Ordering::Equal);
812 return;
813 }
814 for (index, answer) in answers.iter_mut().enumerate() {
815 let row = at_valid(index);
816 *answer = match (left_valid.is_valid(row), right_valid.is_valid(row)) {
817 (true, true) => order_at(index) == Ordering::Equal,
818 (false, false) => true,
819 _ => false,
820 };
821 }
822}
823
824pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
830 if op.is_total() {
831 let same = match (left.is_null(), right.is_null()) {
832 (true, true) => true,
833 (true, false) | (false, true) => false,
834 (false, false) => order(left, right)? == Ordering::Equal,
835 };
836 return Ok(Value::Boolean(match op {
837 Comparison::NotDistinctFrom => same,
838 _ => !same,
839 }));
840 }
841 if left.is_null() || right.is_null() {
842 return Ok(Value::Null);
843 }
844 let ordering = order(left, right)?;
845 let held = match op {
846 Comparison::Equal => ordering == Ordering::Equal,
847 Comparison::NotEqual => ordering != Ordering::Equal,
848 Comparison::Less => ordering == Ordering::Less,
849 Comparison::LessOrEqual => ordering != Ordering::Greater,
850 Comparison::Greater => ordering == Ordering::Greater,
851 Comparison::GreaterOrEqual => ordering != Ordering::Less,
852 Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
853 return Err(Error::internal("a total comparison reached the ordered path"));
854 }
855 };
856 Ok(Value::Boolean(held))
857}
858
859pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
870 match (left, right) {
871 (Value::Null, _) | (_, Value::Null) => {
872 Err(Error::internal("a null reached the ordering path"))
873 }
874 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
875 (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
876 (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
877 (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
878 (Value::Time(a), Value::Time(b)) | (Value::Timestamp(a), Value::Timestamp(b)) => {
879 Ok(a.cmp(b))
880 }
881 (
882 Value::Interval { months: am, days: ad, micros: au },
883 Value::Interval { months: bm, days: bd, micros: bu },
884 ) => Ok(interval_micros(*am, *ad, *au).cmp(&interval_micros(*bm, *bd, *bu))),
885 _ => numeric_order(left, right),
886 }
887}
888
889fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
891 if let (Some(a), Some(b)) = (integral(left), integral(right)) {
892 return Ok(a.cmp(&b));
893 }
894 if let (
895 Value::Decimal { unscaled: a, scale: sa, .. },
896 Value::Decimal { unscaled: b, scale: sb, .. },
897 ) = (left, right)
898 {
899 if sa == sb {
900 return Ok(a.cmp(b));
901 }
902 }
903 match (approximate(left), approximate(right)) {
904 (Some(a), Some(b)) => Ok(float_order(a, b)),
905 _ => Err(Error::not_implemented(format!(
906 "comparing {} with {}",
907 left.logical_type(),
908 right.logical_type()
909 ))),
910 }
911}
912
913fn float_order(left: f64, right: f64) -> Ordering {
915 if left == right {
916 return Ordering::Equal;
917 }
918 match (left.is_nan(), right.is_nan()) {
919 (true, true) => Ordering::Equal,
920 (true, false) => Ordering::Greater,
921 (false, true) => Ordering::Less,
922 (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
923 }
924}
925
926pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
935 match (left.is_null(), right.is_null()) {
936 (true, true) => Ok(Ordering::Equal),
937 (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
938 (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
939 (false, false) => order(left, right),
940 }
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946
947 fn compared(op: Comparison, left: Value, right: Value) -> Value {
948 compare_values(op, &left, &right).expect("these types compare")
949 }
950
951 const EVERY: [Comparison; 8] = [
953 Comparison::Equal,
954 Comparison::NotEqual,
955 Comparison::Less,
956 Comparison::LessOrEqual,
957 Comparison::Greater,
958 Comparison::GreaterOrEqual,
959 Comparison::DistinctFrom,
960 Comparison::NotDistinctFrom,
961 ];
962
963 fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
969 let values: Vec<Value> = (0..left.len())
970 .map(|index| {
971 compare_values(op, &left.value_at(index), &right.value_at(index))
972 .expect("the oracle is only asked about types that compare")
973 })
974 .collect();
975 Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
976 }
977
978 fn agrees(op: Comparison, left: &Vector, right: &Vector) {
982 let fast = compare(op, left, right).expect("compares");
983 let slow = oracle(op, left, right);
984 assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
985 }
986
987 struct Rng(u64);
990
991 impl Rng {
992 fn next(&mut self) -> u64 {
993 self.0 ^= self.0 << 13;
994 self.0 ^= self.0 >> 7;
995 self.0 ^= self.0 << 17;
996 self.0
997 }
998
999 fn below(&mut self, bound: u64) -> u64 {
1000 self.next() % bound
1001 }
1002 }
1003
1004 #[test]
1005 fn an_ordinary_comparison_is_null_when_either_side_is() {
1006 assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
1007 assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
1008 }
1009
1010 #[test]
1011 fn a_total_comparison_is_never_null() {
1012 assert_eq!(
1013 compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
1014 Value::Boolean(true)
1015 );
1016 assert_eq!(
1017 compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
1018 Value::Boolean(false)
1019 );
1020 assert_eq!(
1021 compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
1022 Value::Boolean(true)
1023 );
1024 }
1025
1026 #[test]
1027 fn a_string_compares_by_bytes() {
1028 assert_eq!(
1029 compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
1030 Value::Boolean(true)
1031 );
1032 assert_eq!(
1033 compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
1034 Value::Boolean(true)
1035 );
1036 }
1037
1038 #[test]
1041 fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
1042 assert_eq!(
1043 compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
1044 Value::Boolean(true)
1045 );
1046 assert_eq!(
1047 compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
1048 Value::Boolean(true)
1049 );
1050 }
1051
1052 #[test]
1053 fn zero_has_one_value_however_it_is_signed() {
1054 assert_eq!(
1055 compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
1056 Value::Boolean(true)
1057 );
1058 }
1059
1060 #[test]
1065 fn two_intervals_of_the_same_length_are_one_value() {
1066 let day = Value::Interval { months: 0, days: 1, micros: 0 };
1067 let hours = Value::Interval { months: 0, days: 0, micros: 86_400_000_000 };
1068 let month = Value::Interval { months: 1, days: 0, micros: 0 };
1069 let thirty = Value::Interval { months: 0, days: 30, micros: 0 };
1070 let long_day = Value::Interval { months: 0, days: 0, micros: 90_000_000_000 };
1071 assert_eq!(compared(Comparison::Equal, day.clone(), hours), Value::Boolean(true));
1072 assert_eq!(compared(Comparison::Equal, month, thirty), Value::Boolean(true));
1073 assert_eq!(compared(Comparison::Greater, long_day, day), Value::Boolean(true));
1074 }
1075
1076 #[test]
1077 fn a_number_compares_the_same_however_it_is_stored() {
1078 assert_eq!(
1079 compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
1080 Value::Boolean(true)
1081 );
1082 assert_eq!(
1083 compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
1084 Value::Boolean(true)
1085 );
1086 }
1087
1088 #[test]
1089 fn nulls_go_where_the_query_asked_for_them() {
1090 assert_eq!(
1091 order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
1092 Ordering::Less
1093 );
1094 assert_eq!(
1095 order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
1096 Ordering::Greater
1097 );
1098 }
1099
1100 #[test]
1101 fn two_constant_vectors_cost_one_comparison() {
1102 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
1103 let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
1104 let result = compare(Comparison::Less, &left, &right).expect("compares");
1105 assert_eq!(result.form(), Form::Constant);
1106 assert_eq!(result.value_at(500), Value::Boolean(true));
1107 }
1108
1109 #[test]
1110 fn a_comparison_of_two_vectors_is_one_answer_per_row() {
1111 let left = Vector::from_values(
1112 LogicalType::Integer,
1113 &[Value::Integer(1), Value::Integer(5), Value::Null],
1114 )
1115 .expect("three rows");
1116 let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
1117 let result = compare(Comparison::Greater, &left, &right).expect("compares");
1118 assert_eq!(result.value_at(0), Value::Boolean(false));
1119 assert_eq!(result.value_at(1), Value::Boolean(true));
1120 assert_eq!(result.value_at(2), Value::Null);
1121 }
1122
1123 #[test]
1124 fn two_vectors_of_different_lengths_are_caught() {
1125 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1126 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
1127 let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
1128 assert!(error.message().contains("4 row vector"), "{error}");
1129 }
1130
1131 #[test]
1132 fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
1133 for op in EVERY {
1134 let left = Value::Integer(3);
1135 let right = Value::Integer(7);
1136 assert_eq!(
1137 compare_values(op, &left, &right).expect("compares"),
1138 compare_values(op.swapped(), &right, &left).expect("compares"),
1139 "{op:?}"
1140 );
1141 }
1142 }
1143
1144 #[test]
1147 fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
1148 let mut rng = Rng(0x5eed_1234_9876_4321);
1149 let types: [LogicalType; 11] = [
1150 LogicalType::Boolean,
1151 LogicalType::TinyInt,
1152 LogicalType::SmallInt,
1153 LogicalType::Integer,
1154 LogicalType::BigInt,
1155 LogicalType::HugeInt,
1156 LogicalType::UInteger,
1157 LogicalType::Float,
1158 LogicalType::Double,
1159 LogicalType::Varchar,
1160 LogicalType::Interval,
1161 ];
1162 for ty in &types {
1163 for nulls in [0u64, 1, 3] {
1164 let len = 37;
1165 let make = |rng: &mut Rng| {
1166 let values: Vec<Value> = (0..len)
1167 .map(|_| {
1168 if nulls > 0 && rng.below(nulls + 1) == 0 {
1169 Value::Null
1170 } else {
1171 sample(ty, rng)
1172 }
1173 })
1174 .collect();
1175 Vector::from_values(ty.clone(), &values).expect("a flat vector")
1176 };
1177 let left = make(&mut rng);
1178 let right = make(&mut rng);
1179 let literal = sample(ty, &mut rng);
1180 let constant = Vector::constant(ty.clone(), literal, len);
1181 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1182 let codes: Vec<u32> =
1183 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1184 let dictionary =
1185 Vector::dictionary(codes, left.clone()).expect("codes are in range");
1186 let ends: Vec<u32> = (1..=left.len())
1189 .map(|run| ((run * len) / left.len()).max(run) as u32)
1190 .collect();
1191 let runs = Vector::runs(ends, left.clone()).expect("one value for each run");
1192
1193 for op in EVERY {
1194 agrees(op, &left, &right);
1195 agrees(op, &left, &constant);
1196 agrees(op, &constant, &left);
1197 agrees(op, &left, &null_constant);
1198 agrees(op, &null_constant, &left);
1199 agrees(op, &dictionary, &constant);
1200 agrees(op, &constant, &dictionary);
1201 agrees(op, &dictionary, &right);
1205 agrees(op, &right, &dictionary);
1206 agrees(op, &runs, &constant);
1210 agrees(op, &constant, &runs);
1211 agrees(op, &runs, &right);
1212 agrees(op, &right, &runs);
1213 }
1214 }
1215 }
1216 }
1217
1218 fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
1220 let mut out = Vec::new();
1221 for &row in kept.indices() {
1222 let index = row as usize;
1223 let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
1224 .expect("the oracle is only asked about types that compare");
1225 if is_true(&answer) {
1226 out.push(row);
1227 }
1228 }
1229 Selection::from_indices(out)
1230 }
1231
1232 fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
1233 let fast = refine(op, left, right, kept).expect("compares");
1234 assert_eq!(
1235 fast,
1236 refined(op, left, right, kept),
1237 "{op:?} on a {:?} against a {:?} over {} rows",
1238 left.form(),
1239 right.form(),
1240 kept.len()
1241 );
1242 }
1243
1244 #[test]
1248 fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
1249 let mut rng = Rng(0x5eed_4321_1234_9876);
1250 let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
1251 for ty in &types {
1252 for nulls in [0u64, 1, 3] {
1253 let len = 37;
1254 let make = |rng: &mut Rng| {
1255 let values: Vec<Value> = (0..len)
1256 .map(|_| {
1257 if nulls > 0 && rng.below(nulls + 1) == 0 {
1258 Value::Null
1259 } else {
1260 sample(ty, rng)
1261 }
1262 })
1263 .collect();
1264 Vector::from_values(ty.clone(), &values).expect("a flat vector")
1265 };
1266 let left = make(&mut rng);
1267 let right = make(&mut rng);
1268 let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
1269 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1270 let codes: Vec<u32> =
1271 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1272 let dictionary =
1273 Vector::dictionary(codes, left.clone()).expect("codes are in range");
1274
1275 let selections = [
1279 Selection::identity(len),
1280 Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
1281 Selection::from_indices(vec![2, 5, 6, 17, 36]),
1282 Selection::empty(),
1283 ];
1284 for op in EVERY {
1285 for kept in &selections {
1286 threads(op, &left, &right, kept);
1287 threads(op, &left, &constant, kept);
1288 threads(op, &constant, &left, kept);
1289 threads(op, &left, &null_constant, kept);
1290 threads(op, &null_constant, &left, kept);
1291 threads(op, &constant, &null_constant, kept);
1292 threads(op, &dictionary, &constant, kept);
1293 threads(op, &constant, &dictionary, kept);
1294 threads(op, &dictionary, &right, kept);
1295 threads(op, &right, &dictionary, kept);
1296 }
1297 }
1298 }
1299 }
1300 }
1301
1302 #[test]
1306 fn a_second_conjunct_reads_only_what_the_first_one_left() {
1307 let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
1308 let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
1309 let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
1310 let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
1311
1312 let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
1313 .expect("compares");
1314 let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
1315
1316 let expected: Vec<u32> = (0..64)
1317 .filter(|row| {
1318 let value = row % 10;
1319 value > 3 && value < 7
1320 })
1321 .collect();
1322 assert_eq!(both.indices(), expected.as_slice());
1323 assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
1324 }
1325
1326 #[test]
1330 fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
1331 let column = Vector::from_values(
1332 LogicalType::Integer,
1333 &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
1334 )
1335 .expect("four rows");
1336 let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
1337 let all = Selection::identity(4);
1338 assert_eq!(
1339 refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
1340 &[0]
1341 );
1342 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
1344 assert_eq!(
1345 refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
1346 &[1, 3]
1347 );
1348 }
1349
1350 #[test]
1351 fn a_selection_past_the_end_is_caught() {
1352 let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1353 let past = Selection::from_indices(vec![0, 4]);
1354 let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
1355 assert!(error.message().contains("4 row vector"), "{error}");
1356 }
1357
1358 fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
1360 match ty {
1361 LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
1362 LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
1363 LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
1364 LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
1365 LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
1366 LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
1367 LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
1368 LogicalType::Float => Value::Float(match rng.below(5) {
1371 0 => f32::NAN,
1372 1 => -0.0,
1373 other => other as f32 - 2.0,
1374 }),
1375 LogicalType::Double => Value::Double(match rng.below(5) {
1376 0 => f64::NAN,
1377 1 => -0.0,
1378 other => other as f64 - 2.0,
1379 }),
1380 LogicalType::Interval => match rng.below(6) {
1384 0 => Value::Interval { months: 0, days: 1, micros: 0 },
1385 1 => Value::Interval { months: 0, days: 0, micros: 86_400_000_000 },
1386 2 => Value::Interval { months: 1, days: -29, micros: 86_400_000_000 },
1387 3 => Value::Interval { months: 1, days: 0, micros: 0 },
1388 4 => Value::Interval { months: 0, days: 0, micros: 90_000_000_000 },
1389 _ => Value::Interval { months: -1, days: 0, micros: 0 },
1390 },
1391 LogicalType::Varchar => Value::Varchar(
1394 match rng.below(6) {
1395 0 => "",
1396 1 => "ab",
1397 2 => "abc",
1398 3 => "abcdefghijkl",
1399 4 => "abcdefghijklm",
1400 _ => "abcdefghijklmnopqrstuvwxyz",
1401 }
1402 .to_owned(),
1403 ),
1404 other => panic!("the generator has no values for {other}"),
1405 }
1406 }
1407
1408 #[test]
1412 fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
1413 let words =
1414 ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
1415 let mut column = StringColumn::new();
1416 for word in words {
1417 column.push(word);
1418 }
1419 for (i, one) in words.iter().enumerate() {
1420 for (j, other) in words.iter().enumerate() {
1421 assert_eq!(
1422 string_order(&column, i, &column, j),
1423 one.as_bytes().cmp(other.as_bytes()),
1424 "{one:?} against {other:?}"
1425 );
1426 }
1427 }
1428 }
1429
1430 #[test]
1433 fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
1434 let values = Vector::from_values(
1435 LogicalType::Integer,
1436 &[Value::Integer(1), Value::Null, Value::Integer(9)],
1437 )
1438 .expect("three values");
1439 let dictionary =
1440 Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
1441 let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
1442 let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
1443 assert_eq!(result.value_at(0), Value::Boolean(true));
1444 assert_eq!(result.value_at(1), Value::Null);
1445 assert_eq!(result.value_at(2), Value::Boolean(false));
1446 assert_eq!(result.value_at(3), Value::Null);
1447 assert_eq!(result.value_at(4), Value::Boolean(true));
1448 }
1449
1450 #[test]
1453 fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
1454 let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
1456 let sequence = Vector::sequence(10, 1, 4);
1457 let flat = Vector::from_values(
1458 LogicalType::BigInt,
1459 &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
1460 )
1461 .expect("four rows");
1462 let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
1463 assert_eq!(result.value_at(0), Value::Boolean(false));
1464 assert_eq!(result.value_at(1), Value::Boolean(false));
1465 assert_eq!(result.value_at(2), Value::Boolean(false));
1466 assert_eq!(result.value_at(3), Value::Null);
1467 assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
1468 }
1469
1470 #[test]
1480 fn a_second_level_of_codes_does_not_turn_the_loops_off() {
1481 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
1482 let values = Vector::from_values(
1483 LogicalType::Integer,
1484 &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
1485 )
1486 .expect("three rows");
1487 let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
1488 let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
1489 let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
1490 let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
1491 assert_eq!(result.value_at(0), Value::Boolean(true));
1492 assert_eq!(result.value_at(1), Value::Boolean(false));
1493 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
1494 }
1495
1496 #[test]
1500 fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
1501 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
1502 let flat = Vector::from_values(
1503 LogicalType::Integer,
1504 &[
1505 Value::Integer(1),
1506 Value::Integer(2),
1507 Value::Integer(3),
1508 Value::Integer(4),
1509 Value::Integer(5),
1510 Value::Integer(6),
1511 ],
1512 )
1513 .expect("six rows");
1514 agrees(Comparison::Less, &nulls, &flat);
1515 agrees(Comparison::Equal, &flat, &nulls);
1516 assert_eq!(
1517 compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
1518 &Validity::AllInvalid
1519 );
1520 }
1521
1522 #[test]
1525 fn an_empty_comparison_is_an_empty_answer() {
1526 let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
1527 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
1528 let result = compare(Comparison::Equal, &left, &right).expect("compares");
1529 assert_eq!(result.len(), 0);
1530 }
1531
1532 fn words() -> Vector {
1535 Vector::from_values(
1536 LogicalType::Varchar,
1537 &[
1538 Value::Varchar("http://a".into()),
1539 Value::Varchar("http://b".into()),
1540 Value::Null,
1541 Value::Varchar("ab".into()),
1542 Value::Varchar("http://a".into()),
1543 Value::Varchar("z".into()),
1544 ],
1545 )
1546 .expect("six rows")
1547 }
1548
1549 #[test]
1555 fn a_literal_built_early_answers_what_one_built_here_answers() {
1556 let column = words();
1557 let value = Value::Varchar("http://b".into());
1558 let constant = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
1559 let held = Held::of(&LogicalType::Varchar, &value).expect("a varchar has a column");
1560 let kept = Selection::from_indices(vec![0, 1, 3, 5]);
1561 for op in [
1562 Comparison::Equal,
1563 Comparison::NotEqual,
1564 Comparison::Less,
1565 Comparison::LessOrEqual,
1566 Comparison::Greater,
1567 Comparison::GreaterOrEqual,
1568 Comparison::DistinctFrom,
1569 Comparison::NotDistinctFrom,
1570 ] {
1571 let prepared = compare_prepared(op, &column, &constant, Some(&held)).expect("compares");
1572 assert_eq!(prepared, compare(op, &column, &constant).expect("compares"), "{op:?}");
1573 let flipped = compare_prepared(op, &constant, &column, Some(&held)).expect("compares");
1575 assert_eq!(flipped, compare(op, &constant, &column).expect("compares"), "{op:?}");
1576 let refined =
1577 refine_prepared(op, &column, &constant, &kept, Some(&held)).expect("refines");
1578 assert_eq!(refined, refine(op, &column, &constant, &kept).expect("refines"), "{op:?}");
1579 }
1580 }
1581
1582 #[test]
1589 fn a_literal_built_for_another_value_is_ignored() {
1590 let column = words();
1591 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("z".into()), 6);
1592 let wrong = Held::of(&LogicalType::Varchar, &Value::Varchar("ab".into()))
1593 .expect("a varchar has a column");
1594 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&wrong))
1595 .expect("compares");
1596 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1597 let other = Held::of(&LogicalType::Integer, &Value::Integer(1)).expect("an integer column");
1600 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&other))
1601 .expect("compares");
1602 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1603 }
1604
1605 #[test]
1608 fn a_packed_column_against_a_constant_answers_what_the_oracle_answers() {
1609 let values: Vec<i32> = (0..64).map(|row| 1000 + (row * 37) % 500).collect();
1610 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1611 .expect("integers are an i32 layout");
1612 let packed = flat.bit_packed().expect("a five hundred wide range packs");
1613 assert_eq!(packed.form(), Form::BitPacked);
1614 for literal in [999, 1000, 1200, 1499, 1500, 2000] {
1615 let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 64);
1616 for op in EVERY {
1617 agrees(op, &packed, &constant);
1618 agrees(op, &constant, &packed);
1619 }
1620 }
1621 }
1622
1623 #[test]
1627 fn a_packed_column_with_nulls_answers_what_the_oracle_answers() {
1628 let values: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
1629 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1630 .expect("integers are an i32 layout")
1631 .with_validity(Validity::from_iter(32, |row| row % 5 != 0));
1632 let packed = flat.bit_packed().expect("packs");
1633 let constant = Vector::constant(LogicalType::Integer, Value::Integer(80), 32);
1634 for op in EVERY {
1635 agrees(op, &packed, &constant);
1636 }
1637 }
1638
1639 #[test]
1642 fn a_literal_outside_the_packed_range_answers_the_whole_vector_at_once() {
1643 let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant);
1644 let values: Vec<i32> = (0..16).map(|row| 500 + row).collect();
1645 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1646 .expect("integers are an i32 layout");
1647 let packed = flat.bit_packed().expect("packs");
1648 let literals = [-1, 0, 499, 516, 100_000];
1649 for literal in literals {
1650 let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 16);
1651 for op in EVERY {
1652 agrees(op, &packed, &constant);
1653 }
1654 }
1655 let total = EVERY.iter().filter(|op| op.is_total()).count();
1660 assert_eq!(
1661 fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant) - before,
1662 (literals.len() * total) as u64,
1663 "only the two total comparisons fall through"
1664 );
1665 }
1666
1667 #[test]
1670 fn refining_a_selection_over_a_packed_column_keeps_the_same_rows() {
1671 let values: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
1672 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into()))
1673 .expect("integers are an i32 layout");
1674 let packed = flat.bit_packed().expect("packs");
1675 let kept = Selection::from_predicate(64, |row| row % 3 == 0);
1676 let constant = Vector::constant(LogicalType::Integer, Value::Integer(260), 64);
1677 let packed_rows = refine(Comparison::Greater, &packed, &constant, &kept).expect("refines");
1678 let flat_rows = refine(Comparison::Greater, &flat, &constant, &kept).expect("refines");
1679 assert_eq!(packed_rows.indices(), flat_rows.indices());
1680 assert!(!packed_rows.is_empty(), "the literal is inside the range");
1681 }
1682
1683 fn urls(count: usize) -> Vector {
1686 let mut rng = Rng(0x5eed_1234);
1687 let values: Vec<Value> = (0..count)
1688 .map(|_| {
1689 let host = rng.below(6);
1690 let path = rng.below(40);
1691 Value::Varchar(format!("http://example{host}.test/a/rather/long/path/{path}"))
1692 })
1693 .collect();
1694 Vector::from_values(LogicalType::Varchar, &values).expect("strings")
1695 }
1696
1697 #[test]
1698 fn a_string_view_column_against_a_literal_answers_what_the_oracle_answers() {
1699 let before = fallback::count(Kernel::Compare, Form::StringView, Form::Constant);
1700 let shared = urls(64).shared_text().expect("shares");
1701 assert_eq!(shared.form(), Form::StringView);
1702 let literals = ["http://example3.test/a/rather/long/path/7", "a", "zzz", ""];
1703 for literal in literals {
1704 let value = Value::Varchar(literal.to_owned());
1705 let constant = Vector::constant(LogicalType::Varchar, value, 64);
1706 for op in EVERY {
1707 agrees(op, &shared, &constant);
1708 agrees(op, &constant, &shared);
1709 }
1710 }
1711 assert_eq!(
1712 fallback::count(Kernel::Compare, Form::StringView, Form::Constant),
1713 before,
1714 "the form has a loop of its own for every comparison"
1715 );
1716 }
1717
1718 #[test]
1719 fn a_string_view_column_against_another_one_answers_what_the_oracle_answers() {
1720 let shared = urls(48).shared_text().expect("shares");
1721 let other = urls(48).shared_text().expect("shares");
1722 let flat = urls(48);
1723 for op in EVERY {
1724 agrees(op, &shared, &other);
1725 agrees(op, &shared, &flat);
1726 agrees(op, &flat, &shared);
1727 }
1728 }
1729
1730 #[test]
1731 fn the_nulls_of_a_string_view_column_are_the_nulls_the_oracle_sees() {
1732 let shared = urls(32)
1733 .with_validity(Validity::from_iter(32, |row| row % 4 != 1))
1734 .shared_text()
1735 .expect("shares");
1736 let constant =
1737 Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 32);
1738 for op in EVERY {
1739 agrees(op, &shared, &constant);
1740 }
1741 }
1742
1743 #[test]
1744 fn a_compressed_column_against_a_literal_answers_what_the_oracle_answers() {
1745 let before = fallback::count(Kernel::Compare, Form::Fsst, Form::Constant);
1746 let flat = urls(64);
1747 let coded = flat.clone().compressed().expect("compresses");
1748 assert_eq!(coded.form(), Form::Fsst);
1749 let present = match coded.value_at(9) {
1750 Value::Varchar(text) => text,
1751 other => panic!("a string column reads back strings, not {other:?}"),
1752 };
1753 for literal in [present.as_str(), "http://example3.test/nothing/like/it", ""] {
1754 let value = Value::Varchar(literal.to_owned());
1755 let constant = Vector::constant(LogicalType::Varchar, value, 64);
1756 for op in EVERY {
1757 agrees(op, &coded, &constant);
1758 agrees(op, &constant, &coded);
1759 }
1760 }
1761 let ordered = EVERY.len() - 2;
1765 assert_eq!(
1766 fallback::count(Kernel::Compare, Form::Fsst, Form::Constant) - before,
1767 (3 * ordered) as u64,
1768 "only the comparisons that need an order fall through"
1769 );
1770 }
1771
1772 #[test]
1775 fn every_row_of_a_compressed_column_matches_itself_and_nothing_else() {
1776 let flat = urls(48);
1777 let coded = flat.clone().compressed().expect("compresses");
1778 for row in 0..48 {
1779 let constant = Vector::constant(LogicalType::Varchar, flat.value_at(row), 48);
1780 let equal = compare(Comparison::Equal, &coded, &constant).expect("compares");
1781 for other in 0..48 {
1782 let want = flat.value_at(other) == flat.value_at(row);
1783 assert_eq!(
1784 equal.value_at(other),
1785 Value::Boolean(want),
1786 "row {row} against {other}"
1787 );
1788 }
1789 }
1790 }
1791
1792 #[test]
1793 fn the_nulls_of_a_compressed_column_are_the_nulls_the_oracle_sees() {
1794 let coded = urls(32)
1795 .with_validity(Validity::from_iter(32, |row| row % 3 != 0))
1796 .compressed()
1797 .expect("compresses");
1798 let value = coded.value_at(1);
1799 let constant = Vector::constant(LogicalType::Varchar, value, 32);
1800 for op in EVERY {
1801 agrees(op, &coded, &constant);
1802 }
1803 }
1804
1805 #[test]
1809 fn a_filter_over_either_string_form_keeps_the_same_rows() {
1810 let flat = urls(96);
1811 let shared = flat.clone().shared_text().expect("shares");
1812 let constant =
1813 Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 96);
1814 let kept = Selection::from_predicate(96, |row| row % 5 != 0);
1815 for op in EVERY {
1816 let over_flat = refine(op, &flat, &constant, &kept).expect("refines");
1817 let over_shared = refine(op, &shared, &constant, &kept).expect("refines");
1818 assert_eq!(over_shared.indices(), over_flat.indices(), "{op:?}");
1819 }
1820 }
1821}