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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum Form {
37    /// One value per position.
38    Flat,
39    /// One value, repeated.
40    Constant,
41    /// A start and a step, computed rather than stored.
42    Sequence,
43    /// Codes into a smaller vector of distinct values.
44    Dictionary,
45}
46
47/// The values of a flat vector, one Rust vector per physical type.
48///
49/// The variants are physical rather than logical, which is what lets `DATE` and `INTEGER` share
50/// storage and share a kernel. What a run of `i32` means is the vector's logical type's business.
51#[derive(Debug, Clone, PartialEq)]
52#[non_exhaustive]
53pub enum Data {
54    /// No values, for the type of an untyped `NULL`.
55    Empty,
56    /// One byte per value.
57    Bool(Vec<bool>),
58    /// 8 bit signed.
59    Int8(Vec<i8>),
60    /// 16 bit signed.
61    Int16(Vec<i16>),
62    /// 32 bit signed.
63    Int32(Vec<i32>),
64    /// 64 bit signed.
65    Int64(Vec<i64>),
66    /// 128 bit signed.
67    Int128(Vec<i128>),
68    /// 8 bit unsigned.
69    UInt8(Vec<u8>),
70    /// 16 bit unsigned.
71    UInt16(Vec<u16>),
72    /// 32 bit unsigned.
73    UInt32(Vec<u32>),
74    /// 64 bit unsigned.
75    UInt64(Vec<u64>),
76    /// 128 bit unsigned.
77    UInt128(Vec<u128>),
78    /// IEEE 754 binary32.
79    Float32(Vec<f32>),
80    /// IEEE 754 binary64.
81    Float64(Vec<f64>),
82    /// The months, days and microseconds triple.
83    Interval(Vec<(i32, i32, i64)>),
84    /// Strings, as 16 byte views plus the blocks the long ones live in.
85    Varlen(StringColumn),
86}
87
88impl Data {
89    /// How many values are stored.
90    #[must_use]
91    pub fn len(&self) -> usize {
92        match self {
93            Self::Empty => 0,
94            Self::Bool(v) => v.len(),
95            Self::Int8(v) => v.len(),
96            Self::Int16(v) => v.len(),
97            Self::Int32(v) => v.len(),
98            Self::Int64(v) => v.len(),
99            Self::Int128(v) => v.len(),
100            Self::UInt8(v) => v.len(),
101            Self::UInt16(v) => v.len(),
102            Self::UInt32(v) => v.len(),
103            Self::UInt64(v) => v.len(),
104            Self::UInt128(v) => v.len(),
105            Self::Float32(v) => v.len(),
106            Self::Float64(v) => v.len(),
107            Self::Interval(v) => v.len(),
108            Self::Varlen(v) => v.len(),
109        }
110    }
111
112    /// Whether there are no values.
113    #[must_use]
114    pub fn is_empty(&self) -> bool {
115        self.len() == 0
116    }
117
118    /// An integer at `index`, widened, for any of the signed integer layouts.
119    ///
120    /// Used by the decimal path, which needs the unscaled value out of whichever width the width
121    /// and scale picked, and by anything else that would otherwise repeat the same five arms.
122    #[must_use]
123    pub fn signed_at(&self, index: usize) -> Option<i128> {
124        match self {
125            Self::Int8(v) => v.get(index).map(|&x| i128::from(x)),
126            Self::Int16(v) => v.get(index).map(|&x| i128::from(x)),
127            Self::Int32(v) => v.get(index).map(|&x| i128::from(x)),
128            Self::Int64(v) => v.get(index).map(|&x| i128::from(x)),
129            Self::Int128(v) => v.get(index).copied(),
130            _ => None,
131        }
132    }
133
134    /// An unsigned integer at `index`, widened.
135    #[must_use]
136    pub fn unsigned_at(&self, index: usize) -> Option<u128> {
137        match self {
138            Self::UInt8(v) => v.get(index).map(|&x| u128::from(x)),
139            Self::UInt16(v) => v.get(index).map(|&x| u128::from(x)),
140            Self::UInt32(v) => v.get(index).map(|&x| u128::from(x)),
141            Self::UInt64(v) => v.get(index).map(|&x| u128::from(x)),
142            Self::UInt128(v) => v.get(index).copied(),
143            _ => None,
144        }
145    }
146
147    /// The string at `index`, for a `Varlen`.
148    #[must_use]
149    pub fn str_at(&self, index: usize) -> Option<&str> {
150        match self {
151            Self::Varlen(column) => column.get(index),
152            _ => None,
153        }
154    }
155}
156
157/// A type, a length, a validity representation and some data.
158#[derive(Debug, Clone, PartialEq)]
159pub struct Vector {
160    ty: LogicalType,
161    len: usize,
162    validity: Validity,
163    body: Body,
164}
165
166/// What the vector holds, which is what its form is decided by.
167#[derive(Debug, Clone, PartialEq)]
168enum Body {
169    Flat(Data),
170    Constant(Box<Value>),
171    Sequence { start: i64, step: i64 },
172    Dictionary { codes: Vec<u32>, values: Box<Vector> },
173}
174
175impl Vector {
176    /// A flat vector of `data`, all valid.
177    ///
178    /// # Errors
179    ///
180    /// If the data's physical layout is not the one the type calls for. That check is here rather
181    /// than left to the caller because a vector whose type and layout disagree is a wrong answer
182    /// waiting to be read out, and it costs one comparison at construction to prevent.
183    pub fn flat(ty: LogicalType, data: Data) -> Result<Self> {
184        let len = data.len();
185        if !matches!(data, Data::Empty) && layout_of(&data) != ty.physical() {
186            return Err(Error::internal(format!(
187                "a {ty} vector cannot hold {:?} data",
188                layout_of(&data)
189            )));
190        }
191        Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Flat(data) })
192    }
193
194    /// A flat vector built from single values, with the nulls among them turning into validity.
195    ///
196    /// The slow way in, and the only way in that anything outside this crate has. It is what an
197    /// `INSERT`, a `VALUES` clause and a test build a column with, all of which arrive holding
198    /// values rather than a run of `i32`. Nothing on a scan path calls it: a scan produces a run of
199    /// data directly and hands it to [`Self::flat`].
200    ///
201    /// # Errors
202    ///
203    /// If a value is not one the type can hold, or if the type is one that cannot be stored flat
204    /// yet, which today means the nested types.
205    pub fn from_values(ty: LogicalType, values: &[Value]) -> Result<Self> {
206        let mut data = empty_data_for(&ty)?;
207        for value in values {
208            push_value(&mut data, value)?;
209        }
210        let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
211        Ok(Self { ty, len: values.len(), validity, body: Body::Flat(data) })
212    }
213
214    /// A vector of `len` copies of one value.
215    ///
216    /// Costs one value regardless of the length, which is what makes a literal in a predicate free
217    /// and what makes a projection of a constant free.
218    #[must_use]
219    pub fn constant(ty: LogicalType, value: Value, len: usize) -> Self {
220        let validity = if value.is_null() { Validity::AllInvalid } else { Validity::AllValid };
221        Self { ty, len, validity, body: Body::Constant(Box::new(value)) }
222    }
223
224    /// A vector of `len` values starting at `start` and stepping by `step`.
225    ///
226    /// This is what a row identifier column is, and it costs sixteen bytes rather than eight
227    /// kilobytes. A scan that produces row ids for a later fetch produces one of these.
228    #[must_use]
229    pub fn sequence(start: i64, step: i64, len: usize) -> Self {
230        Self {
231            ty: LogicalType::BigInt,
232            len,
233            validity: Validity::AllValid,
234            body: Body::Sequence { start, step },
235        }
236    }
237
238    /// A vector of codes into a smaller vector of distinct values.
239    ///
240    /// The form the whole M3 thesis rests on. A dictionary vector handed to a group by is an
241    /// integer column, and an aggregate over one is an aggregate over integers no matter what the
242    /// logical type says.
243    ///
244    /// # Errors
245    ///
246    /// If any code is past the end of the value vector.
247    pub fn dictionary(codes: Vec<u32>, values: Vector) -> Result<Self> {
248        if let Some(&bad) = codes.iter().find(|&&code| code as usize >= values.len()) {
249            return Err(Error::internal(format!(
250                "dictionary code {bad} is past the end of a {} value dictionary",
251                values.len()
252            )));
253        }
254        Ok(Self {
255            ty: values.ty.clone(),
256            len: codes.len(),
257            validity: Validity::AllValid,
258            body: Body::Dictionary { codes, values: Box::new(values) },
259        })
260    }
261
262    /// The same vector with a different validity.
263    #[must_use]
264    pub fn with_validity(mut self, validity: Validity) -> Self {
265        self.validity = validity;
266        self
267    }
268
269    /// What kind of values these are.
270    #[must_use]
271    pub fn logical_type(&self) -> &LogicalType {
272        &self.ty
273    }
274
275    /// How many values there are.
276    #[must_use]
277    pub fn len(&self) -> usize {
278        self.len
279    }
280
281    /// Whether there are no values.
282    #[must_use]
283    pub fn is_empty(&self) -> bool {
284        self.len == 0
285    }
286
287    /// Which of the values are not null.
288    #[must_use]
289    pub fn validity(&self) -> &Validity {
290        &self.validity
291    }
292
293    /// Which physical form this vector is in.
294    #[must_use]
295    pub fn form(&self) -> Form {
296        match self.body {
297            Body::Flat(_) => Form::Flat,
298            Body::Constant(_) => Form::Constant,
299            Body::Sequence { .. } => Form::Sequence,
300            Body::Dictionary { .. } => Form::Dictionary,
301        }
302    }
303
304    /// The data, for a flat vector, and `None` for any other form.
305    ///
306    /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
307    /// that can do better on a constant or a dictionary checks [`Self::form`] first.
308    #[must_use]
309    pub fn data(&self) -> Option<&Data> {
310        match &self.body {
311            Body::Flat(data) => Some(data),
312            _ => None,
313        }
314    }
315
316    /// The value at `index`, as a single value.
317    ///
318    /// This is the slow path on purpose. It is what a result set is read out with and what a test
319    /// asserts on, and an operator that calls it per row is an operator that has already lost the
320    /// argument the vector interface exists to win.
321    #[must_use]
322    pub fn value_at(&self, index: usize) -> Value {
323        if index >= self.len || !self.validity.is_valid(index) {
324            return Value::Null;
325        }
326        match &self.body {
327            Body::Constant(value) => value.as_ref().clone(),
328            Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
329            Body::Dictionary { codes, values } => match codes.get(index) {
330                Some(&code) => values.value_at(code as usize),
331                None => Value::Null,
332            },
333            Body::Flat(data) => value_from(&self.ty, data, index),
334        }
335    }
336
337    /// Every value in order, as single values.
338    pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
339        (0..self.len).map(|index| self.value_at(index))
340    }
341
342    /// The same values in flat form.
343    ///
344    /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
345    /// which is exactly why the other forms exist and why nothing on the hot path should call
346    /// this. It is here for the operators that genuinely cannot do better and for the tests that
347    /// check the other forms against it.
348    ///
349    /// # Errors
350    ///
351    /// If the type is one this crate cannot store flat yet, which today means the nested types.
352    pub fn flatten(&self) -> Result<Self> {
353        if let Body::Flat(_) = self.body {
354            return Ok(self.clone());
355        }
356        let values: Vec<Value> = self.iter().collect();
357        let mut data = empty_data_for(&self.ty)?;
358        for value in &values {
359            push_value(&mut data, value)?;
360        }
361        // Taken from the values rather than from `self.validity`, because a dictionary keeps its
362        // nulls in the vector it points at and its own validity says nothing about them. Reading it
363        // instead of them is how a null survives being selected and then comes out as a zero.
364        let validity = Validity::from_iter(self.len, |index| !values[index].is_null());
365        Ok(Self { ty: self.ty.clone(), len: self.len, validity, body: Body::Flat(data) })
366    }
367}
368
369/// The physical layout a run of data is in, for the check that it matches its type.
370fn layout_of(data: &Data) -> rudb_common::PhysicalType {
371    use rudb_common::PhysicalType as P;
372    match data {
373        Data::Empty => P::Empty,
374        Data::Bool(_) => P::Bool,
375        Data::Int8(_) => P::Int8,
376        Data::Int16(_) => P::Int16,
377        Data::Int32(_) => P::Int32,
378        Data::Int64(_) => P::Int64,
379        Data::Int128(_) => P::Int128,
380        Data::UInt8(_) => P::UInt8,
381        Data::UInt16(_) => P::UInt16,
382        Data::UInt32(_) => P::UInt32,
383        Data::UInt64(_) => P::UInt64,
384        Data::UInt128(_) => P::UInt128,
385        Data::Float32(_) => P::Float32,
386        Data::Float64(_) => P::Float64,
387        Data::Interval(_) => P::Interval,
388        Data::Varlen(_) => P::Varlen,
389    }
390}
391
392/// One value out of a run of data, given what the run means.
393///
394/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
395/// from an `INTEGER` and that is the whole reason the two are kept apart.
396fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
397    let signed = || data.signed_at(index);
398    let unsigned = || data.unsigned_at(index);
399    let value = match ty {
400        LogicalType::Boolean => match data {
401            Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
402            _ => None,
403        },
404        LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
405        LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
406        LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
407        LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
408        LogicalType::HugeInt => signed().map(Value::HugeInt),
409        LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
410        LogicalType::USmallInt => {
411            unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
412        }
413        LogicalType::UInteger => {
414            unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
415        }
416        LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
417        LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
418        LogicalType::Float => match data {
419            Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
420            _ => None,
421        },
422        LogicalType::Double => match data {
423            Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
424            _ => None,
425        },
426        LogicalType::Decimal { width, scale } => {
427            signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
428        }
429        LogicalType::Varchar => data.str_at(index).map(|s| Value::Varchar(s.to_string())),
430        LogicalType::Blob | LogicalType::Bit => {
431            data.str_at(index).map(|s| Value::Blob(s.as_bytes().to_vec()))
432        }
433        LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
434        LogicalType::Time | LogicalType::TimeTz => {
435            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time)
436        }
437        LogicalType::Timestamp
438        | LogicalType::TimestampS
439        | LogicalType::TimestampMs
440        | LogicalType::TimestampNs
441        | LogicalType::TimestampTz => {
442            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
443        }
444        LogicalType::Interval => match data {
445            Data::Interval(v) => {
446                v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
447            }
448            _ => None,
449        },
450        _ => None,
451    };
452    value.unwrap_or(Value::Null)
453}
454
455/// An empty run of data of the right layout for a type.
456fn empty_data_for(ty: &LogicalType) -> Result<Data> {
457    use rudb_common::PhysicalType as P;
458    Ok(match ty.physical() {
459        P::Empty => Data::Empty,
460        P::Bool => Data::Bool(Vec::new()),
461        P::Int8 => Data::Int8(Vec::new()),
462        P::Int16 => Data::Int16(Vec::new()),
463        P::Int32 => Data::Int32(Vec::new()),
464        P::Int64 => Data::Int64(Vec::new()),
465        P::Int128 => Data::Int128(Vec::new()),
466        P::UInt8 => Data::UInt8(Vec::new()),
467        P::UInt16 => Data::UInt16(Vec::new()),
468        P::UInt32 => Data::UInt32(Vec::new()),
469        P::UInt64 => Data::UInt64(Vec::new()),
470        P::UInt128 => Data::UInt128(Vec::new()),
471        P::Float32 => Data::Float32(Vec::new()),
472        P::Float64 => Data::Float64(Vec::new()),
473        P::Interval => Data::Interval(Vec::new()),
474        P::Varlen => Data::Varlen(StringColumn::new()),
475        other => {
476            return Err(Error::not_implemented(format!(
477                "a flat vector of {other:?} data, which arrives with the storage layer"
478            )));
479        }
480    })
481}
482
483/// Appends one value to a run of data, or a zero of the right shape when it is null.
484///
485/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
486/// and a run of data with a hole in it would put every value after the hole in the wrong place.
487fn push_value(data: &mut Data, value: &Value) -> Result<()> {
488    macro_rules! push {
489        ($vec:expr, $variant:path, $zero:expr) => {
490            match value {
491                Value::Null => $vec.push($zero),
492                $variant(x) => $vec.push(*x),
493                other => {
494                    return Err(Error::internal(format!(
495                        "{other:?} does not belong in this vector"
496                    )));
497                }
498            }
499        };
500    }
501    match data {
502        Data::Empty => {}
503        Data::Bool(v) => push!(v, Value::Boolean, false),
504        Data::Int8(v) => push!(v, Value::TinyInt, 0),
505        Data::Int16(v) => push!(v, Value::SmallInt, 0),
506        Data::Int32(v) => match value {
507            Value::Null => v.push(0),
508            Value::Integer(x) | Value::Date(x) => v.push(*x),
509            other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
510        },
511        Data::Int64(v) => match value {
512            Value::Null => v.push(0),
513            Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => v.push(*x),
514            other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
515        },
516        Data::Int128(v) => match value {
517            Value::Null => v.push(0),
518            Value::HugeInt(x) => v.push(*x),
519            Value::Decimal { unscaled, .. } => v.push(*unscaled),
520            other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
521        },
522        Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
523        Data::UInt16(v) => push!(v, Value::USmallInt, 0),
524        Data::UInt32(v) => push!(v, Value::UInteger, 0),
525        Data::UInt64(v) => push!(v, Value::UBigInt, 0),
526        Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
527        Data::Float32(v) => push!(v, Value::Float, 0.0),
528        Data::Float64(v) => push!(v, Value::Double, 0.0),
529        Data::Interval(v) => match value {
530            Value::Null => v.push((0, 0, 0)),
531            Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
532            other => return Err(Error::internal(format!("{other:?} is not an interval"))),
533        },
534        Data::Varlen(column) => match value {
535            Value::Null => {
536                column.push("");
537            }
538            Value::Varchar(text) => {
539                column.push(text);
540            }
541            // A blob is bytes and this column is text, so the only blobs that survive a round trip
542            // here are the ones that happen to be valid UTF-8. Real blob storage is a byte column
543            // and it arrives with the storage layer at M2 rather than being faked now.
544            Value::Blob(bytes) => match std::str::from_utf8(bytes) {
545                Ok(text) => {
546                    column.push(text);
547                }
548                Err(_) => {
549                    return Err(Error::not_implemented(
550                        "a blob that is not valid UTF-8, which needs the byte column from M2",
551                    ));
552                }
553            },
554            other => return Err(Error::internal(format!("{other:?} is not a string"))),
555        },
556    }
557    Ok(())
558}
559
560#[cfg(test)]
561mod tests {
562    use rudb_common::{LogicalType, Value};
563
564    use super::{Data, Form, VECTOR_SIZE, Vector};
565    use crate::string::StringColumn;
566    use crate::validity::Validity;
567
568    fn integers(values: &[i32]) -> Vector {
569        Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec())).unwrap()
570    }
571
572    #[test]
573    fn the_vector_size_is_the_one_the_design_is_built_around() {
574        // 1024 and not DuckDB's 2048. A validity mask is 16 u64 words and a vector of string views
575        // is 16 KiB, both of which are consequences of this number rather than coincidences.
576        assert_eq!(VECTOR_SIZE, 1024);
577        assert_eq!(VECTOR_SIZE / 64, 16);
578    }
579
580    #[test]
581    fn a_flat_vector_reads_back_what_was_put_in_it() {
582        let vector = integers(&[1, 2, 3]);
583        assert_eq!(vector.form(), Form::Flat);
584        assert_eq!(vector.len(), 3);
585        assert_eq!(vector.value_at(1), Value::Integer(2));
586        assert_eq!(
587            vector.iter().collect::<Vec<_>>(),
588            vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
589        );
590    }
591
592    #[test]
593    fn a_vector_built_from_values_reads_the_same_values_back() {
594        let vector = Vector::from_values(
595            LogicalType::Varchar,
596            &[
597                Value::Varchar("a".to_string()),
598                Value::Null,
599                Value::Varchar("a string too long to sit inside a view".to_string()),
600            ],
601        )
602        .expect("strings and a null");
603        assert_eq!(vector.len(), 3);
604        assert_eq!(vector.value_at(0), Value::Varchar("a".to_string()));
605        assert_eq!(vector.value_at(1), Value::Null);
606        assert_eq!(
607            vector.value_at(2),
608            Value::Varchar("a string too long to sit inside a view".to_string())
609        );
610    }
611
612    /// A null still occupies a position. If it did not then every value after it would read back
613    /// one place to the left, which is the kind of bug that looks like a storage bug for a week.
614    #[test]
615    fn a_null_in_the_middle_does_not_move_the_values_after_it() {
616        let vector = Vector::from_values(
617            LogicalType::Integer,
618            &[Value::Integer(1), Value::Null, Value::Integer(3)],
619        )
620        .expect("integers and a null");
621        assert_eq!(vector.value_at(2), Value::Integer(3));
622        assert!(vector.validity().has_nulls(3), "the middle one is null");
623    }
624
625    #[test]
626    fn a_value_the_type_cannot_hold_is_refused() {
627        let wrong = Vector::from_values(LogicalType::Integer, &[Value::Varchar("x".to_string())]);
628        assert!(wrong.is_err(), "a string is not an integer");
629    }
630
631    #[test]
632    fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
633        // One comparison here against a wrong answer read out three layers later.
634        let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1]));
635        assert!(wrong.is_err());
636        let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1]));
637        assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
638    }
639
640    #[test]
641    fn a_constant_vector_costs_one_value_whatever_its_length() {
642        let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
643        assert_eq!(vector.form(), Form::Constant);
644        assert_eq!(vector.len(), VECTOR_SIZE);
645        assert_eq!(vector.value_at(0), Value::Integer(7));
646        assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
647        assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
648    }
649
650    #[test]
651    fn a_constant_null_is_all_invalid_without_being_told() {
652        let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
653        assert_eq!(vector.validity(), &Validity::AllInvalid);
654        assert_eq!(vector.value_at(3), Value::Null);
655    }
656
657    #[test]
658    fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
659        let vector = Vector::sequence(100, 1, VECTOR_SIZE);
660        assert_eq!(vector.form(), Form::Sequence);
661        assert_eq!(vector.value_at(0), Value::BigInt(100));
662        assert_eq!(vector.value_at(923), Value::BigInt(1023));
663        let stepped = Vector::sequence(0, 5, 4);
664        assert_eq!(
665            stepped.iter().collect::<Vec<_>>(),
666            vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
667        );
668    }
669
670    #[test]
671    fn a_dictionary_vector_reads_through_its_codes() {
672        let mut column = StringColumn::new();
673        column.push("red");
674        column.push("green");
675        let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
676        let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
677        assert_eq!(vector.form(), Form::Dictionary);
678        assert_eq!(vector.logical_type(), &LogicalType::Varchar);
679        assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
680        assert_eq!(vector.len(), 4);
681    }
682
683    #[test]
684    fn a_dictionary_code_past_the_end_is_refused() {
685        // The alternative is a silent read of the wrong value, which is the failure mode the
686        // entire M3 design has to be careful about.
687        let values = integers(&[1, 2]);
688        assert!(Vector::dictionary(vec![0, 2], values).is_err());
689    }
690
691    #[test]
692    fn every_form_flattens_to_the_same_values_it_reads_out() {
693        // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
694        // miniature and long before there is an encoded kernel to point it at. A form that reads
695        // out one way and flattens another is the exact bug that testing exists to catch.
696        let mut column = StringColumn::new();
697        column.push("alpha");
698        column.push("beta");
699        let dictionary = Vector::dictionary(
700            vec![1, 0, 1],
701            Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
702        )
703        .unwrap();
704        let cases = [
705            Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
706            Vector::sequence(7, -2, 5),
707            dictionary,
708        ];
709        for vector in cases {
710            let flat = vector.flatten().unwrap();
711            assert_eq!(flat.form(), Form::Flat);
712            assert_eq!(flat.len(), vector.len());
713            for index in 0..vector.len() {
714                assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
715            }
716        }
717    }
718
719    #[test]
720    fn a_null_still_occupies_a_position_after_flattening() {
721        // The reason push_value writes a zero for a null rather than skipping it. A run of data
722        // with a hole in it puts every value after the hole in the wrong place, and the validity
723        // mask is what says the position is null.
724        let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
725        let flat = vector.flatten().unwrap();
726        assert_eq!(flat.value_at(0), Value::BigInt(0));
727        assert_eq!(flat.value_at(1), Value::Null);
728        assert_eq!(flat.value_at(2), Value::BigInt(2));
729        assert_eq!(flat.value_at(3), Value::BigInt(3));
730    }
731
732    /// A dictionary holds its nulls in the vector it points at, so its own validity is all valid
733    /// and reading that instead of the values turns a null into whatever zero means for the type.
734    /// A filter over a nullable column produces exactly this vector, so the bug reaches a result
735    /// set as `LEFT JOIN` padding that comes back as zeros.
736    #[test]
737    fn a_null_behind_a_dictionary_survives_flattening() {
738        let values =
739            Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
740        let dictionary = Vector::dictionary(vec![1, 0, 1], values).unwrap();
741        let flat = dictionary.flatten().unwrap();
742        assert_eq!(flat.value_at(0), Value::Null);
743        assert_eq!(flat.value_at(1), Value::Integer(3));
744        assert_eq!(flat.value_at(2), Value::Null);
745    }
746
747    #[test]
748    fn flattening_a_flat_vector_is_the_same_vector() {
749        let vector = integers(&[1, 2, 3]);
750        assert_eq!(vector.flatten().unwrap(), vector);
751    }
752
753    #[test]
754    fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
755        let ty = LogicalType::decimal(9, 2).unwrap();
756        let vector = Vector::flat(ty, Data::Int32(vec![1234])).unwrap();
757        assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
758        assert_eq!(vector.value_at(0).to_string(), "12.34");
759    }
760}