Skip to main content

rudb_vector/
vector.rs

1//! The vector itself.
2//!
3//! `spec/07-execution.md` section 7.1 calls this the widest interface in the system, says every
4//! operator depends on it, and says changing it after twenty operators exist is expensive. So it
5//! is written before the first operator rather than after the fifth.
6//!
7//! A vector is a type, a length of at most [`VECTOR_SIZE`], a physical form, a validity
8//! representation and some data. The four forms are the ones in `spec/04-architecture.md` section
9//! 4.3: flat, constant, sequence and dictionary. Encoded, the fifth, is the M3 work and it arrives
10//! with the specialization contract rather than before it.
11//!
12//! **What is not here yet.** Buffers are owned. Section 7.1 says a vector borrowed from a buffer
13//! managed page carries a pin, and there is no buffer manager until M2, so there is nothing to pin
14//! and pretending otherwise would be an interface built against an imaginary caller. Nested types
15//! are not stored yet either, for the same reason: a `LIST(STRUCT(...))` is offsets plus child
16//! column chunks, and child column chunks are storage.
17
18use std::sync::Arc;
19
20use rudb_common::{Error, LogicalType, Result, Value};
21
22use crate::buffer::Buffer;
23use crate::string::{StringColumn, StringView};
24use crate::validity::Validity;
25
26/// How many values are in a full vector.
27///
28/// 1024 rather than DuckDB's 2048, per `spec/04-architecture.md` section 4.3. It is the FastLanes
29/// unit, it makes a validity mask exactly 16 `u64` words, and it keeps a vector of 16 byte string
30/// views at 16 KiB, which is the size at which several of these fit in L1 together rather than
31/// evicting each other.
32pub const VECTOR_SIZE: usize = 1024;
33
34/// Which physical form a vector is in.
35///
36/// An operator asks this once per vector and then takes the path it wants, which is the one branch
37/// per vector that the whole design is willing to spend.
38///
39/// Not exhaustive, and that is a decision rather than an oversight. `Encoded` is the fifth form
40/// and it arrives at layer three with the specialization contract. If this enum were exhaustive,
41/// the day it lands is the day every kernel in the workspace stops compiling, and the pressure at
42/// that moment would be to add an arm to each of them in a hurry rather than to think about what
43/// each one should do with an encoded vector. A required fallback arm means each kernel already
44/// has a correct answer for a form it has never seen, and specializing it is then a change that
45/// can be made one kernel at a time with a benchmark next to it.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47#[non_exhaustive]
48pub enum Form {
49    /// One value per position.
50    Flat,
51    /// One value, repeated.
52    Constant,
53    /// A start and a step, computed rather than stored.
54    Sequence,
55    /// Codes into a smaller vector of distinct values.
56    Dictionary,
57}
58
59/// The values of a flat vector, one Rust vector per physical type.
60///
61/// The variants are physical rather than logical, which is what lets `DATE` and `INTEGER` share
62/// storage and share a kernel. What a run of `i32` means is the vector's logical type's business.
63#[derive(Debug, Clone, PartialEq)]
64#[non_exhaustive]
65pub enum Data {
66    /// No values, for the type of an untyped `NULL`.
67    Empty,
68    /// One byte per value.
69    Bool(Buffer<bool>),
70    /// 8 bit signed.
71    Int8(Buffer<i8>),
72    /// 16 bit signed.
73    Int16(Buffer<i16>),
74    /// 32 bit signed.
75    Int32(Buffer<i32>),
76    /// 64 bit signed.
77    Int64(Buffer<i64>),
78    /// 128 bit signed.
79    Int128(Buffer<i128>),
80    /// 8 bit unsigned.
81    UInt8(Buffer<u8>),
82    /// 16 bit unsigned.
83    UInt16(Buffer<u16>),
84    /// 32 bit unsigned.
85    UInt32(Buffer<u32>),
86    /// 64 bit unsigned.
87    UInt64(Buffer<u64>),
88    /// 128 bit unsigned.
89    UInt128(Buffer<u128>),
90    /// IEEE 754 binary32.
91    Float32(Buffer<f32>),
92    /// IEEE 754 binary64.
93    Float64(Buffer<f64>),
94    /// The months, days and microseconds triple.
95    Interval(Buffer<(i32, i32, i64)>),
96    /// Strings, as 16 byte views plus the arena the long ones live in.
97    Varlen(StringColumn),
98}
99
100impl Data {
101    /// How many values are stored.
102    ///
103    /// The match below has no wildcard arm, and that is what makes this function the check that
104    /// keeps [`for_each_layout`](crate::for_each_layout) honest. A variant added to this enum
105    /// without being added to the `all` group fails to compile here, which is a line in a build log
106    /// rather than a layout quietly missing from six kernels.
107    #[must_use]
108    pub fn len(&self) -> usize {
109        macro_rules! lengths {
110            ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
111                match self {
112                    Self::Empty => 0,
113                    $(Self::$variant(values) => values.len(),)+
114                }
115            };
116        }
117        crate::for_each_layout!(all, lengths)
118    }
119
120    /// Whether there are no values.
121    #[must_use]
122    pub fn is_empty(&self) -> bool {
123        self.len() == 0
124    }
125
126    /// How many bytes of memory these values are holding.
127    ///
128    /// One arm per layout through the same macro as [`Data::len`], for the same reason: a layout
129    /// added without a size here is a layout the memory limit would charge nothing for, and a
130    /// buffer that is free is a buffer that can be grown until the process dies.
131    #[must_use]
132    pub fn footprint(&self) -> usize {
133        macro_rules! sizes {
134            ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
135                match self {
136                    Self::Empty => 0,
137                    $(Self::$variant(values) => values.footprint(),)+
138                }
139            };
140        }
141        crate::for_each_layout!(all, sizes)
142    }
143
144    /// An integer at `index`, widened, for any of the signed integer layouts.
145    ///
146    /// Used by the decimal path, which needs the unscaled value out of whichever width the width
147    /// and scale picked, and by anything else that would otherwise repeat the same five arms.
148    #[must_use]
149    pub fn signed_at(&self, index: usize) -> Option<i128> {
150        macro_rules! widened {
151            ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
152                match self {
153                    $(Self::$variant(v) => v.get(index).map(|&x| i128::from(x)),)+
154                    _ => None,
155                }
156            };
157        }
158        crate::for_each_layout!(signed, widened)
159    }
160
161    /// An unsigned integer at `index`, widened.
162    #[must_use]
163    pub fn unsigned_at(&self, index: usize) -> Option<u128> {
164        macro_rules! widened {
165            ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
166                match self {
167                    $(Self::$variant(v) => v.get(index).map(|&x| u128::from(x)),)+
168                    _ => None,
169                }
170            };
171        }
172        crate::for_each_layout!(unsigned, widened)
173    }
174
175    /// The string at `index`, for a `Varlen`.
176    #[must_use]
177    pub fn str_at(&self, index: usize) -> Option<&str> {
178        match self {
179            Self::Varlen(column) => column.get(index),
180            _ => None,
181        }
182    }
183
184    /// The bytes at `index`, for a `Varlen`, whatever they are.
185    ///
186    /// What a `BLOB` reads through, since the bytes of one are not required to be text and
187    /// [`Self::str_at`] answers `None` for the ones that are not.
188    #[must_use]
189    pub fn bytes_at(&self, index: usize) -> Option<&[u8]> {
190        match self {
191            Self::Varlen(column) => column.bytes(index),
192            _ => None,
193        }
194    }
195}
196
197/// A type, a length, a validity representation and some data.
198#[derive(Debug, Clone, PartialEq)]
199pub struct Vector {
200    ty: LogicalType,
201    len: usize,
202    validity: Validity,
203    body: Body,
204}
205
206/// What the vector holds, which is what its form is decided by.
207#[derive(Debug, Clone, PartialEq)]
208enum Body {
209    Flat(Data),
210    Constant(Box<Value>),
211    Sequence {
212        start: i64,
213        step: i64,
214    },
215    /// The values are behind an `Arc` rather than a `Box` because slicing shares them.
216    ///
217    /// A dictionary vector is cut once per chunk and the dictionary itself is the same dictionary
218    /// every time, so a `Box` meant a copy of every value in it per cut. On the ClickBench columns
219    /// that are dictionary encoded the dictionary is larger than the chunk of codes pointing into
220    /// it, and copying it was ten percent of the cycles of reading the file.
221    ///
222    /// Nothing here mutates a dictionary in place, so sharing one is only ever a read, and the one
223    /// place that wants an owned copy of the values is [`compose`], which asks for one.
224    Dictionary {
225        codes: Vec<u32>,
226        values: Arc<Vector>,
227    },
228}
229
230impl Vector {
231    /// A flat vector of `data`, all valid.
232    ///
233    /// # Errors
234    ///
235    /// If the data's physical layout is not the one the type calls for. That check is here rather
236    /// than left to the caller because a vector whose type and layout disagree is a wrong answer
237    /// waiting to be read out, and it costs one comparison at construction to prevent.
238    pub fn flat(ty: LogicalType, data: Data) -> Result<Self> {
239        let len = data.len();
240        if !matches!(data, Data::Empty) && layout_of(&data) != ty.physical() {
241            return Err(Error::internal(format!(
242                "a {ty} vector cannot hold {:?} data",
243                layout_of(&data)
244            )));
245        }
246        Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Flat(data) })
247    }
248
249    /// A flat vector built from single values, with the nulls among them turning into validity.
250    ///
251    /// The slow way in, and the only way in that anything outside this crate has. It is what an
252    /// `INSERT`, a `VALUES` clause and a test build a column with, all of which arrive holding
253    /// values rather than a run of `i32`. Nothing on a scan path calls it: a scan produces a run of
254    /// data directly and hands it to [`Self::flat`].
255    ///
256    /// # Errors
257    ///
258    /// If a value is not one the type can hold, or if the type is one that cannot be stored flat
259    /// yet, which today means the nested types.
260    pub fn from_values(ty: LogicalType, values: &[Value]) -> Result<Self> {
261        let mut data = empty_data_for(&ty)?;
262        for value in values {
263            push_value(&mut data, value)?;
264        }
265        let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
266        Ok(Self { ty, len: values.len(), validity, body: Body::Flat(data) })
267    }
268
269    /// A vector of `len` copies of one value.
270    ///
271    /// Costs one value regardless of the length, which is what makes a literal in a predicate free
272    /// and what makes a projection of a constant free.
273    #[must_use]
274    pub fn constant(ty: LogicalType, value: Value, len: usize) -> Self {
275        let validity = if value.is_null() { Validity::AllInvalid } else { Validity::AllValid };
276        Self { ty, len, validity, body: Body::Constant(Box::new(value)) }
277    }
278
279    /// A vector of `len` values starting at `start` and stepping by `step`.
280    ///
281    /// This is what a row identifier column is, and it costs sixteen bytes rather than eight
282    /// kilobytes. A scan that produces row ids for a later fetch produces one of these.
283    #[must_use]
284    pub fn sequence(start: i64, step: i64, len: usize) -> Self {
285        Self {
286            ty: LogicalType::BigInt,
287            len,
288            validity: Validity::AllValid,
289            body: Body::Sequence { start, step },
290        }
291    }
292
293    /// A vector of codes into a smaller vector of distinct values.
294    ///
295    /// The form the whole M3 thesis rests on. A dictionary vector handed to a group by is an
296    /// integer column, and an aggregate over one is an aggregate over integers no matter what the
297    /// logical type says.
298    ///
299    /// A dictionary over a dictionary is composed into one level here rather than left as two, so
300    /// the form has a depth of one always and a kernel that reads [`Self::dictionary_parts`] is
301    /// reading the values rather than another layer of codes. Two filters over the same chunk build
302    /// the second case and four conjuncts pushed down separately build four of it.
303    ///
304    /// The cost of leaving them stacked turned out to be a cliff rather than a slope. Every loop in
305    /// `rudb-kernels` reaches for the values behind the codes with [`Self::data`], a dictionary
306    /// pointing at a dictionary has no data to hand back, so the second level does not make the
307    /// kernels slower, it turns them off and drops the work onto the row at a time path that exists
308    /// to be correct rather than fast. Measured on server3 over a chunk of two numeric columns and a
309    /// consumer of two vectorized passes, one level reads at 3.5 nanoseconds a row and two levels at
310    /// 104, and the third and fourth levels cost almost nothing more because the first one had
311    /// already given up everything there was to give. Composing is one pass over the outer codes,
312    /// which the range check above is already making.
313    ///
314    /// The one dictionary that is not composed past is one carrying a validity of its own. A
315    /// dictionary is built all valid and only [`Self::with_validity`] can change that, so such a
316    /// vector is saying that its nulls are at this level rather than in the values it points at, and
317    /// composing past it would drop them.
318    ///
319    /// # Errors
320    ///
321    /// If any code is past the end of the value vector.
322    pub fn dictionary(codes: Vec<u32>, values: Vector) -> Result<Self> {
323        if let Some(&bad) = codes.iter().find(|&&code| code as usize >= values.len()) {
324            return Err(Error::internal(format!(
325                "dictionary code {bad} is past the end of a {} value dictionary",
326                values.len()
327            )));
328        }
329        let (codes, values) = compose(codes, values);
330        Ok(Self {
331            ty: values.ty.clone(),
332            len: codes.len(),
333            validity: Validity::AllValid,
334            body: Body::Dictionary { codes, values: Arc::new(values) },
335        })
336    }
337
338    /// The same vector with a different validity.
339    #[must_use]
340    pub fn with_validity(mut self, validity: Validity) -> Self {
341        self.validity = validity;
342        self
343    }
344
345    /// What kind of values these are.
346    #[must_use]
347    pub fn logical_type(&self) -> &LogicalType {
348        &self.ty
349    }
350
351    /// How many values there are.
352    #[must_use]
353    pub fn len(&self) -> usize {
354        self.len
355    }
356
357    /// Whether there are no values.
358    #[must_use]
359    pub fn is_empty(&self) -> bool {
360        self.len == 0
361    }
362
363    /// How many bytes of memory this vector is holding.
364    ///
365    /// What the memory limit charges for it. A constant and a sequence hold one value and two
366    /// numbers however long they are, which is the point of both forms, so the number here is the
367    /// form's cost and not the column's width times its length.
368    ///
369    /// A dictionary counts its values in full, and two vectors sharing one dictionary each report
370    /// all of it. That over counts, deliberately: working out that two operators are looking at the
371    /// same `Arc` means threading identity through the accounting, and a limit that over counts
372    /// refuses a query that would have fit while a limit that under counts lets one through that
373    /// does not. The first is a worse answer to give and the second is a worse thing to be.
374    #[must_use]
375    pub fn footprint(&self) -> usize {
376        let body = match &self.body {
377            Body::Flat(data) => data.footprint(),
378            Body::Constant(value) => value.footprint(),
379            Body::Sequence { .. } => 0,
380            Body::Dictionary { codes, values } => {
381                codes.capacity() * size_of::<u32>() + values.footprint()
382            }
383        };
384        size_of::<Self>() + self.validity.footprint() + body
385    }
386
387    /// Which of the values are not null.
388    #[must_use]
389    pub fn validity(&self) -> &Validity {
390        &self.validity
391    }
392
393    /// Which physical form this vector is in.
394    #[must_use]
395    pub fn form(&self) -> Form {
396        match self.body {
397            Body::Flat(_) => Form::Flat,
398            Body::Constant(_) => Form::Constant,
399            Body::Sequence { .. } => Form::Sequence,
400            Body::Dictionary { .. } => Form::Dictionary,
401        }
402    }
403
404    /// The data, for a flat vector, and `None` for any other form.
405    ///
406    /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
407    /// that can do better on a constant or a dictionary checks [`Self::form`] first.
408    #[must_use]
409    pub fn data(&self) -> Option<&Data> {
410        match &self.body {
411            Body::Flat(data) => Some(data),
412            _ => None,
413        }
414    }
415
416    /// The one value, for a constant vector, and `None` for any other form.
417    ///
418    /// A kernel comparing a column against a literal wants the literal once rather than 1024
419    /// times, and [`Self::value_at`] on a constant clones it on every call because it has to be
420    /// able to hand back a `Value` for any form. This is the accessor that lets the specialized
421    /// path hoist the clone out of the loop.
422    #[must_use]
423    pub fn constant_value(&self) -> Option<&Value> {
424        match &self.body {
425            Body::Constant(value) => Some(value.as_ref()),
426            _ => None,
427        }
428    }
429
430    /// The codes and the values, for a dictionary vector, and `None` for any other form.
431    ///
432    /// The reason a kernel needs this rather than reading the dictionary through
433    /// [`Self::value_at`] is the entire argument for the form existing. A filter against a
434    /// dictionary column of 1024 rows and 40 distinct values is 40 comparisons and 1024 lookups,
435    /// not 1024 comparisons, and there is no way to write that loop without seeing the codes.
436    ///
437    /// Note what the validity of the returned vector means. A dictionary keeps its nulls in the
438    /// vector it points at, and the dictionary's own validity says nothing about them, so a caller
439    /// deciding whether row `i` is null has to ask the value vector about `codes[i]` rather than
440    /// asking this vector about `i`. [`Self::flatten`] has the same note on it for the same
441    /// reason, because getting this wrong is a null that survives being selected and comes out as
442    /// a zero.
443    #[must_use]
444    pub fn dictionary_parts(&self) -> Option<(&[u32], &Self)> {
445        match &self.body {
446            Body::Dictionary { codes, values } => Some((codes, values.as_ref())),
447            _ => None,
448        }
449    }
450
451    /// The start and the step, for a sequence vector, and `None` for any other form.
452    #[must_use]
453    pub fn sequence_parts(&self) -> Option<(i64, i64)> {
454        match self.body {
455            Body::Sequence { start, step } => Some((start, step)),
456            _ => None,
457        }
458    }
459
460    /// The value at `index`, as a single value.
461    ///
462    /// This is the slow path on purpose. It is what a result set is read out with and what a test
463    /// asserts on, and an operator that calls it per row is an operator that has already lost the
464    /// argument the vector interface exists to win.
465    #[must_use]
466    pub fn value_at(&self, index: usize) -> Value {
467        if index >= self.len || !self.validity.is_valid(index) {
468            return Value::Null;
469        }
470        match &self.body {
471            Body::Constant(value) => value.as_ref().clone(),
472            Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
473            Body::Dictionary { codes, values } => match codes.get(index) {
474                Some(&code) => values.value_at(code as usize),
475                None => Value::Null,
476            },
477            Body::Flat(data) => value_from(&self.ty, data, index),
478        }
479    }
480
481    /// The text at `index`, borrowed rather than copied.
482    ///
483    /// [`Self::value_at`] on a `VARCHAR` column allocates a `String` per call, and a group by that
484    /// reads a string column keys on one string per input row. This hands back the bytes where they
485    /// already are, so a caller with somewhere to put them does not go to the allocator at all.
486    ///
487    /// `None` for a null, for an index past the end, for a column that is not `VARCHAR`, and for the
488    /// constant and sequence forms, whose values are not stored per position. A caller that gets
489    /// `None` has to fall back to [`Self::value_at`], which is correct for all of those.
490    #[must_use]
491    pub fn text_at(&self, index: usize) -> Option<&str> {
492        if self.ty != LogicalType::Varchar || index >= self.len || !self.validity.is_valid(index) {
493            return None;
494        }
495        match &self.body {
496            Body::Flat(data) => data.str_at(index),
497            Body::Dictionary { codes, values } => {
498                values.text_at(usize::try_from(*codes.get(index)?).ok()?)
499            }
500            _ => None,
501        }
502    }
503
504    /// Every value in order, as single values.
505    pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
506        (0..self.len).map(|index| self.value_at(index))
507    }
508
509    /// A contiguous run of the values, in the form they are already in.
510    ///
511    /// This is the cut [`Self::gather`] cannot do. A gather walks a dictionary to its leaf and
512    /// copies, so gathering a piece of a dictionary encoded column hands back a flat one, and a
513    /// caller that only wanted the first thousand rows of a page has silently paid for a copy and
514    /// thrown the dictionary away. A group by over a dictionary encoded column is the case that
515    /// cares, and it is most of ClickBench.
516    ///
517    /// So each form is cut as itself. A dictionary keeps its dictionary and slices its codes, a
518    /// sequence stays arithmetic with its start moved along, a constant stays a shorter constant,
519    /// and a flat body is the one that genuinely has to copy its range.
520    ///
521    /// The dictionary itself is shared rather than copied, so a cut is the codes and nothing else.
522    /// It used to be copied, and on a read of a ClickBench partition that copy was ten percent of
523    /// the cycles: a page holds one dictionary and is cut into chunk sized pieces, so the whole
524    /// dictionary was copied once per chunk to be read the same way each time.
525    ///
526    /// # Errors
527    ///
528    /// If the range runs past the end of the vector, or if the type has no flat layout and the
529    /// body is one that has to be copied.
530    pub fn slice(&self, at: usize, len: usize) -> Result<Self> {
531        let end = at.checked_add(len).ok_or_else(|| Error::internal("a slice that wraps"))?;
532        if end > self.len {
533            return Err(Error::internal(format!("rows {at} to {end} of a vector of {}", self.len)));
534        }
535        if at == 0 && len == self.len {
536            return Ok(self.clone());
537        }
538        let validity = Validity::from_iter(len, |row| self.validity.is_valid(at + row));
539        let body = match &self.body {
540            Body::Constant(value) => Body::Constant(value.clone()),
541            Body::Sequence { start, step } => {
542                Body::Sequence { start: start + step * at as i64, step: *step }
543            }
544            Body::Dictionary { codes, values } => {
545                Body::Dictionary { codes: codes[at..end].to_vec(), values: Arc::clone(values) }
546            }
547            // The one form with nowhere to point, so its range is copied out. A gather is the
548            // right tool here and does no more than this would: a flat body has no dictionary
549            // under it for the gather to flatten.
550            Body::Flat(_) => {
551                let indices: Vec<u32> =
552                    (at..end).map(|row| u32::try_from(row).unwrap_or(u32::MAX)).collect();
553                return self.gather(&indices);
554            }
555        };
556        Ok(Self { ty: self.ty.clone(), len, validity, body })
557    }
558
559    /// The same values in flat form.
560    ///
561    /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
562    /// which is exactly why the other forms exist and why nothing on the hot path should call
563    /// this. It is here for the operators that genuinely cannot do better and for the tests that
564    /// check the other forms against it.
565    ///
566    /// # Errors
567    ///
568    /// If the type is one this crate cannot store flat yet, which today means the nested types.
569    pub fn flatten(&self) -> Result<Self> {
570        if let Body::Flat(_) = self.body {
571            return Ok(self.clone());
572        }
573        self.copied((0..self.len).collect(), false)
574    }
575
576    /// The values at the given positions, copied, in a form that does not point back at this vector.
577    ///
578    /// This is the copying counterpart to [`Self::dictionary`], and the two are the two halves of
579    /// the decision `spec/07-execution.md` section 7.1 describes. Which half is right is measured
580    /// rather than argued, and [`Chunk::compact`](crate::Chunk::compact) is where the measurement
581    /// is written down.
582    ///
583    /// A dictionary chain is walked to its leaf first and the codes composed on the way down, so the
584    /// copy runs once over the data rather than once per level, and a position that is null at any
585    /// level comes out null here. The copy is a typed loop per physical layout rather than a `Value`
586    /// per row, which is the whole point of it and is what [`Self::flatten`] now goes through too.
587    ///
588    /// # Errors
589    ///
590    /// If the type has no flat layout, which today means the nested types.
591    pub fn gather(&self, indices: &[u32]) -> Result<Self> {
592        self.copied(indices.iter().map(|&index| index as usize).collect(), true)
593    }
594
595    /// The copy both [`Self::gather`] and [`Self::flatten`] are.
596    ///
597    /// `constants_stay` is the one thing the two want differently. A gather of a constant is a
598    /// shorter constant and copying it out would be a thousand writes of the same value for nothing,
599    /// but flattening promises flat form to a caller that is about to read the data slice, so for
600    /// that one the constant has to be written out.
601    fn copied(&self, at: Vec<usize>, constants_stay: bool) -> Result<Self> {
602        let rows = at.len();
603        let (at, leaf) = self.resolve(at);
604        let live: Vec<bool> = at.iter().map(|&index| index != NOWHERE).collect();
605        let validity = Validity::from_run(&live);
606        let body = match &leaf.body {
607            // Every position holds the same value, so the only thing the gather can change is the
608            // length and which positions are null. A gather with no null in it is still a constant.
609            Body::Constant(value) => {
610                if constants_stay && matches!(validity, Validity::AllValid) {
611                    return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
612                }
613                let mut data = empty_data_for(&self.ty)?;
614                for &index in &at {
615                    push_value(&mut data, if index == NOWHERE { &Value::Null } else { value })?;
616                }
617                Body::Flat(data)
618            }
619            // A sequence is arithmetic rather than storage, so the gather is the arithmetic done at
620            // the positions asked for, and a null writes the zero every other layout writes.
621            Body::Sequence { start, step } => Body::Flat(Data::Int64(
622                at.iter()
623                    .map(|&index| if index == NOWHERE { 0 } else { start + step * index as i64 })
624                    .collect(),
625            )),
626            // A flat body with no values is the untyped null, so every position asked for is null
627            // whatever was asked for. Going through the copy would build a run of no values and
628            // call it `rows` long, which is a vector whose length and data disagree.
629            Body::Flat(Data::Empty) => {
630                return Ok(Self::constant(self.ty.clone(), Value::Null, rows));
631            }
632            Body::Flat(data) => Body::Flat(copy_of(data, &at)),
633            // Unreachable, because `resolve` stops at the first body that is not a dictionary.
634            Body::Dictionary { .. } => {
635                return Err(Error::internal("a dictionary survived being resolved"));
636            }
637        };
638        Ok(Self { ty: self.ty.clone(), len: rows, validity, body })
639    }
640
641    /// Where each wanted position lives in the first body that is not a dictionary, and that body.
642    ///
643    /// A position that is null anywhere on the way down, or past the end of anything on the way
644    /// down, comes back as [`NOWHERE`]. That single sentinel is what keeps the copy loop from
645    /// carrying a validity mask alongside the positions it is already walking.
646    fn resolve(&self, mut at: Vec<usize>) -> (Vec<usize>, &Self) {
647        let mut source = self;
648        loop {
649            for slot in &mut at {
650                if *slot >= source.len || !source.validity.is_valid(*slot) {
651                    *slot = NOWHERE;
652                }
653            }
654            let Body::Dictionary { codes, values } = &source.body else {
655                return (at, source);
656            };
657            for slot in &mut at {
658                *slot = match codes.get(*slot) {
659                    Some(&code) => code as usize,
660                    None => NOWHERE,
661                };
662            }
663            source = values.as_ref();
664        }
665    }
666}
667
668/// So that a kernel can take its operands as either a list of vectors or a list of references.
669///
670/// A caller that built a `Vec<Vector>` and a caller whose operands are already somewhere else, in a
671/// chunk or in an evaluator's scratch, want the same kernel. Without this the second kind has to
672/// clone every operand into a `Vec` to satisfy the signature, and a clone of a vector is a copy of
673/// the whole column, so the type would be charging real memory traffic for nothing.
674impl AsRef<Vector> for Vector {
675    fn as_ref(&self) -> &Vector {
676        self
677    }
678}
679
680/// One level of dictionary out of however many levels were handed to [`Vector::dictionary`].
681///
682/// Every dictionary in the system is built through that constructor and every one of them comes
683/// through here first, so the invariant this maintains is that the vector a dictionary points at is
684/// never itself a dictionary that could have been composed away. That makes the work a single `if`
685/// rather than a loop: the inner vector was already composed when it was built, so composing the
686/// outer codes through it leaves the result no deeper than the inner vector already was.
687///
688/// The codes are indexed rather than fetched with `get`, because the caller has already walked the
689/// whole outer array to check that every code is in range and the inner array is exactly as long as
690/// the vector those codes were checked against.
691fn compose(codes: Vec<u32>, values: Vector) -> (Vec<u32>, Vector) {
692    // A dictionary carrying a validity of its own is one whose nulls live at this level rather than
693    // in the values, which is the one thing composition cannot carry down with it.
694    if !matches!(values.validity, Validity::AllValid) {
695        return (codes, values);
696    }
697    let Vector { ty, len, validity, body } = values;
698    match body {
699        Body::Dictionary { codes: inner, values: leaf } => {
700            debug_assert!(
701                !matches!(leaf.body, Body::Dictionary { .. })
702                    || !matches!(leaf.validity, Validity::AllValid),
703                "a dictionary was stacked on a dictionary without going through the constructor"
704            );
705            // The leaf is shared, so taking it out of the `Arc` copies it when something else is
706            // still holding the same dictionary. That is the rare path: a dictionary over a
707            // dictionary only arrives from a caller that built one that way, and the cut that made
708            // sharing worth doing produces neither.
709            (codes.iter().map(|&code| inner[code as usize]).collect(), Arc::unwrap_or_clone(leaf))
710        }
711        body => (codes, Vector { ty, len, validity, body }),
712    }
713}
714
715/// The position of a value that is not anywhere, because it is null or out of range.
716///
717/// `usize::MAX` rather than an `Option<usize>`, because the copy loop's bounds check rejects it for
718/// free and an `Option` would put a second branch next to the one already there.
719const NOWHERE: usize = usize::MAX;
720
721/// A run of data copied at the given positions, with a zero wherever the position is [`NOWHERE`].
722///
723/// A zero and not a skip, because every layout here is a parallel array to a validity mask and a
724/// short one would put every value after the first null at the wrong index. It is the same rule
725/// [`push_value`] follows for a null.
726fn copy_of(data: &Data, at: &[usize]) -> Data {
727    macro_rules! copied {
728        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
729            match data {
730                Data::Empty => Data::Empty,
731                $(Data::$variant(values) => {
732                    let mut out = Buffer::with_capacity(at.len());
733                    for &index in at {
734                        // One bounds check rather than a null test and a bounds check, because
735                        // `NOWHERE` is past the end of every slice there can be.
736                        out.push(values.get(index).copied().unwrap_or($zero));
737                    }
738                    Data::$variant(out)
739                })+
740                // The one layout where a gather is a copy of bytes rather than a copy of fixed
741                // width slots, and the reason compaction is a decision rather than a default on a
742                // string column.
743                Data::Varlen(values) => {
744                    let mut out = StringColumn::with_capacity(at.len());
745                    // The bytes are known before any of them are copied, because a view carries its
746                    // length and the wanted positions are already in hand, so the arena is one
747                    // allocation rather than a run of doublings that each copy what the last one
748                    // copied.
749                    let views = values.views();
750                    out.reserve_bytes(
751                        at.iter()
752                            .filter_map(|&index| views.get(index))
753                            .filter(|view| !view.is_inline())
754                            .map(StringView::len)
755                            .sum(),
756                    );
757                    for &index in at {
758                        out.push_from(values, index);
759                    }
760                    Data::Varlen(out)
761                }
762            }
763        };
764    }
765    crate::for_each_layout!(fixed, copied)
766}
767
768/// The physical layout a run of data is in, for the check that it matches its type.
769///
770/// The two enums name their variants the same way on purpose, so this is one generated arm rather
771/// than sixteen chances to pair the wrong two up.
772fn layout_of(data: &Data) -> rudb_common::PhysicalType {
773    use rudb_common::PhysicalType as P;
774    macro_rules! layouts {
775        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
776            match data {
777                Data::Empty => P::Empty,
778                $(Data::$variant(_) => P::$variant,)+
779            }
780        };
781    }
782    crate::for_each_layout!(all, layouts)
783}
784
785/// One value out of a run of data, given what the run means.
786///
787/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
788/// from an `INTEGER` and that is the whole reason the two are kept apart.
789fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
790    let signed = || data.signed_at(index);
791    let unsigned = || data.unsigned_at(index);
792    let value = match ty {
793        LogicalType::Boolean => match data {
794            Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
795            _ => None,
796        },
797        LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
798        LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
799        LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
800        LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
801        LogicalType::HugeInt => signed().map(Value::HugeInt),
802        LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
803        LogicalType::USmallInt => {
804            unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
805        }
806        LogicalType::UInteger => {
807            unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
808        }
809        LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
810        LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
811        LogicalType::Float => match data {
812            Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
813            _ => None,
814        },
815        LogicalType::Double => match data {
816            Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
817            _ => None,
818        },
819        LogicalType::Decimal { width, scale } => {
820            signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
821        }
822        LogicalType::Varchar => data.str_at(index).map(|s| Value::Varchar(s.to_string())),
823        LogicalType::Blob | LogicalType::Bit => {
824            data.bytes_at(index).map(|bytes| Value::Blob(bytes.to_vec()))
825        }
826        LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
827        LogicalType::Time | LogicalType::TimeTz => {
828            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time)
829        }
830        LogicalType::Timestamp
831        | LogicalType::TimestampS
832        | LogicalType::TimestampMs
833        | LogicalType::TimestampNs
834        | LogicalType::TimestampTz => {
835            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
836        }
837        LogicalType::Interval => match data {
838            Data::Interval(v) => {
839                v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
840            }
841            _ => None,
842        },
843        _ => None,
844    };
845    value.unwrap_or(Value::Null)
846}
847
848/// An empty run of data of the right layout for a type.
849fn empty_data_for(ty: &LogicalType) -> Result<Data> {
850    use rudb_common::PhysicalType as P;
851    macro_rules! empties {
852        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
853            match ty.physical() {
854                P::Empty => Data::Empty,
855                $(P::$variant => Data::$variant(Buffer::new()),)+
856                P::Varlen => Data::Varlen(StringColumn::new()),
857                other => {
858                    return Err(Error::not_implemented(format!(
859                        "a flat vector of {other:?} data, which arrives with the storage layer"
860                    )));
861                }
862            }
863        };
864    }
865    Ok(crate::for_each_layout!(fixed, empties))
866}
867
868/// Appends one value to a run of data, or a zero of the right shape when it is null.
869///
870/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
871/// and a run of data with a hole in it would put every value after the hole in the wrong place.
872fn push_value(data: &mut Data, value: &Value) -> Result<()> {
873    macro_rules! push {
874        ($vec:expr, $variant:path, $zero:expr) => {
875            match value {
876                Value::Null => $vec.push($zero),
877                $variant(x) => $vec.push(*x),
878                other => {
879                    return Err(Error::internal(format!(
880                        "{other:?} does not belong in this vector"
881                    )));
882                }
883            }
884        };
885    }
886    // A decimal is stored as its unscaled integer in whatever width its precision needs, which
887    // `LogicalType::physical` decides and which is why the same `Value::Decimal` is at home in four
888    // different runs. The narrowing cannot fail for a value the binder produced, because the width
889    // that chose the run is the width in the value, but it is checked rather than assumed because
890    // an unchecked cast here would silently store a different number.
891    macro_rules! decimal {
892        ($vec:expr, $ty:ty, $unscaled:expr) => {
893            match <$ty>::try_from(*$unscaled) {
894                Ok(x) => $vec.push(x),
895                Err(_) => {
896                    return Err(Error::internal(format!(
897                        "an unscaled decimal of {} does not fit the run its precision chose",
898                        $unscaled
899                    )));
900                }
901            }
902        };
903    }
904    match data {
905        Data::Empty => {}
906        Data::Bool(v) => push!(v, Value::Boolean, false),
907        Data::Int8(v) => push!(v, Value::TinyInt, 0),
908        Data::Int16(v) => match value {
909            Value::Null => v.push(0),
910            Value::SmallInt(x) => v.push(*x),
911            Value::Decimal { unscaled, .. } => decimal!(v, i16, unscaled),
912            other => return Err(Error::internal(format!("{other:?} is not a 16 bit value"))),
913        },
914        Data::Int32(v) => match value {
915            Value::Null => v.push(0),
916            Value::Integer(x) | Value::Date(x) => v.push(*x),
917            Value::Decimal { unscaled, .. } => decimal!(v, i32, unscaled),
918            other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
919        },
920        Data::Int64(v) => match value {
921            Value::Null => v.push(0),
922            Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => v.push(*x),
923            Value::Decimal { unscaled, .. } => decimal!(v, i64, unscaled),
924            other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
925        },
926        Data::Int128(v) => match value {
927            Value::Null => v.push(0),
928            Value::HugeInt(x) => v.push(*x),
929            Value::Decimal { unscaled, .. } => v.push(*unscaled),
930            other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
931        },
932        Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
933        Data::UInt16(v) => push!(v, Value::USmallInt, 0),
934        Data::UInt32(v) => push!(v, Value::UInteger, 0),
935        Data::UInt64(v) => push!(v, Value::UBigInt, 0),
936        Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
937        Data::Float32(v) => push!(v, Value::Float, 0.0),
938        Data::Float64(v) => push!(v, Value::Double, 0.0),
939        Data::Interval(v) => match value {
940            Value::Null => v.push((0, 0, 0)),
941            Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
942            other => return Err(Error::internal(format!("{other:?} is not an interval"))),
943        },
944        Data::Varlen(column) => match value {
945            Value::Null => {
946                column.push("");
947            }
948            Value::Varchar(text) => {
949                column.push(text);
950            }
951            // A blob goes in as the bytes it is. The column stores a length and some bytes either
952            // way, so text is the reading of one rather than a different column, and a blob that
953            // is not UTF-8 is stored exactly like one that happens to be.
954            Value::Blob(bytes) => {
955                column.push_bytes(bytes);
956            }
957            other => return Err(Error::internal(format!("{other:?} is not a string"))),
958        },
959    }
960    Ok(())
961}
962
963#[cfg(test)]
964mod tests {
965    use std::sync::Arc;
966
967    use rudb_common::{LogicalType, Value};
968
969    use super::{Body, Data, Form, VECTOR_SIZE, Vector};
970    use crate::string::StringColumn;
971    use crate::validity::Validity;
972
973    fn integers(values: &[i32]) -> Vector {
974        Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec().into())).unwrap()
975    }
976
977    #[test]
978    fn slicing_a_dictionary_keeps_it_a_dictionary_where_gathering_would_not() {
979        let values = Vector::from_values(
980            LogicalType::Varchar,
981            &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
982        )
983        .unwrap();
984        let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
985
986        let piece = vector.slice(1, 3).unwrap();
987        assert_eq!(piece.form(), Form::Dictionary, "the form is the whole point");
988        assert_eq!(piece.len(), 3);
989        assert_eq!(
990            piece.iter().collect::<Vec<_>>(),
991            [
992                Value::Varchar("blue".into()),
993                Value::Varchar("blue".into()),
994                Value::Varchar("red".into())
995            ]
996        );
997        assert_eq!(vector.gather(&[1, 2, 3]).unwrap().form(), Form::Flat, "which a gather loses");
998    }
999
1000    #[test]
1001    fn slicing_a_dictionary_shares_the_dictionary_rather_than_copying_it() {
1002        // The assertion is about the address and not about the values, because the values were
1003        // right when the dictionary was copied too. A page holds one dictionary and is cut into a
1004        // chunk of codes at a time, so copying the dictionary here is a copy of every string in it
1005        // per chunk, and on a read of a ClickBench partition it was ten percent of the cycles.
1006        let values = Vector::from_values(
1007            LogicalType::Varchar,
1008            &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
1009        )
1010        .unwrap();
1011        let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
1012        let Body::Dictionary { values: whole, .. } = &vector.body else {
1013            panic!("a dictionary vector holds a dictionary");
1014        };
1015
1016        let piece = vector.slice(1, 3).unwrap();
1017        let Body::Dictionary { codes, values: cut } = &piece.body else {
1018            panic!("a slice of a dictionary is a dictionary");
1019        };
1020        assert!(Arc::ptr_eq(whole, cut), "the cut copied the dictionary");
1021        assert_eq!(codes, &[1, 1, 0], "the codes are the part that is cut");
1022
1023        // And a cut of a cut shares it too, since that is what a scan does to a page it reads twice.
1024        let again = piece.slice(1, 2).unwrap();
1025        let Body::Dictionary { values: cut, .. } = &again.body else {
1026            panic!("a slice of a slice of a dictionary is a dictionary");
1027        };
1028        assert!(Arc::ptr_eq(whole, cut), "the second cut copied the dictionary");
1029        assert_eq!(
1030            again.iter().collect::<Vec<_>>(),
1031            [Value::Varchar("blue".into()), Value::Varchar("red".into())]
1032        );
1033    }
1034
1035    #[test]
1036    fn a_slice_carries_the_nulls_that_were_in_its_range_and_not_the_others() {
1037        let vector =
1038            integers(&[1, 2, 3, 4]).with_validity(Validity::from_run(&[false, true, false, true]));
1039        let piece = vector.slice(1, 2).unwrap();
1040        assert!(piece.validity().is_valid(0));
1041        assert!(!piece.validity().is_valid(1));
1042        assert_eq!(piece.value_at(1), Value::Null);
1043    }
1044
1045    #[test]
1046    fn slicing_a_sequence_moves_its_start_rather_than_writing_the_values_out() {
1047        let vector = Vector::sequence(100, 5, 10);
1048        let piece = vector.slice(3, 4).unwrap();
1049        assert_eq!(piece.form(), Form::Sequence);
1050        assert_eq!(
1051            piece.iter().collect::<Vec<_>>(),
1052            [Value::BigInt(115), Value::BigInt(120), Value::BigInt(125), Value::BigInt(130)]
1053        );
1054    }
1055
1056    #[test]
1057    fn slicing_a_constant_is_a_shorter_constant() {
1058        let vector = Vector::constant(LogicalType::Integer, Value::Integer(9), 8);
1059        let piece = vector.slice(2, 3).unwrap();
1060        assert_eq!(piece.form(), Form::Constant);
1061        assert_eq!(piece.len(), 3);
1062        assert_eq!(piece.value_at(2), Value::Integer(9));
1063    }
1064
1065    #[test]
1066    fn slicing_the_whole_vector_hands_it_back_as_it_was() {
1067        let vector = integers(&[1, 2, 3]);
1068        assert_eq!(
1069            vector.slice(0, 3).unwrap().iter().collect::<Vec<_>>(),
1070            [Value::Integer(1), Value::Integer(2), Value::Integer(3)]
1071        );
1072    }
1073
1074    #[test]
1075    fn a_slice_past_the_end_is_an_error_rather_than_a_short_vector() {
1076        let error = integers(&[1, 2, 3]).slice(2, 2).unwrap_err();
1077        assert!(error.to_string().contains("of a vector of 3"), "{error}");
1078    }
1079
1080    #[test]
1081    fn the_vector_size_is_the_one_the_design_is_built_around() {
1082        // 1024 and not DuckDB's 2048. A validity mask is 16 u64 words and a vector of string views
1083        // is 16 KiB, both of which are consequences of this number rather than coincidences.
1084        assert_eq!(VECTOR_SIZE, 1024);
1085        assert_eq!(VECTOR_SIZE / 64, 16);
1086    }
1087
1088    #[test]
1089    fn a_flat_vector_reads_back_what_was_put_in_it() {
1090        let vector = integers(&[1, 2, 3]);
1091        assert_eq!(vector.form(), Form::Flat);
1092        assert_eq!(vector.len(), 3);
1093        assert_eq!(vector.value_at(1), Value::Integer(2));
1094        assert_eq!(
1095            vector.iter().collect::<Vec<_>>(),
1096            vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
1097        );
1098    }
1099
1100    #[test]
1101    fn a_vector_built_from_values_reads_the_same_values_back() {
1102        let vector = Vector::from_values(
1103            LogicalType::Varchar,
1104            &[
1105                Value::Varchar("a".to_string()),
1106                Value::Null,
1107                Value::Varchar("a string too long to sit inside a view".to_string()),
1108            ],
1109        )
1110        .expect("strings and a null");
1111        assert_eq!(vector.len(), 3);
1112        assert_eq!(vector.value_at(0), Value::Varchar("a".to_string()));
1113        assert_eq!(vector.value_at(1), Value::Null);
1114        assert_eq!(
1115            vector.value_at(2),
1116            Value::Varchar("a string too long to sit inside a view".to_string())
1117        );
1118    }
1119
1120    /// A null still occupies a position. If it did not then every value after it would read back
1121    /// one place to the left, which is the kind of bug that looks like a storage bug for a week.
1122    #[test]
1123    fn a_null_in_the_middle_does_not_move_the_values_after_it() {
1124        let vector = Vector::from_values(
1125            LogicalType::Integer,
1126            &[Value::Integer(1), Value::Null, Value::Integer(3)],
1127        )
1128        .expect("integers and a null");
1129        assert_eq!(vector.value_at(2), Value::Integer(3));
1130        assert!(vector.validity().has_nulls(3), "the middle one is null");
1131    }
1132
1133    #[test]
1134    fn a_value_the_type_cannot_hold_is_refused() {
1135        let wrong = Vector::from_values(LogicalType::Integer, &[Value::Varchar("x".to_string())]);
1136        assert!(wrong.is_err(), "a string is not an integer");
1137    }
1138
1139    #[test]
1140    fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
1141        // One comparison here against a wrong answer read out three layers later.
1142        let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1].into()));
1143        assert!(wrong.is_err());
1144        let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1].into()));
1145        assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
1146    }
1147
1148    #[test]
1149    fn a_constant_vector_costs_one_value_whatever_its_length() {
1150        let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
1151        assert_eq!(vector.form(), Form::Constant);
1152        assert_eq!(vector.len(), VECTOR_SIZE);
1153        assert_eq!(vector.value_at(0), Value::Integer(7));
1154        assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
1155        assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
1156    }
1157
1158    #[test]
1159    fn a_constant_null_is_all_invalid_without_being_told() {
1160        let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
1161        assert_eq!(vector.validity(), &Validity::AllInvalid);
1162        assert_eq!(vector.value_at(3), Value::Null);
1163    }
1164
1165    #[test]
1166    fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
1167        let vector = Vector::sequence(100, 1, VECTOR_SIZE);
1168        assert_eq!(vector.form(), Form::Sequence);
1169        assert_eq!(vector.value_at(0), Value::BigInt(100));
1170        assert_eq!(vector.value_at(923), Value::BigInt(1023));
1171        let stepped = Vector::sequence(0, 5, 4);
1172        assert_eq!(
1173            stepped.iter().collect::<Vec<_>>(),
1174            vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
1175        );
1176    }
1177
1178    #[test]
1179    fn a_dictionary_vector_reads_through_its_codes() {
1180        let mut column = StringColumn::new();
1181        column.push("red");
1182        column.push("green");
1183        let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
1184        let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
1185        assert_eq!(vector.form(), Form::Dictionary);
1186        assert_eq!(vector.logical_type(), &LogicalType::Varchar);
1187        assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
1188        assert_eq!(vector.len(), 4);
1189    }
1190
1191    /// The accessor a group by keys a string column through, which has to agree with `value_at` on
1192    /// every position or two rows holding one string end up in two groups.
1193    #[test]
1194    fn text_is_read_where_it_already_is_for_the_forms_that_store_it() {
1195        let mut column = StringColumn::new();
1196        column.push("red");
1197        column.push("green");
1198        column.push("");
1199        let flat = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
1200        for index in 0..flat.len() {
1201            assert_eq!(flat.text_at(index).map(str::to_string), text_of(&flat.value_at(index)));
1202        }
1203        let dictionary = Vector::dictionary(vec![1, 0, 1, 2], flat).unwrap();
1204        for index in 0..dictionary.len() {
1205            assert_eq!(
1206                dictionary.text_at(index).map(str::to_string),
1207                text_of(&dictionary.value_at(index))
1208            );
1209        }
1210        assert_eq!(dictionary.text_at(4), None, "past the end");
1211    }
1212
1213    /// The forms and types that have no text to hand back, which a caller answers by falling back
1214    /// to `value_at`. A blob is the one that would be a correctness bug rather than a slow path,
1215    /// since its bytes are not required to be text and it is not a `VARCHAR` either way.
1216    #[test]
1217    fn text_is_refused_where_it_is_not_stored_as_itself() {
1218        let nulls =
1219            Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into()), Value::Null])
1220                .unwrap();
1221        assert_eq!(nulls.text_at(0), Some("red"));
1222        assert_eq!(nulls.text_at(1), None, "a null has no text");
1223        let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("red".into()), 3);
1224        assert_eq!(constant.text_at(0), None, "a constant is not stored per position");
1225        assert_eq!(integers(&[1, 2]).text_at(0), None, "an integer is not text");
1226        let mut bytes = StringColumn::new();
1227        bytes.push("red");
1228        let blob = Vector::flat(LogicalType::Blob, Data::Varlen(bytes)).unwrap();
1229        assert_eq!(blob.text_at(0), None, "a blob is not a varchar");
1230    }
1231
1232    /// The text of a value, for comparing `text_at` against `value_at` position by position.
1233    fn text_of(value: &Value) -> Option<String> {
1234        match value {
1235            Value::Varchar(text) => Some(text.clone()),
1236            _ => None,
1237        }
1238    }
1239
1240    #[test]
1241    fn a_dictionary_code_past_the_end_is_refused() {
1242        // The alternative is a silent read of the wrong value, which is the failure mode the
1243        // entire M3 design has to be careful about.
1244        let values = integers(&[1, 2]);
1245        assert!(Vector::dictionary(vec![0, 2], values).is_err());
1246    }
1247
1248    #[test]
1249    fn every_form_flattens_to_the_same_values_it_reads_out() {
1250        // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
1251        // miniature and long before there is an encoded kernel to point it at. A form that reads
1252        // out one way and flattens another is the exact bug that testing exists to catch.
1253        let mut column = StringColumn::new();
1254        column.push("alpha");
1255        column.push("beta");
1256        let dictionary = Vector::dictionary(
1257            vec![1, 0, 1],
1258            Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
1259        )
1260        .unwrap();
1261        let cases = [
1262            Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
1263            Vector::sequence(7, -2, 5),
1264            dictionary,
1265        ];
1266        for vector in cases {
1267            let flat = vector.flatten().unwrap();
1268            assert_eq!(flat.form(), Form::Flat);
1269            assert_eq!(flat.len(), vector.len());
1270            for index in 0..vector.len() {
1271                assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
1272            }
1273        }
1274    }
1275
1276    #[test]
1277    fn a_null_still_occupies_a_position_after_flattening() {
1278        // The reason push_value writes a zero for a null rather than skipping it. A run of data
1279        // with a hole in it puts every value after the hole in the wrong place, and the validity
1280        // mask is what says the position is null.
1281        let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
1282        let flat = vector.flatten().unwrap();
1283        assert_eq!(flat.value_at(0), Value::BigInt(0));
1284        assert_eq!(flat.value_at(1), Value::Null);
1285        assert_eq!(flat.value_at(2), Value::BigInt(2));
1286        assert_eq!(flat.value_at(3), Value::BigInt(3));
1287    }
1288
1289    /// A dictionary holds its nulls in the vector it points at, so its own validity is all valid
1290    /// and reading that instead of the values turns a null into whatever zero means for the type.
1291    /// A filter over a nullable column produces exactly this vector, so the bug reaches a result
1292    /// set as `LEFT JOIN` padding that comes back as zeros.
1293    #[test]
1294    fn a_null_behind_a_dictionary_survives_flattening() {
1295        let values =
1296            Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
1297        let dictionary = Vector::dictionary(vec![1, 0, 1], values).unwrap();
1298        let flat = dictionary.flatten().unwrap();
1299        assert_eq!(flat.value_at(0), Value::Null);
1300        assert_eq!(flat.value_at(1), Value::Integer(3));
1301        assert_eq!(flat.value_at(2), Value::Null);
1302    }
1303
1304    /// The property that makes `gather` usable at all: it has to be the same function as reading the
1305    /// wanted positions one at a time, over every form, or compaction changes answers.
1306    #[test]
1307    fn gathering_reads_what_reading_one_position_at_a_time_reads() {
1308        let mut column = StringColumn::new();
1309        column.push("alpha");
1310        column.push("beta");
1311        column.push("gamma");
1312        let cases = [
1313            integers(&[10, 20, 30, 40]),
1314            integers(&[10, 20, 30, 40]).with_validity(Validity::from_iter(4, |i| i != 2)),
1315            Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
1316            Vector::sequence(100, -7, 4),
1317            Vector::sequence(100, -7, 4).with_validity(Validity::from_iter(4, |i| i % 2 == 0)),
1318            Vector::dictionary(
1319                vec![2, 0, 1, 2],
1320                Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
1321            )
1322            .unwrap(),
1323            Vector::dictionary(
1324                vec![1, 0, 1, 0],
1325                Vector::from_values(LogicalType::Integer, &[Value::Integer(5), Value::Null])
1326                    .unwrap(),
1327            )
1328            .unwrap(),
1329        ];
1330        let wanted = [3_u32, 0, 2, 2, 1];
1331        for vector in cases {
1332            let gathered = vector.gather(&wanted).unwrap();
1333            assert_eq!(gathered.len(), wanted.len());
1334            assert_eq!(gathered.logical_type(), vector.logical_type());
1335            for (slot, &index) in wanted.iter().enumerate() {
1336                assert_eq!(
1337                    gathered.value_at(slot),
1338                    vector.value_at(index as usize),
1339                    "slot {slot} of {:?}",
1340                    vector.form()
1341                );
1342            }
1343        }
1344    }
1345
1346    /// A gather past the end is not an error, because the selection that produced the indices is
1347    /// checked by its caller and the one thing that must not happen here is a read of the wrong
1348    /// value. An index nothing answers is null, which is what an outer join pad needs anyway.
1349    #[test]
1350    fn gathering_a_position_that_is_not_there_is_a_null_and_not_a_wrong_value() {
1351        let vector = integers(&[1, 2, 3]);
1352        let gathered = vector.gather(&[2, 9]).unwrap();
1353        assert_eq!(gathered.value_at(0), Value::Integer(3));
1354        assert_eq!(gathered.value_at(1), Value::Null);
1355    }
1356
1357    /// The vector with nothing in it at all, which is what an untyped `NULL` is stored as. Every
1358    /// position asked for is past its end, so the answer is nulls and the length has to be the
1359    /// length that was asked for rather than the length that was there.
1360    #[test]
1361    fn gathering_from_a_vector_of_no_values_is_that_many_nulls() {
1362        let vector = Vector::flat(LogicalType::Null, Data::Empty).unwrap();
1363        let gathered = vector.gather(&[0, 1, 2]).unwrap();
1364        assert_eq!(gathered.len(), 3);
1365        assert_eq!(gathered.value_at(0), Value::Null);
1366        assert_eq!(gathered.value_at(2), Value::Null);
1367    }
1368
1369    /// Every position holds the same value, so a gather with no hole in it has nothing to copy and
1370    /// the result is the constant again rather than a run of a thousand copies of it.
1371    #[test]
1372    fn gathering_a_constant_stays_a_constant() {
1373        let vector = Vector::constant(LogicalType::Integer, Value::Integer(4), 100);
1374        let gathered = vector.gather(&[7, 7, 99]).unwrap();
1375        assert_eq!(gathered.form(), Form::Constant);
1376        assert_eq!(gathered.len(), 3);
1377        assert_eq!(gathered.value_at(2), Value::Integer(4));
1378    }
1379
1380    /// A dictionary over a dictionary is what a second filter over an already filtered chunk builds,
1381    /// and the gather has to walk to the bottom of that chain rather than one step down it. The
1382    /// constructor composes the ordinary chain away, so the one built here is the kind it cannot,
1383    /// which is a level holding nulls of its own.
1384    #[test]
1385    fn gathering_walks_a_dictionary_over_a_dictionary_to_the_values() {
1386        let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9]))
1387            .unwrap()
1388            .with_validity(Validity::from_iter(3, |index| index != 2));
1389        let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
1390        let gathered = outer.gather(&[0, 1]).unwrap();
1391        assert_eq!(gathered.form(), Form::Flat);
1392        assert_eq!(gathered.value_at(0), Value::Integer(8));
1393        assert_eq!(gathered.value_at(1), Value::Null);
1394    }
1395
1396    /// Two filters over one chunk build a dictionary over a dictionary, four conjuncts pushed down
1397    /// separately build four levels of it, and every level is a dependent load on every later read
1398    /// of every row plus a code array that cannot be freed. Composing at construction is one pass
1399    /// over the codes the range check was walking anyway.
1400    #[test]
1401    fn a_dictionary_over_a_dictionary_is_composed_into_one_level() {
1402        let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9])).unwrap();
1403        let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
1404        let (codes, values) = outer.dictionary_parts().unwrap();
1405        assert_eq!(codes, [1, 0]);
1406        assert_eq!(values.form(), Form::Flat);
1407        assert_eq!(outer.value_at(0), Value::Integer(8));
1408        assert_eq!(outer.value_at(1), Value::Integer(7));
1409    }
1410
1411    /// The invariant stated as the thing it is there for, which is that the depth does not grow with
1412    /// the number of filters. Four levels stacked one at a time are one level at the end of it.
1413    #[test]
1414    fn stacking_dictionaries_does_not_make_them_deeper() {
1415        let mut vector = integers(&[10, 20, 30, 40]);
1416        for _ in 0..4 {
1417            vector = Vector::dictionary(vec![3, 2, 1, 0], vector).unwrap();
1418        }
1419        let (codes, values) = vector.dictionary_parts().unwrap();
1420        assert_eq!(values.form(), Form::Flat);
1421        assert_eq!(codes, [0, 1, 2, 3]);
1422        assert_eq!(
1423            vector.iter().collect::<Vec<_>>(),
1424            integers(&[10, 20, 30, 40]).iter().collect::<Vec<_>>()
1425        );
1426    }
1427
1428    /// Composing has to carry the nulls down with it. The values hold them, the codes point at them,
1429    /// and a composed code that lands on a null position is still a null.
1430    #[test]
1431    fn composing_a_dictionary_keeps_the_nulls_its_values_hold() {
1432        let values =
1433            Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
1434        let inner = Vector::dictionary(vec![1, 0, 1], values).unwrap();
1435        let outer = Vector::dictionary(vec![0, 1], inner).unwrap();
1436        assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Flat);
1437        assert_eq!(outer.value_at(0), Value::Null);
1438        assert_eq!(outer.value_at(1), Value::Integer(3));
1439    }
1440
1441    /// The one level composition cannot go past. A dictionary that was given a validity of its own is
1442    /// saying its nulls are at that level rather than in the values, and pointing the outer codes
1443    /// straight at the values would read through the holes instead of stopping at them.
1444    #[test]
1445    fn a_dictionary_holding_its_own_nulls_is_not_composed_past() {
1446        let inner = Vector::dictionary(vec![0, 1, 2], integers(&[1, 2, 3]))
1447            .unwrap()
1448            .with_validity(Validity::from_iter(3, |index| index != 1));
1449        let outer = Vector::dictionary(vec![1, 2, 0], inner).unwrap();
1450        assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Dictionary);
1451        assert_eq!(outer.value_at(0), Value::Null);
1452        assert_eq!(outer.value_at(1), Value::Integer(3));
1453        assert_eq!(outer.value_at(2), Value::Integer(1));
1454    }
1455
1456    #[test]
1457    fn flattening_a_flat_vector_is_the_same_vector() {
1458        let vector = integers(&[1, 2, 3]);
1459        assert_eq!(vector.flatten().unwrap(), vector);
1460    }
1461
1462    #[test]
1463    fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
1464        let ty = LogicalType::decimal(9, 2).unwrap();
1465        let vector = Vector::flat(ty, Data::Int32(vec![1234].into())).unwrap();
1466        assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
1467        assert_eq!(vector.value_at(0).to_string(), "12.34");
1468    }
1469
1470    #[test]
1471    fn a_decimal_writes_into_whichever_of_the_four_runs_its_precision_chose() {
1472        // The read path worked at every width and the write path only accepted the 128 bit run, so
1473        // `SELECT 2.5` produced a value nothing could store. All four widths round trip now.
1474        for (width, scale, unscaled) in
1475            [(4u8, 1u8, 25i128), (9, 2, 1234), (18, 3, 123_456), (38, 4, 1_234_567)]
1476        {
1477            let ty = LogicalType::decimal(width, scale).unwrap();
1478            let value = Value::Decimal { unscaled, width, scale };
1479            let vector = Vector::from_values(ty, &[value.clone(), Value::Null]).unwrap();
1480            assert_eq!(vector.value_at(0), value, "a decimal of width {width}");
1481            assert_eq!(vector.value_at(1), Value::Null, "a null decimal of width {width}");
1482        }
1483    }
1484
1485    /// The bytes a blob holds are not required to be text, and a vector of them used to refuse the
1486    /// ones that were not. A byte array column in a Parquet file that nothing annotated is a blob,
1487    /// which is what ClickHouse writes and what ten of the ClickBench queries compare against, so
1488    /// this is the path those take rather than a corner of the type system.
1489    #[test]
1490    fn a_blob_holds_bytes_that_are_not_text() {
1491        let bytes = |raw: &[u8]| Value::Blob(raw.to_vec());
1492        let values = [
1493            bytes(b"a\xffb"),
1494            bytes(b"\x00\x01\x02"),
1495            Value::Null,
1496            bytes(b"\xed\xa0\x80 and long enough to leave the view"),
1497            bytes(b""),
1498        ];
1499        let vector = Vector::from_values(LogicalType::Blob, &values).unwrap();
1500        for (index, value) in values.iter().enumerate() {
1501            assert_eq!(&vector.value_at(index), value, "row {index}");
1502        }
1503    }
1504
1505    #[test]
1506    fn a_decimal_too_wide_for_the_run_its_type_chose_is_an_error_and_not_a_wrong_number() {
1507        // Only reachable by hand, since a value's width is what picked the run. Truncating here
1508        // would store a different number and say nothing about it.
1509        let ty = LogicalType::decimal(4, 1).unwrap();
1510        let value = Value::Decimal { unscaled: 1_000_000, width: 4, scale: 1 };
1511        let error = Vector::from_values(ty, &[value]).unwrap_err();
1512        assert!(error.to_string().contains("does not fit"), "{error}");
1513    }
1514
1515    #[test]
1516    fn a_flat_vector_costs_its_values_and_a_constant_costs_one() {
1517        let flat = integers(&[1; 1000]);
1518        assert!(
1519            flat.footprint() >= 4000,
1520            "a thousand i32 are four thousand bytes: {}",
1521            flat.footprint()
1522        );
1523        // The forms that compute their values rather than storing them cost nothing per value,
1524        // which is the point of having them and is what the memory limit should see.
1525        let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1_000_000);
1526        assert!(constant.footprint() < 200, "a constant is one value: {}", constant.footprint());
1527        let sequence = Vector::sequence(0, 1, 1_000_000);
1528        assert!(sequence.footprint() < 200, "a sequence is two numbers: {}", sequence.footprint());
1529    }
1530
1531    #[test]
1532    fn a_string_vector_costs_the_bytes_of_its_long_strings() {
1533        let short =
1534            Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into())]).unwrap();
1535        let long = "a string well past the sixteen bytes a view holds inline".to_string();
1536        let spilled =
1537            Vector::from_values(LogicalType::Varchar, &[Value::Varchar(long.clone())]).unwrap();
1538        assert!(
1539            spilled.footprint() >= short.footprint() + long.len(),
1540            "the arena is counted: {} against {}",
1541            spilled.footprint(),
1542            short.footprint()
1543        );
1544    }
1545}