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 vector of `len` copies of one value.
195    ///
196    /// Costs one value regardless of the length, which is what makes a literal in a predicate free
197    /// and what makes a projection of a constant free.
198    #[must_use]
199    pub fn constant(ty: LogicalType, value: Value, len: usize) -> Self {
200        let validity = if value.is_null() { Validity::AllInvalid } else { Validity::AllValid };
201        Self { ty, len, validity, body: Body::Constant(Box::new(value)) }
202    }
203
204    /// A vector of `len` values starting at `start` and stepping by `step`.
205    ///
206    /// This is what a row identifier column is, and it costs sixteen bytes rather than eight
207    /// kilobytes. A scan that produces row ids for a later fetch produces one of these.
208    #[must_use]
209    pub fn sequence(start: i64, step: i64, len: usize) -> Self {
210        Self {
211            ty: LogicalType::BigInt,
212            len,
213            validity: Validity::AllValid,
214            body: Body::Sequence { start, step },
215        }
216    }
217
218    /// A vector of codes into a smaller vector of distinct values.
219    ///
220    /// The form the whole M3 thesis rests on. A dictionary vector handed to a group by is an
221    /// integer column, and an aggregate over one is an aggregate over integers no matter what the
222    /// logical type says.
223    ///
224    /// # Errors
225    ///
226    /// If any code is past the end of the value vector.
227    pub fn dictionary(codes: Vec<u32>, values: Vector) -> Result<Self> {
228        if let Some(&bad) = codes.iter().find(|&&code| code as usize >= values.len()) {
229            return Err(Error::internal(format!(
230                "dictionary code {bad} is past the end of a {} value dictionary",
231                values.len()
232            )));
233        }
234        Ok(Self {
235            ty: values.ty.clone(),
236            len: codes.len(),
237            validity: Validity::AllValid,
238            body: Body::Dictionary { codes, values: Box::new(values) },
239        })
240    }
241
242    /// The same vector with a different validity.
243    #[must_use]
244    pub fn with_validity(mut self, validity: Validity) -> Self {
245        self.validity = validity;
246        self
247    }
248
249    /// What kind of values these are.
250    #[must_use]
251    pub fn logical_type(&self) -> &LogicalType {
252        &self.ty
253    }
254
255    /// How many values there are.
256    #[must_use]
257    pub fn len(&self) -> usize {
258        self.len
259    }
260
261    /// Whether there are no values.
262    #[must_use]
263    pub fn is_empty(&self) -> bool {
264        self.len == 0
265    }
266
267    /// Which of the values are not null.
268    #[must_use]
269    pub fn validity(&self) -> &Validity {
270        &self.validity
271    }
272
273    /// Which physical form this vector is in.
274    #[must_use]
275    pub fn form(&self) -> Form {
276        match self.body {
277            Body::Flat(_) => Form::Flat,
278            Body::Constant(_) => Form::Constant,
279            Body::Sequence { .. } => Form::Sequence,
280            Body::Dictionary { .. } => Form::Dictionary,
281        }
282    }
283
284    /// The data, for a flat vector, and `None` for any other form.
285    ///
286    /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
287    /// that can do better on a constant or a dictionary checks [`Self::form`] first.
288    #[must_use]
289    pub fn data(&self) -> Option<&Data> {
290        match &self.body {
291            Body::Flat(data) => Some(data),
292            _ => None,
293        }
294    }
295
296    /// The value at `index`, as a single value.
297    ///
298    /// This is the slow path on purpose. It is what a result set is read out with and what a test
299    /// asserts on, and an operator that calls it per row is an operator that has already lost the
300    /// argument the vector interface exists to win.
301    #[must_use]
302    pub fn value_at(&self, index: usize) -> Value {
303        if index >= self.len || !self.validity.is_valid(index) {
304            return Value::Null;
305        }
306        match &self.body {
307            Body::Constant(value) => value.as_ref().clone(),
308            Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
309            Body::Dictionary { codes, values } => match codes.get(index) {
310                Some(&code) => values.value_at(code as usize),
311                None => Value::Null,
312            },
313            Body::Flat(data) => value_from(&self.ty, data, index),
314        }
315    }
316
317    /// Every value in order, as single values.
318    pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
319        (0..self.len).map(|index| self.value_at(index))
320    }
321
322    /// The same values in flat form.
323    ///
324    /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
325    /// which is exactly why the other forms exist and why nothing on the hot path should call
326    /// this. It is here for the operators that genuinely cannot do better and for the tests that
327    /// check the other forms against it.
328    ///
329    /// # Errors
330    ///
331    /// If the type is one this crate cannot store flat yet, which today means the nested types.
332    pub fn flatten(&self) -> Result<Self> {
333        if let Body::Flat(_) = self.body {
334            return Ok(self.clone());
335        }
336        let mut data = empty_data_for(&self.ty)?;
337        for index in 0..self.len {
338            push_value(&mut data, &self.value_at(index))?;
339        }
340        let validity = Validity::from_iter(self.len, |index| self.validity.is_valid(index));
341        Ok(Self { ty: self.ty.clone(), len: self.len, validity, body: Body::Flat(data) })
342    }
343}
344
345/// The physical layout a run of data is in, for the check that it matches its type.
346fn layout_of(data: &Data) -> rudb_common::PhysicalType {
347    use rudb_common::PhysicalType as P;
348    match data {
349        Data::Empty => P::Empty,
350        Data::Bool(_) => P::Bool,
351        Data::Int8(_) => P::Int8,
352        Data::Int16(_) => P::Int16,
353        Data::Int32(_) => P::Int32,
354        Data::Int64(_) => P::Int64,
355        Data::Int128(_) => P::Int128,
356        Data::UInt8(_) => P::UInt8,
357        Data::UInt16(_) => P::UInt16,
358        Data::UInt32(_) => P::UInt32,
359        Data::UInt64(_) => P::UInt64,
360        Data::UInt128(_) => P::UInt128,
361        Data::Float32(_) => P::Float32,
362        Data::Float64(_) => P::Float64,
363        Data::Interval(_) => P::Interval,
364        Data::Varlen(_) => P::Varlen,
365    }
366}
367
368/// One value out of a run of data, given what the run means.
369///
370/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
371/// from an `INTEGER` and that is the whole reason the two are kept apart.
372fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
373    let signed = || data.signed_at(index);
374    let unsigned = || data.unsigned_at(index);
375    let value = match ty {
376        LogicalType::Boolean => match data {
377            Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
378            _ => None,
379        },
380        LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
381        LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
382        LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
383        LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
384        LogicalType::HugeInt => signed().map(Value::HugeInt),
385        LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
386        LogicalType::USmallInt => {
387            unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
388        }
389        LogicalType::UInteger => {
390            unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
391        }
392        LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
393        LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
394        LogicalType::Float => match data {
395            Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
396            _ => None,
397        },
398        LogicalType::Double => match data {
399            Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
400            _ => None,
401        },
402        LogicalType::Decimal { width, scale } => {
403            signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
404        }
405        LogicalType::Varchar => data.str_at(index).map(|s| Value::Varchar(s.to_string())),
406        LogicalType::Blob | LogicalType::Bit => {
407            data.str_at(index).map(|s| Value::Blob(s.as_bytes().to_vec()))
408        }
409        LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
410        LogicalType::Time | LogicalType::TimeTz => {
411            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time)
412        }
413        LogicalType::Timestamp
414        | LogicalType::TimestampS
415        | LogicalType::TimestampMs
416        | LogicalType::TimestampNs
417        | LogicalType::TimestampTz => {
418            signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
419        }
420        LogicalType::Interval => match data {
421            Data::Interval(v) => {
422                v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
423            }
424            _ => None,
425        },
426        _ => None,
427    };
428    value.unwrap_or(Value::Null)
429}
430
431/// An empty run of data of the right layout for a type.
432fn empty_data_for(ty: &LogicalType) -> Result<Data> {
433    use rudb_common::PhysicalType as P;
434    Ok(match ty.physical() {
435        P::Empty => Data::Empty,
436        P::Bool => Data::Bool(Vec::new()),
437        P::Int8 => Data::Int8(Vec::new()),
438        P::Int16 => Data::Int16(Vec::new()),
439        P::Int32 => Data::Int32(Vec::new()),
440        P::Int64 => Data::Int64(Vec::new()),
441        P::Int128 => Data::Int128(Vec::new()),
442        P::UInt8 => Data::UInt8(Vec::new()),
443        P::UInt16 => Data::UInt16(Vec::new()),
444        P::UInt32 => Data::UInt32(Vec::new()),
445        P::UInt64 => Data::UInt64(Vec::new()),
446        P::UInt128 => Data::UInt128(Vec::new()),
447        P::Float32 => Data::Float32(Vec::new()),
448        P::Float64 => Data::Float64(Vec::new()),
449        P::Interval => Data::Interval(Vec::new()),
450        P::Varlen => Data::Varlen(StringColumn::new()),
451        other => {
452            return Err(Error::not_implemented(format!(
453                "a flat vector of {other:?} data, which arrives with the storage layer"
454            )));
455        }
456    })
457}
458
459/// Appends one value to a run of data, or a zero of the right shape when it is null.
460///
461/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
462/// and a run of data with a hole in it would put every value after the hole in the wrong place.
463fn push_value(data: &mut Data, value: &Value) -> Result<()> {
464    macro_rules! push {
465        ($vec:expr, $variant:path, $zero:expr) => {
466            match value {
467                Value::Null => $vec.push($zero),
468                $variant(x) => $vec.push(*x),
469                other => {
470                    return Err(Error::internal(format!(
471                        "{other:?} does not belong in this vector"
472                    )));
473                }
474            }
475        };
476    }
477    match data {
478        Data::Empty => {}
479        Data::Bool(v) => push!(v, Value::Boolean, false),
480        Data::Int8(v) => push!(v, Value::TinyInt, 0),
481        Data::Int16(v) => push!(v, Value::SmallInt, 0),
482        Data::Int32(v) => match value {
483            Value::Null => v.push(0),
484            Value::Integer(x) | Value::Date(x) => v.push(*x),
485            other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
486        },
487        Data::Int64(v) => match value {
488            Value::Null => v.push(0),
489            Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => v.push(*x),
490            other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
491        },
492        Data::Int128(v) => match value {
493            Value::Null => v.push(0),
494            Value::HugeInt(x) => v.push(*x),
495            Value::Decimal { unscaled, .. } => v.push(*unscaled),
496            other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
497        },
498        Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
499        Data::UInt16(v) => push!(v, Value::USmallInt, 0),
500        Data::UInt32(v) => push!(v, Value::UInteger, 0),
501        Data::UInt64(v) => push!(v, Value::UBigInt, 0),
502        Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
503        Data::Float32(v) => push!(v, Value::Float, 0.0),
504        Data::Float64(v) => push!(v, Value::Double, 0.0),
505        Data::Interval(v) => match value {
506            Value::Null => v.push((0, 0, 0)),
507            Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
508            other => return Err(Error::internal(format!("{other:?} is not an interval"))),
509        },
510        Data::Varlen(column) => match value {
511            Value::Null => {
512                column.push("");
513            }
514            Value::Varchar(text) => {
515                column.push(text);
516            }
517            // A blob is bytes and this column is text, so the only blobs that survive a round trip
518            // here are the ones that happen to be valid UTF-8. Real blob storage is a byte column
519            // and it arrives with the storage layer at M2 rather than being faked now.
520            Value::Blob(bytes) => match std::str::from_utf8(bytes) {
521                Ok(text) => {
522                    column.push(text);
523                }
524                Err(_) => {
525                    return Err(Error::not_implemented(
526                        "a blob that is not valid UTF-8, which needs the byte column from M2",
527                    ));
528                }
529            },
530            other => return Err(Error::internal(format!("{other:?} is not a string"))),
531        },
532    }
533    Ok(())
534}
535
536#[cfg(test)]
537mod tests {
538    use rudb_common::{LogicalType, Value};
539
540    use super::{Data, Form, VECTOR_SIZE, Vector};
541    use crate::string::StringColumn;
542    use crate::validity::Validity;
543
544    fn integers(values: &[i32]) -> Vector {
545        Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec())).unwrap()
546    }
547
548    #[test]
549    fn the_vector_size_is_the_one_the_design_is_built_around() {
550        // 1024 and not DuckDB's 2048. A validity mask is 16 u64 words and a vector of string views
551        // is 16 KiB, both of which are consequences of this number rather than coincidences.
552        assert_eq!(VECTOR_SIZE, 1024);
553        assert_eq!(VECTOR_SIZE / 64, 16);
554    }
555
556    #[test]
557    fn a_flat_vector_reads_back_what_was_put_in_it() {
558        let vector = integers(&[1, 2, 3]);
559        assert_eq!(vector.form(), Form::Flat);
560        assert_eq!(vector.len(), 3);
561        assert_eq!(vector.value_at(1), Value::Integer(2));
562        assert_eq!(
563            vector.iter().collect::<Vec<_>>(),
564            vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
565        );
566    }
567
568    #[test]
569    fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
570        // One comparison here against a wrong answer read out three layers later.
571        let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1]));
572        assert!(wrong.is_err());
573        let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1]));
574        assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
575    }
576
577    #[test]
578    fn a_constant_vector_costs_one_value_whatever_its_length() {
579        let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
580        assert_eq!(vector.form(), Form::Constant);
581        assert_eq!(vector.len(), VECTOR_SIZE);
582        assert_eq!(vector.value_at(0), Value::Integer(7));
583        assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
584        assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
585    }
586
587    #[test]
588    fn a_constant_null_is_all_invalid_without_being_told() {
589        let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
590        assert_eq!(vector.validity(), &Validity::AllInvalid);
591        assert_eq!(vector.value_at(3), Value::Null);
592    }
593
594    #[test]
595    fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
596        let vector = Vector::sequence(100, 1, VECTOR_SIZE);
597        assert_eq!(vector.form(), Form::Sequence);
598        assert_eq!(vector.value_at(0), Value::BigInt(100));
599        assert_eq!(vector.value_at(923), Value::BigInt(1023));
600        let stepped = Vector::sequence(0, 5, 4);
601        assert_eq!(
602            stepped.iter().collect::<Vec<_>>(),
603            vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
604        );
605    }
606
607    #[test]
608    fn a_dictionary_vector_reads_through_its_codes() {
609        let mut column = StringColumn::new();
610        column.push("red");
611        column.push("green");
612        let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
613        let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
614        assert_eq!(vector.form(), Form::Dictionary);
615        assert_eq!(vector.logical_type(), &LogicalType::Varchar);
616        assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
617        assert_eq!(vector.len(), 4);
618    }
619
620    #[test]
621    fn a_dictionary_code_past_the_end_is_refused() {
622        // The alternative is a silent read of the wrong value, which is the failure mode the
623        // entire M3 design has to be careful about.
624        let values = integers(&[1, 2]);
625        assert!(Vector::dictionary(vec![0, 2], values).is_err());
626    }
627
628    #[test]
629    fn every_form_flattens_to_the_same_values_it_reads_out() {
630        // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
631        // miniature and long before there is an encoded kernel to point it at. A form that reads
632        // out one way and flattens another is the exact bug that testing exists to catch.
633        let mut column = StringColumn::new();
634        column.push("alpha");
635        column.push("beta");
636        let dictionary = Vector::dictionary(
637            vec![1, 0, 1],
638            Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
639        )
640        .unwrap();
641        let cases = [
642            Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
643            Vector::sequence(7, -2, 5),
644            dictionary,
645        ];
646        for vector in cases {
647            let flat = vector.flatten().unwrap();
648            assert_eq!(flat.form(), Form::Flat);
649            assert_eq!(flat.len(), vector.len());
650            for index in 0..vector.len() {
651                assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
652            }
653        }
654    }
655
656    #[test]
657    fn a_null_still_occupies_a_position_after_flattening() {
658        // The reason push_value writes a zero for a null rather than skipping it. A run of data
659        // with a hole in it puts every value after the hole in the wrong place, and the validity
660        // mask is what says the position is null.
661        let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
662        let flat = vector.flatten().unwrap();
663        assert_eq!(flat.value_at(0), Value::BigInt(0));
664        assert_eq!(flat.value_at(1), Value::Null);
665        assert_eq!(flat.value_at(2), Value::BigInt(2));
666        assert_eq!(flat.value_at(3), Value::BigInt(3));
667    }
668
669    #[test]
670    fn flattening_a_flat_vector_is_the_same_vector() {
671        let vector = integers(&[1, 2, 3]);
672        assert_eq!(vector.flatten().unwrap(), vector);
673    }
674
675    #[test]
676    fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
677        let ty = LogicalType::decimal(9, 2).unwrap();
678        let vector = Vector::flat(ty, Data::Int32(vec![1234])).unwrap();
679        assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
680        assert_eq!(vector.value_at(0).to_string(), "12.34");
681    }
682}