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 rudb_common::{Error, LogicalType, Result, Value};
19
20use crate::string::StringColumn;
21use crate::validity::Validity;
22
23/// How many values are in a full vector.
24///
25/// 1024 rather than DuckDB's 2048, per `spec/04-architecture.md` section 4.3. It is the FastLanes
26/// unit, it makes a validity mask exactly 16 `u64` words, and it keeps a vector of 16 byte string
27/// views at 16 KiB, which is the size at which several of these fit in L1 together rather than
28/// evicting each other.
29pub const VECTOR_SIZE: usize = 1024;
30
31/// Which physical form a vector is in.
32///
33/// An operator asks this once per vector and then takes the path it wants, which is the one branch
34/// per vector that the whole design is willing to spend.
35///
36/// Not exhaustive, and that is a decision rather than an oversight. `Encoded` is the fifth form
37/// and it arrives at layer three with the specialization contract. If this enum were exhaustive,
38/// the day it lands is the day every kernel in the workspace stops compiling, and the pressure at
39/// that moment would be to add an arm to each of them in a hurry rather than to think about what
40/// each one should do with an encoded vector. A required fallback arm means each kernel already
41/// has a correct answer for a form it has never seen, and specializing it is then a change that
42/// can be made one kernel at a time with a benchmark next to it.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44#[non_exhaustive]
45pub enum Form {
46    /// One value per position.
47    Flat,
48    /// One value, repeated.
49    Constant,
50    /// A start and a step, computed rather than stored.
51    Sequence,
52    /// Codes into a smaller vector of distinct values.
53    Dictionary,
54}
55
56/// The values of a flat vector, one Rust vector per physical type.
57///
58/// The variants are physical rather than logical, which is what lets `DATE` and `INTEGER` share
59/// storage and share a kernel. What a run of `i32` means is the vector's logical type's business.
60#[derive(Debug, Clone, PartialEq)]
61#[non_exhaustive]
62pub enum Data {
63    /// No values, for the type of an untyped `NULL`.
64    Empty,
65    /// One byte per value.
66    Bool(Vec<bool>),
67    /// 8 bit signed.
68    Int8(Vec<i8>),
69    /// 16 bit signed.
70    Int16(Vec<i16>),
71    /// 32 bit signed.
72    Int32(Vec<i32>),
73    /// 64 bit signed.
74    Int64(Vec<i64>),
75    /// 128 bit signed.
76    Int128(Vec<i128>),
77    /// 8 bit unsigned.
78    UInt8(Vec<u8>),
79    /// 16 bit unsigned.
80    UInt16(Vec<u16>),
81    /// 32 bit unsigned.
82    UInt32(Vec<u32>),
83    /// 64 bit unsigned.
84    UInt64(Vec<u64>),
85    /// 128 bit unsigned.
86    UInt128(Vec<u128>),
87    /// IEEE 754 binary32.
88    Float32(Vec<f32>),
89    /// IEEE 754 binary64.
90    Float64(Vec<f64>),
91    /// The months, days and microseconds triple.
92    Interval(Vec<(i32, i32, i64)>),
93    /// Strings, as 16 byte views plus the blocks the long ones live in.
94    Varlen(StringColumn),
95}
96
97impl Data {
98    /// How many values are stored.
99    #[must_use]
100    pub fn len(&self) -> usize {
101        match self {
102            Self::Empty => 0,
103            Self::Bool(v) => v.len(),
104            Self::Int8(v) => v.len(),
105            Self::Int16(v) => v.len(),
106            Self::Int32(v) => v.len(),
107            Self::Int64(v) => v.len(),
108            Self::Int128(v) => v.len(),
109            Self::UInt8(v) => v.len(),
110            Self::UInt16(v) => v.len(),
111            Self::UInt32(v) => v.len(),
112            Self::UInt64(v) => v.len(),
113            Self::UInt128(v) => v.len(),
114            Self::Float32(v) => v.len(),
115            Self::Float64(v) => v.len(),
116            Self::Interval(v) => v.len(),
117            Self::Varlen(v) => v.len(),
118        }
119    }
120
121    /// Whether there are no values.
122    #[must_use]
123    pub fn is_empty(&self) -> bool {
124        self.len() == 0
125    }
126
127    /// An integer at `index`, widened, for any of the signed integer layouts.
128    ///
129    /// Used by the decimal path, which needs the unscaled value out of whichever width the width
130    /// and scale picked, and by anything else that would otherwise repeat the same five arms.
131    #[must_use]
132    pub fn signed_at(&self, index: usize) -> Option<i128> {
133        match self {
134            Self::Int8(v) => v.get(index).map(|&x| i128::from(x)),
135            Self::Int16(v) => v.get(index).map(|&x| i128::from(x)),
136            Self::Int32(v) => v.get(index).map(|&x| i128::from(x)),
137            Self::Int64(v) => v.get(index).map(|&x| i128::from(x)),
138            Self::Int128(v) => v.get(index).copied(),
139            _ => None,
140        }
141    }
142
143    /// An unsigned integer at `index`, widened.
144    #[must_use]
145    pub fn unsigned_at(&self, index: usize) -> Option<u128> {
146        match self {
147            Self::UInt8(v) => v.get(index).map(|&x| u128::from(x)),
148            Self::UInt16(v) => v.get(index).map(|&x| u128::from(x)),
149            Self::UInt32(v) => v.get(index).map(|&x| u128::from(x)),
150            Self::UInt64(v) => v.get(index).map(|&x| u128::from(x)),
151            Self::UInt128(v) => v.get(index).copied(),
152            _ => None,
153        }
154    }
155
156    /// The string at `index`, for a `Varlen`.
157    #[must_use]
158    pub fn str_at(&self, index: usize) -> Option<&str> {
159        match self {
160            Self::Varlen(column) => column.get(index),
161            _ => None,
162        }
163    }
164}
165
166/// A type, a length, a validity representation and some data.
167#[derive(Debug, Clone, PartialEq)]
168pub struct Vector {
169    ty: LogicalType,
170    len: usize,
171    validity: Validity,
172    body: Body,
173}
174
175/// What the vector holds, which is what its form is decided by.
176#[derive(Debug, Clone, PartialEq)]
177enum Body {
178    Flat(Data),
179    Constant(Box<Value>),
180    Sequence { start: i64, step: i64 },
181    Dictionary { codes: Vec<u32>, values: Box<Vector> },
182}
183
184impl Vector {
185    /// A flat vector of `data`, all valid.
186    ///
187    /// # Errors
188    ///
189    /// If the data's physical layout is not the one the type calls for. That check is here rather
190    /// than left to the caller because a vector whose type and layout disagree is a wrong answer
191    /// waiting to be read out, and it costs one comparison at construction to prevent.
192    pub fn flat(ty: LogicalType, data: Data) -> Result<Self> {
193        let len = data.len();
194        if !matches!(data, Data::Empty) && layout_of(&data) != ty.physical() {
195            return Err(Error::internal(format!(
196                "a {ty} vector cannot hold {:?} data",
197                layout_of(&data)
198            )));
199        }
200        Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Flat(data) })
201    }
202
203    /// A flat vector built from single values, with the nulls among them turning into validity.
204    ///
205    /// The slow way in, and the only way in that anything outside this crate has. It is what an
206    /// `INSERT`, a `VALUES` clause and a test build a column with, all of which arrive holding
207    /// values rather than a run of `i32`. Nothing on a scan path calls it: a scan produces a run of
208    /// data directly and hands it to [`Self::flat`].
209    ///
210    /// # Errors
211    ///
212    /// If a value is not one the type can hold, or if the type is one that cannot be stored flat
213    /// yet, which today means the nested types.
214    pub fn from_values(ty: LogicalType, values: &[Value]) -> Result<Self> {
215        let mut data = empty_data_for(&ty)?;
216        for value in values {
217            push_value(&mut data, value)?;
218        }
219        let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
220        Ok(Self { ty, len: values.len(), validity, body: Body::Flat(data) })
221    }
222
223    /// A vector of `len` copies of one value.
224    ///
225    /// Costs one value regardless of the length, which is what makes a literal in a predicate free
226    /// and what makes a projection of a constant free.
227    #[must_use]
228    pub fn constant(ty: LogicalType, value: Value, len: usize) -> Self {
229        let validity = if value.is_null() { Validity::AllInvalid } else { Validity::AllValid };
230        Self { ty, len, validity, body: Body::Constant(Box::new(value)) }
231    }
232
233    /// A vector of `len` values starting at `start` and stepping by `step`.
234    ///
235    /// This is what a row identifier column is, and it costs sixteen bytes rather than eight
236    /// kilobytes. A scan that produces row ids for a later fetch produces one of these.
237    #[must_use]
238    pub fn sequence(start: i64, step: i64, len: usize) -> Self {
239        Self {
240            ty: LogicalType::BigInt,
241            len,
242            validity: Validity::AllValid,
243            body: Body::Sequence { start, step },
244        }
245    }
246
247    /// A vector of codes into a smaller vector of distinct values.
248    ///
249    /// The form the whole M3 thesis rests on. A dictionary vector handed to a group by is an
250    /// integer column, and an aggregate over one is an aggregate over integers no matter what the
251    /// logical type says.
252    ///
253    /// # Errors
254    ///
255    /// If any code is past the end of the value vector.
256    pub fn dictionary(codes: Vec<u32>, values: Vector) -> Result<Self> {
257        if let Some(&bad) = codes.iter().find(|&&code| code as usize >= values.len()) {
258            return Err(Error::internal(format!(
259                "dictionary code {bad} is past the end of a {} value dictionary",
260                values.len()
261            )));
262        }
263        Ok(Self {
264            ty: values.ty.clone(),
265            len: codes.len(),
266            validity: Validity::AllValid,
267            body: Body::Dictionary { codes, values: Box::new(values) },
268        })
269    }
270
271    /// The same vector with a different validity.
272    #[must_use]
273    pub fn with_validity(mut self, validity: Validity) -> Self {
274        self.validity = validity;
275        self
276    }
277
278    /// What kind of values these are.
279    #[must_use]
280    pub fn logical_type(&self) -> &LogicalType {
281        &self.ty
282    }
283
284    /// How many values there are.
285    #[must_use]
286    pub fn len(&self) -> usize {
287        self.len
288    }
289
290    /// Whether there are no values.
291    #[must_use]
292    pub fn is_empty(&self) -> bool {
293        self.len == 0
294    }
295
296    /// Which of the values are not null.
297    #[must_use]
298    pub fn validity(&self) -> &Validity {
299        &self.validity
300    }
301
302    /// Which physical form this vector is in.
303    #[must_use]
304    pub fn form(&self) -> Form {
305        match self.body {
306            Body::Flat(_) => Form::Flat,
307            Body::Constant(_) => Form::Constant,
308            Body::Sequence { .. } => Form::Sequence,
309            Body::Dictionary { .. } => Form::Dictionary,
310        }
311    }
312
313    /// The data, for a flat vector, and `None` for any other form.
314    ///
315    /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
316    /// that can do better on a constant or a dictionary checks [`Self::form`] first.
317    #[must_use]
318    pub fn data(&self) -> Option<&Data> {
319        match &self.body {
320            Body::Flat(data) => Some(data),
321            _ => None,
322        }
323    }
324
325    /// The one value, for a constant vector, and `None` for any other form.
326    ///
327    /// A kernel comparing a column against a literal wants the literal once rather than 1024
328    /// times, and [`Self::value_at`] on a constant clones it on every call because it has to be
329    /// able to hand back a `Value` for any form. This is the accessor that lets the specialized
330    /// path hoist the clone out of the loop.
331    #[must_use]
332    pub fn constant_value(&self) -> Option<&Value> {
333        match &self.body {
334            Body::Constant(value) => Some(value.as_ref()),
335            _ => None,
336        }
337    }
338
339    /// The codes and the values, for a dictionary vector, and `None` for any other form.
340    ///
341    /// The reason a kernel needs this rather than reading the dictionary through
342    /// [`Self::value_at`] is the entire argument for the form existing. A filter against a
343    /// dictionary column of 1024 rows and 40 distinct values is 40 comparisons and 1024 lookups,
344    /// not 1024 comparisons, and there is no way to write that loop without seeing the codes.
345    ///
346    /// Note what the validity of the returned vector means. A dictionary keeps its nulls in the
347    /// vector it points at, and the dictionary's own validity says nothing about them, so a caller
348    /// deciding whether row `i` is null has to ask the value vector about `codes[i]` rather than
349    /// asking this vector about `i`. [`Self::flatten`] has the same note on it for the same
350    /// reason, because getting this wrong is a null that survives being selected and comes out as
351    /// a zero.
352    #[must_use]
353    pub fn dictionary_parts(&self) -> Option<(&[u32], &Self)> {
354        match &self.body {
355            Body::Dictionary { codes, values } => Some((codes, values.as_ref())),
356            _ => None,
357        }
358    }
359
360    /// The start and the step, for a sequence vector, and `None` for any other form.
361    #[must_use]
362    pub fn sequence_parts(&self) -> Option<(i64, i64)> {
363        match self.body {
364            Body::Sequence { start, step } => Some((start, step)),
365            _ => None,
366        }
367    }
368
369    /// The value at `index`, as a single value.
370    ///
371    /// This is the slow path on purpose. It is what a result set is read out with and what a test
372    /// asserts on, and an operator that calls it per row is an operator that has already lost the
373    /// argument the vector interface exists to win.
374    #[must_use]
375    pub fn value_at(&self, index: usize) -> Value {
376        if index >= self.len || !self.validity.is_valid(index) {
377            return Value::Null;
378        }
379        match &self.body {
380            Body::Constant(value) => value.as_ref().clone(),
381            Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
382            Body::Dictionary { codes, values } => match codes.get(index) {
383                Some(&code) => values.value_at(code as usize),
384                None => Value::Null,
385            },
386            Body::Flat(data) => value_from(&self.ty, data, index),
387        }
388    }
389
390    /// Every value in order, as single values.
391    pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
392        (0..self.len).map(|index| self.value_at(index))
393    }
394
395    /// The same values in flat form.
396    ///
397    /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
398    /// which is exactly why the other forms exist and why nothing on the hot path should call
399    /// this. It is here for the operators that genuinely cannot do better and for the tests that
400    /// check the other forms against it.
401    ///
402    /// # Errors
403    ///
404    /// If the type is one this crate cannot store flat yet, which today means the nested types.
405    pub fn flatten(&self) -> Result<Self> {
406        if let Body::Flat(_) = self.body {
407            return Ok(self.clone());
408        }
409        self.copied((0..self.len).collect(), false)
410    }
411
412    /// The values at the given positions, copied, in a form that does not point back at this vector.
413    ///
414    /// This is the copying counterpart to [`Self::dictionary`], and the two are the two halves of
415    /// the decision `spec/07-execution.md` section 7.1 describes. Which half is right is measured
416    /// rather than argued, and [`Chunk::compact`](crate::Chunk::compact) is where the measurement
417    /// is written down.
418    ///
419    /// A dictionary chain is walked to its leaf first and the codes composed on the way down, so the
420    /// copy runs once over the data rather than once per level, and a position that is null at any
421    /// level comes out null here. The copy is a typed loop per physical layout rather than a `Value`
422    /// per row, which is the whole point of it and is what [`Self::flatten`] now goes through too.
423    ///
424    /// # Errors
425    ///
426    /// If the type has no flat layout, which today means the nested types.
427    pub fn gather(&self, indices: &[u32]) -> Result<Self> {
428        self.copied(indices.iter().map(|&index| index as usize).collect(), true)
429    }
430
431    /// The copy both [`Self::gather`] and [`Self::flatten`] are.
432    ///
433    /// `constants_stay` is the one thing the two want differently. A gather of a constant is a
434    /// shorter constant and copying it out would be a thousand writes of the same value for nothing,
435    /// but flattening promises flat form to a caller that is about to read the data slice, so for
436    /// that one the constant has to be written out.
437    fn copied(&self, at: Vec<usize>, constants_stay: bool) -> Result<Self> {
438        let rows = at.len();
439        let (at, leaf) = self.resolve(at);
440        let live: Vec<bool> = at.iter().map(|&index| index != NOWHERE).collect();
441        let validity = Validity::from_run(&live);
442        let body = match &leaf.body {
443            // Every position holds the same value, so the only thing the gather can change is the
444            // length and which positions are null. A gather with no null in it is still a constant.
445            Body::Constant(value) => {
446                if constants_stay && matches!(validity, Validity::AllValid) {
447                    return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
448                }
449                let mut data = empty_data_for(&self.ty)?;
450                for &index in &at {
451                    push_value(&mut data, if index == NOWHERE { &Value::Null } else { value })?;
452                }
453                Body::Flat(data)
454            }
455            // A sequence is arithmetic rather than storage, so the gather is the arithmetic done at
456            // the positions asked for, and a null writes the zero every other layout writes.
457            Body::Sequence { start, step } => Body::Flat(Data::Int64(
458                at.iter()
459                    .map(|&index| if index == NOWHERE { 0 } else { start + step * index as i64 })
460                    .collect(),
461            )),
462            // A flat body with no values is the untyped null, so every position asked for is null
463            // whatever was asked for. Going through the copy would build a run of no values and
464            // call it `rows` long, which is a vector whose length and data disagree.
465            Body::Flat(Data::Empty) => {
466                return Ok(Self::constant(self.ty.clone(), Value::Null, rows));
467            }
468            Body::Flat(data) => Body::Flat(copy_of(data, &at)),
469            // Unreachable, because `resolve` stops at the first body that is not a dictionary.
470            Body::Dictionary { .. } => {
471                return Err(Error::internal("a dictionary survived being resolved"));
472            }
473        };
474        Ok(Self { ty: self.ty.clone(), len: rows, validity, body })
475    }
476
477    /// Where each wanted position lives in the first body that is not a dictionary, and that body.
478    ///
479    /// A position that is null anywhere on the way down, or past the end of anything on the way
480    /// down, comes back as [`NOWHERE`]. That single sentinel is what keeps the copy loop from
481    /// carrying a validity mask alongside the positions it is already walking.
482    fn resolve(&self, mut at: Vec<usize>) -> (Vec<usize>, &Self) {
483        let mut source = self;
484        loop {
485            for slot in &mut at {
486                if *slot >= source.len || !source.validity.is_valid(*slot) {
487                    *slot = NOWHERE;
488                }
489            }
490            let Body::Dictionary { codes, values } = &source.body else {
491                return (at, source);
492            };
493            for slot in &mut at {
494                *slot = match codes.get(*slot) {
495                    Some(&code) => code as usize,
496                    None => NOWHERE,
497                };
498            }
499            source = values.as_ref();
500        }
501    }
502}
503
504/// The position of a value that is not anywhere, because it is null or out of range.
505///
506/// `usize::MAX` rather than an `Option<usize>`, because the copy loop's bounds check rejects it for
507/// free and an `Option` would put a second branch next to the one already there.
508const NOWHERE: usize = usize::MAX;
509
510/// A run of data copied at the given positions, with a zero wherever the position is [`NOWHERE`].
511///
512/// A zero and not a skip, because every layout here is a parallel array to a validity mask and a
513/// short one would put every value after the first null at the wrong index. It is the same rule
514/// [`push_value`] follows for a null.
515fn copy_of(data: &Data, at: &[usize]) -> Data {
516    macro_rules! copied {
517        ($values:expr, $variant:path, $zero:expr) => {{
518            let values = $values;
519            let mut out = Vec::with_capacity(at.len());
520            for &index in at {
521                // One bounds check rather than a null test and a bounds check, because `NOWHERE` is
522                // past the end of every slice there can be.
523                out.push(values.get(index).copied().unwrap_or($zero));
524            }
525            $variant(out)
526        }};
527    }
528    match data {
529        Data::Empty => Data::Empty,
530        Data::Bool(values) => copied!(values, Data::Bool, false),
531        Data::Int8(values) => copied!(values, Data::Int8, 0),
532        Data::Int16(values) => copied!(values, Data::Int16, 0),
533        Data::Int32(values) => copied!(values, Data::Int32, 0),
534        Data::Int64(values) => copied!(values, Data::Int64, 0),
535        Data::Int128(values) => copied!(values, Data::Int128, 0),
536        Data::UInt8(values) => copied!(values, Data::UInt8, 0),
537        Data::UInt16(values) => copied!(values, Data::UInt16, 0),
538        Data::UInt32(values) => copied!(values, Data::UInt32, 0),
539        Data::UInt64(values) => copied!(values, Data::UInt64, 0),
540        Data::UInt128(values) => copied!(values, Data::UInt128, 0),
541        Data::Float32(values) => copied!(values, Data::Float32, 0.0),
542        Data::Float64(values) => copied!(values, Data::Float64, 0.0),
543        Data::Interval(values) => copied!(values, Data::Interval, (0, 0, 0)),
544        // The one layout where a gather is a copy of bytes rather than a copy of fixed width slots,
545        // and the reason compaction is a decision rather than a default on a string column.
546        Data::Varlen(values) => {
547            let mut out = StringColumn::with_capacity(at.len());
548            for &index in at {
549                out.push(values.get(index).unwrap_or(""));
550            }
551            Data::Varlen(out)
552        }
553    }
554}
555
556/// The physical layout a run of data is in, for the check that it matches its type.
557fn layout_of(data: &Data) -> rudb_common::PhysicalType {
558    use rudb_common::PhysicalType as P;
559    match data {
560        Data::Empty => P::Empty,
561        Data::Bool(_) => P::Bool,
562        Data::Int8(_) => P::Int8,
563        Data::Int16(_) => P::Int16,
564        Data::Int32(_) => P::Int32,
565        Data::Int64(_) => P::Int64,
566        Data::Int128(_) => P::Int128,
567        Data::UInt8(_) => P::UInt8,
568        Data::UInt16(_) => P::UInt16,
569        Data::UInt32(_) => P::UInt32,
570        Data::UInt64(_) => P::UInt64,
571        Data::UInt128(_) => P::UInt128,
572        Data::Float32(_) => P::Float32,
573        Data::Float64(_) => P::Float64,
574        Data::Interval(_) => P::Interval,
575        Data::Varlen(_) => P::Varlen,
576    }
577}
578
579/// One value out of a run of data, given what the run means.
580///
581/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
582/// from an `INTEGER` and that is the whole reason the two are kept apart.
583fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
584    let signed = || data.signed_at(index);
585    let unsigned = || data.unsigned_at(index);
586    let value = match ty {
587        LogicalType::Boolean => match data {
588            Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
589            _ => None,
590        },
591        LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
592        LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
593        LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
594        LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
595        LogicalType::HugeInt => signed().map(Value::HugeInt),
596        LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
597        LogicalType::USmallInt => {
598            unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
599        }
600        LogicalType::UInteger => {
601            unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
602        }
603        LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
604        LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
605        LogicalType::Float => match data {
606            Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
607            _ => None,
608        },
609        LogicalType::Double => match data {
610            Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
611            _ => None,
612        },
613        LogicalType::Decimal { width, scale } => {
614            signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
615        }
616        LogicalType::Varchar => data.str_at(index).map(|s| Value::Varchar(s.to_string())),
617        LogicalType::Blob | LogicalType::Bit => {
618            data.str_at(index).map(|s| Value::Blob(s.as_bytes().to_vec()))
619        }
620        LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
621        LogicalType::Time | LogicalType::TimeTz => {
622            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time)
623        }
624        LogicalType::Timestamp
625        | LogicalType::TimestampS
626        | LogicalType::TimestampMs
627        | LogicalType::TimestampNs
628        | LogicalType::TimestampTz => {
629            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
630        }
631        LogicalType::Interval => match data {
632            Data::Interval(v) => {
633                v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
634            }
635            _ => None,
636        },
637        _ => None,
638    };
639    value.unwrap_or(Value::Null)
640}
641
642/// An empty run of data of the right layout for a type.
643fn empty_data_for(ty: &LogicalType) -> Result<Data> {
644    use rudb_common::PhysicalType as P;
645    Ok(match ty.physical() {
646        P::Empty => Data::Empty,
647        P::Bool => Data::Bool(Vec::new()),
648        P::Int8 => Data::Int8(Vec::new()),
649        P::Int16 => Data::Int16(Vec::new()),
650        P::Int32 => Data::Int32(Vec::new()),
651        P::Int64 => Data::Int64(Vec::new()),
652        P::Int128 => Data::Int128(Vec::new()),
653        P::UInt8 => Data::UInt8(Vec::new()),
654        P::UInt16 => Data::UInt16(Vec::new()),
655        P::UInt32 => Data::UInt32(Vec::new()),
656        P::UInt64 => Data::UInt64(Vec::new()),
657        P::UInt128 => Data::UInt128(Vec::new()),
658        P::Float32 => Data::Float32(Vec::new()),
659        P::Float64 => Data::Float64(Vec::new()),
660        P::Interval => Data::Interval(Vec::new()),
661        P::Varlen => Data::Varlen(StringColumn::new()),
662        other => {
663            return Err(Error::not_implemented(format!(
664                "a flat vector of {other:?} data, which arrives with the storage layer"
665            )));
666        }
667    })
668}
669
670/// Appends one value to a run of data, or a zero of the right shape when it is null.
671///
672/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
673/// and a run of data with a hole in it would put every value after the hole in the wrong place.
674fn push_value(data: &mut Data, value: &Value) -> Result<()> {
675    macro_rules! push {
676        ($vec:expr, $variant:path, $zero:expr) => {
677            match value {
678                Value::Null => $vec.push($zero),
679                $variant(x) => $vec.push(*x),
680                other => {
681                    return Err(Error::internal(format!(
682                        "{other:?} does not belong in this vector"
683                    )));
684                }
685            }
686        };
687    }
688    // A decimal is stored as its unscaled integer in whatever width its precision needs, which
689    // `LogicalType::physical` decides and which is why the same `Value::Decimal` is at home in four
690    // different runs. The narrowing cannot fail for a value the binder produced, because the width
691    // that chose the run is the width in the value, but it is checked rather than assumed because
692    // an unchecked cast here would silently store a different number.
693    macro_rules! decimal {
694        ($vec:expr, $ty:ty, $unscaled:expr) => {
695            match <$ty>::try_from(*$unscaled) {
696                Ok(x) => $vec.push(x),
697                Err(_) => {
698                    return Err(Error::internal(format!(
699                        "an unscaled decimal of {} does not fit the run its precision chose",
700                        $unscaled
701                    )));
702                }
703            }
704        };
705    }
706    match data {
707        Data::Empty => {}
708        Data::Bool(v) => push!(v, Value::Boolean, false),
709        Data::Int8(v) => push!(v, Value::TinyInt, 0),
710        Data::Int16(v) => match value {
711            Value::Null => v.push(0),
712            Value::SmallInt(x) => v.push(*x),
713            Value::Decimal { unscaled, .. } => decimal!(v, i16, unscaled),
714            other => return Err(Error::internal(format!("{other:?} is not a 16 bit value"))),
715        },
716        Data::Int32(v) => match value {
717            Value::Null => v.push(0),
718            Value::Integer(x) | Value::Date(x) => v.push(*x),
719            Value::Decimal { unscaled, .. } => decimal!(v, i32, unscaled),
720            other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
721        },
722        Data::Int64(v) => match value {
723            Value::Null => v.push(0),
724            Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => v.push(*x),
725            Value::Decimal { unscaled, .. } => decimal!(v, i64, unscaled),
726            other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
727        },
728        Data::Int128(v) => match value {
729            Value::Null => v.push(0),
730            Value::HugeInt(x) => v.push(*x),
731            Value::Decimal { unscaled, .. } => v.push(*unscaled),
732            other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
733        },
734        Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
735        Data::UInt16(v) => push!(v, Value::USmallInt, 0),
736        Data::UInt32(v) => push!(v, Value::UInteger, 0),
737        Data::UInt64(v) => push!(v, Value::UBigInt, 0),
738        Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
739        Data::Float32(v) => push!(v, Value::Float, 0.0),
740        Data::Float64(v) => push!(v, Value::Double, 0.0),
741        Data::Interval(v) => match value {
742            Value::Null => v.push((0, 0, 0)),
743            Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
744            other => return Err(Error::internal(format!("{other:?} is not an interval"))),
745        },
746        Data::Varlen(column) => match value {
747            Value::Null => {
748                column.push("");
749            }
750            Value::Varchar(text) => {
751                column.push(text);
752            }
753            // A blob is bytes and this column is text, so the only blobs that survive a round trip
754            // here are the ones that happen to be valid UTF-8. Real blob storage is a byte column
755            // and it arrives with the storage layer at M2 rather than being faked now.
756            Value::Blob(bytes) => match std::str::from_utf8(bytes) {
757                Ok(text) => {
758                    column.push(text);
759                }
760                Err(_) => {
761                    return Err(Error::not_implemented(
762                        "a blob that is not valid UTF-8, which needs the byte column from M2",
763                    ));
764                }
765            },
766            other => return Err(Error::internal(format!("{other:?} is not a string"))),
767        },
768    }
769    Ok(())
770}
771
772#[cfg(test)]
773mod tests {
774    use rudb_common::{LogicalType, Value};
775
776    use super::{Data, Form, VECTOR_SIZE, Vector};
777    use crate::string::StringColumn;
778    use crate::validity::Validity;
779
780    fn integers(values: &[i32]) -> Vector {
781        Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec())).unwrap()
782    }
783
784    #[test]
785    fn the_vector_size_is_the_one_the_design_is_built_around() {
786        // 1024 and not DuckDB's 2048. A validity mask is 16 u64 words and a vector of string views
787        // is 16 KiB, both of which are consequences of this number rather than coincidences.
788        assert_eq!(VECTOR_SIZE, 1024);
789        assert_eq!(VECTOR_SIZE / 64, 16);
790    }
791
792    #[test]
793    fn a_flat_vector_reads_back_what_was_put_in_it() {
794        let vector = integers(&[1, 2, 3]);
795        assert_eq!(vector.form(), Form::Flat);
796        assert_eq!(vector.len(), 3);
797        assert_eq!(vector.value_at(1), Value::Integer(2));
798        assert_eq!(
799            vector.iter().collect::<Vec<_>>(),
800            vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
801        );
802    }
803
804    #[test]
805    fn a_vector_built_from_values_reads_the_same_values_back() {
806        let vector = Vector::from_values(
807            LogicalType::Varchar,
808            &[
809                Value::Varchar("a".to_string()),
810                Value::Null,
811                Value::Varchar("a string too long to sit inside a view".to_string()),
812            ],
813        )
814        .expect("strings and a null");
815        assert_eq!(vector.len(), 3);
816        assert_eq!(vector.value_at(0), Value::Varchar("a".to_string()));
817        assert_eq!(vector.value_at(1), Value::Null);
818        assert_eq!(
819            vector.value_at(2),
820            Value::Varchar("a string too long to sit inside a view".to_string())
821        );
822    }
823
824    /// A null still occupies a position. If it did not then every value after it would read back
825    /// one place to the left, which is the kind of bug that looks like a storage bug for a week.
826    #[test]
827    fn a_null_in_the_middle_does_not_move_the_values_after_it() {
828        let vector = Vector::from_values(
829            LogicalType::Integer,
830            &[Value::Integer(1), Value::Null, Value::Integer(3)],
831        )
832        .expect("integers and a null");
833        assert_eq!(vector.value_at(2), Value::Integer(3));
834        assert!(vector.validity().has_nulls(3), "the middle one is null");
835    }
836
837    #[test]
838    fn a_value_the_type_cannot_hold_is_refused() {
839        let wrong = Vector::from_values(LogicalType::Integer, &[Value::Varchar("x".to_string())]);
840        assert!(wrong.is_err(), "a string is not an integer");
841    }
842
843    #[test]
844    fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
845        // One comparison here against a wrong answer read out three layers later.
846        let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1]));
847        assert!(wrong.is_err());
848        let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1]));
849        assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
850    }
851
852    #[test]
853    fn a_constant_vector_costs_one_value_whatever_its_length() {
854        let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
855        assert_eq!(vector.form(), Form::Constant);
856        assert_eq!(vector.len(), VECTOR_SIZE);
857        assert_eq!(vector.value_at(0), Value::Integer(7));
858        assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
859        assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
860    }
861
862    #[test]
863    fn a_constant_null_is_all_invalid_without_being_told() {
864        let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
865        assert_eq!(vector.validity(), &Validity::AllInvalid);
866        assert_eq!(vector.value_at(3), Value::Null);
867    }
868
869    #[test]
870    fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
871        let vector = Vector::sequence(100, 1, VECTOR_SIZE);
872        assert_eq!(vector.form(), Form::Sequence);
873        assert_eq!(vector.value_at(0), Value::BigInt(100));
874        assert_eq!(vector.value_at(923), Value::BigInt(1023));
875        let stepped = Vector::sequence(0, 5, 4);
876        assert_eq!(
877            stepped.iter().collect::<Vec<_>>(),
878            vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
879        );
880    }
881
882    #[test]
883    fn a_dictionary_vector_reads_through_its_codes() {
884        let mut column = StringColumn::new();
885        column.push("red");
886        column.push("green");
887        let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
888        let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
889        assert_eq!(vector.form(), Form::Dictionary);
890        assert_eq!(vector.logical_type(), &LogicalType::Varchar);
891        assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
892        assert_eq!(vector.len(), 4);
893    }
894
895    #[test]
896    fn a_dictionary_code_past_the_end_is_refused() {
897        // The alternative is a silent read of the wrong value, which is the failure mode the
898        // entire M3 design has to be careful about.
899        let values = integers(&[1, 2]);
900        assert!(Vector::dictionary(vec![0, 2], values).is_err());
901    }
902
903    #[test]
904    fn every_form_flattens_to_the_same_values_it_reads_out() {
905        // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
906        // miniature and long before there is an encoded kernel to point it at. A form that reads
907        // out one way and flattens another is the exact bug that testing exists to catch.
908        let mut column = StringColumn::new();
909        column.push("alpha");
910        column.push("beta");
911        let dictionary = Vector::dictionary(
912            vec![1, 0, 1],
913            Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
914        )
915        .unwrap();
916        let cases = [
917            Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
918            Vector::sequence(7, -2, 5),
919            dictionary,
920        ];
921        for vector in cases {
922            let flat = vector.flatten().unwrap();
923            assert_eq!(flat.form(), Form::Flat);
924            assert_eq!(flat.len(), vector.len());
925            for index in 0..vector.len() {
926                assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
927            }
928        }
929    }
930
931    #[test]
932    fn a_null_still_occupies_a_position_after_flattening() {
933        // The reason push_value writes a zero for a null rather than skipping it. A run of data
934        // with a hole in it puts every value after the hole in the wrong place, and the validity
935        // mask is what says the position is null.
936        let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
937        let flat = vector.flatten().unwrap();
938        assert_eq!(flat.value_at(0), Value::BigInt(0));
939        assert_eq!(flat.value_at(1), Value::Null);
940        assert_eq!(flat.value_at(2), Value::BigInt(2));
941        assert_eq!(flat.value_at(3), Value::BigInt(3));
942    }
943
944    /// A dictionary holds its nulls in the vector it points at, so its own validity is all valid
945    /// and reading that instead of the values turns a null into whatever zero means for the type.
946    /// A filter over a nullable column produces exactly this vector, so the bug reaches a result
947    /// set as `LEFT JOIN` padding that comes back as zeros.
948    #[test]
949    fn a_null_behind_a_dictionary_survives_flattening() {
950        let values =
951            Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
952        let dictionary = Vector::dictionary(vec![1, 0, 1], values).unwrap();
953        let flat = dictionary.flatten().unwrap();
954        assert_eq!(flat.value_at(0), Value::Null);
955        assert_eq!(flat.value_at(1), Value::Integer(3));
956        assert_eq!(flat.value_at(2), Value::Null);
957    }
958
959    /// The property that makes `gather` usable at all: it has to be the same function as reading the
960    /// wanted positions one at a time, over every form, or compaction changes answers.
961    #[test]
962    fn gathering_reads_what_reading_one_position_at_a_time_reads() {
963        let mut column = StringColumn::new();
964        column.push("alpha");
965        column.push("beta");
966        column.push("gamma");
967        let cases = [
968            integers(&[10, 20, 30, 40]),
969            integers(&[10, 20, 30, 40]).with_validity(Validity::from_iter(4, |i| i != 2)),
970            Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
971            Vector::sequence(100, -7, 4),
972            Vector::sequence(100, -7, 4).with_validity(Validity::from_iter(4, |i| i % 2 == 0)),
973            Vector::dictionary(
974                vec![2, 0, 1, 2],
975                Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
976            )
977            .unwrap(),
978            Vector::dictionary(
979                vec![1, 0, 1, 0],
980                Vector::from_values(LogicalType::Integer, &[Value::Integer(5), Value::Null])
981                    .unwrap(),
982            )
983            .unwrap(),
984        ];
985        let wanted = [3_u32, 0, 2, 2, 1];
986        for vector in cases {
987            let gathered = vector.gather(&wanted).unwrap();
988            assert_eq!(gathered.len(), wanted.len());
989            assert_eq!(gathered.logical_type(), vector.logical_type());
990            for (slot, &index) in wanted.iter().enumerate() {
991                assert_eq!(
992                    gathered.value_at(slot),
993                    vector.value_at(index as usize),
994                    "slot {slot} of {:?}",
995                    vector.form()
996                );
997            }
998        }
999    }
1000
1001    /// A gather past the end is not an error, because the selection that produced the indices is
1002    /// checked by its caller and the one thing that must not happen here is a read of the wrong
1003    /// value. An index nothing answers is null, which is what an outer join pad needs anyway.
1004    #[test]
1005    fn gathering_a_position_that_is_not_there_is_a_null_and_not_a_wrong_value() {
1006        let vector = integers(&[1, 2, 3]);
1007        let gathered = vector.gather(&[2, 9]).unwrap();
1008        assert_eq!(gathered.value_at(0), Value::Integer(3));
1009        assert_eq!(gathered.value_at(1), Value::Null);
1010    }
1011
1012    /// The vector with nothing in it at all, which is what an untyped `NULL` is stored as. Every
1013    /// position asked for is past its end, so the answer is nulls and the length has to be the
1014    /// length that was asked for rather than the length that was there.
1015    #[test]
1016    fn gathering_from_a_vector_of_no_values_is_that_many_nulls() {
1017        let vector = Vector::flat(LogicalType::Null, Data::Empty).unwrap();
1018        let gathered = vector.gather(&[0, 1, 2]).unwrap();
1019        assert_eq!(gathered.len(), 3);
1020        assert_eq!(gathered.value_at(0), Value::Null);
1021        assert_eq!(gathered.value_at(2), Value::Null);
1022    }
1023
1024    /// Every position holds the same value, so a gather with no hole in it has nothing to copy and
1025    /// the result is the constant again rather than a run of a thousand copies of it.
1026    #[test]
1027    fn gathering_a_constant_stays_a_constant() {
1028        let vector = Vector::constant(LogicalType::Integer, Value::Integer(4), 100);
1029        let gathered = vector.gather(&[7, 7, 99]).unwrap();
1030        assert_eq!(gathered.form(), Form::Constant);
1031        assert_eq!(gathered.len(), 3);
1032        assert_eq!(gathered.value_at(2), Value::Integer(4));
1033    }
1034
1035    /// A dictionary over a dictionary is what a second filter over an already filtered chunk builds,
1036    /// and the gather has to walk to the bottom of that chain rather than one step down it.
1037    #[test]
1038    fn gathering_walks_a_dictionary_over_a_dictionary_to_the_values() {
1039        let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9])).unwrap();
1040        let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
1041        let gathered = outer.gather(&[1, 0]).unwrap();
1042        assert_eq!(gathered.form(), Form::Flat);
1043        assert_eq!(gathered.value_at(0), Value::Integer(7));
1044        assert_eq!(gathered.value_at(1), Value::Integer(8));
1045    }
1046
1047    #[test]
1048    fn flattening_a_flat_vector_is_the_same_vector() {
1049        let vector = integers(&[1, 2, 3]);
1050        assert_eq!(vector.flatten().unwrap(), vector);
1051    }
1052
1053    #[test]
1054    fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
1055        let ty = LogicalType::decimal(9, 2).unwrap();
1056        let vector = Vector::flat(ty, Data::Int32(vec![1234])).unwrap();
1057        assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
1058        assert_eq!(vector.value_at(0).to_string(), "12.34");
1059    }
1060
1061    #[test]
1062    fn a_decimal_writes_into_whichever_of_the_four_runs_its_precision_chose() {
1063        // The read path worked at every width and the write path only accepted the 128 bit run, so
1064        // `SELECT 2.5` produced a value nothing could store. All four widths round trip now.
1065        for (width, scale, unscaled) in
1066            [(4u8, 1u8, 25i128), (9, 2, 1234), (18, 3, 123_456), (38, 4, 1_234_567)]
1067        {
1068            let ty = LogicalType::decimal(width, scale).unwrap();
1069            let value = Value::Decimal { unscaled, width, scale };
1070            let vector = Vector::from_values(ty, &[value.clone(), Value::Null]).unwrap();
1071            assert_eq!(vector.value_at(0), value, "a decimal of width {width}");
1072            assert_eq!(vector.value_at(1), Value::Null, "a null decimal of width {width}");
1073        }
1074    }
1075
1076    #[test]
1077    fn a_decimal_too_wide_for_the_run_its_type_chose_is_an_error_and_not_a_wrong_number() {
1078        // Only reachable by hand, since a value's width is what picked the run. Truncating here
1079        // would store a different number and say nothing about it.
1080        let ty = LogicalType::decimal(4, 1).unwrap();
1081        let value = Value::Decimal { unscaled: 1_000_000, width: 4, scale: 1 };
1082        let error = Vector::from_values(ty, &[value]).unwrap_err();
1083        assert!(error.to_string().contains("does not fit"), "{error}");
1084    }
1085}