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