Skip to main content

rudb_kernels/
compare.rs

1//! Comparing values, which is where SQL's three-valued logic actually lives.
2//!
3//! Six of the eight comparisons return null when either side is null, and the other two never do.
4//! That is not a detail: `WHERE a = b` drops a row where either is null and `WHERE a IS NOT
5//! DISTINCT FROM b` keeps the row where both are, and the binder produces the second one for `IS
6//! NULL` and for a `USING` join under some rewrites. One enum with the null rule attached to the
7//! variant is what stops that difference from being re-decided in every operator.
8//!
9//! The comparison enum here is this crate's own rather than `rudb_plan`'s, because the plan sits
10//! nine ranks above the kernels and a kernel that imports a plan type is a kernel that cannot be
11//! called from anywhere else. The executor maps one to the other, which is four lines it writes
12//! once.
13//!
14//! Float comparison is DuckDB's rather than IEEE's. Two NaNs are equal, NaN sorts above every
15//! number, and negative zero equals zero. IEEE says the first is false and that a NaN comparison is
16//! unordered, which would make `GROUP BY` over a column with a NaN in it produce a group nothing
17//! can ever find again and make a sort's result depend on the order the rows arrived in.
18//!
19//! # How the vectorized path is put together
20//!
21//! `spec/engine/03-data-plane.md` opens with this file as the example of what layer one is for.
22//! What it used to be was a loop from zero to length calling `value_at` on both sides, comparing
23//! two owned `Value`s and pushing into a `Vec<Value>` that a second pass then walked to pack into a
24//! vector. On a varchar column that is a heap allocation and a memcpy per row per side, plus a
25//! match on the operator inside the loop that the compiler has no way to hoist.
26//!
27//! What it is now is three decisions taken once per vector and then a loop that does one thing.
28//!
29//! The first decision is the form pair. Flat against flat, flat against constant and dictionary
30//! against constant each get a hand written path, because those three are what a filter on a scan
31//! actually produces. Constant on the left is the same code with the comparison turned around,
32//! which [`Comparison::swapped`] does, so there is one loop rather than two. Everything else falls
33//! through to the row at a time path, which is still here, is still correct, and now increments a
34//! counter in [`crate::fallback`] on the way past so that a combination worth specializing shows up
35//! as a number rather than as an opinion.
36//!
37//! The second decision is the physical type, which a macro turns into one loop per layout. Fifteen
38//! layouts by three form pairs by eight operators written out by hand is how a wrong answer gets
39//! in, and it is also four thousand lines nobody reads.
40//!
41//! The third decision is the operator, hoisted out of the loop once. The eight operators
42//! become eight monomorphized loops over the same ordering, each with a comparison against a
43//! constant `Ordering` in it, which is what makes the body a compare and a store.
44//!
45//! Validity gets its three cases used rather than collapsed. Two all valid sides skip the mask
46//! entirely and produce an all valid result. Either side all invalid, on one of the six ordinary
47//! comparisons, is every answer null without reading the data at all, which is a real case because
48//! it is what a constant `NULL` in a predicate is.
49//!
50//! A conjunct that is not the first one does not need every row. [`refine`] is the same three
51//! decisions with the output position mapped through the selection the conjuncts before it left, so
52//! every loop in this file serves the threaded path without being written twice. The mapping is a
53//! generic parameter rather than a function in a field, because an index mapping the compiler cannot
54//! see through is an indirect call in a loop that is otherwise three instructions.
55//!
56//! Strings resolve from the four byte prefix in the view. Two views whose prefixes differ are in
57//! that order, which holds because the payload past the end of a short string is zero and zero is
58//! the least byte, so prefix order is byte order whenever the prefixes are not equal. On `hits` the
59//! columns that carry the file are `URL` and `Referer`, and a filter on either of them is now a
60//! four byte compare on almost every row instead of a `String` being built to be thrown away.
61//!
62//! # What is still slow here
63//!
64//! The index into each side goes through a closure so that the same macro serves flat, constant and
65//! dictionary, which means the bounds check on each access survives. That is a known cost and it is
66//! next to nothing beside the allocation it replaced, but it is the reason this file will not hit
67//! the one nanosecond per row target on its own. The way out is a slice narrowed to the vector
68//! length on the identity path, and that wants the benchmark suite to exist first so that the
69//! change is a number rather than a belief.
70
71use 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/// Which comparison.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
87pub enum Comparison {
88    /// `=`, null if either side is null.
89    Equal,
90    /// `<>`, null if either side is null.
91    NotEqual,
92    /// `<`, null if either side is null.
93    Less,
94    /// `<=`, null if either side is null.
95    LessOrEqual,
96    /// `>`, null if either side is null.
97    Greater,
98    /// `>=`, null if either side is null.
99    GreaterOrEqual,
100    /// `IS DISTINCT FROM`, which is total and never null.
101    DistinctFrom,
102    /// `IS NOT DISTINCT FROM`, which is total and never null.
103    NotDistinctFrom,
104}
105
106impl Comparison {
107    /// Whether this comparison treats null as a value rather than as an absence.
108    #[must_use]
109    pub fn is_total(self) -> bool {
110        matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
111    }
112
113    /// The comparison that means the same thing with the two sides exchanged.
114    ///
115    /// This is what halves the number of specialized loops. A constant on the left against a
116    /// column on the right is the column against the constant with the inequality turned around,
117    /// and writing it that way means the column against constant loop is written once and tested
118    /// once rather than twice with a chance of the second one being subtly wrong.
119    #[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
131/// Compares two vectors of the same length, producing a `BOOLEAN` vector.
132///
133/// # Errors
134///
135/// If the two sides are not the same length, or if the two types cannot be compared.
136pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
137    compare_prepared(op, left, right, None)
138}
139
140/// [`compare`], with the constant side already turned into the column the loops read it through.
141///
142/// The same body and the same answer. A caller that built the plan knows which side is a literal
143/// and can hand a [`Held`] built once for the query, which saves the allocations that building it
144/// per chunk costs. A caller that has no plan in front of it passes `None` and nothing changes.
145///
146/// # Errors
147///
148/// The same ones [`compare`] gives.
149pub 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    // Either side entirely null, on one of the six ordinary comparisons, is every answer null and
170    // the data is never read. This is not a corner case: a `NULL` literal in a predicate is a
171    // constant vector whose validity is exactly this, and so is a column the scan knows is empty.
172    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    // row at a time: the path recorded on the line above, which exists to be correct for a pair of
190    // forms no specialization covers and counts itself so that pair shows up in the report.
191    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
197/// The rows of `kept` the comparison also keeps.
198///
199/// This is [`compare`] for a conjunct that is not the first one. A filter with four conjuncts
200/// evaluated the obvious way runs all four over every row, so on TPC-H Q6, where each conjunct
201/// passes about a fifth of the rows and the four together pass about two percent, the last conjunct
202/// does fifty times the work it needs to. Handing it the rows the earlier ones kept is the whole
203/// difference, and it is a difference that grows with the number of conjuncts rather than washing
204/// out.
205///
206/// The answer is the rows of `kept`, in the order `kept` has them, for which the comparison is true.
207/// Null is not true, so a row whose either side is null is dropped on the six ordinary comparisons,
208/// which is the same rule [`crate::select::selection`] applies to a flag vector and the reason both
209/// of them are a kernel rather than a line at the call site.
210///
211/// # Errors
212///
213/// If the two sides are not the same length, or if a position in `kept` is past the end of them.
214pub 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
223/// [`refine`], with the constant side already built, for the reason [`compare_prepared`] gives.
224///
225/// This is the one that gains the most from it. A conjunct after the first reads the rows the ones
226/// before it kept, so the loop can be eleven rows long while the setup is the same size it would be
227/// for a full chunk.
228///
229/// # Errors
230///
231/// The same ones [`refine`] gives.
232pub 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    // One vectorized pass over a run of `u32` before any of the loops below index with them, which
248    // is what turns a caller's mistake into this message rather than into a panic from inside a
249    // macro generated loop eight frames down.
250    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        // A total comparison has the nulls in the answer already, and two all valid sides have no
273        // null to drop, so both of those get the loop with nothing in it but the flag.
274        if op.is_total() || (left_valid == Validity::AllValid && right_valid == Validity::AllValid)
275        {
276            return Ok(narrowed(&answers, rows, |_| true));
277        }
278        // A bit at a time rather than a word at a time, which is the one place this path gives up
279        // something `compare` has. The rows are scattered by construction, so the two mask reads for
280        // one row are in different words as often as not and a word oriented loop would reread them.
281        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    // row at a time: the path recorded on the line above, for a pair of forms no specialization
290    // covers, reading only the rows the conjuncts before this one kept.
291    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
300/// The positions of `rows` whose answer is true and whose row is live, without a branch per row.
301///
302/// The same shape as the loop in `crate::select` and for the same reason: which rows a filter keeps is
303/// what the data decides rather than what the code does, so the branch is unpredictable by
304/// construction and a mispredict is worth more than the rest of the loop put together. Every slot
305/// writes its row at the current length and only a slot that is kept moves the length on.
306fn 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        // A single `&` rather than `&&`, because the short circuit would put back the branch.
312        count += usize::from(answer & live(slot));
313    }
314    out.truncate(count);
315    Selection::from_indices(out)
316}
317
318/// A `BOOLEAN` vector from a run of answers and the validity that says which of them count.
319fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
320    // An empty vector has no null to record, and `Vector::from_values` normalizes the empty mask it
321    // builds to all valid, so saying the same here is what keeps an empty specialized result the
322    // same vector as the oracle's rather than merely the same length.
323    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
327/// A false in every position the validity says is null.
328///
329/// The comparison at a null position read whatever the zero the null was stored as compared to,
330/// which is a defined value and a meaningless one. Writing false there costs one pass over a run
331/// of bytes, only when there are nulls at all, and it buys the property that a specialized result
332/// is the same vector as the row at a time result rather than merely the same answer. A test that
333/// can compare two vectors with `==` is a much better test than one that has to walk them.
334fn 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/// The answers for a form pair this file has a loop for, or `None` to say it has not.
346///
347/// `map` turns an output position into the row of `left` and `right` it is the answer for, and
348/// `len` is how many output positions there are. [`compare`] passes [`identity`] and the length of
349/// its operands, which is every row. [`refine`] passes the selection it was handed and the size of
350/// it, which is how a conjunct after the first reads only the rows the conjuncts before it kept.
351///
352/// A generic parameter rather than a `fn(usize) -> usize` in a field, for the reason
353/// `spec/engine/03-data-plane.md` records as the first performance lesson of this layer: an index
354/// mapping the compiler cannot see through is an indirect call per row, and one of those in a loop
355/// that is otherwise three instructions is the whole loop.
356#[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    // Across representations is the fallback's job. `INTEGER` against `BIGINT` reaches the same
375    // answer through `numeric_order`, and a specialized loop that assumed the two runs had the same
376    // layout would compare a four byte column against an eight byte one position by position.
377    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    // A bit packed column against a literal, which is the pair the form was added for. The literal
385    // is turned into a code once and then the loop compares codes, so nothing is unpacked at all,
386    // and a literal outside what the width can hold answers the whole vector without a bit of it
387    // being read. Only the six comparisons that go null on a null side come here, because the other
388    // two want the null rule inside the loop and this loop does not have it.
389    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        // The same loop with the comparison turned around, rather than a second loop.
406        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    // A compressed column against a literal, tested in the code space the column is already in.
411    // Only equality, because a symbol code says nothing about where its symbol sorts, so an ordering
412    // comparison has to decompress and does. Equality does not: compressing is a function of the
413    // table and the bytes, so two strings have the same codes exactly when they are the same string.
414    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    // A string column against another one or against a literal, with the views read where they are.
425    // It catches the string view form, whose bytes live in an arena the vector shares and so has no
426    // data slice for the branches above to find, and it catches the flat form as well so that the
427    // two cannot be compared by two different loops. The order itself is the one `view_order`
428    // writes down either way.
429    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    // A string column against a literal. The literal becomes one view before the loop starts, so
442    // every row is a four byte prefix against the same four bytes and the payload is only read for
443    // the rows the prefix could not settle.
444    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        // The same loop with the comparison turned around, rather than a second loop.
459        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    // A dictionary against a flat column. This pair had no loop until the kernel table put a number
486    // on what that cost, which on `server3` was 83 nanoseconds a row against 1.2 for the dictionary
487    // against constant pair beside it, on the same data and the same operator. It is not a rare
488    // shape either: it is what a filtered column compared against an unfiltered one is, which is
489    // every conjunct after the first.
490    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
503/// A literal as the whole number it is, and `None` for one that is not a whole number.
504///
505/// It goes through [`readied`] rather than reading the [`Value`] apart, so that a literal written
506/// as `900` against a `SMALLINT` column is narrowed by the same cast path every other comparison
507/// narrows it with. Reading the value apart here would be a second cast path with its own rounding
508/// and its own overflow rule, which is how two comparisons of the same literal end up disagreeing.
509fn 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
515/// A literal in the code space a compressed column is in, and `None` for one with no bytes.
516///
517/// It goes through [`readied`] for the reason [`exact`] does: the literal is narrowed to the column
518/// type by the same path every other comparison narrows it with, rather than by a second reading of
519/// the [`Value`] that could disagree with the first.
520fn 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
531/// A compressed column against a literal, tested without decompressing a row of it.
532///
533/// The comparison is a byte slice against a byte slice, which is what it would have been on the
534/// strings, over half as many bytes and with no decompression before it. A row whose codes are a
535/// different length is settled by the length alone, which on a column of URLs is most of them.
536fn 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
554/// A bit packed column against a literal, compared in the code space the column is already in.
555///
556/// The translation is one subtraction done once. After it the loop is a shift, a mask and a compare
557/// of two `u64`, which is what the flat loop would have been doing anyway minus the unpacking, so
558/// the form costs nothing on the operation a filter spends most of its time in.
559fn 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        // The literal is outside the range the width can hold, so every row answers the same way
571        // and the answer is arithmetic on two numbers rather than a pass over the column.
572        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    // The operator is decided before the loop rather than inside it, which is the same reason the
582    // generated loops take it as a function rather than matching per row.
583    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/// One loop per physical layout, generated rather than written out.
599///
600/// The two index closures are what let the same body serve flat against flat, a column against a
601/// constant and a dictionary against a constant. `identity` on both sides is the first, `first` on
602/// the right is the second, and the codes on the left are the third.
603#[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                // Floats have their own order, which is DuckDB's rather than IEEE's, and the
638                // widening on a `f32` is free because the comparison is against another `f32`.
639                (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                // An interval is three counts and the order is over the one length they add up to,
661                // so this is not the derived order of the triple and cannot be generated above.
662                (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
689/// The one row column for a constant, either the one that was built early or one built here.
690///
691/// Borrowed when a caller handed one over for this side and this value, owned when it did not, and
692/// the loop below cannot tell the two apart. `None` is a type with no column layout, which is what
693/// sends the whole comparison to the row at a time path.
694fn 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
701/// Two strings in byte order, resolved from the four byte prefix where it can be.
702///
703/// The lemma this rests on is that prefix order is byte order whenever the two prefixes differ. A
704/// view pads a string shorter than four bytes with zeros, zero is the least byte, and byte order
705/// says a string is less than any string that extends it, so padding compares the same way the
706/// missing bytes would have. When the prefixes are equal the payload settles it, which for an
707/// inline string is the same sixteen bytes already loaded and for a long one is a block read.
708fn 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
717/// The same comparison written against a view and the arena behind it rather than against a column.
718///
719/// Both forms that hold strings come through here, so a flat varchar column and a string view column
720/// order a pair of rows the same way and there is no second copy of the prefix rule to drift from
721/// this one.
722fn 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    // Bytes rather than `StringColumn::get`, which validates UTF-8. Everything in a column was
736    // pushed from a `&str` so the validation cannot fail, and on a URL column, where every row
737    // shares the `http` prefix and the payload therefore decides every comparison, it was the
738    // larger half of the per row cost.
739    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
744/// The answers for one ordering, with the operator decided once rather than once per row.
745///
746/// This is where the match on the operator gets hoisted. Each arm calls a generic `fill` with a
747/// different predicate, so the compiler produces eight loops whose bodies are an ordering against a
748/// constant, rather than one loop with a branch table in it.
749fn 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/// One loop, one predicate, no branch on the operator.
783#[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
794/// `IS NOT DISTINCT FROM`, which reads validity as data rather than as an absence.
795///
796/// Two nulls are the same value here and a null against anything else is not, which is the whole
797/// difference between this and `=`. The all valid case is checked once so that the common shape,
798/// which is a total comparison inside a join on columns that happen not to be nullable, does not
799/// pay for two validity lookups per row.
800fn 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
824/// Compares two values, producing `TRUE`, `FALSE` or `NULL`.
825///
826/// # Errors
827///
828/// If the two types cannot be compared, which after binding means one of them is a nested type.
829pub 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
859/// The order of two values, neither of which is null.
860///
861/// This is the one place the sort order of a type is written down. `ORDER BY`, `GROUP BY`, a merge
862/// join and a min or max aggregate all reach it, and a type that ordered differently in two of
863/// those would produce a query whose answer depends on which operator the optimizer picked.
864///
865/// # Errors
866///
867/// If either value is null, which is the caller's mistake rather than a comparison, or if the
868/// types have no order between them.
869pub 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        // A zoned value orders with its own kind and by the same rule, since both of them are the
879        // count of microseconds from a fixed point and the zone is about printing.
880        (Value::Time(a), Value::Time(b))
881        | (Value::TimeTz(a), Value::TimeTz(b))
882        | (Value::Timestamp(a), Value::Timestamp(b))
883        | (Value::TimestampTz(a), Value::TimestampTz(b)) => Ok(a.cmp(b)),
884        (
885            Value::Interval { months: am, days: ad, micros: au },
886            Value::Interval { months: bm, days: bd, micros: bu },
887        ) => Ok(interval_micros(*am, *ad, *au).cmp(&interval_micros(*bm, *bd, *bu))),
888        _ => numeric_order(left, right),
889    }
890}
891
892/// The order of two numbers, which is the case that has to work across representations.
893fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
894    if let (Some(a), Some(b)) = (integral(left), integral(right)) {
895        return Ok(a.cmp(&b));
896    }
897    if let (
898        Value::Decimal { unscaled: a, scale: sa, .. },
899        Value::Decimal { unscaled: b, scale: sb, .. },
900    ) = (left, right)
901    {
902        if sa == sb {
903            return Ok(a.cmp(b));
904        }
905    }
906    match (approximate(left), approximate(right)) {
907        (Some(a), Some(b)) => Ok(float_order(a, b)),
908        _ => Err(Error::not_implemented(format!(
909            "comparing {} with {}",
910            left.logical_type(),
911            right.logical_type()
912        ))),
913    }
914}
915
916/// DuckDB's float order: NaN is equal to itself and above everything else, and zero has one place.
917fn float_order(left: f64, right: f64) -> Ordering {
918    if left == right {
919        return Ordering::Equal;
920    }
921    match (left.is_nan(), right.is_nan()) {
922        (true, true) => Ordering::Equal,
923        (true, false) => Ordering::Greater,
924        (false, true) => Ordering::Less,
925        (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
926    }
927}
928
929/// The order of two values with nulls in it, for a sort key.
930///
931/// A sort has to put nulls somewhere and SQL lets the query say where, so this takes the answer
932/// rather than deciding it.
933///
934/// # Errors
935///
936/// If the two types have no order between them.
937pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
938    match (left.is_null(), right.is_null()) {
939        (true, true) => Ok(Ordering::Equal),
940        (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
941        (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
942        (false, false) => order(left, right),
943    }
944}
945
946#[cfg(test)]
947mod tests {
948    use super::*;
949
950    fn compared(op: Comparison, left: Value, right: Value) -> Value {
951        compare_values(op, &left, &right).expect("these types compare")
952    }
953
954    /// Every comparison, so that a test that sweeps them cannot quietly miss one.
955    const EVERY: [Comparison; 8] = [
956        Comparison::Equal,
957        Comparison::NotEqual,
958        Comparison::Less,
959        Comparison::LessOrEqual,
960        Comparison::Greater,
961        Comparison::GreaterOrEqual,
962        Comparison::DistinctFrom,
963        Comparison::NotDistinctFrom,
964    ];
965
966    /// The row at a time path, kept as the oracle rather than deleted.
967    ///
968    /// `spec/engine/03-data-plane.md` is explicit that the slow path becomes the thing the fast
969    /// path is checked against. This is that, written out here so that a test can call it on a pair
970    /// of vectors whose forms the fast path does specialize.
971    fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
972        let values: Vec<Value> = (0..left.len())
973            .map(|index| {
974                compare_values(op, &left.value_at(index), &right.value_at(index))
975                    .expect("the oracle is only asked about types that compare")
976            })
977            .collect();
978        Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
979    }
980
981    /// Asserts that the specialized path and the oracle produce the same vector, not merely the
982    /// same answers. Same vector means the same data, the same validity representation and the
983    /// same false in every null position, which is a much stronger statement and is free to check.
984    fn agrees(op: Comparison, left: &Vector, right: &Vector) {
985        let fast = compare(op, left, right).expect("compares");
986        let slow = oracle(op, left, right);
987        assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
988    }
989
990    /// A small deterministic generator, because a property test with no seed is a test that fails
991    /// on somebody else's machine and passes on yours.
992    struct Rng(u64);
993
994    impl Rng {
995        fn next(&mut self) -> u64 {
996            self.0 ^= self.0 << 13;
997            self.0 ^= self.0 >> 7;
998            self.0 ^= self.0 << 17;
999            self.0
1000        }
1001
1002        fn below(&mut self, bound: u64) -> u64 {
1003            self.next() % bound
1004        }
1005    }
1006
1007    #[test]
1008    fn an_ordinary_comparison_is_null_when_either_side_is() {
1009        assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
1010        assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
1011    }
1012
1013    #[test]
1014    fn a_total_comparison_is_never_null() {
1015        assert_eq!(
1016            compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
1017            Value::Boolean(true)
1018        );
1019        assert_eq!(
1020            compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
1021            Value::Boolean(false)
1022        );
1023        assert_eq!(
1024            compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
1025            Value::Boolean(true)
1026        );
1027    }
1028
1029    #[test]
1030    fn a_string_compares_by_bytes() {
1031        assert_eq!(
1032            compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
1033            Value::Boolean(true)
1034        );
1035        assert_eq!(
1036            compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
1037            Value::Boolean(true)
1038        );
1039    }
1040
1041    /// The reason this crate does not use `f64::partial_cmp` directly. A NaN that compared
1042    /// unordered would make a group by produce a group nothing can find again.
1043    #[test]
1044    fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
1045        assert_eq!(
1046            compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
1047            Value::Boolean(true)
1048        );
1049        assert_eq!(
1050            compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
1051            Value::Boolean(true)
1052        );
1053    }
1054
1055    #[test]
1056    fn zero_has_one_value_however_it_is_signed() {
1057        assert_eq!(
1058            compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
1059            Value::Boolean(true)
1060        );
1061    }
1062
1063    /// An interval is three counts and two of them that are the same length are one value, at
1064    /// thirty days to a month and twenty four hours to a day, which is what upstream answers. The
1065    /// three counts are still kept apart, because adding a month to a date is not adding thirty
1066    /// days to it, so these pairs are equal and print differently.
1067    #[test]
1068    fn two_intervals_of_the_same_length_are_one_value() {
1069        let day = Value::Interval { months: 0, days: 1, micros: 0 };
1070        let hours = Value::Interval { months: 0, days: 0, micros: 86_400_000_000 };
1071        let month = Value::Interval { months: 1, days: 0, micros: 0 };
1072        let thirty = Value::Interval { months: 0, days: 30, micros: 0 };
1073        let long_day = Value::Interval { months: 0, days: 0, micros: 90_000_000_000 };
1074        assert_eq!(compared(Comparison::Equal, day.clone(), hours), Value::Boolean(true));
1075        assert_eq!(compared(Comparison::Equal, month, thirty), Value::Boolean(true));
1076        assert_eq!(compared(Comparison::Greater, long_day, day), Value::Boolean(true));
1077    }
1078
1079    #[test]
1080    fn a_number_compares_the_same_however_it_is_stored() {
1081        assert_eq!(
1082            compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
1083            Value::Boolean(true)
1084        );
1085        assert_eq!(
1086            compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
1087            Value::Boolean(true)
1088        );
1089    }
1090
1091    #[test]
1092    fn nulls_go_where_the_query_asked_for_them() {
1093        assert_eq!(
1094            order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
1095            Ordering::Less
1096        );
1097        assert_eq!(
1098            order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
1099            Ordering::Greater
1100        );
1101    }
1102
1103    #[test]
1104    fn two_constant_vectors_cost_one_comparison() {
1105        let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
1106        let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
1107        let result = compare(Comparison::Less, &left, &right).expect("compares");
1108        assert_eq!(result.form(), Form::Constant);
1109        assert_eq!(result.value_at(500), Value::Boolean(true));
1110    }
1111
1112    #[test]
1113    fn a_comparison_of_two_vectors_is_one_answer_per_row() {
1114        let left = Vector::from_values(
1115            LogicalType::Integer,
1116            &[Value::Integer(1), Value::Integer(5), Value::Null],
1117        )
1118        .expect("three rows");
1119        let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
1120        let result = compare(Comparison::Greater, &left, &right).expect("compares");
1121        assert_eq!(result.value_at(0), Value::Boolean(false));
1122        assert_eq!(result.value_at(1), Value::Boolean(true));
1123        assert_eq!(result.value_at(2), Value::Null);
1124    }
1125
1126    #[test]
1127    fn two_vectors_of_different_lengths_are_caught() {
1128        let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1129        let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
1130        let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
1131        assert!(error.message().contains("4 row vector"), "{error}");
1132    }
1133
1134    #[test]
1135    fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
1136        for op in EVERY {
1137            let left = Value::Integer(3);
1138            let right = Value::Integer(7);
1139            assert_eq!(
1140                compare_values(op, &left, &right).expect("compares"),
1141                compare_values(op.swapped(), &right, &left).expect("compares"),
1142                "{op:?}"
1143            );
1144        }
1145    }
1146
1147    /// The whole point of the rewrite, stated as a property. Every operator, every physical
1148    /// layout, every form pair the fast path claims, against the row at a time oracle.
1149    #[test]
1150    fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
1151        let mut rng = Rng(0x5eed_1234_9876_4321);
1152        let types: [LogicalType; 11] = [
1153            LogicalType::Boolean,
1154            LogicalType::TinyInt,
1155            LogicalType::SmallInt,
1156            LogicalType::Integer,
1157            LogicalType::BigInt,
1158            LogicalType::HugeInt,
1159            LogicalType::UInteger,
1160            LogicalType::Float,
1161            LogicalType::Double,
1162            LogicalType::Varchar,
1163            LogicalType::Interval,
1164        ];
1165        for ty in &types {
1166            for nulls in [0u64, 1, 3] {
1167                let len = 37;
1168                let make = |rng: &mut Rng| {
1169                    let values: Vec<Value> = (0..len)
1170                        .map(|_| {
1171                            if nulls > 0 && rng.below(nulls + 1) == 0 {
1172                                Value::Null
1173                            } else {
1174                                sample(ty, rng)
1175                            }
1176                        })
1177                        .collect();
1178                    Vector::from_values(ty.clone(), &values).expect("a flat vector")
1179                };
1180                let left = make(&mut rng);
1181                let right = make(&mut rng);
1182                let literal = sample(ty, &mut rng);
1183                let constant = Vector::constant(ty.clone(), literal, len);
1184                let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1185                let codes: Vec<u32> =
1186                    (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1187                let dictionary =
1188                    Vector::dictionary(codes, left.clone()).expect("codes are in range");
1189                // Runs over the same values, with the last one cut short so that a run boundary
1190                // does not land on the end of the vector.
1191                let ends: Vec<u32> = (1..=left.len())
1192                    .map(|run| ((run * len) / left.len()).max(run) as u32)
1193                    .collect();
1194                let runs = Vector::runs(ends, left.clone()).expect("one value for each run");
1195
1196                for op in EVERY {
1197                    agrees(op, &left, &right);
1198                    agrees(op, &left, &constant);
1199                    agrees(op, &constant, &left);
1200                    agrees(op, &left, &null_constant);
1201                    agrees(op, &null_constant, &left);
1202                    agrees(op, &dictionary, &constant);
1203                    agrees(op, &constant, &dictionary);
1204                    // The dictionary against a flat column, which reads a null from either side and
1205                    // from the dictionary's values as well, so it is the pair with the most ways to
1206                    // disagree with the oracle and the one that got a loop last.
1207                    agrees(op, &dictionary, &right);
1208                    agrees(op, &right, &dictionary);
1209                    // The same four pairings for run length, which reaches the same loops through
1210                    // the same accessor, so what is being checked is that the positions it works
1211                    // out are the positions the row at a time path reads.
1212                    agrees(op, &runs, &constant);
1213                    agrees(op, &constant, &runs);
1214                    agrees(op, &runs, &right);
1215                    agrees(op, &right, &runs);
1216                }
1217            }
1218        }
1219    }
1220
1221    /// The rows of a selection the row at a time path keeps, which is what [`refine`] has to say.
1222    fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
1223        let mut out = Vec::new();
1224        for &row in kept.indices() {
1225            let index = row as usize;
1226            let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
1227                .expect("the oracle is only asked about types that compare");
1228            if is_true(&answer) {
1229                out.push(row);
1230            }
1231        }
1232        Selection::from_indices(out)
1233    }
1234
1235    fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
1236        let fast = refine(op, left, right, kept).expect("compares");
1237        assert_eq!(
1238            fast,
1239            refined(op, left, right, kept),
1240            "{op:?} on a {:?} against a {:?} over {} rows",
1241            left.form(),
1242            right.form(),
1243            kept.len()
1244        );
1245    }
1246
1247    /// Threading a selection through a comparison is the same rows as comparing everything and
1248    /// then keeping the ones that were already kept. Every operator, every form pair that has a
1249    /// loop, at four densities of selection, against the row at a time path.
1250    #[test]
1251    fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
1252        let mut rng = Rng(0x5eed_4321_1234_9876);
1253        let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
1254        for ty in &types {
1255            for nulls in [0u64, 1, 3] {
1256                let len = 37;
1257                let make = |rng: &mut Rng| {
1258                    let values: Vec<Value> = (0..len)
1259                        .map(|_| {
1260                            if nulls > 0 && rng.below(nulls + 1) == 0 {
1261                                Value::Null
1262                            } else {
1263                                sample(ty, rng)
1264                            }
1265                        })
1266                        .collect();
1267                    Vector::from_values(ty.clone(), &values).expect("a flat vector")
1268                };
1269                let left = make(&mut rng);
1270                let right = make(&mut rng);
1271                let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
1272                let null_constant = Vector::constant(ty.clone(), Value::Null, len);
1273                let codes: Vec<u32> =
1274                    (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
1275                let dictionary =
1276                    Vector::dictionary(codes, left.clone()).expect("codes are in range");
1277
1278                // Everything, every third row, a handful including the last one, and nothing,
1279                // which is the state a conjunct chain reaches as soon as one conjunct rejects a
1280                // whole chunk and is the case where the loop below must not read anything at all.
1281                let selections = [
1282                    Selection::identity(len),
1283                    Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
1284                    Selection::from_indices(vec![2, 5, 6, 17, 36]),
1285                    Selection::empty(),
1286                ];
1287                for op in EVERY {
1288                    for kept in &selections {
1289                        threads(op, &left, &right, kept);
1290                        threads(op, &left, &constant, kept);
1291                        threads(op, &constant, &left, kept);
1292                        threads(op, &left, &null_constant, kept);
1293                        threads(op, &null_constant, &left, kept);
1294                        threads(op, &constant, &null_constant, kept);
1295                        threads(op, &dictionary, &constant, kept);
1296                        threads(op, &constant, &dictionary, kept);
1297                        threads(op, &dictionary, &right, kept);
1298                        threads(op, &right, &dictionary, kept);
1299                    }
1300                }
1301            }
1302        }
1303    }
1304
1305    /// Two conjuncts threaded one after the other are the rows both of them keep, which is the
1306    /// property the whole filter path rests on. The second comparison sees the rows the first one
1307    /// left and never looks at the others.
1308    #[test]
1309    fn a_second_conjunct_reads_only_what_the_first_one_left() {
1310        let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
1311        let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
1312        let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
1313        let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
1314
1315        let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
1316            .expect("compares");
1317        let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
1318
1319        let expected: Vec<u32> = (0..64)
1320            .filter(|row| {
1321                let value = row % 10;
1322                value > 3 && value < 7
1323            })
1324            .collect();
1325        assert_eq!(both.indices(), expected.as_slice());
1326        assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
1327    }
1328
1329    /// A null is not a true, so a threaded comparison drops the row rather than keeping it with an
1330    /// unknown answer. This is the rule that makes `WHERE a < 5` leave out the rows where `a` is
1331    /// null, and it is the one a branchless loop gets wrong if the validity is left out of it.
1332    #[test]
1333    fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
1334        let column = Vector::from_values(
1335            LogicalType::Integer,
1336            &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
1337        )
1338        .expect("four rows");
1339        let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
1340        let all = Selection::identity(4);
1341        assert_eq!(
1342            refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
1343            &[0]
1344        );
1345        // The total comparison has an answer at every row, so the two nulls are kept here.
1346        let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
1347        assert_eq!(
1348            refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
1349            &[1, 3]
1350        );
1351    }
1352
1353    #[test]
1354    fn a_selection_past_the_end_is_caught() {
1355        let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
1356        let past = Selection::from_indices(vec![0, 4]);
1357        let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
1358        assert!(error.message().contains("4 row vector"), "{error}");
1359    }
1360
1361    /// One value of a type, for the generator above.
1362    fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
1363        match ty {
1364            LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
1365            LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
1366            LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
1367            LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
1368            LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
1369            LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
1370            LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
1371            // A NaN and a negative zero in the pool on purpose, because DuckDB's float order is
1372            // not IEEE's and the fast path has to reach the same answer the oracle does.
1373            LogicalType::Float => Value::Float(match rng.below(5) {
1374                0 => f32::NAN,
1375                1 => -0.0,
1376                other => other as f32 - 2.0,
1377            }),
1378            LogicalType::Double => Value::Double(match rng.below(5) {
1379                0 => f64::NAN,
1380                1 => -0.0,
1381                other => other as f64 - 2.0,
1382            }),
1383            // The same length written three ways and two lengths that are close to it, because an
1384            // interval that compares as a triple gets every pair here wrong and one that compares
1385            // as a length gets them right.
1386            LogicalType::Interval => match rng.below(6) {
1387                0 => Value::Interval { months: 0, days: 1, micros: 0 },
1388                1 => Value::Interval { months: 0, days: 0, micros: 86_400_000_000 },
1389                2 => Value::Interval { months: 1, days: -29, micros: 86_400_000_000 },
1390                3 => Value::Interval { months: 1, days: 0, micros: 0 },
1391                4 => Value::Interval { months: 0, days: 0, micros: 90_000_000_000 },
1392                _ => Value::Interval { months: -1, days: 0, micros: 0 },
1393            },
1394            // Short, at the inline limit, over it, and sharing a prefix with each other, which is
1395            // where a comparison that trusts the prefix too far goes wrong.
1396            LogicalType::Varchar => Value::Varchar(
1397                match rng.below(6) {
1398                    0 => "",
1399                    1 => "ab",
1400                    2 => "abc",
1401                    3 => "abcdefghijkl",
1402                    4 => "abcdefghijklm",
1403                    _ => "abcdefghijklmnopqrstuvwxyz",
1404                }
1405                .to_owned(),
1406            ),
1407            other => panic!("the generator has no values for {other}"),
1408        }
1409    }
1410
1411    /// The prefix lemma, written as a test because the whole string path rests on it. A view pads
1412    /// a short string with zeros, so prefix order has to agree with byte order on every pair where
1413    /// the prefixes differ, including the pairs where one string is shorter than four bytes.
1414    #[test]
1415    fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
1416        let words =
1417            ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
1418        let mut column = StringColumn::new();
1419        for word in words {
1420            column.push(word);
1421        }
1422        for (i, one) in words.iter().enumerate() {
1423            for (j, other) in words.iter().enumerate() {
1424                assert_eq!(
1425                    string_order(&column, i, &column, j),
1426                    one.as_bytes().cmp(other.as_bytes()),
1427                    "{one:?} against {other:?}"
1428                );
1429            }
1430        }
1431    }
1432
1433    /// A dictionary is compared once per distinct value, not once per row, and it has to reach the
1434    /// same answer including for the nulls it keeps in the vector it points at.
1435    #[test]
1436    fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
1437        let values = Vector::from_values(
1438            LogicalType::Integer,
1439            &[Value::Integer(1), Value::Null, Value::Integer(9)],
1440        )
1441        .expect("three values");
1442        let dictionary =
1443            Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
1444        let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
1445        let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
1446        assert_eq!(result.value_at(0), Value::Boolean(true));
1447        assert_eq!(result.value_at(1), Value::Null);
1448        assert_eq!(result.value_at(2), Value::Boolean(false));
1449        assert_eq!(result.value_at(3), Value::Null);
1450        assert_eq!(result.value_at(4), Value::Boolean(true));
1451    }
1452
1453    /// A form pair with no loop is answered correctly and counted, which is the whole contract of
1454    /// the fallback counter. Sequence against a column is the one this file leaves out on purpose.
1455    #[test]
1456    fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
1457        // The counters are per thread in a test build, so this reads its own and nothing else's.
1458        let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
1459        let sequence = Vector::sequence(10, 1, 4);
1460        let flat = Vector::from_values(
1461            LogicalType::BigInt,
1462            &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
1463        )
1464        .expect("four rows");
1465        let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
1466        assert_eq!(result.value_at(0), Value::Boolean(false));
1467        assert_eq!(result.value_at(1), Value::Boolean(false));
1468        assert_eq!(result.value_at(2), Value::Boolean(false));
1469        assert_eq!(result.value_at(3), Value::Null);
1470        assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
1471    }
1472
1473    /// The reason `Vector::dictionary` composes rather than stacks, stated as the thing that breaks
1474    /// if it stops.
1475    ///
1476    /// Every loop in this file reaches for the values behind the codes with `Vector::data`, and a
1477    /// dictionary pointing at a dictionary has no data to hand back, so a second filter over an
1478    /// already filtered chunk used to turn every one of these kernels off and drop the comparison
1479    /// onto the row at a time path. Measured on server3 over a chunk of two numeric columns that was
1480    /// selected twice, that was 3.5 nanoseconds a row becoming 104, and a third and fourth level
1481    /// cost nothing more because the first one had already given up everything there was to give.
1482    #[test]
1483    fn a_second_level_of_codes_does_not_turn_the_loops_off() {
1484        let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
1485        let values = Vector::from_values(
1486            LogicalType::Integer,
1487            &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
1488        )
1489        .expect("three rows");
1490        let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
1491        let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
1492        let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
1493        let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
1494        assert_eq!(result.value_at(0), Value::Boolean(true));
1495        assert_eq!(result.value_at(1), Value::Boolean(false));
1496        assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
1497    }
1498
1499    /// Either side all null, on one of the six ordinary comparisons, is every answer null without
1500    /// the data being read. The vector this produces has to be the one the oracle produces, which
1501    /// is a flat run of falses under an all invalid validity rather than a constant.
1502    #[test]
1503    fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
1504        let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
1505        let flat = Vector::from_values(
1506            LogicalType::Integer,
1507            &[
1508                Value::Integer(1),
1509                Value::Integer(2),
1510                Value::Integer(3),
1511                Value::Integer(4),
1512                Value::Integer(5),
1513                Value::Integer(6),
1514            ],
1515        )
1516        .expect("six rows");
1517        agrees(Comparison::Less, &nulls, &flat);
1518        agrees(Comparison::Equal, &flat, &nulls);
1519        assert_eq!(
1520            compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
1521            &Validity::AllInvalid
1522        );
1523    }
1524
1525    /// An empty vector is not a special case anywhere, and the easiest way to keep it that way is
1526    /// to say so in a test rather than to find out from a panic in an operator.
1527    #[test]
1528    fn an_empty_comparison_is_an_empty_answer() {
1529        let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
1530        let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
1531        let result = compare(Comparison::Equal, &left, &right).expect("compares");
1532        assert_eq!(result.len(), 0);
1533    }
1534
1535    /// Six strings, three of them sharing a prefix, and a null, which is the column the two tests
1536    /// below read.
1537    fn words() -> Vector {
1538        Vector::from_values(
1539            LogicalType::Varchar,
1540            &[
1541                Value::Varchar("http://a".into()),
1542                Value::Varchar("http://b".into()),
1543                Value::Null,
1544                Value::Varchar("ab".into()),
1545                Value::Varchar("http://a".into()),
1546                Value::Varchar("z".into()),
1547            ],
1548        )
1549        .expect("six rows")
1550    }
1551
1552    /// A literal built early answers what a literal built per chunk answers.
1553    ///
1554    /// Every operator and both entry points, because the whole claim of the prepared literal is
1555    /// that it changes nothing, and the string column is the one where it changes the most work:
1556    /// what it carries is the four byte prefix the comparison resolves almost every row from.
1557    #[test]
1558    fn a_literal_built_early_answers_what_one_built_here_answers() {
1559        let column = words();
1560        let value = Value::Varchar("http://b".into());
1561        let constant = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
1562        let held = Held::of(&LogicalType::Varchar, &value).expect("a varchar has a column");
1563        let kept = Selection::from_indices(vec![0, 1, 3, 5]);
1564        for op in [
1565            Comparison::Equal,
1566            Comparison::NotEqual,
1567            Comparison::Less,
1568            Comparison::LessOrEqual,
1569            Comparison::Greater,
1570            Comparison::GreaterOrEqual,
1571            Comparison::DistinctFrom,
1572            Comparison::NotDistinctFrom,
1573        ] {
1574            let prepared = compare_prepared(op, &column, &constant, Some(&held)).expect("compares");
1575            assert_eq!(prepared, compare(op, &column, &constant).expect("compares"), "{op:?}");
1576            // And with the literal on the left, which is the same loop turned around.
1577            let flipped = compare_prepared(op, &constant, &column, Some(&held)).expect("compares");
1578            assert_eq!(flipped, compare(op, &constant, &column).expect("compares"), "{op:?}");
1579            let refined =
1580                refine_prepared(op, &column, &constant, &kept, Some(&held)).expect("refines");
1581            assert_eq!(refined, refine(op, &column, &constant, &kept).expect("refines"), "{op:?}");
1582        }
1583    }
1584
1585    /// A literal built for something else is ignored rather than believed.
1586    ///
1587    /// The caller in `rudb-exec` takes the value out of the step it hands the answer back with, so
1588    /// this cannot happen there, and the kernel is public. A wrong answer is a much worse failure
1589    /// than a column built per chunk, so the check is a value comparison per chunk and this is what
1590    /// says it works.
1591    #[test]
1592    fn a_literal_built_for_another_value_is_ignored() {
1593        let column = words();
1594        let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("z".into()), 6);
1595        let wrong = Held::of(&LogicalType::Varchar, &Value::Varchar("ab".into()))
1596            .expect("a varchar has a column");
1597        let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&wrong))
1598            .expect("compares");
1599        assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1600        // And one built for another type, which is what a comparison across two types would hand
1601        // over if the caller took it from the wrong side.
1602        let other = Held::of(&LogicalType::Integer, &Value::Integer(1)).expect("an integer column");
1603        let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&other))
1604            .expect("compares");
1605        assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
1606    }
1607
1608    /// A bit packed column against a literal is compared in code space, which has to reach the
1609    /// oracle's answer on all eight comparisons and with the literal on either side.
1610    #[test]
1611    fn a_packed_column_against_a_constant_answers_what_the_oracle_answers() {
1612        let values: Vec<i32> = (0..64).map(|row| 1000 + (row * 37) % 500).collect();
1613        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1614            .expect("integers are an i32 layout");
1615        let packed = flat.bit_packed().expect("a five hundred wide range packs");
1616        assert_eq!(packed.form(), Form::BitPacked);
1617        for literal in [999, 1000, 1200, 1499, 1500, 2000] {
1618            let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 64);
1619            for op in EVERY {
1620                agrees(op, &packed, &constant);
1621                agrees(op, &constant, &packed);
1622            }
1623        }
1624    }
1625
1626    /// The nulls of a packed column live in its validity rather than in its bits, so a comparison
1627    /// has to blank them the way it blanks a flat column's, and the bits under them are whatever
1628    /// the packing wrote there.
1629    #[test]
1630    fn a_packed_column_with_nulls_answers_what_the_oracle_answers() {
1631        let values: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
1632        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1633            .expect("integers are an i32 layout")
1634            .with_validity(Validity::from_iter(32, |row| row % 5 != 0));
1635        let packed = flat.bit_packed().expect("packs");
1636        let constant = Vector::constant(LogicalType::Integer, Value::Integer(80), 32);
1637        for op in EVERY {
1638            agrees(op, &packed, &constant);
1639        }
1640    }
1641
1642    /// A literal the width cannot hold answers every row without a bit being read, and the answer
1643    /// still has to be the one the oracle gives.
1644    #[test]
1645    fn a_literal_outside_the_packed_range_answers_the_whole_vector_at_once() {
1646        let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant);
1647        let values: Vec<i32> = (0..16).map(|row| 500 + row).collect();
1648        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
1649            .expect("integers are an i32 layout");
1650        let packed = flat.bit_packed().expect("packs");
1651        let literals = [-1, 0, 499, 516, 100_000];
1652        for literal in literals {
1653            let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 16);
1654            for op in EVERY {
1655                agrees(op, &packed, &constant);
1656            }
1657        }
1658        // The six ordinary comparisons have a loop for this pair and the two that never go null do
1659        // not, because those want the null rule inside the loop and the code space loop does not
1660        // carry one. They take the row at a time path and count themselves, which is the counter
1661        // doing its job rather than a gap being hidden.
1662        let total = EVERY.iter().filter(|op| op.is_total()).count();
1663        assert_eq!(
1664            fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant) - before,
1665            (literals.len() * total) as u64,
1666            "only the two total comparisons fall through"
1667        );
1668    }
1669
1670    /// The conjunct path reads the rows an earlier conjunct kept, so the code space loop has to be
1671    /// reached through the selection rather than through the row number.
1672    #[test]
1673    fn refining_a_selection_over_a_packed_column_keeps_the_same_rows() {
1674        let values: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
1675        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into()))
1676            .expect("integers are an i32 layout");
1677        let packed = flat.bit_packed().expect("packs");
1678        let kept = Selection::from_predicate(64, |row| row % 3 == 0);
1679        let constant = Vector::constant(LogicalType::Integer, Value::Integer(260), 64);
1680        let packed_rows = refine(Comparison::Greater, &packed, &constant, &kept).expect("refines");
1681        let flat_rows = refine(Comparison::Greater, &flat, &constant, &kept).expect("refines");
1682        assert_eq!(packed_rows.indices(), flat_rows.indices());
1683        assert!(!packed_rows.is_empty(), "the literal is inside the range");
1684    }
1685
1686    /// A column of URLs, which is the shape the string view form exists for: a shared prefix that
1687    /// the four bytes in the view cannot settle, and payloads long enough to be in the arena.
1688    fn urls(count: usize) -> Vector {
1689        let mut rng = Rng(0x5eed_1234);
1690        let values: Vec<Value> = (0..count)
1691            .map(|_| {
1692                let host = rng.below(6);
1693                let path = rng.below(40);
1694                Value::Varchar(format!("http://example{host}.test/a/rather/long/path/{path}"))
1695            })
1696            .collect();
1697        Vector::from_values(LogicalType::Varchar, &values).expect("strings")
1698    }
1699
1700    #[test]
1701    fn a_string_view_column_against_a_literal_answers_what_the_oracle_answers() {
1702        let before = fallback::count(Kernel::Compare, Form::StringView, Form::Constant);
1703        let shared = urls(64).shared_text().expect("shares");
1704        assert_eq!(shared.form(), Form::StringView);
1705        let literals = ["http://example3.test/a/rather/long/path/7", "a", "zzz", ""];
1706        for literal in literals {
1707            let value = Value::Varchar(literal.to_owned());
1708            let constant = Vector::constant(LogicalType::Varchar, value, 64);
1709            for op in EVERY {
1710                agrees(op, &shared, &constant);
1711                agrees(op, &constant, &shared);
1712            }
1713        }
1714        assert_eq!(
1715            fallback::count(Kernel::Compare, Form::StringView, Form::Constant),
1716            before,
1717            "the form has a loop of its own for every comparison"
1718        );
1719    }
1720
1721    #[test]
1722    fn a_string_view_column_against_another_one_answers_what_the_oracle_answers() {
1723        let shared = urls(48).shared_text().expect("shares");
1724        let other = urls(48).shared_text().expect("shares");
1725        let flat = urls(48);
1726        for op in EVERY {
1727            agrees(op, &shared, &other);
1728            agrees(op, &shared, &flat);
1729            agrees(op, &flat, &shared);
1730        }
1731    }
1732
1733    #[test]
1734    fn the_nulls_of_a_string_view_column_are_the_nulls_the_oracle_sees() {
1735        let shared = urls(32)
1736            .with_validity(Validity::from_iter(32, |row| row % 4 != 1))
1737            .shared_text()
1738            .expect("shares");
1739        let constant =
1740            Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 32);
1741        for op in EVERY {
1742            agrees(op, &shared, &constant);
1743        }
1744    }
1745
1746    #[test]
1747    fn a_compressed_column_against_a_literal_answers_what_the_oracle_answers() {
1748        let before = fallback::count(Kernel::Compare, Form::Fsst, Form::Constant);
1749        let flat = urls(64);
1750        let coded = flat.clone().compressed().expect("compresses");
1751        assert_eq!(coded.form(), Form::Fsst);
1752        let present = match coded.value_at(9) {
1753            Value::Varchar(text) => text,
1754            other => panic!("a string column reads back strings, not {other:?}"),
1755        };
1756        for literal in [present.as_str(), "http://example3.test/nothing/like/it", ""] {
1757            let value = Value::Varchar(literal.to_owned());
1758            let constant = Vector::constant(LogicalType::Varchar, value, 64);
1759            for op in EVERY {
1760                agrees(op, &coded, &constant);
1761                agrees(op, &constant, &coded);
1762            }
1763        }
1764        // Equality has a loop in code space and the six comparisons that need an order do not,
1765        // because a symbol code says nothing about where its symbol sorts. Those decompress a row at
1766        // a time and count themselves, which is the counter doing its job rather than a gap hiding.
1767        let ordered = EVERY.len() - 2;
1768        assert_eq!(
1769            fallback::count(Kernel::Compare, Form::Fsst, Form::Constant) - before,
1770            (3 * ordered) as u64,
1771            "only the comparisons that need an order fall through"
1772        );
1773    }
1774
1775    /// Equality in code space is only right if compressing is a function, so the same string always
1776    /// has the same codes and two different strings never do. This is that claim as a test.
1777    #[test]
1778    fn every_row_of_a_compressed_column_matches_itself_and_nothing_else() {
1779        let flat = urls(48);
1780        let coded = flat.clone().compressed().expect("compresses");
1781        for row in 0..48 {
1782            let constant = Vector::constant(LogicalType::Varchar, flat.value_at(row), 48);
1783            let equal = compare(Comparison::Equal, &coded, &constant).expect("compares");
1784            for other in 0..48 {
1785                let want = flat.value_at(other) == flat.value_at(row);
1786                assert_eq!(
1787                    equal.value_at(other),
1788                    Value::Boolean(want),
1789                    "row {row} against {other}"
1790                );
1791            }
1792        }
1793    }
1794
1795    #[test]
1796    fn the_nulls_of_a_compressed_column_are_the_nulls_the_oracle_sees() {
1797        let coded = urls(32)
1798            .with_validity(Validity::from_iter(32, |row| row % 3 != 0))
1799            .compressed()
1800            .expect("compresses");
1801        let value = coded.value_at(1);
1802        let constant = Vector::constant(LogicalType::Varchar, value, 32);
1803        for op in EVERY {
1804            agrees(op, &coded, &constant);
1805        }
1806    }
1807
1808    /// The two forms hold the same strings in two different places, so a filter over either one has
1809    /// to keep the same rows. This is the differential check that the arena being shared changed
1810    /// nothing about what a comparison means.
1811    #[test]
1812    fn a_filter_over_either_string_form_keeps_the_same_rows() {
1813        let flat = urls(96);
1814        let shared = flat.clone().shared_text().expect("shares");
1815        let constant =
1816            Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 96);
1817        let kept = Selection::from_predicate(96, |row| row % 5 != 0);
1818        for op in EVERY {
1819            let over_flat = refine(op, &flat, &constant, &kept).expect("refines");
1820            let over_shared = refine(op, &shared, &constant, &kept).expect("refines");
1821            assert_eq!(over_shared.indices(), over_flat.indices(), "{op:?}");
1822        }
1823    }
1824}