1use std::borrow::Cow;
72use std::cmp::Ordering;
73use std::sync::Arc;
74
75use rudb_common::{Error, LogicalType, Result, Value, interval_micros};
76use rudb_vector::{
77 Coded, Data, Form, Packed, Selection, StringColumn, StringView, Validity, Vector,
78};
79
80use crate::fallback::{self, Kernel};
81use crate::logic::is_true;
82use crate::number::{approximate, integral};
83use crate::peel::{self, Found};
84use crate::prepare::Held;
85use crate::shape::{first, identity, nulls_of, single};
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
89pub enum Comparison {
90 Equal,
92 NotEqual,
94 Less,
96 LessOrEqual,
98 Greater,
100 GreaterOrEqual,
102 DistinctFrom,
104 NotDistinctFrom,
106}
107
108impl Comparison {
109 #[must_use]
111 pub fn is_total(self) -> bool {
112 matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
113 }
114
115 #[must_use]
122 pub fn swapped(self) -> Self {
123 match self {
124 Self::Less => Self::Greater,
125 Self::LessOrEqual => Self::GreaterOrEqual,
126 Self::Greater => Self::Less,
127 Self::GreaterOrEqual => Self::LessOrEqual,
128 same => same,
129 }
130 }
131
132 #[must_use]
138 fn holds(self, order: Ordering) -> bool {
139 match self {
140 Self::Equal => order == Ordering::Equal,
141 Self::NotEqual => order != Ordering::Equal,
142 Self::Less => order == Ordering::Less,
143 Self::LessOrEqual => order != Ordering::Greater,
144 Self::Greater => order == Ordering::Greater,
145 Self::GreaterOrEqual => order != Ordering::Less,
146 Self::DistinctFrom | Self::NotDistinctFrom => false,
147 }
148 }
149}
150
151pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
157 compare_prepared(op, left, right, None)
158}
159
160pub fn compare_prepared(
170 op: Comparison,
171 left: &Vector,
172 right: &Vector,
173 held: Option<&Held>,
174) -> Result<Vector> {
175 if left.len() != right.len() {
176 return Err(Error::internal(format!(
177 "a comparison of a {} row vector with a {} row one",
178 left.len(),
179 right.len()
180 )));
181 }
182 let len = left.len();
183 if left.form() == Form::Constant && right.form() == Form::Constant && len > 0 {
184 let single = compare_values(op, &left.try_value_at(0)?, &right.try_value_at(0)?)?;
185 return Ok(Vector::constant(LogicalType::Boolean, single, len));
186 }
187
188 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
189 if !op.is_total()
193 && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
194 && len > 0
195 {
196 return boolean(vec![false; len], Validity::AllInvalid, len);
197 }
198
199 if let Some(answers) = external_text_literal(op, left, right, len, identity, held)? {
200 let validity = left_valid.and(&right_valid, len);
201 return boolean(blank_the_nulls(answers, &validity), validity, len);
202 }
203 if let Some(answers) =
204 specialized(op, left, right, &left_valid, &right_valid, len, identity, held)
205 {
206 let validity =
207 if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
208 return boolean(blank_the_nulls(answers, &validity), validity, len);
209 }
210
211 fallback::record(Kernel::Compare, left.form(), right.form());
212 let mut values = Vec::with_capacity(len);
213 for index in 0..len {
216 values.push(compare_values(op, &left.try_value_at(index)?, &right.try_value_at(index)?)?);
217 }
218 Vector::from_values(LogicalType::Boolean, &values)
219}
220
221pub fn select_prepared(
235 op: Comparison,
236 left: &Vector,
237 right: &Vector,
238 held: Option<&Held>,
239) -> Result<Selection> {
240 if left.len() != right.len() {
241 return Err(Error::internal(format!(
242 "a comparison of a {} row vector with a {} row one",
243 left.len(),
244 right.len()
245 )));
246 }
247 let len = left.len();
248 if len == 0 {
249 return Ok(Selection::empty());
250 }
251 if left.form() == Form::Constant && right.form() == Form::Constant {
252 let single = compare_values(op, &left.try_value_at(0)?, &right.try_value_at(0)?)?;
253 return Ok(if is_true(&single) { Selection::identity(len) } else { Selection::empty() });
254 }
255 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
256 if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
257 {
258 return Ok(Selection::empty());
259 }
260 if u32::try_from(len).is_ok() {
263 if let Some(answers) = external_text_literal(op, left, right, len, identity, held)? {
264 return Ok(crate::select::picked(
265 &answers,
266 identity,
267 len,
268 &left_valid.and(&right_valid, len),
269 ));
270 }
271 if let Some(answers) =
272 specialized(op, left, right, &left_valid, &right_valid, len, identity, held)
273 {
274 let validity =
275 if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
276 return Ok(crate::select::picked(&answers, identity, len, &validity));
277 }
278 }
279 Ok(crate::select::selection(&compare_prepared(op, left, right, held)?, len))
280}
281
282pub fn refine(
300 op: Comparison,
301 left: &Vector,
302 right: &Vector,
303 kept: &Selection,
304) -> Result<Selection> {
305 refine_prepared(op, left, right, kept, None)
306}
307
308pub fn refine_prepared(
318 op: Comparison,
319 left: &Vector,
320 right: &Vector,
321 kept: &Selection,
322 held: Option<&Held>,
323) -> Result<Selection> {
324 if left.len() != right.len() {
325 return Err(Error::internal(format!(
326 "a comparison of a {} row vector with a {} row one",
327 left.len(),
328 right.len()
329 )));
330 }
331 let len = left.len();
332 if kept.indices().iter().any(|&row| row as usize >= len) {
336 return Err(Error::internal(format!("a selection past the end of a {len} row vector")));
337 }
338 if kept.is_empty() {
339 return Ok(Selection::empty());
340 }
341 if left.form() == Form::Constant && right.form() == Form::Constant {
342 let single = compare_values(op, &left.try_value_at(0)?, &right.try_value_at(0)?)?;
343 return Ok(if is_true(&single) { kept.clone() } else { Selection::empty() });
344 }
345
346 let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
347 if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
348 {
349 return Ok(Selection::empty());
350 }
351
352 let rows = kept.indices();
353 let map = |slot: usize| rows[slot] as usize;
354 if let Some(answers) = external_text_literal(op, left, right, kept.len(), map, held)? {
355 return Ok(narrowed(&answers, rows, |slot| {
356 let row = rows[slot] as usize;
357 left_valid.is_valid(row) && right_valid.is_valid(row)
358 }));
359 }
360 if let Some(answers) =
361 specialized(op, left, right, &left_valid, &right_valid, kept.len(), map, held)
362 {
363 if op.is_total() || (left_valid == Validity::AllValid && right_valid == Validity::AllValid)
366 {
367 return Ok(narrowed(&answers, rows, |_| true));
368 }
369 return Ok(narrowed(&answers, rows, |slot| {
373 let row = rows[slot] as usize;
374 left_valid.is_valid(row) && right_valid.is_valid(row)
375 }));
376 }
377
378 fallback::record(Kernel::Compare, left.form(), right.form());
379 let mut out = Vec::with_capacity(kept.len());
380 for &row in rows {
383 let index = row as usize;
384 if is_true(&compare_values(op, &left.try_value_at(index)?, &right.try_value_at(index)?)?) {
385 out.push(row);
386 }
387 }
388 Ok(Selection::from_indices(out))
389}
390
391fn external_text_literal<M>(
407 op: Comparison,
408 left: &Vector,
409 right: &Vector,
410 len: usize,
411 map: M,
412 held: Option<&Held>,
413) -> Result<Option<Vec<bool>>>
414where
415 M: Fn(usize) -> usize + Copy,
416{
417 if op.is_total()
418 || left.logical_type() != &LogicalType::Varchar
419 || right.logical_type() != &LogicalType::Varchar
420 {
421 return Ok(None);
422 }
423 let (column, literal, swapped) = match (left.constant_value(), right.constant_value()) {
424 (None, Some(Value::Varchar(literal))) if left.positions().is_some() => {
425 (left, literal.as_bytes(), false)
426 }
427 (Some(Value::Varchar(literal)), None) if right.positions().is_some() => {
428 (right, literal.as_bytes(), true)
429 }
430 _ => return Ok(None),
431 };
432 let op = if swapped { op.swapped() } else { op };
435 let same = op == Comparison::Equal;
436 if matches!(op, Comparison::Equal | Comparison::NotEqual) {
437 if let Some(held) = held.filter(|held| held.text() == Some(literal)) {
441 if let Some(found) = held.lookup().find(column, literal) {
444 return Ok(Some(against_code(column, found?, len, map, same)?));
445 }
446 let decide = |dictionary: &Vector, code: usize| -> Result<bool> {
447 let found = if literal.is_empty() {
448 dictionary.try_bytes_len_at(code)?.is_some_and(|length| length == 0)
449 } else {
450 dictionary.try_bytes_at(code)?.is_some_and(|bytes| bytes == literal)
451 };
452 Ok(found)
453 };
454 if let Some(answers) = held.peel().answer(column, len, map, decide) {
455 let mut answers = answers?;
456 if !same {
457 for answer in &mut answers {
458 *answer = !*answer;
459 }
460 }
461 return Ok(Some(answers));
462 }
463 }
464 let mut answers = Vec::with_capacity(len);
465 for slot in 0..len {
466 let row = map(slot);
467 let equal = if literal.is_empty() {
470 column.try_bytes_len_at(row)?.is_some_and(|length| length == 0)
471 } else {
472 column.try_bytes_at(row)?.is_some_and(|bytes| bytes == literal)
473 };
474 answers.push(equal == same);
475 }
476 return Ok(Some(answers));
477 }
478 if let Some(answers) = by_rank(op, column, literal, len, map)? {
479 return Ok(Some(answers));
480 }
481 let mut answers = Vec::with_capacity(len);
482 for slot in 0..len {
483 let row = map(slot);
484 let order = match column.try_bytes_at(row)? {
488 Some(bytes) => bytes.cmp(literal),
489 None => Ordering::Equal,
490 };
491 answers.push(op.holds(order));
492 }
493 Ok(Some(answers))
494}
495
496fn by_rank<M>(
518 op: Comparison,
519 column: &Vector,
520 literal: &[u8],
521 len: usize,
522 map: M,
523) -> Result<Option<Vec<bool>>>
524where
525 M: Fn(usize) -> usize,
526{
527 let Some((codes, dictionary)) = column.shared_dictionary_parts() else { return Ok(None) };
528 let Some(ranks) = dictionary.ranks() else { return Ok(None) };
529 let Some(order) = dictionary.code_ranks() else { return Ok(None) };
530 let (below, equal) = peel::below(dictionary, ranks, literal)?;
531 let cut = match op {
534 Comparison::Less | Comparison::GreaterOrEqual => below,
535 _ => below + usize::from(equal),
536 };
537 let under = matches!(op, Comparison::Less | Comparison::LessOrEqual);
538 let mut answers = Vec::with_capacity(len);
539 for slot in 0..len {
541 let code = *codes
542 .get(map(slot))
543 .ok_or_else(|| Error::internal("a ranked row is past the end of its codes"))?;
544 let rank = *order
545 .get(code as usize)
546 .ok_or_else(|| Error::internal("a ranked code is past the end of its dictionary"))?;
547 answers.push(((rank as usize) < cut) == under);
548 }
549 Ok(Some(answers))
550}
551
552#[must_use]
574pub fn select_against_rank(
575 op: Comparison,
576 column: &Vector,
577 dictionary: &Arc<Vector>,
578 rank: u32,
579 rows: usize,
580) -> Option<Selection> {
581 let (codes, values) = column.shared_dictionary_parts()?;
582 if !Arc::ptr_eq(values, dictionary) {
583 return None;
584 }
585 let order = values.code_ranks()?;
586 let validity = column.validity();
587 let live = !validity.has_nulls(rows);
588 let rows = rows.min(codes.len());
589 let mut kept = vec![0_u32; rows];
590 let mut count = 0;
591 for (row, &code) in codes.iter().enumerate().take(rows) {
595 let at = *order.get(code as usize)?;
596 let held = match op {
597 Comparison::Less => at < rank,
598 Comparison::LessOrEqual => at <= rank,
599 Comparison::Greater => at > rank,
600 Comparison::GreaterOrEqual => at >= rank,
601 _ => return None,
602 };
603 kept[count] = u32::try_from(row).ok()?;
604 count += usize::from(held & (live || validity.is_valid(row)));
606 }
607 kept.truncate(count);
608 Some(Selection::from_indices(kept))
609}
610
611#[must_use]
620pub fn rank_at(column: &Vector, row: usize) -> Option<(Arc<Vector>, u32)> {
621 let (codes, values) = column.shared_dictionary_parts()?;
622 if !column.validity().is_valid(row) {
623 return None;
624 }
625 let order = values.code_ranks()?;
626 let code = *codes.get(row)?;
627 let rank = *order.get(code as usize)?;
628 Some((Arc::clone(values), rank))
629}
630
631#[must_use]
645pub fn rank_within(column: &Vector, row: usize, dictionary: &Arc<Vector>) -> Option<u32> {
646 let (codes, values) = column.shared_dictionary_parts()?;
647 if !Arc::ptr_eq(values, dictionary) || !column.validity().is_valid(row) {
648 return None;
649 }
650 let order = values.code_ranks()?;
651 let code = *codes.get(row)?;
652 Some(*order.get(code as usize)?)
653}
654
655fn against_code<M>(
663 column: &Vector,
664 found: Found,
665 len: usize,
666 map: M,
667 same: bool,
668) -> Result<Vec<bool>>
669where
670 M: Fn(usize) -> usize,
671{
672 let Found::At(wanted) = found else { return Ok(vec![!same; len]) };
673 let (codes, _) = column
674 .shared_dictionary_parts()
675 .ok_or_else(|| Error::internal("a resolved literal lost the codes it was resolved for"))?;
676 if codes.len() < column.len() {
681 return Err(Error::internal("a compared column is longer than its codes"));
682 }
683 Ok((0..len).map(|slot| (codes[map(slot)] == wanted) == same).collect())
685}
686
687fn narrowed<L: Fn(usize) -> bool>(answers: &[bool], rows: &[u32], live: L) -> Selection {
694 let mut out = vec![0_u32; answers.len()];
695 let mut count = 0;
696 for (slot, &answer) in answers.iter().enumerate() {
697 out[count] = rows[slot];
698 count += usize::from(answer & live(slot));
700 }
701 out.truncate(count);
702 Selection::from_indices(out)
703}
704
705fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
707 let validity = if len == 0 { Validity::AllValid } else { validity.normalize(len) };
711 Ok(Vector::flat(LogicalType::Boolean, Data::Bool(answers.into()))?.with_validity(validity))
712}
713
714fn blank_the_nulls(mut answers: Vec<bool>, validity: &Validity) -> Vec<bool> {
722 if let Validity::Mask(mask) = validity {
723 for (index, answer) in answers.iter_mut().enumerate() {
724 if !mask.get(index) {
725 *answer = false;
726 }
727 }
728 }
729 answers
730}
731
732#[expect(
744 clippy::too_many_arguments,
745 reason = "two sides, two validities, the operator, the length, the index mapping and the \
746 literal that was built early, all of which the branches below need"
747)]
748fn specialized<M>(
749 op: Comparison,
750 left: &Vector,
751 right: &Vector,
752 left_valid: &Validity,
753 right_valid: &Validity,
754 len: usize,
755 map: M,
756 held: Option<&Held>,
757) -> Option<Vec<bool>>
758where
759 M: Fn(usize) -> usize + Copy,
760{
761 if left.logical_type() != right.logical_type() {
765 return None;
766 }
767
768 let (one, other) = (through(left), through(right));
771
772 if let (Some(one), Some(other)) = (&one, &other) {
773 return match (one, other) {
774 (Through::Direct(a), Through::Direct(b)) => {
775 dispatch(op, len, a, map, b, map, left_valid, right_valid, map)
776 }
777 (Through::Coded(codes, a), Through::Direct(b)) => dispatch(
778 op,
779 len,
780 a,
781 |slot| codes[map(slot)] as usize,
782 b,
783 map,
784 left_valid,
785 right_valid,
786 map,
787 ),
788 (Through::Direct(a), Through::Coded(codes, b)) => dispatch(
789 op,
790 len,
791 a,
792 map,
793 b,
794 |slot| codes[map(slot)] as usize,
795 left_valid,
796 right_valid,
797 map,
798 ),
799 (Through::Coded(left_codes, a), Through::Coded(right_codes, b)) => dispatch(
800 op,
801 len,
802 a,
803 |slot| left_codes[map(slot)] as usize,
804 b,
805 |slot| right_codes[map(slot)] as usize,
806 left_valid,
807 right_valid,
808 map,
809 ),
810 };
811 }
812 if !op.is_total() {
818 if let (Some(packed), Some(value)) = (left.packed_parts(), right.constant_value()) {
819 let wanted = exact(held, left.logical_type(), value)?;
820 return Some(packed_against(op, &packed, wanted, len, map));
821 }
822 if let (Some(value), Some(packed)) = (left.constant_value(), right.packed_parts()) {
823 let wanted = exact(held, right.logical_type(), value)?;
824 return Some(packed_against(op.swapped(), &packed, wanted, len, map));
825 }
826 if let (Some(one), Some(other)) = (packing(left), packing(right)) {
827 return packings_against_each_other(op, &one, &other, len, map);
828 }
829 if let (Some(one), Some(other)) = (packing(left), &other) {
837 return packing_against_run(op, &one, other, len, map);
838 }
839 if let (Some(one), Some(other)) = (&one, packing(right)) {
840 return packing_against_run(op.swapped(), &other, one, len, map);
841 }
842 }
843 if let (Some(one), Some(value)) = (&one, right.constant_value()) {
844 let column = readied(held, left.logical_type(), value)?;
845 let other = column.data()?;
846 return match one {
847 Through::Direct(a) => {
848 dispatch(op, len, a, map, other, first, left_valid, right_valid, map)
849 }
850 Through::Coded(codes, a) => dispatch(
851 op,
852 len,
853 a,
854 |slot| codes[map(slot)] as usize,
855 other,
856 first,
857 left_valid,
858 right_valid,
859 map,
860 ),
861 };
862 }
863 if let (Some(value), Some(other)) = (left.constant_value(), &other) {
864 let column = readied(held, right.logical_type(), value)?;
866 let one = column.data()?;
867 return match other {
868 Through::Direct(b) => {
869 dispatch(op.swapped(), len, b, map, one, first, right_valid, left_valid, map)
870 }
871 Through::Coded(codes, b) => dispatch(
872 op.swapped(),
873 len,
874 b,
875 |slot| codes[map(slot)] as usize,
876 one,
877 first,
878 right_valid,
879 left_valid,
880 map,
881 ),
882 };
883 }
884 if matches!(op, Comparison::Equal | Comparison::NotEqual) {
889 if let (Some(coded), Some(value)) = (left.coded_parts(), right.constant_value()) {
890 let wanted = encoded(&coded, held, left.logical_type(), value)?;
891 return Some(coded_against(op, &coded, &wanted, len, map));
892 }
893 if let (Some(value), Some(coded)) = (left.constant_value(), right.coded_parts()) {
894 let wanted = encoded(&coded, held, right.logical_type(), value)?;
895 return Some(coded_against(op, &coded, &wanted, len, map));
896 }
897 }
898 if let (Some((one, one_arena)), Some((other, other_arena))) =
904 (left.text_parts(), right.text_parts())
905 {
906 return Some(sweep(
907 op,
908 len,
909 |index| view_order(one.get(map(index)), one_arena, other.get(map(index)), other_arena),
910 left_valid,
911 right_valid,
912 map,
913 ));
914 }
915 if let (Some((one, one_arena)), Some(value)) = (left.text_parts(), right.constant_value()) {
919 let column = readied(held, left.logical_type(), value)?;
920 let (other, other_arena) = column.text_parts()?;
921 let wanted = other.first();
922 return Some(sweep(
923 op,
924 len,
925 |index| view_order(one.get(map(index)), one_arena, wanted, other_arena),
926 left_valid,
927 right_valid,
928 map,
929 ));
930 }
931 if let (Some(value), Some((other, other_arena))) = (left.constant_value(), right.text_parts()) {
932 let column = readied(held, right.logical_type(), value)?;
934 let (one, one_arena) = column.text_parts()?;
935 let wanted = one.first();
936 return Some(sweep(
937 op.swapped(),
938 len,
939 |index| view_order(other.get(map(index)), other_arena, wanted, one_arena),
940 right_valid,
941 left_valid,
942 map,
943 ));
944 }
945 if let (Some((codes, values)), Some(value)) = (left.positions(), right.constant_value()) {
946 let one = values.data()?;
947 let column = readied(held, left.logical_type(), value)?;
948 let other = column.data()?;
949 let at = |index: usize| codes[map(index)] as usize;
950 return dispatch(op, len, one, at, other, first, left_valid, right_valid, map);
951 }
952 if let (Some(value), Some((codes, values))) = (left.constant_value(), right.positions()) {
953 let other = values.data()?;
954 let column = readied(held, right.logical_type(), value)?;
955 let one = column.data()?;
956 let at = |index: usize| codes[map(index)] as usize;
957 return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid, map);
958 }
959 if let (Some((codes, values)), Some(other)) = (left.positions(), right.data()) {
965 let one = values.data()?;
966 let at = |index: usize| codes[map(index)] as usize;
967 return dispatch(op, len, one, at, other, map, left_valid, right_valid, map);
968 }
969 if let (Some(one), Some((codes, values))) = (left.data(), right.positions()) {
970 let other = values.data()?;
971 let at = |index: usize| codes[map(index)] as usize;
972 return dispatch(op.swapped(), len, other, at, one, map, right_valid, left_valid, map);
973 }
974 None
975}
976
977fn exact(held: Option<&Held>, ty: &LogicalType, value: &Value) -> Option<i128> {
984 let column = readied(held, ty, value)?;
985 let data = column.data()?;
986 data.signed_at(0).or_else(|| data.unsigned_at(0).and_then(|value| i128::try_from(value).ok()))
987}
988
989fn encoded(
995 coded: &Coded<'_>,
996 held: Option<&Held>,
997 ty: &LogicalType,
998 value: &Value,
999) -> Option<Vec<u8>> {
1000 let column = readied(held, ty, value)?;
1001 let (views, arena) = column.text_parts()?;
1002 Some(coded.encode(views.first()?.bytes_in(arena)?))
1003}
1004
1005fn coded_against<M>(
1011 op: Comparison,
1012 coded: &Coded<'_>,
1013 wanted: &[u8],
1014 len: usize,
1015 map: M,
1016) -> Vec<bool>
1017where
1018 M: Fn(usize) -> usize + Copy,
1019{
1020 let same = op == Comparison::Equal;
1021 let mut answers = Vec::with_capacity(len);
1022 for row in 0..len {
1023 answers.push((coded.row(map(row)) == Some(wanted)) == same);
1024 }
1025 answers
1026}
1027
1028fn packed_against<M>(
1041 op: Comparison,
1042 packed: &Packed<'_>,
1043 wanted: i128,
1044 len: usize,
1045 map: M,
1046) -> Vec<bool>
1047where
1048 M: Fn(usize) -> usize + Copy,
1049{
1050 let Some(code) = packed.code_of(wanted) else {
1051 let above = wanted > packed.ceiling();
1054 let same = match op {
1055 Comparison::Equal | Comparison::NotDistinctFrom => false,
1056 Comparison::NotEqual | Comparison::DistinctFrom => true,
1057 Comparison::Less | Comparison::LessOrEqual => above,
1058 Comparison::Greater | Comparison::GreaterOrEqual => !above,
1059 };
1060 return vec![same; len];
1061 };
1062 let mut answers = vec![false; len];
1063 macro_rules! sweep {
1065 ($test:expr) => {{
1066 let test = $test;
1067 for (row, answer) in answers.iter_mut().enumerate() {
1068 *answer = test(packed.code(map(row)), code);
1069 }
1070 }};
1071 }
1072 match op {
1073 Comparison::Equal | Comparison::NotDistinctFrom => sweep!(|found, want| found == want),
1074 Comparison::NotEqual | Comparison::DistinctFrom => sweep!(|found, want| found != want),
1075 Comparison::Less => sweep!(|found, want| found < want),
1076 Comparison::LessOrEqual => sweep!(|found, want| found <= want),
1077 Comparison::Greater => sweep!(|found, want| found > want),
1078 Comparison::GreaterOrEqual => sweep!(|found, want| found >= want),
1079 }
1080 answers
1081}
1082
1083fn packed_against_packed<L, R, M>(
1107 op: Comparison,
1108 left: &Packed<'_>,
1109 at_left: L,
1110 right: &Packed<'_>,
1111 at_right: R,
1112 len: usize,
1113 map: M,
1114) -> Option<Vec<bool>>
1115where
1116 L: Fn(usize) -> usize,
1117 R: Fn(usize) -> usize,
1118 M: Fn(usize) -> usize + Copy,
1119{
1120 let (low, high) = (left.base(), ceiling_of(left)?);
1121 let (other_low, other_high) = (right.base(), ceiling_of(right)?);
1122 if high < other_low || other_high < low {
1123 let below = high < other_low;
1126 let same = match op {
1127 Comparison::Equal | Comparison::NotDistinctFrom => false,
1128 Comparison::NotEqual | Comparison::DistinctFrom => true,
1129 Comparison::Less | Comparison::LessOrEqual => below,
1130 Comparison::Greater | Comparison::GreaterOrEqual => !below,
1131 };
1132 return Some(vec![same; len]);
1133 }
1134 let mut answers = vec![false; len];
1137 macro_rules! sweep {
1139 ($test:expr) => {{
1140 let test = $test;
1141 for (slot, answer) in answers.iter_mut().enumerate() {
1142 let row = map(slot);
1143 *answer = test(
1144 low + i128::from(left.code(at_left(row))),
1145 other_low + i128::from(right.code(at_right(row))),
1146 );
1147 }
1148 }};
1149 }
1150 match op {
1151 Comparison::Equal | Comparison::NotDistinctFrom => sweep!(|one, other| one == other),
1152 Comparison::NotEqual | Comparison::DistinctFrom => sweep!(|one, other| one != other),
1153 Comparison::Less => sweep!(|one, other| one < other),
1154 Comparison::LessOrEqual => sweep!(|one, other| one <= other),
1155 Comparison::Greater => sweep!(|one, other| one > other),
1156 Comparison::GreaterOrEqual => sweep!(|one, other| one >= other),
1157 }
1158 Some(answers)
1159}
1160
1161enum Packing<'a> {
1167 Straight(Packed<'a>),
1169 Coded(Cow<'a, [u32]>, Packed<'a>),
1171}
1172
1173fn packing(vector: &Vector) -> Option<Packing<'_>> {
1175 if let Some(packed) = vector.packed_parts() {
1176 return Some(Packing::Straight(packed));
1177 }
1178 let (codes, values) = vector.positions()?;
1179 Some(Packing::Coded(codes, values.packed_parts()?))
1180}
1181
1182fn packings_against_each_other<M>(
1185 op: Comparison,
1186 left: &Packing<'_>,
1187 right: &Packing<'_>,
1188 len: usize,
1189 map: M,
1190) -> Option<Vec<bool>>
1191where
1192 M: Fn(usize) -> usize + Copy,
1193{
1194 match (left, right) {
1195 (Packing::Straight(one), Packing::Straight(other)) => {
1196 packed_against_packed(op, one, identity, other, identity, len, map)
1197 }
1198 (Packing::Straight(one), Packing::Coded(codes, other)) => {
1199 packed_against_packed(op, one, identity, other, |row| codes[row] as usize, len, map)
1200 }
1201 (Packing::Coded(codes, one), Packing::Straight(other)) => {
1202 packed_against_packed(op, one, |row| codes[row] as usize, other, identity, len, map)
1203 }
1204 (Packing::Coded(codes, one), Packing::Coded(others, other)) => packed_against_packed(
1205 op,
1206 one,
1207 |row| codes[row] as usize,
1208 other,
1209 |row| others[row] as usize,
1210 len,
1211 map,
1212 ),
1213 }
1214}
1215
1216fn packing_against_run<M>(
1223 op: Comparison,
1224 packed: &Packing<'_>,
1225 run: &Through<'_>,
1226 len: usize,
1227 map: M,
1228) -> Option<Vec<bool>>
1229where
1230 M: Fn(usize) -> usize + Copy,
1231{
1232 match (packed, run) {
1233 (Packing::Straight(one), Through::Direct(other)) => {
1234 packed_against_flat(op, one, identity, other, identity, len, map)
1235 }
1236 (Packing::Straight(one), Through::Coded(codes, other)) => {
1237 packed_against_flat(op, one, identity, other, |row| codes[row] as usize, len, map)
1238 }
1239 (Packing::Coded(codes, one), Through::Direct(other)) => {
1240 packed_against_flat(op, one, |row| codes[row] as usize, other, identity, len, map)
1241 }
1242 (Packing::Coded(codes, one), Through::Coded(others, other)) => packed_against_flat(
1243 op,
1244 one,
1245 |row| codes[row] as usize,
1246 other,
1247 |row| others[row] as usize,
1248 len,
1249 map,
1250 ),
1251 }
1252}
1253
1254fn packed_against_flat<L, R, M>(
1268 op: Comparison,
1269 packed: &Packed<'_>,
1270 at_packed: L,
1271 flat: &Data,
1272 at_flat: R,
1273 len: usize,
1274 map: M,
1275) -> Option<Vec<bool>>
1276where
1277 L: Fn(usize) -> usize,
1278 R: Fn(usize) -> usize,
1279 M: Fn(usize) -> usize + Copy,
1280{
1281 ceiling_of(packed)?;
1282 let base = packed.base();
1283 macro_rules! layouts {
1284 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
1285 match flat {
1286 $(
1287 Data::$variant(run) => Some(numbers_compared(op, len, |slot| {
1288 let row = map(slot);
1289 (
1290 base + i128::from(packed.code(at_packed(row))),
1291 i128::from(run[at_flat(row)]),
1292 )
1293 })),
1294 )+
1295 _ => None,
1298 }
1299 };
1300 }
1301 rudb_vector::for_each_layout!(exact, layouts)
1302}
1303
1304fn numbers_compared<P>(op: Comparison, len: usize, pair: P) -> Vec<bool>
1310where
1311 P: Fn(usize) -> (i128, i128),
1312{
1313 let mut answers = vec![false; len];
1314 macro_rules! sweep {
1316 ($test:expr) => {{
1317 let test = $test;
1318 for (slot, answer) in answers.iter_mut().enumerate() {
1319 let (one, other) = pair(slot);
1320 *answer = test(one, other);
1321 }
1322 }};
1323 }
1324 match op {
1325 Comparison::Equal | Comparison::NotDistinctFrom => sweep!(|one, other| one == other),
1326 Comparison::NotEqual | Comparison::DistinctFrom => sweep!(|one, other| one != other),
1327 Comparison::Less => sweep!(|one, other| one < other),
1328 Comparison::LessOrEqual => sweep!(|one, other| one <= other),
1329 Comparison::Greater => sweep!(|one, other| one > other),
1330 Comparison::GreaterOrEqual => sweep!(|one, other| one >= other),
1331 }
1332 answers
1333}
1334
1335fn ceiling_of(packed: &Packed<'_>) -> Option<i128> {
1341 let mask = u64::MAX >> (u64::BITS - packed.width());
1342 packed.base().checked_add(i128::from(mask))
1343}
1344
1345enum Through<'a> {
1359 Direct(&'a Data),
1361 Coded(Cow<'a, [u32]>, &'a Data),
1363}
1364
1365fn through(vector: &Vector) -> Option<Through<'_>> {
1372 if let Some(data) = vector.data() {
1373 return Some(Through::Direct(data));
1374 }
1375 let (codes, values) = vector.positions()?;
1376 Some(Through::Coded(codes, values.data()?))
1377}
1378
1379#[expect(
1385 clippy::too_many_arguments,
1386 reason = "two sides with an index each, the operator, the length and two validities, all of \
1387 which the loop needs and none of which is worth a struct that exists for one call"
1388)]
1389fn dispatch<L, R, V>(
1390 op: Comparison,
1391 len: usize,
1392 left: &Data,
1393 at_left: L,
1394 right: &Data,
1395 at_right: R,
1396 left_valid: &Validity,
1397 right_valid: &Validity,
1398 at_valid: V,
1399) -> Option<Vec<bool>>
1400where
1401 L: Fn(usize) -> usize,
1402 R: Fn(usize) -> usize,
1403 V: Fn(usize) -> usize,
1404{
1405 macro_rules! layouts {
1406 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
1407 match (left, right) {
1408 $(
1409 (Data::$variant(one), Data::$variant(other)) => Some(sweep(
1410 op,
1411 len,
1412 |index| one[at_left(index)].cmp(&other[at_right(index)]),
1413 left_valid,
1414 right_valid,
1415 &at_valid,
1416 )),
1417 )+
1418 (Data::Float32(one), Data::Float32(other)) => Some(sweep(
1421 op,
1422 len,
1423 |index| {
1424 float_order(
1425 f64::from(one[at_left(index)]),
1426 f64::from(other[at_right(index)]),
1427 )
1428 },
1429 left_valid,
1430 right_valid,
1431 &at_valid,
1432 )),
1433 (Data::Float64(one), Data::Float64(other)) => Some(sweep(
1434 op,
1435 len,
1436 |index| float_order(one[at_left(index)], other[at_right(index)]),
1437 left_valid,
1438 right_valid,
1439 &at_valid,
1440 )),
1441 (Data::Interval(one), Data::Interval(other)) => Some(sweep(
1444 op,
1445 len,
1446 |index| {
1447 let (months, days, micros) = one[at_left(index)];
1448 let (bm, bd, bu) = other[at_right(index)];
1449 interval_micros(months, days, micros).cmp(&interval_micros(bm, bd, bu))
1450 },
1451 left_valid,
1452 right_valid,
1453 &at_valid,
1454 )),
1455 (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
1456 op,
1457 len,
1458 |index| string_order(one, at_left(index), other, at_right(index)),
1459 left_valid,
1460 right_valid,
1461 &at_valid,
1462 )),
1463 _ => None,
1464 }
1465 };
1466 }
1467 rudb_vector::for_each_layout!(ordered, layouts)
1468}
1469
1470fn readied<'a>(held: Option<&'a Held>, ty: &LogicalType, value: &Value) -> Option<Cow<'a, Vector>> {
1476 match held {
1477 Some(held) if held.matches(ty, value) => Some(Cow::Borrowed(held.single())),
1478 _ => Some(Cow::Owned(single(ty, value)?)),
1479 }
1480}
1481
1482fn string_order(
1490 left: &StringColumn,
1491 at_left: usize,
1492 right: &StringColumn,
1493 at_right: usize,
1494) -> Ordering {
1495 view_order(left.views().get(at_left), left.arena(), right.views().get(at_right), right.arena())
1496}
1497
1498fn view_order(
1504 one: Option<&StringView>,
1505 one_arena: &[u8],
1506 other: Option<&StringView>,
1507 other_arena: &[u8],
1508) -> Ordering {
1509 let (Some(one), Some(other)) = (one, other) else {
1510 return Ordering::Equal;
1511 };
1512 let (prefix, against) = (one.prefix(), other.prefix());
1513 if prefix != against {
1514 return prefix.cmp(&against);
1515 }
1516 let bytes = one.bytes_in(one_arena).unwrap_or_default();
1521 let against_bytes = other.bytes_in(other_arena).unwrap_or_default();
1522 bytes.cmp(against_bytes)
1523}
1524
1525fn sweep<O, V>(
1531 op: Comparison,
1532 len: usize,
1533 order_at: O,
1534 left_valid: &Validity,
1535 right_valid: &Validity,
1536 at_valid: V,
1537) -> Vec<bool>
1538where
1539 O: Fn(usize) -> Ordering,
1540 V: Fn(usize) -> usize,
1541{
1542 let mut answers = vec![false; len];
1543 match op {
1544 Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
1545 Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
1546 Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
1547 Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
1548 Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
1549 Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
1550 Comparison::DistinctFrom => {
1551 total(&mut answers, order_at, left_valid, right_valid, at_valid);
1552 for answer in &mut answers {
1553 *answer = !*answer;
1554 }
1555 }
1556 Comparison::NotDistinctFrom => {
1557 total(&mut answers, order_at, left_valid, right_valid, at_valid);
1558 }
1559 }
1560 answers
1561}
1562
1563#[inline]
1565fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
1566where
1567 O: Fn(usize) -> Ordering,
1568 H: Fn(Ordering) -> bool,
1569{
1570 for (index, answer) in answers.iter_mut().enumerate() {
1571 *answer = held(order_at(index));
1572 }
1573}
1574
1575fn total<O, V>(
1582 answers: &mut [bool],
1583 order_at: O,
1584 left_valid: &Validity,
1585 right_valid: &Validity,
1586 at_valid: V,
1587) where
1588 O: Fn(usize) -> Ordering,
1589 V: Fn(usize) -> usize,
1590{
1591 if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
1592 fill(answers, order_at, |o| o == Ordering::Equal);
1593 return;
1594 }
1595 for (index, answer) in answers.iter_mut().enumerate() {
1596 let row = at_valid(index);
1597 *answer = match (left_valid.is_valid(row), right_valid.is_valid(row)) {
1598 (true, true) => order_at(index) == Ordering::Equal,
1599 (false, false) => true,
1600 _ => false,
1601 };
1602 }
1603}
1604
1605pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
1611 if op.is_total() {
1612 let same = match (left.is_null(), right.is_null()) {
1613 (true, true) => true,
1614 (true, false) | (false, true) => false,
1615 (false, false) => order(left, right)? == Ordering::Equal,
1616 };
1617 return Ok(Value::Boolean(match op {
1618 Comparison::NotDistinctFrom => same,
1619 _ => !same,
1620 }));
1621 }
1622 if left.is_null() || right.is_null() {
1623 return Ok(Value::Null);
1624 }
1625 let ordering = order(left, right)?;
1626 let held = match op {
1627 Comparison::Equal => ordering == Ordering::Equal,
1628 Comparison::NotEqual => ordering != Ordering::Equal,
1629 Comparison::Less => ordering == Ordering::Less,
1630 Comparison::LessOrEqual => ordering != Ordering::Greater,
1631 Comparison::Greater => ordering == Ordering::Greater,
1632 Comparison::GreaterOrEqual => ordering != Ordering::Less,
1633 Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
1634 return Err(Error::internal("a total comparison reached the ordered path"));
1635 }
1636 };
1637 Ok(Value::Boolean(held))
1638}
1639
1640pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
1651 match (left, right) {
1652 (Value::Null, _) | (_, Value::Null) => {
1653 Err(Error::internal("a null reached the ordering path"))
1654 }
1655 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
1656 (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
1657 (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
1658 (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
1659 (Value::Time(a), Value::Time(b))
1662 | (Value::TimeTz(a), Value::TimeTz(b))
1663 | (Value::Timestamp(a), Value::Timestamp(b))
1664 | (Value::TimestampTz(a), Value::TimestampTz(b)) => Ok(a.cmp(b)),
1665 (
1666 Value::Interval { months: am, days: ad, micros: au },
1667 Value::Interval { months: bm, days: bd, micros: bu },
1668 ) => Ok(interval_micros(*am, *ad, *au).cmp(&interval_micros(*bm, *bd, *bu))),
1669 (Value::List { values: a, .. }, Value::List { values: b, .. }) => list_order(a, b),
1670 _ => numeric_order(left, right),
1671 }
1672}
1673
1674fn list_order(left: &[Value], right: &[Value]) -> Result<Ordering> {
1689 for (one, other) in left.iter().zip(right) {
1690 let ordering = order_with_nulls(one, other, false)?;
1691 if ordering != Ordering::Equal {
1692 return Ok(ordering);
1693 }
1694 }
1695 Ok(left.len().cmp(&right.len()))
1696}
1697
1698fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
1700 if let (Some(a), Some(b)) = (integral(left), integral(right)) {
1701 return Ok(a.cmp(&b));
1702 }
1703 if let (
1704 Value::Decimal { unscaled: a, scale: sa, .. },
1705 Value::Decimal { unscaled: b, scale: sb, .. },
1706 ) = (left, right)
1707 {
1708 if sa == sb {
1709 return Ok(a.cmp(b));
1710 }
1711 }
1712 match (approximate(left), approximate(right)) {
1713 (Some(a), Some(b)) => Ok(float_order(a, b)),
1714 _ => Err(Error::not_implemented(format!(
1715 "comparing {} with {}",
1716 left.logical_type(),
1717 right.logical_type()
1718 ))),
1719 }
1720}
1721
1722fn float_order(left: f64, right: f64) -> Ordering {
1724 if left == right {
1725 return Ordering::Equal;
1726 }
1727 match (left.is_nan(), right.is_nan()) {
1728 (true, true) => Ordering::Equal,
1729 (true, false) => Ordering::Greater,
1730 (false, true) => Ordering::Less,
1731 (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
1732 }
1733}
1734
1735pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
1744 match (left.is_null(), right.is_null()) {
1745 (true, true) => Ok(Ordering::Equal),
1746 (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
1747 (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
1748 (false, false) => order(left, right),
1749 }
1750}
1751
1752#[cfg(test)]
1753mod tests {
1754 use super::*;
1755
1756 fn compared(op: Comparison, left: Value, right: Value) -> Value {
1757 compare_values(op, &left, &right).expect("these types compare")
1758 }
1759
1760 const EVERY: [Comparison; 8] = [
1762 Comparison::Equal,
1763 Comparison::NotEqual,
1764 Comparison::Less,
1765 Comparison::LessOrEqual,
1766 Comparison::Greater,
1767 Comparison::GreaterOrEqual,
1768 Comparison::DistinctFrom,
1769 Comparison::NotDistinctFrom,
1770 ];
1771
1772 fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
1778 let values: Vec<Value> = (0..left.len())
1779 .map(|index| {
1780 compare_values(op, &left.value_at(index), &right.value_at(index))
1781 .expect("the oracle is only asked about types that compare")
1782 })
1783 .collect();
1784 Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
1785 }
1786
1787 fn agrees(op: Comparison, left: &Vector, right: &Vector) {
1791 let fast = compare(op, left, right).expect("compares");
1792 let slow = oracle(op, left, right);
1793 assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
1794 }
1795
1796 fn agrees_and_selects(op: Comparison, left: &Vector, right: &Vector) {
1800 agrees(op, left, right);
1801 let slow = oracle(op, left, right);
1802 let picked = select_prepared(op, left, right, None).expect("selects");
1803 assert_eq!(
1804 picked.indices(),
1805 crate::select::selection(&slow, slow.len()).indices(),
1806 "{op:?} selected on a {:?} against a {:?}",
1807 left.form(),
1808 right.form()
1809 );
1810 }
1811
1812 struct Rng(u64);
1815
1816 impl Rng {
1817 fn next(&mut self) -> u64 {
1818 self.0 ^= self.0 << 13;
1819 self.0 ^= self.0 >> 7;
1820 self.0 ^= self.0 << 17;
1821 self.0
1822 }
1823
1824 fn below(&mut self, bound: u64) -> u64 {
1825 self.next() % bound
1826 }
1827 }
1828
1829 #[test]
1830 fn an_ordinary_comparison_is_null_when_either_side_is() {
1831 assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
1832 assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
1833 }
1834
1835 #[test]
1836 fn a_total_comparison_is_never_null() {
1837 assert_eq!(
1838 compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
1839 Value::Boolean(true)
1840 );
1841 assert_eq!(
1842 compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
1843 Value::Boolean(false)
1844 );
1845 assert_eq!(
1846 compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
1847 Value::Boolean(true)
1848 );
1849 }
1850
1851 #[test]
1852 fn a_string_compares_by_bytes() {
1853 assert_eq!(
1854 compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
1855 Value::Boolean(true)
1856 );
1857 assert_eq!(
1858 compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
1859 Value::Boolean(true)
1860 );
1861 }
1862
1863 #[test]
1866 fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
1867 assert_eq!(
1868 compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
1869 Value::Boolean(true)
1870 );
1871 assert_eq!(
1872 compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
1873 Value::Boolean(true)
1874 );
1875 }
1876
1877 #[test]
1878 fn zero_has_one_value_however_it_is_signed() {
1879 assert_eq!(
1880 compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
1881 Value::Boolean(true)
1882 );
1883 }
1884
1885 #[test]
1890 fn two_intervals_of_the_same_length_are_one_value() {
1891 let day = Value::Interval { months: 0, days: 1, micros: 0 };
1892 let hours = Value::Interval { months: 0, days: 0, micros: 86_400_000_000 };
1893 let month = Value::Interval { months: 1, days: 0, micros: 0 };
1894 let thirty = Value::Interval { months: 0, days: 30, micros: 0 };
1895 let long_day = Value::Interval { months: 0, days: 0, micros: 90_000_000_000 };
1896 assert_eq!(compared(Comparison::Equal, day.clone(), hours), Value::Boolean(true));
1897 assert_eq!(compared(Comparison::Equal, month, thirty), Value::Boolean(true));
1898 assert_eq!(compared(Comparison::Greater, long_day, day), Value::Boolean(true));
1899 }
1900
1901 #[test]
1902 fn a_number_compares_the_same_however_it_is_stored() {
1903 assert_eq!(
1904 compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
1905 Value::Boolean(true)
1906 );
1907 assert_eq!(
1908 compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
1909 Value::Boolean(true)
1910 );
1911 }
1912
1913 #[test]
1914 fn nulls_go_where_the_query_asked_for_them() {
1915 assert_eq!(
1916 order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
1917 Ordering::Less
1918 );
1919 assert_eq!(
1920 order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
1921 Ordering::Greater
1922 );
1923 }
1924
1925 #[test]
1926 fn two_constant_vectors_cost_one_comparison() {
1927 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
1928 let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
1929 let result = compare(Comparison::Less, &left, &right).expect("compares");
1930 assert_eq!(result.form(), Form::Constant);
1931 assert_eq!(result.value_at(500), Value::Boolean(true));
1932 }
1933
1934 #[test]
1935 fn a_comparison_of_two_vectors_is_one_answer_per_row() {
1936 let left = Vector::from_values(
1937 LogicalType::Integer,
1938 &[Value::Integer(1), Value::Integer(5), Value::Null],
1939 )
1940 .expect("three rows");
1941 let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
1942 let result = compare(Comparison::Greater, &left, &right).expect("compares");
1943 assert_eq!(result.value_at(0), Value::Boolean(false));
1944 assert_eq!(result.value_at(1), Value::Boolean(true));
1945 assert_eq!(result.value_at(2), Value::Null);
1946 }
1947
1948 #[test]
1949 fn two_vectors_of_different_lengths_are_caught() {
1950 let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1951 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
1952 let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
1953 assert!(error.message().contains("4 row vector"), "{error}");
1954 }
1955
1956 #[test]
1957 fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
1958 for op in EVERY {
1959 let left = Value::Integer(3);
1960 let right = Value::Integer(7);
1961 assert_eq!(
1962 compare_values(op, &left, &right).expect("compares"),
1963 compare_values(op.swapped(), &right, &left).expect("compares"),
1964 "{op:?}"
1965 );
1966 }
1967 }
1968
1969 #[test]
1972 fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
1973 let mut rng = Rng(0x5eed_1234_9876_4321);
1974 let types: [LogicalType; 11] = [
1975 LogicalType::Boolean,
1976 LogicalType::TinyInt,
1977 LogicalType::SmallInt,
1978 LogicalType::Integer,
1979 LogicalType::BigInt,
1980 LogicalType::HugeInt,
1981 LogicalType::UInteger,
1982 LogicalType::Float,
1983 LogicalType::Double,
1984 LogicalType::Varchar,
1985 LogicalType::Interval,
1986 ];
1987 for ty in &types {
1988 for nulls in [0u64, 1, 3] {
1989 let len = 37;
1990 let make = |rng: &mut Rng| {
1991 let values: Vec<Value> = (0..len)
1992 .map(|_| {
1993 if nulls > 0 && rng.below(nulls + 1) == 0 {
1994 Value::Null
1995 } else {
1996 sample(ty, rng)
1997 }
1998 })
1999 .collect();
2000 Vector::from_values(ty.clone(), &values).expect("a flat vector")
2001 };
2002 let left = make(&mut rng);
2003 let right = make(&mut rng);
2004 let literal = sample(ty, &mut rng);
2005 let constant = Vector::constant(ty.clone(), literal, len);
2006 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
2007 let codes: Vec<u32> =
2008 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
2009 let dictionary =
2010 Vector::dictionary(codes, left.clone()).expect("codes are in range");
2011 let ends: Vec<u32> = (1..=left.len())
2014 .map(|run| ((run * len) / left.len()).max(run) as u32)
2015 .collect();
2016 let runs =
2017 Vector::runs(ends.clone(), left.clone()).expect("one value for each run");
2018 let other_codes: Vec<u32> =
2022 (0..len).map(|_| rng.below(right.len() as u64) as u32).collect();
2023 let other_dictionary =
2024 Vector::dictionary(other_codes, right.clone()).expect("codes are in range");
2025 let other_runs = Vector::runs(ends, right.clone()).expect("one value for each run");
2026
2027 for op in EVERY {
2028 agrees_and_selects(op, &left, &right);
2029 agrees_and_selects(op, &left, &constant);
2030 agrees_and_selects(op, &constant, &left);
2031 agrees_and_selects(op, &left, &null_constant);
2032 agrees_and_selects(op, &null_constant, &left);
2033 agrees_and_selects(op, &dictionary, &constant);
2034 agrees_and_selects(op, &constant, &dictionary);
2035 agrees_and_selects(op, &dictionary, &right);
2039 agrees_and_selects(op, &right, &dictionary);
2040 agrees_and_selects(op, &runs, &constant);
2044 agrees_and_selects(op, &constant, &runs);
2045 agrees_and_selects(op, &runs, &right);
2046 agrees_and_selects(op, &right, &runs);
2047 agrees_and_selects(op, &dictionary, &other_dictionary);
2053 agrees_and_selects(op, &runs, &other_runs);
2054 agrees_and_selects(op, &dictionary, &other_runs);
2055 agrees_and_selects(op, &runs, &other_dictionary);
2056 }
2057 }
2058 }
2059 }
2060
2061 fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
2063 let mut out = Vec::new();
2064 for &row in kept.indices() {
2065 let index = row as usize;
2066 let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
2067 .expect("the oracle is only asked about types that compare");
2068 if is_true(&answer) {
2069 out.push(row);
2070 }
2071 }
2072 Selection::from_indices(out)
2073 }
2074
2075 fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
2076 let fast = refine(op, left, right, kept).expect("compares");
2077 assert_eq!(
2078 fast,
2079 refined(op, left, right, kept),
2080 "{op:?} on a {:?} against a {:?} over {} rows",
2081 left.form(),
2082 right.form(),
2083 kept.len()
2084 );
2085 }
2086
2087 #[test]
2091 fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
2092 let mut rng = Rng(0x5eed_4321_1234_9876);
2093 let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
2094 for ty in &types {
2095 for nulls in [0u64, 1, 3] {
2096 let len = 37;
2097 let make = |rng: &mut Rng| {
2098 let values: Vec<Value> = (0..len)
2099 .map(|_| {
2100 if nulls > 0 && rng.below(nulls + 1) == 0 {
2101 Value::Null
2102 } else {
2103 sample(ty, rng)
2104 }
2105 })
2106 .collect();
2107 Vector::from_values(ty.clone(), &values).expect("a flat vector")
2108 };
2109 let left = make(&mut rng);
2110 let right = make(&mut rng);
2111 let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
2112 let null_constant = Vector::constant(ty.clone(), Value::Null, len);
2113 let codes: Vec<u32> =
2114 (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
2115 let dictionary =
2116 Vector::dictionary(codes, left.clone()).expect("codes are in range");
2117
2118 let selections = [
2122 Selection::identity(len),
2123 Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
2124 Selection::from_indices(vec![2, 5, 6, 17, 36]),
2125 Selection::empty(),
2126 ];
2127 for op in EVERY {
2128 for kept in &selections {
2129 threads(op, &left, &right, kept);
2130 threads(op, &left, &constant, kept);
2131 threads(op, &constant, &left, kept);
2132 threads(op, &left, &null_constant, kept);
2133 threads(op, &null_constant, &left, kept);
2134 threads(op, &constant, &null_constant, kept);
2135 threads(op, &dictionary, &constant, kept);
2136 threads(op, &constant, &dictionary, kept);
2137 threads(op, &dictionary, &right, kept);
2138 threads(op, &right, &dictionary, kept);
2139 }
2140 }
2141 }
2142 }
2143 }
2144
2145 #[test]
2149 fn a_second_conjunct_reads_only_what_the_first_one_left() {
2150 let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
2151 let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
2152 let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
2153 let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
2154
2155 let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
2156 .expect("compares");
2157 let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
2158
2159 let expected: Vec<u32> = (0..64)
2160 .filter(|row| {
2161 let value = row % 10;
2162 value > 3 && value < 7
2163 })
2164 .collect();
2165 assert_eq!(both.indices(), expected.as_slice());
2166 assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
2167 }
2168
2169 #[test]
2173 fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
2174 let column = Vector::from_values(
2175 LogicalType::Integer,
2176 &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
2177 )
2178 .expect("four rows");
2179 let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
2180 let all = Selection::identity(4);
2181 assert_eq!(
2182 refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
2183 &[0]
2184 );
2185 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
2187 assert_eq!(
2188 refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
2189 &[1, 3]
2190 );
2191 }
2192
2193 #[test]
2194 fn a_selection_past_the_end_is_caught() {
2195 let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
2196 let past = Selection::from_indices(vec![0, 4]);
2197 let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
2198 assert!(error.message().contains("4 row vector"), "{error}");
2199 }
2200
2201 fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
2203 match ty {
2204 LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
2205 LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
2206 LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
2207 LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
2208 LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
2209 LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
2210 LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
2211 LogicalType::Float => Value::Float(match rng.below(5) {
2214 0 => f32::NAN,
2215 1 => -0.0,
2216 other => other as f32 - 2.0,
2217 }),
2218 LogicalType::Double => Value::Double(match rng.below(5) {
2219 0 => f64::NAN,
2220 1 => -0.0,
2221 other => other as f64 - 2.0,
2222 }),
2223 LogicalType::Interval => match rng.below(6) {
2227 0 => Value::Interval { months: 0, days: 1, micros: 0 },
2228 1 => Value::Interval { months: 0, days: 0, micros: 86_400_000_000 },
2229 2 => Value::Interval { months: 1, days: -29, micros: 86_400_000_000 },
2230 3 => Value::Interval { months: 1, days: 0, micros: 0 },
2231 4 => Value::Interval { months: 0, days: 0, micros: 90_000_000_000 },
2232 _ => Value::Interval { months: -1, days: 0, micros: 0 },
2233 },
2234 LogicalType::Varchar => Value::Varchar(
2237 match rng.below(6) {
2238 0 => "",
2239 1 => "ab",
2240 2 => "abc",
2241 3 => "abcdefghijkl",
2242 4 => "abcdefghijklm",
2243 _ => "abcdefghijklmnopqrstuvwxyz",
2244 }
2245 .to_owned(),
2246 ),
2247 other => panic!("the generator has no values for {other}"),
2248 }
2249 }
2250
2251 #[test]
2255 fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
2256 let words =
2257 ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
2258 let mut column = StringColumn::new();
2259 for word in words {
2260 column.push(word);
2261 }
2262 for (i, one) in words.iter().enumerate() {
2263 for (j, other) in words.iter().enumerate() {
2264 assert_eq!(
2265 string_order(&column, i, &column, j),
2266 one.as_bytes().cmp(other.as_bytes()),
2267 "{one:?} against {other:?}"
2268 );
2269 }
2270 }
2271 }
2272
2273 #[test]
2276 fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
2277 let values = Vector::from_values(
2278 LogicalType::Integer,
2279 &[Value::Integer(1), Value::Null, Value::Integer(9)],
2280 )
2281 .expect("three values");
2282 let dictionary =
2283 Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
2284 let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
2285 let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
2286 assert_eq!(result.value_at(0), Value::Boolean(true));
2287 assert_eq!(result.value_at(1), Value::Null);
2288 assert_eq!(result.value_at(2), Value::Boolean(false));
2289 assert_eq!(result.value_at(3), Value::Null);
2290 assert_eq!(result.value_at(4), Value::Boolean(true));
2291 }
2292
2293 #[test]
2302 fn an_ordering_on_text_against_a_literal_does_not_fall_back() {
2303 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
2304 let values = Vector::from_values(
2305 LogicalType::Varchar,
2306 &[Value::Varchar("apple".into()), Value::Null, Value::Varchar("pear".into())],
2307 )
2308 .expect("three values");
2309 let column = Vector::dictionary(vec![0, 1, 2, 0], values).expect("codes are in range");
2310 let cut = Vector::constant(LogicalType::Varchar, Value::Varchar("melon".into()), 4);
2311 let result = compare(Comparison::Less, &column, &cut).expect("compares");
2312 assert_eq!(result.value_at(0), Value::Boolean(true));
2313 assert_eq!(result.value_at(1), Value::Null);
2314 assert_eq!(result.value_at(2), Value::Boolean(false));
2315 assert_eq!(result.value_at(3), Value::Boolean(true));
2316 let other = compare(Comparison::Greater, &cut, &column).expect("compares");
2319 assert_eq!(other.value_at(0), Value::Boolean(true));
2320 assert_eq!(other.value_at(1), Value::Null);
2321 assert_eq!(other.value_at(2), Value::Boolean(false));
2322 let kept = refine(Comparison::GreaterOrEqual, &column, &cut, &Selection::identity(4))
2324 .expect("refines");
2325 assert_eq!(kept.indices(), [2]);
2326 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
2327 }
2328
2329 #[test]
2337 fn two_dictionary_columns_compared_with_each_other_do_not_fall_back() {
2338 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary);
2339 let dates = |values: &[Value]| {
2340 Vector::from_values(LogicalType::Date, values).expect("a flat date column")
2341 };
2342 let committed = Vector::dictionary(
2344 vec![0, 1, 0, 2],
2345 dates(&[Value::Date(10), Value::Date(20), Value::Date(30)]),
2346 )
2347 .expect("codes are in range");
2348 let received = Vector::dictionary(
2349 vec![0, 1, 2, 0],
2350 dates(&[Value::Date(15), Value::Null, Value::Date(5)]),
2351 )
2352 .expect("codes are in range");
2353 let result = compare(Comparison::Less, &committed, &received).expect("compares");
2354 assert_eq!(result.value_at(0), Value::Boolean(true), "10 < 15");
2355 assert_eq!(result.value_at(1), Value::Null, "20 against a null");
2356 assert_eq!(result.value_at(2), Value::Boolean(false), "10 against 5");
2357 assert_eq!(result.value_at(3), Value::Boolean(false), "30 against 15");
2358 let kept = refine(Comparison::Less, &committed, &received, &Selection::identity(4))
2360 .expect("refines");
2361 assert_eq!(kept.indices(), [0]);
2362 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary), before);
2363 }
2364
2365 #[test]
2368 fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
2369 let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
2371 let sequence = Vector::sequence(10, 1, 4);
2372 let flat = Vector::from_values(
2373 LogicalType::BigInt,
2374 &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
2375 )
2376 .expect("four rows");
2377 let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
2378 assert_eq!(result.value_at(0), Value::Boolean(false));
2379 assert_eq!(result.value_at(1), Value::Boolean(false));
2380 assert_eq!(result.value_at(2), Value::Boolean(false));
2381 assert_eq!(result.value_at(3), Value::Null);
2382 assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
2383 }
2384
2385 #[test]
2395 fn a_second_level_of_codes_does_not_turn_the_loops_off() {
2396 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
2397 let values = Vector::from_values(
2398 LogicalType::Integer,
2399 &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
2400 )
2401 .expect("three rows");
2402 let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
2403 let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
2404 let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
2405 let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
2406 assert_eq!(result.value_at(0), Value::Boolean(true));
2407 assert_eq!(result.value_at(1), Value::Boolean(false));
2408 assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
2409 }
2410
2411 #[test]
2415 fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
2416 let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
2417 let flat = Vector::from_values(
2418 LogicalType::Integer,
2419 &[
2420 Value::Integer(1),
2421 Value::Integer(2),
2422 Value::Integer(3),
2423 Value::Integer(4),
2424 Value::Integer(5),
2425 Value::Integer(6),
2426 ],
2427 )
2428 .expect("six rows");
2429 agrees(Comparison::Less, &nulls, &flat);
2430 agrees(Comparison::Equal, &flat, &nulls);
2431 assert_eq!(
2432 compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
2433 &Validity::AllInvalid
2434 );
2435 }
2436
2437 #[test]
2440 fn an_empty_comparison_is_an_empty_answer() {
2441 let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
2442 let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
2443 let result = compare(Comparison::Equal, &left, &right).expect("compares");
2444 assert_eq!(result.len(), 0);
2445 }
2446
2447 fn words() -> Vector {
2450 Vector::from_values(
2451 LogicalType::Varchar,
2452 &[
2453 Value::Varchar("http://a".into()),
2454 Value::Varchar("http://b".into()),
2455 Value::Null,
2456 Value::Varchar("ab".into()),
2457 Value::Varchar("http://a".into()),
2458 Value::Varchar("z".into()),
2459 ],
2460 )
2461 .expect("six rows")
2462 }
2463
2464 #[test]
2470 fn a_literal_built_early_answers_what_one_built_here_answers() {
2471 let column = words();
2472 let value = Value::Varchar("http://b".into());
2473 let constant = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
2474 let held = Held::of(&LogicalType::Varchar, &value).expect("a varchar has a column");
2475 let kept = Selection::from_indices(vec![0, 1, 3, 5]);
2476 for op in [
2477 Comparison::Equal,
2478 Comparison::NotEqual,
2479 Comparison::Less,
2480 Comparison::LessOrEqual,
2481 Comparison::Greater,
2482 Comparison::GreaterOrEqual,
2483 Comparison::DistinctFrom,
2484 Comparison::NotDistinctFrom,
2485 ] {
2486 let prepared = compare_prepared(op, &column, &constant, Some(&held)).expect("compares");
2487 assert_eq!(prepared, compare(op, &column, &constant).expect("compares"), "{op:?}");
2488 let flipped = compare_prepared(op, &constant, &column, Some(&held)).expect("compares");
2490 assert_eq!(flipped, compare(op, &constant, &column).expect("compares"), "{op:?}");
2491 let refined =
2492 refine_prepared(op, &column, &constant, &kept, Some(&held)).expect("refines");
2493 assert_eq!(refined, refine(op, &column, &constant, &kept).expect("refines"), "{op:?}");
2494 }
2495 }
2496
2497 #[test]
2504 fn a_literal_built_for_another_value_is_ignored() {
2505 let column = words();
2506 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("z".into()), 6);
2507 let wrong = Held::of(&LogicalType::Varchar, &Value::Varchar("ab".into()))
2508 .expect("a varchar has a column");
2509 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&wrong))
2510 .expect("compares");
2511 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
2512 let other = Held::of(&LogicalType::Integer, &Value::Integer(1)).expect("an integer column");
2515 let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&other))
2516 .expect("compares");
2517 assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
2518 }
2519
2520 #[test]
2523 fn a_packed_column_against_a_constant_answers_what_the_oracle_answers() {
2524 let values: Vec<i32> = (0..64).map(|row| 1000 + (row * 37) % 500).collect();
2525 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
2526 .expect("integers are an i32 layout");
2527 let packed = flat.bit_packed().expect("a five hundred wide range packs");
2528 assert_eq!(packed.form(), Form::BitPacked);
2529 for literal in [999, 1000, 1200, 1499, 1500, 2000] {
2530 let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 64);
2531 for op in EVERY {
2532 agrees(op, &packed, &constant);
2533 agrees(op, &constant, &packed);
2534 }
2535 }
2536 }
2537
2538 #[test]
2542 fn a_packed_column_with_nulls_answers_what_the_oracle_answers() {
2543 let values: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
2544 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
2545 .expect("integers are an i32 layout")
2546 .with_validity(Validity::from_iter(32, |row| row % 5 != 0));
2547 let packed = flat.bit_packed().expect("packs");
2548 let constant = Vector::constant(LogicalType::Integer, Value::Integer(80), 32);
2549 for op in EVERY {
2550 agrees(op, &packed, &constant);
2551 }
2552 }
2553
2554 #[test]
2557 fn a_literal_outside_the_packed_range_answers_the_whole_vector_at_once() {
2558 let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant);
2559 let values: Vec<i32> = (0..16).map(|row| 500 + row).collect();
2560 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
2561 .expect("integers are an i32 layout");
2562 let packed = flat.bit_packed().expect("packs");
2563 let literals = [-1, 0, 499, 516, 100_000];
2564 for literal in literals {
2565 let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 16);
2566 for op in EVERY {
2567 agrees(op, &packed, &constant);
2568 }
2569 }
2570 let total = EVERY.iter().filter(|op| op.is_total()).count();
2575 assert_eq!(
2576 fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant) - before,
2577 (literals.len() * total) as u64,
2578 "only the two total comparisons fall through"
2579 );
2580 }
2581
2582 #[test]
2585 fn refining_a_selection_over_a_packed_column_keeps_the_same_rows() {
2586 let values: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
2587 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into()))
2588 .expect("integers are an i32 layout");
2589 let packed = flat.bit_packed().expect("packs");
2590 let kept = Selection::from_predicate(64, |row| row % 3 == 0);
2591 let constant = Vector::constant(LogicalType::Integer, Value::Integer(260), 64);
2592 let packed_rows = refine(Comparison::Greater, &packed, &constant, &kept).expect("refines");
2593 let flat_rows = refine(Comparison::Greater, &flat, &constant, &kept).expect("refines");
2594 assert_eq!(packed_rows.indices(), flat_rows.indices());
2595 assert!(!packed_rows.is_empty(), "the literal is inside the range");
2596 }
2597
2598 #[test]
2602 fn two_packed_columns_against_each_other_answer_what_the_oracle_answers() {
2603 let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::BitPacked);
2604 let one: Vec<i32> = (0..64).map(|row| 9000 + (row * 37) % 500).collect();
2605 let other: Vec<i32> = (0..64).map(|row| 9200 + (row * 53) % 400).collect();
2606 let left = Vector::flat(LogicalType::Integer, Data::Int32(one.into()))
2607 .expect("integers are an i32 layout")
2608 .bit_packed()
2609 .expect("a five hundred wide range packs");
2610 let right = Vector::flat(LogicalType::Integer, Data::Int32(other.into()))
2611 .expect("integers are an i32 layout")
2612 .bit_packed()
2613 .expect("a four hundred wide range packs");
2614 assert_eq!(left.form(), Form::BitPacked);
2615 assert_eq!(right.form(), Form::BitPacked);
2616 assert_ne!(
2617 left.packed_parts().expect("packed").base(),
2618 right.packed_parts().expect("packed").base(),
2619 "the two bases are the two column minimums and this test wants them apart"
2620 );
2621 for op in EVERY {
2622 agrees(op, &left, &right);
2623 agrees(op, &right, &left);
2624 }
2625 let total = EVERY.iter().filter(|op| op.is_total()).count();
2629 assert_eq!(
2630 fallback::count(Kernel::Compare, Form::BitPacked, Form::BitPacked) - before,
2631 (total * 2) as u64,
2632 "only the two total comparisons fall through"
2633 );
2634 }
2635
2636 #[test]
2639 fn two_packed_columns_whose_ranges_do_not_overlap_answer_the_whole_vector_at_once() {
2640 let one: Vec<i32> = (0..32).map(|row| 100 + row).collect();
2641 let other: Vec<i32> = (0..32).map(|row| 500 + row * 2).collect();
2642 let low = Vector::flat(LogicalType::Integer, Data::Int32(one.into()))
2643 .expect("integers are an i32 layout")
2644 .bit_packed()
2645 .expect("packs");
2646 let high = Vector::flat(LogicalType::Integer, Data::Int32(other.into()))
2647 .expect("integers are an i32 layout")
2648 .bit_packed()
2649 .expect("packs");
2650 for op in EVERY {
2651 agrees(op, &low, &high);
2652 agrees(op, &high, &low);
2653 }
2654 }
2655
2656 #[test]
2660 fn two_packed_columns_with_nulls_answer_what_the_oracle_answers() {
2661 let one: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
2662 let other: Vec<i32> = (0..32).map(|row| 60 + row * 2).collect();
2663 let left = Vector::flat(LogicalType::Integer, Data::Int32(one.into()))
2664 .expect("integers are an i32 layout")
2665 .with_validity(Validity::from_iter(32, |row| row % 5 != 0))
2666 .bit_packed()
2667 .expect("packs");
2668 let right = Vector::flat(LogicalType::Integer, Data::Int32(other.into()))
2669 .expect("integers are an i32 layout")
2670 .with_validity(Validity::from_iter(32, |row| row % 3 != 0))
2671 .bit_packed()
2672 .expect("packs");
2673 for op in EVERY {
2674 agrees(op, &left, &right);
2675 }
2676 }
2677
2678 #[test]
2683 fn a_dictionary_over_a_packed_run_answers_what_the_oracle_answers() {
2684 let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary);
2685 let distinct = |start: i32, step: i32, nulls: usize| {
2686 let values: Vec<i32> = (0..24).map(|row| start + row * step).collect();
2687 Vector::flat(LogicalType::Date, Data::Int32(values.into()))
2688 .expect("dates are an i32 layout")
2689 .with_validity(Validity::from_iter(24, |row| row % nulls != 0))
2690 .bit_packed()
2691 .expect("packs")
2692 };
2693 let codes =
2694 |seed: usize| -> Vec<u32> { (0..64).map(|row| ((row * seed) % 24) as u32).collect() };
2695 let one = Vector::dictionary(codes(7), distinct(9_000, 3, 5)).expect("codes are in range");
2696 let other =
2697 Vector::dictionary(codes(5), distinct(9_020, 2, 7)).expect("codes are in range");
2698 let straight = Vector::flat(
2699 LogicalType::Date,
2700 Data::Int32((0..64).map(|row| 9_010 + row).collect::<Vec<i32>>().into()),
2701 )
2702 .expect("dates are an i32 layout")
2703 .bit_packed()
2704 .expect("packs");
2705 assert_eq!(one.form(), Form::Dictionary);
2706 assert_eq!(straight.form(), Form::BitPacked);
2707 for op in EVERY {
2708 agrees(op, &one, &other);
2709 agrees(op, &one, &straight);
2710 agrees(op, &straight, &other);
2711 }
2712 let total = EVERY.iter().filter(|op| op.is_total()).count();
2714 assert_eq!(
2715 fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary) - before,
2716 total as u64,
2717 "only the two total comparisons fall through"
2718 );
2719 }
2720
2721 #[test]
2730 fn a_packed_column_against_a_flat_one_answers_what_the_oracle_answers() {
2731 let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Flat);
2732 let dates = |start: i32, step: i32, nulls: usize| {
2733 Vector::flat(
2734 LogicalType::Date,
2735 Data::Int32((0..64).map(|row| start + row * step).collect::<Vec<i32>>().into()),
2736 )
2737 .expect("dates are an i32 layout")
2738 .with_validity(Validity::from_iter(64, |row| row % nulls != 0))
2739 };
2740 let codes =
2741 |seed: usize| -> Vec<u32> { (0..64).map(|row| ((row * seed) % 64) as u32).collect() };
2742 let packed = dates(9_000, 3, 5).bit_packed().expect("packs");
2743 let flat = dates(9_040, 2, 7);
2744 let over_packed = Vector::dictionary(codes(7), packed.clone()).expect("codes are in range");
2745 let over_flat = Vector::dictionary(codes(11), flat.clone()).expect("codes are in range");
2746 assert_eq!(packed.form(), Form::BitPacked);
2747 assert_eq!(flat.form(), Form::Flat);
2748 assert!(packed.packed_parts().expect("packed").base() < 9_040 + 63 * 2);
2751 for op in EVERY {
2752 agrees(op, &packed, &flat);
2753 agrees(op, &flat, &packed);
2754 agrees(op, &packed, &over_flat);
2755 agrees(op, &over_packed, &flat);
2756 agrees(op, &over_packed, &over_flat);
2757 }
2758 let total = EVERY.iter().filter(|op| op.is_total()).count();
2761 assert_eq!(
2762 fallback::count(Kernel::Compare, Form::BitPacked, Form::Flat) - before,
2763 total as u64,
2764 "only the two total comparisons fall through"
2765 );
2766 }
2767
2768 #[test]
2772 fn refining_a_selection_over_two_packed_columns_keeps_the_same_rows() {
2773 let one: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
2774 let other: Vec<i32> = (0..64).map(|row| 240 + (row * 17) % 96).collect();
2775 let left = Vector::flat(LogicalType::Integer, Data::Int32(one.clone().into()))
2776 .expect("integers are an i32 layout");
2777 let right = Vector::flat(LogicalType::Integer, Data::Int32(other.clone().into()))
2778 .expect("integers are an i32 layout");
2779 let kept = Selection::from_predicate(64, |row| row % 3 == 0);
2780 let packed_rows = refine(
2781 Comparison::Less,
2782 &left.bit_packed().expect("packs"),
2783 &right.bit_packed().expect("packs"),
2784 &kept,
2785 )
2786 .expect("refines");
2787 let flat_rows = refine(Comparison::Less, &left, &right, &kept).expect("refines");
2788 assert_eq!(packed_rows.indices(), flat_rows.indices());
2789 assert!(!packed_rows.is_empty(), "the two ranges overlap");
2790 }
2791
2792 fn urls(count: usize) -> Vector {
2795 let mut rng = Rng(0x5eed_1234);
2796 let values: Vec<Value> = (0..count)
2797 .map(|_| {
2798 let host = rng.below(6);
2799 let path = rng.below(40);
2800 Value::Varchar(format!("http://example{host}.test/a/rather/long/path/{path}"))
2801 })
2802 .collect();
2803 Vector::from_values(LogicalType::Varchar, &values).expect("strings")
2804 }
2805
2806 #[test]
2807 fn a_string_view_column_against_a_literal_answers_what_the_oracle_answers() {
2808 let before = fallback::count(Kernel::Compare, Form::StringView, Form::Constant);
2809 let shared = urls(64).shared_text().expect("shares");
2810 assert_eq!(shared.form(), Form::StringView);
2811 let literals = ["http://example3.test/a/rather/long/path/7", "a", "zzz", ""];
2812 for literal in literals {
2813 let value = Value::Varchar(literal.to_owned());
2814 let constant = Vector::constant(LogicalType::Varchar, value, 64);
2815 for op in EVERY {
2816 agrees(op, &shared, &constant);
2817 agrees(op, &constant, &shared);
2818 }
2819 }
2820 assert_eq!(
2821 fallback::count(Kernel::Compare, Form::StringView, Form::Constant),
2822 before,
2823 "the form has a loop of its own for every comparison"
2824 );
2825 }
2826
2827 #[test]
2828 fn a_string_view_column_against_another_one_answers_what_the_oracle_answers() {
2829 let shared = urls(48).shared_text().expect("shares");
2830 let other = urls(48).shared_text().expect("shares");
2831 let flat = urls(48);
2832 for op in EVERY {
2833 agrees(op, &shared, &other);
2834 agrees(op, &shared, &flat);
2835 agrees(op, &flat, &shared);
2836 }
2837 }
2838
2839 #[test]
2840 fn the_nulls_of_a_string_view_column_are_the_nulls_the_oracle_sees() {
2841 let shared = urls(32)
2842 .with_validity(Validity::from_iter(32, |row| row % 4 != 1))
2843 .shared_text()
2844 .expect("shares");
2845 let constant =
2846 Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 32);
2847 for op in EVERY {
2848 agrees(op, &shared, &constant);
2849 }
2850 }
2851
2852 #[test]
2853 fn a_compressed_column_against_a_literal_answers_what_the_oracle_answers() {
2854 let before = fallback::count(Kernel::Compare, Form::Fsst, Form::Constant);
2855 let flat = urls(64);
2856 let coded = flat.clone().compressed().expect("compresses");
2857 assert_eq!(coded.form(), Form::Fsst);
2858 let present = match coded.value_at(9) {
2859 Value::Varchar(text) => text,
2860 other => panic!("a string column reads back strings, not {other:?}"),
2861 };
2862 for literal in [present.as_str(), "http://example3.test/nothing/like/it", ""] {
2863 let value = Value::Varchar(literal.to_owned());
2864 let constant = Vector::constant(LogicalType::Varchar, value, 64);
2865 for op in EVERY {
2866 agrees(op, &coded, &constant);
2867 agrees(op, &constant, &coded);
2868 }
2869 }
2870 let ordered = EVERY.len() - 2;
2874 assert_eq!(
2875 fallback::count(Kernel::Compare, Form::Fsst, Form::Constant) - before,
2876 (3 * ordered) as u64,
2877 "only the comparisons that need an order fall through"
2878 );
2879 }
2880
2881 #[test]
2884 fn every_row_of_a_compressed_column_matches_itself_and_nothing_else() {
2885 let flat = urls(48);
2886 let coded = flat.clone().compressed().expect("compresses");
2887 for row in 0..48 {
2888 let constant = Vector::constant(LogicalType::Varchar, flat.value_at(row), 48);
2889 let equal = compare(Comparison::Equal, &coded, &constant).expect("compares");
2890 for other in 0..48 {
2891 let want = flat.value_at(other) == flat.value_at(row);
2892 assert_eq!(
2893 equal.value_at(other),
2894 Value::Boolean(want),
2895 "row {row} against {other}"
2896 );
2897 }
2898 }
2899 }
2900
2901 #[test]
2902 fn the_nulls_of_a_compressed_column_are_the_nulls_the_oracle_sees() {
2903 let coded = urls(32)
2904 .with_validity(Validity::from_iter(32, |row| row % 3 != 0))
2905 .compressed()
2906 .expect("compresses");
2907 let value = coded.value_at(1);
2908 let constant = Vector::constant(LogicalType::Varchar, value, 32);
2909 for op in EVERY {
2910 agrees(op, &coded, &constant);
2911 }
2912 }
2913
2914 #[test]
2918 fn a_filter_over_either_string_form_keeps_the_same_rows() {
2919 let flat = urls(96);
2920 let shared = flat.clone().shared_text().expect("shares");
2921 let constant =
2922 Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 96);
2923 let kept = Selection::from_predicate(96, |row| row % 5 != 0);
2924 for op in EVERY {
2925 let over_flat = refine(op, &flat, &constant, &kept).expect("refines");
2926 let over_shared = refine(op, &shared, &constant, &kept).expect("refines");
2927 assert_eq!(over_shared.indices(), over_flat.indices(), "{op:?}");
2928 }
2929 }
2930
2931 #[test]
2935 fn a_comparison_peeled_over_a_shared_dictionary_answers_what_the_oracle_answers() {
2936 let words = ["", "one", "two", "", "three"];
2937 let values: Vec<Value> = words.iter().map(|text| Value::Varchar((*text).into())).collect();
2938 let values =
2939 Arc::new(Vector::from_values(LogicalType::Varchar, &values).expect("a vector of text"));
2940 let codes = vec![0, 1, 3, 2, 0, 4, 1, 0];
2941 let column = Vector::stable_dictionary(codes.clone(), values).expect("codes are in range");
2942 same_as_the_oracle(&column);
2943 }
2944
2945 #[derive(Debug)]
2948 struct Filed {
2949 values: Vec<Vec<u8>>,
2950 order: Vec<u32>,
2951 ranked: std::sync::OnceLock<Option<Vec<u32>>>,
2953 }
2954
2955 impl rudb_vector::TextSource for Filed {
2956 fn len(&self) -> usize {
2957 self.values.len()
2958 }
2959
2960 fn bytes_at(&self, index: usize) -> Result<Option<&[u8]>> {
2961 Ok(self.values.get(index).map(Vec::as_slice))
2962 }
2963
2964 fn footprint(&self) -> usize {
2965 self.values.iter().map(Vec::len).sum()
2966 }
2967
2968 fn ranks(&self) -> Option<usize> {
2969 Some(self.order.len())
2970 }
2971
2972 fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
2973 Ok(self.values[self.order[rank] as usize].as_slice().cmp(wanted))
2976 }
2977
2978 fn code_at_rank(&self, rank: usize) -> Result<u32> {
2979 Ok(self.order[rank])
2980 }
2981
2982 fn code_ranks(&self) -> Option<&[u32]> {
2983 self.ranked
2984 .get_or_init(|| {
2985 let mut ranks = vec![0; self.order.len()];
2986 for (rank, &code) in self.order.iter().enumerate() {
2987 ranks[code as usize] = rank as u32;
2988 }
2989 Some(ranks)
2990 })
2991 .as_deref()
2992 }
2993 }
2994
2995 #[test]
2998 fn a_comparison_against_a_sorted_dictionary_answers_what_the_oracle_answers() {
2999 let (column, _) = filed(&["", "one", "two", "four", "three"], vec![0, 1, 3, 2, 0, 4, 1, 0]);
3002 same_as_the_oracle(&column);
3003 }
3004
3005 fn filed(words: &[&str], codes: Vec<u32>) -> (Vector, Arc<Vector>) {
3008 let values: Vec<Vec<u8>> = words.iter().map(|text| text.as_bytes().to_vec()).collect();
3009 let mut order = (0..values.len() as u32).collect::<Vec<_>>();
3010 order.sort_by(|&left, &right| values[left as usize].cmp(&values[right as usize]));
3011 let dictionary = Arc::new(
3012 Vector::external_text(
3013 LogicalType::Varchar,
3014 Arc::new(Filed { values, order, ranked: std::sync::OnceLock::new() }),
3015 )
3016 .expect("a filed vector"),
3017 );
3018 let column =
3019 Vector::stable_dictionary(codes, Arc::clone(&dictionary)).expect("codes are in range");
3020 (column, dictionary)
3021 }
3022
3023 #[test]
3026 fn a_comparison_against_a_known_rank_keeps_what_a_search_for_it_keeps() {
3027 let (column, dictionary) =
3028 filed(&["", "one", "two", "four", "three"], vec![0, 1, 3, 2, 0, 4, 1, 0]);
3029 let rows = column.len();
3030 for row in 0..rows {
3031 let (held, rank) = rank_at(&column, row).expect("a row of a ranked dictionary");
3032 assert!(Arc::ptr_eq(&held, &dictionary), "the dictionary it came from");
3033 let value = column.try_value_at(row).expect("a value");
3034 for op in [
3035 Comparison::Less,
3036 Comparison::LessOrEqual,
3037 Comparison::Greater,
3038 Comparison::GreaterOrEqual,
3039 ] {
3040 let against = Vector::constant(LogicalType::Varchar, value.clone(), rows);
3041 let flags = compare(op, &column, &against).expect("the search path answers");
3042 let wanted = crate::select::selection(&flags, rows);
3043 let got = select_against_rank(op, &column, &dictionary, rank, rows)
3044 .expect("the rank path answers");
3045 assert_eq!(got.indices(), wanted.indices(), "row {row} under {op:?}");
3046 }
3047 }
3048 }
3049
3050 #[test]
3053 fn a_rank_offered_against_another_dictionary_is_declined() {
3054 let (column, dictionary) = filed(&["one", "two"], vec![0, 1]);
3055 let (other, _) = filed(&["one", "two"], vec![1, 0]);
3056 assert!(select_against_rank(Comparison::Less, &column, &dictionary, 1, 2).is_some());
3057 assert!(select_against_rank(Comparison::Less, &other, &dictionary, 1, 2).is_none());
3058 let flat = Vector::constant(LogicalType::Varchar, Value::Varchar("one".into()), 2);
3059 assert!(select_against_rank(Comparison::Less, &flat, &dictionary, 1, 2).is_none());
3060 assert!(rank_at(&flat, 0).is_none(), "a column with no dictionary has no ranks");
3061 assert!(rank_within(&other, 0, &dictionary).is_none(), "another dictionary says nothing");
3062 assert!(rank_within(&flat, 0, &dictionary).is_none(), "no dictionary says nothing");
3063 }
3064
3065 #[test]
3068 fn two_ranks_in_one_dictionary_order_their_values() {
3069 let (column, dictionary) =
3070 filed(&["", "one", "two", "four", "three"], vec![0, 1, 3, 2, 0, 4, 1, 0]);
3071 let rows = column.len();
3072 for left in 0..rows {
3073 for right in 0..rows {
3074 let here = rank_within(&column, left, &dictionary).expect("a ranked row");
3075 let there = rank_within(&column, right, &dictionary).expect("a ranked row");
3076 let values = (
3077 column.try_value_at(left).expect("a value"),
3078 column.try_value_at(right).expect("a value"),
3079 );
3080 let wanted = order(&values.0, &values.1).expect("two strings compare");
3081 assert_eq!(here.cmp(&there), wanted, "rows {left} and {right}");
3082 let (held, rank) = rank_at(&column, left).expect("a ranked row");
3083 assert!(Arc::ptr_eq(&held, &dictionary), "the dictionary it came from");
3084 assert_eq!(rank, here, "the same rank whichever way it is asked for");
3085 }
3086 }
3087 }
3088
3089 fn same_as_the_oracle(column: &Vector) {
3093 for literal in ["", "one", "missing", "zzz"] {
3094 for op in [
3095 Comparison::Equal,
3096 Comparison::NotEqual,
3097 Comparison::Less,
3098 Comparison::LessOrEqual,
3099 Comparison::Greater,
3100 Comparison::GreaterOrEqual,
3101 ] {
3102 let value = Value::Varchar(literal.to_owned());
3103 let held = Held::of(&LogicalType::Varchar, &value).expect("text has a column");
3104 let right = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
3105 let wanted = oracle(op, column, &right);
3106 let got = compare_prepared(op, column, &right, Some(&held))
3107 .expect("the peeled path answers");
3108 assert_eq!(got, wanted, "{literal:?} under {op:?}");
3109 let held = Held::of(&LogicalType::Varchar, &value).expect("text has a column");
3110 let picked = select_prepared(op, column, &right, Some(&held))
3111 .expect("the peeled path selects");
3112 assert_eq!(
3113 picked.indices(),
3114 crate::select::selection(&wanted, column.len()).indices(),
3115 "{literal:?} under {op:?}, selected"
3116 );
3117 let held = Held::of(&LogicalType::Varchar, &value).expect("text has a column");
3119 let kept = Selection::from_predicate(column.len(), |row| row % 3 != 1);
3120 let refined = refine_prepared(op, column, &right, &kept, Some(&held))
3121 .expect("the peeled path narrows");
3122 let wanted: Vec<u32> = kept
3123 .indices()
3124 .iter()
3125 .copied()
3126 .filter(|&row| is_true(&wanted.value_at(row as usize)))
3127 .collect();
3128 assert_eq!(refined.indices(), wanted, "{literal:?} under {op:?}, narrowed");
3129 }
3130 }
3131 }
3132}