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::cell::RefCell;
73use std::cmp::Ordering;
74use std::sync::Arc;
75
76use rudb_common::{Error, LogicalType, Result, Value, interval_micros};
77use rudb_vector::{
78    Coded, Data, Form, Packed, Selection, StringColumn, StringView, Validity, Vector,
79};
80
81use crate::fallback::{self, Kernel};
82use crate::logic::is_true;
83use crate::number::{approximate, integral};
84use crate::peel::{self, Found};
85use crate::prepare::Held;
86use crate::shape::{first, identity, nulls_of, single};
87
88/// Which comparison.
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
90pub enum Comparison {
91    /// `=`, null if either side is null.
92    Equal,
93    /// `<>`, null if either side is null.
94    NotEqual,
95    /// `<`, null if either side is null.
96    Less,
97    /// `<=`, null if either side is null.
98    LessOrEqual,
99    /// `>`, null if either side is null.
100    Greater,
101    /// `>=`, null if either side is null.
102    GreaterOrEqual,
103    /// `IS DISTINCT FROM`, which is total and never null.
104    DistinctFrom,
105    /// `IS NOT DISTINCT FROM`, which is total and never null.
106    NotDistinctFrom,
107}
108
109impl Comparison {
110    /// Whether this comparison treats null as a value rather than as an absence.
111    #[must_use]
112    pub fn is_total(self) -> bool {
113        matches!(self, Self::DistinctFrom | Self::NotDistinctFrom)
114    }
115
116    /// The comparison that means the same thing with the two sides exchanged.
117    ///
118    /// This is what halves the number of specialized loops. A constant on the left against a
119    /// column on the right is the column against the constant with the inequality turned around,
120    /// and writing it that way means the column against constant loop is written once and tested
121    /// once rather than twice with a chance of the second one being subtly wrong.
122    #[must_use]
123    pub fn swapped(self) -> Self {
124        match self {
125            Self::Less => Self::Greater,
126            Self::LessOrEqual => Self::GreaterOrEqual,
127            Self::Greater => Self::Less,
128            Self::GreaterOrEqual => Self::LessOrEqual,
129            same => same,
130        }
131    }
132
133    /// Whether this comparison is true of two sides that sit in this order.
134    ///
135    /// For the six ordinary comparisons only. The two total ones read a null as a value and an
136    /// `Ordering` has no way to say which side was null, so there is nothing sensible to return for
137    /// them and they answer false rather than pretending.
138    #[must_use]
139    fn holds(self, order: Ordering) -> bool {
140        match self {
141            Self::Equal => order == Ordering::Equal,
142            Self::NotEqual => order != Ordering::Equal,
143            Self::Less => order == Ordering::Less,
144            Self::LessOrEqual => order != Ordering::Greater,
145            Self::Greater => order == Ordering::Greater,
146            Self::GreaterOrEqual => order != Ordering::Less,
147            Self::DistinctFrom | Self::NotDistinctFrom => false,
148        }
149    }
150}
151
152/// Compares two vectors of the same length, producing a `BOOLEAN` vector.
153///
154/// # Errors
155///
156/// If the two sides are not the same length, or if the two types cannot be compared.
157pub fn compare(op: Comparison, left: &Vector, right: &Vector) -> Result<Vector> {
158    compare_prepared(op, left, right, None)
159}
160
161/// [`compare`], with the constant side already turned into the column the loops read it through.
162///
163/// The same body and the same answer. A caller that built the plan knows which side is a literal
164/// and can hand a [`Held`] built once for the query, which saves the allocations that building it
165/// per chunk costs. A caller that has no plan in front of it passes `None` and nothing changes.
166///
167/// # Errors
168///
169/// The same ones [`compare`] gives.
170pub fn compare_prepared(
171    op: Comparison,
172    left: &Vector,
173    right: &Vector,
174    held: Option<&Held>,
175) -> Result<Vector> {
176    if left.len() != right.len() {
177        return Err(Error::internal(format!(
178            "a comparison of a {} row vector with a {} row one",
179            left.len(),
180            right.len()
181        )));
182    }
183    let len = left.len();
184    if left.form() == Form::Constant && right.form() == Form::Constant && len > 0 {
185        let single = compare_values(op, &left.try_value_at(0)?, &right.try_value_at(0)?)?;
186        return Ok(Vector::constant(LogicalType::Boolean, single, len));
187    }
188
189    let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
190    // Either side entirely null, on one of the six ordinary comparisons, is every answer null and
191    // the data is never read. This is not a corner case: a `NULL` literal in a predicate is a
192    // constant vector whose validity is exactly this, and so is a column the scan knows is empty.
193    if !op.is_total()
194        && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
195        && len > 0
196    {
197        return boolean(vec![false; len], Validity::AllInvalid, len);
198    }
199
200    if let Some(answers) = external_text_literal(op, left, right, len, identity, held)? {
201        let validity = left_valid.and(&right_valid, len);
202        return boolean(blank_the_nulls(answers, &validity), validity, len);
203    }
204    if let Some(answers) =
205        specialized(op, left, right, &left_valid, &right_valid, len, identity, held)
206    {
207        let validity =
208            if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
209        return boolean(blank_the_nulls(answers, &validity), validity, len);
210    }
211
212    fallback::record(Kernel::Compare, left.form(), right.form());
213    let mut values = Vec::with_capacity(len);
214    // row at a time: the path recorded on the line above, which exists to be correct for a pair of
215    // forms no specialization covers and counts itself so that pair shows up in the report.
216    for index in 0..len {
217        values.push(compare_values(op, &left.try_value_at(index)?, &right.try_value_at(index)?)?);
218    }
219    Vector::from_values(LogicalType::Boolean, &values)
220}
221
222/// The rows the comparison is true on, which is [`compare_prepared`] and then
223/// [`crate::select::selection`] without the flag vector in between.
224///
225/// The first conjunct of a filter asks exactly this, and going the long way round built a
226/// `BOOLEAN` vector, wrote false into every null of it, and then had `selection` take the vector
227/// apart again to find the booleans it had just been handed. Here the answers go straight to the
228/// loop that picks the rows, and a null is dropped by the validity the way `selection` drops a
229/// null flag, so the rows are the same ones. A pair of forms with no loop of its own goes the long
230/// way, which is where it is counted.
231///
232/// # Errors
233///
234/// The same ones [`compare`] gives.
235pub fn select_prepared(
236    op: Comparison,
237    left: &Vector,
238    right: &Vector,
239    held: Option<&Held>,
240) -> Result<Selection> {
241    if left.len() != right.len() {
242        return Err(Error::internal(format!(
243            "a comparison of a {} row vector with a {} row one",
244            left.len(),
245            right.len()
246        )));
247    }
248    let len = left.len();
249    if len == 0 {
250        return Ok(Selection::empty());
251    }
252    if left.form() == Form::Constant && right.form() == Form::Constant {
253        let single = compare_values(op, &left.try_value_at(0)?, &right.try_value_at(0)?)?;
254        return Ok(if is_true(&single) { Selection::identity(len) } else { Selection::empty() });
255    }
256    let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
257    if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
258    {
259        return Ok(Selection::empty());
260    }
261    // A selection holds `u32` rows, and a chunk is nowhere near that, but the long way checks it
262    // and so this does too rather than casting past it.
263    if u32::try_from(len).is_ok() {
264        if let Some(answers) = external_text_literal(op, left, right, len, identity, held)? {
265            return Ok(crate::select::picked_flat(
266                &answers[..len],
267                &left_valid.and(&right_valid, len),
268            ));
269        }
270        if left_valid == Validity::AllValid && right_valid == Validity::AllValid {
271            if let Some(kept) = flat_kept(op, left, right, None, held) {
272                return Ok(kept);
273            }
274            if let Some(kept) = packed_kept(op, left, right, None) {
275                return Ok(kept);
276            }
277        }
278        if let Some(answers) =
279            specialized(op, left, right, &left_valid, &right_valid, len, identity, held)
280        {
281            let validity =
282                if op.is_total() { Validity::AllValid } else { left_valid.and(&right_valid, len) };
283            return Ok(crate::select::picked_flat(&answers[..len], &validity));
284        }
285    }
286    Ok(crate::select::selection(&compare_prepared(op, left, right, held)?, len))
287}
288
289/// The rows of a flat integer column with no nulls that hold against a literal or against another
290/// such column, in one pass.
291///
292/// The common shape of a scan's first filter, `AdvEngineID <> 0` on ClickBench Q1, and of the date
293/// checks in TPC-H q4, q12 and q21, `l_commitdate < l_receiptdate`. The general path gets there in
294/// two passes: an ordering per row into a run of booleans, through index closures the loop cannot
295/// see past, and then [`crate::select::picked`] or [`narrowed`] over the booleans. Here the two
296/// sides are compared in place and the row goes straight into the selection, so the loop is two
297/// loads, a compare and a store, and it no longer writes a byte per row that is read once and
298/// thrown away. `rows` is the rows the conjuncts before this one kept, or `None` for every row.
299/// Floats are left to the general path, because their order is DuckDB's rather than the machine's.
300fn flat_kept(
301    op: Comparison,
302    left: &Vector,
303    right: &Vector,
304    rows: Option<&[u32]>,
305    held: Option<&Held>,
306) -> Option<Selection> {
307    if op.is_total() || left.logical_type() != right.logical_type() {
308        return None;
309    }
310    let len = left.len();
311    let data = left.data()?;
312    macro_rules! ordered {
313        ($values:expr, $side:expr) => {{
314            let (values, side) = ($values, $side);
315            match op {
316                Comparison::Equal => flat_where(rows, values, side, |a, b| a == b),
317                Comparison::NotEqual => flat_where(rows, values, side, |a, b| a != b),
318                Comparison::Less => flat_where(rows, values, side, |a, b| a < b),
319                Comparison::LessOrEqual => flat_where(rows, values, side, |a, b| a <= b),
320                Comparison::Greater => flat_where(rows, values, side, |a, b| a > b),
321                Comparison::GreaterOrEqual => flat_where(rows, values, side, |a, b| a >= b),
322                Comparison::DistinctFrom | Comparison::NotDistinctFrom => return None,
323            }
324        }};
325    }
326    macro_rules! layouts {
327        ($($variant:ident),+ $(,)?) => {
328            if let Some(others) = right.data() {
329                match (data, others) {
330                    $(
331                        (Data::$variant(values), Data::$variant(others)) => {
332                            let (values, others) = (values.get(..len)?, others.get(..len)?);
333                            Some(ordered!(values, Side::Column(others)))
334                        }
335                    )+
336                    _ => None,
337                }
338            } else {
339                let column = readied(held, left.logical_type(), right.constant_value()?)?;
340                match (data, column.data()?) {
341                    $(
342                        (Data::$variant(values), Data::$variant(wanted)) => {
343                            let (values, wanted) = (values.get(..len)?, *wanted.first()?);
344                            Some(ordered!(values, Side::Constant(wanted)))
345                        }
346                    )+
347                    _ => None,
348                }
349            }
350        };
351    }
352    layouts!(Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128)
353}
354
355/// The right side of a comparison [`flat_where`] runs, another column or one value for every row.
356#[derive(Clone, Copy)]
357enum Side<'a, T> {
358    Column(&'a [T]),
359    Constant(T),
360}
361
362/// The rows of `values` for which `test` holds against `side`, out of `rows` when there are some.
363///
364/// With no `rows` this hands [`kept_in_blocks`] the slices themselves, so a block's flags come from
365/// zipping 64 values with no index to check, which the compiler turns into vector compares. Through
366/// a closure over a row number each row was a load behind a bounds check and a compare on its own.
367fn flat_where<T: Copy>(
368    rows: Option<&[u32]>,
369    values: &[T],
370    side: Side<'_, T>,
371    test: impl Fn(T, T) -> bool,
372) -> Selection {
373    let len = values.len();
374    match (rows, side) {
375        (Some(rows), Side::Constant(wanted)) => {
376            kept_where(Some(rows), len, |row| test(values[row], wanted))
377        }
378        (Some(rows), Side::Column(others)) => {
379            kept_where(Some(rows), len, |row| test(values[row], others[row]))
380        }
381        (None, Side::Constant(wanted)) => kept_in_blocks(
382            len,
383            |base, flags| {
384                for (flag, &value) in flags.iter_mut().zip(&values[base..base + 64]) {
385                    *flag = u8::from(test(value, wanted));
386                }
387            },
388            |row| test(values[row], wanted),
389        ),
390        (None, Side::Column(others)) => {
391            let others = &others[..len];
392            kept_in_blocks(
393                len,
394                |base, flags| {
395                    let pairs = values[base..base + 64].iter().zip(&others[base..base + 64]);
396                    for (flag, (&value, &other)) in flags.iter_mut().zip(pairs) {
397                        *flag = u8::from(test(value, other));
398                    }
399                },
400                |row| test(values[row], others[row]),
401            )
402        }
403    }
404}
405
406/// The rows where one bit packed column with no nulls holds against another, in one pass.
407///
408/// This is `l_commitdate < l_receiptdate` and `l_shipdate < l_commitdate` in q4, q12 and q21 as a
409/// stored table hands them up. [`packed_against_packed`] reads each code on its own, working out
410/// the word and the straddle every time, and writes a flag per row for a second pass to pick the
411/// rows out of. Here both sides are unpacked in blocks by [`Packed::unpack`], where the width is a
412/// constant, and the comparison writes the selection directly. The two bases are folded into one
413/// difference added to the right side, so the loop compares two `i64` rather than two `i128`. When
414/// the conjuncts before this one left only a few rows, the codes of just those rows are read one at
415/// a time instead, since unpacking the whole vector would read far more than it keeps.
416///
417/// `None` for anything but two straight packed runs of the same type, for codes too wide to leave
418/// room for the difference, and for two ranges that do not meet, which the general path answers
419/// without reading a code.
420fn packed_kept(
421    op: Comparison,
422    left: &Vector,
423    right: &Vector,
424    rows: Option<&[u32]>,
425) -> Option<Selection> {
426    if op.is_total() || left.logical_type() != right.logical_type() {
427        return None;
428    }
429    let (one, other) = (left.packed_parts()?, right.packed_parts()?);
430    if one.width() > 61 || other.width() > 61 {
431        return None;
432    }
433    if one.ceiling() < other.base() || other.ceiling() < one.base() {
434        return None;
435    }
436    // A row holds when `one.base() + a op other.base() + b`, which is `a op b + shift`.
437    let shift = i64::try_from(other.base() - one.base()).ok()?;
438    if shift.unsigned_abs() > 1 << 61 {
439        return None;
440    }
441    let len = left.len();
442    let dense = rows.is_none_or(|rows| rows.len() * 8 >= len);
443    macro_rules! ordered {
444        ($at:expr, $rows:expr) => {{
445            let at = $at;
446            match op {
447                Comparison::Equal => kept_where($rows, len, |row| {
448                    let (a, b) = at(row);
449                    a == b
450                }),
451                Comparison::NotEqual => kept_where($rows, len, |row| {
452                    let (a, b) = at(row);
453                    a != b
454                }),
455                Comparison::Less => kept_where($rows, len, |row| {
456                    let (a, b) = at(row);
457                    a < b
458                }),
459                Comparison::LessOrEqual => kept_where($rows, len, |row| {
460                    let (a, b) = at(row);
461                    a <= b
462                }),
463                Comparison::Greater => kept_where($rows, len, |row| {
464                    let (a, b) = at(row);
465                    a > b
466                }),
467                Comparison::GreaterOrEqual => kept_where($rows, len, |row| {
468                    let (a, b) = at(row);
469                    a >= b
470                }),
471                Comparison::DistinctFrom | Comparison::NotDistinctFrom => return None,
472            }
473        }};
474    }
475    #[expect(
476        clippy::cast_possible_wrap,
477        reason = "both widths are at most 61 bits, so a code is well inside an i64"
478    )]
479    let kept = if dense {
480        // Unpacked into two runs of `i64` with the difference already on the right, and then
481        // compared as two flat columns are, so that a block of 64 is a zip the compiler does in
482        // vector registers. Compared through a closure over the row, each row reloaded both
483        // vectors behind the flag it had just stored, which could have been either of them for
484        // all the compiler knew, and that was a fifth of q12.
485        // Codes of 30 bits or fewer, moved by less than 2^30, fit an `i32` on both sides, and a
486        // vector register holds twice as many of those and compares them signed in one step,
487        // where a signed compare of `i64` lanes is put together out of several on SSE2. Either
488        // way the codes go straight into their lanes a block at a time, rather than into a run of
489        // `u64` zeroed first and then walked again into a second run, which was 6% of q12.
490        if one.width() <= 30 && other.width() <= 30 && shift.unsigned_abs() < 1 << 30 {
491            #[expect(
492                clippy::cast_possible_truncation,
493                reason = "a code is below 2^30 and the shift is below 2^30 either way"
494            )]
495            let (a, b) = {
496                let (mut a, mut b) = (Vec::new(), Vec::new());
497                one.unpack_mapped(0, len, &mut a, |code| code as i32);
498                other.unpack_mapped(0, len, &mut b, |code| (code as i64 + shift) as i32);
499                (a, b)
500            };
501            flat_by(op, rows, &a, &b)?
502        } else {
503            let (mut a, mut b) = (Vec::new(), Vec::new());
504            one.unpack_mapped(0, len, &mut a, |code| code as i64);
505            other.unpack_mapped(0, len, &mut b, |code| code as i64 + shift);
506            flat_by(op, rows, &a, &b)?
507        }
508    } else {
509        ordered!(|row: usize| (one.code(row) as i64, other.code(row) as i64 + shift), rows)
510    };
511    Some(kept)
512}
513
514/// One end of a range a filter asks for: the comparison that sets it, the literal it compares
515/// against, and the column that literal was built into early, if one was.
516#[derive(Clone, Copy, Debug)]
517pub struct Bound<'a> {
518    /// `>` or `>=` for the low end, `<` or `<=` for the high one.
519    pub op: Comparison,
520    /// The literal, in the column's own type.
521    pub value: &'a Value,
522    /// What the step that holds the literal built for it, see [`Held`].
523    pub held: Option<&'a Held>,
524}
525
526/// The rows of `column` that lie between `low` and `high`, out of `live` when there are some, in one
527/// pass over the column.
528///
529/// `l_shipdate >= date '1994-01-01' and l_shipdate < date '1995-01-01'` is two conjuncts, and each
530/// of them on its own keeps most of the rows it is given, so running them one after the other pays
531/// for a selection of half the chunk that the second one then walks again. Together they keep a
532/// seventh of it. A value is in the range when its distance above the low end, read unsigned, is at
533/// most the width of the range, which is one subtraction and one compare a row and a loop the
534/// compiler does in vector registers. TPC-H q6 asks this twice and q4, q5, q10, q12, q14 and q15
535/// ask it once. See `spec/perf/65-one-range-one-pass.md`.
536///
537/// `None` for anything this has no loop for, a column with nulls, a form other than flat or bit
538/// packed, a type wider than 64 bits, a literal that is null or of another type, so that the caller
539/// runs the two comparisons the way it would have.
540#[must_use]
541pub fn select_range(
542    column: &Vector,
543    low: Bound<'_>,
544    high: Bound<'_>,
545    live: Option<&[u32]>,
546) -> Option<Selection> {
547    let len = column.len();
548    if len == 0 || u32::try_from(len).is_err() || nulls_of(column) != Validity::AllValid {
549        return None;
550    }
551    // Asked before the literals are built, since building one is an allocation.
552    let integral = column.packed_parts().is_some()
553        || matches!(
554            column.data(),
555            Some(
556                Data::Int8(_)
557                    | Data::Int16(_)
558                    | Data::Int32(_)
559                    | Data::Int64(_)
560                    | Data::UInt8(_)
561                    | Data::UInt16(_)
562                    | Data::UInt32(_)
563                    | Data::UInt64(_)
564            )
565        );
566    if !integral {
567        return None;
568    }
569    let ty = column.logical_type();
570    let literal = |bound: Bound<'_>| -> Option<i128> {
571        if bound.value.is_null() {
572            return None;
573        }
574        let single = readied(bound.held, ty, bound.value)?;
575        if single.logical_type() != ty {
576            return None;
577        }
578        Some(match single.data()? {
579            Data::Int8(values) => i128::from(*values.first()?),
580            Data::Int16(values) => i128::from(*values.first()?),
581            Data::Int32(values) => i128::from(*values.first()?),
582            Data::Int64(values) => i128::from(*values.first()?),
583            Data::UInt8(values) => i128::from(*values.first()?),
584            Data::UInt16(values) => i128::from(*values.first()?),
585            Data::UInt32(values) => i128::from(*values.first()?),
586            Data::UInt64(values) => i128::from(*values.first()?),
587            _ => return None,
588        })
589    };
590    // Both ends inclusive from here on.
591    let low = match low.op {
592        Comparison::GreaterOrEqual => literal(low)?,
593        Comparison::Greater => literal(low)? + 1,
594        _ => return None,
595    };
596    let high = match high.op {
597        Comparison::LessOrEqual => literal(high)?,
598        Comparison::Less => literal(high)? - 1,
599        _ => return None,
600    };
601    if let Some(packed) = column.packed_parts() {
602        return packed_range(&packed, len, low, high, live);
603    }
604    macro_rules! flat {
605        ($($variant:ident: $signed:ty => $unsigned:ty),+ $(,)?) => {
606            match column.data()? {
607                $(
608                    Data::$variant(values) => {
609                        let values = values.get(..len)?;
610                        let low = low.max(i128::from(<$signed>::MIN));
611                        let high = high.min(i128::from(<$signed>::MAX));
612                        if low > high {
613                            return Some(Selection::empty());
614                        }
615                        #[expect(
616                            clippy::cast_possible_truncation,
617                            clippy::cast_sign_loss,
618                            reason = "both ends were clamped to the type, and the distance is read \
619                                      unsigned on purpose"
620                        )]
621                        let (low, span) = (low as $signed, (high - low) as $unsigned);
622                        // Allowed rather than expected, since an unsigned type has no sign to lose.
623                        #[allow(clippy::cast_sign_loss, reason = "the distance is read unsigned")]
624                        let within = |value: $signed| value.wrapping_sub(low) as $unsigned <= span;
625                        Some(match live {
626                            Some(rows) => kept_where(Some(rows), len, |row| within(values[row])),
627                            None => kept_in_blocks(
628                                len,
629                                |base, flags| {
630                                    for (flag, &value) in
631                                        flags.iter_mut().zip(&values[base..base + 64])
632                                    {
633                                        *flag = u8::from(within(value));
634                                    }
635                                },
636                                |row| within(values[row]),
637                            ),
638                        })
639                    }
640                )+
641                _ => None,
642            }
643        };
644    }
645    flat!(
646        Int8: i8 => u8,
647        Int16: i16 => u16,
648        Int32: i32 => u32,
649        Int64: i64 => u64,
650        UInt8: u8 => u8,
651        UInt16: u16 => u16,
652        UInt32: u32 => u32,
653        UInt64: u64 => u64,
654    )
655}
656
657/// [`select_range`] on a bit packed column, in code space, where the range moves down by the base
658/// and is cut to the codes the width can hold, or `None` for a width and base whose top code does
659/// not fit an `i128`.
660fn packed_range(
661    packed: &Packed<'_>,
662    len: usize,
663    low: i128,
664    high: i128,
665    live: Option<&[u32]>,
666) -> Option<Selection> {
667    let (low, high) = (low.max(packed.base()), high.min(ceiling_of(packed)?));
668    if low > high {
669        return Some(Selection::empty());
670    }
671    #[expect(
672        clippy::cast_possible_truncation,
673        clippy::cast_sign_loss,
674        reason = "both ends are inside the codes the width holds, so both differences fit a u64"
675    )]
676    let (from, span) = ((low - packed.base()) as u64, (high - low) as u64);
677    let within = |code: u64| code.wrapping_sub(from) <= span;
678    Some(match live {
679        Some(rows) => kept_where(Some(rows), len, |row| within(packed.code(row))),
680        None => kept_in_blocks(
681            len,
682            |base, flags| {
683                let mut codes = [0_u64; 64];
684                packed.unpack(base, &mut codes);
685                for (flag, &code) in flags.iter_mut().zip(&codes) {
686                    *flag = u8::from(within(code));
687                }
688            },
689            |row| within(packed.code(row)),
690        ),
691    })
692}
693
694/// The rows where `a` stands in `op` to `b`, row by row, or none for the two operators that are
695/// about nulls, which two flat runs of codes know nothing of.
696fn flat_by<T: Copy + PartialOrd>(
697    op: Comparison,
698    rows: Option<&[u32]>,
699    a: &[T],
700    b: &[T],
701) -> Option<Selection> {
702    let side = Side::Column(b);
703    Some(match op {
704        Comparison::Equal => flat_where(rows, a, side, |x, y| x == y),
705        Comparison::NotEqual => flat_where(rows, a, side, |x, y| x != y),
706        Comparison::Less => flat_where(rows, a, side, |x, y| x < y),
707        Comparison::LessOrEqual => flat_where(rows, a, side, |x, y| x <= y),
708        Comparison::Greater => flat_where(rows, a, side, |x, y| x > y),
709        Comparison::GreaterOrEqual => flat_where(rows, a, side, |x, y| x >= y),
710        Comparison::DistinctFrom | Comparison::NotDistinctFrom => return None,
711    })
712}
713
714/// The rows out of `rows`, or out of every row below `len` when there is no `rows`, that `held`
715/// keeps, written without a branch on the answer.
716#[inline]
717fn kept_where(rows: Option<&[u32]>, len: usize, held: impl Fn(usize) -> bool) -> Selection {
718    let Some(rows) = rows else {
719        let fill = |base: usize, flags: &mut [u8; 64]| {
720            for (bit, flag) in flags.iter_mut().enumerate() {
721                *flag = u8::from(held(base + bit));
722            }
723        };
724        return kept_in_blocks(len, fill, &held);
725    };
726    let mut kept = 0;
727    let mut out = vec![0_u32; rows.len()];
728    for &row in rows {
729        out[kept] = row;
730        kept += usize::from(held(row as usize));
731    }
732    out.truncate(kept);
733    Selection::from_indices(out)
734}
735
736/// [`kept_where`] over every row below `len`, a block of 64 rows at a time.
737///
738/// The branchless loop writes each row and then moves the end of the answer by the flag, so every
739/// row waits on the one before it through the count, and the compare can't be done in vector
740/// registers. ClickBench Q1, `AdvEngineID <> 0` over a SMALLINT, spent 1.5ns a row there, and the
741/// buffer the size of the chunk it zeroed first was another few percent. Here a block's 64 flags are
742/// worked out on their own, which the compiler does in vector registers, and folded into a mask.
743/// This is how ClickHouse filters a column: a block the mask says is empty is skipped, a full one
744/// is copied as a range, and only a mixed block walks its set bits. `fill` writes the flags of the
745/// 64 rows from the one it is given, and `held` answers for the rows after the last whole block.
746#[expect(
747    clippy::cast_possible_truncation,
748    reason = "the caller checked that the row count fits in a u32 before getting here"
749)]
750#[inline]
751pub(crate) fn kept_in_blocks(
752    len: usize,
753    fill: impl Fn(usize, &mut [u8; 64]),
754    held: impl Fn(usize) -> bool,
755) -> Selection {
756    let mut out = Vec::with_capacity(len);
757    let mut base = 0;
758    while base + 64 <= len {
759        let mut flags = [0_u8; 64];
760        fill(base, &mut flags);
761        let mut mask = 0_u64;
762        for (lane, eight) in flags.chunks_exact(8).enumerate() {
763            let bytes = u64::from_le_bytes(eight.try_into().unwrap_or_default());
764            // Each byte is 0 or 1, and the multiply gathers byte i into bit 56 + i.
765            mask |= (bytes.wrapping_mul(0x0102_0408_1020_4080) >> 56) << (lane * 8);
766        }
767        if mask == u64::MAX {
768            out.extend(base as u32..(base + 64) as u32);
769        } else {
770            while mask != 0 {
771                out.push((base + mask.trailing_zeros() as usize) as u32);
772                mask &= mask - 1;
773            }
774        }
775        base += 64;
776    }
777    out.extend((base..len).filter(|&index| held(index)).map(|index| index as u32));
778    Selection::from_indices(out)
779}
780
781/// The rows of `kept` the comparison also keeps.
782///
783/// This is [`compare`] for a conjunct that is not the first one. A filter with four conjuncts
784/// evaluated the obvious way runs all four over every row, so on TPC-H Q6, where each conjunct
785/// passes about a fifth of the rows and the four together pass about two percent, the last conjunct
786/// does fifty times the work it needs to. Handing it the rows the earlier ones kept is the whole
787/// difference, and it is a difference that grows with the number of conjuncts rather than washing
788/// out.
789///
790/// The answer is the rows of `kept`, in the order `kept` has them, for which the comparison is true.
791/// Null is not true, so a row whose either side is null is dropped on the six ordinary comparisons,
792/// which is the same rule [`crate::select::selection`] applies to a flag vector and the reason both
793/// of them are a kernel rather than a line at the call site.
794///
795/// # Errors
796///
797/// If the two sides are not the same length, or if a position in `kept` is past the end of them.
798pub fn refine(
799    op: Comparison,
800    left: &Vector,
801    right: &Vector,
802    kept: &Selection,
803) -> Result<Selection> {
804    refine_prepared(op, left, right, kept, None)
805}
806
807/// [`refine`], with the constant side already built, for the reason [`compare_prepared`] gives.
808///
809/// This is the one that gains the most from it. A conjunct after the first reads the rows the ones
810/// before it kept, so the loop can be eleven rows long while the setup is the same size it would be
811/// for a full chunk.
812///
813/// # Errors
814///
815/// The same ones [`refine`] gives.
816pub fn refine_prepared(
817    op: Comparison,
818    left: &Vector,
819    right: &Vector,
820    kept: &Selection,
821    held: Option<&Held>,
822) -> Result<Selection> {
823    if left.len() != right.len() {
824        return Err(Error::internal(format!(
825            "a comparison of a {} row vector with a {} row one",
826            left.len(),
827            right.len()
828        )));
829    }
830    let len = left.len();
831    // One vectorized pass over a run of `u32` before any of the loops below index with them, which
832    // is what turns a caller's mistake into this message rather than into a panic from inside a
833    // macro generated loop eight frames down.
834    if !rudb_vector::below(kept.indices(), len) {
835        return Err(Error::internal(format!("a selection past the end of a {len} row vector")));
836    }
837    if kept.is_empty() {
838        return Ok(Selection::empty());
839    }
840    if left.form() == Form::Constant && right.form() == Form::Constant {
841        let single = compare_values(op, &left.try_value_at(0)?, &right.try_value_at(0)?)?;
842        return Ok(if is_true(&single) { kept.clone() } else { Selection::empty() });
843    }
844
845    let (left_valid, right_valid) = (nulls_of(left), nulls_of(right));
846    if !op.is_total() && (left_valid == Validity::AllInvalid || right_valid == Validity::AllInvalid)
847    {
848        return Ok(Selection::empty());
849    }
850
851    let rows = kept.indices();
852    if left_valid == Validity::AllValid && right_valid == Validity::AllValid {
853        if let Some(kept) = flat_kept(op, left, right, Some(rows), held) {
854            return Ok(kept);
855        }
856        if let Some(kept) = packed_kept(op, left, right, Some(rows)) {
857            return Ok(kept);
858        }
859    }
860    let map = |slot: usize| rows[slot] as usize;
861    if let Some(answers) = external_text_literal(op, left, right, kept.len(), map, held)? {
862        return Ok(narrowed(&answers, rows, |slot| {
863            let row = rows[slot] as usize;
864            left_valid.is_valid(row) && right_valid.is_valid(row)
865        }));
866    }
867    if let Some(answers) =
868        specialized(op, left, right, &left_valid, &right_valid, kept.len(), map, held)
869    {
870        // A total comparison has the nulls in the answer already, and two all valid sides have no
871        // null to drop, so both of those get the loop with nothing in it but the flag.
872        if op.is_total() || (left_valid == Validity::AllValid && right_valid == Validity::AllValid)
873        {
874            return Ok(narrowed(&answers, rows, |_| true));
875        }
876        // A bit at a time rather than a word at a time, which is the one place this path gives up
877        // something `compare` has. The rows are scattered by construction, so the two mask reads for
878        // one row are in different words as often as not and a word oriented loop would reread them.
879        return Ok(narrowed(&answers, rows, |slot| {
880            let row = rows[slot] as usize;
881            left_valid.is_valid(row) && right_valid.is_valid(row)
882        }));
883    }
884
885    fallback::record(Kernel::Compare, left.form(), right.form());
886    let mut out = Vec::with_capacity(kept.len());
887    // row at a time: the path recorded on the line above, for a pair of forms no specialization
888    // covers, reading only the rows the conjuncts before this one kept.
889    for &row in rows {
890        let index = row as usize;
891        if is_true(&compare_values(op, &left.try_value_at(index)?, &right.try_value_at(index)?)?) {
892            out.push(row);
893        }
894    }
895    Ok(Selection::from_indices(out))
896}
897
898/// One of the six ordinary comparisons between storage-backed text and a literal, without
899/// constructing row values.
900///
901/// Where the comparison is an equality, the column is a dictionary that shares its values and the
902/// caller brought the literal it was built with, this decides once per distinct value instead of
903/// once per row. See the `peel` module. Everything else reads the column a row at a time, which is
904/// still better than the general path because it never builds a value.
905///
906/// An ordering comparison gets none of that and is here anyway, because what the general path costs
907/// on a text column is not the comparison. It is `try_value_at`, which allocates a `String` a row so
908/// that `compare_values` has a `Value` to look at, and then drops it. Reading the bytes where they
909/// lie and comparing those is the same answer with neither the allocation nor the dispatch, and the
910/// caller this matters most to is the top N: it asks every chunk whether any row can still beat the
911/// worst candidate it holds, and the constant it asks about changes as it goes, so nothing is memoized
912/// and the row loop is the whole of it.
913fn external_text_literal<M>(
914    op: Comparison,
915    left: &Vector,
916    right: &Vector,
917    len: usize,
918    map: M,
919    held: Option<&Held>,
920) -> Result<Option<Vec<bool>>>
921where
922    M: Fn(usize) -> usize + Copy,
923{
924    if op.is_total()
925        || left.logical_type() != &LogicalType::Varchar
926        || right.logical_type() != &LogicalType::Varchar
927    {
928        return Ok(None);
929    }
930    let (column, literal, swapped) = match (left.constant_value(), right.constant_value()) {
931        (None, Some(Value::Varchar(literal))) if left.positions().is_some() => {
932            (left, literal.as_bytes(), false)
933        }
934        (Some(Value::Varchar(literal)), None) if right.positions().is_some() => {
935            (right, literal.as_bytes(), true)
936        }
937        _ => return Ok(None),
938    };
939    // The column is on the left from here on, so an inequality written the other way round is
940    // turned around once rather than once a row.
941    let op = if swapped { op.swapped() } else { op };
942    let same = op == Comparison::Equal;
943    if matches!(op, Comparison::Equal | Comparison::NotEqual) {
944        // The literal has to be the one the memo was filled against, which it is when the caller
945        // took both from the same comparison node. A caller that gets it wrong is slow rather than
946        // wrong, which is the rule the rest of `Held` keeps.
947        if let Some(held) = held.filter(|held| held.text() == Some(literal)) {
948            // A dictionary that came with its sorted order answers this without reading any value
949            // more than the search does, so try that before filling a memo one value at a time.
950            if let Some(found) = held.lookup().find(column, literal) {
951                return Ok(Some(against_code(column, found?, len, map, same)?));
952            }
953            let decide = |dictionary: &Vector, code: usize| -> Result<bool> {
954                let found = if literal.is_empty() {
955                    dictionary.try_bytes_len_at(code)?.is_some_and(|length| length == 0)
956                } else {
957                    dictionary.try_bytes_at(code)?.is_some_and(|bytes| bytes == literal)
958                };
959                Ok(found)
960            };
961            if let Some(answers) = held.peel().answer(column, len, map, decide) {
962                let mut answers = answers?;
963                if !same {
964                    for answer in &mut answers {
965                        *answer = !*answer;
966                    }
967                }
968                return Ok(Some(answers));
969            }
970        }
971        let mut answers = Vec::with_capacity(len);
972        for slot in 0..len {
973            let row = map(slot);
974            // An empty literal is settled by the length alone, which for a dictionary is one load
975            // of two offsets rather than a walk to wherever the value's bytes live.
976            let equal = if literal.is_empty() {
977                column.try_bytes_len_at(row)?.is_some_and(|length| length == 0)
978            } else {
979                column.try_bytes_at(row)?.is_some_and(|bytes| bytes == literal)
980            };
981            answers.push(equal == same);
982        }
983        return Ok(Some(answers));
984    }
985    if let Some(answers) = by_rank(op, column, literal, len, map)? {
986        return Ok(Some(answers));
987    }
988    let mut answers = Vec::with_capacity(len);
989    for slot in 0..len {
990        let row = map(slot);
991        // A null row's bytes are whatever the column left there, and the answer for it is thrown
992        // away by the caller, which blanks every position the validity says is null. Equal is what
993        // is written there because it is the cheapest thing to write and it is never read.
994        let order = match column.try_bytes_at(row)? {
995            Some(bytes) => bytes.cmp(literal),
996            None => Ordering::Equal,
997        };
998        answers.push(op.holds(order));
999    }
1000    Ok(Some(answers))
1001}
1002
1003/// An inequality against a literal answered out of the dictionary's sorted order, or `None` when
1004/// there is no order to answer it from.
1005///
1006/// The equality path has resolved a literal to a code and compared integers since the sorted order
1007/// was written, and this is the same trick for the other four comparisons. One binary search puts the
1008/// literal at a rank boundary, the inverse of the order turns each row's code into its rank, and then
1009/// the whole comparison is one `usize` against another. No value is read and no bytes are compared.
1010///
1011/// The caller this was written for is the top N. `ORDER BY <varchar> LIMIT 10` asks every chunk
1012/// whether any row in it can still beat the tenth best candidate, which is a comparison of the key
1013/// column against a literal that changes as the query runs, so there is nothing to memoize and the
1014/// row loop is the whole of the operator. On ClickBench 25, which is that query over `SearchPhrase`,
1015/// the top N was 0.377 of the 0.791 milliseconds the pipeline's operators spent per instance, against
1016/// 0.097 for the same query ordered by a timestamp. The gap was the byte compare.
1017///
1018/// The filter gets it too, for `WHERE <varchar> < 'literal'` and for both halves of a `BETWEEN`.
1019///
1020/// Two things have to be true and the source decides both. It has to know its own order, and it has
1021/// to be willing to hand the order back inverted, which is a `u32` per value it builds once and keeps.
1022/// A source that would rather not answers `None` to one of them and the byte loop below runs instead,
1023/// which is what every in memory column does today.
1024fn by_rank<M>(
1025    op: Comparison,
1026    column: &Vector,
1027    literal: &[u8],
1028    len: usize,
1029    map: M,
1030) -> Result<Option<Vec<bool>>>
1031where
1032    M: Fn(usize) -> usize,
1033{
1034    let Some((codes, dictionary)) = column.shared_dictionary_parts() else { return Ok(None) };
1035    let Some(ranks) = dictionary.ranks() else { return Ok(None) };
1036    let Some(order) = dictionary.code_ranks() else { return Ok(None) };
1037    let (below, equal) = peel::below(dictionary, ranks, literal)?;
1038    // The two boundaries `peel::below` describes, picked by which side of the literal the comparison
1039    // wants and whether the literal itself counts as being on that side.
1040    let cut = match op {
1041        Comparison::Less | Comparison::GreaterOrEqual => below,
1042        _ => below + usize::from(equal),
1043    };
1044    let under = matches!(op, Comparison::Less | Comparison::LessOrEqual);
1045    let mut answers = Vec::with_capacity(len);
1046    // row at a time: the comparison is the loop, and a row of it is two loads and an integer compare.
1047    for slot in 0..len {
1048        let code = *codes
1049            .get(map(slot))
1050            .ok_or_else(|| Error::internal("a ranked row is past the end of its codes"))?;
1051        let rank = *order
1052            .get(code as usize)
1053            .ok_or_else(|| Error::internal("a ranked code is past the end of its dictionary"))?;
1054        answers.push(((rank as usize) < cut) == under);
1055    }
1056    Ok(Some(answers))
1057}
1058
1059/// The rows that compare true against the value already known to sit at `rank`, or `None`.
1060///
1061/// The `by_rank` path with the search taken out. That path searches because it is handed a literal
1062/// and has to find out where the literal sits, and the search is not cheap: about nineteen probes of
1063/// a dictionary of a hundred thousand, and a probe that cannot settle on the eight bytes the file
1064/// stores per rank has to read a value, which decodes the block the value sits in. On ClickBench 25
1065/// that search and the block decoding under it were most of the query.
1066///
1067/// A caller that already knows the rank pays none of it. The one this was written for is the top N,
1068/// whose bound is not a literal from the query at all: it is a value that came out of this same
1069/// dictionary, carried by a row that arrived with its code, so its rank was known the moment it was
1070/// kept and nothing has to be found. See `crate::topn`.
1071///
1072/// `None` when the column is not a dictionary over `dictionary`, when that dictionary will not hand
1073/// its order back inverted, or for a comparison that is not one of the four inequalities. The
1074/// identity check is the whole of what makes this safe to offer: a rank means nothing except against
1075/// the dictionary it was read out of, so the caller hands that dictionary over and this refuses
1076/// rather than trusting it.
1077///
1078/// Null rows are dropped, which is what [`crate::select::selection`] does with a null flag and
1079/// therefore what the caller would have got by going the long way round.
1080#[must_use]
1081pub fn select_against_rank(
1082    op: Comparison,
1083    column: &Vector,
1084    dictionary: &Arc<Vector>,
1085    rank: u32,
1086    rows: usize,
1087) -> Option<Selection> {
1088    let (codes, values) = column.shared_dictionary_parts()?;
1089    if !Arc::ptr_eq(values, dictionary) {
1090        return None;
1091    }
1092    let order = values.code_ranks()?;
1093    let validity = column.validity();
1094    let live = !validity.has_nulls(rows);
1095    let rows = rows.min(codes.len());
1096    let mut kept = vec![0_u32; rows];
1097    let mut count = 0;
1098    // row at a time: the comparison is the loop, and a row of it is two loads and an integer
1099    // compare. Every slot writes its row at the current length and only a kept slot moves the
1100    // length on, for the reason `narrowed` gives.
1101    for (row, &code) in codes.iter().enumerate().take(rows) {
1102        let at = *order.get(code as usize)?;
1103        let held = match op {
1104            Comparison::Less => at < rank,
1105            Comparison::LessOrEqual => at <= rank,
1106            Comparison::Greater => at > rank,
1107            Comparison::GreaterOrEqual => at >= rank,
1108            _ => return None,
1109        };
1110        kept[count] = u32::try_from(row).ok()?;
1111        // A single `&` rather than `&&`, because the short circuit would put back the branch.
1112        count += usize::from(held & (live || validity.is_valid(row)));
1113    }
1114    kept.truncate(count);
1115    Some(Selection::from_indices(kept))
1116}
1117
1118/// The rank of the value one row of a dictionary column holds, when that is knowable.
1119///
1120/// The other half of [`select_against_rank`]. A caller that wants to compare against a row's value
1121/// later without searching for it asks for this when the row goes by and keeps the answer.
1122///
1123/// `None` for a column that is not a dictionary over a source that knows its order, for a row that
1124/// is null, and for a code the order does not cover. The caller treats all three the same way, by
1125/// giving up on ranks and doing what it did before.
1126#[must_use]
1127pub fn rank_at(column: &Vector, row: usize) -> Option<(Arc<Vector>, u32)> {
1128    let (codes, values) = column.shared_dictionary_parts()?;
1129    if !column.validity().is_valid(row) {
1130        return None;
1131    }
1132    let order = values.code_ranks()?;
1133    let code = *codes.get(row)?;
1134    let rank = *order.get(code as usize)?;
1135    Some((Arc::clone(values), rank))
1136}
1137
1138/// The rank of one row's value in a dictionary the caller is already holding.
1139///
1140/// [`rank_at`] for a caller that has a dictionary in hand and wants to know where one row sits in
1141/// it, which is a top n rejecting a row against a candidate it kept earlier. It answers the question
1142/// without the clone of the `Arc` that `rank_at` has to make, because a reject runs on every row
1143/// that reaches the operator and an atomic increment per row is not nothing.
1144///
1145/// The identity check is what makes a rank mean anything, and it is the same one
1146/// [`select_against_rank`] makes: a rank is a position in one dictionary and says nothing at all
1147/// about any other, so this refuses a column that is not over the dictionary it was given.
1148///
1149/// `None` in every case `rank_at` answers `None` in, and additionally for a column over a different
1150/// dictionary. The caller reads the value and compares it the old way.
1151#[must_use]
1152pub fn rank_within(column: &Vector, row: usize, dictionary: &Arc<Vector>) -> Option<u32> {
1153    let (codes, values) = column.shared_dictionary_parts()?;
1154    if !Arc::ptr_eq(values, dictionary) || !column.validity().is_valid(row) {
1155        return None;
1156    }
1157    let order = values.code_ranks()?;
1158    let code = *codes.get(row)?;
1159    Some(*order.get(code as usize)?)
1160}
1161
1162/// Every row's answer once the literal has been resolved to a code, or to nothing.
1163///
1164/// This is the whole point of storing a dictionary's sorted order. The comparison is a `u32`
1165/// against a `u32` and it never touches the payload, so a filter on a text column costs what a
1166/// filter on an integer column costs. A literal the dictionary does not hold is decided for the
1167/// whole chunk without looking at the codes at all, because a code that is in the dictionary cannot
1168/// be the one that is not.
1169fn against_code<M>(
1170    column: &Vector,
1171    found: Found,
1172    len: usize,
1173    map: M,
1174    same: bool,
1175) -> Result<Vec<bool>>
1176where
1177    M: Fn(usize) -> usize,
1178{
1179    let Found::At(wanted) = found else { return Ok(vec![!same; len]) };
1180    let (codes, _) = column
1181        .shared_dictionary_parts()
1182        .ok_or_else(|| Error::internal("a resolved literal lost the codes it was resolved for"))?;
1183    // Every row the map can name is a row of the column, which both callers check before they get
1184    // here, so codes as long as the column settle the bound for the whole chunk at once. Asking per
1185    // row put an error path and a push in a loop that is otherwise one compare, and that loop was
1186    // fifteen instructions a row on ClickBench 28 rather than one.
1187    if codes.len() < column.len() {
1188        return Err(Error::internal("a compared column is longer than its codes"));
1189    }
1190    // row at a time: the comparison is the loop. Nothing here reads a value or allocates.
1191    Ok((0..len).map(|slot| (codes[map(slot)] == wanted) == same).collect())
1192}
1193
1194/// The positions of `rows` whose answer is true and whose row is live, without a branch per row.
1195///
1196/// The same shape as the loop in `crate::select` and for the same reason: which rows a filter keeps is
1197/// what the data decides rather than what the code does, so the branch is unpredictable by
1198/// construction and a mispredict is worth more than the rest of the loop put together. Every slot
1199/// writes its row at the current length and only a slot that is kept moves the length on.
1200fn narrowed<L: Fn(usize) -> bool>(answers: &[bool], rows: &[u32], live: L) -> Selection {
1201    let mut out = vec![0_u32; answers.len()];
1202    let mut count = 0;
1203    for (slot, &answer) in answers.iter().enumerate() {
1204        out[count] = rows[slot];
1205        // A single `&` rather than `&&`, because the short circuit would put back the branch.
1206        count += usize::from(answer & live(slot));
1207    }
1208    out.truncate(count);
1209    Selection::from_indices(out)
1210}
1211
1212/// A `BOOLEAN` vector from a run of answers and the validity that says which of them count.
1213fn boolean(answers: Vec<bool>, validity: Validity, len: usize) -> Result<Vector> {
1214    // An empty vector has no null to record, and `Vector::from_values` normalizes the empty mask it
1215    // builds to all valid, so saying the same here is what keeps an empty specialized result the
1216    // same vector as the oracle's rather than merely the same length.
1217    let validity = if len == 0 { Validity::AllValid } else { validity.normalize(len) };
1218    Ok(Vector::flat(LogicalType::Boolean, Data::Bool(answers.into()))?.with_validity(validity))
1219}
1220
1221/// A false in every position the validity says is null.
1222///
1223/// The comparison at a null position read whatever the zero the null was stored as compared to,
1224/// which is a defined value and a meaningless one. Writing false there costs one pass over a run
1225/// of bytes, only when there are nulls at all, and it buys the property that a specialized result
1226/// is the same vector as the row at a time result rather than merely the same answer. A test that
1227/// can compare two vectors with `==` is a much better test than one that has to walk them.
1228fn blank_the_nulls(mut answers: Vec<bool>, validity: &Validity) -> Vec<bool> {
1229    if let Validity::Mask(mask) = validity {
1230        for (index, answer) in answers.iter_mut().enumerate() {
1231            if !mask.get(index) {
1232                *answer = false;
1233            }
1234        }
1235    }
1236    answers
1237}
1238
1239/// The answers for a form pair this file has a loop for, or `None` to say it has not.
1240///
1241/// `map` turns an output position into the row of `left` and `right` it is the answer for, and
1242/// `len` is how many output positions there are. [`compare`] passes [`identity`] and the length of
1243/// its operands, which is every row. [`refine`] passes the selection it was handed and the size of
1244/// it, which is how a conjunct after the first reads only the rows the conjuncts before it kept.
1245///
1246/// A generic parameter rather than a `fn(usize) -> usize` in a field, for the reason
1247/// `spec/engine/03-data-plane.md` records as the first performance lesson of this layer: an index
1248/// mapping the compiler cannot see through is an indirect call per row, and one of those in a loop
1249/// that is otherwise three instructions is the whole loop.
1250#[expect(
1251    clippy::too_many_arguments,
1252    reason = "two sides, two validities, the operator, the length, the index mapping and the \
1253              literal that was built early, all of which the branches below need"
1254)]
1255fn specialized<M>(
1256    op: Comparison,
1257    left: &Vector,
1258    right: &Vector,
1259    left_valid: &Validity,
1260    right_valid: &Validity,
1261    len: usize,
1262    map: M,
1263    held: Option<&Held>,
1264) -> Option<Vec<bool>>
1265where
1266    M: Fn(usize) -> usize + Copy,
1267{
1268    // Across representations is the fallback's job. `INTEGER` against `BIGINT` reaches the same
1269    // answer through `numeric_order`, and a specialized loop that assumed the two runs had the same
1270    // layout would compare a four byte column against an eight byte one position by position.
1271    if left.logical_type() != right.logical_type() {
1272        return None;
1273    }
1274    // A bit string's bytes do not sort the way its bits do, so ordering two of them is the
1275    // fallback's, which asks `bit::cmp`. Equality is still the bytes, since a bit string has one
1276    // layout.
1277    let equality = matches!(
1278        op,
1279        Comparison::Equal
1280            | Comparison::NotEqual
1281            | Comparison::DistinctFrom
1282            | Comparison::NotDistinctFrom
1283    );
1284    if *left.logical_type() == LogicalType::Bit && !equality {
1285        return None;
1286    }
1287
1288    // Where each side keeps its values and how a row of it is reached, which is what turns flat,
1289    // dictionary and run length into one branch below rather than nine. See [`Through`].
1290    let (one, other) = (through(left), through(right));
1291
1292    if let (Some(one), Some(other)) = (&one, &other) {
1293        return match (one, other) {
1294            (Through::Direct(a), Through::Direct(b)) => {
1295                dispatch(op, len, a, map, b, map, left_valid, right_valid, map)
1296            }
1297            (Through::Coded(codes, a), Through::Direct(b)) => dispatch(
1298                op,
1299                len,
1300                a,
1301                |slot| codes[map(slot)] as usize,
1302                b,
1303                map,
1304                left_valid,
1305                right_valid,
1306                map,
1307            ),
1308            (Through::Direct(a), Through::Coded(codes, b)) => dispatch(
1309                op,
1310                len,
1311                a,
1312                map,
1313                b,
1314                |slot| codes[map(slot)] as usize,
1315                left_valid,
1316                right_valid,
1317                map,
1318            ),
1319            (Through::Coded(left_codes, a), Through::Coded(right_codes, b)) => dispatch(
1320                op,
1321                len,
1322                a,
1323                |slot| left_codes[map(slot)] as usize,
1324                b,
1325                |slot| right_codes[map(slot)] as usize,
1326                left_valid,
1327                right_valid,
1328                map,
1329            ),
1330        };
1331    }
1332    // A bit packed column against a literal, which is the pair the form was added for. The literal
1333    // is turned into a code once and then the loop compares codes, so nothing is unpacked at all,
1334    // and a literal outside what the width can hold answers the whole vector without a bit of it
1335    // being read. Only the six comparisons that go null on a null side come here, because the other
1336    // two want the null rule inside the loop and this loop does not have it.
1337    if !op.is_total() {
1338        if let (Some(packed), Some(value)) = (left.packed_parts(), right.constant_value()) {
1339            let wanted = exact(held, left.logical_type(), value)?;
1340            return Some(packed_against(op, &packed, wanted, len, map));
1341        }
1342        if let (Some(value), Some(packed)) = (left.constant_value(), right.packed_parts()) {
1343            let wanted = exact(held, right.logical_type(), value)?;
1344            return Some(packed_against(op.swapped(), &packed, wanted, len, map));
1345        }
1346        if let (Some(one), Some(other)) = (packing(left), packing(right)) {
1347            return packings_against_each_other(op, &one, &other, len, map);
1348        }
1349        // A bit packed column against a flat one, which is the pair a clustered table hands the
1350        // filter. Inside a narrow partition a date column takes few enough distinct values to pack
1351        // and the column beside it does not, so the better encoding the clustering buys is what
1352        // used to send the comparison to the row at a time path. Both sides are read where they
1353        // are, the packed one as its base plus its code and the flat one as the number it already
1354        // is. On TPC-H this is `l_commitdate < l_receiptdate` on the clustered file, which is q4
1355        // and q21.
1356        if let (Some(one), Some(other)) = (packing(left), &other) {
1357            return packing_against_run(op, &one, other, len, map);
1358        }
1359        if let (Some(one), Some(other)) = (&one, packing(right)) {
1360            return packing_against_run(op.swapped(), &other, one, len, map);
1361        }
1362    }
1363    if let (Some(one), Some(value)) = (&one, right.constant_value()) {
1364        let column = readied(held, left.logical_type(), value)?;
1365        let other = column.data()?;
1366        return match one {
1367            Through::Direct(a) => {
1368                dispatch(op, len, a, map, other, first, left_valid, right_valid, map)
1369            }
1370            Through::Coded(codes, a) => dispatch(
1371                op,
1372                len,
1373                a,
1374                |slot| codes[map(slot)] as usize,
1375                other,
1376                first,
1377                left_valid,
1378                right_valid,
1379                map,
1380            ),
1381        };
1382    }
1383    if let (Some(value), Some(other)) = (left.constant_value(), &other) {
1384        // The same loop with the comparison turned around, rather than a second loop.
1385        let column = readied(held, right.logical_type(), value)?;
1386        let one = column.data()?;
1387        return match other {
1388            Through::Direct(b) => {
1389                dispatch(op.swapped(), len, b, map, one, first, right_valid, left_valid, map)
1390            }
1391            Through::Coded(codes, b) => dispatch(
1392                op.swapped(),
1393                len,
1394                b,
1395                |slot| codes[map(slot)] as usize,
1396                one,
1397                first,
1398                right_valid,
1399                left_valid,
1400                map,
1401            ),
1402        };
1403    }
1404    // A compressed column against a literal, tested in the code space the column is already in.
1405    // Only equality, because a symbol code says nothing about where its symbol sorts, so an ordering
1406    // comparison has to decompress and does. Equality does not: compressing is a function of the
1407    // table and the bytes, so two strings have the same codes exactly when they are the same string.
1408    if matches!(op, Comparison::Equal | Comparison::NotEqual) {
1409        if let (Some(coded), Some(value)) = (left.coded_parts(), right.constant_value()) {
1410            let wanted = encoded(&coded, held, left.logical_type(), value)?;
1411            return Some(coded_against(op, &coded, &wanted, len, map));
1412        }
1413        if let (Some(value), Some(coded)) = (left.constant_value(), right.coded_parts()) {
1414            let wanted = encoded(&coded, held, right.logical_type(), value)?;
1415            return Some(coded_against(op, &coded, &wanted, len, map));
1416        }
1417    }
1418    // A string column against another one or against a literal, with the views read where they are.
1419    // It catches the string view form, whose bytes live in an arena the vector shares and so has no
1420    // data slice for the branches above to find, and it catches the flat form as well so that the
1421    // two cannot be compared by two different loops. The order itself is the one `view_order`
1422    // writes down either way.
1423    if let (Some((one, one_arena)), Some((other, other_arena))) =
1424        (left.text_parts(), right.text_parts())
1425    {
1426        return Some(sweep(
1427            op,
1428            len,
1429            |index| view_order(one.get(map(index)), one_arena, other.get(map(index)), other_arena),
1430            left_valid,
1431            right_valid,
1432            map,
1433        ));
1434    }
1435    // A string column against a literal. The literal becomes one view before the loop starts, so
1436    // every row is a four byte prefix against the same four bytes and the payload is only read for
1437    // the rows the prefix could not settle.
1438    if let (Some((one, one_arena)), Some(value)) = (left.text_parts(), right.constant_value()) {
1439        let column = readied(held, left.logical_type(), value)?;
1440        let (other, other_arena) = column.text_parts()?;
1441        let wanted = other.first();
1442        return Some(sweep(
1443            op,
1444            len,
1445            |index| view_order(one.get(map(index)), one_arena, wanted, other_arena),
1446            left_valid,
1447            right_valid,
1448            map,
1449        ));
1450    }
1451    if let (Some(value), Some((other, other_arena))) = (left.constant_value(), right.text_parts()) {
1452        // The same loop with the comparison turned around, rather than a second loop.
1453        let column = readied(held, right.logical_type(), value)?;
1454        let (one, one_arena) = column.text_parts()?;
1455        let wanted = one.first();
1456        return Some(sweep(
1457            op.swapped(),
1458            len,
1459            |index| view_order(other.get(map(index)), other_arena, wanted, one_arena),
1460            right_valid,
1461            left_valid,
1462            map,
1463        ));
1464    }
1465    if let (Some((codes, values)), Some(value)) = (left.positions(), right.constant_value()) {
1466        let one = values.data()?;
1467        let column = readied(held, left.logical_type(), value)?;
1468        let other = column.data()?;
1469        let at = |index: usize| codes[map(index)] as usize;
1470        return dispatch(op, len, one, at, other, first, left_valid, right_valid, map);
1471    }
1472    if let (Some(value), Some((codes, values))) = (left.constant_value(), right.positions()) {
1473        let other = values.data()?;
1474        let column = readied(held, right.logical_type(), value)?;
1475        let one = column.data()?;
1476        let at = |index: usize| codes[map(index)] as usize;
1477        return dispatch(op.swapped(), len, other, at, one, first, right_valid, left_valid, map);
1478    }
1479    // A dictionary against a flat column. This pair had no loop until the kernel table put a number
1480    // on what that cost, which on `server3` was 83 nanoseconds a row against 1.2 for the dictionary
1481    // against constant pair beside it, on the same data and the same operator. It is not a rare
1482    // shape either: it is what a filtered column compared against an unfiltered one is, which is
1483    // every conjunct after the first.
1484    if let (Some((codes, values)), Some(other)) = (left.positions(), right.data()) {
1485        let one = values.data()?;
1486        let at = |index: usize| codes[map(index)] as usize;
1487        return dispatch(op, len, one, at, other, map, left_valid, right_valid, map);
1488    }
1489    if let (Some(one), Some((codes, values))) = (left.data(), right.positions()) {
1490        let other = values.data()?;
1491        let at = |index: usize| codes[map(index)] as usize;
1492        return dispatch(op.swapped(), len, other, at, one, map, right_valid, left_valid, map);
1493    }
1494    None
1495}
1496
1497/// A literal as the whole number it is, and `None` for one that is not a whole number.
1498///
1499/// It goes through [`readied`] rather than reading the [`Value`] apart, so that a literal written
1500/// as `900` against a `SMALLINT` column is narrowed by the same cast path every other comparison
1501/// narrows it with. Reading the value apart here would be a second cast path with its own rounding
1502/// and its own overflow rule, which is how two comparisons of the same literal end up disagreeing.
1503fn exact(held: Option<&Held>, ty: &LogicalType, value: &Value) -> Option<i128> {
1504    let column = readied(held, ty, value)?;
1505    let data = column.data()?;
1506    data.signed_at(0).or_else(|| data.unsigned_at(0).and_then(|value| i128::try_from(value).ok()))
1507}
1508
1509/// A literal in the code space a compressed column is in, and `None` for one with no bytes.
1510///
1511/// It goes through [`readied`] for the reason [`exact`] does: the literal is narrowed to the column
1512/// type by the same path every other comparison narrows it with, rather than by a second reading of
1513/// the [`Value`] that could disagree with the first.
1514fn encoded(
1515    coded: &Coded<'_>,
1516    held: Option<&Held>,
1517    ty: &LogicalType,
1518    value: &Value,
1519) -> Option<Vec<u8>> {
1520    let column = readied(held, ty, value)?;
1521    let (views, arena) = column.text_parts()?;
1522    Some(coded.encode(views.first()?.bytes_in(arena)?))
1523}
1524
1525/// A compressed column against a literal, tested without decompressing a row of it.
1526///
1527/// The comparison is a byte slice against a byte slice, which is what it would have been on the
1528/// strings, over half as many bytes and with no decompression before it. A row whose codes are a
1529/// different length is settled by the length alone, which on a column of URLs is most of them.
1530fn coded_against<M>(
1531    op: Comparison,
1532    coded: &Coded<'_>,
1533    wanted: &[u8],
1534    len: usize,
1535    map: M,
1536) -> Vec<bool>
1537where
1538    M: Fn(usize) -> usize + Copy,
1539{
1540    let same = op == Comparison::Equal;
1541    let mut answers = Vec::with_capacity(len);
1542    for row in 0..len {
1543        answers.push((coded.row(map(row)) == Some(wanted)) == same);
1544    }
1545    answers
1546}
1547
1548/// A bit packed column against a literal, compared in the code space the column is already in.
1549///
1550/// The translation is one subtraction done once. After it the loop is a shift, a mask and a compare
1551/// of two `u64`, which is what the flat loop would have been doing anyway minus the unpacking, so
1552/// the form costs nothing on the operation a filter spends most of its time in.
1553///
1554/// The operator is a match out here and a separate loop under each arm rather than one loop calling
1555/// a function it was handed. A function pointer is an indirect call per row, and a loop with one in
1556/// it is a loop the compiler will not widen, so the compare that should have been a few rows at a
1557/// time was one row at a time with a call in the middle. On a sample of the TPC-H q20 filter, which
1558/// is two comparisons of a packed date column over six million rows, this pair of loops was two
1559/// thirds of everything the scan did.
1560///
1561/// The codes go into a vector each thread keeps and the answers are built by the sweep rather than
1562/// laid out as a run of `false` for it to write over. Both of those were an allocation and a run of
1563/// zeroes per chunk per conjunct, and a filter over six million rows is three thousand chunks, so
1564/// the allocator and the zeroing were four of the twenty two instructions a row this path costs.
1565fn packed_against<M>(
1566    op: Comparison,
1567    packed: &Packed<'_>,
1568    wanted: i128,
1569    len: usize,
1570    map: M,
1571) -> Vec<bool>
1572where
1573    M: Fn(usize) -> usize + Copy,
1574{
1575    let Some(code) = packed.code_of(wanted) else {
1576        // The literal is outside the range the width can hold, so every row answers the same way
1577        // and the answer is arithmetic on two numbers rather than a pass over the column.
1578        let above = wanted > packed.ceiling();
1579        let same = match op {
1580            Comparison::Equal | Comparison::NotDistinctFrom => false,
1581            Comparison::NotEqual | Comparison::DistinctFrom => true,
1582            Comparison::Less | Comparison::LessOrEqual => above,
1583            Comparison::Greater | Comparison::GreaterOrEqual => !above,
1584        };
1585        return vec![same; len];
1586    };
1587    thread_local! {
1588        static CODES: RefCell<Vec<u64>> = const { RefCell::new(Vec::new()) };
1589    }
1590    // Taken out of the thread's slot and put back rather than borrowed for the body, because a body
1591    // in a closure that both arms of a borrow call is a body that stops being inlined, and the sweep
1592    // under each arm is the loop this whole path exists to keep tight.
1593    let mut held = CODES.with_borrow_mut(std::mem::take);
1594    // Unpacked in bulk first, so that the loop under each arm is a compare of two numbers. See
1595    // [`Packed::unpack`].
1596    packed.codes_into(map, len, &mut held);
1597    let codes = &held[..len];
1598    /// One pass over the rows with the comparison inlined into it.
1599    macro_rules! sweep {
1600        ($test:expr) => {{
1601            let test = $test;
1602            codes.iter().map(|&found| test(found, code)).collect()
1603        }};
1604    }
1605    let answers: Vec<bool> = match op {
1606        Comparison::Equal | Comparison::NotDistinctFrom => sweep!(|found, want| found == want),
1607        Comparison::NotEqual | Comparison::DistinctFrom => sweep!(|found, want| found != want),
1608        Comparison::Less => sweep!(|found, want| found < want),
1609        Comparison::LessOrEqual => sweep!(|found, want| found <= want),
1610        Comparison::Greater => sweep!(|found, want| found > want),
1611        Comparison::GreaterOrEqual => sweep!(|found, want| found >= want),
1612    };
1613    CODES.with_borrow_mut(|slot| *slot = held);
1614    answers
1615}
1616
1617/// Two bit packed columns against each other, which is the pair a stored table produces.
1618///
1619/// A packed vector's value is its base plus its code, so a row is compared by adding each side's
1620/// base to each side's code and comparing the two sums. Nothing is unpacked into a vector of its
1621/// own and no `Value` is built, which is what the row at a time path underneath this was doing for
1622/// both sides of every row.
1623///
1624/// The two bases are almost never the same number, since each one is the smallest value in its own
1625/// column, so there is no shortcut in comparing the codes directly. What there is instead is that
1626/// the ranges may not overlap at all: a column whose largest value is below the other's smallest
1627/// answers every row the same way, and that is decided here out of four numbers with no bit of
1628/// either column being read.
1629///
1630/// `None` for a pair whose base plus width does not fit, which sends it to the row at a time path
1631/// rather than wrapping. A `DECIMAL(38)` column can be packed and its base can sit near the end of
1632/// the range, and the loop adds without asking so the asking happens once out here.
1633///
1634/// Each side takes its own index mapping, which is what lets a dictionary over a packed run of
1635/// values reach this with its codes as the mapping. A stored column of dates is that as often as it
1636/// is a packed run on its own, and from here the two are one loop with a different index.
1637///
1638/// On TPC-H this is `l_commitdate < l_receiptdate` and `l_shipdate < l_commitdate`, two packed date
1639/// columns of six million rows, which is q4, q12 and q21.
1640fn packed_against_packed<L, R, M>(
1641    op: Comparison,
1642    left: &Packed<'_>,
1643    at_left: L,
1644    right: &Packed<'_>,
1645    at_right: R,
1646    len: usize,
1647    map: M,
1648) -> Option<Vec<bool>>
1649where
1650    L: Fn(usize) -> usize,
1651    R: Fn(usize) -> usize,
1652    M: Fn(usize) -> usize + Copy,
1653{
1654    let (low, high) = (left.base(), ceiling_of(left)?);
1655    let (other_low, other_high) = (right.base(), ceiling_of(right)?);
1656    if high < other_low || other_high < low {
1657        // The two ranges are disjoint, so every row of the left column is on the same side of every
1658        // row of the right one and the answer is arithmetic on four numbers.
1659        let below = high < other_low;
1660        let same = match op {
1661            Comparison::Equal | Comparison::NotDistinctFrom => false,
1662            Comparison::NotEqual | Comparison::DistinctFrom => true,
1663            Comparison::Less | Comparison::LessOrEqual => below,
1664            Comparison::Greater | Comparison::GreaterOrEqual => !below,
1665        };
1666        return Some(vec![same; len]);
1667    }
1668    // The operator is a match out here with a loop under each arm, the same way `packed_against`
1669    // takes it and for the same reason.
1670    let mut answers = vec![false; len];
1671    /// One pass over the rows with the comparison inlined into it.
1672    macro_rules! sweep {
1673        ($test:expr) => {{
1674            let test = $test;
1675            for (slot, answer) in answers.iter_mut().enumerate() {
1676                let row = map(slot);
1677                *answer = test(
1678                    low + i128::from(left.code(at_left(row))),
1679                    other_low + i128::from(right.code(at_right(row))),
1680                );
1681            }
1682        }};
1683    }
1684    match op {
1685        Comparison::Equal | Comparison::NotDistinctFrom => sweep!(|one, other| one == other),
1686        Comparison::NotEqual | Comparison::DistinctFrom => sweep!(|one, other| one != other),
1687        Comparison::Less => sweep!(|one, other| one < other),
1688        Comparison::LessOrEqual => sweep!(|one, other| one <= other),
1689        Comparison::Greater => sweep!(|one, other| one > other),
1690        Comparison::GreaterOrEqual => sweep!(|one, other| one >= other),
1691    }
1692    Some(answers)
1693}
1694
1695/// A side whose values are a packed run, either its own or one a dictionary points into.
1696///
1697/// A dictionary of few distinct numbers over a wide range is what our own storage writes for a
1698/// column like a date, and [`through`] answers `None` for it because a packed run is not a run of
1699/// `Data` to index. This is the same question asked of the form underneath.
1700enum Packing<'a> {
1701    /// The run is this vector's own and row `n` is code `n` of it.
1702    Straight(Packed<'a>),
1703    /// The run belongs to a dictionary and row `n` is the code the run names for it.
1704    Coded(Cow<'a, [u32]>, Packed<'a>),
1705}
1706
1707/// How `vector` reaches a packed run, or `None` when it does not have one.
1708fn packing(vector: &Vector) -> Option<Packing<'_>> {
1709    if let Some(packed) = vector.packed_parts() {
1710        return Some(Packing::Straight(packed));
1711    }
1712    let (codes, values) = vector.positions()?;
1713    Some(Packing::Coded(codes, values.packed_parts()?))
1714}
1715
1716/// The four ways a pair of packed runs can be indexed, resolved once out here so that the loop
1717/// underneath is monomorphized on both mappings rather than calling through a pointer per row.
1718fn packings_against_each_other<M>(
1719    op: Comparison,
1720    left: &Packing<'_>,
1721    right: &Packing<'_>,
1722    len: usize,
1723    map: M,
1724) -> Option<Vec<bool>>
1725where
1726    M: Fn(usize) -> usize + Copy,
1727{
1728    match (left, right) {
1729        (Packing::Straight(one), Packing::Straight(other)) => {
1730            packed_against_packed(op, one, identity, other, identity, len, map)
1731        }
1732        (Packing::Straight(one), Packing::Coded(codes, other)) => {
1733            packed_against_packed(op, one, identity, other, |row| codes[row] as usize, len, map)
1734        }
1735        (Packing::Coded(codes, one), Packing::Straight(other)) => {
1736            packed_against_packed(op, one, |row| codes[row] as usize, other, identity, len, map)
1737        }
1738        (Packing::Coded(codes, one), Packing::Coded(others, other)) => packed_against_packed(
1739            op,
1740            one,
1741            |row| codes[row] as usize,
1742            other,
1743            |row| others[row] as usize,
1744            len,
1745            map,
1746        ),
1747    }
1748}
1749
1750/// A packed run against a run of whole numbers, with the four ways to index the pair resolved here.
1751///
1752/// The answer is for `packed op run`, so a caller with the flat side on the left hands the swapped
1753/// operator rather than a second loop. It is the same arrangement [`packings_against_each_other`]
1754/// has and it is here for the same reason: the mapping is picked once out here so that the loop
1755/// underneath is monomorphized on it rather than calling through a pointer per row.
1756fn packing_against_run<M>(
1757    op: Comparison,
1758    packed: &Packing<'_>,
1759    run: &Through<'_>,
1760    len: usize,
1761    map: M,
1762) -> Option<Vec<bool>>
1763where
1764    M: Fn(usize) -> usize + Copy,
1765{
1766    match (packed, run) {
1767        (Packing::Straight(one), Through::Direct(other)) => {
1768            packed_against_flat(op, one, identity, other, identity, len, map)
1769        }
1770        (Packing::Straight(one), Through::Coded(codes, other)) => {
1771            packed_against_flat(op, one, identity, other, |row| codes[row] as usize, len, map)
1772        }
1773        (Packing::Coded(codes, one), Through::Direct(other)) => {
1774            packed_against_flat(op, one, |row| codes[row] as usize, other, identity, len, map)
1775        }
1776        (Packing::Coded(codes, one), Through::Coded(others, other)) => packed_against_flat(
1777            op,
1778            one,
1779            |row| codes[row] as usize,
1780            other,
1781            |row| others[row] as usize,
1782            len,
1783            map,
1784        ),
1785    }
1786}
1787
1788/// A bit packed column against a flat one, with neither side turned into the other.
1789///
1790/// The packed side is its base plus its code and the flat side is the number it already holds, so
1791/// the loop is an add, a widen and a compare, and nothing is unpacked into a vector of its own. The
1792/// row at a time path underneath this was building a [`Value`] for both sides of every row.
1793///
1794/// `None` for a layout whose values do not all fit in an `i128`, and for a packed side whose base
1795/// plus width does not fit either, which is the question [`ceiling_of`] asks. The loop adds without
1796/// asking so the asking happens once out here, the same way [`packed_against_packed`] does it.
1797///
1798/// This is the pair a clustered table produces. Sorting lineitem by month of `l_shipdate` leaves
1799/// `l_commitdate` with about a hundred distinct values inside a partition, which packs, while
1800/// `l_receiptdate` arrives flat, and `l_commitdate < l_receiptdate` is q4, q12 and q21.
1801fn packed_against_flat<L, R, M>(
1802    op: Comparison,
1803    packed: &Packed<'_>,
1804    at_packed: L,
1805    flat: &Data,
1806    at_flat: R,
1807    len: usize,
1808    map: M,
1809) -> Option<Vec<bool>>
1810where
1811    L: Fn(usize) -> usize,
1812    R: Fn(usize) -> usize,
1813    M: Fn(usize) -> usize + Copy,
1814{
1815    ceiling_of(packed)?;
1816    let base = packed.base();
1817    macro_rules! layouts {
1818        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
1819            match flat {
1820                $(
1821                    Data::$variant(run) => Some(numbers_compared(op, len, |slot| {
1822                        let row = map(slot);
1823                        (
1824                            base + i128::from(packed.code(at_packed(row))),
1825                            i128::from(run[at_flat(row)]),
1826                        )
1827                    })),
1828                )+
1829                // A layout with no whole number in it, which is every string, float and interval
1830                // column, plus `UBIGINT`'s wider sibling whose largest value has no `i128`.
1831                _ => None,
1832            }
1833        };
1834    }
1835    rudb_vector::for_each_layout!(exact, layouts)
1836}
1837
1838/// One pass over the rows with the comparison inlined into it, over a pair of numbers a row.
1839///
1840/// The operator is a match out here and a separate loop under each arm rather than one loop calling
1841/// a function it was handed, for the reason [`packed_against`] gives: a function pointer is an
1842/// indirect call per row and a loop with one in it is a loop the compiler will not widen.
1843fn numbers_compared<P>(op: Comparison, len: usize, pair: P) -> Vec<bool>
1844where
1845    P: Fn(usize) -> (i128, i128),
1846{
1847    let mut answers = vec![false; len];
1848    /// One pass over the rows with `$test` as the body.
1849    macro_rules! sweep {
1850        ($test:expr) => {{
1851            let test = $test;
1852            for (slot, answer) in answers.iter_mut().enumerate() {
1853                let (one, other) = pair(slot);
1854                *answer = test(one, other);
1855            }
1856        }};
1857    }
1858    match op {
1859        Comparison::Equal | Comparison::NotDistinctFrom => sweep!(|one, other| one == other),
1860        Comparison::NotEqual | Comparison::DistinctFrom => sweep!(|one, other| one != other),
1861        Comparison::Less => sweep!(|one, other| one < other),
1862        Comparison::LessOrEqual => sweep!(|one, other| one <= other),
1863        Comparison::Greater => sweep!(|one, other| one > other),
1864        Comparison::GreaterOrEqual => sweep!(|one, other| one >= other),
1865    }
1866    answers
1867}
1868
1869/// The largest value a packed vector can hold, or `None` if that number does not exist.
1870///
1871/// [`Packed::ceiling`] adds without asking, which is right where the caller has already put a
1872/// literal through [`Packed::code_of`] and so knows the base and the width are a pair that works.
1873/// A loop that adds a code to a base for every row has not asked anything yet, so it asks here.
1874fn ceiling_of(packed: &Packed<'_>) -> Option<i128> {
1875    let mask = u64::MAX >> (u64::BITS - packed.width());
1876    packed.base().checked_add(i128::from(mask))
1877}
1878
1879/// Where a side keeps its values, for the forms that reach them through a run of them.
1880///
1881/// A flat vector holds its values itself and row `n` is at position `n`. A dictionary holds them
1882/// somewhere else and a code per row, so row `n` is at position `codes[n]` of that. A run length
1883/// vector is the same shape with the run index standing in for the code, which is why both come
1884/// from `Vector::positions` rather than from an accessor per form: from here there is no difference
1885/// between them and writing two branches would only be two chances to write one of them wrong.
1886///
1887/// The point of naming it is that the loop underneath does not change. A comparison of two
1888/// dictionary columns is the flat loop with a different index mapping, so it costs one extra load
1889/// per row per coded side against a path that was allocating a `Value` per row and calling the
1890/// generic comparison on it. On TPC-H that path was `l_commitdate < l_receiptdate`, two dictionary
1891/// encoded date columns of six million rows, which is q4, q12 and q21.
1892enum Through<'a> {
1893    /// The values are this vector's own and row `n` is at position `n`.
1894    Direct(&'a Data),
1895    /// The values are somewhere else and row `n` is at the position this run names for it.
1896    Coded(Cow<'a, [u32]>, &'a Data),
1897}
1898
1899/// How `vector` reaches its values, or `None` for a form that does not reach them through a run.
1900///
1901/// A constant, a bit packed column and a compressed one all answer `None` here, and each has a
1902/// branch of its own further down [`specialized`] that does something better than reading a run
1903/// would. A dictionary whose values are themselves not flat answers `None` too, because then there
1904/// is no run to index and the only thing left is the row at a time path.
1905fn through(vector: &Vector) -> Option<Through<'_>> {
1906    if let Some(data) = vector.data() {
1907        return Some(Through::Direct(data));
1908    }
1909    let (codes, values) = vector.positions()?;
1910    Some(Through::Coded(codes, values.data()?))
1911}
1912
1913/// One loop per physical layout, generated rather than written out.
1914///
1915/// The two index closures are what let the same body serve flat against flat, a column against a
1916/// constant and a dictionary against a constant. `identity` on both sides is the first, `first` on
1917/// the right is the second, and the codes on the left are the third.
1918#[expect(
1919    clippy::too_many_arguments,
1920    reason = "two sides with an index each, the operator, the length and two validities, all of \
1921              which the loop needs and none of which is worth a struct that exists for one call"
1922)]
1923fn dispatch<L, R, V>(
1924    op: Comparison,
1925    len: usize,
1926    left: &Data,
1927    at_left: L,
1928    right: &Data,
1929    at_right: R,
1930    left_valid: &Validity,
1931    right_valid: &Validity,
1932    at_valid: V,
1933) -> Option<Vec<bool>>
1934where
1935    L: Fn(usize) -> usize,
1936    R: Fn(usize) -> usize,
1937    V: Fn(usize) -> usize,
1938{
1939    macro_rules! layouts {
1940        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
1941            match (left, right) {
1942                $(
1943                    (Data::$variant(one), Data::$variant(other)) => Some(sweep(
1944                        op,
1945                        len,
1946                        |index| one[at_left(index)].cmp(&other[at_right(index)]),
1947                        left_valid,
1948                        right_valid,
1949                        &at_valid,
1950                    )),
1951                )+
1952                // Floats have their own order, which is DuckDB's rather than IEEE's, and the
1953                // widening on a `f32` is free because the comparison is against another `f32`.
1954                (Data::Float32(one), Data::Float32(other)) => Some(sweep(
1955                    op,
1956                    len,
1957                    |index| {
1958                        float_order(
1959                            f64::from(one[at_left(index)]),
1960                            f64::from(other[at_right(index)]),
1961                        )
1962                    },
1963                    left_valid,
1964                    right_valid,
1965                    &at_valid,
1966                )),
1967                (Data::Float64(one), Data::Float64(other)) => Some(sweep(
1968                    op,
1969                    len,
1970                    |index| float_order(one[at_left(index)], other[at_right(index)]),
1971                    left_valid,
1972                    right_valid,
1973                    &at_valid,
1974                )),
1975                // An interval is three counts and the order is over the one length they add up to,
1976                // so this is not the derived order of the triple and cannot be generated above.
1977                (Data::Interval(one), Data::Interval(other)) => Some(sweep(
1978                    op,
1979                    len,
1980                    |index| {
1981                        let (months, days, micros) = one[at_left(index)];
1982                        let (bm, bd, bu) = other[at_right(index)];
1983                        interval_micros(months, days, micros).cmp(&interval_micros(bm, bd, bu))
1984                    },
1985                    left_valid,
1986                    right_valid,
1987                    &at_valid,
1988                )),
1989                (Data::Varlen(one), Data::Varlen(other)) => Some(sweep(
1990                    op,
1991                    len,
1992                    |index| string_order(one, at_left(index), other, at_right(index)),
1993                    left_valid,
1994                    right_valid,
1995                    &at_valid,
1996                )),
1997                _ => None,
1998            }
1999        };
2000    }
2001    rudb_vector::for_each_layout!(ordered, layouts)
2002}
2003
2004/// The one row column for a constant, either the one that was built early or one built here.
2005///
2006/// Borrowed when a caller handed one over for this side and this value, owned when it did not, and
2007/// the loop below cannot tell the two apart. `None` is a type with no column layout, which is what
2008/// sends the whole comparison to the row at a time path.
2009fn readied<'a>(held: Option<&'a Held>, ty: &LogicalType, value: &Value) -> Option<Cow<'a, Vector>> {
2010    match held {
2011        Some(held) if held.matches(ty, value) => Some(Cow::Borrowed(held.single())),
2012        _ => Some(Cow::Owned(single(ty, value)?)),
2013    }
2014}
2015
2016/// Two strings in byte order, resolved from the four byte prefix where it can be.
2017///
2018/// The lemma this rests on is that prefix order is byte order whenever the two prefixes differ. A
2019/// view pads a string shorter than four bytes with zeros, zero is the least byte, and byte order
2020/// says a string is less than any string that extends it, so padding compares the same way the
2021/// missing bytes would have. When the prefixes are equal the payload settles it, which for an
2022/// inline string is the same sixteen bytes already loaded and for a long one is a block read.
2023fn string_order(
2024    left: &StringColumn,
2025    at_left: usize,
2026    right: &StringColumn,
2027    at_right: usize,
2028) -> Ordering {
2029    view_order(left.views().get(at_left), left.arena(), right.views().get(at_right), right.arena())
2030}
2031
2032/// The same comparison written against a view and the arena behind it rather than against a column.
2033///
2034/// Both forms that hold strings come through here, so a flat varchar column and a string view column
2035/// order a pair of rows the same way and there is no second copy of the prefix rule to drift from
2036/// this one.
2037fn view_order(
2038    one: Option<&StringView>,
2039    one_arena: &[u8],
2040    other: Option<&StringView>,
2041    other_arena: &[u8],
2042) -> Ordering {
2043    let (Some(one), Some(other)) = (one, other) else {
2044        return Ordering::Equal;
2045    };
2046    let (prefix, against) = (one.prefix(), other.prefix());
2047    if prefix != against {
2048        return prefix.cmp(&against);
2049    }
2050    // Bytes rather than `StringColumn::get`, which validates UTF-8. Everything in a column was
2051    // pushed from a `&str` so the validation cannot fail, and on a URL column, where every row
2052    // shares the `http` prefix and the payload therefore decides every comparison, it was the
2053    // larger half of the per row cost.
2054    let bytes = one.bytes_in(one_arena).unwrap_or_default();
2055    let against_bytes = other.bytes_in(other_arena).unwrap_or_default();
2056    bytes.cmp(against_bytes)
2057}
2058
2059/// The answers for one ordering, with the operator decided once rather than once per row.
2060///
2061/// This is where the match on the operator gets hoisted. Each arm calls a generic `fill` with a
2062/// different predicate, so the compiler produces eight loops whose bodies are an ordering against a
2063/// constant, rather than one loop with a branch table in it.
2064fn sweep<O, V>(
2065    op: Comparison,
2066    len: usize,
2067    order_at: O,
2068    left_valid: &Validity,
2069    right_valid: &Validity,
2070    at_valid: V,
2071) -> Vec<bool>
2072where
2073    O: Fn(usize) -> Ordering,
2074    V: Fn(usize) -> usize,
2075{
2076    let mut answers = vec![false; len];
2077    match op {
2078        Comparison::Equal => fill(&mut answers, order_at, |o| o == Ordering::Equal),
2079        Comparison::NotEqual => fill(&mut answers, order_at, |o| o != Ordering::Equal),
2080        Comparison::Less => fill(&mut answers, order_at, |o| o == Ordering::Less),
2081        Comparison::LessOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Greater),
2082        Comparison::Greater => fill(&mut answers, order_at, |o| o == Ordering::Greater),
2083        Comparison::GreaterOrEqual => fill(&mut answers, order_at, |o| o != Ordering::Less),
2084        Comparison::DistinctFrom => {
2085            total(&mut answers, order_at, left_valid, right_valid, at_valid);
2086            for answer in &mut answers {
2087                *answer = !*answer;
2088            }
2089        }
2090        Comparison::NotDistinctFrom => {
2091            total(&mut answers, order_at, left_valid, right_valid, at_valid);
2092        }
2093    }
2094    answers
2095}
2096
2097/// One loop, one predicate, no branch on the operator.
2098#[inline]
2099fn fill<O, H>(answers: &mut [bool], order_at: O, held: H)
2100where
2101    O: Fn(usize) -> Ordering,
2102    H: Fn(Ordering) -> bool,
2103{
2104    for (index, answer) in answers.iter_mut().enumerate() {
2105        *answer = held(order_at(index));
2106    }
2107}
2108
2109/// `IS NOT DISTINCT FROM`, which reads validity as data rather than as an absence.
2110///
2111/// Two nulls are the same value here and a null against anything else is not, which is the whole
2112/// difference between this and `=`. The all valid case is checked once so that the common shape,
2113/// which is a total comparison inside a join on columns that happen not to be nullable, does not
2114/// pay for two validity lookups per row.
2115fn total<O, V>(
2116    answers: &mut [bool],
2117    order_at: O,
2118    left_valid: &Validity,
2119    right_valid: &Validity,
2120    at_valid: V,
2121) where
2122    O: Fn(usize) -> Ordering,
2123    V: Fn(usize) -> usize,
2124{
2125    if *left_valid == Validity::AllValid && *right_valid == Validity::AllValid {
2126        fill(answers, order_at, |o| o == Ordering::Equal);
2127        return;
2128    }
2129    for (index, answer) in answers.iter_mut().enumerate() {
2130        let row = at_valid(index);
2131        *answer = match (left_valid.is_valid(row), right_valid.is_valid(row)) {
2132            (true, true) => order_at(index) == Ordering::Equal,
2133            (false, false) => true,
2134            _ => false,
2135        };
2136    }
2137}
2138
2139/// Compares two values, producing `TRUE`, `FALSE` or `NULL`.
2140///
2141/// # Errors
2142///
2143/// If the two types cannot be compared, which after binding means one of them is a nested type.
2144pub fn compare_values(op: Comparison, left: &Value, right: &Value) -> Result<Value> {
2145    if op.is_total() {
2146        let same = match (left.is_null(), right.is_null()) {
2147            (true, true) => true,
2148            (true, false) | (false, true) => false,
2149            (false, false) => order(left, right)? == Ordering::Equal,
2150        };
2151        return Ok(Value::Boolean(match op {
2152            Comparison::NotDistinctFrom => same,
2153            _ => !same,
2154        }));
2155    }
2156    if left.is_null() || right.is_null() {
2157        return Ok(Value::Null);
2158    }
2159    let ordering = order(left, right)?;
2160    let held = match op {
2161        Comparison::Equal => ordering == Ordering::Equal,
2162        Comparison::NotEqual => ordering != Ordering::Equal,
2163        Comparison::Less => ordering == Ordering::Less,
2164        Comparison::LessOrEqual => ordering != Ordering::Greater,
2165        Comparison::Greater => ordering == Ordering::Greater,
2166        Comparison::GreaterOrEqual => ordering != Ordering::Less,
2167        Comparison::DistinctFrom | Comparison::NotDistinctFrom => {
2168            return Err(Error::internal("a total comparison reached the ordered path"));
2169        }
2170    };
2171    Ok(Value::Boolean(held))
2172}
2173
2174/// The order of two values, neither of which is null.
2175///
2176/// This is the one place the sort order of a type is written down. `ORDER BY`, `GROUP BY`, a merge
2177/// join and a min or max aggregate all reach it, and a type that ordered differently in two of
2178/// those would produce a query whose answer depends on which operator the optimizer picked.
2179///
2180/// # Errors
2181///
2182/// If either value is null, which is the caller's mistake rather than a comparison, or if the
2183/// types have no order between them.
2184pub fn order(left: &Value, right: &Value) -> Result<Ordering> {
2185    match (left, right) {
2186        (Value::Null, _) | (_, Value::Null) => {
2187            Err(Error::internal("a null reached the ordering path"))
2188        }
2189        (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
2190        (Value::Varchar(a), Value::Varchar(b)) => Ok(a.as_bytes().cmp(b.as_bytes())),
2191        (Value::Blob(a), Value::Blob(b)) => Ok(a.cmp(b)),
2192        (Value::Bit(a), Value::Bit(b)) => Ok(rudb_common::bit::cmp(a, b)),
2193        (Value::Date(a), Value::Date(b)) => Ok(a.cmp(b)),
2194        // A zoned value orders with its own kind and by the same rule, since both of them are the
2195        // count of microseconds from a fixed point and the zone is about printing.
2196        (Value::Time(a), Value::Time(b))
2197        | (Value::TimeTz(a), Value::TimeTz(b))
2198        | (Value::Timestamp(a), Value::Timestamp(b))
2199        | (Value::TimestampTz(a), Value::TimestampTz(b)) => Ok(a.cmp(b)),
2200        (
2201            Value::Interval { months: am, days: ad, micros: au },
2202            Value::Interval { months: bm, days: bd, micros: bu },
2203        ) => Ok(interval_micros(*am, *ad, *au).cmp(&interval_micros(*bm, *bd, *bu))),
2204        (Value::List { values: a, .. }, Value::List { values: b, .. }) => list_order(a, b),
2205        // Two structs of one type order field by field in the order the type lists them, with a
2206        // null field above everything the way a null element is in a list, which is the pin's.
2207        (Value::Struct(a), Value::Struct(b)) => {
2208            for ((_, one), (_, other)) in a.iter().zip(b) {
2209                let ordering = order_with_nulls(one, other, false)?;
2210                if ordering != Ordering::Equal {
2211                    return Ok(ordering);
2212                }
2213            }
2214            Ok(a.len().cmp(&b.len()))
2215        }
2216        // A map is a list of key and value structs underneath on the pin and orders as one, entry
2217        // by entry and key before value, with the shorter one first when one runs out.
2218        (Value::Map { entries: a, .. }, Value::Map { entries: b, .. }) => {
2219            for ((key, value), (other_key, other_value)) in a.iter().zip(b) {
2220                let ordering = order_with_nulls(key, other_key, false)?.then(order_with_nulls(
2221                    value,
2222                    other_value,
2223                    false,
2224                )?);
2225                if ordering != Ordering::Equal {
2226                    return Ok(ordering);
2227                }
2228            }
2229            Ok(a.len().cmp(&b.len()))
2230        }
2231        _ => numeric_order(left, right),
2232    }
2233}
2234
2235/// Two lists in the order DuckDB puts them in, which is the order two words are in a dictionary.
2236///
2237/// The first element the two disagree on decides, and if neither ran out of elements before that
2238/// happened then the shorter one is the smaller one. So `[] < [1]` and `[1, 2] < [1, 2, 3]`, and a
2239/// list is never equal to a longer list that starts with it.
2240///
2241/// A null element is not an absence here, it is the largest value there is, which is the one place
2242/// a comparison inside a list disagrees with the same comparison outside one. `[1, NULL] > [1, 2]`
2243/// is true on the pin and `[NULL] < [1]` is false, and two nulls in the same position are equal,
2244/// which is what makes `[1, NULL] = [1, NULL]` true while `NULL = NULL` is null. That is
2245/// [`order_with_nulls`] with nulls last, so it is the sort's rule and not a second one written here.
2246///
2247/// A null list, as opposed to a list with a null in it, never reaches this. It is handled by the
2248/// caller the way a null of any other type is, which is why `NULL::INT[] = [1]` is null.
2249fn list_order(left: &[Value], right: &[Value]) -> Result<Ordering> {
2250    for (one, other) in left.iter().zip(right) {
2251        let ordering = order_with_nulls(one, other, false)?;
2252        if ordering != Ordering::Equal {
2253            return Ok(ordering);
2254        }
2255    }
2256    Ok(left.len().cmp(&right.len()))
2257}
2258
2259/// The order of two numbers, which is the case that has to work across representations.
2260fn numeric_order(left: &Value, right: &Value) -> Result<Ordering> {
2261    if let (Some(a), Some(b)) = (integral(left), integral(right)) {
2262        return Ok(a.cmp(&b));
2263    }
2264    if let (
2265        Value::Decimal { unscaled: a, scale: sa, .. },
2266        Value::Decimal { unscaled: b, scale: sb, .. },
2267    ) = (left, right)
2268        && sa == sb
2269    {
2270        return Ok(a.cmp(b));
2271    }
2272    match (approximate(left), approximate(right)) {
2273        (Some(a), Some(b)) => Ok(float_order(a, b)),
2274        _ => Err(Error::not_implemented(format!(
2275            "comparing {} with {}",
2276            left.logical_type(),
2277            right.logical_type()
2278        ))),
2279    }
2280}
2281
2282/// DuckDB's float order: NaN is equal to itself and above everything else, and zero has one place.
2283pub(crate) fn float_order(left: f64, right: f64) -> Ordering {
2284    if left == right {
2285        return Ordering::Equal;
2286    }
2287    match (left.is_nan(), right.is_nan()) {
2288        (true, true) => Ordering::Equal,
2289        (true, false) => Ordering::Greater,
2290        (false, true) => Ordering::Less,
2291        (false, false) => left.partial_cmp(&right).unwrap_or(Ordering::Equal),
2292    }
2293}
2294
2295/// The order of two values with nulls in it, for a sort key.
2296///
2297/// A sort has to put nulls somewhere and SQL lets the query say where, so this takes the answer
2298/// rather than deciding it.
2299///
2300/// # Errors
2301///
2302/// If the two types have no order between them.
2303pub fn order_with_nulls(left: &Value, right: &Value, nulls_first: bool) -> Result<Ordering> {
2304    match (left.is_null(), right.is_null()) {
2305        (true, true) => Ok(Ordering::Equal),
2306        (true, false) => Ok(if nulls_first { Ordering::Less } else { Ordering::Greater }),
2307        (false, true) => Ok(if nulls_first { Ordering::Greater } else { Ordering::Less }),
2308        (false, false) => order(left, right),
2309    }
2310}
2311
2312#[cfg(test)]
2313mod tests {
2314    use super::*;
2315
2316    fn compared(op: Comparison, left: Value, right: Value) -> Value {
2317        compare_values(op, &left, &right).expect("these types compare")
2318    }
2319
2320    /// Every comparison, so that a test that sweeps them cannot quietly miss one.
2321    const EVERY: [Comparison; 8] = [
2322        Comparison::Equal,
2323        Comparison::NotEqual,
2324        Comparison::Less,
2325        Comparison::LessOrEqual,
2326        Comparison::Greater,
2327        Comparison::GreaterOrEqual,
2328        Comparison::DistinctFrom,
2329        Comparison::NotDistinctFrom,
2330    ];
2331
2332    /// The row at a time path, kept as the oracle rather than deleted.
2333    ///
2334    /// `spec/engine/03-data-plane.md` is explicit that the slow path becomes the thing the fast
2335    /// path is checked against. This is that, written out here so that a test can call it on a pair
2336    /// of vectors whose forms the fast path does specialize.
2337    fn oracle(op: Comparison, left: &Vector, right: &Vector) -> Vector {
2338        let values: Vec<Value> = (0..left.len())
2339            .map(|index| {
2340                compare_values(op, &left.value_at(index), &right.value_at(index))
2341                    .expect("the oracle is only asked about types that compare")
2342            })
2343            .collect();
2344        Vector::from_values(LogicalType::Boolean, &values).expect("booleans")
2345    }
2346
2347    /// Asserts that the specialized path and the oracle produce the same vector, not merely the
2348    /// same answers. Same vector means the same data, the same validity representation and the
2349    /// same false in every null position, which is a much stronger statement and is free to check.
2350    fn agrees(op: Comparison, left: &Vector, right: &Vector) {
2351        let fast = compare(op, left, right).expect("compares");
2352        let slow = oracle(op, left, right);
2353        assert_eq!(fast, slow, "{op:?} on a {:?} against a {:?}", left.form(), right.form());
2354    }
2355
2356    /// Every row in blocks of 64 is the plain filter, over empty, full and mixed blocks, with and
2357    /// without a tail, and through a flat column against a literal and against another column.
2358    #[test]
2359    fn rows_kept_in_blocks_are_the_rows_a_plain_filter_keeps() {
2360        let shapes: [fn(usize) -> bool; 5] = [
2361            |_| false,
2362            |_| true,
2363            |row| row % 7 == 3,
2364            |row| (row / 64) % 3 == 1,
2365            |row| (row / 64) % 2 == 0 || row % 61 == 0,
2366        ];
2367        for len in [0, 1, 63, 64, 65, 128, 1000, 2048] {
2368            for held in shapes {
2369                let blocks = kept_where(None, len, held);
2370                let plain: Vec<u32> = (0..len)
2371                    .filter(|&row| held(row))
2372                    .map(|row| u32::try_from(row).expect("small"))
2373                    .collect();
2374                assert_eq!(blocks.indices(), plain.as_slice(), "{len} rows");
2375            }
2376        }
2377        let values: Vec<Value> =
2378            (0..2000).map(|row| Value::SmallInt(if row % 50 == 0 { 3 } else { 0 })).collect();
2379        let column = Vector::from_values(LogicalType::SmallInt, &values).expect("smallints");
2380        let zero = Vector::constant(LogicalType::SmallInt, Value::SmallInt(0), 2000);
2381        let others: Vec<Value> = (0..2000).map(|row| Value::SmallInt(row % 5)).collect();
2382        let others = Vector::from_values(LogicalType::SmallInt, &others).expect("smallints");
2383        for op in [Comparison::NotEqual, Comparison::Equal, Comparison::Less] {
2384            agrees_and_selects(op, &column, &zero);
2385            agrees_and_selects(op, &column, &others);
2386        }
2387    }
2388
2389    /// [`agrees`], and the rows picked straight from the answers are the rows the flag vector
2390    /// gives. Kept apart from `agrees` because a pair of forms with no loop goes the long way here
2391    /// too, and the tests that count the long way would count it twice.
2392    fn agrees_and_selects(op: Comparison, left: &Vector, right: &Vector) {
2393        agrees(op, left, right);
2394        let slow = oracle(op, left, right);
2395        let picked = select_prepared(op, left, right, None).expect("selects");
2396        assert_eq!(
2397            picked.indices(),
2398            crate::select::selection(&slow, slow.len()).indices(),
2399            "{op:?} selected on a {:?} against a {:?}",
2400            left.form(),
2401            right.form()
2402        );
2403    }
2404
2405    /// A small deterministic generator, because a property test with no seed is a test that fails
2406    /// on somebody else's machine and passes on yours.
2407    struct Rng(u64);
2408
2409    impl Rng {
2410        fn next(&mut self) -> u64 {
2411            self.0 ^= self.0 << 13;
2412            self.0 ^= self.0 >> 7;
2413            self.0 ^= self.0 << 17;
2414            self.0
2415        }
2416
2417        fn below(&mut self, bound: u64) -> u64 {
2418            self.next() % bound
2419        }
2420    }
2421
2422    #[test]
2423    fn an_ordinary_comparison_is_null_when_either_side_is() {
2424        assert_eq!(compared(Comparison::Equal, Value::Integer(1), Value::Null), Value::Null);
2425        assert_eq!(compared(Comparison::Less, Value::Null, Value::Integer(1)), Value::Null);
2426    }
2427
2428    #[test]
2429    fn a_total_comparison_is_never_null() {
2430        assert_eq!(
2431            compared(Comparison::NotDistinctFrom, Value::Null, Value::Null),
2432            Value::Boolean(true)
2433        );
2434        assert_eq!(
2435            compared(Comparison::NotDistinctFrom, Value::Integer(1), Value::Null),
2436            Value::Boolean(false)
2437        );
2438        assert_eq!(
2439            compared(Comparison::DistinctFrom, Value::Integer(1), Value::Null),
2440            Value::Boolean(true)
2441        );
2442    }
2443
2444    #[test]
2445    fn a_string_compares_by_bytes() {
2446        assert_eq!(
2447            compared(Comparison::Less, Value::Varchar("a".into()), Value::Varchar("b".into())),
2448            Value::Boolean(true)
2449        );
2450        assert_eq!(
2451            compared(Comparison::Less, Value::Varchar("Z".into()), Value::Varchar("a".into())),
2452            Value::Boolean(true)
2453        );
2454    }
2455
2456    /// The reason this crate does not use `f64::partial_cmp` directly. A NaN that compared
2457    /// unordered would make a group by produce a group nothing can find again.
2458    #[test]
2459    fn two_nans_are_one_value_and_they_sort_above_the_numbers() {
2460        assert_eq!(
2461            compared(Comparison::Equal, Value::Double(f64::NAN), Value::Double(f64::NAN)),
2462            Value::Boolean(true)
2463        );
2464        assert_eq!(
2465            compared(Comparison::Greater, Value::Double(f64::NAN), Value::Double(1e300)),
2466            Value::Boolean(true)
2467        );
2468    }
2469
2470    #[test]
2471    fn zero_has_one_value_however_it_is_signed() {
2472        assert_eq!(
2473            compared(Comparison::Equal, Value::Double(0.0), Value::Double(-0.0)),
2474            Value::Boolean(true)
2475        );
2476    }
2477
2478    /// An interval is three counts and two of them that are the same length are one value, at
2479    /// thirty days to a month and twenty four hours to a day, which is what upstream answers. The
2480    /// three counts are still kept apart, because adding a month to a date is not adding thirty
2481    /// days to it, so these pairs are equal and print differently.
2482    #[test]
2483    fn two_intervals_of_the_same_length_are_one_value() {
2484        let day = Value::Interval { months: 0, days: 1, micros: 0 };
2485        let hours = Value::Interval { months: 0, days: 0, micros: 86_400_000_000 };
2486        let month = Value::Interval { months: 1, days: 0, micros: 0 };
2487        let thirty = Value::Interval { months: 0, days: 30, micros: 0 };
2488        let long_day = Value::Interval { months: 0, days: 0, micros: 90_000_000_000 };
2489        assert_eq!(compared(Comparison::Equal, day.clone(), hours), Value::Boolean(true));
2490        assert_eq!(compared(Comparison::Equal, month, thirty), Value::Boolean(true));
2491        assert_eq!(compared(Comparison::Greater, long_day, day), Value::Boolean(true));
2492    }
2493
2494    #[test]
2495    fn a_number_compares_the_same_however_it_is_stored() {
2496        assert_eq!(
2497            compared(Comparison::Equal, Value::Integer(3), Value::BigInt(3)),
2498            Value::Boolean(true)
2499        );
2500        assert_eq!(
2501            compared(Comparison::Less, Value::Integer(3), Value::Double(3.5)),
2502            Value::Boolean(true)
2503        );
2504    }
2505
2506    #[test]
2507    fn nulls_go_where_the_query_asked_for_them() {
2508        assert_eq!(
2509            order_with_nulls(&Value::Null, &Value::Integer(1), true).expect("orders"),
2510            Ordering::Less
2511        );
2512        assert_eq!(
2513            order_with_nulls(&Value::Null, &Value::Integer(1), false).expect("orders"),
2514            Ordering::Greater
2515        );
2516    }
2517
2518    #[test]
2519    fn two_constant_vectors_cost_one_comparison() {
2520        let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 512);
2521        let right = Vector::constant(LogicalType::Integer, Value::Integer(2), 512);
2522        let result = compare(Comparison::Less, &left, &right).expect("compares");
2523        assert_eq!(result.form(), Form::Constant);
2524        assert_eq!(result.value_at(500), Value::Boolean(true));
2525    }
2526
2527    #[test]
2528    fn a_comparison_of_two_vectors_is_one_answer_per_row() {
2529        let left = Vector::from_values(
2530            LogicalType::Integer,
2531            &[Value::Integer(1), Value::Integer(5), Value::Null],
2532        )
2533        .expect("three rows");
2534        let right = Vector::constant(LogicalType::Integer, Value::Integer(3), 3);
2535        let result = compare(Comparison::Greater, &left, &right).expect("compares");
2536        assert_eq!(result.value_at(0), Value::Boolean(false));
2537        assert_eq!(result.value_at(1), Value::Boolean(true));
2538        assert_eq!(result.value_at(2), Value::Null);
2539    }
2540
2541    #[test]
2542    fn two_vectors_of_different_lengths_are_caught() {
2543        let left = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
2544        let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 5);
2545        let error = compare(Comparison::Equal, &left, &right).expect_err("ragged");
2546        assert!(error.message().contains("4 row vector"), "{error}");
2547    }
2548
2549    #[test]
2550    fn turning_a_comparison_around_is_what_the_other_side_would_have_said() {
2551        for op in EVERY {
2552            let left = Value::Integer(3);
2553            let right = Value::Integer(7);
2554            assert_eq!(
2555                compare_values(op, &left, &right).expect("compares"),
2556                compare_values(op.swapped(), &right, &left).expect("compares"),
2557                "{op:?}"
2558            );
2559        }
2560    }
2561
2562    /// The whole point of the rewrite, stated as a property. Every operator, every physical
2563    /// layout, every form pair the fast path claims, against the row at a time oracle.
2564    #[test]
2565    fn every_specialized_path_agrees_with_the_row_at_a_time_path() {
2566        let mut rng = Rng(0x5eed_1234_9876_4321);
2567        let types: [LogicalType; 11] = [
2568            LogicalType::Boolean,
2569            LogicalType::TinyInt,
2570            LogicalType::SmallInt,
2571            LogicalType::Integer,
2572            LogicalType::BigInt,
2573            LogicalType::HugeInt,
2574            LogicalType::UInteger,
2575            LogicalType::Float,
2576            LogicalType::Double,
2577            LogicalType::Varchar,
2578            LogicalType::Interval,
2579        ];
2580        for ty in &types {
2581            for nulls in [0u64, 1, 3] {
2582                let len = 37;
2583                let make = |rng: &mut Rng| {
2584                    let values: Vec<Value> = (0..len)
2585                        .map(|_| {
2586                            if nulls > 0 && rng.below(nulls + 1) == 0 {
2587                                Value::Null
2588                            } else {
2589                                sample(ty, rng)
2590                            }
2591                        })
2592                        .collect();
2593                    Vector::from_values(ty.clone(), &values).expect("a flat vector")
2594                };
2595                let left = make(&mut rng);
2596                let right = make(&mut rng);
2597                let literal = sample(ty, &mut rng);
2598                let constant = Vector::constant(ty.clone(), literal, len);
2599                let null_constant = Vector::constant(ty.clone(), Value::Null, len);
2600                let codes: Vec<u32> =
2601                    (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
2602                let dictionary =
2603                    Vector::dictionary(codes, left.clone()).expect("codes are in range");
2604                // Runs over the same values, with the last one cut short so that a run boundary
2605                // does not land on the end of the vector.
2606                let ends: Vec<u32> = (1..=left.len())
2607                    .map(|run| ((run * len) / left.len()).max(run) as u32)
2608                    .collect();
2609                let runs =
2610                    Vector::runs(ends.clone(), left.clone()).expect("one value for each run");
2611                // A second pair over the other column's values, so that a coded side against a
2612                // coded side is two different runs of values reached through two different sets of
2613                // codes rather than one set read twice.
2614                let other_codes: Vec<u32> =
2615                    (0..len).map(|_| rng.below(right.len() as u64) as u32).collect();
2616                let other_dictionary =
2617                    Vector::dictionary(other_codes, right.clone()).expect("codes are in range");
2618                let other_runs = Vector::runs(ends, right.clone()).expect("one value for each run");
2619
2620                for op in EVERY {
2621                    agrees_and_selects(op, &left, &right);
2622                    agrees_and_selects(op, &left, &constant);
2623                    agrees_and_selects(op, &constant, &left);
2624                    agrees_and_selects(op, &left, &null_constant);
2625                    agrees_and_selects(op, &null_constant, &left);
2626                    agrees_and_selects(op, &dictionary, &constant);
2627                    agrees_and_selects(op, &constant, &dictionary);
2628                    // The dictionary against a flat column, which reads a null from either side and
2629                    // from the dictionary's values as well, so it is the pair with the most ways to
2630                    // disagree with the oracle and the one that got a loop last.
2631                    agrees_and_selects(op, &dictionary, &right);
2632                    agrees_and_selects(op, &right, &dictionary);
2633                    // The same four pairings for run length, which reaches the same loops through
2634                    // the same accessor, so what is being checked is that the positions it works
2635                    // out are the positions the row at a time path reads.
2636                    agrees_and_selects(op, &runs, &constant);
2637                    agrees_and_selects(op, &constant, &runs);
2638                    agrees_and_selects(op, &runs, &right);
2639                    agrees_and_selects(op, &right, &runs);
2640                    // Both sides reached through codes, which is the pair TPC-H actually hits:
2641                    // `l_commitdate < l_receiptdate` is two dictionary encoded columns of one
2642                    // table. A null here can be in four places at once, the two dictionaries' own
2643                    // masks and the two value vectors, and the answer has to be null if it is in
2644                    // any of them.
2645                    agrees_and_selects(op, &dictionary, &other_dictionary);
2646                    agrees_and_selects(op, &runs, &other_runs);
2647                    agrees_and_selects(op, &dictionary, &other_runs);
2648                    agrees_and_selects(op, &runs, &other_dictionary);
2649                }
2650            }
2651        }
2652    }
2653
2654    /// The rows of a selection the row at a time path keeps, which is what [`refine`] has to say.
2655    fn refined(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) -> Selection {
2656        let mut out = Vec::new();
2657        for &row in kept.indices() {
2658            let index = row as usize;
2659            let answer = compare_values(op, &left.value_at(index), &right.value_at(index))
2660                .expect("the oracle is only asked about types that compare");
2661            if is_true(&answer) {
2662                out.push(row);
2663            }
2664        }
2665        Selection::from_indices(out)
2666    }
2667
2668    fn threads(op: Comparison, left: &Vector, right: &Vector, kept: &Selection) {
2669        let fast = refine(op, left, right, kept).expect("compares");
2670        assert_eq!(
2671            fast,
2672            refined(op, left, right, kept),
2673            "{op:?} on a {:?} against a {:?} over {} rows",
2674            left.form(),
2675            right.form(),
2676            kept.len()
2677        );
2678    }
2679
2680    /// Threading a selection through a comparison is the same rows as comparing everything and
2681    /// then keeping the ones that were already kept. Every operator, every form pair that has a
2682    /// loop, at four densities of selection, against the row at a time path.
2683    #[test]
2684    fn a_threaded_comparison_keeps_what_the_row_at_a_time_path_keeps() {
2685        let mut rng = Rng(0x5eed_4321_1234_9876);
2686        let types = [LogicalType::Integer, LogicalType::Double, LogicalType::Varchar];
2687        for ty in &types {
2688            for nulls in [0u64, 1, 3] {
2689                let len = 37;
2690                let make = |rng: &mut Rng| {
2691                    let values: Vec<Value> = (0..len)
2692                        .map(|_| {
2693                            if nulls > 0 && rng.below(nulls + 1) == 0 {
2694                                Value::Null
2695                            } else {
2696                                sample(ty, rng)
2697                            }
2698                        })
2699                        .collect();
2700                    Vector::from_values(ty.clone(), &values).expect("a flat vector")
2701                };
2702                let left = make(&mut rng);
2703                let right = make(&mut rng);
2704                let constant = Vector::constant(ty.clone(), sample(ty, &mut rng), len);
2705                let null_constant = Vector::constant(ty.clone(), Value::Null, len);
2706                let codes: Vec<u32> =
2707                    (0..len).map(|_| rng.below(left.len() as u64) as u32).collect();
2708                let dictionary =
2709                    Vector::dictionary(codes, left.clone()).expect("codes are in range");
2710
2711                // Everything, every third row, a handful including the last one, and nothing,
2712                // which is the state a conjunct chain reaches as soon as one conjunct rejects a
2713                // whole chunk and is the case where the loop below must not read anything at all.
2714                let selections = [
2715                    Selection::identity(len),
2716                    Selection::from_indices((0..len as u32).filter(|row| row % 3 == 0).collect()),
2717                    Selection::from_indices(vec![2, 5, 6, 17, 36]),
2718                    Selection::empty(),
2719                ];
2720                for op in EVERY {
2721                    for kept in &selections {
2722                        threads(op, &left, &right, kept);
2723                        threads(op, &left, &constant, kept);
2724                        threads(op, &constant, &left, kept);
2725                        threads(op, &left, &null_constant, kept);
2726                        threads(op, &null_constant, &left, kept);
2727                        threads(op, &constant, &null_constant, kept);
2728                        threads(op, &dictionary, &constant, kept);
2729                        threads(op, &constant, &dictionary, kept);
2730                        threads(op, &dictionary, &right, kept);
2731                        threads(op, &right, &dictionary, kept);
2732                    }
2733                }
2734            }
2735        }
2736    }
2737
2738    /// Two conjuncts threaded one after the other are the rows both of them keep, which is the
2739    /// property the whole filter path rests on. The second comparison sees the rows the first one
2740    /// left and never looks at the others.
2741    #[test]
2742    fn a_second_conjunct_reads_only_what_the_first_one_left() {
2743        let numbers: Vec<Value> = (0..64).map(|row| Value::Integer(row % 10)).collect();
2744        let column = Vector::from_values(LogicalType::Integer, &numbers).expect("a flat vector");
2745        let three = Vector::constant(LogicalType::Integer, Value::Integer(3), 64);
2746        let seven = Vector::constant(LogicalType::Integer, Value::Integer(7), 64);
2747
2748        let first = refine(Comparison::Greater, &column, &three, &Selection::identity(64))
2749            .expect("compares");
2750        let both = refine(Comparison::Less, &column, &seven, &first).expect("compares");
2751
2752        let expected: Vec<u32> = (0..64)
2753            .filter(|row| {
2754                let value = row % 10;
2755                value > 3 && value < 7
2756            })
2757            .collect();
2758        assert_eq!(both.indices(), expected.as_slice());
2759        assert!(both.len() < first.len(), "the second conjunct narrowed the selection");
2760    }
2761
2762    /// A null is not a true, so a threaded comparison drops the row rather than keeping it with an
2763    /// unknown answer. This is the rule that makes `WHERE a < 5` leave out the rows where `a` is
2764    /// null, and it is the one a branchless loop gets wrong if the validity is left out of it.
2765    #[test]
2766    fn a_null_row_is_not_kept_by_an_ordinary_comparison_and_is_by_a_total_one() {
2767        let column = Vector::from_values(
2768            LogicalType::Integer,
2769            &[Value::Integer(1), Value::Null, Value::Integer(3), Value::Null],
2770        )
2771        .expect("four rows");
2772        let cut = Vector::constant(LogicalType::Integer, Value::Integer(2), 4);
2773        let all = Selection::identity(4);
2774        assert_eq!(
2775            refine(Comparison::Less, &column, &cut, &all).expect("compares").indices(),
2776            &[0]
2777        );
2778        // The total comparison has an answer at every row, so the two nulls are kept here.
2779        let nulls = Vector::constant(LogicalType::Integer, Value::Null, 4);
2780        assert_eq!(
2781            refine(Comparison::NotDistinctFrom, &column, &nulls, &all).expect("compares").indices(),
2782            &[1, 3]
2783        );
2784    }
2785
2786    #[test]
2787    fn a_selection_past_the_end_is_caught() {
2788        let column = Vector::constant(LogicalType::Integer, Value::Integer(1), 4);
2789        let past = Selection::from_indices(vec![0, 4]);
2790        let error = refine(Comparison::Equal, &column, &column, &past).expect_err("out of range");
2791        assert!(error.message().contains("4 row vector"), "{error}");
2792    }
2793
2794    /// One value of a type, for the generator above.
2795    fn sample(ty: &LogicalType, rng: &mut Rng) -> Value {
2796        match ty {
2797            LogicalType::Boolean => Value::Boolean(rng.below(2) == 1),
2798            LogicalType::TinyInt => Value::TinyInt(rng.below(7) as i8 - 3),
2799            LogicalType::SmallInt => Value::SmallInt(rng.below(11) as i16 - 5),
2800            LogicalType::Integer => Value::Integer(rng.below(9) as i32 - 4),
2801            LogicalType::BigInt => Value::BigInt(rng.below(9) as i64 - 4),
2802            LogicalType::HugeInt => Value::HugeInt(i128::from(rng.below(9)) - 4),
2803            LogicalType::UInteger => Value::UInteger(rng.below(9) as u32),
2804            // A NaN and a negative zero in the pool on purpose, because DuckDB's float order is
2805            // not IEEE's and the fast path has to reach the same answer the oracle does.
2806            LogicalType::Float => Value::Float(match rng.below(5) {
2807                0 => f32::NAN,
2808                1 => -0.0,
2809                other => other as f32 - 2.0,
2810            }),
2811            LogicalType::Double => Value::Double(match rng.below(5) {
2812                0 => f64::NAN,
2813                1 => -0.0,
2814                other => other as f64 - 2.0,
2815            }),
2816            // The same length written three ways and two lengths that are close to it, because an
2817            // interval that compares as a triple gets every pair here wrong and one that compares
2818            // as a length gets them right.
2819            LogicalType::Interval => match rng.below(6) {
2820                0 => Value::Interval { months: 0, days: 1, micros: 0 },
2821                1 => Value::Interval { months: 0, days: 0, micros: 86_400_000_000 },
2822                2 => Value::Interval { months: 1, days: -29, micros: 86_400_000_000 },
2823                3 => Value::Interval { months: 1, days: 0, micros: 0 },
2824                4 => Value::Interval { months: 0, days: 0, micros: 90_000_000_000 },
2825                _ => Value::Interval { months: -1, days: 0, micros: 0 },
2826            },
2827            // Short, at the inline limit, over it, and sharing a prefix with each other, which is
2828            // where a comparison that trusts the prefix too far goes wrong.
2829            LogicalType::Varchar => Value::Varchar(
2830                match rng.below(6) {
2831                    0 => "",
2832                    1 => "ab",
2833                    2 => "abc",
2834                    3 => "abcdefghijkl",
2835                    4 => "abcdefghijklm",
2836                    _ => "abcdefghijklmnopqrstuvwxyz",
2837                }
2838                .to_owned(),
2839            ),
2840            other => panic!("the generator has no values for {other}"),
2841        }
2842    }
2843
2844    /// The prefix lemma, written as a test because the whole string path rests on it. A view pads
2845    /// a short string with zeros, so prefix order has to agree with byte order on every pair where
2846    /// the prefixes differ, including the pairs where one string is shorter than four bytes.
2847    #[test]
2848    fn prefix_order_is_byte_order_whenever_the_prefixes_differ() {
2849        let words =
2850            ["", "a", "ab", "abc", "abcd", "abcde", "b", "abcdefghijklmnop", "abcdefghijklmnoq"];
2851        let mut column = StringColumn::new();
2852        for word in words {
2853            column.push(word);
2854        }
2855        for (i, one) in words.iter().enumerate() {
2856            for (j, other) in words.iter().enumerate() {
2857                assert_eq!(
2858                    string_order(&column, i, &column, j),
2859                    one.as_bytes().cmp(other.as_bytes()),
2860                    "{one:?} against {other:?}"
2861                );
2862            }
2863        }
2864    }
2865
2866    /// A dictionary is compared once per distinct value, not once per row, and it has to reach the
2867    /// same answer including for the nulls it keeps in the vector it points at.
2868    #[test]
2869    fn a_dictionary_against_a_constant_reads_its_nulls_from_the_values() {
2870        let values = Vector::from_values(
2871            LogicalType::Integer,
2872            &[Value::Integer(1), Value::Null, Value::Integer(9)],
2873        )
2874        .expect("three values");
2875        let dictionary =
2876            Vector::dictionary(vec![0, 1, 2, 1, 0], values).expect("codes are in range");
2877        let constant = Vector::constant(LogicalType::Integer, Value::Integer(5), 5);
2878        let result = compare(Comparison::Less, &dictionary, &constant).expect("compares");
2879        assert_eq!(result.value_at(0), Value::Boolean(true));
2880        assert_eq!(result.value_at(1), Value::Null);
2881        assert_eq!(result.value_at(2), Value::Boolean(false));
2882        assert_eq!(result.value_at(3), Value::Null);
2883        assert_eq!(result.value_at(4), Value::Boolean(true));
2884    }
2885
2886    /// An ordering comparison on a text column reads the bytes where they lie rather than building a
2887    /// `Value` a row.
2888    ///
2889    /// The assertion that matters is the counter at the end. The answers were already right through
2890    /// the row at a time path, and what was wrong was the cost: `ORDER BY <varchar> LIMIT 10` asks
2891    /// every chunk whether any row in it can still beat the worst candidate the top N holds, and that
2892    /// question used to allocate a `String` for every row of every chunk. On the ClickBench file that
2893    /// was eighteen times the CPU of the same query with an integer sort key.
2894    #[test]
2895    fn an_ordering_on_text_against_a_literal_does_not_fall_back() {
2896        let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
2897        let values = Vector::from_values(
2898            LogicalType::Varchar,
2899            &[Value::Varchar("apple".into()), Value::Null, Value::Varchar("pear".into())],
2900        )
2901        .expect("three values");
2902        let column = Vector::dictionary(vec![0, 1, 2, 0], values).expect("codes are in range");
2903        let cut = Vector::constant(LogicalType::Varchar, Value::Varchar("melon".into()), 4);
2904        let result = compare(Comparison::Less, &column, &cut).expect("compares");
2905        assert_eq!(result.value_at(0), Value::Boolean(true));
2906        assert_eq!(result.value_at(1), Value::Null);
2907        assert_eq!(result.value_at(2), Value::Boolean(false));
2908        assert_eq!(result.value_at(3), Value::Boolean(true));
2909        // The literal on the left, which is the same question with the comparison turned around, and
2910        // it has to be turned around once rather than once a row.
2911        let other = compare(Comparison::Greater, &cut, &column).expect("compares");
2912        assert_eq!(other.value_at(0), Value::Boolean(true));
2913        assert_eq!(other.value_at(1), Value::Null);
2914        assert_eq!(other.value_at(2), Value::Boolean(false));
2915        // The selection entry point, which is the one the filter and the top N reach.
2916        let kept = refine(Comparison::GreaterOrEqual, &column, &cut, &Selection::identity(4))
2917            .expect("refines");
2918        assert_eq!(kept.indices(), [2]);
2919        assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
2920    }
2921
2922    /// Two dictionary columns compared with each other, which is the pair the TPC-H suite spends
2923    /// the most row at a time calls on and had no loop until it was counted.
2924    ///
2925    /// `l_commitdate < l_receiptdate` in q4, q12 and q21 is two dictionary encoded date columns of
2926    /// six million rows each, and every one of those rows was going through the generic comparison
2927    /// on a pair of freshly allocated `Value`s. The shape here is the same one: different codes,
2928    /// different values, and a null reached through the codes rather than sitting at the row.
2929    #[test]
2930    fn two_dictionary_columns_compared_with_each_other_do_not_fall_back() {
2931        let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary);
2932        let dates = |values: &[Value]| {
2933            Vector::from_values(LogicalType::Date, values).expect("a flat date column")
2934        };
2935        // 10, 20, 10, 30 against 15, null, 5, 15.
2936        let committed = Vector::dictionary(
2937            vec![0, 1, 0, 2],
2938            dates(&[Value::Date(10), Value::Date(20), Value::Date(30)]),
2939        )
2940        .expect("codes are in range");
2941        let received = Vector::dictionary(
2942            vec![0, 1, 2, 0],
2943            dates(&[Value::Date(15), Value::Null, Value::Date(5)]),
2944        )
2945        .expect("codes are in range");
2946        let result = compare(Comparison::Less, &committed, &received).expect("compares");
2947        assert_eq!(result.value_at(0), Value::Boolean(true), "10 < 15");
2948        assert_eq!(result.value_at(1), Value::Null, "20 against a null");
2949        assert_eq!(result.value_at(2), Value::Boolean(false), "10 against 5");
2950        assert_eq!(result.value_at(3), Value::Boolean(false), "30 against 15");
2951        // The selection entry point, which is the one the filter reaches and the one q4 is made of.
2952        let kept = refine(Comparison::Less, &committed, &received, &Selection::identity(4))
2953            .expect("refines");
2954        assert_eq!(kept.indices(), [0]);
2955        assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary), before);
2956    }
2957
2958    /// A form pair with no loop is answered correctly and counted, which is the whole contract of
2959    /// the fallback counter. Sequence against a column is the one this file leaves out on purpose.
2960    #[test]
2961    fn a_form_pair_with_no_loop_is_still_right_and_says_so() {
2962        // The counters are per thread in a test build, so this reads its own and nothing else's.
2963        let before = fallback::count(Kernel::Compare, Form::Sequence, Form::Flat);
2964        let sequence = Vector::sequence(10, 1, 4);
2965        let flat = Vector::from_values(
2966            LogicalType::BigInt,
2967            &[Value::BigInt(9), Value::BigInt(11), Value::BigInt(12), Value::Null],
2968        )
2969        .expect("four rows");
2970        let result = compare(Comparison::Less, &sequence, &flat).expect("compares");
2971        assert_eq!(result.value_at(0), Value::Boolean(false));
2972        assert_eq!(result.value_at(1), Value::Boolean(false));
2973        assert_eq!(result.value_at(2), Value::Boolean(false));
2974        assert_eq!(result.value_at(3), Value::Null);
2975        assert!(fallback::count(Kernel::Compare, Form::Sequence, Form::Flat) > before);
2976    }
2977
2978    /// The reason `Vector::dictionary` composes rather than stacks, stated as the thing that breaks
2979    /// if it stops.
2980    ///
2981    /// Every loop in this file reaches for the values behind the codes with `Vector::data`, and a
2982    /// dictionary pointing at a dictionary has no data to hand back, so a second filter over an
2983    /// already filtered chunk used to turn every one of these kernels off and drop the comparison
2984    /// onto the row at a time path. Measured on server3 over a chunk of two numeric columns that was
2985    /// selected twice, that was 3.5 nanoseconds a row becoming 104, and a third and fourth level
2986    /// cost nothing more because the first one had already given up everything there was to give.
2987    #[test]
2988    fn a_second_level_of_codes_does_not_turn_the_loops_off() {
2989        let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant);
2990        let values = Vector::from_values(
2991            LogicalType::Integer,
2992            &[Value::Integer(1), Value::Integer(5), Value::Integer(9)],
2993        )
2994        .expect("three rows");
2995        let once = Vector::dictionary(vec![2, 1, 0], values).expect("codes are in range");
2996        let twice = Vector::dictionary(vec![1, 2], once).expect("codes are in range");
2997        let cut = Vector::constant(LogicalType::Integer, Value::Integer(4), 2);
2998        let result = compare(Comparison::Greater, &twice, &cut).expect("compares");
2999        assert_eq!(result.value_at(0), Value::Boolean(true));
3000        assert_eq!(result.value_at(1), Value::Boolean(false));
3001        assert_eq!(fallback::count(Kernel::Compare, Form::Dictionary, Form::Constant), before);
3002    }
3003
3004    /// Either side all null, on one of the six ordinary comparisons, is every answer null without
3005    /// the data being read. The vector this produces has to be the one the oracle produces, which
3006    /// is a flat run of falses under an all invalid validity rather than a constant.
3007    #[test]
3008    fn a_side_that_is_entirely_null_answers_without_reading_the_other() {
3009        let nulls = Vector::constant(LogicalType::Integer, Value::Null, 6);
3010        let flat = Vector::from_values(
3011            LogicalType::Integer,
3012            &[
3013                Value::Integer(1),
3014                Value::Integer(2),
3015                Value::Integer(3),
3016                Value::Integer(4),
3017                Value::Integer(5),
3018                Value::Integer(6),
3019            ],
3020        )
3021        .expect("six rows");
3022        agrees(Comparison::Less, &nulls, &flat);
3023        agrees(Comparison::Equal, &flat, &nulls);
3024        assert_eq!(
3025            compare(Comparison::Less, &nulls, &flat).expect("compares").validity(),
3026            &Validity::AllInvalid
3027        );
3028    }
3029
3030    /// An empty vector is not a special case anywhere, and the easiest way to keep it that way is
3031    /// to say so in a test rather than to find out from a panic in an operator.
3032    #[test]
3033    fn an_empty_comparison_is_an_empty_answer() {
3034        let left = Vector::from_values(LogicalType::Integer, &[]).expect("no rows");
3035        let right = Vector::constant(LogicalType::Integer, Value::Integer(1), 0);
3036        let result = compare(Comparison::Equal, &left, &right).expect("compares");
3037        assert_eq!(result.len(), 0);
3038    }
3039
3040    /// Six strings, three of them sharing a prefix, and a null, which is the column the two tests
3041    /// below read.
3042    fn words() -> Vector {
3043        Vector::from_values(
3044            LogicalType::Varchar,
3045            &[
3046                Value::Varchar("http://a".into()),
3047                Value::Varchar("http://b".into()),
3048                Value::Null,
3049                Value::Varchar("ab".into()),
3050                Value::Varchar("http://a".into()),
3051                Value::Varchar("z".into()),
3052            ],
3053        )
3054        .expect("six rows")
3055    }
3056
3057    /// A literal built early answers what a literal built per chunk answers.
3058    ///
3059    /// Every operator and both entry points, because the whole claim of the prepared literal is
3060    /// that it changes nothing, and the string column is the one where it changes the most work:
3061    /// what it carries is the four byte prefix the comparison resolves almost every row from.
3062    #[test]
3063    fn a_literal_built_early_answers_what_one_built_here_answers() {
3064        let column = words();
3065        let value = Value::Varchar("http://b".into());
3066        let constant = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
3067        let held = Held::of(&LogicalType::Varchar, &value).expect("a varchar has a column");
3068        let kept = Selection::from_indices(vec![0, 1, 3, 5]);
3069        for op in [
3070            Comparison::Equal,
3071            Comparison::NotEqual,
3072            Comparison::Less,
3073            Comparison::LessOrEqual,
3074            Comparison::Greater,
3075            Comparison::GreaterOrEqual,
3076            Comparison::DistinctFrom,
3077            Comparison::NotDistinctFrom,
3078        ] {
3079            let prepared = compare_prepared(op, &column, &constant, Some(&held)).expect("compares");
3080            assert_eq!(prepared, compare(op, &column, &constant).expect("compares"), "{op:?}");
3081            // And with the literal on the left, which is the same loop turned around.
3082            let flipped = compare_prepared(op, &constant, &column, Some(&held)).expect("compares");
3083            assert_eq!(flipped, compare(op, &constant, &column).expect("compares"), "{op:?}");
3084            let refined =
3085                refine_prepared(op, &column, &constant, &kept, Some(&held)).expect("refines");
3086            assert_eq!(refined, refine(op, &column, &constant, &kept).expect("refines"), "{op:?}");
3087        }
3088    }
3089
3090    /// A literal built for something else is ignored rather than believed.
3091    ///
3092    /// The caller in `rudb-exec` takes the value out of the step it hands the answer back with, so
3093    /// this cannot happen there, and the kernel is public. A wrong answer is a much worse failure
3094    /// than a column built per chunk, so the check is a value comparison per chunk and this is what
3095    /// says it works.
3096    #[test]
3097    fn a_literal_built_for_another_value_is_ignored() {
3098        let column = words();
3099        let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("z".into()), 6);
3100        let wrong = Held::of(&LogicalType::Varchar, &Value::Varchar("ab".into()))
3101            .expect("a varchar has a column");
3102        let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&wrong))
3103            .expect("compares");
3104        assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
3105        // And one built for another type, which is what a comparison across two types would hand
3106        // over if the caller took it from the wrong side.
3107        let other = Held::of(&LogicalType::Integer, &Value::Integer(1)).expect("an integer column");
3108        let answer = compare_prepared(Comparison::Equal, &column, &constant, Some(&other))
3109            .expect("compares");
3110        assert_eq!(answer, compare(Comparison::Equal, &column, &constant).expect("compares"));
3111    }
3112
3113    /// A range answered in one pass keeps the rows the two comparisons keep one after the other,
3114    /// flat and bit packed, strict and not, from every row and from some, and for ends that cut
3115    /// past the column's values or meet nowhere.
3116    #[test]
3117    fn a_range_keeps_the_rows_its_two_comparisons_keep() {
3118        let values: Vec<i32> = (0..1000).map(|row| 700 + (row * 37) % 600).collect();
3119        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
3120            .expect("integers are an i32 layout");
3121        let packed = flat.bit_packed().expect("packs");
3122        let some = Selection::from_predicate(1000, |row| row % 3 != 1);
3123        let ends = [i32::MIN, -5, 699, 700, 701, 900, 1299, 1300, 5000, i32::MAX];
3124        for column in [&flat, &packed] {
3125            for low in ends {
3126                for high in ends {
3127                    for (lower, upper) in [
3128                        (Comparison::GreaterOrEqual, Comparison::LessOrEqual),
3129                        (Comparison::Greater, Comparison::Less),
3130                    ] {
3131                        let (low, high) = (Value::Integer(low), Value::Integer(high));
3132                        let at = |value: &Value| {
3133                            Vector::constant(LogicalType::Integer, value.clone(), 1000)
3134                        };
3135                        let (one, other) = (at(&low), at(&high));
3136                        let bounds = (
3137                            Bound { op: lower, value: &low, held: None },
3138                            Bound { op: upper, value: &high, held: None },
3139                        );
3140                        let first = select_prepared(lower, column, &one, None).expect("compares");
3141                        let both = refine(upper, column, &other, &first).expect("refines");
3142                        let ranged = select_range(column, bounds.0, bounds.1, None)
3143                            .expect("a column with no nulls has a range");
3144                        assert_eq!(
3145                            ranged.indices(),
3146                            both.indices(),
3147                            "{low} {lower:?}, {high} {upper:?}"
3148                        );
3149                        let first = refine(lower, column, &one, &some).expect("refines");
3150                        let both = refine(upper, column, &other, &first).expect("refines");
3151                        let ranged = select_range(column, bounds.0, bounds.1, Some(some.indices()))
3152                            .expect("a column with no nulls has a range");
3153                        assert_eq!(
3154                            ranged.indices(),
3155                            both.indices(),
3156                            "{low} {lower:?}, {high} {upper:?} of some"
3157                        );
3158                    }
3159                }
3160            }
3161        }
3162    }
3163
3164    /// Nulls, a literal of another type and a string column are left to the two comparisons.
3165    #[test]
3166    fn a_range_it_has_no_loop_for_is_none() {
3167        let low = Value::Integer(1);
3168        let high = Value::Integer(5);
3169        fn bound(op: Comparison, value: &Value) -> Bound<'_> {
3170            Bound { op, value, held: None }
3171        }
3172        let nulls = Vector::from_values(LogicalType::Integer, &[Value::Integer(2), Value::Null])
3173            .expect("integers");
3174        let range = |column: &Vector, low: &Value, high: &Value| {
3175            select_range(
3176                column,
3177                bound(Comparison::GreaterOrEqual, low),
3178                bound(Comparison::Less, high),
3179                None,
3180            )
3181        };
3182        assert!(range(&nulls, &low, &high).is_none());
3183        let plain =
3184            Vector::from_values(LogicalType::Integer, &[Value::Integer(2), Value::Integer(9)])
3185                .expect("integers");
3186        assert_eq!(range(&plain, &low, &high).expect("a range").indices(), &[0]);
3187        assert!(range(&plain, &Value::Null, &high).is_none());
3188        assert!(range(&words(), &low, &high).is_none());
3189        let wrong = select_range(
3190            &plain,
3191            bound(Comparison::Less, &low),
3192            bound(Comparison::Less, &high),
3193            None,
3194        );
3195        assert!(wrong.is_none(), "a low end has to be > or >=");
3196    }
3197
3198    /// A bit packed column against a literal is compared in code space, which has to reach the
3199    /// oracle's answer on all eight comparisons and with the literal on either side.
3200    #[test]
3201    fn a_packed_column_against_a_constant_answers_what_the_oracle_answers() {
3202        let values: Vec<i32> = (0..64).map(|row| 1000 + (row * 37) % 500).collect();
3203        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
3204            .expect("integers are an i32 layout");
3205        let packed = flat.bit_packed().expect("a five hundred wide range packs");
3206        assert_eq!(packed.form(), Form::BitPacked);
3207        for literal in [999, 1000, 1200, 1499, 1500, 2000] {
3208            let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 64);
3209            for op in EVERY {
3210                agrees(op, &packed, &constant);
3211                agrees(op, &constant, &packed);
3212            }
3213        }
3214    }
3215
3216    /// The nulls of a packed column live in its validity rather than in its bits, so a comparison
3217    /// has to blank them the way it blanks a flat column's, and the bits under them are whatever
3218    /// the packing wrote there.
3219    #[test]
3220    fn a_packed_column_with_nulls_answers_what_the_oracle_answers() {
3221        let values: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
3222        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
3223            .expect("integers are an i32 layout")
3224            .with_validity(Validity::from_iter(32, |row| row % 5 != 0));
3225        let packed = flat.bit_packed().expect("packs");
3226        let constant = Vector::constant(LogicalType::Integer, Value::Integer(80), 32);
3227        for op in EVERY {
3228            agrees(op, &packed, &constant);
3229        }
3230    }
3231
3232    /// A literal the width cannot hold answers every row without a bit being read, and the answer
3233    /// still has to be the one the oracle gives.
3234    #[test]
3235    fn a_literal_outside_the_packed_range_answers_the_whole_vector_at_once() {
3236        let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant);
3237        let values: Vec<i32> = (0..16).map(|row| 500 + row).collect();
3238        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
3239            .expect("integers are an i32 layout");
3240        let packed = flat.bit_packed().expect("packs");
3241        let literals = [-1, 0, 499, 516, 100_000];
3242        for literal in literals {
3243            let constant = Vector::constant(LogicalType::Integer, Value::Integer(literal), 16);
3244            for op in EVERY {
3245                agrees(op, &packed, &constant);
3246            }
3247        }
3248        // The six ordinary comparisons have a loop for this pair and the two that never go null do
3249        // not, because those want the null rule inside the loop and the code space loop does not
3250        // carry one. They take the row at a time path and count themselves, which is the counter
3251        // doing its job rather than a gap being hidden.
3252        let total = EVERY.iter().filter(|op| op.is_total()).count();
3253        assert_eq!(
3254            fallback::count(Kernel::Compare, Form::BitPacked, Form::Constant) - before,
3255            (literals.len() * total) as u64,
3256            "only the two total comparisons fall through"
3257        );
3258    }
3259
3260    /// The conjunct path reads the rows an earlier conjunct kept, so the code space loop has to be
3261    /// reached through the selection rather than through the row number.
3262    #[test]
3263    fn refining_a_selection_over_a_packed_column_keeps_the_same_rows() {
3264        let values: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
3265        let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into()))
3266            .expect("integers are an i32 layout");
3267        let packed = flat.bit_packed().expect("packs");
3268        let kept = Selection::from_predicate(64, |row| row % 3 == 0);
3269        let constant = Vector::constant(LogicalType::Integer, Value::Integer(260), 64);
3270        let packed_rows = refine(Comparison::Greater, &packed, &constant, &kept).expect("refines");
3271        let flat_rows = refine(Comparison::Greater, &flat, &constant, &kept).expect("refines");
3272        assert_eq!(packed_rows.indices(), flat_rows.indices());
3273        assert!(!packed_rows.is_empty(), "the literal is inside the range");
3274    }
3275
3276    /// Two packed columns whose ranges overlap, which is the pair a stored table produces and the
3277    /// pair `l_commitdate < l_receiptdate` is. The two bases differ, so the answer has to come out
3278    /// of the sums rather than out of the codes, and it has to be the oracle's answer.
3279    #[test]
3280    fn two_packed_columns_against_each_other_answer_what_the_oracle_answers() {
3281        let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::BitPacked);
3282        let one: Vec<i32> = (0..64).map(|row| 9000 + (row * 37) % 500).collect();
3283        let other: Vec<i32> = (0..64).map(|row| 9200 + (row * 53) % 400).collect();
3284        let left = Vector::flat(LogicalType::Integer, Data::Int32(one.into()))
3285            .expect("integers are an i32 layout")
3286            .bit_packed()
3287            .expect("a five hundred wide range packs");
3288        let right = Vector::flat(LogicalType::Integer, Data::Int32(other.into()))
3289            .expect("integers are an i32 layout")
3290            .bit_packed()
3291            .expect("a four hundred wide range packs");
3292        assert_eq!(left.form(), Form::BitPacked);
3293        assert_eq!(right.form(), Form::BitPacked);
3294        assert_ne!(
3295            left.packed_parts().expect("packed").base(),
3296            right.packed_parts().expect("packed").base(),
3297            "the two bases are the two column minimums and this test wants them apart"
3298        );
3299        for op in EVERY {
3300            agrees(op, &left, &right);
3301            agrees(op, &right, &left);
3302        }
3303        // The two total comparisons want the null rule inside the loop and the code space loop does
3304        // not carry one, so those are the only ones that count themselves, the same way they do for
3305        // a packed column against a literal.
3306        let total = EVERY.iter().filter(|op| op.is_total()).count();
3307        assert_eq!(
3308            fallback::count(Kernel::Compare, Form::BitPacked, Form::BitPacked) - before,
3309            (total * 2) as u64,
3310            "only the two total comparisons fall through"
3311        );
3312    }
3313
3314    #[test]
3315    fn two_long_packed_columns_sliced_off_a_word_answer_what_the_oracle_answers() {
3316        // Past one block of 64 with a ragged tail, and sliced so that the rows do not start on a
3317        // word, which are the two ways the unpacked runs could come out misaligned.
3318        let one: Vec<i32> = (0..1000).map(|row| 9000 + (row * 37) % 500).collect();
3319        let other: Vec<i32> = (0..1000).map(|row| 9200 + (row * 53) % 400).collect();
3320        let packed = |values: Vec<i32>| {
3321            Vector::flat(LogicalType::Integer, Data::Int32(values.into()))
3322                .expect("integers are an i32 layout")
3323                .bit_packed()
3324                .expect("a narrow range packs")
3325        };
3326        let (left, right) = (packed(one), packed(other));
3327        for (at, len) in [(0, 1000), (7, 900), (70, 129)] {
3328            let (left, right) = (
3329                left.slice(at, len).expect("inside the vector"),
3330                right.slice(at, len).expect("inside the vector"),
3331            );
3332            for op in EVERY {
3333                agrees(op, &left, &right);
3334                agrees(op, &right, &left);
3335            }
3336        }
3337    }
3338
3339    /// The rows the oracle's flags keep out of `kept`, or out of every row.
3340    fn wanted(op: Comparison, left: &Vector, right: &Vector, kept: Option<&Selection>) -> Vec<u32> {
3341        let flags = oracle(op, left, right);
3342        let every = crate::select::selection(&flags, flags.len());
3343        match kept {
3344            None => every.indices().to_vec(),
3345            Some(kept) => {
3346                kept.indices().iter().copied().filter(|row| every.indices().contains(row)).collect()
3347            }
3348        }
3349    }
3350
3351    /// Two date columns of a thousand rows, flat and packed, compared the way a filter's first
3352    /// conjunct and a later one compare them. A thousand rows is whole blocks of sixty four and a
3353    /// tail, and the later conjunct is asked over a dense selection, which unpacks, and a sparse
3354    /// one, which reads a code at a time.
3355    #[test]
3356    fn two_columns_compared_in_one_pass_keep_the_rows_the_oracle_keeps() {
3357        let one: Vec<i32> = (0..1000).map(|row| 9000 + (row * 37) % 500).collect();
3358        let other: Vec<i32> = (0..1000).map(|row| 9200 + (row * 53) % 400).collect();
3359        let flat = |values: Vec<i32>| {
3360            Vector::flat(LogicalType::Date, Data::Int32(values.into())).expect("dates are i32")
3361        };
3362        let (left, right) = (flat(one), flat(other));
3363        let (packed_left, packed_right) =
3364            (left.bit_packed().expect("packs"), right.bit_packed().expect("packs"));
3365        assert_eq!(packed_left.form(), Form::BitPacked);
3366        assert_eq!(packed_right.form(), Form::BitPacked);
3367        let dense = Selection::from_predicate(1000, |row| row % 3 != 0);
3368        let sparse = Selection::from_predicate(1000, |row| row % 97 == 5);
3369        for op in EVERY {
3370            for (a, b) in [(&left, &right), (&right, &left), (&packed_left, &packed_right)] {
3371                let picked = select_prepared(op, a, b, None).expect("selects");
3372                assert_eq!(picked.indices(), wanted(op, a, b, None), "{op:?} {:?}", a.form());
3373                for kept in [&dense, &sparse] {
3374                    let refined = refine(op, a, b, kept).expect("refines");
3375                    assert_eq!(refined.indices(), wanted(op, a, b, Some(kept)), "{op:?}");
3376                }
3377            }
3378        }
3379        let refined = refine(Comparison::Less, &packed_left, &packed_right, &sparse).expect("ok");
3380        assert!(!refined.is_empty(), "the sparse rows reach both answers");
3381    }
3382
3383    /// A literal against a flat column in a later conjunct, which now picks its rows in the same
3384    /// pass that compares them.
3385    #[test]
3386    fn a_flat_column_refined_against_a_literal_keeps_the_rows_the_oracle_keeps() {
3387        let values: Vec<i64> = (0..700).map(|row| (row * 7919) % 1000).collect();
3388        let column = Vector::flat(LogicalType::BigInt, Data::Int64(values.into())).expect("i64");
3389        let literal = Vector::constant(LogicalType::BigInt, Value::BigInt(500), 700);
3390        let kept = Selection::from_predicate(700, |row| row % 4 == 1);
3391        for op in EVERY {
3392            let refined = refine(op, &column, &literal, &kept).expect("refines");
3393            assert_eq!(refined.indices(), wanted(op, &column, &literal, Some(&kept)), "{op:?}");
3394        }
3395    }
3396
3397    /// A column whose largest value is below the other's smallest answers every row the same way,
3398    /// and the answer still has to be the one the oracle gives on all eight comparisons.
3399    #[test]
3400    fn two_packed_columns_whose_ranges_do_not_overlap_answer_the_whole_vector_at_once() {
3401        let one: Vec<i32> = (0..32).map(|row| 100 + row).collect();
3402        let other: Vec<i32> = (0..32).map(|row| 500 + row * 2).collect();
3403        let low = Vector::flat(LogicalType::Integer, Data::Int32(one.into()))
3404            .expect("integers are an i32 layout")
3405            .bit_packed()
3406            .expect("packs");
3407        let high = Vector::flat(LogicalType::Integer, Data::Int32(other.into()))
3408            .expect("integers are an i32 layout")
3409            .bit_packed()
3410            .expect("packs");
3411        for op in EVERY {
3412            agrees(op, &low, &high);
3413            agrees(op, &high, &low);
3414        }
3415    }
3416
3417    /// The nulls of a packed column live in its validity rather than in its bits, so a pair of them
3418    /// has to blank the rows either side is null in, and the bits under those rows are whatever the
3419    /// packing wrote there.
3420    #[test]
3421    fn two_packed_columns_with_nulls_answer_what_the_oracle_answers() {
3422        let one: Vec<i32> = (0..32).map(|row| 40 + row * 3).collect();
3423        let other: Vec<i32> = (0..32).map(|row| 60 + row * 2).collect();
3424        let left = Vector::flat(LogicalType::Integer, Data::Int32(one.into()))
3425            .expect("integers are an i32 layout")
3426            .with_validity(Validity::from_iter(32, |row| row % 5 != 0))
3427            .bit_packed()
3428            .expect("packs");
3429        let right = Vector::flat(LogicalType::Integer, Data::Int32(other.into()))
3430            .expect("integers are an i32 layout")
3431            .with_validity(Validity::from_iter(32, |row| row % 3 != 0))
3432            .bit_packed()
3433            .expect("packs");
3434        for op in EVERY {
3435            agrees(op, &left, &right);
3436        }
3437    }
3438
3439    /// A dictionary over a packed run on either side or both, which is what a stored date column
3440    /// comes back as and is the pair q04 and q21 fall through on. The nulls are in three places at
3441    /// once here, the outer mask, the dictionary's values and the rows a code repeats, and the
3442    /// oracle sees all three.
3443    #[test]
3444    fn a_dictionary_over_a_packed_run_answers_what_the_oracle_answers() {
3445        let before = fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary);
3446        let distinct = |start: i32, step: i32, nulls: usize| {
3447            let values: Vec<i32> = (0..24).map(|row| start + row * step).collect();
3448            Vector::flat(LogicalType::Date, Data::Int32(values.into()))
3449                .expect("dates are an i32 layout")
3450                .with_validity(Validity::from_iter(24, |row| row % nulls != 0))
3451                .bit_packed()
3452                .expect("packs")
3453        };
3454        let codes =
3455            |seed: usize| -> Vec<u32> { (0..64).map(|row| ((row * seed) % 24) as u32).collect() };
3456        let one = Vector::dictionary(codes(7), distinct(9_000, 3, 5)).expect("codes are in range");
3457        let other =
3458            Vector::dictionary(codes(5), distinct(9_020, 2, 7)).expect("codes are in range");
3459        let straight = Vector::flat(
3460            LogicalType::Date,
3461            Data::Int32((0..64).map(|row| 9_010 + row).collect::<Vec<i32>>().into()),
3462        )
3463        .expect("dates are an i32 layout")
3464        .bit_packed()
3465        .expect("packs");
3466        assert_eq!(one.form(), Form::Dictionary);
3467        assert_eq!(straight.form(), Form::BitPacked);
3468        for op in EVERY {
3469            agrees(op, &one, &other);
3470            agrees(op, &one, &straight);
3471            agrees(op, &straight, &other);
3472        }
3473        // Three pairs, and only the two total comparisons of each are left to count themselves.
3474        let total = EVERY.iter().filter(|op| op.is_total()).count();
3475        assert_eq!(
3476            fallback::count(Kernel::Compare, Form::Dictionary, Form::Dictionary) - before,
3477            total as u64,
3478            "only the two total comparisons fall through"
3479        );
3480    }
3481
3482    /// A bit packed column against a flat one, which is the pair a clustered table hands the filter.
3483    ///
3484    /// Sorting lineitem by month of `l_shipdate` leaves `l_commitdate` with few enough distinct
3485    /// values inside a partition to pack, while `l_receiptdate` arrives flat, so the better encoding
3486    /// the clustering buys was what turned `l_commitdate < l_receiptdate` into a `Value` a side a
3487    /// row. All four ways the two sides can be indexed are here, because a stored date column comes
3488    /// back as a dictionary over a packed run about as often as it comes back as a packed run on its
3489    /// own.
3490    #[test]
3491    fn a_packed_column_against_a_flat_one_answers_what_the_oracle_answers() {
3492        let before = fallback::count(Kernel::Compare, Form::BitPacked, Form::Flat);
3493        let dates = |start: i32, step: i32, nulls: usize| {
3494            Vector::flat(
3495                LogicalType::Date,
3496                Data::Int32((0..64).map(|row| start + row * step).collect::<Vec<i32>>().into()),
3497            )
3498            .expect("dates are an i32 layout")
3499            .with_validity(Validity::from_iter(64, |row| row % nulls != 0))
3500        };
3501        let codes =
3502            |seed: usize| -> Vec<u32> { (0..64).map(|row| ((row * seed) % 64) as u32).collect() };
3503        let packed = dates(9_000, 3, 5).bit_packed().expect("packs");
3504        let flat = dates(9_040, 2, 7);
3505        let over_packed = Vector::dictionary(codes(7), packed.clone()).expect("codes are in range");
3506        let over_flat = Vector::dictionary(codes(11), flat.clone()).expect("codes are in range");
3507        assert_eq!(packed.form(), Form::BitPacked);
3508        assert_eq!(flat.form(), Form::Flat);
3509        // The ranges overlap, which is what makes the comparison a pass over the rows rather than
3510        // arithmetic on four numbers, and this test wants the pass.
3511        assert!(packed.packed_parts().expect("packed").base() < 9_040 + 63 * 2);
3512        for op in EVERY {
3513            agrees(op, &packed, &flat);
3514            agrees(op, &flat, &packed);
3515            agrees(op, &packed, &over_flat);
3516            agrees(op, &over_packed, &flat);
3517            agrees(op, &over_packed, &over_flat);
3518        }
3519        // Only the two total comparisons are left to count themselves, the same way they are for a
3520        // pair of packed columns, and of the five pairs above only the first is packed against flat.
3521        let total = EVERY.iter().filter(|op| op.is_total()).count();
3522        assert_eq!(
3523            fallback::count(Kernel::Compare, Form::BitPacked, Form::Flat) - before,
3524            total as u64,
3525            "only the two total comparisons fall through"
3526        );
3527    }
3528
3529    /// The conjunct path reads the rows an earlier conjunct kept, so a pair of packed columns has
3530    /// to be reached through the selection rather than through the row number, which is what q12
3531    /// does with its two date comparisons one after the other.
3532    #[test]
3533    fn refining_a_selection_over_two_packed_columns_keeps_the_same_rows() {
3534        let one: Vec<i32> = (0..64).map(|row| 200 + (row * 11) % 128).collect();
3535        let other: Vec<i32> = (0..64).map(|row| 240 + (row * 17) % 96).collect();
3536        let left = Vector::flat(LogicalType::Integer, Data::Int32(one.clone().into()))
3537            .expect("integers are an i32 layout");
3538        let right = Vector::flat(LogicalType::Integer, Data::Int32(other.clone().into()))
3539            .expect("integers are an i32 layout");
3540        let kept = Selection::from_predicate(64, |row| row % 3 == 0);
3541        let packed_rows = refine(
3542            Comparison::Less,
3543            &left.bit_packed().expect("packs"),
3544            &right.bit_packed().expect("packs"),
3545            &kept,
3546        )
3547        .expect("refines");
3548        let flat_rows = refine(Comparison::Less, &left, &right, &kept).expect("refines");
3549        assert_eq!(packed_rows.indices(), flat_rows.indices());
3550        assert!(!packed_rows.is_empty(), "the two ranges overlap");
3551    }
3552
3553    /// A column of URLs, which is the shape the string view form exists for: a shared prefix that
3554    /// the four bytes in the view cannot settle, and payloads long enough to be in the arena.
3555    fn urls(count: usize) -> Vector {
3556        let mut rng = Rng(0x5eed_1234);
3557        let values: Vec<Value> = (0..count)
3558            .map(|_| {
3559                let host = rng.below(6);
3560                let path = rng.below(40);
3561                Value::Varchar(format!("http://example{host}.test/a/rather/long/path/{path}"))
3562            })
3563            .collect();
3564        Vector::from_values(LogicalType::Varchar, &values).expect("strings")
3565    }
3566
3567    #[test]
3568    fn a_string_view_column_against_a_literal_answers_what_the_oracle_answers() {
3569        let before = fallback::count(Kernel::Compare, Form::StringView, Form::Constant);
3570        let shared = urls(64).shared_text().expect("shares");
3571        assert_eq!(shared.form(), Form::StringView);
3572        let literals = ["http://example3.test/a/rather/long/path/7", "a", "zzz", ""];
3573        for literal in literals {
3574            let value = Value::Varchar(literal.to_owned());
3575            let constant = Vector::constant(LogicalType::Varchar, value, 64);
3576            for op in EVERY {
3577                agrees(op, &shared, &constant);
3578                agrees(op, &constant, &shared);
3579            }
3580        }
3581        assert_eq!(
3582            fallback::count(Kernel::Compare, Form::StringView, Form::Constant),
3583            before,
3584            "the form has a loop of its own for every comparison"
3585        );
3586    }
3587
3588    #[test]
3589    fn a_string_view_column_against_another_one_answers_what_the_oracle_answers() {
3590        let shared = urls(48).shared_text().expect("shares");
3591        let other = urls(48).shared_text().expect("shares");
3592        let flat = urls(48);
3593        for op in EVERY {
3594            agrees(op, &shared, &other);
3595            agrees(op, &shared, &flat);
3596            agrees(op, &flat, &shared);
3597        }
3598    }
3599
3600    #[test]
3601    fn the_nulls_of_a_string_view_column_are_the_nulls_the_oracle_sees() {
3602        let shared = urls(32)
3603            .with_validity(Validity::from_iter(32, |row| row % 4 != 1))
3604            .shared_text()
3605            .expect("shares");
3606        let constant =
3607            Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 32);
3608        for op in EVERY {
3609            agrees(op, &shared, &constant);
3610        }
3611    }
3612
3613    #[test]
3614    fn a_compressed_column_against_a_literal_answers_what_the_oracle_answers() {
3615        let before = fallback::count(Kernel::Compare, Form::Fsst, Form::Constant);
3616        let flat = urls(64);
3617        let coded = flat.clone().compressed().expect("compresses");
3618        assert_eq!(coded.form(), Form::Fsst);
3619        let present = match coded.value_at(9) {
3620            Value::Varchar(text) => text,
3621            other => panic!("a string column reads back strings, not {other:?}"),
3622        };
3623        for literal in [present.as_str(), "http://example3.test/nothing/like/it", ""] {
3624            let value = Value::Varchar(literal.to_owned());
3625            let constant = Vector::constant(LogicalType::Varchar, value, 64);
3626            for op in EVERY {
3627                agrees(op, &coded, &constant);
3628                agrees(op, &constant, &coded);
3629            }
3630        }
3631        // Equality has a loop in code space and the six comparisons that need an order do not,
3632        // because a symbol code says nothing about where its symbol sorts. Those decompress a row at
3633        // a time and count themselves, which is the counter doing its job rather than a gap hiding.
3634        let ordered = EVERY.len() - 2;
3635        assert_eq!(
3636            fallback::count(Kernel::Compare, Form::Fsst, Form::Constant) - before,
3637            (3 * ordered) as u64,
3638            "only the comparisons that need an order fall through"
3639        );
3640    }
3641
3642    /// Equality in code space is only right if compressing is a function, so the same string always
3643    /// has the same codes and two different strings never do. This is that claim as a test.
3644    #[test]
3645    fn every_row_of_a_compressed_column_matches_itself_and_nothing_else() {
3646        let flat = urls(48);
3647        let coded = flat.clone().compressed().expect("compresses");
3648        for row in 0..48 {
3649            let constant = Vector::constant(LogicalType::Varchar, flat.value_at(row), 48);
3650            let equal = compare(Comparison::Equal, &coded, &constant).expect("compares");
3651            for other in 0..48 {
3652                let want = flat.value_at(other) == flat.value_at(row);
3653                assert_eq!(
3654                    equal.value_at(other),
3655                    Value::Boolean(want),
3656                    "row {row} against {other}"
3657                );
3658            }
3659        }
3660    }
3661
3662    #[test]
3663    fn the_nulls_of_a_compressed_column_are_the_nulls_the_oracle_sees() {
3664        let coded = urls(32)
3665            .with_validity(Validity::from_iter(32, |row| row % 3 != 0))
3666            .compressed()
3667            .expect("compresses");
3668        let value = coded.value_at(1);
3669        let constant = Vector::constant(LogicalType::Varchar, value, 32);
3670        for op in EVERY {
3671            agrees(op, &coded, &constant);
3672        }
3673    }
3674
3675    /// The two forms hold the same strings in two different places, so a filter over either one has
3676    /// to keep the same rows. This is the differential check that the arena being shared changed
3677    /// nothing about what a comparison means.
3678    #[test]
3679    fn a_filter_over_either_string_form_keeps_the_same_rows() {
3680        let flat = urls(96);
3681        let shared = flat.clone().shared_text().expect("shares");
3682        let constant =
3683            Vector::constant(LogicalType::Varchar, Value::Varchar("http://example3".into()), 96);
3684        let kept = Selection::from_predicate(96, |row| row % 5 != 0);
3685        for op in EVERY {
3686            let over_flat = refine(op, &flat, &constant, &kept).expect("refines");
3687            let over_shared = refine(op, &shared, &constant, &kept).expect("refines");
3688            assert_eq!(over_shared.indices(), over_flat.indices(), "{op:?}");
3689        }
3690    }
3691
3692    /// The peeled path and the row at a time oracle on the same rows, on both spellings and on
3693    /// both entry points. A dictionary that shares its values is what a native scan hands over, so
3694    /// this is the shape every `WHERE URL <> ''` in ClickBench arrives in.
3695    #[test]
3696    fn a_comparison_peeled_over_a_shared_dictionary_answers_what_the_oracle_answers() {
3697        let words = ["", "one", "two", "", "three"];
3698        let values: Vec<Value> = words.iter().map(|text| Value::Varchar((*text).into())).collect();
3699        let values =
3700            Arc::new(Vector::from_values(LogicalType::Varchar, &values).expect("a vector of text"));
3701        let codes = vec![0, 1, 3, 2, 0, 4, 1, 0];
3702        let column = Vector::stable_dictionary(codes.clone(), values).expect("codes are in range");
3703        same_as_the_oracle(&column);
3704    }
3705
3706    /// Values a storage reader would hand over, which answer one at a time and which know the
3707    /// order the writer sorted them into.
3708    #[derive(Debug)]
3709    struct Filed {
3710        values: Vec<Vec<u8>>,
3711        order: Vec<u32>,
3712        /// [`Self::order`] turned round, built on the first ask the way a reader's is.
3713        ranked: std::sync::OnceLock<Option<Vec<u32>>>,
3714    }
3715
3716    impl rudb_vector::TextSource for Filed {
3717        fn len(&self) -> usize {
3718            self.values.len()
3719        }
3720
3721        fn bytes_at(&self, index: usize) -> Result<Option<&[u8]>> {
3722            Ok(self.values.get(index).map(Vec::as_slice))
3723        }
3724
3725        fn footprint(&self) -> usize {
3726            self.values.iter().map(Vec::len).sum()
3727        }
3728
3729        fn ranks(&self) -> Option<usize> {
3730            Some(self.order.len())
3731        }
3732
3733        fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
3734            // Plain bytes rather than the head the native format compares first, because what this
3735            // test is about is the answer the comparison gives and not how few reads it took.
3736            Ok(self.values[self.order[rank] as usize].as_slice().cmp(wanted))
3737        }
3738
3739        fn code_at_rank(&self, rank: usize) -> Result<u32> {
3740            Ok(self.order[rank])
3741        }
3742
3743        fn code_ranks(&self) -> Option<&[u32]> {
3744            self.ranked
3745                .get_or_init(|| {
3746                    let mut ranks = vec![0; self.order.len()];
3747                    for (rank, &code) in self.order.iter().enumerate() {
3748                        ranks[code as usize] = rank as u32;
3749                    }
3750                    Some(ranks)
3751                })
3752                .as_deref()
3753        }
3754    }
3755
3756    /// The same comparison over a dictionary whose values came out of a file with their order, so
3757    /// the literal is resolved to a code by search rather than compared against every value.
3758    #[test]
3759    fn a_comparison_against_a_sorted_dictionary_answers_what_the_oracle_answers() {
3760        // Distinct, which is what a source promises by answering with an order at all, and which
3761        // a global dictionary is by construction.
3762        let (column, _) = filed(&["", "one", "two", "four", "three"], vec![0, 1, 3, 2, 0, 4, 1, 0]);
3763        same_as_the_oracle(&column);
3764    }
3765
3766    /// A dictionary column over values that arrived from a file with their sorted order, handed
3767    /// back with the dictionary so a caller can check what it is holding a rank against.
3768    fn filed(words: &[&str], codes: Vec<u32>) -> (Vector, Arc<Vector>) {
3769        let values: Vec<Vec<u8>> = words.iter().map(|text| text.as_bytes().to_vec()).collect();
3770        let mut order = (0..values.len() as u32).collect::<Vec<_>>();
3771        order.sort_by(|&left, &right| values[left as usize].cmp(&values[right as usize]));
3772        let dictionary = Arc::new(
3773            Vector::external_text(
3774                LogicalType::Varchar,
3775                Arc::new(Filed { values, order, ranked: std::sync::OnceLock::new() }),
3776            )
3777            .expect("a filed vector"),
3778        );
3779        let column =
3780            Vector::stable_dictionary(codes, Arc::clone(&dictionary)).expect("codes are in range");
3781        (column, dictionary)
3782    }
3783
3784    /// The top N's path. A bound whose rank is already known is compared without a search, and what
3785    /// it keeps is what comparing against the same value the long way round keeps.
3786    #[test]
3787    fn a_comparison_against_a_known_rank_keeps_what_a_search_for_it_keeps() {
3788        let (column, dictionary) =
3789            filed(&["", "one", "two", "four", "three"], vec![0, 1, 3, 2, 0, 4, 1, 0]);
3790        let rows = column.len();
3791        for row in 0..rows {
3792            let (held, rank) = rank_at(&column, row).expect("a row of a ranked dictionary");
3793            assert!(Arc::ptr_eq(&held, &dictionary), "the dictionary it came from");
3794            let value = column.try_value_at(row).expect("a value");
3795            for op in [
3796                Comparison::Less,
3797                Comparison::LessOrEqual,
3798                Comparison::Greater,
3799                Comparison::GreaterOrEqual,
3800            ] {
3801                let against = Vector::constant(LogicalType::Varchar, value.clone(), rows);
3802                let flags = compare(op, &column, &against).expect("the search path answers");
3803                let wanted = crate::select::selection(&flags, rows);
3804                let got = select_against_rank(op, &column, &dictionary, rank, rows)
3805                    .expect("the rank path answers");
3806                assert_eq!(got.indices(), wanted.indices(), "row {row} under {op:?}");
3807            }
3808        }
3809    }
3810
3811    /// A rank is a position in one dictionary and means nothing in another, so a rank offered
3812    /// against the wrong one is declined rather than answered out of the wrong order.
3813    #[test]
3814    fn a_rank_offered_against_another_dictionary_is_declined() {
3815        let (column, dictionary) = filed(&["one", "two"], vec![0, 1]);
3816        let (other, _) = filed(&["one", "two"], vec![1, 0]);
3817        assert!(select_against_rank(Comparison::Less, &column, &dictionary, 1, 2).is_some());
3818        assert!(select_against_rank(Comparison::Less, &other, &dictionary, 1, 2).is_none());
3819        let flat = Vector::constant(LogicalType::Varchar, Value::Varchar("one".into()), 2);
3820        assert!(select_against_rank(Comparison::Less, &flat, &dictionary, 1, 2).is_none());
3821        assert!(rank_at(&flat, 0).is_none(), "a column with no dictionary has no ranks");
3822        assert!(rank_within(&other, 0, &dictionary).is_none(), "another dictionary says nothing");
3823        assert!(rank_within(&flat, 0, &dictionary).is_none(), "no dictionary says nothing");
3824    }
3825
3826    /// The top N's reject. Two rows of the same column ordered by their ranks come out in the order
3827    /// their values come out in, which is the whole of what the rank comparison assumes.
3828    #[test]
3829    fn two_ranks_in_one_dictionary_order_their_values() {
3830        let (column, dictionary) =
3831            filed(&["", "one", "two", "four", "three"], vec![0, 1, 3, 2, 0, 4, 1, 0]);
3832        let rows = column.len();
3833        for left in 0..rows {
3834            for right in 0..rows {
3835                let here = rank_within(&column, left, &dictionary).expect("a ranked row");
3836                let there = rank_within(&column, right, &dictionary).expect("a ranked row");
3837                let values = (
3838                    column.try_value_at(left).expect("a value"),
3839                    column.try_value_at(right).expect("a value"),
3840                );
3841                let wanted = order(&values.0, &values.1).expect("two strings compare");
3842                assert_eq!(here.cmp(&there), wanted, "rows {left} and {right}");
3843                let (held, rank) = rank_at(&column, left).expect("a ranked row");
3844                assert!(Arc::ptr_eq(&held, &dictionary), "the dictionary it came from");
3845                assert_eq!(rank, here, "the same rank whichever way it is asked for");
3846            }
3847        }
3848    }
3849
3850    /// Every equality and inequality against a handful of literals, whole and narrowed, checked
3851    /// against the row at a time path. `missing` is in here because a dictionary that does not
3852    /// hold the literal is decided for the whole chunk and that is its own arm of the code.
3853    fn same_as_the_oracle(column: &Vector) {
3854        for literal in ["", "one", "missing", "zzz"] {
3855            for op in [
3856                Comparison::Equal,
3857                Comparison::NotEqual,
3858                Comparison::Less,
3859                Comparison::LessOrEqual,
3860                Comparison::Greater,
3861                Comparison::GreaterOrEqual,
3862            ] {
3863                let value = Value::Varchar(literal.to_owned());
3864                let held = Held::of(&LogicalType::Varchar, &value).expect("text has a column");
3865                let right = Vector::constant(LogicalType::Varchar, value.clone(), column.len());
3866                let wanted = oracle(op, column, &right);
3867                let got = compare_prepared(op, column, &right, Some(&held))
3868                    .expect("the peeled path answers");
3869                assert_eq!(got, wanted, "{literal:?} under {op:?}");
3870                let held = Held::of(&LogicalType::Varchar, &value).expect("text has a column");
3871                let picked = select_prepared(op, column, &right, Some(&held))
3872                    .expect("the peeled path selects");
3873                assert_eq!(
3874                    picked.indices(),
3875                    crate::select::selection(&wanted, column.len()).indices(),
3876                    "{literal:?} under {op:?}, selected"
3877                );
3878                // A fresh memo for the selection, since the one above belongs to that call's node.
3879                let held = Held::of(&LogicalType::Varchar, &value).expect("text has a column");
3880                let kept = Selection::from_predicate(column.len(), |row| row % 3 != 1);
3881                let refined = refine_prepared(op, column, &right, &kept, Some(&held))
3882                    .expect("the peeled path narrows");
3883                let wanted: Vec<u32> = kept
3884                    .indices()
3885                    .iter()
3886                    .copied()
3887                    .filter(|&row| is_true(&wanted.value_at(row as usize)))
3888                    .collect();
3889                assert_eq!(refined.indices(), wanted, "{literal:?} under {op:?}, narrowed");
3890            }
3891        }
3892    }
3893}