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, bit packed and string view come
10//! after them, one at a time with the kernels that read them rather than all at once ahead of
11//! 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//! String view is the odd one out, because it is not about making a column smaller. It is about who
20//! owns the bytes: the views are the vector's and the arena is shared, so cutting a chunk out of a
21//! page of strings moves sixteen bytes a row and copies none of the payload. Every other form here
22//! trades a little work per row for less memory, and that one trades nothing at all.
23//!
24//! The nested forms are the odd ones out in a different direction. The forms above are all ways of
25//! writing a column of scalars down more cheaply, and a nested value is not a scalar at all, so
26//! [`Form::List`] and [`Form::Struct`] are each the only form their column has rather than one of
27//! several it could be in. A list is a child vector of every element plus a start and a length per
28//! row. A struct is one child per field with no entries at all, because a struct row holds one value
29//! per field rather than a run of them. Either way the children are ordinary vectors and can be in any
30//! of the forms above, which is where a nested column gets made smaller.
31//!
32//! **What is not here yet.** Buffers are owned. Section 7.1 says a vector borrowed from a buffer
33//! managed page carries a pin, and there is no buffer manager until M2, so there is nothing to pin
34//! and pretending otherwise would be an interface built against an imaginary caller. `ARRAY` is not
35//! stored yet either, and it is a composition of what is here rather than a new shape: it is a list
36//! whose length is the type's rather than the row's, the way a `MAP` is a list whose child is a two
37//! field struct of keys and values. `UNION` is the one that is genuinely different, since it is one
38//! child per member plus a tag saying which member each row is in.
39
40use std::borrow::Cow;
41use std::cmp::Ordering;
42use std::sync::Arc;
43
44use rudb_common::{Cause, Error, Field, LogicalType, Result, Value, slow};
45
46use crate::buffer::Buffer;
47use crate::fsst::SymbolTable;
48use crate::string::{StringColumn, StringView};
49use crate::validity::Validity;
50
51/// How many values are in a full vector.
52///
53/// 8192, which is four times DuckDB's 2048 and eight times what this was. It started at 1024 for
54/// three reasons: the FastLanes unit is 1024, a validity mask comes out at exactly 16 `u64` words,
55/// and a vector of 16 byte string views is 16 KiB, which is small enough that several of them sit
56/// in L1 at once. The first two are still true of any multiple of 1024. The third was the argument
57/// and it was an argument about the wrong level, because it was also deciding how much of a table
58/// one zone map covered and how much work one call into the pipeline did, and those wanted a much
59/// larger number than L1 did.
60///
61/// #984 separated them: a table in memory is stored in row groups of 122,880 rows now and a chunk
62/// is a window into one, so the vector size is only the execution unit and is free to be chosen for
63/// what an operator costs per call. #480 measured it. On twenty million rows in memory, one thread,
64/// going from 1024 to 8192 takes `count(*)` with a filter from 14.0 milliseconds to 1.9, `sum(v)`
65/// with the same filter from 39.6 to 29.6 and `sum(k + v)` from 66.8 to 52.6. On ClickBench over
66/// Parquet, where the time is decode and hash aggregation rather than per call overhead, the same
67/// move is worth about eight percent on the total of the twenty nine queries that run.
68///
69/// 32768 was measured too and is not better: it wins another few percent on the full scans and
70/// loses on the load, on a needle that the chunk zone maps would otherwise prune, and on anything
71/// with a string column, where a vector of views is half a megabyte. 8192 is where the per call
72/// overhead has stopped mattering and the working set has not started to.
73pub const VECTOR_SIZE: usize = 8192;
74
75/// What the key field of a map's child struct is called.
76///
77/// A map is stored as a list of two field structs, and these are the two names. They are DuckDB's, and
78/// they are also the names the Parquet specification gives a map's repeated group, so a reader that
79/// builds one of these from a file finds the names already agreed rather than translated.
80pub const MAP_KEY: &str = "key";
81
82/// What the value field of a map's child struct is called. See [`MAP_KEY`].
83pub const MAP_VALUE: &str = "value";
84
85/// What [`Vector::map_parts`] hands back: one entry per row, then the keys and then the values.
86///
87/// A name rather than the triple written out, because the triple written out is over the complexity
88/// clippy allows and because a kernel that takes these as an argument should be able to say so in one
89/// word.
90pub type MapParts<'a> = (&'a [(u32, u32)], &'a Vector, &'a Vector);
91
92/// Which physical form a vector is in.
93///
94/// An operator asks this once per vector and then takes the path it wants, which is the one branch
95/// per vector that the whole design is willing to spend.
96///
97/// Not exhaustive, and that is a decision rather than an oversight. `Encoded` is the fifth form
98/// and it arrives at layer three with the specialization contract. If this enum were exhaustive,
99/// the day it lands is the day every kernel in the workspace stops compiling, and the pressure at
100/// that moment would be to add an arm to each of them in a hurry rather than to think about what
101/// each one should do with an encoded vector. A required fallback arm means each kernel already
102/// has a correct answer for a form it has never seen, and specializing it is then a change that
103/// can be made one kernel at a time with a benchmark next to it.
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105#[non_exhaustive]
106pub enum Form {
107 /// One value per position.
108 Flat,
109 /// One value, repeated.
110 Constant,
111 /// A start and a step, computed rather than stored.
112 Sequence,
113 /// Codes into a smaller vector of distinct values.
114 Dictionary,
115 /// Integers stored in as many bits as the range of the column needs, offset from a base.
116 ///
117 /// The form a narrow integer column is in. A ClickBench `ResolutionWidth` is a `SMALLINT` whose
118 /// values live between 0 and 2560, which is twelve bits, so the column is three quarters of the
119 /// size it was and the pages behind it are three quarters of the reads. What it costs is a shift
120 /// and a mask per value, which is why this is worth it at storage and at rest and is not a form
121 /// anything should be building in the middle of a pipeline.
122 BitPacked,
123 /// Sixteen byte views over an arena the vector shares rather than owns.
124 ///
125 /// The form a varchar column is in once more than one vector is looking at the same page. A flat
126 /// varchar vector owns its arena, so cutting a chunk out of it copies every byte of every long
127 /// string in the range, and on ClickBench that is most of what reading `URL` costs. Sharing the
128 /// arena makes the cut the views and nothing else, the way a dictionary cut is the codes and
129 /// nothing else.
130 StringView,
131 /// Strings compressed against one symbol table, each row on its own.
132 ///
133 /// The form a text column is in at rest. FSST is about half the bytes on the ClickBench `URL`
134 /// and `Title` columns, and unlike a block compressor it keeps random access, so reading row
135 /// four million does not decompress the four million before it. What it costs is a decompression
136 /// per row read, which is why an equality filter over it is worth writing in code space: the
137 /// literal compresses once and the rows never decompress at all.
138 Fsst,
139 /// One value per run, with the row each run ends at.
140 ///
141 /// The form a clustered column is in. `hits` is written in time order, so `EventDate` is a few
142 /// hundred runs over a hundred million rows, and a sum over it is a few hundred multiplications
143 /// rather than a hundred million additions. Dictionary says which distinct values there are and
144 /// this says where they stop, and a column can want either one without wanting the other.
145 Rle,
146 /// A child vector of every element, and a start and a length per row.
147 ///
148 /// The form a `LIST` column is in, and the only form it has. The others are all ways of writing
149 /// down a column of scalars more cheaply and this is the shape a nested value has at all, so a
150 /// list vector reports this whether or not anything has tried to make it smaller. Making it
151 /// smaller happens in the child, which is an ordinary vector and can be any of the forms above.
152 ///
153 /// A `MAP` column reports this too, because a map is a list whose child is a two field struct and
154 /// the bytes really are a list's. This enum is about the physical layout, and the logical type is
155 /// what remembers the difference, which is the same division `LogicalType::physical` already makes.
156 List,
157 /// One child vector per field, each as long as the vector itself.
158 ///
159 /// The form a `STRUCT` column is in, and the only form it has, for the reason [`Form::List`] is
160 /// the only form a list has. A struct holds exactly one value per field per row rather than a run
161 /// of them, so there are no entries here and the children line up with the rows one to one, which
162 /// makes a cut a cut of every child and a gather a gather of every child. Each child is an
163 /// ordinary vector and can be in any of the forms above, so that is where a struct column gets
164 /// made smaller.
165 Struct,
166 /// One row id per row, into a source vector that is far longer than this one.
167 ///
168 /// The form a link join's parent columns are in, per `spec/graph/08-vector-engine.md` section
169 /// 8.2. Physically it is [`Form::Dictionary`] and logically it is the opposite of one, which is
170 /// why it is a form of its own rather than a dictionary with a note on it. A dictionary promises
171 /// that the values are few and distinct, and every kernel that has a dictionary arm takes that
172 /// promise by folding the operation over the values once and then indexing. A gather's source is
173 /// a whole parent table, so folding over it to answer two thousand rows reads fifteen million
174 /// values for nothing. Both forms want the same code and they want it under opposite conditions,
175 /// so the condition is [`Vector::fold_over_source`] and the form is what makes a kernel ask.
176 Gathered,
177}
178
179/// The values of a flat vector, one Rust vector per physical type.
180///
181/// The variants are physical rather than logical, which is what lets `DATE` and `INTEGER` share
182/// storage and share a kernel. What a run of `i32` means is the vector's logical type's business.
183#[derive(Debug, Clone, PartialEq)]
184#[non_exhaustive]
185pub enum Data {
186 /// No values, for the type of an untyped `NULL`.
187 Empty,
188 /// One byte per value.
189 Bool(Buffer<bool>),
190 /// 8 bit signed.
191 Int8(Buffer<i8>),
192 /// 16 bit signed.
193 Int16(Buffer<i16>),
194 /// 32 bit signed.
195 Int32(Buffer<i32>),
196 /// 64 bit signed.
197 Int64(Buffer<i64>),
198 /// 128 bit signed.
199 Int128(Buffer<i128>),
200 /// 8 bit unsigned.
201 UInt8(Buffer<u8>),
202 /// 16 bit unsigned.
203 UInt16(Buffer<u16>),
204 /// 32 bit unsigned.
205 UInt32(Buffer<u32>),
206 /// 64 bit unsigned.
207 UInt64(Buffer<u64>),
208 /// 128 bit unsigned.
209 UInt128(Buffer<u128>),
210 /// IEEE 754 binary32.
211 Float32(Buffer<f32>),
212 /// IEEE 754 binary64.
213 Float64(Buffer<f64>),
214 /// The months, days and microseconds triple.
215 Interval(Buffer<(i32, i32, i64)>),
216 /// Strings, as 16 byte views plus the arena the long ones live in.
217 Varlen(StringColumn),
218}
219
220impl Data {
221 /// How many values are stored.
222 ///
223 /// The match below has no wildcard arm, and that is what makes this function the check that
224 /// keeps [`for_each_layout`](crate::for_each_layout) honest. A variant added to this enum
225 /// without being added to the `all` group fails to compile here, which is a line in a build log
226 /// rather than a layout quietly missing from six kernels.
227 #[must_use]
228 pub fn len(&self) -> usize {
229 macro_rules! lengths {
230 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
231 match self {
232 Self::Empty => 0,
233 $(Self::$variant(values) => values.len(),)+
234 }
235 };
236 }
237 crate::for_each_layout!(all, lengths)
238 }
239
240 /// Whether there are no values.
241 #[must_use]
242 pub fn is_empty(&self) -> bool {
243 self.len() == 0
244 }
245
246 /// How many bytes of memory these values are holding.
247 ///
248 /// One arm per layout through the same macro as [`Data::len`], for the same reason: a layout
249 /// added without a size here is a layout the memory limit would charge nothing for, and a
250 /// buffer that is free is a buffer that can be grown until the process dies.
251 #[must_use]
252 pub fn footprint(&self) -> usize {
253 macro_rules! sizes {
254 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
255 match self {
256 Self::Empty => 0,
257 $(Self::$variant(values) => values.footprint(),)+
258 }
259 };
260 }
261 crate::for_each_layout!(all, sizes)
262 }
263
264 /// These values held as a page, so that copying or cutting them does not copy the values.
265 ///
266 /// For a producer that is going to hand the same values out many times, which is what a stored
267 /// column is. It costs one `Arc` per layout and moves the run into it without touching a value,
268 /// and after it a write through any reader copies out rather than writing the page, which is
269 /// [`Buffer::to_mut`]. A run that is already a page comes back as it was.
270 #[must_use]
271 pub fn into_pages(self) -> Self {
272 macro_rules! paged {
273 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
274 match self {
275 Self::Empty => Self::Empty,
276 $(Self::$variant(values) => Self::$variant(values.into_page()),)+
277 }
278 };
279 }
280 crate::for_each_layout!(all, paged)
281 }
282
283 /// An integer at `index`, widened, for any of the signed integer layouts.
284 ///
285 /// Used by the decimal path, which needs the unscaled value out of whichever width the width
286 /// and scale picked, and by anything else that would otherwise repeat the same five arms.
287 #[must_use]
288 pub fn signed_at(&self, index: usize) -> Option<i128> {
289 macro_rules! widened {
290 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
291 match self {
292 $(Self::$variant(v) => v.get(index).map(|&x| i128::from(x)),)+
293 _ => None,
294 }
295 };
296 }
297 crate::for_each_layout!(signed, widened)
298 }
299
300 /// The first `len` signed integers, widened to `i64`, appended to `out`.
301 ///
302 /// The bulk form of [`Self::signed_at`]. Four of the five signed layouts, because the fifth is
303 /// 128 bits wide and does not fit what this hands back. `Int64` is a copy of the run and the
304 /// three narrower ones are a sign extension the compiler turns into one instruction per lane.
305 ///
306 /// `false`, leaving `out` as it found it, for the wide layout, for a run shorter than `len` and
307 /// for every layout that is not a signed integer.
308 #[must_use]
309 pub fn signed_block(&self, len: usize, out: &mut Vec<i64>) -> bool {
310 match self {
311 Self::Int8(v) => widen(v.as_slice(), len, out),
312 Self::Int16(v) => widen(v.as_slice(), len, out),
313 Self::Int32(v) => widen(v.as_slice(), len, out),
314 Self::Int64(v) => match v.as_slice().get(..len) {
315 Some(run) => {
316 out.extend_from_slice(run);
317 true
318 }
319 None => false,
320 },
321 _ => false,
322 }
323 }
324
325 /// An unsigned integer at `index`, widened.
326 #[must_use]
327 pub fn unsigned_at(&self, index: usize) -> Option<u128> {
328 macro_rules! widened {
329 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
330 match self {
331 $(Self::$variant(v) => v.get(index).map(|&x| u128::from(x)),)+
332 _ => None,
333 }
334 };
335 }
336 crate::for_each_layout!(unsigned, widened)
337 }
338
339 /// The string at `index`, for a `Varlen`.
340 #[must_use]
341 pub fn str_at(&self, index: usize) -> Option<&str> {
342 match self {
343 Self::Varlen(column) => column.get(index),
344 _ => None,
345 }
346 }
347
348 /// The bytes at `index`, for a `Varlen`, whatever they are.
349 ///
350 /// What a `BLOB` reads through, since the bytes of one are not required to be text and
351 /// [`Self::str_at`] answers `None` for the ones that are not.
352 #[must_use]
353 pub fn bytes_at(&self, index: usize) -> Option<&[u8]> {
354 match self {
355 Self::Varlen(column) => column.bytes(index),
356 _ => None,
357 }
358 }
359}
360
361/// A type, a length, a validity representation and some data.
362#[derive(Debug, Clone, PartialEq)]
363pub struct Vector {
364 ty: LogicalType,
365 len: usize,
366 validity: Validity,
367 body: Body,
368}
369
370/// What the vector holds, which is what its form is decided by.
371#[derive(Debug, Clone, PartialEq)]
372enum Body {
373 Flat(Data),
374 Constant(Box<Value>),
375 Sequence {
376 start: i64,
377 step: i64,
378 },
379 /// The values are behind an `Arc` rather than a `Box` because slicing shares them.
380 ///
381 /// A dictionary vector is cut once per chunk and the dictionary itself is the same dictionary
382 /// every time, so a `Box` meant a copy of every value in it per cut. On the ClickBench columns
383 /// that are dictionary encoded the dictionary is larger than the chunk of codes pointing into
384 /// it, and copying it was ten percent of the cycles of reading the file.
385 ///
386 /// Nothing here mutates a dictionary in place, so sharing one is only ever a read, and the one
387 /// place that wants an owned copy of the values is [`compose`], which asks for one.
388 Dictionary {
389 codes: Vec<u32>,
390 values: Arc<Vector>,
391 stable: bool,
392 },
393 /// Integer codes of `width` bits each, packed end to end, each one an offset from `base`.
394 ///
395 /// Row `r` is the `width` bits starting at bit `(offset + r) * width`, read little end first, so
396 /// a code that straddles a word boundary has its low bits in the earlier word. `offset` is what
397 /// lets a cut of a packed column be free: the bits are not byte aligned, so a slice either
398 /// repacks or remembers where it starts, and remembering is one addition per read.
399 ///
400 /// The words are behind an `Arc` for the reason the dictionary's values are. A page is packed
401 /// once and cut into chunk sized pieces, and copying the words per cut would undo most of what
402 /// the packing saved.
403 Packed {
404 words: Arc<Vec<u64>>,
405 width: u32,
406 base: i128,
407 offset: usize,
408 },
409 /// The views of a string column, over an arena that other vectors are reading at the same time.
410 ///
411 /// The views are owned because a cut is a different run of views, and the arena is shared
412 /// because a cut is the same bytes. That split is the whole form: sixteen bytes a row move and
413 /// the payload does not, however many cuts a page is taken in.
414 ///
415 /// A row's bytes are found the same way [`StringColumn`] finds them, through
416 /// [`StringView::bytes_in`], so a short string never reads the arena at all and the two ways of
417 /// holding strings cannot answer a row differently.
418 Views {
419 views: Vec<StringView>,
420 arena: Arc<Buffer<u8>>,
421 },
422 /// Text owned by a storage source and fetched by position.
423 ExternalText {
424 source: Arc<dyn TextSource>,
425 },
426 /// The FSST codes of every row, end to end, with one symbol table over all of them.
427 ///
428 /// A span rather than a run of offsets, because a gather keeps this form and a gather puts the
429 /// rows in an order the codes are not in. Eight bytes a row either way, and the span is the one
430 /// that survives being permuted.
431 ///
432 /// The codes and the table are shared for the reason a dictionary's values are: one table is
433 /// trained per page and every chunk cut out of it points at the same one. A table is sixty five
434 /// thousand hash slots, so a table per chunk would cost more than the compression saves.
435 Coded {
436 codes: Arc<Vec<u8>>,
437 spans: Vec<(u32, u32)>,
438 table: Arc<SymbolTable>,
439 },
440 /// One value per run, with the row each run ends at, exclusive and increasing.
441 ///
442 /// Ends rather than lengths, because every reader of this wants to know which run holds a row
443 /// and ends answer that with a binary search while lengths answer it with a running total. The
444 /// two are the same information and only one of them is the one that gets asked for.
445 ///
446 /// The values are behind an `Arc` for the reason the dictionary's are: a page is cut into chunk
447 /// sized pieces and the values are the same values every time.
448 Runs {
449 ends: Vec<u32>,
450 values: Arc<Vector>,
451 },
452 /// One child vector holding every element of every row, and a start and a length per row.
453 ///
454 /// Start and length rather than the run of offsets Arrow carries, because offsets say where a
455 /// row ends by saying where the next one begins, and that is only true while the rows are in
456 /// order and none is skipped. A gather permutes the rows and a filter drops them, both of which
457 /// this form has to survive without copying the child, so each row says where its own elements
458 /// are and nothing is implied about its neighbour.
459 ///
460 /// The child is behind an `Arc` for the reason a dictionary's values are. A cut of a list column
461 /// is the entries and nothing else, so a page of lists taken in chunk sized pieces holds one
462 /// child however many pieces it is read in, and the elements outside the cut stay reachable but
463 /// unreferenced rather than being copied out.
464 ///
465 /// A null list and an empty list are different rows and this is where the difference lives. A
466 /// null is the validity mask at this level being false, the same as for any other type, and its
467 /// entry is `(start, 0)` and never read. An empty list is a valid row whose entry is `(start, 0)`
468 /// as well. So the entry alone does not say which one a row is, the mask does, which is the same
469 /// division of labour every other form here uses.
470 ///
471 /// A `MAP` is stored here too, with a [`Body::Fields`] child of `key` and `value`. Everything above
472 /// is true of it unchanged, which is the point of storing it this way: the cut, the gather and the
473 /// null rule are written once and a map inherits all three.
474 Nested {
475 entries: Vec<(u32, u32)>,
476 child: Arc<Vector>,
477 },
478 /// One child vector per field, in the order the type names them, each as long as this vector.
479 ///
480 /// No entries, which is the whole difference from [`Body::Nested`]. A list row is a run of
481 /// elements so it needs to say where its run is, and a struct row is one value per field so row
482 /// `r` of field `f` is position `r` of child `f` and there is nothing to record. That makes a cut
483 /// a cut of every child and a gather a gather of every child, both at the same positions, rather
484 /// than a rewrite of an index.
485 ///
486 /// The children are behind an `Arc` for the reason a dictionary's values are, and it pays off less
487 /// often here. A cut of a list column shares its child untouched because the entries carry the
488 /// range, and a cut of a struct column has to cut each child, so the sharing only survives the
489 /// cases where nothing moves. It is still worth having, because a struct of a hundred fields
490 /// handed between operators is a hundred pointers rather than a hundred columns.
491 ///
492 /// A null struct is the validity mask at this level being false and says nothing about the
493 /// children, which still hold whatever was put in them at that row. That is DuckDB's behaviour and
494 /// it is the reason this form cannot decide a row is null by looking down: the mask is the answer,
495 /// the same as it is for a list.
496 Fields {
497 children: Vec<Arc<Vector>>,
498 },
499 /// Row `r` is row `rids[offset + r]` of `source`, and is null where that is [`NO_ROW`].
500 ///
501 /// Late materialization written into the type system. A link join emits one of these per
502 /// projected parent column and reads nothing out of the parent at all, so a column that is
503 /// projected but never inspected is read once at the end for the rows that reached the end, and
504 /// a column used in a filter is filtered in this form over the distinct parent rows that were
505 /// actually reached rather than once per child row.
506 ///
507 /// The `rids` are shared and carry an `offset` for the reason [`Body::Packed`] carries one: a
508 /// link join fills one buffer of parent rows per child chunk and then the pipeline cuts it, and
509 /// a cut that copied the ids would spend more moving them than the gather it is describing
510 /// costs. Sharing makes a cut two words.
511 ///
512 /// [`NO_ROW`] is the whole of the outer join story here. Section 5.2 says a left link join keeps
513 /// the child rows whose link is the no parent sentinel and gathers null for them, and an inner
514 /// one drops them, so the operator decides which rows exist and this decides only what they
515 /// hold. That keeps the validity of a gather derivable rather than stored: a row is null when
516 /// its id is [`NO_ROW`] or when the source row it names is null, which is two loads and no
517 /// allocation, and the bitmap is materialized only when a kernel asks for one.
518 Gathered {
519 source: Arc<Vector>,
520 rids: Arc<Vec<u32>>,
521 offset: usize,
522 },
523}
524
525/// Random access to immutable text kept by a storage reader.
526pub trait TextSource: std::fmt::Debug + Send + Sync {
527 /// Number of values available.
528 fn len(&self) -> usize;
529 /// Whether this source has no values.
530 fn is_empty(&self) -> bool {
531 self.len() == 0
532 }
533 /// Bytes at one position, or no value when the position is outside the source.
534 fn bytes_at(&self, index: usize) -> Result<Option<&[u8]>>;
535 /// Byte length at one position without requiring the payload when the source has an index.
536 fn bytes_len_at(&self, index: usize) -> Result<Option<usize>> {
537 Ok(self.bytes_at(index)?.map(<[u8]>::len))
538 }
539 /// The byte length at each of `indices`, into the same place of `into`, and zero for a position
540 /// the source does not have.
541 ///
542 /// The same answers as [`bytes_len_at`](Self::bytes_len_at) a position at a time, which is what
543 /// the default does. A source overrides it when it can answer a run of positions for less than
544 /// the run of calls: a length asked once per row goes through a dispatch here, a dispatch in the
545 /// vector and a `Result` at each, and on a column whose lengths are one load each that was most
546 /// of what `STRLEN` cost.
547 fn bytes_lens_at(&self, indices: &[u32], into: &mut [i64]) -> Result<()> {
548 for (slot, &index) in into.iter_mut().zip(indices) {
549 let len = self.bytes_len_at(index as usize)?.unwrap_or_default();
550 *slot = i64::try_from(len).unwrap_or(i64::MAX);
551 }
552 Ok(())
553 }
554 /// Hands `body` the values from `first` up to at most `limit`, and answers where it stopped.
555 ///
556 /// The point of it is what it does not do, which is keep what it read.
557 /// [`bytes_at`](Self::bytes_at) hands back a borrow, so a source that decodes a block to answer
558 /// it has to hold that block for as long as the source lives, and a reader that walks the whole
559 /// source therefore ends up holding the whole thing decoded. On the ClickBench `URL` dictionary
560 /// that is 4.2 GB resident to answer one `LIKE`, and none of it is read twice.
561 ///
562 /// A caller that means to walk a stretch of values once calls this instead and gets the bytes
563 /// on loan for the length of the call. The source decides how much it hands over at a time,
564 /// which for a blocked payload is the rest of the block it had to decode anyway, and answers
565 /// with one past the last value it visited so the caller can come back for the next stretch.
566 /// The answer is always above `first` where `first` is a value this source has, so a loop on it
567 /// finishes.
568 ///
569 /// The default hands over one value through `bytes_at` and is correct for every source. It is
570 /// also pointless for a source that keeps everything anyway, which is every source built in
571 /// memory, and that is the right default for exactly that reason.
572 fn sweep(
573 &self,
574 first: usize,
575 limit: usize,
576 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
577 ) -> Result<usize> {
578 if first >= limit.min(self.len()) {
579 return Ok(first);
580 }
581 body(first, self.bytes_at(first)?.unwrap_or_default())?;
582 Ok(first + 1)
583 }
584 /// Whether the payload block holding `first` might contain `literal` in any value.
585 ///
586 /// A false answer is a proof that every value in the block misses. A source without a stored
587 /// substring signature answers true, which keeps the ordinary exact comparison authoritative.
588 fn might_contain(&self, first: usize, literal: &[u8]) -> Result<bool> {
589 let _ = (first, literal);
590 Ok(true)
591 }
592 /// Hands over the values at `indices`, which rise, without keeping what reading them decoded.
593 ///
594 /// The scattered twin of [`sweep`](Self::sweep). A caller that wants a few hundred values spread
595 /// over the whole source once, which is what turning a frequency synopsis's codes into values
596 /// is, would otherwise leave every block it touched decoded and held for the rest of the
597 /// source's life. On ClickBench `SearchPhrase` that is a hundred and twenty five blocks, the
598 /// larger part of what a query answered out of the synopsis was holding.
599 ///
600 /// `body` is told the position in `indices` and the bytes. The default reads through
601 /// `bytes_at`, which is right for every source that keeps everything anyway.
602 fn visit(
603 &self,
604 indices: &[usize],
605 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
606 ) -> Result<()> {
607 for (at, &index) in indices.iter().enumerate() {
608 body(at, self.bytes_at(index)?.unwrap_or_default())?;
609 }
610 Ok(())
611 }
612 /// Resident bytes retained by this source.
613 fn footprint(&self) -> usize;
614 /// How many ranks this source's sorted value order has, when it has one.
615 ///
616 /// A rank is a position in the values sorted by their bytes, so rank zero is the smallest value
617 /// and rank `ranks() - 1` is the largest. A storage format that keeps a dictionary for a whole
618 /// column can afford to sort the distinct values once when it writes the file, and what that
619 /// buys is a binary search where a reader that only knows the values are distinct has to ask
620 /// every one of them whether it matches.
621 ///
622 /// `None` means the source does not know its order, which is the honest answer for anything
623 /// built in memory and for a file written before its format stored one. Nothing is allowed to
624 /// depend on this for correctness, only for speed.
625 ///
626 /// A source that answers with `Some` promises the ranks cover every value it has, and that
627 /// [`compare_rank`](Self::compare_rank) is consistent with an ordering in which the values are
628 /// strictly increasing. Strictly, which is to say the values are distinct, because what reads
629 /// this searches it, and a search of a run of equal values finds one of them rather than all of
630 /// them. A source that holds the same value twice must answer `None` here even though it could
631 /// sort itself perfectly well.
632 fn ranks(&self) -> Option<usize> {
633 None
634 }
635 /// How the value at `rank` compares against `wanted`.
636 ///
637 /// This is a method rather than a slice of positions the caller indexes because the answer is
638 /// the only thing a search wants, and a source that knows that can answer most probes without
639 /// reading a value at all. A file that stores the first few bytes of each value in rank order
640 /// settles every probe from those bytes except the ones where two values start the same way,
641 /// and the payload stays untouched. A caller handed positions instead would have to read a
642 /// value per probe, which for a dictionary of half a million entries spread over thirty
643 /// megabytes is a fresh block of the file every time.
644 ///
645 /// Only called for a rank below [`ranks`](Self::ranks), so the default is the error a source
646 /// that has no order should never be asked to produce.
647 fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
648 let _ = (rank, wanted);
649 Err(Error::internal("a text source without a sorted order was asked to compare a rank"))
650 }
651 /// How many values sort before `wanted`, and whether one of them is `wanted`.
652 ///
653 /// The whole search rather than a probe of it, so that a source which can answer the same
654 /// question twice without repeating the work is allowed to. The default runs the search through
655 /// [`compare_rank`](Self::compare_rank) and remembers nothing, which is right for a source whose
656 /// probes are cheap.
657 ///
658 /// The reason it is on the trait at all is the top N. `ORDER BY <varchar> LIMIT 10` asks once a
659 /// chunk whether anything left can beat the worst candidate, and the worst candidate stops
660 /// changing long before the chunks run out, so nearly every one of those searches is the one
661 /// before it asked again. A probe of a file backed dictionary is not cheap: it settles on the
662 /// stored head where it can and reads a value where it cannot, and reading a value means
663 /// decoding the payload block it sits in. On ClickBench 25 that search was 29 percent of the
664 /// query's instructions and the block decoding under it another 40.
665 ///
666 /// Only called when [`ranks`](Self::ranks) is `Some`, and `ranks` is what it answered.
667 fn below(&self, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)> {
668 search_below(self, ranks, wanted)
669 }
670 /// The position of the value at `rank`, which is what a search returns once it has found one.
671 ///
672 /// Called about once per search rather than once per probe, so unlike
673 /// [`compare_rank`](Self::compare_rank) it is free to be the expensive one.
674 fn code_at_rank(&self, rank: usize) -> Result<u32> {
675 let _ = rank;
676 Err(Error::internal("a text source without a sorted order was asked for a rank"))
677 }
678 /// The rank of every value, in position order, when the source can hand the whole map over.
679 ///
680 /// This is [`code_at_rank`](Self::code_at_rank) turned round, and it is a separate method
681 /// because the two are wanted by opposite kinds of reader. A search wants one code out of a
682 /// rank and probes a handful of times, so it reads the order a block at a time and leaves the
683 /// rest alone. A min or a max over a grouped column wants a rank out of a code once per row,
684 /// and a walk of the order per row costs far more than reading the order once and turning it
685 /// round. What that buys is a comparison of two integers where the alternative is a fetch of
686 /// two strings out of a payload the size of the column.
687 ///
688 /// The slice is indexed by position and is as long as [`len`](Self::len), so a caller holding a
689 /// dictionary code indexes it directly.
690 ///
691 /// `None` from a source with no order, and from one with an order it would rather not invert.
692 /// Nothing depends on this for correctness, only for speed.
693 fn code_ranks(&self) -> Option<&[u32]> {
694 None
695 }
696 /// Whether another source presents the same values.
697 fn equal(&self, other: &dyn TextSource) -> bool {
698 self.len() == other.len()
699 && (0..self.len()).all(|index| {
700 matches!(
701 (self.bytes_at(index), other.bytes_at(index)),
702 (Ok(left), Ok(right)) if left == right
703 )
704 })
705 }
706}
707
708impl PartialEq for dyn TextSource {
709 fn eq(&self, other: &Self) -> bool {
710 self.equal(other)
711 }
712}
713
714/// The binary search behind [`TextSource::below`], written once so an override can still use it.
715///
716/// A source that remembers its answers overrides `below` to look in what it remembers first, and
717/// then it still has to do the search when it does not find one. This is that search. It carries on
718/// past an equal probe to the first rank holding the value, so what it returns is a boundary rather
719/// than wherever the halving happened to touch down, and the values are distinct so there is exactly
720/// one such rank.
721///
722/// # Errors
723///
724/// Whatever [`TextSource::compare_rank`] gives for a probe.
725pub fn search_below<S>(source: &S, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)>
726where
727 S: TextSource + ?Sized,
728{
729 let mut low = 0;
730 let mut high = ranks;
731 let mut equal = false;
732 while low < high {
733 let middle = low + (high - low) / 2;
734 match source.compare_rank(middle, wanted)? {
735 Ordering::Less => low = middle + 1,
736 Ordering::Greater => high = middle,
737 Ordering::Equal => {
738 equal = true;
739 high = middle;
740 }
741 }
742 }
743 Ok((low, equal))
744}
745
746impl Vector {
747 /// A flat vector of `data`, all valid.
748 ///
749 /// # Errors
750 ///
751 /// If the data's physical layout is not the one the type calls for. That check is here rather
752 /// than left to the caller because a vector whose type and layout disagree is a wrong answer
753 /// waiting to be read out, and it costs one comparison at construction to prevent.
754 pub fn flat(ty: LogicalType, data: Data) -> Result<Self> {
755 let len = data.len();
756 if !matches!(data, Data::Empty) && layout_of(&data) != ty.physical() {
757 return Err(Error::internal(format!(
758 "a {ty} vector cannot hold {:?} data",
759 layout_of(&data)
760 )));
761 }
762 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Flat(data) })
763 }
764
765 /// A flat vector built from single values, with the nulls among them turning into validity.
766 ///
767 /// The slow way in, and the only way in that anything outside this crate has. It is what an
768 /// `INSERT`, a `VALUES` clause and a test build a column with, all of which arrive holding
769 /// values rather than a run of `i32`. Nothing on a scan path calls it: a scan produces a run of
770 /// data directly and hands it to [`Self::flat`].
771 ///
772 /// # Errors
773 ///
774 /// If a value is not one the type can hold, or if the type is one there is no vector for yet,
775 /// which today means `ARRAY` and `UNION`. A `LIST`, a `STRUCT` and a `MAP` are routed to their own
776 /// builders and come back built.
777 pub fn from_values(ty: LogicalType, values: &[Value]) -> Result<Self> {
778 match &ty {
779 LogicalType::List(element) => {
780 return Self::list_from_values(element.as_ref().clone(), values);
781 }
782 LogicalType::Struct(fields) => return Self::struct_from_values(fields, values),
783 LogicalType::Map(key, value) => {
784 return Self::map_from_values(key.as_ref().clone(), value.as_ref().clone(), values);
785 }
786 _ => {}
787 }
788 let mut data = empty_data_for(&ty)?;
789 for value in values {
790 push_value(&mut data, value)?;
791 }
792 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
793 Ok(Self { ty, len: values.len(), validity, body: Body::Flat(data) })
794 }
795
796 /// A list vector of `element`, built from one [`Value::List`] per row.
797 ///
798 /// The elements of every row go into one child vector end to end, so a row's elements are a
799 /// contiguous range of it and a row is a start and a length into it. That is what makes a cut of
800 /// this form the entries and nothing else.
801 ///
802 /// A null row contributes no elements and gets an entry of length zero, which is the same entry
803 /// an empty list gets. The two are told apart by the validity mask rather than by the entry, for
804 /// the reason written on [`Body::Nested`].
805 fn list_from_values(element: LogicalType, values: &[Value]) -> Result<Self> {
806 let mut flat = Vec::new();
807 let mut entries = Vec::with_capacity(values.len());
808 for value in values {
809 let start = u32::try_from(flat.len())
810 .map_err(|_| Error::internal("a list column with more than u32 elements in it"))?;
811 match value {
812 Value::Null => entries.push((start, 0)),
813 Value::List { values: held, .. } => {
814 let len = u32::try_from(held.len())
815 .map_err(|_| Error::internal("a list longer than u32"))?;
816 flat.extend_from_slice(held);
817 entries.push((start, len));
818 }
819 other => {
820 return Err(Error::internal(format!(
821 "{other:?} does not belong in a list vector"
822 )));
823 }
824 }
825 }
826 // The element type is the column's rather than any one value's. A `Value::List` carries what
827 // it thinks it is empty of, and a column built from a row of `INTEGER[]` and a row of
828 // `[]::NULL[]` would otherwise take its type from whichever row came first.
829 let child = Self::from_values(element, &flat)?;
830 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
831 Ok(Self {
832 ty: LogicalType::list(child.ty.clone()),
833 len: values.len(),
834 validity,
835 body: Body::Nested { entries, child: Arc::new(child) },
836 })
837 }
838
839 /// A list vector over a child that already exists, one entry per row.
840 ///
841 /// What a scan and a list returning kernel build, both of which produce the elements in bulk and
842 /// then say which row each range belongs to. Every row is valid, since a caller with nulls to
843 /// record adds them with [`Self::with_validity`].
844 ///
845 /// # Errors
846 ///
847 /// If an entry runs past the end of the child, which would be a row that reads elements belonging
848 /// to nobody and is the one mistake this form makes easy.
849 pub fn list(entries: Vec<(u32, u32)>, child: Vector) -> Result<Self> {
850 let reach = child.len();
851 for &(start, len) in &entries {
852 if start as usize + len as usize > reach {
853 return Err(Error::internal(format!(
854 "a list entry of {len} at {start} in a child of {reach}"
855 )));
856 }
857 }
858 Ok(Self {
859 ty: LogicalType::list(child.ty.clone()),
860 len: entries.len(),
861 validity: Validity::AllValid,
862 body: Body::Nested { entries, child: Arc::new(child) },
863 })
864 }
865
866 /// A struct vector of `fields`, built from one [`Value::Struct`] per row.
867 ///
868 /// One pass per field rather than one pass per row, because each field becomes its own child
869 /// vector and a child is built from a run of values of one type. So a struct of three fields over
870 /// a thousand rows is three calls to [`Self::from_values`] and not a thousand.
871 ///
872 /// The fields are matched by name and not by position. A `Value::Struct` carries its names, and a
873 /// caller that built one in a different order from the type's would otherwise get the values
874 /// silently transposed into the wrong columns, which is the kind of wrong answer that reads as
875 /// right. A row missing a field the type names is an error rather than a null for the same reason.
876 ///
877 /// A null row is a null in every child as well as a false bit in the mask here. [`Body::Fields`]
878 /// says a null struct is allowed to have readable children and that is about a struct built out of
879 /// children that already exist, where whatever is underneath is the caller's. Built from values
880 /// there is nothing underneath to keep, so the children get the null.
881 fn struct_from_values(fields: &[Field], values: &[Value]) -> Result<Self> {
882 let mut children = Vec::with_capacity(fields.len());
883 for field in fields {
884 let mut column = Vec::with_capacity(values.len());
885 for value in values {
886 column.push(match value {
887 Value::Null => Value::Null,
888 Value::Struct(held) => held
889 .iter()
890 .find(|(name, _)| *name == field.name)
891 .map(|(_, held)| held.clone())
892 .ok_or_else(|| {
893 Error::internal(format!(
894 "a struct row with no {} field in it",
895 field.name
896 ))
897 })?,
898 other => {
899 return Err(Error::internal(format!(
900 "{other:?} does not belong in a struct vector"
901 )));
902 }
903 });
904 }
905 children.push(Arc::new(Self::from_values(field.ty.clone(), &column)?));
906 }
907 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
908 Ok(Self {
909 ty: LogicalType::Struct(fields.to_vec()),
910 len: values.len(),
911 validity,
912 body: Body::Fields { children },
913 })
914 }
915
916 /// A struct vector over children that already exist, one per field.
917 ///
918 /// What a scan and a struct returning kernel build, both of which produce each field as a column
919 /// and then put them side by side. Every row is valid, since a caller with nulls to record adds
920 /// them with [`Self::with_validity`].
921 ///
922 /// # Errors
923 ///
924 /// If there are no fields, or if the children are not all the same length. The first is not a
925 /// fussy restriction: a struct vector with no children has no child to take its length from, so a
926 /// zero field struct column would be a length with nothing to check it against, and a caller that
927 /// wants a column of empty structs wants a constant vector of one.
928 pub fn structure(children: Vec<(String, Vector)>) -> Result<Self> {
929 let Some((_, first)) = children.first() else {
930 return Err(Error::internal("a struct vector of no fields, which has no length"));
931 };
932 let len = first.len();
933 for (name, child) in &children {
934 if child.len() != len {
935 return Err(Error::internal(format!(
936 "a {} field of {} rows beside a struct of {len}",
937 name,
938 child.len()
939 )));
940 }
941 }
942 let fields = children
943 .iter()
944 .map(|(name, child)| Field::new(name.clone(), child.ty.clone()))
945 .collect();
946 let children = children.into_iter().map(|(_, child)| Arc::new(child)).collect();
947 Ok(Self {
948 ty: LogicalType::Struct(fields),
949 len,
950 validity: Validity::AllValid,
951 body: Body::Fields { children },
952 })
953 }
954
955 /// The children, for a struct vector, and `None` for any other form.
956 ///
957 /// The accessor a kernel over a struct column reads, and the reason field extraction is free:
958 /// picking one field out of a struct is picking one of these, so a projection of `s.a` hands back
959 /// a vector that already exists rather than reading a row at a time and rebuilding a column.
960 #[must_use]
961 pub fn struct_parts(&self) -> Option<&[Arc<Self>]> {
962 match &self.body {
963 Body::Fields { children } => Some(children),
964 _ => None,
965 }
966 }
967
968 /// A map vector, built from one [`Value::Map`] per row.
969 ///
970 /// A map is a list whose child is a two field struct of keys and values, which is what DuckDB
971 /// stores and what Arrow and Parquet store, so this is the list builder and the struct builder
972 /// composed rather than a third layout. The keys of every row go into one column end to end, the
973 /// values into another beside it, and a row is a start and a length into the pair.
974 ///
975 /// The field names are [`MAP_KEY`] and [`MAP_VALUE`] because those are the names DuckDB gives them
976 /// and the names anything reading a Parquet map field will expect to find.
977 ///
978 /// A null row and an empty map are both an entry of length zero, told apart by the validity mask,
979 /// for the reason written on [`Body::Nested`].
980 fn map_from_values(key: LogicalType, value: LogicalType, values: &[Value]) -> Result<Self> {
981 let mut keys = Vec::new();
982 let mut held = Vec::new();
983 let mut entries = Vec::with_capacity(values.len());
984 for row in values {
985 let start = u32::try_from(keys.len())
986 .map_err(|_| Error::internal("a map column with more than u32 entries in it"))?;
987 match row {
988 Value::Null => entries.push((start, 0)),
989 Value::Map { entries: pairs, .. } => {
990 let len = u32::try_from(pairs.len())
991 .map_err(|_| Error::internal("a map with more than u32 entries"))?;
992 for (one, other) in pairs {
993 keys.push(one.clone());
994 held.push(other.clone());
995 }
996 entries.push((start, len));
997 }
998 other => {
999 return Err(Error::internal(format!(
1000 "{other:?} does not belong in a map vector"
1001 )));
1002 }
1003 }
1004 }
1005 // The two types are the column's rather than any one row's, for the reason the list builder
1006 // takes the element type from the column: a row that is the empty map carries whatever it was
1007 // built as being empty of, and the column is not entitled to take its type from that.
1008 let child = Self::structure(vec![
1009 (MAP_KEY.to_string(), Self::from_values(key, &keys)?),
1010 (MAP_VALUE.to_string(), Self::from_values(value, &held)?),
1011 ])?;
1012 let ty = LogicalType::map(
1013 fields_of(&child.ty)[0].ty.clone(),
1014 fields_of(&child.ty)[1].ty.clone(),
1015 );
1016 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
1017 Ok(Self {
1018 ty,
1019 len: values.len(),
1020 validity,
1021 body: Body::Nested { entries, child: Arc::new(child) },
1022 })
1023 }
1024
1025 /// A map vector over a pair of columns that already exist, one entry per row.
1026 ///
1027 /// What a scan and a map returning kernel build. The keys and the values are two columns of the
1028 /// same length, and each row of the map is the same range of both. Every row is valid, since a
1029 /// caller with nulls to record adds them with [`Self::with_validity`].
1030 ///
1031 /// # Errors
1032 ///
1033 /// If the two columns are different lengths, or if an entry runs past the end of them.
1034 pub fn map(entries: Vec<(u32, u32)>, keys: Vector, values: Vector) -> Result<Self> {
1035 let key = keys.ty.clone();
1036 let value = values.ty.clone();
1037 let child =
1038 Self::structure(vec![(MAP_KEY.to_string(), keys), (MAP_VALUE.to_string(), values)])?;
1039 let mut vector = Self::list(entries, child)?;
1040 vector.ty = LogicalType::map(key, value);
1041 Ok(vector)
1042 }
1043
1044 /// The entries and the two columns, for a map vector, and `None` for anything else.
1045 ///
1046 /// Reaches through the struct child that a map is stored as, so that a kernel over a map column
1047 /// reads the keys and the values as the two columns they are rather than having to know that the
1048 /// pair is spelled as a struct underneath.
1049 #[must_use]
1050 pub fn map_parts(&self) -> Option<MapParts<'_>> {
1051 if !matches!(self.ty, LogicalType::Map(_, _)) {
1052 return None;
1053 }
1054 let (entries, child) = self.list_parts()?;
1055 let [keys, values] = child.struct_parts()? else { return None };
1056 Some((entries, keys, values))
1057 }
1058
1059 /// The entries and the child, for a list vector, and `None` for any other form.
1060 ///
1061 /// The accessor a kernel over a list column reads, for the reason
1062 /// [`Self::dictionary_parts`] exists: `unnest` over 1024 rows wants the child once and the
1063 /// entries once, and reading it through [`Self::value_at`] would build a `Value::List` per row
1064 /// and then throw every one of them away.
1065 ///
1066 /// A map answers here as well, with the struct child it is stored as, because this is a question
1067 /// about the layout and a map's layout is a list's. A caller that wants the keys and the values as
1068 /// two columns wants [`Self::map_parts`], which reaches through that child.
1069 #[must_use]
1070 pub fn list_parts(&self) -> Option<(&[(u32, u32)], &Self)> {
1071 match &self.body {
1072 Body::Nested { entries, child } => Some((entries, child)),
1073 _ => None,
1074 }
1075 }
1076
1077 /// A vector of `len` copies of one value.
1078 ///
1079 /// Costs one value regardless of the length, which is what makes a literal in a predicate free
1080 /// and what makes a projection of a constant free.
1081 #[must_use]
1082 pub fn constant(ty: LogicalType, value: Value, len: usize) -> Self {
1083 let validity = if value.is_null() { Validity::AllInvalid } else { Validity::AllValid };
1084 Self { ty, len, validity, body: Body::Constant(Box::new(value)) }
1085 }
1086
1087 /// A vector of `len` values starting at `start` and stepping by `step`.
1088 ///
1089 /// This is what a row identifier column is, and it costs sixteen bytes rather than eight
1090 /// kilobytes. A scan that produces row ids for a later fetch produces one of these.
1091 #[must_use]
1092 pub fn sequence(start: i64, step: i64, len: usize) -> Self {
1093 Self {
1094 ty: LogicalType::BigInt,
1095 len,
1096 validity: Validity::AllValid,
1097 body: Body::Sequence { start, step },
1098 }
1099 }
1100
1101 /// A vector of codes into a smaller vector of distinct values.
1102 ///
1103 /// The form the whole M3 thesis rests on. A dictionary vector handed to a group by is an
1104 /// integer column, and an aggregate over one is an aggregate over integers no matter what the
1105 /// logical type says.
1106 ///
1107 /// A dictionary over a dictionary is composed into one level here rather than left as two, so
1108 /// the form has a depth of one always and a kernel that reads [`Self::dictionary_parts`] is
1109 /// reading the values rather than another layer of codes. Two filters over the same chunk build
1110 /// the second case and four conjuncts pushed down separately build four of it.
1111 ///
1112 /// The cost of leaving them stacked turned out to be a cliff rather than a slope. Every loop in
1113 /// `rudb-kernels` reaches for the values behind the codes with [`Self::data`], a dictionary
1114 /// pointing at a dictionary has no data to hand back, so the second level does not make the
1115 /// kernels slower, it turns them off and drops the work onto the row at a time path that exists
1116 /// to be correct rather than fast. Measured on server3 over a chunk of two numeric columns and a
1117 /// consumer of two vectorized passes, one level reads at 3.5 nanoseconds a row and two levels at
1118 /// 104, and the third and fourth levels cost almost nothing more because the first one had
1119 /// already given up everything there was to give. Composing is one pass over the outer codes,
1120 /// which the range check above is already making.
1121 ///
1122 /// The one dictionary that is not composed past is one carrying a validity of its own. A
1123 /// dictionary is built all valid and only [`Self::with_validity`] can change that, so such a
1124 /// vector is saying that its nulls are at this level rather than in the values it points at, and
1125 /// composing past it would drop them.
1126 ///
1127 /// # Errors
1128 ///
1129 /// If any code is past the end of the value vector.
1130 pub fn dictionary(codes: Vec<u32>, values: Vector) -> Result<Self> {
1131 Self::dictionary_over(codes, Arc::new(values))
1132 }
1133
1134 /// The same, over a set of values somebody else is holding too.
1135 ///
1136 /// The body holds its values in an `Arc` either way, so a caller that already has one has
1137 /// nothing to hand over but a pointer. The caller this is for is a Parquet chunk: one dictionary
1138 /// page serves every data page of the chunk, and going through [`Self::dictionary`] meant
1139 /// copying the whole dictionary into each page's vector on the way to putting it in an `Arc`
1140 /// that then had a single holder. On a ClickBench scan that copy was sixteen percent of the
1141 /// instructions the query ran.
1142 ///
1143 /// Composing a dictionary over a dictionary keeps the handle too. The leaf of the stack is what
1144 /// the composed dictionary points at and neither its values nor anything about it changes, so
1145 /// there is nothing to own and the new dictionary shares the same leaf the old one did.
1146 ///
1147 /// The range check takes the highest code rather than stopping at the first bad one. Stopping
1148 /// early sounds cheaper and is not, because a loop that can exit anywhere cannot be vectorized
1149 /// and a running maximum can, and the only run that would have exited early is the one about to
1150 /// fail the query anyway. Every other run reads the whole of `codes` either way. It was 5.2
1151 /// percent of a ClickBench scan as a `find`.
1152 ///
1153 /// # Errors
1154 ///
1155 /// If any code is past the end of the value vector.
1156 pub fn dictionary_over(codes: Vec<u32>, values: Arc<Vector>) -> Result<Self> {
1157 let highest = codes.iter().copied().fold(0, u32::max);
1158 if !codes.is_empty() && highest as usize >= values.len() {
1159 return Err(Error::internal(format!(
1160 "dictionary code {highest} is past the end of a {} value dictionary",
1161 values.len()
1162 )));
1163 }
1164 let (codes, values) = compose(codes, values);
1165 Ok(Self {
1166 ty: values.ty.clone(),
1167 len: codes.len(),
1168 validity: Validity::AllValid,
1169 body: Body::Dictionary { codes, values, stable: false },
1170 })
1171 }
1172
1173 /// A dictionary whose codes keep the same meaning across every page of its source.
1174 pub fn stable_dictionary(codes: Vec<u32>, values: Arc<Vector>) -> Result<Self> {
1175 let mut vector = Self::dictionary_over(codes, values)?;
1176 if let Body::Dictionary { stable, .. } = &mut vector.body {
1177 *stable = true;
1178 }
1179 Ok(vector)
1180 }
1181
1182 /// A stable dictionary whose caller already found the largest code while decoding it.
1183 pub fn stable_dictionary_validated(
1184 codes: Vec<u32>,
1185 values: Arc<Vector>,
1186 highest: Option<u32>,
1187 ) -> Result<Self> {
1188 if highest.is_some_and(|code| code as usize >= values.len()) {
1189 return Err(Error::internal("a stable dictionary code is past its value dictionary"));
1190 }
1191 Ok(Self {
1192 ty: values.ty.clone(),
1193 len: codes.len(),
1194 validity: Validity::AllValid,
1195 body: Body::Dictionary { codes, values, stable: true },
1196 })
1197 }
1198
1199 /// One row of `source` per id, without reading any of them.
1200 ///
1201 /// What a link join emits for each of its parent columns, per `spec/graph/08-vector-engine.md`
1202 /// section 8.2. Row `r` is row `rids[r]` of `source`, and is null where that is [`NO_ROW`].
1203 ///
1204 /// The ids are taken by `Arc` rather than by value because one link join fills one buffer of
1205 /// parent rows per child chunk and then hands the same buffer to every projected parent column,
1206 /// so a gather of eight columns is eight pointers and one buffer. [`Self::gathered_from`] is the
1207 /// same thing starting part way in, which is what a cut of one produces.
1208 ///
1209 /// # Errors
1210 ///
1211 /// If an id is past the end of the source and is not [`NO_ROW`]. That check is a pass over the
1212 /// ids and it is the only thing standing between a link built against the wrong parent and a
1213 /// read of whatever happens to be at that offset, so it is not optional and it is not deferred:
1214 /// `spec/graph/03-the-file-format.md` section 3.1 says a stale section is ignored rather than
1215 /// repaired, and this is where a stale one stops being ignorable.
1216 pub fn gathered(source: Arc<Vector>, rids: Arc<Vec<u32>>) -> Result<Self> {
1217 let len = rids.len();
1218 Self::gathered_from(source, rids, 0, len)
1219 }
1220
1221 /// The same, reading `len` ids starting at `offset`.
1222 ///
1223 /// # Errors
1224 ///
1225 /// If the range runs past the end of the ids, or if an id in it is past the end of the source.
1226 pub fn gathered_from(
1227 source: Arc<Vector>,
1228 rids: Arc<Vec<u32>>,
1229 offset: usize,
1230 len: usize,
1231 ) -> Result<Self> {
1232 let end = offset.checked_add(len).ok_or_else(|| Error::internal("a gather that wraps"))?;
1233 let Some(taken) = rids.get(offset..end) else {
1234 return Err(Error::internal(format!(
1235 "rows {offset} to {end} of a gather over {} ids",
1236 rids.len()
1237 )));
1238 };
1239 let rows = source.len();
1240 if taken.iter().any(|&rid| rid != NO_ROW && rid as usize >= rows) {
1241 return Err(Error::internal(format!(
1242 "a gathered row id is past the {rows} rows of its source"
1243 )));
1244 }
1245 Ok(Self {
1246 ty: source.ty.clone(),
1247 len,
1248 // The mask is all valid and the nulls are real, which is the same split a dictionary
1249 // makes: this level says every row exists and the body says what each one holds, and
1250 // `is_null_at` reads through to answer. A mask here would be a second copy of what the
1251 // ids already say and the two could disagree.
1252 validity: Validity::AllValid,
1253 body: Body::Gathered { source, rids, offset },
1254 })
1255 }
1256
1257 /// The source and the ids of a gathered vector, and `None` for any other form.
1258 #[must_use]
1259 pub fn gathered_parts(&self) -> Option<(&Arc<Self>, &[u32])> {
1260 match &self.body {
1261 Body::Gathered { source, rids, offset } => {
1262 Some((source, rids.get(*offset..offset + self.len)?))
1263 }
1264 _ => None,
1265 }
1266 }
1267
1268 /// Whether a kernel over this vector should fold over the source once and then index.
1269 ///
1270 /// Section 8.2's dispatch rule, which is one comparison and is the whole difference between a
1271 /// gather and a dictionary. Every kernel with a dictionary arm already folds over the values
1272 /// once and indexes, and that arm is right for a gather exactly when the source is shorter than
1273 /// the rows being answered. A dictionary always is, by construction. A gather off a parent
1274 /// table almost never is, and a kernel that took the dictionary arm anyway would read fifteen
1275 /// million parent rows to answer two thousand child ones.
1276 ///
1277 /// `false` for every other form, so a kernel can ask this without first asking what it has.
1278 #[must_use]
1279 pub fn fold_over_source(&self) -> bool {
1280 match &self.body {
1281 Body::Gathered { source, .. } => source.len() < self.len,
1282 _ => false,
1283 }
1284 }
1285
1286 /// A vector of runs, one value each, with the row each run ends at.
1287 ///
1288 /// `ends` is exclusive and strictly increasing, so run `i` covers the rows from `ends[i - 1]` to
1289 /// `ends[i]` and run zero starts at nothing. The length of the vector is the last end.
1290 ///
1291 /// The depth is one, the same way a dictionary's is, and for a sharper reason. Every kernel that
1292 /// wants runs wants the value of a run without another search, and a run length vector over a
1293 /// run length vector turns one search into two and then into three. Rather than compose, this
1294 /// refuses: nothing in the engine builds a stacked one, because [`Self::run_encoded`] only ever
1295 /// reads a flat body, so a stacked one is a caller doing something by hand and the useful answer
1296 /// is to say so rather than to quietly do a pass of work they did not ask for.
1297 ///
1298 /// A run over a dictionary is fine and is not that case. The two forms answer different
1299 /// questions and a column that is both clustered and low cardinality genuinely wants both.
1300 ///
1301 /// # Errors
1302 ///
1303 /// If there is not exactly one value per run, if the ends do not increase, or if the values are
1304 /// themselves run length encoded.
1305 pub fn runs(ends: Vec<u32>, values: Vector) -> Result<Self> {
1306 if matches!(values.body, Body::Runs { .. }) {
1307 return Err(Error::internal("runs of runs, which is two searches to read one row"));
1308 }
1309 if ends.len() != values.len() {
1310 return Err(Error::internal(format!(
1311 "{} runs and {} values to put in them",
1312 ends.len(),
1313 values.len()
1314 )));
1315 }
1316 if ends.windows(2).any(|pair| pair[0] >= pair[1]) || ends.first() == Some(&0) {
1317 return Err(Error::internal("run ends that do not increase"));
1318 }
1319 let len = ends.last().copied().unwrap_or(0) as usize;
1320 Ok(Self {
1321 ty: values.ty.clone(),
1322 len,
1323 validity: Validity::AllValid,
1324 body: Body::Runs { ends, values: Arc::new(values) },
1325 })
1326 }
1327
1328 /// The same values as runs, when there are few enough runs for that to be smaller.
1329 ///
1330 /// Costs one pass over the column to find out, which is why this is a call somebody makes rather
1331 /// than something a constructor does. The decision is the same arithmetic every time: a row in
1332 /// flat form costs one value, a run costs one value plus the four bytes of its end, so runs are
1333 /// smaller once there are fewer than about half as many runs as rows, and the narrower the
1334 /// column the more runs it takes. `RUNS_PAY_AT` is that ratio, written down rather than spelt
1335 /// into an `if`, because it is the number a sweep will want to move.
1336 ///
1337 /// Only a flat body is looked at. A constant and a sequence are already one value and two
1338 /// numbers, so there is nothing to win, and a dictionary that is also clustered is a real case
1339 /// that wants its codes run length encoded rather than its values, which is a different function
1340 /// and not this one.
1341 ///
1342 /// Two adjacent nulls are one run. Two adjacent equal values with a null between them are three,
1343 /// because the null is a value of the column as far as anything reading it is concerned.
1344 ///
1345 /// # Errors
1346 ///
1347 /// From the gather this does at the end, and nowhere else. A body that is not flat comes back
1348 /// unchanged rather than as an error, so a nested vector never reaches the part that can fail.
1349 pub fn run_encoded(&self) -> Result<Self> {
1350 let Body::Flat(data) = &self.body else {
1351 return Ok(self.clone());
1352 };
1353 let ends = boundaries(data, &self.validity, self.len);
1354 if ends.len().saturating_mul(RUNS_PAY_AT) >= self.len {
1355 return Ok(self.clone());
1356 }
1357 let starts: Vec<u32> =
1358 std::iter::once(0).chain(ends.iter().copied()).take(ends.len()).collect();
1359 Self::runs(ends, self.gather(&starts)?)
1360 }
1361
1362 /// A vector of `len` integers packed `width` bits each, every one an offset from `base`.
1363 ///
1364 /// The way in for a reader that already has the packed bits, which is what a column file holds
1365 /// and what a network frame carries. Nothing unpacks on the way in, so a scan of a packed column
1366 /// hands the bits straight to the chunk and the cost of the form is paid by whoever reads a
1367 /// value rather than by the scan.
1368 ///
1369 /// The range check is on the two ends rather than on every code, which is the whole check. A
1370 /// code is between zero and `2^width - 1` by construction, so if `base` and `base + 2^width - 1`
1371 /// both fit the column's layout then every value does, and that is two comparisons instead of
1372 /// one per row.
1373 ///
1374 /// # Errors
1375 ///
1376 /// If the type is not one of the integer layouts, if the width is not between one and
1377 /// [`PACKED_WIDTH_MAX`], if there are not enough words for the length, or if either end of the
1378 /// range would not fit the type.
1379 pub fn packed(
1380 ty: LogicalType,
1381 words: Vec<u64>,
1382 width: u32,
1383 base: i128,
1384 len: usize,
1385 ) -> Result<Self> {
1386 let Some((low, high)) = layout_range(&ty) else {
1387 return Err(Error::internal(format!("a {ty} vector has no integer layout to pack")));
1388 };
1389 if width == 0 || width > PACKED_WIDTH_MAX {
1390 return Err(Error::internal(format!(
1391 "a packed width of {width}, which is outside 1 to {PACKED_WIDTH_MAX}"
1392 )));
1393 }
1394 let needed = words_for(len, width);
1395 if words.len() < needed {
1396 return Err(Error::internal(format!(
1397 "{} words for {len} values of {width} bits, which needs {needed}",
1398 words.len()
1399 )));
1400 }
1401 let top = base + i128::from(u64::MAX >> (64 - width));
1402 if base < low || top > high {
1403 return Err(Error::internal(format!(
1404 "packed values from {base} to {top}, which a {ty} cannot hold"
1405 )));
1406 }
1407 Ok(Self {
1408 ty,
1409 len,
1410 validity: Validity::AllValid,
1411 body: Body::Packed { words: Arc::new(words), width, base, offset: 0 },
1412 })
1413 }
1414
1415 /// The same values bit packed, when the range of the column makes that smaller.
1416 ///
1417 /// Costs one pass to find the range and one to write the bits, which is why this is a call
1418 /// somebody makes rather than something a constructor does. It is the counterpart of
1419 /// [`Self::run_encoded`] and the decision has the same shape: a row flat costs the width of its
1420 /// layout, a row packed costs the bits the column's range needs, and the form is worth having
1421 /// only when the second is a good deal smaller than the first. [`PACKING_PAYS_AT`] is that
1422 /// ratio, written down rather than spelt into an `if`, because it is the number a sweep will
1423 /// want to move.
1424 ///
1425 /// Only a flat integer body is looked at. A constant and a sequence are already smaller than any
1426 /// packing of them, a dictionary's codes are the thing that would want packing rather than its
1427 /// values, and a float has no range to pack into since the bits of an `f64` are not an integer
1428 /// that arithmetic on the column agrees with.
1429 ///
1430 /// The range is taken over every slot including the null ones, which hold a zero. A column of
1431 /// large values with one null in it therefore packs a range that reaches down to zero and comes
1432 /// out wider than it needed to be. The alternative is a pass that consults the validity per slot
1433 /// to find the range and a second rule for what to write into a null slot, and this form exists
1434 /// to make reads cheap rather than to squeeze the last bit out of a sparse column.
1435 ///
1436 /// A column whose values are all the same packs to nothing at all, and rather than invent a zero
1437 /// bit code this declines and leaves it to [`Self::run_encoded`], which turns that column into
1438 /// one run and is smaller than any packing of it.
1439 ///
1440 /// # Errors
1441 ///
1442 /// If the packed bits and the length disagree, which would be a bug here rather than a caller
1443 /// doing something wrong.
1444 pub fn bit_packed(&self) -> Result<Self> {
1445 let Body::Flat(data) = &self.body else {
1446 return Ok(self.clone());
1447 };
1448 let Some((low, high)) = span_of(data, self.len) else {
1449 return Ok(self.clone());
1450 };
1451 let Some(range) = high.checked_sub(low).and_then(|range| u64::try_from(range).ok()) else {
1452 return Ok(self.clone());
1453 };
1454 let width = u64::BITS - range.leading_zeros();
1455 if width == 0 || width > PACKED_WIDTH_MAX {
1456 return Ok(self.clone());
1457 }
1458 if words_for(self.len, width) * size_of::<u64>() * PACKING_PAYS_AT > data.footprint() {
1459 return Ok(self.clone());
1460 }
1461 let words = pack(data, self.len, low, width);
1462 let packed = Self::packed(self.ty.clone(), words, width, low, self.len)?;
1463 Ok(packed.with_validity(self.validity.clone()))
1464 }
1465
1466 /// A vector of string views over an arena somebody else is holding too.
1467 ///
1468 /// The way in for a scan that has a page of strings and wants several chunks over it. Each chunk
1469 /// gets its own run of views and they all share the one arena, so the bytes are read where the
1470 /// page put them and nothing copies them.
1471 ///
1472 /// Every view is checked against the arena here rather than when a row is read. That is a pass
1473 /// over the views at construction, which is the same pass the caller just did to build them, and
1474 /// what it buys is that a row of this form cannot resolve to bytes that are not there. The check
1475 /// is on the offsets and not on the bytes, so it says nothing about whether the payload is text,
1476 /// which is the same promise a `BLOB` column makes.
1477 ///
1478 /// # Errors
1479 ///
1480 /// If the type is not one stored as views, or if a view points past the end of the arena.
1481 pub fn string_views(
1482 ty: LogicalType,
1483 views: Vec<StringView>,
1484 arena: Arc<Buffer<u8>>,
1485 ) -> Result<Self> {
1486 if ty.physical() != rudb_common::PhysicalType::Varlen {
1487 return Err(Error::internal(format!("a {ty} vector cannot hold string views")));
1488 }
1489 if views.iter().any(|view| view.bytes_in(&arena).is_none()) {
1490 return Err(Error::internal("a string view points past the end of its arena"));
1491 }
1492 let len = views.len();
1493 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Views { views, arena } })
1494 }
1495
1496 /// A text vector whose values remain in a storage source until they are read.
1497 pub fn external_text(ty: LogicalType, source: Arc<dyn TextSource>) -> Result<Self> {
1498 if ty.physical() != rudb_common::PhysicalType::Varlen {
1499 return Err(Error::internal(format!(
1500 "a {ty} vector cannot use an external text source"
1501 )));
1502 }
1503 let len = source.len();
1504 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::ExternalText { source } })
1505 }
1506
1507 /// The same strings, in a form where a cut of them does not copy the bytes.
1508 ///
1509 /// The counterpart of [`Self::run_encoded`] and [`Self::bit_packed`] for a string column, and
1510 /// the only one of the three that takes `self` by value. It has to: what it does is move the
1511 /// arena into an `Arc` so nothing copies it again, and a version taking `&self` would start by
1512 /// copying the arena once to have one to move.
1513 ///
1514 /// Anything that is not a flat string column comes back as it was, which includes a column that
1515 /// is already in this form.
1516 ///
1517 /// # Errors
1518 ///
1519 /// Nothing here fails today. The result is a `Result` because the check inside
1520 /// [`Self::string_views`] is worth running on the views this builds rather than trusting that
1521 /// this function built them right.
1522 pub fn shared_text(self) -> Result<Self> {
1523 let Body::Flat(Data::Varlen(column)) = self.body else {
1524 return Ok(self);
1525 };
1526 let (views, arena) = column.into_parts();
1527 let shared = Self::string_views(self.ty, views, Arc::new(arena))?;
1528 Ok(shared.with_validity(self.validity))
1529 }
1530
1531 /// A vector of FSST codes against a table somebody else trained.
1532 ///
1533 /// The way in for a reader that has a page of compressed strings and the table that goes with
1534 /// it. The codes are not copied and the table is not retrained, so laying several chunks over
1535 /// one page costs the spans and nothing else.
1536 ///
1537 /// # Errors
1538 ///
1539 /// If the type is not one stored as text, or if a span runs past the end of the codes.
1540 pub fn coded(
1541 ty: LogicalType,
1542 codes: Arc<Vec<u8>>,
1543 spans: Vec<(u32, u32)>,
1544 table: Arc<SymbolTable>,
1545 ) -> Result<Self> {
1546 if ty.physical() != rudb_common::PhysicalType::Varlen {
1547 return Err(Error::internal(format!("a {ty} vector cannot hold FSST codes")));
1548 }
1549 let end = u32::try_from(codes.len()).unwrap_or(u32::MAX);
1550 if spans.iter().any(|&(from, to)| from > to || to > end) {
1551 return Err(Error::internal("an FSST span runs past the end of the codes"));
1552 }
1553 let len = spans.len();
1554 Ok(Self {
1555 ty,
1556 len,
1557 validity: Validity::AllValid,
1558 body: Body::Coded { codes, spans, table },
1559 })
1560 }
1561
1562 /// The same strings, compressed against a table trained on them.
1563 ///
1564 /// The counterpart of [`Self::run_encoded`] and [`Self::bit_packed`] for a text column, and it
1565 /// takes `self` by value for the reason [`Self::shared_text`] does.
1566 ///
1567 /// The table is trained on every row rather than on a sample. A vector is at most 1024 rows, so
1568 /// the sample would be most of the column anyway, and the systematic sampling
1569 /// `spec/06-compression.md` section 6.3 asks for is a decision about a page and belongs to
1570 /// whoever is holding one.
1571 ///
1572 /// It declines unless the codes are at most half the bytes the strings are. FSST gets about that
1573 /// on text and rather less on anything already short or already random, and below that the
1574 /// decompression per row read is not bought back. A column it declines on comes back as it was.
1575 ///
1576 /// # Errors
1577 ///
1578 /// Nothing here fails today. The result is a `Result` because the checks inside [`Self::coded`]
1579 /// are worth running on what this builds rather than trusting that this built it right.
1580 pub fn compressed(self) -> Result<Self> {
1581 let Body::Flat(Data::Varlen(column)) = &self.body else {
1582 return Ok(self);
1583 };
1584 let rows: Vec<&[u8]> = (0..self.len).filter_map(|row| column.bytes(row)).collect();
1585 if rows.len() != self.len {
1586 return Ok(self);
1587 }
1588 let plain: usize = rows.iter().map(|row| row.len()).sum();
1589 let table = SymbolTable::train(&rows);
1590 let mut codes = Vec::with_capacity(plain);
1591 let mut spans = Vec::with_capacity(self.len);
1592 for row in &rows {
1593 let from = u32::try_from(codes.len()).unwrap_or(u32::MAX);
1594 table.compress(row, &mut codes);
1595 spans.push((from, u32::try_from(codes.len()).unwrap_or(u32::MAX)));
1596 }
1597 if codes.len() * FSST_PAYS_AT > plain {
1598 return Ok(self);
1599 }
1600 let coded = Self::coded(self.ty.clone(), Arc::new(codes), spans, Arc::new(table))?;
1601 Ok(coded.with_validity(self.validity.clone()))
1602 }
1603
1604 /// The same values under a wider decimal type that stores them the same way.
1605 ///
1606 /// A decimal is kept as its unscaled integer, so two decimal types with one scale and one
1607 /// storage width describe the same bits, and going from the narrower of them to the wider is a
1608 /// relabelling rather than a conversion. The binder writes three of those into
1609 /// `l_extendedprice * (1 - l_discount)`, because a product's operands are given the answer's
1610 /// width and the answer's width is eighteen while both columns are fifteen, and each one was a
1611 /// pass over six million rows that wrote back the bytes it had just read.
1612 ///
1613 /// A flat run only, and deliberately. The general cast flattens whatever it is given, so a
1614 /// dictionary column came out of a width change as a run of values, and a relabelling that kept
1615 /// the dictionary would hand the arithmetic above two columns it has to read through a code per
1616 /// row instead of two it can read end to end. That was measured and it is the worse of the two:
1617 /// on `sum(l_extendedprice * l_discount)` under the filter q6 puts on it, where the rows left
1618 /// are few and scattered and the indirection is a cache miss each, keeping the dictionary cost
1619 /// half again as much as the flattening it saved. The flat case has no such question, since
1620 /// what it hands on is exactly what the pass would have built.
1621 ///
1622 /// Only widening, because a narrower width is a range every value has to be checked against and
1623 /// checking it is the pass this exists to avoid. `None` for anything else, including a narrower
1624 /// width, a changed scale, a changed storage width and any form but the flat one.
1625 #[must_use]
1626 pub fn as_wider_decimal(&self, target: &LogicalType) -> Option<Self> {
1627 let (
1628 LogicalType::Decimal { width: from, scale: held },
1629 LogicalType::Decimal { width: into, scale },
1630 ) = (&self.ty, target)
1631 else {
1632 return None;
1633 };
1634 if held != scale || from > into || self.ty.decimal_storage() != target.decimal_storage() {
1635 return None;
1636 }
1637 // Nothing in a flat run says what its numbers mean, so the relabelling is the type and
1638 // nothing else, and the buffer underneath is shared rather than copied.
1639 if !matches!(self.body, Body::Flat(_)) {
1640 return None;
1641 }
1642 Some(Self {
1643 ty: target.clone(),
1644 len: self.len,
1645 validity: self.validity.clone(),
1646 body: self.body.clone(),
1647 })
1648 }
1649
1650 /// The same vector with a different validity.
1651 #[must_use]
1652 pub fn with_validity(mut self, validity: Validity) -> Self {
1653 self.validity = validity;
1654 self
1655 }
1656
1657 /// What kind of values these are.
1658 #[must_use]
1659 pub fn logical_type(&self) -> &LogicalType {
1660 &self.ty
1661 }
1662
1663 /// How many values there are.
1664 #[must_use]
1665 pub fn len(&self) -> usize {
1666 self.len
1667 }
1668
1669 /// Whether there are no values.
1670 #[must_use]
1671 pub fn is_empty(&self) -> bool {
1672 self.len == 0
1673 }
1674
1675 /// How many bytes of memory this vector is holding.
1676 ///
1677 /// What the memory limit charges for it. A constant and a sequence hold one value and two
1678 /// numbers however long they are, which is the point of both forms, so the number here is the
1679 /// form's cost and not the column's width times its length.
1680 ///
1681 /// A part that is behind an `Arc` counts as one holder's share of it, which is
1682 /// [`Buffer::footprint`]'s rule for a shared page applied to the other shared parts. A
1683 /// dictionary counted in full in every vector sharing it is not a conservative over count, it is
1684 /// a number with the chunk count in it: an aggregate that emits nineteen thousand chunks of
1685 /// groups out of one stable dictionary reported that dictionary nineteen thousand times and
1686 /// refused itself a budget of twenty five gigabytes while the process held one. Dividing by the
1687 /// holders makes the sum over everything sharing the part come to about the part, which is what
1688 /// the number is supposed to mean, and it errs high rather than low whenever the holders arrive
1689 /// one after another, because each of them counts what it sees at the time it asks.
1690 #[must_use]
1691 pub fn footprint(&self) -> usize {
1692 let body = match &self.body {
1693 Body::Flat(data) => data.footprint(),
1694 Body::Constant(value) => value.footprint(),
1695 Body::Sequence { .. } => 0,
1696 Body::Dictionary { codes, values, .. } => {
1697 codes.capacity() * size_of::<u32>() + share(values.footprint(), values)
1698 }
1699 Body::Packed { words, .. } => share(words.capacity() * size_of::<u64>(), words),
1700 Body::Views { views, arena } => {
1701 views.capacity() * size_of::<StringView>() + share(arena.footprint(), arena)
1702 }
1703 Body::ExternalText { source } => share(source.footprint(), source),
1704 Body::Coded { codes, spans, table } => {
1705 share(codes.capacity(), codes)
1706 + spans.capacity() * size_of::<(u32, u32)>()
1707 + share(table.footprint(), table)
1708 }
1709 Body::Runs { ends, values } => {
1710 ends.capacity() * size_of::<u32>() + share(values.footprint(), values)
1711 }
1712 // The ids are shared between every cut of one link join's output, and the source is
1713 // shared with every other column gathered off the same parent, so both are divided by
1714 // their holders for the reason the dictionary above is. A gather whose source counted in
1715 // full would report a parent table per projected column per chunk.
1716 Body::Gathered { source, rids, .. } => {
1717 share(rids.capacity() * size_of::<u32>(), rids) + share(source.footprint(), source)
1718 }
1719 Body::Nested { entries, child } => {
1720 entries.capacity() * size_of::<(u32, u32)>() + share(child.footprint(), child)
1721 }
1722 // A struct is as wide as its fields are, so this is the one body whose cost is a sum
1723 // over children rather than one number, and a struct of a hundred narrow fields costs
1724 // what the hundred columns cost.
1725 Body::Fields { children } => {
1726 children.capacity() * size_of::<Arc<Self>>()
1727 + children.iter().map(|child| share(child.footprint(), child)).sum::<usize>()
1728 }
1729 };
1730 size_of::<Self>() + self.validity.footprint() + body
1731 }
1732
1733 /// Which of the values are not null, at this level and no deeper.
1734 ///
1735 /// This is not the same question as [`Self::is_null_at`] and the difference has already cost
1736 /// one wrong answer. A dictionary and a run length vector keep their nulls in the values they
1737 /// point at rather than in a mask of their own, so both are built with every row marked present
1738 /// here and a row whose value is null reads as valid. A caller that wants to know whether a row
1739 /// is null wants the other one. A caller that wants the mask of a flat column, to copy it or to
1740 /// count it, wants this one.
1741 #[must_use]
1742 pub fn validity(&self) -> &Validity {
1743 &self.validity
1744 }
1745
1746 /// Whether the row at `index` is null, in whichever form the vector is in.
1747 ///
1748 /// Reads through a dictionary or a run to the value it stands for, which is where those two
1749 /// forms keep their nulls, and answers from the mask for every other form. A row past the end
1750 /// is null, the same answer [`Self::value_at`] gives it.
1751 #[must_use]
1752 pub fn is_null_at(&self, index: usize) -> bool {
1753 if index >= self.len || !self.validity.is_valid(index) {
1754 return true;
1755 }
1756 match &self.body {
1757 Body::Dictionary { codes, values, .. } => match codes.get(index) {
1758 Some(&code) => values.is_null_at(code as usize),
1759 None => true,
1760 },
1761 Body::Runs { ends, values } => match run_holding(ends, index) {
1762 Some(run) => values.is_null_at(run),
1763 None => true,
1764 },
1765 // Section 8.2's lazy validity, which is this line. A gather has no mask of its own and
1766 // does not need one: the id says whether there is a row and the source says whether that
1767 // row is null, and both of those are already in memory.
1768 Body::Gathered { source, rids, offset } => match rids.get(offset + index) {
1769 Some(&NO_ROW) | None => true,
1770 Some(&rid) => source.is_null_at(rid as usize),
1771 },
1772 _ => false,
1773 }
1774 }
1775
1776 /// Whether no row in range is null, answered without reading a row.
1777 ///
1778 /// This is the cheap side of [`Self::is_null_at`] and has to follow it exactly. A dictionary and
1779 /// a run keep their nulls in the values they stand for, so both levels have to say they have
1780 /// none. Every other form answers from its own mask. A false means only that the cheap answer
1781 /// was not available, so a caller that gets one still has to ask row by row.
1782 ///
1783 /// Public because the alternative a caller has is a pass over the values, and on a dictionary
1784 /// that is the size of a Parquet column chunk's that pass is the thing it was trying to avoid.
1785 #[must_use]
1786 pub fn never_null(&self) -> bool {
1787 if self.validity.has_nulls(self.len) {
1788 return false;
1789 }
1790 match &self.body {
1791 Body::Dictionary { values, .. } | Body::Runs { values, .. } => values.never_null(),
1792 // A gather is never null when no id is the sentinel and the source holds no nulls. The
1793 // first of those is a pass over the ids rather than a constant, which is the one place
1794 // this question is not free, and it is worth paying: the ids are four bytes a row and
1795 // contiguous, and the alternative is reading through to the source once per row for the
1796 // whole vector, which is the random access this form exists to postpone.
1797 Body::Gathered { source, rids, offset } => {
1798 source.never_null()
1799 && !rids[*offset..].iter().take(self.len).any(|&rid| rid == NO_ROW)
1800 }
1801 _ => true,
1802 }
1803 }
1804
1805 /// Which physical form this vector is in.
1806 #[must_use]
1807 pub fn form(&self) -> Form {
1808 match self.body {
1809 Body::Flat(_) => Form::Flat,
1810 Body::Constant(_) => Form::Constant,
1811 Body::Sequence { .. } => Form::Sequence,
1812 Body::Dictionary { .. } => Form::Dictionary,
1813 Body::Packed { .. } => Form::BitPacked,
1814 Body::Views { .. } => Form::StringView,
1815 Body::ExternalText { .. } => Form::StringView,
1816 Body::Coded { .. } => Form::Fsst,
1817 Body::Runs { .. } => Form::Rle,
1818 Body::Nested { .. } => Form::List,
1819 Body::Fields { .. } => Form::Struct,
1820 Body::Gathered { .. } => Form::Gathered,
1821 }
1822 }
1823
1824 /// The data, for a flat vector, and `None` for any other form.
1825 ///
1826 /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
1827 /// that can do better on a constant or a dictionary checks [`Self::form`] first.
1828 #[must_use]
1829 pub fn data(&self) -> Option<&Data> {
1830 match &self.body {
1831 Body::Flat(data) => Some(data),
1832 _ => None,
1833 }
1834 }
1835
1836 /// The one value, for a constant vector, and `None` for any other form.
1837 ///
1838 /// A kernel comparing a column against a literal wants the literal once rather than 1024
1839 /// times, and [`Self::value_at`] on a constant clones it on every call because it has to be
1840 /// able to hand back a `Value` for any form. This is the accessor that lets the specialized
1841 /// path hoist the clone out of the loop.
1842 #[must_use]
1843 pub fn constant_value(&self) -> Option<&Value> {
1844 match &self.body {
1845 Body::Constant(value) => Some(value.as_ref()),
1846 _ => None,
1847 }
1848 }
1849
1850 /// The codes and the values, for a dictionary vector, and `None` for any other form.
1851 ///
1852 /// The reason a kernel needs this rather than reading the dictionary through
1853 /// [`Self::value_at`] is the entire argument for the form existing. A filter against a
1854 /// dictionary column of 1024 rows and 40 distinct values is 40 comparisons and 1024 lookups,
1855 /// not 1024 comparisons, and there is no way to write that loop without seeing the codes.
1856 ///
1857 /// Note what the validity of the returned vector means. A dictionary keeps its nulls in the
1858 /// vector it points at, and the dictionary's own validity says nothing about them, so a caller
1859 /// deciding whether row `i` is null has to ask the value vector about `codes[i]` rather than
1860 /// asking this vector about `i`. [`Self::flatten`] has the same note on it for the same
1861 /// reason, because getting this wrong is a null that survives being selected and comes out as
1862 /// a zero.
1863 #[must_use]
1864 pub fn dictionary_parts(&self) -> Option<(&[u32], &Self)> {
1865 match &self.body {
1866 Body::Dictionary { codes, values, .. } => Some((codes, values.as_ref())),
1867 _ => None,
1868 }
1869 }
1870
1871 /// The codes and the shared dictionary handle for a dictionary vector.
1872 ///
1873 /// Storage readers use the identity of this handle to prove that codes from separate pages
1874 /// belong to one table-wide dictionary. Kernels that only read values should continue to use
1875 /// [`Self::dictionary_parts`].
1876 #[must_use]
1877 pub fn shared_dictionary_parts(&self) -> Option<(&[u32], &Arc<Self>)> {
1878 match &self.body {
1879 Body::Dictionary { codes, values, .. } => Some((codes, values)),
1880 _ => None,
1881 }
1882 }
1883
1884 /// Stable codes and their shared values, when storage guarantees one code space across pages.
1885 #[must_use]
1886 pub fn stable_dictionary_parts(&self) -> Option<(&[u32], &Arc<Self>)> {
1887 match &self.body {
1888 Body::Dictionary { codes, values, stable: true } => Some((codes, values)),
1889 _ => None,
1890 }
1891 }
1892
1893 /// The run ends and the run values, for a run length vector, and `None` for any other form.
1894 ///
1895 /// The ends are exclusive and increasing, and there is exactly one value per run, so a kernel
1896 /// that wants to walk this walks the pairs and never asks which run a row is in. That is the
1897 /// whole argument for the form: an aggregate over a clustered column is one multiply per run
1898 /// instead of one add per row, and there is no way to write that loop without seeing the ends.
1899 ///
1900 /// The nulls are in the values, the way a dictionary's are, so a caller deciding whether row `i`
1901 /// is null asks the value vector about the run rather than asking this vector about `i`.
1902 #[must_use]
1903 pub fn run_parts(&self) -> Option<(&[u32], &Self)> {
1904 match &self.body {
1905 Body::Runs { ends, values } => Some((ends, values.as_ref())),
1906 _ => None,
1907 }
1908 }
1909
1910 /// Where each row's value is, for the two forms that keep their values somewhere else.
1911 ///
1912 /// A dictionary and a run length vector are the same shape seen from a kernel: a run of
1913 /// positions and a vector to read them out of. The difference is that a dictionary stores the
1914 /// positions and a run length vector works them out, and a kernel writing `values[at[row]]` does
1915 /// not care which. So every specialization written against [`Self::dictionary_parts`] covers
1916 /// both forms by asking this instead, and the day a third form with an indirection arrives it
1917 /// covers that one too without any of those kernels being reopened.
1918 ///
1919 /// The run length side costs an allocation of one position per row and a pass to fill it, which
1920 /// is the same four bytes a row a dictionary was already carrying and is paid once per kernel
1921 /// call rather than once per row. That is the price of this being one accessor rather than a
1922 /// second arm in eighteen kernels, and it is not the last word: a kernel that wants a run at a
1923 /// time reads [`Self::run_parts`] and pays nothing, which is the specialization this makes it
1924 /// possible to skip writing until a sweep says it is worth it.
1925 #[must_use]
1926 pub fn positions(&self) -> Option<(Cow<'_, [u32]>, &Self)> {
1927 match &self.body {
1928 Body::Dictionary { codes, values, .. } => Some((Cow::Borrowed(codes), values.as_ref())),
1929 Body::Runs { ends, values } => {
1930 let mut at = Vec::with_capacity(self.len);
1931 for (run, &stop) in ends.iter().enumerate() {
1932 let run = u32::try_from(run).unwrap_or(u32::MAX);
1933 at.resize(stop as usize, run);
1934 }
1935 Some((Cow::Owned(at), values.as_ref()))
1936 }
1937 _ => None,
1938 }
1939 }
1940
1941 /// The bits and what they mean, for a bit packed vector, and `None` for any other form.
1942 ///
1943 /// What a kernel needs to stay in code space. A comparison against a literal is the case that
1944 /// pays: `column > 900` over a column packed from a base of 40 is `code > 860`, which is the
1945 /// same shift and mask the read was going to do anyway and no unpacking at all, and a literal
1946 /// outside the packed range answers the whole vector without reading a bit of it. None of that
1947 /// can be written without seeing the width and the base.
1948 #[must_use]
1949 pub fn packed_parts(&self) -> Option<Packed<'_>> {
1950 match &self.body {
1951 Body::Packed { words, width, base, offset } => {
1952 Some(Packed { words, width: *width, base: *base, offset: *offset })
1953 }
1954 _ => None,
1955 }
1956 }
1957
1958 /// The views and the arena, for either form that stores strings, and `None` for the rest.
1959 ///
1960 /// This is to the two string forms what [`Self::positions`] is to the two forms that point
1961 /// somewhere else. A flat varchar column owns its arena and a string view column shares one, and
1962 /// a kernel reading a row wants the view and the bytes either way, so every specialization
1963 /// written against this covers both forms and neither has to be reopened when a third way of
1964 /// holding an arena arrives.
1965 ///
1966 /// The arena is whatever the long strings live in, which for a column over a page is the page,
1967 /// including the parts of it no view points at. Only the views say which bytes are a row.
1968 #[must_use]
1969 pub fn text_parts(&self) -> Option<(&[StringView], &[u8])> {
1970 match &self.body {
1971 Body::Flat(Data::Varlen(column)) => Some((column.views(), column.arena())),
1972 Body::Views { views, arena } => Some((views, arena)),
1973 _ => None,
1974 }
1975 }
1976
1977 /// The codes and the table, for an FSST vector, and `None` for any other form.
1978 ///
1979 /// What a kernel needs to stay in code space. An equality filter is the case that pays, and it
1980 /// pays completely: the literal is compressed once against the same table and after that a row
1981 /// matches exactly when its code bytes match, because compressing is a function and so is
1982 /// decompressing. No row is decompressed at all. An ordering comparison cannot do that, since a
1983 /// symbol code says nothing about where its symbol sorts, so those decompress and say so.
1984 #[must_use]
1985 pub fn coded_parts(&self) -> Option<Coded<'_>> {
1986 match &self.body {
1987 Body::Coded { codes, spans, table } => Some(Coded { codes, spans, table }),
1988 _ => None,
1989 }
1990 }
1991
1992 /// The start and the step, for a sequence vector, and `None` for any other form.
1993 #[must_use]
1994 pub fn sequence_parts(&self) -> Option<(i64, i64)> {
1995 match self.body {
1996 Body::Sequence { start, step } => Some((start, step)),
1997 _ => None,
1998 }
1999 }
2000
2001 /// The value at `index`, as a single value.
2002 ///
2003 /// This is the slow path on purpose. It is what a result set is read out with and what a test
2004 /// asserts on, and an operator that calls it per row is an operator that has already lost the
2005 /// argument the vector interface exists to win.
2006 #[must_use]
2007 pub fn value_at(&self, index: usize) -> Value {
2008 if index >= self.len || !self.validity.is_valid(index) {
2009 return Value::Null;
2010 }
2011 match &self.body {
2012 Body::Constant(value) => value.as_ref().clone(),
2013 Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
2014 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2015 Some(&code) => values.value_at(code as usize),
2016 None => Value::Null,
2017 },
2018 Body::Runs { ends, values } => match run_holding(ends, index) {
2019 Some(run) => values.value_at(run),
2020 None => Value::Null,
2021 },
2022 // The one read every other reader of this form is: follow the id, and answer null when
2023 // there is no row to follow. Written out once per reader rather than through a helper
2024 // because each of them returns a different kind of nothing.
2025 Body::Gathered { source, rids, offset } => match rids.get(offset + index) {
2026 Some(&NO_ROW) | None => Value::Null,
2027 Some(&rid) => source.value_at(rid as usize),
2028 },
2029 // One value unpacked into a run of one, so that what a packed value means is decided in
2030 // the same place a flat one is rather than in a second copy of the type mapping that
2031 // could drift from it. It allocates, which this path is allowed to do and the typed
2032 // unpack in `copied` is not, and it is the reason anything about to read a packed
2033 // column a row at a time should flatten it once instead.
2034 Body::Packed { words, width, base, offset } => {
2035 unpack(&self.ty, words, *offset, *width, *base, &[index])
2036 .map_or(Value::Null, |data| value_from(&self.ty, &data, 0))
2037 }
2038 // The bytes are where the arena has them, and what they are read as is the logical
2039 // type's business, so this hands the row to the same reader a flat column goes through
2040 // rather than deciding here that a `BLOB` is a string.
2041 Body::Views { views, arena } => {
2042 match views.get(index).and_then(|v| v.bytes_in(arena)) {
2043 Some(bytes) => bytes_as(&self.ty, bytes),
2044 None => Value::Null,
2045 }
2046 }
2047 Body::ExternalText { source } => source
2048 .bytes_at(index)
2049 .ok()
2050 .flatten()
2051 .map_or(Value::Null, |bytes| bytes_as(&self.ty, bytes)),
2052 // One row decompressed on its own, which is the property the form is chosen for. It
2053 // allocates, which this path is allowed to do, and it is the reason anything about to
2054 // read a compressed column a row at a time should flatten it once instead.
2055 Body::Coded { codes, spans, table } => {
2056 match spans.get(index).and_then(|&(from, to)| {
2057 let mut out = Vec::new();
2058 table.decompress(codes.get(from as usize..to as usize)?, &mut out).ok()?;
2059 Some(out)
2060 }) {
2061 Some(bytes) => bytes_as(&self.ty, &bytes),
2062 None => Value::Null,
2063 }
2064 }
2065 // A row's elements are read out of the child one at a time, which is the slow path this
2066 // whole function is and is why a kernel over a list column reads `list_parts` instead.
2067 // The element type comes from the child rather than from this vector's type, so a list
2068 // whose child was built narrower than the column claims still hands back what is in it.
2069 //
2070 // A map is stored in this body too, so which value comes out is decided by the logical
2071 // type rather than by the body. That is the one place the composition shows: the bytes of
2072 // a map really are the bytes of a list of two field structs, and the only thing that
2073 // remembers it is a map is the type.
2074 Body::Nested { entries, child } => match (entries.get(index), &self.ty) {
2075 (Some(&(start, len)), LogicalType::Map(key, value)) => {
2076 let pairs = child.struct_parts().unwrap_or_default();
2077 Value::map(
2078 key.as_ref().clone(),
2079 value.as_ref().clone(),
2080 (start..start + len)
2081 .filter_map(|at| {
2082 let [keys, values] = pairs else { return None };
2083 Some((keys.value_at(at as usize), values.value_at(at as usize)))
2084 })
2085 .collect(),
2086 )
2087 }
2088 (Some(&(start, len)), _) => Value::List {
2089 element: child.ty.clone(),
2090 values: (start..start + len).map(|at| child.value_at(at as usize)).collect(),
2091 },
2092 (None, _) => Value::Null,
2093 },
2094 // One value read out of each child at the same position, which is the slow path this whole
2095 // function is and is why a kernel over a struct column reads `struct_parts` instead. The
2096 // names come from this vector's type rather than from the children, because a child is a
2097 // vector and a vector has no name, and the type is where the field order is written down.
2098 Body::Fields { children } => Value::Struct(
2099 fields_of(&self.ty)
2100 .iter()
2101 .zip(children)
2102 .map(|(field, child)| (field.name.clone(), child.value_at(index)))
2103 .collect(),
2104 ),
2105 Body::Flat(data) => value_from(&self.ty, data, index),
2106 }
2107 }
2108
2109 /// One value of this vector's type, built out of bytes the caller already holds.
2110 ///
2111 /// [`try_value_at`](Self::try_value_at) finds the bytes itself, which over a dictionary that
2112 /// keeps its payload in a file means a read. A caller that swept the values out has the bytes in
2113 /// hand already and wants nothing from here but the type.
2114 pub fn value_of(&self, bytes: &[u8]) -> Value {
2115 bytes_as(&self.ty, bytes)
2116 }
2117
2118 /// The value at `index`, preserving storage read and validation failures.
2119 pub fn try_value_at(&self, index: usize) -> Result<Value> {
2120 if index >= self.len || !self.validity.is_valid(index) {
2121 return Ok(Value::Null);
2122 }
2123 match &self.body {
2124 Body::ExternalText { source } => {
2125 Ok(source.bytes_at(index)?.map_or(Value::Null, |bytes| bytes_as(&self.ty, bytes)))
2126 }
2127 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2128 Some(&code) => values.try_value_at(code as usize),
2129 None => Ok(Value::Null),
2130 },
2131 Body::Runs { ends, values } => match run_holding(ends, index) {
2132 Some(run) => values.try_value_at(run),
2133 None => Ok(Value::Null),
2134 },
2135 Body::Nested { entries, child } => match (entries.get(index), &self.ty) {
2136 (Some(&(start, len)), LogicalType::Map(key, value)) => {
2137 let pairs = child.struct_parts().unwrap_or_default();
2138 let [keys, values] = pairs else { return Ok(Value::Null) };
2139 let mut entries = Vec::with_capacity(len as usize);
2140 for at in start..start + len {
2141 entries.push((
2142 keys.try_value_at(at as usize)?,
2143 values.try_value_at(at as usize)?,
2144 ));
2145 }
2146 Ok(Value::map(key.as_ref().clone(), value.as_ref().clone(), entries))
2147 }
2148 (Some(&(start, len)), _) => {
2149 let mut values = Vec::with_capacity(len as usize);
2150 for at in start..start + len {
2151 values.push(child.try_value_at(at as usize)?);
2152 }
2153 Ok(Value::List { element: child.ty.clone(), values })
2154 }
2155 (None, _) => Ok(Value::Null),
2156 },
2157 Body::Fields { children } => {
2158 let mut values = Vec::with_capacity(children.len());
2159 for (field, child) in fields_of(&self.ty).iter().zip(children) {
2160 values.push((field.name.clone(), child.try_value_at(index)?));
2161 }
2162 Ok(Value::Struct(values))
2163 }
2164 _ => Ok(self.value_at(index)),
2165 }
2166 }
2167
2168 /// The text at `index`, borrowed rather than copied.
2169 ///
2170 /// [`Self::value_at`] on a `VARCHAR` column allocates a `String` per call, and a group by that
2171 /// reads a string column keys on one string per input row. This hands back the bytes where they
2172 /// already are, so a caller with somewhere to put them does not go to the allocator at all.
2173 ///
2174 /// `None` for a null, for an index past the end, for a column that is not `VARCHAR`, and for the
2175 /// constant and sequence forms, whose values are not stored per position. A caller that gets
2176 /// `None` has to fall back to [`Self::value_at`], which is correct for all of those.
2177 #[must_use]
2178 pub fn text_at(&self, index: usize) -> Option<&str> {
2179 if self.ty != LogicalType::Varchar || index >= self.len || !self.validity.is_valid(index) {
2180 return None;
2181 }
2182 match &self.body {
2183 Body::Flat(data) => data.str_at(index),
2184 Body::Dictionary { codes, values, .. } => {
2185 values.text_at(usize::try_from(*codes.get(index)?).ok()?)
2186 }
2187 Body::Runs { ends, values } => values.text_at(run_holding(ends, index)?),
2188 Body::Gathered { source, rids, offset } => {
2189 source.text_at(row_of(rids, *offset, index)?)
2190 }
2191 Body::Views { views, arena } => {
2192 std::str::from_utf8(views.get(index)?.bytes_in(arena)?).ok()
2193 }
2194 Body::ExternalText { source } => {
2195 std::str::from_utf8(source.bytes_at(index).ok().flatten()?).ok()
2196 }
2197 _ => None,
2198 }
2199 }
2200
2201 /// The variable length bytes at `index`, borrowed without validating or copying them.
2202 ///
2203 /// String data is validated when it enters a vector. Hashing and equality only need its bytes,
2204 /// so those kernels should not pay for UTF-8 validation again on every read.
2205 #[must_use]
2206 pub fn bytes_at(&self, index: usize) -> Option<&[u8]> {
2207 if index >= self.len || !self.validity.is_valid(index) {
2208 return None;
2209 }
2210 match &self.body {
2211 Body::Constant(value) => match value.as_ref() {
2212 Value::Varchar(text) => Some(text.as_bytes()),
2213 Value::Blob(bytes) => Some(bytes),
2214 _ => None,
2215 },
2216 Body::Dictionary { codes, values, .. } => {
2217 values.bytes_at(usize::try_from(*codes.get(index)?).ok()?)
2218 }
2219 Body::Runs { ends, values } => values.bytes_at(run_holding(ends, index)?),
2220 Body::Gathered { source, rids, offset } => {
2221 source.bytes_at(row_of(rids, *offset, index)?)
2222 }
2223 Body::Views { views, arena } => views.get(index)?.bytes_in(arena),
2224 Body::ExternalText { source } => source.bytes_at(index).ok().flatten(),
2225 Body::Flat(data) => data.bytes_at(index),
2226 // The same `None` [`Self::text_at`] gives, for the same reason. A compressed row is not
2227 // anywhere in its plain bytes, so there is nothing here to hand back a borrow of, and a
2228 // caller that gets `None` goes to `value_at` and gets the row decompressed into a value.
2229 // A list row is `None` for a nearer reason: it is not bytes at all, and a caller wanting
2230 // its elements wants [`Self::list_parts`] rather than a borrow of one row.
2231 Body::Coded { .. }
2232 | Body::Sequence { .. }
2233 | Body::Packed { .. }
2234 | Body::Nested { .. }
2235 | Body::Fields { .. } => None,
2236 }
2237 }
2238
2239 /// Variable length bytes at `index`, preserving storage read and validation failures.
2240 pub fn try_bytes_at(&self, index: usize) -> Result<Option<&[u8]>> {
2241 if index >= self.len || !self.validity.is_valid(index) {
2242 return Ok(None);
2243 }
2244 match &self.body {
2245 Body::Constant(value) => Ok(match value.as_ref() {
2246 Value::Varchar(text) => Some(text.as_bytes()),
2247 Value::Blob(bytes) => Some(bytes.as_slice()),
2248 _ => None,
2249 }),
2250 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2251 Some(&code) => values.try_bytes_at(code as usize),
2252 None => Ok(None),
2253 },
2254 Body::Runs { ends, values } => match run_holding(ends, index) {
2255 Some(run) => values.try_bytes_at(run),
2256 None => Ok(None),
2257 },
2258 Body::Gathered { source, rids, offset } => match row_of(rids, *offset, index) {
2259 Some(row) => source.try_bytes_at(row),
2260 None => Ok(None),
2261 },
2262 Body::Views { views, arena } => {
2263 Ok(views.get(index).and_then(|view| view.bytes_in(arena)))
2264 }
2265 Body::ExternalText { source } => source.bytes_at(index),
2266 Body::Flat(data) => Ok(data.bytes_at(index)),
2267 Body::Coded { .. }
2268 | Body::Sequence { .. }
2269 | Body::Packed { .. }
2270 | Body::Nested { .. }
2271 | Body::Fields { .. } => Ok(None),
2272 }
2273 }
2274
2275 /// Walks the values from `first` up to at most `limit`, without keeping what it read.
2276 ///
2277 /// [`TextSource::sweep`] is what this is for and what the doc on it explains. Everything else
2278 /// here is the honest fallback: a vector that is not reading text out of a file has its values
2279 /// already, so there is nothing to avoid keeping, and it hands over one value and lets the
2280 /// caller come back. The answer is one past the last value visited either way, so the loop that
2281 /// calls this is the same loop whichever form it got.
2282 ///
2283 /// Nulls go the slow way. A source that reads a file holds no validity of its own, so the
2284 /// vector's own mask is the only thing that knows, and rather than teach the sweep about it the
2285 /// one form that can have both hands over a value at a time through the reader that checks.
2286 ///
2287 /// # Errors
2288 ///
2289 /// Whatever reading a value raises, and whatever `body` raises.
2290 pub fn sweep_text(
2291 &self,
2292 first: usize,
2293 limit: usize,
2294 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
2295 ) -> Result<usize> {
2296 let limit = limit.min(self.len);
2297 if first >= limit {
2298 return Ok(first);
2299 }
2300 if let Body::ExternalText { source } = &self.body {
2301 if matches!(self.validity, Validity::AllValid) {
2302 return source.sweep(first, limit, body);
2303 }
2304 }
2305 body(first, self.try_bytes_at(first)?.unwrap_or_default())?;
2306 Ok(first + 1)
2307 }
2308
2309 /// A conservative substring test for the payload block holding `first`.
2310 ///
2311 /// Only a file-backed string source with all-valid values can skip a whole block. Every other
2312 /// form returns true and lets the ordinary sweep decide its values.
2313 pub fn text_block_might_contain(&self, first: usize, literal: &[u8]) -> Result<bool> {
2314 match &self.body {
2315 Body::ExternalText { source } if matches!(self.validity, Validity::AllValid) => {
2316 source.might_contain(first, literal)
2317 }
2318 _ => Ok(true),
2319 }
2320 }
2321
2322 /// The values at `indices`, which rise, without keeping what reading them decoded.
2323 ///
2324 /// [`TextSource::visit`] is what this is for. A vector that is not reading text out of a file, or
2325 /// that has nulls of its own, reads a value at a time through the reader that checks.
2326 ///
2327 /// # Errors
2328 ///
2329 /// Whatever reading a value raises.
2330 pub fn try_values_visited(&self, indices: &[usize]) -> Result<Vec<Value>> {
2331 if let Body::ExternalText { source } = &self.body {
2332 if matches!(self.validity, Validity::AllValid) {
2333 let mut out = vec![Value::Null; indices.len()];
2334 let mut own = |at: usize, bytes: &[u8]| {
2335 if indices[at] < self.len {
2336 out[at] = bytes_as(&self.ty, bytes);
2337 }
2338 Ok(())
2339 };
2340 source.visit(indices, &mut own)?;
2341 return Ok(out);
2342 }
2343 }
2344 indices.iter().map(|&index| self.try_value_at(index)).collect()
2345 }
2346
2347 /// Variable length byte count at `index`, preserving storage failures.
2348 pub fn try_bytes_len_at(&self, index: usize) -> Result<Option<usize>> {
2349 if index >= self.len || !self.validity.is_valid(index) {
2350 return Ok(None);
2351 }
2352 match &self.body {
2353 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2354 Some(&code) => values.try_bytes_len_at(code as usize),
2355 None => Ok(None),
2356 },
2357 Body::Runs { ends, values } => match run_holding(ends, index) {
2358 Some(run) => values.try_bytes_len_at(run),
2359 None => Ok(None),
2360 },
2361 Body::ExternalText { source } => source.bytes_len_at(index),
2362 _ => Ok(self.bytes_at(index).map(<[u8]>::len)),
2363 }
2364 }
2365
2366 /// The byte length of every row, in one call to whatever holds the text, when that is possible.
2367 ///
2368 /// `into` is one slot per row. The answer is whether it was filled: a vector with nulls in it,
2369 /// or one whose text is not read from a [`TextSource`], answers `false` and leaves the caller to
2370 /// ask a row at a time through [`Self::try_bytes_len_at`], which is right for every shape. The
2371 /// two shapes taken here are the two a scan of a stored string column hands out, the text itself
2372 /// and a dictionary of codes over it, and each is one call to the source for the whole vector
2373 /// rather than a call per row down through this type.
2374 ///
2375 /// # Errors
2376 ///
2377 /// Whatever reading the lengths out of storage raises.
2378 pub fn try_bytes_lens(&self, into: &mut [i64]) -> Result<bool> {
2379 if into.len() != self.len || !matches!(self.validity, Validity::AllValid) {
2380 return Ok(false);
2381 }
2382 match &self.body {
2383 Body::ExternalText { source } => {
2384 let Ok(rows) = u32::try_from(self.len) else { return Ok(false) };
2385 let indices = (0..rows).collect::<Vec<_>>();
2386 source.bytes_lens_at(&indices, into)?;
2387 Ok(true)
2388 }
2389 Body::Dictionary { codes, values, .. } => match &values.body {
2390 Body::ExternalText { source } if matches!(values.validity, Validity::AllValid) => {
2391 source.bytes_lens_at(codes, into)?;
2392 Ok(true)
2393 }
2394 _ => Ok(false),
2395 },
2396 _ => Ok(false),
2397 }
2398 }
2399
2400 /// How many ranks this vector's values have in sorted order, when whatever holds them knows.
2401 ///
2402 /// See [`TextSource::ranks`] for what a rank is and what a source promises by answering with
2403 /// one. Only a vector whose values come from storage can answer, because only storage is in a
2404 /// position to have sorted them once and written the answer down.
2405 #[must_use]
2406 pub fn ranks(&self) -> Option<usize> {
2407 match &self.body {
2408 Body::ExternalText { source } => source.ranks(),
2409 _ => None,
2410 }
2411 }
2412
2413 /// How the value at `rank` compares against `wanted`. See [`TextSource::compare_rank`].
2414 pub fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
2415 match &self.body {
2416 Body::ExternalText { source } => source.compare_rank(rank, wanted),
2417 _ => {
2418 Err(Error::internal("a vector without a sorted order was asked to compare a rank"))
2419 }
2420 }
2421 }
2422
2423 /// Where `wanted` would go in the sorted order. See [`TextSource::below`].
2424 ///
2425 /// # Errors
2426 ///
2427 /// If this vector has no sorted order, or if a probe of it fails.
2428 pub fn below(&self, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)> {
2429 match &self.body {
2430 Body::ExternalText { source } => source.below(ranks, wanted),
2431 _ => Err(Error::internal("a vector without a sorted order was asked for a boundary")),
2432 }
2433 }
2434
2435 /// The position of the value at `rank`. See [`TextSource::code_at_rank`].
2436 pub fn code_at_rank(&self, rank: usize) -> Result<u32> {
2437 match &self.body {
2438 Body::ExternalText { source } => source.code_at_rank(rank),
2439 _ => Err(Error::internal("a vector without a sorted order was asked for a rank")),
2440 }
2441 }
2442
2443 /// The rank of every value, indexed by position. See [`TextSource::code_ranks`].
2444 #[must_use]
2445 pub fn code_ranks(&self) -> Option<&[u32]> {
2446 match &self.body {
2447 Body::ExternalText { source } => source.code_ranks(),
2448 _ => None,
2449 }
2450 }
2451
2452 /// Text at `index`, preserving storage read, validation and UTF-8 failures.
2453 pub fn try_text_at(&self, index: usize) -> Result<Option<&str>> {
2454 if self.ty != LogicalType::Varchar {
2455 return Ok(None);
2456 }
2457 self.try_bytes_at(index)?
2458 .map(|bytes| {
2459 std::str::from_utf8(bytes).map_err(|error| {
2460 Error::conversion(format!("invalid UTF-8 in VARCHAR: {error}"))
2461 })
2462 })
2463 .transpose()
2464 }
2465
2466 /// Read every storage-backed value reachable through this vector.
2467 pub fn validate_external(&self) -> Result<()> {
2468 match &self.body {
2469 Body::ExternalText { source } => {
2470 for index in 0..source.len() {
2471 source.bytes_at(index)?;
2472 }
2473 }
2474 Body::Dictionary { codes, values, .. } => {
2475 for &code in codes {
2476 values.try_bytes_at(code as usize)?;
2477 }
2478 }
2479 Body::Runs { values, .. } | Body::Gathered { source: values, .. } => {
2480 values.validate_external()?;
2481 }
2482 Body::Nested { child, .. } => child.validate_external()?,
2483 Body::Fields { children } => {
2484 for child in children {
2485 child.validate_external()?;
2486 }
2487 }
2488 _ => {}
2489 }
2490 Ok(())
2491 }
2492
2493 /// The signed integer at `index`, widened, read without building a [`Value`].
2494 ///
2495 /// The integer sibling of [`Self::bytes_at`], and it is here for the same caller. A group by on
2496 /// an integer column compares one key per input row against the group it probed, and doing that
2497 /// through [`Self::value_at`] built and dropped a sixty four byte value a row at a time for a
2498 /// number that was already sitting in the column.
2499 ///
2500 /// Widened to `i128` because that is what [`Data::signed_at`] hands back underneath, and one
2501 /// method that covers every signed width is worth more than five that do not. A caller that
2502 /// wants a narrower type narrows it, which is a range check against a value in a register.
2503 ///
2504 /// The types this answers for are the ones whose flat data is read through `signed_at`, so the
2505 /// five signed integer widths and the decimal, date, time and timestamp types that are stored
2506 /// in them. A decimal answers with its unscaled value, which is the number the column holds.
2507 ///
2508 /// `None` for a null, for an index past the end, for a column of any other type, and for the
2509 /// compressed form. Packed integers stay in code space and answer `base + code` directly. A
2510 /// caller that gets `None` falls back to [`Self::value_at`], which is correct for the remaining
2511 /// forms.
2512 #[must_use]
2513 pub fn signed_at(&self, index: usize) -> Option<i128> {
2514 if index >= self.len || !self.validity.is_valid(index) {
2515 return None;
2516 }
2517 match &self.body {
2518 Body::Flat(data) => data.signed_at(index),
2519 Body::Constant(value) => match value.as_ref() {
2520 Value::TinyInt(x) => Some(i128::from(*x)),
2521 Value::SmallInt(x) => Some(i128::from(*x)),
2522 Value::Integer(x) | Value::Date(x) => Some(i128::from(*x)),
2523 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => Some(i128::from(*x)),
2524 Value::HugeInt(x) | Value::Decimal { unscaled: x, .. } => Some(*x),
2525 _ => None,
2526 },
2527 // The same arithmetic [`Self::value_at`] does on a sequence, so the two agree about a
2528 // sequence that runs off the end of the width it is stored in.
2529 Body::Sequence { start, step } => {
2530 Some(i128::from(start.wrapping_add(step.wrapping_mul(index as i64))))
2531 }
2532 Body::Dictionary { codes, values, .. } => {
2533 values.signed_at(usize::try_from(*codes.get(index)?).ok()?)
2534 }
2535 Body::Runs { ends, values } => values.signed_at(run_holding(ends, index)?),
2536 Body::Gathered { source, rids, offset } => {
2537 source.signed_at(row_of(rids, *offset, index)?)
2538 }
2539 Body::Packed { words, width, base, offset } => Some(
2540 *base + i128::from(code_at(words, (*offset + index) * *width as usize, *width)),
2541 ),
2542 // The same `None` [`Self::bytes_at`] gives, for the same reason. A compressed row is not
2543 // an integer anywhere until it has been unpacked, and a caller that gets
2544 // `None` goes to `value_at` and gets the row unpacked into a value. A list row is not an
2545 // integer in any form, however many integers are in it, and a struct row is not one even
2546 // when it has exactly one integer field, since the row is the struct and not the field.
2547 Body::Coded { .. }
2548 | Body::Views { .. }
2549 | Body::ExternalText { .. }
2550 | Body::Nested { .. }
2551 | Body::Fields { .. } => None,
2552 }
2553 }
2554
2555 /// Every signed value in order, widened to `i64`, written into `out`.
2556 ///
2557 /// The bulk form of [`Self::signed_at`], for a caller that is going to read the whole vector
2558 /// anyway. A group by on two integer columns called `signed_at` once per column per row, and
2559 /// every one of those matched on the body, called into the data and matched again on the
2560 /// layout, which is about sixty five instructions to read a number that was already sitting in
2561 /// a slice. It was a fifth of ClickBench 32 on its own.
2562 ///
2563 /// A null writes whatever the body holds under it, which is the zero a flat column keeps behind
2564 /// its mask. Nulls are a separate question and the caller asks it separately, from
2565 /// [`Self::none_null`] once for the vector when that answers and a row at a time when it does
2566 /// not.
2567 ///
2568 /// `false`, with `out` left empty, for a vector this cannot hand over as a block: `HUGEINT` and
2569 /// the wide decimals, whose values do not fit an `i64`, the string and nested forms, the
2570 /// compressed form, and the dictionary and run forms, which are a gather rather than a copy and
2571 /// are left until something wants them. A caller that gets `false` reads the vector the way it
2572 /// read it before, with [`Self::signed_at`].
2573 #[must_use]
2574 pub fn signed_block(&self, out: &mut Vec<i64>) -> bool {
2575 out.clear();
2576 match &self.body {
2577 Body::Flat(data) => data.signed_block(self.len, out),
2578 Body::Constant(value) => {
2579 let held = match value.as_ref() {
2580 Value::TinyInt(x) => i64::from(*x),
2581 Value::SmallInt(x) => i64::from(*x),
2582 Value::Integer(x) | Value::Date(x) => i64::from(*x),
2583 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => *x,
2584 _ => return false,
2585 };
2586 out.resize(self.len, held);
2587 true
2588 }
2589 // The same arithmetic [`Self::signed_at`] does on a sequence, once per row rather than
2590 // once per call, and it wraps where that one wraps.
2591 Body::Sequence { start, step } => {
2592 out.extend(
2593 (0..self.len).map(|index| start.wrapping_add(step.wrapping_mul(index as i64))),
2594 );
2595 true
2596 }
2597 Body::Packed { words, width, base, offset } => match i64::try_from(*base) {
2598 Ok(base) => {
2599 out.extend((0..self.len).map(|index| {
2600 base.wrapping_add(code_at(
2601 words,
2602 (*offset + index) * *width as usize,
2603 *width,
2604 ) as i64)
2605 }));
2606 true
2607 }
2608 Err(_) => false,
2609 },
2610 Body::Dictionary { .. }
2611 | Body::Runs { .. }
2612 | Body::Gathered { .. }
2613 | Body::Coded { .. }
2614 | Body::Views { .. }
2615 | Body::ExternalText { .. }
2616 | Body::Nested { .. }
2617 | Body::Fields { .. } => false,
2618 }
2619 }
2620
2621 /// Whether the vector holds no nulls at all, asked once rather than a row at a time.
2622 ///
2623 /// The bulk form of [`Self::is_null_at`], and it answers the same question that one does, so a
2624 /// dictionary and a run are read through to the values behind them where those two keep their
2625 /// nulls. A dictionary that holds a null no code points at answers `false` here and `false` at
2626 /// every row, which is the safe direction and is the only place the two can differ.
2627 ///
2628 /// A caller that gets `false` goes back to asking a row at a time.
2629 #[must_use]
2630 pub fn none_null(&self) -> bool {
2631 if self.validity.has_nulls(self.len) {
2632 return false;
2633 }
2634 match &self.body {
2635 Body::Dictionary { values, .. } | Body::Runs { values, .. } => values.none_null(),
2636 Body::Gathered { source, rids, offset } => {
2637 source.none_null()
2638 && !rids[*offset..].iter().take(self.len).any(|&rid| rid == NO_ROW)
2639 }
2640 _ => true,
2641 }
2642 }
2643
2644 /// Every value in order, as single values.
2645 pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
2646 (0..self.len).map(|index| self.value_at(index))
2647 }
2648
2649 /// This vector with its payload held as a page, so that copying or cutting it is free.
2650 ///
2651 /// For a producer that means to hand the same values out many times, which is what a stored
2652 /// column is. A flat body is the form this changes, because it is the only one that owns a run
2653 /// of values a copy would have to copy. Every other form already shares what is expensive and
2654 /// owns only what a cut has to rewrite, so it comes back as it was: a dictionary shares its
2655 /// values, a packed body shares its words, a string body shares its arena, an FSST body shares
2656 /// its codes and its table, and a constant and a sequence have nothing to share.
2657 ///
2658 /// Not recursive into a nested column's children, because a `LIST` or a `STRUCT` holds its
2659 /// children behind an `Arc` already.
2660 #[must_use]
2661 pub fn into_pages(self) -> Self {
2662 let body = match self.body {
2663 Body::Flat(data) => Body::Flat(data.into_pages()),
2664 other => other,
2665 };
2666 Self { body, ..self }
2667 }
2668
2669 /// A contiguous run of the values, in the form they are already in.
2670 ///
2671 /// This is the cut [`Self::gather`] cannot do. A gather walks a dictionary to its leaf and
2672 /// copies, so gathering a piece of a dictionary encoded column hands back a flat one, and a
2673 /// caller that only wanted the first thousand rows of a page has silently paid for a copy and
2674 /// thrown the dictionary away. A group by over a dictionary encoded column is the case that
2675 /// cares, and it is most of ClickBench.
2676 ///
2677 /// So each form is cut as itself. A dictionary keeps its dictionary and slices its codes, a
2678 /// sequence stays arithmetic with its start moved along, a constant stays a shorter constant,
2679 /// and a flat body is a window into its page when it has one and a copy of its range when it
2680 /// does not, which [`Self::into_pages`] is how a producer decides.
2681 ///
2682 /// The dictionary itself is shared rather than copied, so a cut is the codes and nothing else.
2683 /// It used to be copied, and on a read of a ClickBench partition that copy was ten percent of
2684 /// the cycles: a page holds one dictionary and is cut into chunk sized pieces, so the whole
2685 /// dictionary was copied once per chunk to be read the same way each time.
2686 ///
2687 /// # Errors
2688 ///
2689 /// If the range runs past the end of the vector, or if the type has no flat layout and the
2690 /// body is one that has to be copied.
2691 pub fn slice(&self, at: usize, len: usize) -> Result<Self> {
2692 let end = at.checked_add(len).ok_or_else(|| Error::internal("a slice that wraps"))?;
2693 if end > self.len {
2694 return Err(Error::internal(format!("rows {at} to {end} of a vector of {}", self.len)));
2695 }
2696 if at == 0 && len == self.len {
2697 return Ok(self.clone());
2698 }
2699 let validity = self.validity.slice(at, len);
2700 let body = match &self.body {
2701 Body::Constant(value) => Body::Constant(value.clone()),
2702 Body::Sequence { start, step } => {
2703 Body::Sequence { start: start + step * at as i64, step: *step }
2704 }
2705 Body::Dictionary { codes, values, stable } => Body::Dictionary {
2706 codes: codes[at..end].to_vec(),
2707 values: Arc::clone(values),
2708 stable: *stable,
2709 },
2710 // The same cut [`Body::Packed`] below takes and for the same reason, and here it is free
2711 // rather than merely cheap: a link join fills one buffer of parent rows per child chunk
2712 // and the pipeline cuts it, so moving the starting row is what keeps the ids from being
2713 // copied once per cut. Both ends of the gather stay shared, the ids and the source.
2714 Body::Gathered { source, rids, offset } => Body::Gathered {
2715 source: Arc::clone(source),
2716 rids: Arc::clone(rids),
2717 offset: offset + at,
2718 },
2719 // The bits are not byte aligned, so a cut either repacks them or moves the row the
2720 // reading starts at. Moving it is one addition and repacking is a pass, and a page is
2721 // cut into chunk sized pieces often enough that the difference is the form.
2722 Body::Packed { words, width, base, offset } => Body::Packed {
2723 words: Arc::clone(words),
2724 width: *width,
2725 base: *base,
2726 offset: offset + at,
2727 },
2728 // The cut a flat string column cannot do. Sixteen bytes a row move and the payload stays
2729 // where the page put it, so taking a chunk out of a column of long strings costs the
2730 // same as taking one out of a column of integers. A flat varchar body copies every byte
2731 // of every long string in the range instead, which is the measurement written down in
2732 // `Chunk::compact`: compaction loses on a varchar column, and this is the half of the
2733 // reason that is about cutting rather than about selecting.
2734 Body::Views { views, arena } => {
2735 Body::Views { views: views[at..end].to_vec(), arena: Arc::clone(arena) }
2736 }
2737 // The spans are absolute positions in the shared codes, so a cut is a run of them and
2738 // nothing has to be rebased. One page of compressed strings, one table, and as many
2739 // chunks over it as the reader wants.
2740 Body::Coded { codes, spans, table } => Body::Coded {
2741 codes: Arc::clone(codes),
2742 spans: spans[at..end].to_vec(),
2743 table: Arc::clone(table),
2744 },
2745 // Only the runs the range touches survive, the first and last of them cut back to where
2746 // the range starts and stops, and every end moved to be relative to the new row zero. A
2747 // cut of a hundred rows out of a column of a hundred million is a handful of runs, which
2748 // is the reason this form is worth cutting as itself rather than copying out.
2749 Body::Runs { ends, values } if len > 0 => {
2750 let first = run_holding(ends, at).unwrap_or(0);
2751 let last = run_holding(ends, end - 1).unwrap_or(first);
2752 let cut: Vec<u32> = ends[first..=last]
2753 .iter()
2754 .map(|&stop| stop.min(end as u32) - at as u32)
2755 .collect();
2756 let values = values.slice(first, last - first + 1)?;
2757 Body::Runs { ends: cut, values: Arc::new(values) }
2758 }
2759 // An empty cut has no run to point at and an empty run length body would be a vector of
2760 // no runs claiming a length, so it comes back as the empty flat vector instead.
2761 Body::Runs { .. } => return self.gather(&[]),
2762 // The entries are absolute positions in the shared child, so a cut is a run of them and
2763 // nothing has to be rebased, the same as a cut of FSST spans. The elements outside the
2764 // range stay in the child unreferenced, which is the trade this form makes: a chunk cut
2765 // out of a page of lists moves eight bytes a row and copies no elements at all.
2766 Body::Nested { entries, child } => {
2767 Body::Nested { entries: entries[at..end].to_vec(), child: Arc::clone(child) }
2768 }
2769 // Every child cut at the same place, because a struct row is one value per field at the
2770 // same position in each and there is no entry standing between the row and the child to
2771 // rewrite instead. So this is the one nested form whose cut is not free, and what it costs
2772 // is whatever cutting each field costs, which for a field of string views is sixteen bytes
2773 // a row and for a field of packed integers is one addition.
2774 Body::Fields { children } => Body::Fields {
2775 children: children
2776 .iter()
2777 .map(|child| child.slice(at, len).map(Arc::new))
2778 .collect::<Result<Vec<_>>>()?,
2779 },
2780 Body::ExternalText { source } => {
2781 let mut out = StringColumn::with_capacity(len);
2782 for index in at..end {
2783 out.push_bytes(source.bytes_at(index)?.unwrap_or_default());
2784 }
2785 Body::Flat(Data::Varlen(out))
2786 }
2787 // The one form with nowhere to point, so its range is copied out. A run and not a
2788 // gather: this used to build a vector of the positions `at..end` and hand it to
2789 // `gather`, which then built a vector of `usize` from it, a vector of `bool` beside
2790 // that, and read the values back one bounds checked index at a time. That is five
2791 // passes and three allocations to say `memcpy`, and on a scan it was the largest thing
2792 // in the program after the aggregation itself, because every chunk of every column of
2793 // every page comes through here.
2794 Body::Flat(data) => Body::Flat(run_of(data, at, end)),
2795 };
2796 Ok(Self { ty: self.ty.clone(), len, validity, body })
2797 }
2798
2799 /// The same values in flat form.
2800 ///
2801 /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
2802 /// which is exactly why the other forms exist and why nothing on the hot path should call
2803 /// this. It is here for the operators that genuinely cannot do better and for the tests that
2804 /// check the other forms against it.
2805 ///
2806 /// A call that copies counts itself against [`Cause::Flatten`], because a flatten on a hot path
2807 /// is the most expensive thing in this crate and the only way to find one is to have the number.
2808 /// A call on a vector that is already flat does not count, since it neither copies nor gives
2809 /// anything up.
2810 ///
2811 /// # Errors
2812 ///
2813 /// If the type is one there is no vector for yet, which today means `ARRAY` and `UNION`. A `LIST`
2814 /// and a `MAP` flatten to themselves and a `STRUCT` to a struct of flattened fields, since none of
2815 /// the three has a data slice in any form and there is nothing flatter to become.
2816 pub fn flatten(&self) -> Result<Self> {
2817 if let Body::Flat(_) = self.body {
2818 return Ok(self.clone());
2819 }
2820 slow::took(Cause::Flatten);
2821 self.copied((0..self.len).collect(), false)
2822 }
2823
2824 /// The same values in flat form, taking the vector rather than borrowing it.
2825 ///
2826 /// A vector that is already flat comes back as itself, which is the whole reason this exists
2827 /// beside [`Self::flatten`]. Flattening through a borrow has to clone that vector, and a clone
2828 /// of a flat vector that owns its values copies every one of them to produce a vector that is
2829 /// identical to the one it was handed. Anything not already flat goes the same way it does
2830 /// through [`Self::flatten`], since the copy is real work there rather than work for nothing.
2831 ///
2832 /// # Errors
2833 ///
2834 /// The same as [`Self::flatten`].
2835 pub fn into_flat(self) -> Result<Self> {
2836 if let Body::Flat(_) = self.body {
2837 return Ok(self);
2838 }
2839 // flatten: the caller asked for flat, and the form that is already flat took the branch
2840 // above, so this is the one case where the copy is what was wanted rather than a shortcut
2841 // somebody took instead of reading the column where it lies.
2842 self.flatten()
2843 }
2844
2845 /// The values at the given positions, copied, in a form that does not point back at this vector.
2846 ///
2847 /// This is the copying counterpart to [`Self::dictionary`], and the two are the two halves of
2848 /// the decision `spec/07-execution.md` section 7.1 describes. Which half is right is measured
2849 /// rather than argued, and [`Chunk::compact`](crate::Chunk::compact) is where the measurement
2850 /// is written down.
2851 ///
2852 /// A dictionary chain is walked to its leaf first and the codes composed on the way down, so the
2853 /// copy runs once over the data rather than once per level, and a position that is null at any
2854 /// level comes out null here. The copy is a typed loop per physical layout rather than a `Value`
2855 /// per row, which is the whole point of it and is what [`Self::flatten`] now goes through too.
2856 ///
2857 /// # Errors
2858 ///
2859 /// If the type is one there is no vector for yet, which today means `ARRAY` and `UNION`. A `LIST`
2860 /// and a `MAP` gather by permuting their entries and a `STRUCT` by gathering every field.
2861 pub fn gather(&self, indices: &[u32]) -> Result<Self> {
2862 self.copied(indices.iter().map(|&index| index as usize).collect(), true)
2863 }
2864
2865 /// The copy both [`Self::gather`] and [`Self::flatten`] are.
2866 ///
2867 /// `forms_stay` is the one thing the two want differently. A gather of a constant is a shorter
2868 /// constant and copying it out would be a thousand writes of the same value for nothing, and a
2869 /// gather of string views is a shorter run of views over the same arena rather than a copy of
2870 /// the bytes. Flattening promises flat form to a caller that is about to read the data slice, so
2871 /// for that one both of them have to be written out.
2872 fn copied(&self, at: Vec<usize>, forms_stay: bool) -> Result<Self> {
2873 let rows = at.len();
2874 if forms_stay {
2875 if let Body::Dictionary { codes, values, stable: true } = &self.body {
2876 // A gather off a column with no nulls in it is all valid as long as every index it
2877 // was handed is in range, and both of those are answered by a word at a time rather
2878 // than by asking each row whether it is null. That per row question reads through
2879 // the dictionary to the value it stands for, which made it the single line a
2880 // filtered scan of a dictionary column spent most of its copy in.
2881 let validity = if self.never_null() && at.iter().all(|&index| index < self.len) {
2882 Validity::AllValid
2883 } else {
2884 Validity::from_iter(rows, |row| {
2885 at.get(row)
2886 .is_some_and(|&index| index < self.len && !self.is_null_at(index))
2887 })
2888 };
2889 let gathered: Vec<u32> =
2890 at.iter().map(|&index| codes.get(index).copied().unwrap_or(0)).collect();
2891 // Every code here is one this vector already held, which was checked against the
2892 // same values on the way in, or the zero a row past the end is written as. So the
2893 // only code that can be out of range is that zero over no values at all, and the
2894 // pass that looks for the largest code is not needed to find it. On ClickBench 28
2895 // that pass was four percent of the query, because every filtered chunk of `URL`
2896 // came through here.
2897 // Values that are themselves a dictionary are composed through by the constructor,
2898 // and this skips the constructor, so that shape still goes the checked way.
2899 if matches!(values.body, Body::Dictionary { .. }) {
2900 return Ok(Self::stable_dictionary(gathered, Arc::clone(values))?
2901 .with_validity(validity));
2902 }
2903 let highest = (values.is_empty() && !gathered.is_empty()).then_some(0);
2904 return Ok(Self::stable_dictionary_validated(
2905 gathered,
2906 Arc::clone(values),
2907 highest,
2908 )?
2909 .with_validity(validity));
2910 }
2911 }
2912 let (at, leaf) = self.resolve(at);
2913 let live: Vec<bool> = at.iter().map(|&index| index != NOWHERE).collect();
2914 let validity = Validity::from_run(&live);
2915 let body = match &leaf.body {
2916 // The same gather the arm below is, for a type that has no flat layout to be written out
2917 // into. It goes through the nested builders rather than through a run of data, because they
2918 // are the one place that knows a row of a list column is a range of a child and a row of a
2919 // struct column is one position in each of several, and a second copy of that here would
2920 // be a second thing to keep in step with them.
2921 Body::Constant(value)
2922 if matches!(
2923 self.ty,
2924 LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _)
2925 ) =>
2926 {
2927 if forms_stay && matches!(validity, Validity::AllValid) {
2928 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
2929 }
2930 let rows: Vec<Value> = at
2931 .iter()
2932 .map(
2933 |&index| {
2934 if index == NOWHERE { Value::Null } else { value.as_ref().clone() }
2935 },
2936 )
2937 .collect();
2938 return Self::from_values(self.ty.clone(), &rows);
2939 }
2940 // Every position holds the same value, so the only thing the gather can change is the
2941 // length and which positions are null. A gather with no null in it is still a constant.
2942 Body::Constant(value) => {
2943 if forms_stay && matches!(validity, Validity::AllValid) {
2944 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
2945 }
2946 let mut data = empty_data_for(&self.ty)?;
2947 for &index in &at {
2948 push_value(&mut data, if index == NOWHERE { &Value::Null } else { value })?;
2949 }
2950 Body::Flat(data)
2951 }
2952 // A sequence is arithmetic rather than storage, so the gather is the arithmetic done at
2953 // the positions asked for, and a null writes the zero every other layout writes.
2954 Body::Sequence { start, step } => Body::Flat(Data::Int64(
2955 at.iter()
2956 .map(|&index| if index == NOWHERE { 0 } else { start + step * index as i64 })
2957 .collect(),
2958 )),
2959 // A flat body with no values is the untyped null, so every position asked for is null
2960 // whatever was asked for. Going through the copy would build a run of no values and
2961 // call it `rows` long, which is a vector whose length and data disagree.
2962 Body::Flat(Data::Empty) => {
2963 return Ok(Self::constant(self.ty.clone(), Value::Null, rows));
2964 }
2965 Body::Flat(data) => Body::Flat(copy_of(data, &at)),
2966 // The one form whose copy is arithmetic rather than a move of bytes. It goes through a
2967 // typed loop per layout the way the flat copy does, because the alternative is a `Value`
2968 // per row and this is the path a flatten of a scanned column takes.
2969 Body::Packed { words, width, base, offset } => {
2970 Body::Flat(unpack(&self.ty, words, *offset, *width, *base, &at)?)
2971 }
2972 // A gather keeps the form, which is what makes selecting rows out of a string column
2973 // cost sixteen bytes a row instead of the bytes of the strings. The arena it shares is
2974 // the whole arena and not the part the kept rows point at, so a selection that throws
2975 // most of a page away goes on holding the page. That is the trade the form is: a cut and
2976 // a filter are cheap and the memory comes back when the last vector over the page goes,
2977 // and a caller that wants the bytes narrowed asks for a flatten.
2978 Body::Views { views, arena } if forms_stay => Body::Views {
2979 views: at
2980 .iter()
2981 .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
2982 .collect(),
2983 arena: Arc::clone(arena),
2984 },
2985 // Flattening promises a data slice, and a flat string column is views over an arena
2986 // just as this form is, so when the arena is a page the flatten is the views and
2987 // nothing else. The form is given up, which is what was asked for, and not the sharing,
2988 // which nobody asked to have given up: a result set of six million strings used to copy
2989 // every byte of them out of the pages they were already sitting in.
2990 Body::Views { views, arena } if arena.is_shared() => {
2991 Body::Flat(Data::Varlen(StringColumn::from_parts(
2992 at.iter()
2993 .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
2994 .collect(),
2995 (**arena).clone(),
2996 )))
2997 }
2998 // The arena is this vector's own, so there is nothing to share and the bytes are copied
2999 // out into an arena of their own. The total is known before any of it is copied, the
3000 // way the flat copy works it out, so the new arena is one allocation.
3001 Body::Views { views, arena } => {
3002 let mut out = StringColumn::with_capacity(at.len());
3003 out.reserve_bytes(
3004 at.iter()
3005 .filter_map(|&index| views.get(index))
3006 .filter(|view| !view.is_inline())
3007 .map(StringView::len)
3008 .sum(),
3009 );
3010 for &index in &at {
3011 let bytes = views.get(index).and_then(|view| view.bytes_in(arena));
3012 out.push_bytes(bytes.unwrap_or_default());
3013 }
3014 Body::Flat(Data::Varlen(out))
3015 }
3016 Body::ExternalText { source } => {
3017 let mut out = StringColumn::with_capacity(at.len());
3018 for &index in &at {
3019 out.push_bytes(source.bytes_at(index)?.unwrap_or_default());
3020 }
3021 Body::Flat(Data::Varlen(out))
3022 }
3023 // A gather keeps the form, because the codes do not move and a span survives being put
3024 // in an order the codes are not in. A position that resolved to nowhere gets the empty
3025 // span, which decompresses to no bytes, which is the zero every other layout writes.
3026 Body::Coded { codes, spans, table } if forms_stay => Body::Coded {
3027 codes: Arc::clone(codes),
3028 spans: at
3029 .iter()
3030 .map(|&index| spans.get(index).copied().unwrap_or((0, 0)))
3031 .collect(),
3032 table: Arc::clone(table),
3033 },
3034 // Flattening decompresses, which is the price of the data slice it promises. The scratch
3035 // buffer is reused across rows, so this is one allocation for the whole column rather
3036 // than one per row the way reading it a value at a time would be.
3037 Body::Coded { codes, spans, table } => {
3038 let mut out = StringColumn::with_capacity(at.len());
3039 let mut scratch = Vec::new();
3040 for &index in &at {
3041 scratch.clear();
3042 let span = spans
3043 .get(index)
3044 .and_then(|&(from, to)| codes.get(from as usize..to as usize));
3045 if let Some(span) = span {
3046 table.decompress(span, &mut scratch)?;
3047 }
3048 out.push_bytes(&scratch);
3049 }
3050 Body::Flat(Data::Varlen(out))
3051 }
3052 // The entries move and the child does not, which is the same trade the string forms
3053 // make and is why a gather of a list column costs eight bytes a row however long the
3054 // lists are. A position that resolved to nowhere gets a zero length entry, and the mask
3055 // already says it is null, so the entry is never read.
3056 //
3057 // This arm ignores `forms_stay`, unlike every arm above it, because there is nothing
3058 // flatter for a list to become. The other forms are all cheaper ways of writing down a
3059 // column of scalars and flattening gives up the saving to hand back a data slice, and a
3060 // list has no data slice in any form, so a flatten of one is this and a caller reading it
3061 // goes through `list_parts` either way.
3062 Body::Nested { entries, child } => Body::Nested {
3063 entries: at
3064 .iter()
3065 .map(|&index| entries.get(index).copied().unwrap_or((0, 0)))
3066 .collect(),
3067 child: Arc::clone(child),
3068 },
3069 // Every child gathered at the same positions, for the reason the cut cuts every child:
3070 // there are no entries to permute instead, so the permutation happens once per field. The
3071 // positions handed down are the resolved ones, sentinel and all, so a row that resolved to
3072 // nowhere comes back null in each field as well as null here.
3073 //
3074 // `forms_stay` is passed straight through rather than ignored, which is the opposite of
3075 // what the list arm does, and the difference is real. There is nothing flatter for a list
3076 // to become, and a struct is only as flat as its fields are, so a flatten of a struct
3077 // column is a flatten of each field and a caller that asked for data slices gets them.
3078 Body::Fields { children } => Body::Fields {
3079 children: children
3080 .iter()
3081 .map(|child| child.copied(at.clone(), forms_stay).map(Arc::new))
3082 .collect::<Result<Vec<_>>>()?,
3083 },
3084 // Unreachable, because `resolve` walks past every form that points at another vector
3085 // and stops at the first body that does not.
3086 Body::Dictionary { .. } | Body::Runs { .. } | Body::Gathered { .. } => {
3087 return Err(Error::internal(
3088 "a form that points somewhere survived being resolved",
3089 ));
3090 }
3091 };
3092 Ok(Self { ty: self.ty.clone(), len: rows, validity, body })
3093 }
3094
3095 /// Where each wanted position lives in the first body that points nowhere else, and that body.
3096 ///
3097 /// A position that is null anywhere on the way down, or past the end of anything on the way
3098 /// down, comes back as [`NOWHERE`]. That single sentinel is what keeps the copy loop from
3099 /// carrying a validity mask alongside the positions it is already walking.
3100 fn resolve(&self, mut at: Vec<usize>) -> (Vec<usize>, &Self) {
3101 let mut source = self;
3102 loop {
3103 for slot in &mut at {
3104 if *slot >= source.len || !source.validity.is_valid(*slot) {
3105 *slot = NOWHERE;
3106 }
3107 }
3108 source = match &source.body {
3109 Body::Dictionary { codes, values, .. } => {
3110 for slot in &mut at {
3111 *slot = match codes.get(*slot) {
3112 Some(&code) => code as usize,
3113 None => NOWHERE,
3114 };
3115 }
3116 values.as_ref()
3117 }
3118 // A run length body is a dictionary whose code is worked out from the position
3119 // rather than stored, so the walk down is the same walk with a search where the
3120 // lookup was. `NOWHERE` searches for nothing and stays `NOWHERE`.
3121 Body::Runs { ends, values } => {
3122 for slot in &mut at {
3123 *slot = run_holding(ends, *slot).unwrap_or(NOWHERE);
3124 }
3125 values.as_ref()
3126 }
3127 // The same walk the dictionary above takes, with the sentinel folded into the one
3128 // this loop already has. That composition is the whole reason a gather is a body
3129 // rather than an operator: a filter over the output of a link join selects into the
3130 // ids and copies nothing, and a gather off a gather is one walk down to whatever is
3131 // at the bottom rather than two passes over the parent.
3132 Body::Gathered { source: below, rids, offset } => {
3133 for slot in &mut at {
3134 *slot = if *slot == NOWHERE {
3135 NOWHERE
3136 } else {
3137 row_of(rids, *offset, *slot).unwrap_or(NOWHERE)
3138 };
3139 }
3140 below.as_ref()
3141 }
3142 _ => return (at, source),
3143 };
3144 }
3145 }
3146}
3147
3148/// So that a kernel can take its operands as either a list of vectors or a list of references.
3149///
3150/// A caller that built a `Vec<Vector>` and a caller whose operands are already somewhere else, in a
3151/// chunk or in an evaluator's scratch, want the same kernel. Without this the second kind has to
3152/// clone every operand into a `Vec` to satisfy the signature, and a clone of a vector is a copy of
3153/// the whole column, so the type would be charging real memory traffic for nothing.
3154impl AsRef<Vector> for Vector {
3155 fn as_ref(&self) -> &Vector {
3156 self
3157 }
3158}
3159
3160/// The bits of a packed vector and what they mean, for a kernel that wants to stay in code space.
3161///
3162/// Borrowed from the vector rather than owning anything, so getting one costs nothing and a kernel
3163/// that finds it cannot use them has given up nothing by asking.
3164#[derive(Debug, Clone, Copy)]
3165pub struct Packed<'a> {
3166 words: &'a [u64],
3167 width: u32,
3168 base: i128,
3169 offset: usize,
3170}
3171
3172impl Packed<'_> {
3173 /// Packed words. A persisted vector also records [`Self::offset`].
3174 #[must_use]
3175 pub fn words(&self) -> &[u64] {
3176 self.words
3177 }
3178
3179 /// Bit offset, in rows, of the first value.
3180 #[must_use]
3181 pub fn offset(&self) -> usize {
3182 self.offset
3183 }
3184
3185 /// How many bits one code takes, between one and [`PACKED_WIDTH_MAX`].
3186 #[must_use]
3187 pub fn width(&self) -> u32 {
3188 self.width
3189 }
3190
3191 /// What zero means, so that the value of a row is the base plus its code.
3192 #[must_use]
3193 pub fn base(&self) -> i128 {
3194 self.base
3195 }
3196
3197 /// The largest value this vector can be holding, whatever it is actually holding.
3198 ///
3199 /// With [`Self::base`] this is the pair a comparison kernel wants first. A literal outside the
3200 /// two answers every row of the vector the same way, which is a whole chunk decided without a
3201 /// bit being read, and that is the case a zone map would have caught if there were one here.
3202 #[must_use]
3203 pub fn ceiling(&self) -> i128 {
3204 self.base + i128::from(u64::MAX >> (u64::BITS - self.width))
3205 }
3206
3207 /// The code of row `row`, which is its value minus [`Self::base`].
3208 ///
3209 /// Out of range rows read as zero rather than panicking, the way every other accessor in this
3210 /// file answers for a row that is not there.
3211 ///
3212 /// Marked inline because every caller that matters is a kernel in another crate reading one code
3213 /// per row, and thin LTO was leaving it as a call there. On TPC-H SF1 that call was 1.5 percent of
3214 /// the suite and a tenth of q12.
3215 #[must_use]
3216 #[inline]
3217 pub fn code(&self, row: usize) -> u64 {
3218 code_at(self.words, (self.offset + row) * self.width as usize, self.width)
3219 }
3220
3221 /// Which code a value would have, and `None` for a value this vector cannot be holding.
3222 ///
3223 /// The translation a comparison does once per vector so that it does not have to unpack once per
3224 /// row. `None` is the useful answer rather than a failure: it says the literal is outside the
3225 /// packed range, so every row compares against it the same way.
3226 #[must_use]
3227 pub fn code_of(&self, value: i128) -> Option<u64> {
3228 u64::try_from(value.checked_sub(self.base)?).ok().filter(|&code| code <= self.mask())
3229 }
3230
3231 /// The largest code the width allows.
3232 fn mask(&self) -> u64 {
3233 u64::MAX >> (u64::BITS - self.width)
3234 }
3235}
3236
3237/// The widest a packed code is allowed to be.
3238///
3239/// Sixty three rather than sixty four so that a mask is `u64::MAX >> (64 - width)` with no shift of
3240/// a whole word in it, and reading a code is one branch on whether it straddles rather than two. A
3241/// sixty four bit code saves nothing anyway, since it is the layout it came from.
3242pub const PACKED_WIDTH_MAX: u32 = 63;
3243
3244/// How much smaller packing has to be before it is worth the shift and the mask on every read.
3245///
3246/// Two, so a column packs when the bits come to half the flat size or less. A column that would save
3247/// a tenth stays flat, because a tenth of a column is not worth turning every read of it into
3248/// arithmetic, and the whole argument for the form is that a narrow column saves most of itself.
3249pub const PACKING_PAYS_AT: usize = 2;
3250
3251/// How much smaller compressing has to be before it is worth a decompression on every read.
3252///
3253/// Two, the same rule packing follows and for the same reason. FSST gets about that on text, so a
3254/// column of English or of URLs compresses and a column of short codes or of random bytes does not,
3255/// which is the right answer for both.
3256pub const FSST_PAYS_AT: usize = 2;
3257
3258/// The codes of a compressed column and the table they are against.
3259///
3260/// Handed out by [`Vector::coded_parts`] so a kernel can work in code space. Nothing here
3261/// decompresses, which is the point: [`Self::encode`] puts the literal into the same space the rows
3262/// are already in, and after that an equality test is a byte slice comparison.
3263#[derive(Debug, Clone, Copy)]
3264pub struct Coded<'a> {
3265 codes: &'a [u8],
3266 spans: &'a [(u32, u32)],
3267 table: &'a SymbolTable,
3268}
3269
3270impl Coded<'_> {
3271 /// The table every row in this vector is compressed against.
3272 #[must_use]
3273 pub fn table(&self) -> &SymbolTable {
3274 self.table
3275 }
3276
3277 /// The code bytes of one row, still compressed.
3278 #[must_use]
3279 pub fn row(&self, row: usize) -> Option<&[u8]> {
3280 let &(from, to) = self.spans.get(row)?;
3281 self.codes.get(from as usize..to as usize)
3282 }
3283
3284 /// Some bytes in the code space this vector is in.
3285 ///
3286 /// The literal side of an equality filter. Compressing is a function of the table and the bytes,
3287 /// so two strings compress to the same codes exactly when they are the same string, and an
3288 /// equality test on the codes is an equality test on the strings with no decompression in it.
3289 #[must_use]
3290 pub fn encode(&self, bytes: &[u8]) -> Vec<u8> {
3291 let mut out = Vec::with_capacity(bytes.len());
3292 self.table.compress(bytes, &mut out);
3293 out
3294 }
3295}
3296
3297/// The first `len` of a run of some narrower signed width, sign extended into `out`.
3298///
3299/// Written once and called from the three narrow arms of [`Data::signed_block`], so that the sign
3300/// extension is one loop the compiler can widen rather than three written out by hand.
3301fn widen<T: Copy + Into<i64>>(run: &[T], len: usize, out: &mut Vec<i64>) -> bool {
3302 match run.get(..len) {
3303 Some(run) => {
3304 out.extend(run.iter().map(|&x| x.into()));
3305 true
3306 }
3307 None => false,
3308 }
3309}
3310
3311/// One holder's share of a part that several vectors are reading at the same time.
3312///
3313/// The rule [`Buffer::footprint`] already uses for a shared page. Everything holding the part asks
3314/// this, so what they say between them comes to about what the part costs rather than to the part
3315/// times the number of them, and the answer is never zero for a part that costs anything, because a
3316/// caller with a reference is at least one holder.
3317fn share<T: ?Sized>(bytes: usize, held: &Arc<T>) -> usize {
3318 bytes / Arc::strong_count(held).max(1)
3319}
3320
3321/// How many words hold `len` codes of `width` bits.
3322fn words_for(len: usize, width: u32) -> usize {
3323 (len * width as usize).div_ceil(u64::BITS as usize)
3324}
3325
3326/// The lowest and highest value a type's layout can hold, and `None` for a type with no integer one.
3327///
3328/// This is also the test of whether a type can be packed at all, and it is the only one, so the
3329/// layouts listed here and the layouts [`pack`] and [`unpack`] know how to walk are the same list
3330/// from the same macro and cannot drift apart.
3331fn layout_range(ty: &LogicalType) -> Option<(i128, i128)> {
3332 use rudb_common::PhysicalType as P;
3333 macro_rules! ranges {
3334 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3335 match ty.physical() {
3336 $(P::$variant => Some((i128::from(<$native>::MIN), i128::from(<$native>::MAX))),)+
3337 _ => None,
3338 }
3339 };
3340 }
3341 crate::for_each_layout!(exact, ranges)
3342}
3343
3344/// The lowest and highest value in the first `len` slots of a run of integer data.
3345///
3346/// `None` for data that is not integers, which is what says a column cannot be packed. The null
3347/// slots are in the span, holding whatever zero was written into them, which
3348/// [`Vector::bit_packed`] says more about.
3349fn span_of(data: &Data, len: usize) -> Option<(i128, i128)> {
3350 macro_rules! spans {
3351 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3352 match data {
3353 $(Data::$variant(values) => {
3354 let mut low = i128::MAX;
3355 let mut high = i128::MIN;
3356 for &value in values.as_slice().iter().take(len) {
3357 let value = i128::from(value);
3358 low = low.min(value);
3359 high = high.max(value);
3360 }
3361 (low <= high).then_some((low, high))
3362 })+
3363 _ => None,
3364 }
3365 };
3366 }
3367 crate::for_each_layout!(exact, spans)
3368}
3369
3370/// The first `len` values of a run of integer data, written out as codes of `width` bits from `base`.
3371fn pack(data: &Data, len: usize, base: i128, width: u32) -> Vec<u64> {
3372 let mut words = vec![0u64; words_for(len, width)];
3373 macro_rules! packing {
3374 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3375 match data {
3376 $(Data::$variant(values) => {
3377 for (row, &value) in values.as_slice().iter().take(len).enumerate() {
3378 // In range because `base` and `width` came from the span of this same run.
3379 let code = u64::try_from(i128::from(value) - base).unwrap_or(0);
3380 write_code(&mut words, row * width as usize, width, code);
3381 }
3382 })+
3383 _ => {}
3384 }
3385 };
3386 }
3387 crate::for_each_layout!(exact, packing);
3388 words
3389}
3390
3391/// The codes at the given rows, unpacked into the flat layout the type calls for.
3392///
3393/// A row of [`NOWHERE`] writes the layout's zero, which is the rule [`copy_of`] follows for the same
3394/// reason: every layout here is a parallel array to a validity mask, so a null takes a slot.
3395///
3396/// # Errors
3397///
3398/// If the type has no flat layout, which a packed vector cannot have and which is checked when one
3399/// is built, so an error here is a bug rather than a caller mistake.
3400fn unpack(
3401 ty: &LogicalType,
3402 words: &[u64],
3403 offset: usize,
3404 width: u32,
3405 base: i128,
3406 at: &[usize],
3407) -> Result<Data> {
3408 let mut out = empty_data_for(ty)?;
3409 let value_of = |row: usize| {
3410 if row == NOWHERE {
3411 return None;
3412 }
3413 Some(base + i128::from(code_at(words, (offset + row) * width as usize, width)))
3414 };
3415 macro_rules! unpacking {
3416 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3417 match &mut out {
3418 $(Data::$variant(values) => {
3419 values.reserve(at.len());
3420 for &row in at {
3421 // In range because both ends of it were checked when the vector was built.
3422 let value = value_of(row)
3423 .and_then(|value| <$native>::try_from(value).ok())
3424 .unwrap_or($zero);
3425 values.push(value);
3426 }
3427 })+
3428 _ => {
3429 return Err(Error::internal(format!(
3430 "a {ty} vector was packed, which no integer layout allows"
3431 )));
3432 }
3433 }
3434 };
3435 }
3436 crate::for_each_layout!(exact, unpacking);
3437 Ok(out)
3438}
3439
3440/// The `width` bits starting at `bit`, low end first.
3441///
3442/// Zero for bits past the end of the words, which keeps a read of a row that is not there from
3443/// panicking and matches what every other accessor here does with one.
3444#[inline]
3445fn code_at(words: &[u64], bit: usize, width: u32) -> u64 {
3446 let word = bit / u64::BITS as usize;
3447 let shift = (bit % u64::BITS as usize) as u32;
3448 let mask = u64::MAX >> (u64::BITS - width);
3449 let low = words.get(word).copied().unwrap_or(0) >> shift;
3450 let taken = u64::BITS - shift;
3451 if taken >= width {
3452 return low & mask;
3453 }
3454 // The code straddles two words, and `taken` is under the width here so it is under sixty four,
3455 // which is what makes the shift below one the hardware will do rather than one it refuses.
3456 let high = words.get(word + 1).copied().unwrap_or(0) << taken;
3457 (low | high) & mask
3458}
3459
3460/// Writes `width` bits of `code` starting at `bit`, over words that started out zero.
3461fn write_code(words: &mut [u64], bit: usize, width: u32, code: u64) {
3462 let word = bit / u64::BITS as usize;
3463 let shift = (bit % u64::BITS as usize) as u32;
3464 words[word] |= code << shift;
3465 let taken = u64::BITS - shift;
3466 if taken < width {
3467 words[word + 1] |= code >> taken;
3468 }
3469}
3470
3471/// One level of dictionary out of however many levels were handed to [`Vector::dictionary`].
3472///
3473/// Every dictionary in the system is built through that constructor and every one of them comes
3474/// through here first, so the invariant this maintains is that the vector a dictionary points at is
3475/// never itself a dictionary that could have been composed away. That makes the work a single `if`
3476/// rather than a loop: the inner vector was already composed when it was built, so composing the
3477/// outer codes through it leaves the result no deeper than the inner vector already was.
3478///
3479/// The codes are indexed rather than fetched with `get`, because the caller has already walked the
3480/// whole outer array to check that every code is in range and the inner array is exactly as long as
3481/// the vector those codes were checked against.
3482fn compose(codes: Vec<u32>, values: Arc<Vector>) -> (Vec<u32>, Arc<Vector>) {
3483 // A dictionary carrying a validity of its own is one whose nulls live at this level rather than
3484 // in the values, which is the one thing composition cannot carry down with it.
3485 if !matches!(values.validity, Validity::AllValid) {
3486 return (codes, values);
3487 }
3488 let Body::Dictionary { codes: inner, values: leaf, .. } = &values.body else {
3489 return (codes, values);
3490 };
3491 debug_assert!(
3492 !matches!(leaf.body, Body::Dictionary { .. })
3493 || !matches!(leaf.validity, Validity::AllValid),
3494 "a dictionary was stacked on a dictionary without going through the constructor"
3495 );
3496 // The leaf is handed on as the handle it already is. Nothing here reads it and nothing here
3497 // changes it, so the composed dictionary points at the same values the stacked one did and
3498 // whoever else is holding them keeps holding them. This used to take them out of the `Arc`,
3499 // which copied the whole leaf whenever anybody else was still reading it, and a scan selecting
3500 // rows out of a chunk whose column came from a shared page dictionary is exactly that: the page
3501 // holds the leaf, every chunk cut from the page composes through it, and every one of those
3502 // cuts copied the page's dictionary. TPC-H q21 does it once per thousand rows of `lineitem`.
3503 let composed = codes.iter().map(|&code| inner[code as usize]).collect();
3504 (composed, Arc::clone(leaf))
3505}
3506
3507/// How many rows a run has to cover on average before run length encoding is smaller.
3508///
3509/// A run costs its value plus the four bytes of its end, so on a four byte column a run of two rows
3510/// breaks even and a run of three wins. Wider columns win sooner and narrower ones later, and this
3511/// is the one ratio for all of them because a threshold per width is a table that has to be right
3512/// nine times rather than once. It is a constant with a name so that the sweep that eventually moves
3513/// it has something to move.
3514const RUNS_PAY_AT: usize = 2;
3515
3516/// Which run holds `row`, given ends that are exclusive and increasing.
3517///
3518/// A binary search rather than a scan, because the callers that ask this are the ones that are not
3519/// walking the runs in order: a single value read out of a result set, or a gather at scattered
3520/// positions. Anything walking in order should be reading [`Vector::run_parts`] instead, which is
3521/// what the form is for.
3522fn run_holding(ends: &[u32], row: usize) -> Option<usize> {
3523 let row = u32::try_from(row).ok()?;
3524 let run = match ends.binary_search(&row) {
3525 // The ends are exclusive, so landing exactly on one means the row is the first of the next.
3526 Ok(at) => at + 1,
3527 Err(at) => at,
3528 };
3529 (run < ends.len()).then_some(run)
3530}
3531
3532/// The row each run ends at, for a flat body read alongside the validity that goes with it.
3533///
3534/// Two adjacent nulls are one run, because a reader of either gets a null and cannot tell them
3535/// apart. A null between two equal values is three runs for the same reason, since the null is a
3536/// value of the column as far as anything reading it is concerned.
3537///
3538/// The comparison is per layout rather than per `Value`, which is the whole reason this is a macro.
3539/// A `Value` a row would allocate a string per row on a `VARCHAR` column and would be the exact
3540/// defect `cargo xtask rowloop` exists to fail the build on.
3541fn boundaries(data: &Data, validity: &Validity, len: usize) -> Vec<u32> {
3542 if len == 0 {
3543 return Vec::new();
3544 }
3545 let breaks = |ends: &mut Vec<u32>, mut differs: Box<dyn FnMut(usize, usize) -> bool + '_>| {
3546 for row in 1..len {
3547 let same = match (validity.is_valid(row), validity.is_valid(row - 1)) {
3548 (false, false) => true,
3549 (true, true) => !differs(row, row - 1),
3550 _ => false,
3551 };
3552 if !same {
3553 ends.push(u32::try_from(row).unwrap_or(u32::MAX));
3554 }
3555 }
3556 ends.push(u32::try_from(len).unwrap_or(u32::MAX));
3557 };
3558 let mut ends = Vec::new();
3559 macro_rules! walked {
3560 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3561 match data {
3562 // No values at all, so every row is the same null and the column is one run.
3563 Data::Empty => ends.push(u32::try_from(len).unwrap_or(u32::MAX)),
3564 $(Data::$variant(values) => {
3565 breaks(&mut ends, Box::new(|a, b| values.get(a) != values.get(b)));
3566 })+
3567 Data::Varlen(values) => {
3568 breaks(&mut ends, Box::new(|a, b| values.bytes(a) != values.bytes(b)));
3569 }
3570 }
3571 };
3572 }
3573 crate::for_each_layout!(fixed, walked);
3574 ends
3575}
3576
3577/// The position of a value that is not anywhere, because it is null or out of range.
3578///
3579/// `usize::MAX` rather than an `Option<usize>`, because the copy loop's bounds check rejects it for
3580/// free and an `Option` would put a second branch next to the one already there.
3581pub(crate) const NOWHERE: usize = usize::MAX;
3582
3583/// The row id of a row that is not in the source, which reads as null.
3584///
3585/// Public because whoever builds a [`Form::Gathered`] vector has to write it, and it is `u32::MAX`
3586/// for the reason the crate's own offset sentinel is `usize::MAX`: a bounds check the reader is
3587/// doing anyway rejects it, where an `Option<u32>` would be eight bytes a row instead of four and a
3588/// second branch beside the one already there. It costs the last row of a four billion row source,
3589/// which is a source no column in this engine has.
3590pub const NO_ROW: u32 = u32::MAX;
3591
3592/// Which source row a gathered row names, and `None` when it names none.
3593///
3594/// The `Option` is what every reader of [`Body::Gathered`] that returns an `Option` wants, so the
3595/// three cases that are all *there is nothing here*, past the end of the ids, the sentinel, and an
3596/// id that does not fit a `usize`, are collapsed once here rather than three times each.
3597fn row_of(rids: &[u32], offset: usize, index: usize) -> Option<usize> {
3598 match rids.get(offset + index) {
3599 Some(&NO_ROW) | None => None,
3600 Some(&rid) => Some(rid as usize),
3601 }
3602}
3603
3604/// A run of data copied at the given positions, with a zero wherever the position is [`NOWHERE`].
3605///
3606/// A zero and not a skip, because every layout here is a parallel array to a validity mask and a
3607/// short one would put every value after the first null at the wrong index. It is the same rule
3608/// [`push_value`] follows for a null.
3609/// A contiguous run of a flat body, copied out.
3610///
3611/// The counterpart to [`copy_of`] for the one case that is a range rather than a set of positions,
3612/// which is what [`Vector::slice`] asks for. Every fixed width layout is one `memcpy` and the
3613/// string layout is a run of views and their bytes, where `copy_of` is a bounds checked index and a
3614/// null test per row.
3615///
3616/// The caller has already checked that `end` is inside the vector, and a body whose data is shorter
3617/// than its vector claims is a bug elsewhere, so a short run is clamped rather than reported.
3618///
3619/// A fixed width run over a buffer that is a window into a page does not copy anything, because
3620/// [`Buffer::slice`] moves the offset instead. That is the case a scan over stored memory is in, and
3621/// it is why the flat body is no longer the one form of a vector whose cut costs an allocation.
3622fn run_of(data: &Data, at: usize, end: usize) -> Data {
3623 macro_rules! run {
3624 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3625 match data {
3626 Data::Empty => Data::Empty,
3627 $(Data::$variant(values) => {
3628 let held = values.len();
3629 let from = at.min(held);
3630 let to = end.max(from).min(held);
3631 if to == end {
3632 // The whole run is there, so this is a window on a shared page and a copy on
3633 // an owned one, decided inside the buffer rather than here.
3634 Data::$variant(values.slice(from, end - from))
3635 } else {
3636 let values = values.as_slice();
3637 let mut out = Buffer::with_capacity(end - at);
3638 out.extend_from_slice(&values[from..to]);
3639 // A body shorter than the rows asked for pads with the zero every layout
3640 // uses for a null, which is the answer `copy_of` gives for a position past
3641 // the end.
3642 // row at a time: never runs on a vector whose data matches its length.
3643 for _ in to..end {
3644 out.push($zero);
3645 }
3646 Data::$variant(out)
3647 }
3648 })+
3649 // A view says where its bytes are, so a run of rows is not a run of bytes and this
3650 // is the one layout whose cut is still a loop. The total is known before any of it
3651 // is copied, so the arena is one allocation.
3652 //
3653 // Unless the payload is a page, in which case the cut points at the same page the
3654 // column does and no byte of it moves. That is the case a scan of a stored column
3655 // is in, and it is the whole of why a producer pages its payload: a page cut into
3656 // chunk sized pieces used to copy every byte of every long string once per piece.
3657 Data::Varlen(values) => {
3658 if let Some(shared) = values.viewing(at..end) {
3659 return Data::Varlen(shared);
3660 }
3661 let views = values.views();
3662 let mut out = StringColumn::with_capacity(end - at);
3663 out.reserve_bytes(
3664 views
3665 .get(at.min(views.len())..end.min(views.len()))
3666 .unwrap_or(&[])
3667 .iter()
3668 .filter(|view| !view.is_inline())
3669 .map(StringView::len)
3670 .sum(),
3671 );
3672 // row at a time: see above, the bytes of consecutive rows need not be next to
3673 // each other.
3674 for index in at..end {
3675 out.push_from(values, index);
3676 }
3677 Data::Varlen(out)
3678 }
3679 }
3680 };
3681 }
3682 crate::for_each_layout!(fixed, run)
3683}
3684
3685/// The values of `data` written to the places `inverse` gives them, the other way round from
3686/// [`copy_of`]: value `n` lands at `inverse[n]`.
3687///
3688/// `inverse` is a permutation of the positions of `data` and the answer is as long as it. A place
3689/// past the end is dropped rather than trusted, and a place nobody wrote keeps the zero, the same
3690/// zero a gather writes for a position that resolved to nowhere. Strings are turned back into
3691/// positions and gathered, because their one caller moves the views itself and never sends them.
3692pub(crate) fn placed_of(data: &Data, inverse: &[u32]) -> Data {
3693 macro_rules! placed {
3694 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3695 match data {
3696 $(Data::$variant(values) => {
3697 let mut out: Vec<$native> = vec![$zero; inverse.len()];
3698 for (value, &to) in values.as_slice().iter().zip(inverse) {
3699 if let Some(slot) = out.get_mut(to as usize) {
3700 *slot = *value;
3701 }
3702 }
3703 Data::$variant(Buffer::from_vec(out))
3704 })+
3705 Data::Empty => Data::Empty,
3706 // Turned back round into positions and gathered, so a caller that does hand this
3707 // strings gets the right answer rather than a missing arm.
3708 Data::Varlen(_) => {
3709 let mut at = vec![NOWHERE; inverse.len()];
3710 for (row, &to) in inverse.iter().enumerate() {
3711 if let Some(slot) = at.get_mut(to as usize) {
3712 *slot = row;
3713 }
3714 }
3715 copy_of(data, &at)
3716 }
3717 }
3718 };
3719 }
3720 crate::for_each_layout!(fixed, placed)
3721}
3722
3723pub(crate) fn copy_of(data: &Data, at: &[usize]) -> Data {
3724 macro_rules! copied {
3725 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3726 match data {
3727 Data::Empty => Data::Empty,
3728 $(Data::$variant(values) => {
3729 let values = values.as_slice();
3730 // Into a `Vec` and then into a buffer, rather than pushing at the buffer. A
3731 // push asks the buffer whether it owns its run and copies the page out if it
3732 // does not, which is the copy on write point and is the right answer for a
3733 // caller writing one value. This caller is writing `at.len()` of them into a
3734 // run it made itself one line earlier, so the question has one answer and it
3735 // is asked once by not being asked at all. The map is exact sized, so the
3736 // extend reserves once and writes without a capacity check per value.
3737 let mut out: Vec<$native> = Vec::with_capacity(at.len());
3738 // One bounds check rather than a null test and a bounds check, because
3739 // `NOWHERE` is past the end of every slice there can be.
3740 out.extend(at.iter().map(|&index| values.get(index).copied().unwrap_or($zero)));
3741 Data::$variant(Buffer::from_vec(out))
3742 })+
3743 // The one layout where a gather is a copy of bytes rather than a copy of fixed
3744 // width slots, and the reason compaction is a decision rather than a default on a
3745 // string column. A payload that is a page is the exception: the gathered views
3746 // point at the page the column already points at, so the gather is sixteen bytes a
3747 // row and the bytes stay where the page put them.
3748 Data::Varlen(values) => {
3749 if let Some(shared) = values.viewing(at.iter().copied()) {
3750 return Data::Varlen(shared);
3751 }
3752 let mut out = StringColumn::with_capacity(at.len());
3753 // The bytes are known before any of them are copied, because a view carries its
3754 // length and the wanted positions are already in hand, so the arena is one
3755 // allocation rather than a run of doublings that each copy what the last one
3756 // copied.
3757 let views = values.views();
3758 out.reserve_bytes(
3759 at.iter()
3760 .filter_map(|&index| views.get(index))
3761 .filter(|view| !view.is_inline())
3762 .map(StringView::len)
3763 .sum(),
3764 );
3765 for &index in at {
3766 out.push_from(values, index);
3767 }
3768 Data::Varlen(out)
3769 }
3770 }
3771 };
3772 }
3773 crate::for_each_layout!(fixed, copied)
3774}
3775
3776/// The physical layout a run of data is in, for the check that it matches its type.
3777///
3778/// The two enums name their variants the same way on purpose, so this is one generated arm rather
3779/// than sixteen chances to pair the wrong two up.
3780pub(crate) fn layout_of(data: &Data) -> rudb_common::PhysicalType {
3781 use rudb_common::PhysicalType as P;
3782 macro_rules! layouts {
3783 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3784 match data {
3785 Data::Empty => P::Empty,
3786 $(Data::$variant(_) => P::$variant,)+
3787 }
3788 };
3789 }
3790 crate::for_each_layout!(all, layouts)
3791}
3792
3793/// One value out of a run of data, given what the run means.
3794///
3795/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
3796/// from an `INTEGER` and that is the whole reason the two are kept apart.
3797fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
3798 let signed = || data.signed_at(index);
3799 let unsigned = || data.unsigned_at(index);
3800 let value = match ty {
3801 LogicalType::Boolean => match data {
3802 Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
3803 _ => None,
3804 },
3805 LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
3806 LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
3807 LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
3808 LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
3809 LogicalType::HugeInt => signed().map(Value::HugeInt),
3810 LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
3811 LogicalType::USmallInt => {
3812 unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
3813 }
3814 LogicalType::UInteger => {
3815 unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
3816 }
3817 LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
3818 LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
3819 LogicalType::Float => match data {
3820 Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
3821 _ => None,
3822 },
3823 LogicalType::Double => match data {
3824 Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
3825 _ => None,
3826 },
3827 LogicalType::Decimal { width, scale } => {
3828 signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
3829 }
3830 LogicalType::Varchar | LogicalType::Blob | LogicalType::Bit => {
3831 data.bytes_at(index).map(|bytes| bytes_as(ty, bytes))
3832 }
3833 LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
3834 LogicalType::Time => signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time),
3835 LogicalType::TimeTz => signed().and_then(|x| i64::try_from(x).ok()).map(Value::TimeTz),
3836 LogicalType::Timestamp
3837 | LogicalType::TimestampS
3838 | LogicalType::TimestampMs
3839 | LogicalType::TimestampNs => {
3840 signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
3841 }
3842 LogicalType::TimestampTz => {
3843 signed().and_then(|x| i64::try_from(x).ok()).map(Value::TimestampTz)
3844 }
3845 LogicalType::Interval => match data {
3846 Data::Interval(v) => {
3847 v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
3848 }
3849 _ => None,
3850 },
3851 _ => None,
3852 };
3853 value.unwrap_or(Value::Null)
3854}
3855
3856/// The fields a struct type names, and nothing for any other type.
3857///
3858/// Only a `STRUCT` vector has a [`Body::Fields`] body, and the two are built together, so in practice
3859/// the empty slice is unreachable and is here so that reading a field name is not a panic if that ever
3860/// stops being true. A struct vector whose type has fewer fields than it has children answers about
3861/// the fields it can name, because the zip stops at the shorter of the two.
3862fn fields_of(ty: &LogicalType) -> &[Field] {
3863 match ty {
3864 LogicalType::Struct(fields) => fields,
3865 _ => &[],
3866 }
3867}
3868
3869/// One row of a string column as a value, given what its bytes are meant to be read as.
3870///
3871/// Both forms that hold strings come through here, so a row that is a `BLOB` in a flat column is a
3872/// `BLOB` in a string view column too. Bytes that are not text in a `VARCHAR` column are a null
3873/// rather than a panic, since everything that got in went in as a string and a column that has
3874/// something else in it is a bug somewhere earlier that a read should not turn into a crash.
3875fn bytes_as(ty: &LogicalType, bytes: &[u8]) -> Value {
3876 match ty {
3877 LogicalType::Varchar => {
3878 std::str::from_utf8(bytes).map_or(Value::Null, |text| Value::Varchar(text.to_owned()))
3879 }
3880 LogicalType::Blob | LogicalType::Bit => Value::Blob(bytes.to_vec()),
3881 _ => Value::Null,
3882 }
3883}
3884
3885/// An empty run of data of the right layout for a type.
3886pub(crate) fn empty_data_for(ty: &LogicalType) -> Result<Data> {
3887 use rudb_common::PhysicalType as P;
3888 macro_rules! empties {
3889 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3890 match ty.physical() {
3891 P::Empty => Data::Empty,
3892 $(P::$variant => Data::$variant(Buffer::new()),)+
3893 P::Varlen => Data::Varlen(StringColumn::new()),
3894 other => {
3895 return Err(Error::not_implemented(format!(
3896 "a flat vector of {other:?} data, which arrives with the storage layer"
3897 )));
3898 }
3899 }
3900 };
3901 }
3902 Ok(crate::for_each_layout!(fixed, empties))
3903}
3904
3905/// An empty run of the type's layout with room for `rows` values already taken.
3906///
3907/// For a caller that knows how many values are going in before the first one does, which is a
3908/// producer laying pieces end to end. Growing from empty instead reallocates once per doubling and
3909/// finishes holding a run rounded up to the next power of two, and on a row group of 122,880 values
3910/// that rounding is the last 8,192 of them carried for the life of the table.
3911///
3912/// Bytes are not reserved for a varlen run, because how many of them there are is not the number of
3913/// rows and the caller appending them is the one that can work it out.
3914///
3915/// # Errors
3916///
3917/// If the type has no flat layout, the same as [`empty_data_for`].
3918pub(crate) fn data_for(ty: &LogicalType, rows: usize) -> Result<Data> {
3919 let mut data = empty_data_for(ty)?;
3920 macro_rules! reserved {
3921 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3922 match &mut data {
3923 Data::Empty => {}
3924 $(Data::$variant(values) => values.reserve(rows),)+
3925 Data::Varlen(values) => values.reserve_views(rows),
3926 }
3927 };
3928 }
3929 crate::for_each_layout!(fixed, reserved);
3930 Ok(data)
3931}
3932
3933/// Appends one value to a run of data, or a zero of the right shape when it is null.
3934///
3935/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
3936/// and a run of data with a hole in it would put every value after the hole in the wrong place.
3937fn push_value(data: &mut Data, value: &Value) -> Result<()> {
3938 macro_rules! push {
3939 ($vec:expr, $variant:path, $zero:expr) => {
3940 match value {
3941 Value::Null => $vec.push($zero),
3942 $variant(x) => $vec.push(*x),
3943 other => {
3944 return Err(Error::internal(format!(
3945 "{other:?} does not belong in this vector"
3946 )));
3947 }
3948 }
3949 };
3950 }
3951 // A decimal is stored as its unscaled integer in whatever width its precision needs, which
3952 // `LogicalType::physical` decides and which is why the same `Value::Decimal` is at home in four
3953 // different runs. The narrowing cannot fail for a value the binder produced, because the width
3954 // that chose the run is the width in the value, but it is checked rather than assumed because
3955 // an unchecked cast here would silently store a different number.
3956 macro_rules! decimal {
3957 ($vec:expr, $ty:ty, $unscaled:expr) => {
3958 match <$ty>::try_from(*$unscaled) {
3959 Ok(x) => $vec.push(x),
3960 Err(_) => {
3961 return Err(Error::internal(format!(
3962 "an unscaled decimal of {} does not fit the run its precision chose",
3963 $unscaled
3964 )));
3965 }
3966 }
3967 };
3968 }
3969 match data {
3970 Data::Empty => {}
3971 Data::Bool(v) => push!(v, Value::Boolean, false),
3972 Data::Int8(v) => push!(v, Value::TinyInt, 0),
3973 Data::Int16(v) => match value {
3974 Value::Null => v.push(0),
3975 Value::SmallInt(x) => v.push(*x),
3976 Value::Decimal { unscaled, .. } => decimal!(v, i16, unscaled),
3977 other => return Err(Error::internal(format!("{other:?} is not a 16 bit value"))),
3978 },
3979 Data::Int32(v) => match value {
3980 Value::Null => v.push(0),
3981 Value::Integer(x) | Value::Date(x) => v.push(*x),
3982 Value::Decimal { unscaled, .. } => decimal!(v, i32, unscaled),
3983 other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
3984 },
3985 Data::Int64(v) => match value {
3986 Value::Null => v.push(0),
3987 Value::BigInt(x)
3988 | Value::Time(x)
3989 | Value::TimeTz(x)
3990 | Value::Timestamp(x)
3991 | Value::TimestampTz(x) => v.push(*x),
3992 Value::Decimal { unscaled, .. } => decimal!(v, i64, unscaled),
3993 other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
3994 },
3995 Data::Int128(v) => match value {
3996 Value::Null => v.push(0),
3997 Value::HugeInt(x) => v.push(*x),
3998 Value::Decimal { unscaled, .. } => v.push(*unscaled),
3999 other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
4000 },
4001 Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
4002 Data::UInt16(v) => push!(v, Value::USmallInt, 0),
4003 Data::UInt32(v) => push!(v, Value::UInteger, 0),
4004 Data::UInt64(v) => push!(v, Value::UBigInt, 0),
4005 Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
4006 Data::Float32(v) => push!(v, Value::Float, 0.0),
4007 Data::Float64(v) => push!(v, Value::Double, 0.0),
4008 Data::Interval(v) => match value {
4009 Value::Null => v.push((0, 0, 0)),
4010 Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
4011 other => return Err(Error::internal(format!("{other:?} is not an interval"))),
4012 },
4013 Data::Varlen(column) => match value {
4014 Value::Null => {
4015 column.push("");
4016 }
4017 Value::Varchar(text) => {
4018 column.push(text);
4019 }
4020 // A blob goes in as the bytes it is. The column stores a length and some bytes either
4021 // way, so text is the reading of one rather than a different column, and a blob that
4022 // is not UTF-8 is stored exactly like one that happens to be.
4023 Value::Blob(bytes) => {
4024 column.push_bytes(bytes);
4025 }
4026 other => return Err(Error::internal(format!("{other:?} is not a string"))),
4027 },
4028 }
4029 Ok(())
4030}
4031
4032#[cfg(test)]
4033mod tests {
4034 use std::sync::Arc;
4035
4036 use rudb_common::{Field, LogicalType, Value};
4037
4038 use super::{Body, Data, FSST_PAYS_AT, Form, MAP_KEY, MAP_VALUE, NO_ROW, VECTOR_SIZE, Vector};
4039 use crate::buffer::Buffer;
4040 use crate::fsst::SymbolTable;
4041 use crate::string::{StringColumn, StringView};
4042 use crate::validity::Validity;
4043
4044 fn integers(values: &[i32]) -> Vector {
4045 Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec().into())).unwrap()
4046 }
4047
4048 /// A `Value::List` of integers, which is what a row of a list column arrives as.
4049 fn list(values: &[i32]) -> Value {
4050 Value::List {
4051 element: LogicalType::Integer,
4052 values: values.iter().map(|&v| Value::Integer(v)).collect(),
4053 }
4054 }
4055
4056 fn list_column(rows: &[Value]) -> Vector {
4057 Vector::from_values(LogicalType::list(LogicalType::Integer), rows).unwrap()
4058 }
4059
4060 #[test]
4061 fn a_list_column_is_one_child_and_a_range_per_row() {
4062 let rows = vec![list(&[1, 2, 3]), list(&[]), Value::Null, list(&[4])];
4063 let column = list_column(&rows);
4064 assert_eq!(column.form(), Form::List);
4065 assert_eq!(column.len(), 4);
4066 assert_eq!(column.logical_type(), &LogicalType::list(LogicalType::Integer));
4067 // Four rows and four elements, because a null and an empty list both contribute none.
4068 let (entries, child) = column.list_parts().expect("a list");
4069 assert_eq!(entries, [(0, 3), (3, 0), (3, 0), (3, 1)]);
4070 assert_eq!(child.len(), 4);
4071 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
4072 }
4073
4074 /// The one thing the entries cannot say on their own, so it has to be checked that the mask says
4075 /// it. An empty list is a row that is there and holds nothing, a null is a row that is not there,
4076 /// and both of them have an entry of length zero.
4077 #[test]
4078 fn an_empty_list_and_a_null_list_have_the_same_entry_and_are_different_rows() {
4079 let column = list_column(&[list(&[]), Value::Null]);
4080 let (entries, _) = column.list_parts().expect("a list");
4081 assert_eq!(entries[0].1, entries[1].1, "both entries are empty");
4082 assert!(!column.is_null_at(0), "an empty list is not null");
4083 assert!(column.is_null_at(1), "a null list is null");
4084 assert_eq!(column.value_at(0), list(&[]));
4085 assert_eq!(column.value_at(1), Value::Null);
4086 }
4087
4088 #[test]
4089 fn slicing_a_list_column_shares_the_child_rather_than_copying_it() {
4090 let rows: Vec<Value> = (0..64).map(|row| list(&[row, row + 1, row + 2])).collect();
4091 let column = list_column(&rows);
4092 let cut = column.slice(8, 4).unwrap();
4093 assert_eq!(cut.form(), Form::List);
4094 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[8..12]);
4095 // The entries are absolute positions in a child that was not cut, which is what makes the
4096 // cut eight bytes a row however long the lists are. The elements outside the range are still
4097 // there and nothing points at them.
4098 let (entries, child) = cut.list_parts().expect("a list");
4099 assert_eq!(entries[0], (24, 3));
4100 assert_eq!(child.len(), 192);
4101 }
4102
4103 #[test]
4104 fn gathering_a_list_column_permutes_the_entries_and_leaves_the_child_alone() {
4105 let rows = vec![list(&[1]), list(&[2, 2]), list(&[3, 3, 3])];
4106 let column = list_column(&rows);
4107 let picked = column.gather(&[2, 0, 2]).unwrap();
4108 assert_eq!(
4109 picked.iter().collect::<Vec<_>>(),
4110 [list(&[3, 3, 3]), list(&[1]), list(&[3, 3, 3])]
4111 );
4112 // Two of the three rows are the same row, which is the case a run of offsets cannot write
4113 // down and a start and a length can. That is the whole reason this form carries both.
4114 assert_eq!(picked.list_parts().expect("a list").1.len(), 6);
4115 }
4116
4117 #[test]
4118 fn a_gather_past_the_end_of_a_list_column_is_null_rather_than_somebody_elses_elements() {
4119 let column = list_column(&[list(&[1, 2]), list(&[3])]);
4120 let picked = column.gather(&[1, 9]).unwrap();
4121 assert_eq!(picked.value_at(0), list(&[3]));
4122 assert_eq!(picked.value_at(1), Value::Null);
4123 }
4124
4125 #[test]
4126 fn a_list_of_lists_nests_as_far_as_it_is_written() {
4127 let outer = Value::List {
4128 element: LogicalType::list(LogicalType::Integer),
4129 values: vec![list(&[1, 2]), list(&[3])],
4130 };
4131 let column = Vector::from_values(
4132 LogicalType::list(LogicalType::list(LogicalType::Integer)),
4133 std::slice::from_ref(&outer),
4134 )
4135 .unwrap();
4136 assert_eq!(column.value_at(0), outer);
4137 assert_eq!(column.list_parts().expect("a list").1.form(), Form::List);
4138 }
4139
4140 /// A list row is not bytes and not an integer, and a caller that asks for either gets nothing
4141 /// rather than the first element or a length. Both of those would be a wrong answer that a
4142 /// group by or a hash would read without complaining.
4143 #[test]
4144 fn the_scalar_readers_decline_a_list_instead_of_answering_about_its_elements() {
4145 let column = list_column(&[list(&[7])]);
4146 assert_eq!(column.signed_at(0), None);
4147 assert_eq!(column.bytes_at(0), None);
4148 assert_eq!(column.data(), None);
4149 }
4150
4151 fn pair(a: i32, b: &str) -> Value {
4152 Value::Struct(vec![
4153 ("a".to_string(), Value::Integer(a)),
4154 ("b".to_string(), Value::Varchar(b.to_string())),
4155 ])
4156 }
4157
4158 fn pair_type() -> LogicalType {
4159 LogicalType::Struct(vec![
4160 Field::new("a", LogicalType::Integer),
4161 Field::new("b", LogicalType::Varchar),
4162 ])
4163 }
4164
4165 fn pair_column(rows: &[Value]) -> Vector {
4166 Vector::from_values(pair_type(), rows).unwrap()
4167 }
4168
4169 #[test]
4170 fn a_struct_column_is_one_child_per_field_as_long_as_the_column() {
4171 let rows = vec![pair(1, "x"), pair(2, "y"), pair(3, "z")];
4172 let column = pair_column(&rows);
4173 assert_eq!(column.form(), Form::Struct);
4174 assert_eq!(column.len(), 3);
4175 assert_eq!(column.logical_type(), &pair_type());
4176 // Two children rather than two entries and a child, and both of them as long as the column,
4177 // which is the whole difference between this form and the list one.
4178 let children = column.struct_parts().expect("a struct");
4179 assert_eq!(children.len(), 2);
4180 assert_eq!(children[0].len(), 3);
4181 assert_eq!(children[1].len(), 3);
4182 assert_eq!(children[0].logical_type(), &LogicalType::Integer);
4183 assert_eq!(children[1].logical_type(), &LogicalType::Varchar);
4184 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
4185 }
4186
4187 /// Picking one field out of a struct is picking one child, which is the reason this accessor is
4188 /// public. A projection of `s.a` hands back a vector that already exists, so it costs a pointer
4189 /// rather than a pass over the rows, and that is only true while the children are full length.
4190 #[test]
4191 fn one_field_of_a_struct_column_is_a_column_that_is_already_there() {
4192 let column = pair_column(&[pair(10, "x"), pair(20, "y")]);
4193 let field = &column.struct_parts().expect("a struct")[0];
4194 assert_eq!(field.iter().collect::<Vec<_>>(), [Value::Integer(10), Value::Integer(20)]);
4195 assert_eq!(field.signed_at(1), Some(20), "the field is a scalar column and reads like one");
4196 }
4197
4198 /// A null struct is a bit in the mask at the top and nothing deeper, which is how every other type
4199 /// records a null and is what DuckDB does. The row reads as a single null rather than as a struct of
4200 /// nulls, and the fields underneath are still their own columns.
4201 #[test]
4202 fn a_null_struct_is_the_mask_at_the_top_and_not_a_struct_full_of_nulls() {
4203 let column = pair_column(&[pair(1, "x"), Value::Null]);
4204 assert!(!column.is_null_at(0));
4205 assert!(column.is_null_at(1));
4206 assert_eq!(column.value_at(1), Value::Null);
4207 // A struct row whose every field happens to be null is a different row, and it is not null.
4208 let all_null = pair_column(&[Value::Struct(vec![
4209 ("a".to_string(), Value::Null),
4210 ("b".to_string(), Value::Null),
4211 ])]);
4212 assert!(!all_null.is_null_at(0), "a struct of nulls is a row that is there");
4213 assert_ne!(all_null.value_at(0), Value::Null);
4214 }
4215
4216 #[test]
4217 fn slicing_a_struct_column_cuts_every_field_at_the_same_place() {
4218 let rows: Vec<Value> = (0..64).map(|row| pair(row, "s")).collect();
4219 let column = pair_column(&rows);
4220 let cut = column.slice(8, 4).unwrap();
4221 assert_eq!(cut.form(), Form::Struct);
4222 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[8..12]);
4223 // The cut a list column does not have to do. A list shares its child untouched because the
4224 // entries carry the range, and a struct has no entry standing between the row and the child,
4225 // so every child is four rows long here rather than sixty four.
4226 for child in cut.struct_parts().expect("a struct") {
4227 assert_eq!(child.len(), 4);
4228 }
4229 }
4230
4231 #[test]
4232 fn gathering_a_struct_column_gathers_every_field_at_the_same_positions() {
4233 let column = pair_column(&[pair(1, "x"), pair(2, "y"), pair(3, "z")]);
4234 let picked = column.gather(&[2, 0, 2]).unwrap();
4235 assert_eq!(picked.iter().collect::<Vec<_>>(), [pair(3, "z"), pair(1, "x"), pair(3, "z")]);
4236 for child in picked.struct_parts().expect("a struct") {
4237 assert_eq!(child.len(), 3, "a field is as long as the gather, not as the source");
4238 }
4239 }
4240
4241 #[test]
4242 fn a_gather_past_the_end_of_a_struct_column_is_null_in_every_field_and_at_the_top() {
4243 let column = pair_column(&[pair(1, "x"), pair(2, "y")]);
4244 let picked = column.gather(&[1, 9]).unwrap();
4245 assert_eq!(picked.value_at(0), pair(2, "y"));
4246 assert_eq!(picked.value_at(1), Value::Null);
4247 for child in picked.struct_parts().expect("a struct") {
4248 assert!(child.is_null_at(1), "a row that came from nowhere has no field value either");
4249 }
4250 }
4251
4252 /// The names are matched and not counted, because a caller holding a struct value built in a
4253 /// different order from the type's would otherwise get its columns transposed, and that is a wrong
4254 /// answer that reads as a right one.
4255 #[test]
4256 fn the_fields_of_a_struct_value_go_in_by_name_rather_than_by_position() {
4257 let swapped = Value::Struct(vec![
4258 ("b".to_string(), Value::Varchar("x".to_string())),
4259 ("a".to_string(), Value::Integer(1)),
4260 ]);
4261 let column = pair_column(&[swapped]);
4262 assert_eq!(column.value_at(0), pair(1, "x"));
4263 let wrong = Value::Struct(vec![
4264 ("a".to_string(), Value::Integer(1)),
4265 ("c".to_string(), Value::Varchar("x".to_string())),
4266 ]);
4267 let failed = Vector::from_values(pair_type(), &[wrong]);
4268 assert!(failed.is_err(), "a row with no b field is an error rather than a null b");
4269 }
4270
4271 #[test]
4272 fn a_struct_built_from_children_takes_its_field_names_from_the_caller() {
4273 let column = Vector::structure(vec![
4274 ("a".to_string(), integers(&[1, 2, 3])),
4275 ("b".to_string(), integers(&[4, 5, 6])),
4276 ])
4277 .expect("two columns of three");
4278 assert_eq!(column.len(), 3);
4279 assert_eq!(
4280 column.logical_type(),
4281 &LogicalType::Struct(vec![
4282 Field::new("a", LogicalType::Integer),
4283 Field::new("b", LogicalType::Integer),
4284 ])
4285 );
4286 assert_eq!(
4287 column.value_at(1),
4288 Value::Struct(vec![
4289 ("a".to_string(), Value::Integer(2)),
4290 ("b".to_string(), Value::Integer(5)),
4291 ])
4292 );
4293 }
4294
4295 /// The two mistakes this constructor makes easy, both refused rather than stored. A short field is
4296 /// the one that matters: it would be a struct that reads past the end of one of its own children,
4297 /// which is the same mistake `Vector::list` checks for at the other end.
4298 #[test]
4299 fn a_struct_of_uneven_children_or_of_no_children_is_refused() {
4300 let uneven = Vector::structure(vec![
4301 ("a".to_string(), integers(&[1, 2, 3])),
4302 ("b".to_string(), integers(&[4, 5])),
4303 ]);
4304 assert!(uneven.is_err(), "a field shorter than the struct");
4305 assert!(Vector::structure(vec![]).is_err(), "no field to take a length from");
4306 }
4307
4308 #[test]
4309 fn a_struct_of_lists_and_a_list_of_structs_both_nest() {
4310 let ty =
4311 LogicalType::Struct(vec![Field::new("a", LogicalType::list(LogicalType::Integer))]);
4312 let row = Value::Struct(vec![("a".to_string(), list(&[1, 2]))]);
4313 let column = Vector::from_values(ty, std::slice::from_ref(&row)).unwrap();
4314 assert_eq!(column.value_at(0), row);
4315 assert_eq!(column.struct_parts().expect("a struct")[0].form(), Form::List);
4316
4317 let outer = Value::List { element: pair_type(), values: vec![pair(1, "x"), pair(2, "y")] };
4318 let lists =
4319 Vector::from_values(LogicalType::list(pair_type()), std::slice::from_ref(&outer))
4320 .unwrap();
4321 assert_eq!(lists.value_at(0), outer);
4322 assert_eq!(lists.list_parts().expect("a list").1.form(), Form::Struct);
4323 }
4324
4325 fn tags(pairs: &[(&str, &str)]) -> Value {
4326 Value::map(
4327 LogicalType::Varchar,
4328 LogicalType::Varchar,
4329 pairs
4330 .iter()
4331 .map(|&(key, value)| {
4332 (Value::Varchar(key.to_string()), Value::Varchar(value.to_string()))
4333 })
4334 .collect(),
4335 )
4336 }
4337
4338 fn tag_column(rows: &[Value]) -> Vector {
4339 Vector::from_values(LogicalType::map(LogicalType::Varchar, LogicalType::Varchar), rows)
4340 .unwrap()
4341 }
4342
4343 /// A map is a list of two field structs, which is the whole design, so the test that says so is
4344 /// the one that reaches through both layers and finds the pieces where each of them puts them.
4345 #[test]
4346 fn a_map_column_is_a_list_whose_child_is_a_struct_of_keys_and_values() {
4347 let rows =
4348 vec![tags(&[("a", "b"), ("c", "d")]), tags(&[]), Value::Null, tags(&[("e", "f")])];
4349 let column = tag_column(&rows);
4350 assert_eq!(column.len(), 4);
4351 assert_eq!(
4352 column.logical_type(),
4353 &LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
4354 );
4355 // The physical form is a list's, because the bytes are a list's. The logical type is what
4356 // remembers it is a map, which is the same split `LogicalType::physical` already makes.
4357 assert_eq!(column.form(), Form::List);
4358 let (entries, child) = column.list_parts().expect("the layout of a list");
4359 assert_eq!(entries, [(0, 2), (2, 0), (2, 0), (2, 1)]);
4360 assert_eq!(child.form(), Form::Struct);
4361 assert_eq!(
4362 child.logical_type(),
4363 &LogicalType::Struct(vec![
4364 Field::new(MAP_KEY, LogicalType::Varchar),
4365 Field::new(MAP_VALUE, LogicalType::Varchar),
4366 ])
4367 );
4368 // And the accessor that reaches through it hands back the two columns rather than the struct.
4369 let (entries, keys, values) = column.map_parts().expect("a map");
4370 assert_eq!(entries.len(), 4);
4371 assert_eq!(keys.text_at(0), Some("a"));
4372 assert_eq!(values.text_at(0), Some("b"));
4373 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
4374 }
4375
4376 /// The same distinction a list has, checked again here rather than assumed from the composition,
4377 /// because the empty map is the one every catalog table in D2 is full of and a null map is what a
4378 /// column with no tags at all would be.
4379 #[test]
4380 fn an_empty_map_and_a_null_map_are_different_rows() {
4381 let column = tag_column(&[tags(&[]), Value::Null]);
4382 assert!(!column.is_null_at(0), "an empty map is a row that is there");
4383 assert!(column.is_null_at(1));
4384 assert_eq!(column.value_at(0), tags(&[]));
4385 assert_eq!(column.value_at(1), Value::Null);
4386 assert_eq!(column.value_at(0).to_string(), "{}");
4387 assert_eq!(column.value_at(1).to_string(), "NULL");
4388 }
4389
4390 /// A map prints `{a=b}` and a struct prints `{'a': b}`, both measured off the pin. They share a
4391 /// layout and they cannot share a printer, which is the one thing about this composition that does
4392 /// not fall out of it.
4393 #[test]
4394 fn a_map_prints_with_equals_signs_and_a_struct_prints_with_quoted_names() {
4395 assert_eq!(tags(&[("a", "b"), ("c", "d")]).to_string(), "{a=b, c=d}");
4396 assert_eq!(pair(1, "x").to_string(), "{'a': 1, 'b': x}");
4397 let numbers = Value::map(
4398 LogicalType::Integer,
4399 LogicalType::Integer,
4400 vec![(Value::Integer(1), Value::Integer(3)), (Value::Integer(2), Value::Integer(4))],
4401 );
4402 assert_eq!(numbers.to_string(), "{1=3, 2=4}");
4403 let null_value = Value::map(
4404 LogicalType::Varchar,
4405 LogicalType::Varchar,
4406 vec![(Value::Varchar("x".to_string()), Value::Null)],
4407 );
4408 assert_eq!(null_value.to_string(), "{x=NULL}");
4409 }
4410
4411 /// A map inherits the list's cut and the list's gather, which is the payoff for storing it as one.
4412 /// Neither of these is code written for maps and both of them are worth a test that says the
4413 /// inheritance works, since the type is rewritten on the way through and a form that came back as a
4414 /// list would still read.
4415 #[test]
4416 fn cutting_and_gathering_a_map_keeps_it_a_map() {
4417 let rows: Vec<Value> =
4418 (0..16).map(|row| tags(&[("k", if row % 2 == 0 { "e" } else { "o" })])).collect();
4419 let column = tag_column(&rows);
4420
4421 let cut = column.slice(4, 3).unwrap();
4422 assert!(matches!(cut.logical_type(), LogicalType::Map(_, _)), "still a map after a cut");
4423 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[4..7]);
4424 // The child was not cut, the same as for a list, which is what makes the cut eight bytes a row.
4425 assert_eq!(cut.map_parts().expect("a map").1.len(), 16);
4426
4427 let picked = column.gather(&[3, 0, 3]).unwrap();
4428 assert!(matches!(picked.logical_type(), LogicalType::Map(_, _)));
4429 assert_eq!(
4430 picked.iter().collect::<Vec<_>>(),
4431 [rows[3].clone(), rows[0].clone(), rows[3].clone()]
4432 );
4433 let past = column.gather(&[0, 99]).unwrap();
4434 assert_eq!(past.value_at(1), Value::Null);
4435 }
4436
4437 #[test]
4438 fn a_map_built_from_two_columns_pairs_them_by_position() {
4439 let keys = Vector::from_values(
4440 LogicalType::Varchar,
4441 &[Value::Varchar("a".to_string()), Value::Varchar("c".to_string())],
4442 )
4443 .unwrap();
4444 let values = Vector::from_values(
4445 LogicalType::Varchar,
4446 &[Value::Varchar("b".to_string()), Value::Varchar("d".to_string())],
4447 )
4448 .unwrap();
4449 let column = Vector::map(vec![(0, 2), (2, 0)], keys, values).expect("two rows");
4450 assert_eq!(column.len(), 2);
4451 assert_eq!(
4452 column.logical_type(),
4453 &LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
4454 );
4455 assert_eq!(column.value_at(0), tags(&[("a", "b"), ("c", "d")]));
4456 assert_eq!(column.value_at(1), tags(&[]));
4457 // The entry check the list constructor does is the one a map gets, so an entry past the end of
4458 // the pair of columns is refused here too rather than read as somebody else's keys.
4459 let short =
4460 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("a".to_string())]).unwrap();
4461 let other =
4462 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("b".to_string())]).unwrap();
4463 assert!(Vector::map(vec![(0, 9)], short, other).is_err(), "an entry past the end");
4464 }
4465
4466 /// `map_parts` is about the logical type and `list_parts` is about the layout, so a list has to
4467 /// decline the first and a map has to answer the second. Getting that backwards would let a kernel
4468 /// written for maps read a list of two field structs as if it were one.
4469 #[test]
4470 fn a_list_is_not_a_map_however_much_its_child_looks_like_one() {
4471 let pairs = Value::List { element: pair_type(), values: vec![pair(1, "x")] };
4472 let column =
4473 Vector::from_values(LogicalType::list(pair_type()), std::slice::from_ref(&pairs))
4474 .unwrap();
4475 assert!(column.map_parts().is_none(), "a list of structs is a list");
4476 assert!(column.list_parts().is_some());
4477 let map = tag_column(&[tags(&[("a", "b")])]);
4478 assert!(map.map_parts().is_some());
4479 assert!(map.list_parts().is_some(), "a map has a list's layout and says so");
4480 }
4481
4482 /// A struct row is not bytes and not an integer, and it stays that way when it has exactly one
4483 /// integer field, which is the case where answering about the field would look reasonable and would
4484 /// be a hash keyed on the wrong thing.
4485 #[test]
4486 fn the_scalar_readers_decline_a_struct_of_one_integer_field() {
4487 let ty = LogicalType::Struct(vec![Field::new("a", LogicalType::Integer)]);
4488 let row = Value::Struct(vec![("a".to_string(), Value::Integer(7))]);
4489 let column = Vector::from_values(ty, &[row]).unwrap();
4490 assert_eq!(column.signed_at(0), None);
4491 assert_eq!(column.bytes_at(0), None);
4492 assert_eq!(column.data(), None);
4493 }
4494
4495 #[test]
4496 fn a_clustered_column_becomes_runs_and_reads_back_the_same() {
4497 let mut values = Vec::new();
4498 for (value, times) in [(7, 400), (8, 300), (7, 324)] {
4499 values.extend(std::iter::repeat_n(value, times));
4500 }
4501 let flat = integers(&values);
4502 let runs = flat.run_encoded().unwrap();
4503 assert_eq!(runs.form(), Form::Rle);
4504 assert_eq!(runs.run_parts().expect("runs").0, [400, 700, 1024]);
4505 assert_eq!(runs.len(), flat.len());
4506 assert_eq!(runs.iter().collect::<Vec<_>>(), flat.iter().collect::<Vec<_>>());
4507 assert!(
4508 runs.footprint() * 10 < flat.footprint(),
4509 "three runs against a thousand rows: {} against {}",
4510 runs.footprint(),
4511 flat.footprint()
4512 );
4513 }
4514
4515 /// The check is worth having in both directions. A form that is only ever bigger than what it
4516 /// replaced is a form that costs a pass over the column to decide not to use.
4517 #[test]
4518 fn a_column_that_does_not_repeat_is_left_flat() {
4519 let flat = integers(&(0..1024).collect::<Vec<i32>>());
4520 assert_eq!(flat.run_encoded().unwrap().form(), Form::Flat);
4521 // Two runs over four rows is exactly break even on a four byte column, and break even is
4522 // not a reason to change form.
4523 assert_eq!(integers(&[1, 1, 2, 2]).run_encoded().unwrap().form(), Form::Flat);
4524 assert_eq!(integers(&[1, 1, 1, 2, 2]).run_encoded().unwrap().form(), Form::Rle);
4525 }
4526
4527 #[test]
4528 fn two_nulls_beside_each_other_are_one_run_and_a_null_between_two_equals_is_a_break() {
4529 let mut values = vec![Value::Integer(4), Value::Integer(4)];
4530 values.extend([Value::Null, Value::Null, Value::Null]);
4531 values.extend(std::iter::repeat_n(Value::Integer(4), 5));
4532 let flat = Vector::from_values(LogicalType::Integer, &values).unwrap();
4533 let runs = flat.run_encoded().unwrap();
4534 assert_eq!(runs.run_parts().expect("runs").0, [2, 5, 10]);
4535 assert_eq!(runs.iter().collect::<Vec<_>>(), values);
4536 }
4537
4538 #[test]
4539 fn slicing_runs_keeps_them_runs_and_cuts_the_first_and_last_one_back() {
4540 let flat = integers(&[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]);
4541 let runs = flat.run_encoded().unwrap();
4542 let piece = runs.slice(3, 6).unwrap();
4543 assert_eq!(piece.form(), Form::Rle, "the form is the whole point");
4544 assert_eq!(piece.run_parts().expect("runs").0, [1, 5, 6]);
4545 assert_eq!(
4546 piece.iter().collect::<Vec<_>>(),
4547 flat.slice(3, 6).unwrap().iter().collect::<Vec<_>>()
4548 );
4549 assert_eq!(runs.slice(0, 0).unwrap().len(), 0);
4550 assert_eq!(runs.slice(0, 12).unwrap().form(), Form::Rle);
4551 }
4552
4553 #[test]
4554 fn gathering_out_of_runs_walks_to_the_values_the_way_it_walks_a_dictionary() {
4555 let mut values = vec![Value::Varchar("red".into()); 4];
4556 values.extend([Value::Null, Value::Null, Value::Null]);
4557 values.extend(vec![Value::Varchar("blue".into()); 4]);
4558 let runs =
4559 Vector::from_values(LogicalType::Varchar, &values).unwrap().run_encoded().unwrap();
4560 assert_eq!(runs.form(), Form::Rle);
4561 let picked = runs.gather(&[8, 0, 5, 2]).unwrap();
4562 assert_eq!(picked.form(), Form::Flat, "a gather copies, whatever it gathered from");
4563 assert_eq!(
4564 picked.iter().collect::<Vec<_>>(),
4565 [values[8].clone(), values[0].clone(), Value::Null, values[2].clone()]
4566 );
4567 assert_eq!(runs.text_at(1), Some("red"));
4568 assert_eq!(runs.text_at(5), None, "a null has no text");
4569 assert_eq!(runs.flatten().unwrap().iter().collect::<Vec<_>>(), values);
4570 }
4571
4572 /// A run length vector over a run length vector turns one search per row into two, and there is
4573 /// nothing in the engine that builds one, so it is refused rather than composed.
4574 #[test]
4575 fn runs_of_runs_are_refused_and_runs_of_a_dictionary_are_not() {
4576 let inner = integers(&[1, 1, 1, 1, 2]).run_encoded().unwrap();
4577 assert_eq!(inner.form(), Form::Rle);
4578 let error = Vector::runs(vec![2, 8], inner).unwrap_err();
4579 assert!(error.to_string().contains("runs of runs"), "{error}");
4580
4581 let words = Vector::from_values(
4582 LogicalType::Varchar,
4583 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
4584 )
4585 .unwrap();
4586 let dictionary = Vector::dictionary(vec![1, 0], words).unwrap();
4587 let stacked = Vector::runs(vec![4, 9], dictionary).unwrap();
4588 assert_eq!(stacked.len(), 9);
4589 assert_eq!(stacked.value_at(3), Value::Varchar("blue".into()));
4590 assert_eq!(stacked.value_at(4), Value::Varchar("red".into()));
4591 }
4592
4593 #[test]
4594 fn run_ends_have_to_increase_and_there_is_one_value_for_each_of_them() {
4595 let values = integers(&[1, 2]);
4596 assert!(Vector::runs(vec![4], values.clone()).is_err(), "two values and one run");
4597 assert!(Vector::runs(vec![4, 4], values.clone()).is_err(), "an end that repeats");
4598 assert!(Vector::runs(vec![4, 2], values.clone()).is_err(), "an end that goes backwards");
4599 assert!(Vector::runs(vec![0, 2], values.clone()).is_err(), "a first run holding no rows");
4600 assert_eq!(Vector::runs(vec![4, 9], values).unwrap().len(), 9);
4601 }
4602
4603 #[test]
4604 fn a_form_that_is_already_compact_is_left_where_it_is() {
4605 let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1000);
4606 assert_eq!(constant.run_encoded().unwrap().form(), Form::Constant);
4607 assert_eq!(Vector::sequence(0, 1, 1000).run_encoded().unwrap().form(), Form::Sequence);
4608 }
4609
4610 /// What makes one accessor cover both forms. A dictionary hands back the codes it stores and a
4611 /// run length vector works the same numbers out, and a kernel writing `values[at[row]]` reads
4612 /// the same rows out of either.
4613 #[test]
4614 fn both_forms_that_point_somewhere_hand_back_a_position_per_row() {
4615 let words = Vector::from_values(
4616 LogicalType::Varchar,
4617 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
4618 )
4619 .unwrap();
4620 let runs = Vector::runs(vec![3, 5], words.clone()).unwrap();
4621 let (at, values) = runs.positions().expect("runs point somewhere");
4622 assert_eq!(at.as_ref(), [0, 0, 0, 1, 1]);
4623 assert_eq!(values.value_at(at[3] as usize), runs.value_at(3));
4624
4625 let dictionary = Vector::dictionary(vec![1, 0, 1], words).unwrap();
4626 let (at, values) = dictionary.positions().expect("a dictionary points somewhere");
4627 assert_eq!(at.as_ref(), [1, 0, 1]);
4628 assert_eq!(values.value_at(at[0] as usize), dictionary.value_at(0));
4629
4630 assert!(integers(&[1, 2, 3]).positions().is_none(), "a flat vector points at itself");
4631 assert!(Vector::sequence(0, 1, 4).positions().is_none(), "a sequence stores nothing");
4632 }
4633
4634 #[test]
4635 fn slicing_a_dictionary_keeps_it_a_dictionary_where_gathering_would_not() {
4636 let values = Vector::from_values(
4637 LogicalType::Varchar,
4638 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
4639 )
4640 .unwrap();
4641 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
4642
4643 let piece = vector.slice(1, 3).unwrap();
4644 assert_eq!(piece.form(), Form::Dictionary, "the form is the whole point");
4645 assert_eq!(piece.len(), 3);
4646 assert_eq!(
4647 piece.iter().collect::<Vec<_>>(),
4648 [
4649 Value::Varchar("blue".into()),
4650 Value::Varchar("blue".into()),
4651 Value::Varchar("red".into())
4652 ]
4653 );
4654 assert_eq!(vector.gather(&[1, 2, 3]).unwrap().form(), Form::Flat, "which a gather loses");
4655 }
4656
4657 #[test]
4658 fn slicing_a_dictionary_shares_the_dictionary_rather_than_copying_it() {
4659 // The assertion is about the address and not about the values, because the values were
4660 // right when the dictionary was copied too. A page holds one dictionary and is cut into a
4661 // chunk of codes at a time, so copying the dictionary here is a copy of every string in it
4662 // per chunk, and on a read of a ClickBench partition it was ten percent of the cycles.
4663 let values = Vector::from_values(
4664 LogicalType::Varchar,
4665 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
4666 )
4667 .unwrap();
4668 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
4669 let Body::Dictionary { values: whole, .. } = &vector.body else {
4670 panic!("a dictionary vector holds a dictionary");
4671 };
4672
4673 let piece = vector.slice(1, 3).unwrap();
4674 let Body::Dictionary { codes, values: cut, .. } = &piece.body else {
4675 panic!("a slice of a dictionary is a dictionary");
4676 };
4677 assert!(Arc::ptr_eq(whole, cut), "the cut copied the dictionary");
4678 assert_eq!(codes, &[1, 1, 0], "the codes are the part that is cut");
4679
4680 // And a cut of a cut shares it too, since that is what a scan does to a page it reads twice.
4681 let again = piece.slice(1, 2).unwrap();
4682 let Body::Dictionary { values: cut, .. } = &again.body else {
4683 panic!("a slice of a slice of a dictionary is a dictionary");
4684 };
4685 assert!(Arc::ptr_eq(whole, cut), "the second cut copied the dictionary");
4686 assert_eq!(
4687 again.iter().collect::<Vec<_>>(),
4688 [Value::Varchar("blue".into()), Value::Varchar("red".into())]
4689 );
4690 }
4691
4692 #[test]
4693 fn a_slice_carries_the_nulls_that_were_in_its_range_and_not_the_others() {
4694 let vector =
4695 integers(&[1, 2, 3, 4]).with_validity(Validity::from_run(&[false, true, false, true]));
4696 let piece = vector.slice(1, 2).unwrap();
4697 assert!(piece.validity().is_valid(0));
4698 assert!(!piece.validity().is_valid(1));
4699 assert_eq!(piece.value_at(1), Value::Null);
4700 }
4701
4702 #[test]
4703 fn slicing_a_sequence_moves_its_start_rather_than_writing_the_values_out() {
4704 let vector = Vector::sequence(100, 5, 10);
4705 let piece = vector.slice(3, 4).unwrap();
4706 assert_eq!(piece.form(), Form::Sequence);
4707 assert_eq!(
4708 piece.iter().collect::<Vec<_>>(),
4709 [Value::BigInt(115), Value::BigInt(120), Value::BigInt(125), Value::BigInt(130)]
4710 );
4711 }
4712
4713 #[test]
4714 fn slicing_a_constant_is_a_shorter_constant() {
4715 let vector = Vector::constant(LogicalType::Integer, Value::Integer(9), 8);
4716 let piece = vector.slice(2, 3).unwrap();
4717 assert_eq!(piece.form(), Form::Constant);
4718 assert_eq!(piece.len(), 3);
4719 assert_eq!(piece.value_at(2), Value::Integer(9));
4720 }
4721
4722 #[test]
4723 fn slicing_the_whole_vector_hands_it_back_as_it_was() {
4724 let vector = integers(&[1, 2, 3]);
4725 assert_eq!(
4726 vector.slice(0, 3).unwrap().iter().collect::<Vec<_>>(),
4727 [Value::Integer(1), Value::Integer(2), Value::Integer(3)]
4728 );
4729 }
4730
4731 #[test]
4732 fn cutting_a_flat_body_answers_what_gathering_the_same_rows_answers() {
4733 // The cut of a flat body used to be written as a gather over the positions in the range,
4734 // and it is now a run copied out, so the two have to keep saying the same thing. Every
4735 // start and every length, with nulls in the range and out of it, since the validity is the
4736 // half of this that changed shape.
4737 let rows: Vec<i32> = (0..70).collect();
4738 let valid: Vec<bool> = (0..70).map(|row| row % 7 != 0 && row % 11 != 3).collect();
4739 let vector = integers(&rows).with_validity(Validity::from_run(&valid));
4740 for at in 0..70usize {
4741 for len in 0..=(70 - at) {
4742 let cut = vector.slice(at, len).unwrap();
4743 let positions: Vec<u32> = (at..at + len).map(|row| row as u32).collect();
4744 let gathered = vector.gather(&positions).unwrap();
4745 assert_eq!(cut.len(), len, "rows {at} to {}", at + len);
4746 assert_eq!(
4747 cut.iter().collect::<Vec<_>>(),
4748 gathered.iter().collect::<Vec<_>>(),
4749 "rows {at} to {}",
4750 at + len
4751 );
4752 }
4753 }
4754 }
4755
4756 /// The flat body used to be the one form of a vector whose cut cost an allocation and a copy,
4757 /// and it is not any more when its buffer is a run inside a page. Asserted on the address,
4758 /// because the values are the same either way and the address is the whole claim.
4759 #[test]
4760 fn cutting_a_flat_body_over_a_page_does_not_copy_it() {
4761 let page = Arc::new((0i64..64).collect::<Vec<_>>());
4762 let address = page.as_ptr() as usize;
4763 let data = Data::Int64(Buffer::from_arc(Arc::clone(&page)));
4764 let vector = Vector::flat(LogicalType::BigInt, data).unwrap();
4765 let cut = vector.slice(16, 8).unwrap();
4766 assert_eq!(cut.form(), Form::Flat);
4767 assert_eq!(cut.len(), 8);
4768 let Some(Data::Int64(run)) = cut.data() else {
4769 panic!("the layout changed under the test")
4770 };
4771 assert!(run.is_shared(), "the cut copied the run out of the page");
4772 assert_eq!(run.as_slice().as_ptr() as usize, address + 16 * 8);
4773 assert_eq!(run.as_slice(), &(16i64..24).collect::<Vec<_>>()[..]);
4774 assert_eq!(cut.value_at(0), Value::BigInt(16));
4775 // And the same cut of an owned run says the same thing, by copying it.
4776 let owned = Vector::flat(LogicalType::BigInt, Data::Int64((0i64..64).collect())).unwrap();
4777 let copied = owned.slice(16, 8).unwrap();
4778 let Some(Data::Int64(run)) = copied.data() else {
4779 panic!("the layout changed under the test")
4780 };
4781 assert!(!run.is_shared());
4782 assert_eq!(run.as_slice(), &(16i64..24).collect::<Vec<_>>()[..]);
4783 }
4784
4785 /// `into_pages` is how a producer says its values will be handed out many times. A flat body is
4786 /// the form it changes, and after it a copy of the vector is a reference count bump.
4787 #[test]
4788 fn a_vector_over_pages_is_copied_and_cut_without_its_values_moving() {
4789 let vector = integers(&[1, 2, 3, 4, 5, 6, 7, 8]).into_pages();
4790 let address = |vector: &Vector| match vector.data() {
4791 Some(Data::Int32(values)) => values.as_slice().as_ptr() as usize,
4792 _ => panic!("the layout changed under the test"),
4793 };
4794 let stored = address(&vector);
4795 assert_eq!(address(&vector.clone()), stored, "a copy moved the values");
4796 assert_eq!(address(&vector.slice(2, 4).unwrap()), stored + 2 * 4, "a cut moved the values");
4797 assert_eq!(
4798 vector.slice(2, 4).unwrap().iter().collect::<Vec<_>>(),
4799 [Value::Integer(3), Value::Integer(4), Value::Integer(5), Value::Integer(6)]
4800 );
4801 // Twice is not two pages.
4802 assert_eq!(address(&vector.clone().into_pages()), stored);
4803 }
4804
4805 /// A cut, a gather and a flatten of a string column over a page all move views and no bytes.
4806 ///
4807 /// This is the string half of the paging that `a_vector_over_pages_is_copied_and_cut_without_
4808 /// its_values_moving` checks for a fixed width column, and it is worth its own test because a
4809 /// string column is two allocations rather than one: the cut that matters is the payload
4810 /// staying where it is while the views move.
4811 #[test]
4812 fn a_string_column_over_a_page_is_cut_and_gathered_without_its_payload_moving() {
4813 let long = ["the first of the long strings", "the second one", "and a third long one here"];
4814 let mut built = StringColumn::with_capacity(long.len());
4815 for text in long {
4816 built.push(text);
4817 }
4818 let vector = Vector::flat(LogicalType::Varchar, Data::Varlen(built.into_page())).unwrap();
4819 let payload = |vector: &Vector| match vector.data() {
4820 Some(Data::Varlen(column)) => column.arena().as_ptr() as usize,
4821 _ => panic!("the layout changed under the test"),
4822 };
4823 let stored = payload(&vector);
4824 let cut = vector.slice(1, 2).unwrap();
4825 assert_eq!(payload(&cut), stored, "a cut moved the payload");
4826 assert_eq!(cut.text_at(0), Some(long[1]));
4827 assert_eq!(cut.text_at(1), Some(long[2]));
4828 let gathered = vector.gather(&[2, 0]).unwrap();
4829 assert_eq!(payload(&gathered), stored, "a gather moved the payload");
4830 assert_eq!(gathered.text_at(0), Some(long[2]));
4831 assert_eq!(gathered.text_at(1), Some(long[0]));
4832 // And the same column with its own arena still copies, because sharing an owned arena
4833 // means cloning every byte of it including the bytes nobody asked for.
4834 let mut owned = StringColumn::with_capacity(long.len());
4835 for text in long {
4836 owned.push(text);
4837 }
4838 let held = Vector::flat(LogicalType::Varchar, Data::Varlen(owned)).unwrap();
4839 let copied = held.slice(1, 2).unwrap();
4840 assert_ne!(payload(&copied), payload(&held), "an owned payload was shared");
4841 assert_eq!(copied.text_at(0), Some(long[1]));
4842 }
4843
4844 /// A flatten gives up the form and not the sharing. The views form is already views over an
4845 /// arena, so flattening one over a page is the views and nothing else, and the flat column
4846 /// that comes out reads the same strings out of the same bytes.
4847 #[test]
4848 fn flattening_string_views_over_a_page_keeps_the_page() {
4849 let mut built = StringColumn::with_capacity(2);
4850 built.push("a string too long to sit inside a view");
4851 built.push("another string that is also too long");
4852 let (views, arena) = built.into_page().into_parts();
4853 let stored = arena.as_slice().as_ptr() as usize;
4854 let vector = Vector::string_views(LogicalType::Varchar, views, Arc::new(arena)).unwrap();
4855 assert_eq!(vector.form(), Form::StringView);
4856 let flat = vector.flatten().unwrap();
4857 assert_eq!(flat.form(), Form::Flat);
4858 let Some(Data::Varlen(column)) = flat.data() else {
4859 panic!("the layout changed under the test")
4860 };
4861 assert_eq!(column.arena().as_ptr() as usize, stored, "the flatten moved the payload");
4862 assert_eq!(flat.text_at(0), Some("a string too long to sit inside a view"));
4863 assert_eq!(flat.text_at(1), Some("another string that is also too long"));
4864 }
4865
4866 /// Every form that is not flat already shares what is expensive, so this is a no op on them and
4867 /// in particular does not flatten anything. A form that came back flat would be a column that
4868 /// lost its encoding on the way into a table.
4869 #[test]
4870 fn putting_a_vector_on_pages_does_not_change_any_other_form() {
4871 let dictionary = Vector::dictionary(
4872 vec![0, 1, 0, 1],
4873 Vector::from_values(
4874 LogicalType::Varchar,
4875 &[Value::Varchar("a".into()), Value::Varchar("b".into())],
4876 )
4877 .unwrap(),
4878 )
4879 .unwrap();
4880 let cases = [
4881 Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
4882 Vector::sequence(4, 0, 1),
4883 dictionary,
4884 ];
4885 for vector in cases {
4886 let form = vector.form();
4887 let paged = vector.clone().into_pages();
4888 assert_eq!(paged.form(), form, "{form:?} changed form");
4889 assert_eq!(paged.iter().collect::<Vec<_>>(), vector.iter().collect::<Vec<_>>());
4890 }
4891 }
4892
4893 #[test]
4894 fn cutting_a_flat_string_column_answers_what_gathering_it_answers() {
4895 // The string layout is the one whose cut is still a loop, and it is also the one where a
4896 // row is a view into an arena rather than a slot, so it gets the same treatment separately.
4897 // Both inline and out of line strings, since they are copied by different paths.
4898 let rows: Vec<String> =
4899 (0..40).map(|row| "x".repeat(row % 30) + &row.to_string()).collect();
4900 let values: Vec<Value> = rows.iter().map(|row| Value::Varchar(row.clone())).collect();
4901 let vector = Vector::from_values(LogicalType::Varchar, &values).unwrap().flatten().unwrap();
4902 assert_eq!(vector.form(), Form::Flat, "the cut under test is the flat one");
4903 for at in 0..40usize {
4904 for len in 0..=(40 - at) {
4905 let cut = vector.slice(at, len).unwrap();
4906 let positions: Vec<u32> = (at..at + len).map(|row| row as u32).collect();
4907 let gathered = vector.gather(&positions).unwrap();
4908 assert_eq!(
4909 cut.iter().collect::<Vec<_>>(),
4910 gathered.iter().collect::<Vec<_>>(),
4911 "rows {at} to {}",
4912 at + len
4913 );
4914 }
4915 }
4916 }
4917
4918 #[test]
4919 fn a_slice_past_the_end_is_an_error_rather_than_a_short_vector() {
4920 let error = integers(&[1, 2, 3]).slice(2, 2).unwrap_err();
4921 assert!(error.to_string().contains("of a vector of 3"), "{error}");
4922 }
4923
4924 #[test]
4925 fn the_vector_size_is_the_one_the_design_is_built_around() {
4926 // 8192, which is four times DuckDB's 2048, measured in #480 against 1024, 2048, 4096 and
4927 // 32768. What the rest of the code assumes about it is not the value but the shape: a
4928 // multiple of 1024, which is the FastLanes unit and is what makes a validity mask a whole
4929 // number of u64 words with none of them half used.
4930 assert_eq!(VECTOR_SIZE, 8192);
4931 assert_eq!(VECTOR_SIZE % 1024, 0);
4932 assert_eq!(VECTOR_SIZE % 64, 0);
4933 assert_eq!(VECTOR_SIZE / 64, 128, "the words in a validity mask");
4934 }
4935
4936 #[test]
4937 fn a_flat_vector_reads_back_what_was_put_in_it() {
4938 let vector = integers(&[1, 2, 3]);
4939 assert_eq!(vector.form(), Form::Flat);
4940 assert_eq!(vector.len(), 3);
4941 assert_eq!(vector.value_at(1), Value::Integer(2));
4942 assert_eq!(
4943 vector.iter().collect::<Vec<_>>(),
4944 vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
4945 );
4946 }
4947
4948 #[test]
4949 fn a_vector_built_from_values_reads_the_same_values_back() {
4950 let vector = Vector::from_values(
4951 LogicalType::Varchar,
4952 &[
4953 Value::Varchar("a".to_string()),
4954 Value::Null,
4955 Value::Varchar("a string too long to sit inside a view".to_string()),
4956 ],
4957 )
4958 .expect("strings and a null");
4959 assert_eq!(vector.len(), 3);
4960 assert_eq!(vector.value_at(0), Value::Varchar("a".to_string()));
4961 assert_eq!(vector.value_at(1), Value::Null);
4962 assert_eq!(
4963 vector.value_at(2),
4964 Value::Varchar("a string too long to sit inside a view".to_string())
4965 );
4966 }
4967
4968 /// A null still occupies a position. If it did not then every value after it would read back
4969 /// one place to the left, which is the kind of bug that looks like a storage bug for a week.
4970 #[test]
4971 fn a_null_in_the_middle_does_not_move_the_values_after_it() {
4972 let vector = Vector::from_values(
4973 LogicalType::Integer,
4974 &[Value::Integer(1), Value::Null, Value::Integer(3)],
4975 )
4976 .expect("integers and a null");
4977 assert_eq!(vector.value_at(2), Value::Integer(3));
4978 assert!(vector.validity().has_nulls(3), "the middle one is null");
4979 }
4980
4981 #[test]
4982 fn a_value_the_type_cannot_hold_is_refused() {
4983 let wrong = Vector::from_values(LogicalType::Integer, &[Value::Varchar("x".to_string())]);
4984 assert!(wrong.is_err(), "a string is not an integer");
4985 }
4986
4987 #[test]
4988 fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
4989 // One comparison here against a wrong answer read out three layers later.
4990 let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1].into()));
4991 assert!(wrong.is_err());
4992 let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1].into()));
4993 assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
4994 }
4995
4996 #[test]
4997 fn a_constant_vector_costs_one_value_whatever_its_length() {
4998 let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
4999 assert_eq!(vector.form(), Form::Constant);
5000 assert_eq!(vector.len(), VECTOR_SIZE);
5001 assert_eq!(vector.value_at(0), Value::Integer(7));
5002 assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
5003 assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
5004 }
5005
5006 #[test]
5007 fn a_constant_null_is_all_invalid_without_being_told() {
5008 let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
5009 assert_eq!(vector.validity(), &Validity::AllInvalid);
5010 assert_eq!(vector.value_at(3), Value::Null);
5011 }
5012
5013 #[test]
5014 fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
5015 let vector = Vector::sequence(100, 1, VECTOR_SIZE);
5016 assert_eq!(vector.form(), Form::Sequence);
5017 assert_eq!(vector.value_at(0), Value::BigInt(100));
5018 assert_eq!(vector.value_at(923), Value::BigInt(1023));
5019 let stepped = Vector::sequence(0, 5, 4);
5020 assert_eq!(
5021 stepped.iter().collect::<Vec<_>>(),
5022 vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
5023 );
5024 }
5025
5026 #[test]
5027 fn a_dictionary_vector_reads_through_its_codes() {
5028 let mut column = StringColumn::new();
5029 column.push("red");
5030 column.push("green");
5031 let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
5032 let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
5033 assert_eq!(vector.form(), Form::Dictionary);
5034 assert_eq!(vector.logical_type(), &LogicalType::Varchar);
5035 assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
5036 assert_eq!(vector.len(), 4);
5037 }
5038
5039 /// The accessor a group by keys a string column through, which has to agree with `value_at` on
5040 /// every position or two rows holding one string end up in two groups.
5041 #[test]
5042 fn text_is_read_where_it_already_is_for_the_forms_that_store_it() {
5043 let mut column = StringColumn::new();
5044 column.push("red");
5045 column.push("green");
5046 column.push("");
5047 let flat = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
5048 for index in 0..flat.len() {
5049 assert_eq!(flat.text_at(index).map(str::to_string), text_of(&flat.value_at(index)));
5050 }
5051 let dictionary = Vector::dictionary(vec![1, 0, 1, 2], flat).unwrap();
5052 for index in 0..dictionary.len() {
5053 assert_eq!(
5054 dictionary.text_at(index).map(str::to_string),
5055 text_of(&dictionary.value_at(index))
5056 );
5057 }
5058 assert_eq!(dictionary.text_at(4), None, "past the end");
5059 }
5060
5061 /// The forms and types that have no text to hand back, which a caller answers by falling back
5062 /// to `value_at`. A blob is the one that would be a correctness bug rather than a slow path,
5063 /// since its bytes are not required to be text and it is not a `VARCHAR` either way.
5064 #[test]
5065 fn text_is_refused_where_it_is_not_stored_as_itself() {
5066 let nulls =
5067 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into()), Value::Null])
5068 .unwrap();
5069 assert_eq!(nulls.text_at(0), Some("red"));
5070 assert_eq!(nulls.text_at(1), None, "a null has no text");
5071 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("red".into()), 3);
5072 assert_eq!(constant.text_at(0), None, "a constant is not stored per position");
5073 assert_eq!(integers(&[1, 2]).text_at(0), None, "an integer is not text");
5074 let mut bytes = StringColumn::new();
5075 bytes.push("red");
5076 let blob = Vector::flat(LogicalType::Blob, Data::Varlen(bytes)).unwrap();
5077 assert_eq!(blob.text_at(0), None, "a blob is not a varchar");
5078 }
5079
5080 /// The accessor a group by keys an integer column through, which has to agree with `value_at`
5081 /// on every position or two rows holding one number end up in two groups.
5082 #[test]
5083 fn a_signed_integer_is_read_where_it_already_is_for_the_forms_that_store_it() {
5084 let flat = integers(&[7, -3, 0, 2]);
5085 for index in 0..flat.len() {
5086 assert_eq!(flat.signed_at(index), signed_of(&flat.value_at(index)), "flat {index}");
5087 }
5088 let dictionary = Vector::dictionary(vec![1, 0, 3, 2], flat).unwrap();
5089 for index in 0..dictionary.len() {
5090 assert_eq!(
5091 dictionary.signed_at(index),
5092 signed_of(&dictionary.value_at(index)),
5093 "dictionary {index}"
5094 );
5095 }
5096 assert_eq!(dictionary.signed_at(4), None, "past the end");
5097
5098 let runs = Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap();
5099 for index in 0..runs.len() {
5100 assert_eq!(runs.signed_at(index), signed_of(&runs.value_at(index)), "run {index}");
5101 }
5102 let constant = Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3);
5103 assert_eq!(constant.signed_at(2), Some(11));
5104 let sequence = Vector::sequence(100, 5, 4);
5105 for index in 0..sequence.len() {
5106 assert_eq!(
5107 sequence.signed_at(index),
5108 signed_of(&sequence.value_at(index)),
5109 "sequence {index}"
5110 );
5111 }
5112 }
5113
5114 /// The forms and types that have no integer to hand back, which a caller answers by falling
5115 /// back to `value_at`.
5116 #[test]
5117 fn a_signed_integer_is_refused_where_it_is_not_stored_as_itself() {
5118 let nulls =
5119 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
5120 assert_eq!(nulls.signed_at(0), Some(4));
5121 assert_eq!(nulls.signed_at(1), None, "a null is not a number");
5122 let packed = integers(&[1, 2, 3, 1]).bit_packed().unwrap();
5123 assert_eq!(packed.signed_at(0), Some(1), "a packed integer is read in code space");
5124 let mut bytes = StringColumn::new();
5125 bytes.push("red");
5126 let text = Vector::flat(LogicalType::Varchar, Data::Varlen(bytes)).unwrap();
5127 assert_eq!(text.signed_at(0), None, "a string is not a number");
5128 let double = Vector::flat(LogicalType::Double, Data::Float64(vec![1.5].into())).unwrap();
5129 assert_eq!(double.signed_at(0), None, "a double is not a signed integer");
5130 }
5131
5132 /// The block form has to agree with the row at a time form on every position of every shape it
5133 /// answers for, because a caller picks one of the two and a group by that read two different
5134 /// numbers for one row would put that row in two groups.
5135 #[test]
5136 fn a_block_of_signed_integers_holds_what_the_row_at_a_time_accessor_hands_back() {
5137 let mut out = Vec::new();
5138 let shapes = [
5139 integers(&[7, -3, 0, 2]),
5140 Vector::flat(LogicalType::Integer, Data::Int32(vec![5, -6, 7].into())).unwrap(),
5141 Vector::flat(LogicalType::SmallInt, Data::Int16(vec![1, -2].into())).unwrap(),
5142 Vector::flat(LogicalType::TinyInt, Data::Int8(vec![-128, 127].into())).unwrap(),
5143 Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3),
5144 Vector::sequence(100, 5, 4),
5145 integers(&[1, 2, 3, 1]).bit_packed().unwrap(),
5146 ];
5147 for column in &shapes {
5148 assert!(column.signed_block(&mut out), "{:?} hands over a block", column.form());
5149 assert_eq!(out.len(), column.len(), "{:?} filled the whole chunk", column.form());
5150 for (index, &held) in out.iter().enumerate() {
5151 assert_eq!(
5152 Some(i128::from(held)),
5153 column.signed_at(index),
5154 "{:?} at {index}",
5155 column.form()
5156 );
5157 }
5158 }
5159 }
5160
5161 /// What the block form will not answer for, where the caller reads the vector a row at a time
5162 /// instead. A null is not one of them: it writes whatever sits under it and the caller reads the
5163 /// null from the column.
5164 #[test]
5165 fn a_block_is_refused_for_the_shapes_it_would_have_to_gather_or_widen() {
5166 let mut out = Vec::new();
5167 let flat = integers(&[7, -3, 0, 2]);
5168 assert!(!Vector::dictionary(vec![1, 0], flat.clone()).unwrap().signed_block(&mut out));
5169 assert!(!Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap().signed_block(&mut out));
5170 let wide = Vector::flat(LogicalType::HugeInt, Data::Int128(vec![1, 2].into())).unwrap();
5171 assert!(!wide.signed_block(&mut out), "a hugeint does not fit sixty four bits");
5172 let double = Vector::flat(LogicalType::Double, Data::Float64(vec![1.5].into())).unwrap();
5173 assert!(!double.signed_block(&mut out), "a double is not a signed integer");
5174 assert!(out.is_empty(), "a refusal leaves the buffer empty");
5175
5176 let nulls =
5177 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
5178 assert!(nulls.signed_block(&mut out), "a flat column with nulls still hands over");
5179 assert_eq!(out[0], 4);
5180 }
5181
5182 /// Asked once for a chunk, and it has to agree with `is_null_at` asked for every row of it.
5183 #[test]
5184 fn a_vector_says_whether_it_holds_any_null_at_all() {
5185 let flat = integers(&[7, -3, 0, 2]);
5186 assert!(flat.none_null());
5187 let nulls =
5188 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
5189 assert!(!nulls.none_null());
5190 assert!(Vector::dictionary(vec![1, 0], flat.clone()).unwrap().none_null());
5191 // The null is in the dictionary rather than in the mask, which is the case the row at a time
5192 // form reads through for and the reason this one does too.
5193 let holed = Vector::dictionary(vec![0, 0], nulls.clone()).unwrap();
5194 assert!(!holed.none_null(), "a dictionary is read through to its values");
5195 assert!(!holed.is_null_at(0), "and no code points at the null it holds");
5196 assert!(Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap().none_null());
5197 assert!(!Vector::runs(vec![1, 2], nulls).unwrap().none_null());
5198 assert!(Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3).none_null());
5199 assert!(!Vector::constant(LogicalType::BigInt, Value::Null, 3).none_null());
5200 }
5201
5202 /// The integer of a value, for comparing `signed_at` against `value_at` position by position.
5203 fn signed_of(value: &Value) -> Option<i128> {
5204 match value {
5205 Value::TinyInt(x) => Some(i128::from(*x)),
5206 Value::SmallInt(x) => Some(i128::from(*x)),
5207 Value::Integer(x) | Value::Date(x) => Some(i128::from(*x)),
5208 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => Some(i128::from(*x)),
5209 Value::HugeInt(x) | Value::Decimal { unscaled: x, .. } => Some(*x),
5210 _ => None,
5211 }
5212 }
5213
5214 /// The text of a value, for comparing `text_at` against `value_at` position by position.
5215 fn text_of(value: &Value) -> Option<String> {
5216 match value {
5217 Value::Varchar(text) => Some(text.clone()),
5218 _ => None,
5219 }
5220 }
5221
5222 #[test]
5223 fn a_dictionary_code_past_the_end_is_refused() {
5224 // The alternative is a silent read of the wrong value, which is the failure mode the
5225 // entire M3 design has to be careful about.
5226 let values = integers(&[1, 2]);
5227 assert!(Vector::dictionary(vec![0, 2], values).is_err());
5228 // The check runs on the highest code rather than the first bad one, so it has to say that
5229 // no codes at all is fine even when there are no values for them to point at either.
5230 let empty = Vector::dictionary(Vec::new(), integers(&[])).expect("no codes, no values");
5231 assert_eq!(empty.len(), 0);
5232 // And a code of zero against an empty dictionary is still past the end.
5233 assert!(Vector::dictionary(vec![0], integers(&[])).is_err());
5234 }
5235
5236 #[test]
5237 fn every_form_flattens_to_the_same_values_it_reads_out() {
5238 // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
5239 // miniature and long before there is an encoded kernel to point it at. A form that reads
5240 // out one way and flattens another is the exact bug that testing exists to catch.
5241 let mut column = StringColumn::new();
5242 column.push("alpha");
5243 column.push("beta");
5244 let dictionary = Vector::dictionary(
5245 vec![1, 0, 1],
5246 Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
5247 )
5248 .unwrap();
5249 let cases = [
5250 Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
5251 Vector::sequence(7, -2, 5),
5252 dictionary,
5253 ];
5254 for vector in cases {
5255 let flat = vector.flatten().unwrap();
5256 assert_eq!(flat.form(), Form::Flat);
5257 assert_eq!(flat.len(), vector.len());
5258 for index in 0..vector.len() {
5259 assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
5260 }
5261 }
5262 }
5263
5264 #[test]
5265 fn a_null_still_occupies_a_position_after_flattening() {
5266 // The reason push_value writes a zero for a null rather than skipping it. A run of data
5267 // with a hole in it puts every value after the hole in the wrong place, and the validity
5268 // mask is what says the position is null.
5269 let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
5270 let flat = vector.flatten().unwrap();
5271 assert_eq!(flat.value_at(0), Value::BigInt(0));
5272 assert_eq!(flat.value_at(1), Value::Null);
5273 assert_eq!(flat.value_at(2), Value::BigInt(2));
5274 assert_eq!(flat.value_at(3), Value::BigInt(3));
5275 }
5276
5277 /// A dictionary holds its nulls in the vector it points at, so its own validity is all valid
5278 /// and reading that instead of the values turns a null into whatever zero means for the type.
5279 /// A filter over a nullable column produces exactly this vector, so the bug reaches a result
5280 /// set as `LEFT JOIN` padding that comes back as zeros.
5281 #[test]
5282 fn a_null_behind_a_dictionary_survives_flattening() {
5283 let values =
5284 Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
5285 let dictionary = Vector::dictionary(vec![1, 0, 1], values).unwrap();
5286 let flat = dictionary.flatten().unwrap();
5287 assert_eq!(flat.value_at(0), Value::Null);
5288 assert_eq!(flat.value_at(1), Value::Integer(3));
5289 assert_eq!(flat.value_at(2), Value::Null);
5290 }
5291
5292 /// The property that makes `gather` usable at all: it has to be the same function as reading the
5293 /// wanted positions one at a time, over every form, or compaction changes answers.
5294 #[test]
5295 fn gathering_reads_what_reading_one_position_at_a_time_reads() {
5296 let mut column = StringColumn::new();
5297 column.push("alpha");
5298 column.push("beta");
5299 column.push("gamma");
5300 let cases = [
5301 integers(&[10, 20, 30, 40]),
5302 integers(&[10, 20, 30, 40]).with_validity(Validity::from_iter(4, |i| i != 2)),
5303 Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
5304 Vector::sequence(100, -7, 4),
5305 Vector::sequence(100, -7, 4).with_validity(Validity::from_iter(4, |i| i % 2 == 0)),
5306 Vector::dictionary(
5307 vec![2, 0, 1, 2],
5308 Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
5309 )
5310 .unwrap(),
5311 Vector::dictionary(
5312 vec![1, 0, 1, 0],
5313 Vector::from_values(LogicalType::Integer, &[Value::Integer(5), Value::Null])
5314 .unwrap(),
5315 )
5316 .unwrap(),
5317 ];
5318 let wanted = [3_u32, 0, 2, 2, 1];
5319 for vector in cases {
5320 let gathered = vector.gather(&wanted).unwrap();
5321 assert_eq!(gathered.len(), wanted.len());
5322 assert_eq!(gathered.logical_type(), vector.logical_type());
5323 for (slot, &index) in wanted.iter().enumerate() {
5324 assert_eq!(
5325 gathered.value_at(slot),
5326 vector.value_at(index as usize),
5327 "slot {slot} of {:?}",
5328 vector.form()
5329 );
5330 }
5331 }
5332 }
5333
5334 /// A gather past the end is not an error, because the selection that produced the indices is
5335 /// checked by its caller and the one thing that must not happen here is a read of the wrong
5336 /// value. An index nothing answers is null, which is what an outer join pad needs anyway.
5337 #[test]
5338 fn gathering_a_position_that_is_not_there_is_a_null_and_not_a_wrong_value() {
5339 let vector = integers(&[1, 2, 3]);
5340 let gathered = vector.gather(&[2, 9]).unwrap();
5341 assert_eq!(gathered.value_at(0), Value::Integer(3));
5342 assert_eq!(gathered.value_at(1), Value::Null);
5343 }
5344
5345 /// The vector with nothing in it at all, which is what an untyped `NULL` is stored as. Every
5346 /// position asked for is past its end, so the answer is nulls and the length has to be the
5347 /// length that was asked for rather than the length that was there.
5348 #[test]
5349 fn gathering_from_a_vector_of_no_values_is_that_many_nulls() {
5350 let vector = Vector::flat(LogicalType::Null, Data::Empty).unwrap();
5351 let gathered = vector.gather(&[0, 1, 2]).unwrap();
5352 assert_eq!(gathered.len(), 3);
5353 assert_eq!(gathered.value_at(0), Value::Null);
5354 assert_eq!(gathered.value_at(2), Value::Null);
5355 }
5356
5357 /// Every position holds the same value, so a gather with no hole in it has nothing to copy and
5358 /// the result is the constant again rather than a run of a thousand copies of it.
5359 #[test]
5360 fn gathering_a_constant_stays_a_constant() {
5361 let vector = Vector::constant(LogicalType::Integer, Value::Integer(4), 100);
5362 let gathered = vector.gather(&[7, 7, 99]).unwrap();
5363 assert_eq!(gathered.form(), Form::Constant);
5364 assert_eq!(gathered.len(), 3);
5365 assert_eq!(gathered.value_at(2), Value::Integer(4));
5366 }
5367
5368 /// A dictionary over a dictionary is what a second filter over an already filtered chunk builds,
5369 /// and the gather has to walk to the bottom of that chain rather than one step down it. The
5370 /// constructor composes the ordinary chain away, so the one built here is the kind it cannot,
5371 /// which is a level holding nulls of its own.
5372 #[test]
5373 fn gathering_walks_a_dictionary_over_a_dictionary_to_the_values() {
5374 let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9]))
5375 .unwrap()
5376 .with_validity(Validity::from_iter(3, |index| index != 2));
5377 let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
5378 let gathered = outer.gather(&[0, 1]).unwrap();
5379 assert_eq!(gathered.form(), Form::Flat);
5380 assert_eq!(gathered.value_at(0), Value::Integer(8));
5381 assert_eq!(gathered.value_at(1), Value::Null);
5382 }
5383
5384 /// Two filters over one chunk build a dictionary over a dictionary, four conjuncts pushed down
5385 /// separately build four levels of it, and every level is a dependent load on every later read
5386 /// of every row plus a code array that cannot be freed. Composing at construction is one pass
5387 /// over the codes the range check was walking anyway.
5388 #[test]
5389 fn a_dictionary_over_a_dictionary_is_composed_into_one_level() {
5390 let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9])).unwrap();
5391 let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
5392 let (codes, values) = outer.dictionary_parts().unwrap();
5393 assert_eq!(codes, [1, 0]);
5394 assert_eq!(values.form(), Form::Flat);
5395 assert_eq!(outer.value_at(0), Value::Integer(8));
5396 assert_eq!(outer.value_at(1), Value::Integer(7));
5397 }
5398
5399 /// The invariant stated as the thing it is there for, which is that the depth does not grow with
5400 /// the number of filters. Four levels stacked one at a time are one level at the end of it.
5401 #[test]
5402 fn stacking_dictionaries_does_not_make_them_deeper() {
5403 let mut vector = integers(&[10, 20, 30, 40]);
5404 for _ in 0..4 {
5405 vector = Vector::dictionary(vec![3, 2, 1, 0], vector).unwrap();
5406 }
5407 let (codes, values) = vector.dictionary_parts().unwrap();
5408 assert_eq!(values.form(), Form::Flat);
5409 assert_eq!(codes, [0, 1, 2, 3]);
5410 assert_eq!(
5411 vector.iter().collect::<Vec<_>>(),
5412 integers(&[10, 20, 30, 40]).iter().collect::<Vec<_>>()
5413 );
5414 }
5415
5416 /// Composing has to carry the nulls down with it. The values hold them, the codes point at them,
5417 /// and a composed code that lands on a null position is still a null.
5418 #[test]
5419 fn composing_a_dictionary_keeps_the_nulls_its_values_hold() {
5420 let values =
5421 Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
5422 let inner = Vector::dictionary(vec![1, 0, 1], values).unwrap();
5423 let outer = Vector::dictionary(vec![0, 1], inner).unwrap();
5424 assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Flat);
5425 assert_eq!(outer.value_at(0), Value::Null);
5426 assert_eq!(outer.value_at(1), Value::Integer(3));
5427 }
5428
5429 /// The one level composition cannot go past. A dictionary that was given a validity of its own is
5430 /// saying its nulls are at that level rather than in the values, and pointing the outer codes
5431 /// straight at the values would read through the holes instead of stopping at them.
5432 #[test]
5433 fn a_dictionary_holding_its_own_nulls_is_not_composed_past() {
5434 let inner = Vector::dictionary(vec![0, 1, 2], integers(&[1, 2, 3]))
5435 .unwrap()
5436 .with_validity(Validity::from_iter(3, |index| index != 1));
5437 let outer = Vector::dictionary(vec![1, 2, 0], inner).unwrap();
5438 assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Dictionary);
5439 assert_eq!(outer.value_at(0), Value::Null);
5440 assert_eq!(outer.value_at(1), Value::Integer(3));
5441 assert_eq!(outer.value_at(2), Value::Integer(1));
5442 }
5443
5444 /// The difference between the two questions about nulls, which a group by got wrong. A filtered
5445 /// chunk is dictionary vectors, those are built with every row marked present at their own
5446 /// level, and the nulls are down in the values. So the mask says the row has a value and the
5447 /// row does not.
5448 #[test]
5449 fn a_null_behind_a_dictionary_reads_as_null_even_though_the_mask_says_otherwise() {
5450 let values = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
5451 .unwrap()
5452 .with_validity(Validity::from_iter(2, |index| index != 0));
5453 let vector = Vector::dictionary(vec![0, 1, 0], values).unwrap();
5454 assert!(vector.validity().is_valid(0), "the mask at this level says present");
5455 assert!(vector.is_null_at(0));
5456 assert!(!vector.is_null_at(1));
5457 assert!(vector.is_null_at(2));
5458 assert!(vector.is_null_at(3), "a row past the end is null");
5459 }
5460
5461 /// The same for runs, which are built the same way and keep their nulls in the same place.
5462 #[test]
5463 fn a_null_inside_a_run_reads_as_null_even_though_the_mask_says_otherwise() {
5464 let values = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
5465 .unwrap()
5466 .with_validity(Validity::from_iter(2, |index| index != 0));
5467 let vector = Vector::runs(vec![2, 3], values).unwrap();
5468 assert!(vector.validity().is_valid(0));
5469 assert!(vector.is_null_at(0));
5470 assert!(vector.is_null_at(1));
5471 assert!(!vector.is_null_at(2));
5472 }
5473
5474 /// Every other form keeps its nulls in its own mask, so the two answers agree there.
5475 #[test]
5476 fn the_forms_that_hold_their_own_nulls_answer_the_same_either_way() {
5477 let flat = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
5478 .unwrap()
5479 .with_validity(Validity::from_iter(2, |index| index != 0));
5480 let constant = Vector::constant(LogicalType::Integer, Value::Null, 2);
5481 let sequence = Vector::sequence(10, 2, 2);
5482 for vector in [flat, constant, sequence] {
5483 for row in 0..vector.len() {
5484 assert_eq!(vector.is_null_at(row), !vector.validity().is_valid(row));
5485 }
5486 }
5487 }
5488
5489 #[test]
5490 fn flattening_a_flat_vector_is_the_same_vector() {
5491 let vector = integers(&[1, 2, 3]);
5492 assert_eq!(vector.flatten().unwrap(), vector);
5493 }
5494
5495 /// The same answer as `flatten` and, for the vector that is already flat and owns its values,
5496 /// the same allocation. Asserted on the address because that is the whole claim: the values
5497 /// come back where they were rather than in a copy of themselves. A flatten through a borrow
5498 /// cannot do that, and at the top of a query it copied every column of every chunk of the
5499 /// result to hand back the bytes it was given.
5500 #[test]
5501 fn flattening_a_vector_that_owns_its_values_moves_them_rather_than_copying_them() {
5502 let vector = integers(&[1, 2, 3, 4]);
5503 let address = |vector: &Vector| match vector.data() {
5504 Some(Data::Int32(values)) => values.as_slice().as_ptr() as usize,
5505 _ => panic!("the layout changed under the test"),
5506 };
5507 let stored = address(&vector);
5508 let flat = vector.into_flat().unwrap();
5509 assert_eq!(address(&flat), stored, "the values moved");
5510 assert_eq!(
5511 flat.iter().collect::<Vec<_>>(),
5512 (1..=4).map(Value::Integer).collect::<Vec<_>>()
5513 );
5514 // And a form that is not flat is flattened, which is the case the copy is deserved in.
5515 let dictionary = Vector::dictionary(vec![1, 0, 1], integers(&[7, 8])).unwrap();
5516 let flat = dictionary.clone().into_flat().unwrap();
5517 assert_eq!(flat.form(), Form::Flat);
5518 assert_eq!(flat.iter().collect::<Vec<_>>(), dictionary.iter().collect::<Vec<_>>());
5519 }
5520
5521 #[test]
5522 fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
5523 let ty = LogicalType::decimal(9, 2).unwrap();
5524 let vector = Vector::flat(ty, Data::Int32(vec![1234].into())).unwrap();
5525 assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
5526 assert_eq!(vector.value_at(0).to_string(), "12.34");
5527 }
5528
5529 #[test]
5530 fn a_decimal_writes_into_whichever_of_the_four_runs_its_precision_chose() {
5531 // The read path worked at every width and the write path only accepted the 128 bit run, so
5532 // `SELECT 2.5` produced a value nothing could store. All four widths round trip now.
5533 for (width, scale, unscaled) in
5534 [(4u8, 1u8, 25i128), (9, 2, 1234), (18, 3, 123_456), (38, 4, 1_234_567)]
5535 {
5536 let ty = LogicalType::decimal(width, scale).unwrap();
5537 let value = Value::Decimal { unscaled, width, scale };
5538 let vector = Vector::from_values(ty, &[value.clone(), Value::Null]).unwrap();
5539 assert_eq!(vector.value_at(0), value, "a decimal of width {width}");
5540 assert_eq!(vector.value_at(1), Value::Null, "a null decimal of width {width}");
5541 }
5542 }
5543
5544 /// The bytes a blob holds are not required to be text, and a vector of them used to refuse the
5545 /// ones that were not. A byte array column in a Parquet file that nothing annotated is a blob,
5546 /// which is what ClickHouse writes and what ten of the ClickBench queries compare against, so
5547 /// this is the path those take rather than a corner of the type system.
5548 #[test]
5549 fn a_blob_holds_bytes_that_are_not_text() {
5550 let bytes = |raw: &[u8]| Value::Blob(raw.to_vec());
5551 let values = [
5552 bytes(b"a\xffb"),
5553 bytes(b"\x00\x01\x02"),
5554 Value::Null,
5555 bytes(b"\xed\xa0\x80 and long enough to leave the view"),
5556 bytes(b""),
5557 ];
5558 let vector = Vector::from_values(LogicalType::Blob, &values).unwrap();
5559 for (index, value) in values.iter().enumerate() {
5560 assert_eq!(&vector.value_at(index), value, "row {index}");
5561 }
5562 }
5563
5564 #[test]
5565 fn a_decimal_too_wide_for_the_run_its_type_chose_is_an_error_and_not_a_wrong_number() {
5566 // Only reachable by hand, since a value's width is what picked the run. Truncating here
5567 // would store a different number and say nothing about it.
5568 let ty = LogicalType::decimal(4, 1).unwrap();
5569 let value = Value::Decimal { unscaled: 1_000_000, width: 4, scale: 1 };
5570 let error = Vector::from_values(ty, &[value]).unwrap_err();
5571 assert!(error.to_string().contains("does not fit"), "{error}");
5572 }
5573
5574 #[test]
5575 fn a_flat_vector_costs_its_values_and_a_constant_costs_one() {
5576 let flat = integers(&[1; 1000]);
5577 assert!(
5578 flat.footprint() >= 4000,
5579 "a thousand i32 are four thousand bytes: {}",
5580 flat.footprint()
5581 );
5582 // The forms that compute their values rather than storing them cost nothing per value,
5583 // which is the point of having them and is what the memory limit should see.
5584 let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1_000_000);
5585 assert!(constant.footprint() < 200, "a constant is one value: {}", constant.footprint());
5586 let sequence = Vector::sequence(0, 1, 1_000_000);
5587 assert!(sequence.footprint() < 200, "a sequence is two numbers: {}", sequence.footprint());
5588 }
5589
5590 #[test]
5591 fn a_gather_off_a_dictionary_answers_the_same_nulls_either_way_round() {
5592 let words = [Value::Varchar("north".into()), Value::Null, Value::Varchar("south".into())];
5593 let plain: Vec<Value> =
5594 ["north", "east", "south"].iter().map(|word| Value::Varchar((*word).into())).collect();
5595 let clean = Arc::new(Vector::from_values(LogicalType::Varchar, &plain).unwrap());
5596 let dirty = Arc::new(Vector::from_values(LogicalType::Varchar, &words).unwrap());
5597 let codes = vec![0, 1, 2, 0, 1, 2];
5598 let sources = [
5599 Vector::stable_dictionary(codes.clone(), Arc::clone(&clean)).unwrap(),
5600 Vector::stable_dictionary(codes.clone(), Arc::clone(&dirty)).unwrap(),
5601 Vector::stable_dictionary(codes, Arc::clone(&clean))
5602 .unwrap()
5603 .with_validity(Validity::from_run(&[true, true, false, true, true, true])),
5604 ];
5605 // What a gather says about a row has to be what the column it came out of says about the
5606 // row it was taken from, whichever of the two ways the nulls are reached: the mask over the
5607 // codes, or the value a code stands for. The fast answer is only allowed when neither has
5608 // any, and an index past the end is null in both readings.
5609 for source in &sources {
5610 let picks: Vec<u32> = vec![5, 0, 3, 2, 1, 99, 4];
5611 let taken = source.gather(&picks).unwrap();
5612 for (row, &pick) in picks.iter().enumerate() {
5613 assert_eq!(
5614 taken.is_null_at(row),
5615 source.is_null_at(pick as usize),
5616 "row {row} of a gather of {picks:?}"
5617 );
5618 }
5619 }
5620 }
5621
5622 #[test]
5623 fn a_dictionary_read_by_many_cuts_is_counted_about_once_between_them() {
5624 let strings: Vec<Value> = (0..2000)
5625 .map(|at| Value::Varchar(format!("a value well past the inline limit, number {at}")))
5626 .collect();
5627 let values = Arc::new(Vector::from_values(LogicalType::Varchar, &strings).unwrap());
5628 let dictionary = values.footprint();
5629 let cuts: Vec<Vector> = (0..500)
5630 .map(|_| Vector::stable_dictionary(vec![0; 8], Arc::clone(&values)).unwrap())
5631 .collect();
5632 let together: usize = cuts.iter().map(Vector::footprint).sum();
5633 // Five hundred chunks cut out of one page hold one dictionary, and what they say they hold
5634 // has to be about one dictionary. Before this it was five hundred of them, which is a
5635 // reading that grows with the answer and refuses a query holding a gigabyte a budget of
5636 // twenty five.
5637 assert!(
5638 together < dictionary * 2,
5639 "five hundred cuts are not five hundred dictionaries: {together} against {dictionary}"
5640 );
5641 assert!(
5642 together > dictionary / 2,
5643 "the dictionary is still counted: {together} against {dictionary}"
5644 );
5645 }
5646
5647 #[test]
5648 fn a_string_vector_costs_the_bytes_of_its_long_strings() {
5649 let short =
5650 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into())]).unwrap();
5651 let long = "a string well past the sixteen bytes a view holds inline".to_string();
5652 let spilled =
5653 Vector::from_values(LogicalType::Varchar, &[Value::Varchar(long.clone())]).unwrap();
5654 assert!(
5655 spilled.footprint() >= short.footprint() + long.len(),
5656 "the arena is counted: {} against {}",
5657 spilled.footprint(),
5658 short.footprint()
5659 );
5660 }
5661
5662 /// The cases worth checking are the widths where a code straddles a word boundary, which is
5663 /// every width that does not divide sixty four, and the two ends of the range.
5664 #[test]
5665 fn a_narrow_column_packs_and_reads_back_the_same_at_every_width() {
5666 for width in 1..=20u32 {
5667 let span = (1i64 << width) - 1;
5668 let values: Vec<i64> =
5669 (0..1000).map(|row| 1_000_000 + (row * 7919) % (span + 1)).collect();
5670 let flat =
5671 Vector::flat(LogicalType::BigInt, Data::Int64(values.clone().into())).unwrap();
5672 let packed = flat.bit_packed().unwrap();
5673 assert_eq!(packed.len(), flat.len());
5674 assert_eq!(
5675 packed.iter().collect::<Vec<_>>(),
5676 flat.iter().collect::<Vec<_>>(),
5677 "width {width} read back differently"
5678 );
5679 }
5680 }
5681
5682 #[test]
5683 fn the_width_is_the_bits_the_range_needs_and_not_the_bits_the_type_has() {
5684 let values: Vec<i32> = (0..1024).map(|row| 40 + (row * 2560) / 1023).collect();
5685 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
5686 let packed = flat.bit_packed().unwrap();
5687 assert_eq!(packed.form(), Form::BitPacked);
5688 let parts = packed.packed_parts().expect("packed");
5689 assert_eq!(parts.width(), 12, "0 to 2560 is twelve bits");
5690 assert_eq!(parts.base(), 40);
5691 assert!(
5692 packed.footprint() * 2 < flat.footprint(),
5693 "twelve bits against thirty two: {} against {}",
5694 packed.footprint(),
5695 flat.footprint()
5696 );
5697 }
5698
5699 /// The check is worth having in both directions, the way the run length one is. A form that is
5700 /// only ever bigger than what it replaced costs a pass over the column to decide not to use.
5701 #[test]
5702 fn a_column_that_uses_its_whole_type_is_left_flat() {
5703 let values: Vec<i32> = (0..1024).map(|row| row * 2_000_000 - 1_000_000_000).collect();
5704 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
5705 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
5706 }
5707
5708 /// A column of one value would pack to no bits at all, and one run is smaller than any packing
5709 /// of it, so the two forms do not fight over that column.
5710 #[test]
5711 fn a_column_of_one_value_is_left_to_the_run_length_form() {
5712 let flat = integers(&[9; 1024]);
5713 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
5714 assert_eq!(flat.run_encoded().unwrap().form(), Form::Rle);
5715 }
5716
5717 #[test]
5718 fn a_string_column_has_no_range_to_pack() {
5719 let text = Vector::from_values(
5720 LogicalType::Varchar,
5721 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5722 )
5723 .unwrap();
5724 assert_eq!(text.bit_packed().unwrap().form(), Form::Flat);
5725 }
5726
5727 /// The cut is the reason the form carries a row to start reading at. It stays packed, it shares
5728 /// the same words, and it reads the rows the range asked for.
5729 #[test]
5730 fn a_cut_of_a_packed_column_stays_packed_and_shares_its_bits() {
5731 let values: Vec<i32> = (0..1024).map(|row| 100 + row % 300).collect();
5732 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
5733 let packed = flat.bit_packed().unwrap();
5734 let cut = packed.slice(500, 24).unwrap();
5735 assert_eq!(cut.form(), Form::BitPacked);
5736 assert_eq!(cut.len(), 24);
5737 assert_eq!(
5738 cut.iter().collect::<Vec<_>>(),
5739 flat.slice(500, 24).unwrap().iter().collect::<Vec<_>>()
5740 );
5741 assert!(
5742 cut.footprint() >= packed.footprint(),
5743 "a cut shares the words rather than copying a piece of them"
5744 );
5745 }
5746
5747 #[test]
5748 fn a_gather_of_a_packed_column_comes_out_flat_and_keeps_the_nulls() {
5749 let values: Vec<i32> = (0..64).map(|row| 10 + row).collect();
5750 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
5751 let packed =
5752 flat.bit_packed().unwrap().with_validity(Validity::from_iter(64, |row| row % 3 != 0));
5753 let taken = packed.gather(&[0, 1, 2, 3, 62]).unwrap();
5754 assert_eq!(taken.form(), Form::Flat);
5755 assert_eq!(
5756 taken.iter().collect::<Vec<_>>(),
5757 vec![
5758 Value::Null,
5759 Value::Integer(11),
5760 Value::Integer(12),
5761 Value::Null,
5762 Value::Integer(72)
5763 ]
5764 );
5765 }
5766
5767 /// The pair a comparison kernel asks for before it reads a bit. A literal inside the range has a
5768 /// code and a literal outside it does not, which answers the whole vector at once.
5769 #[test]
5770 fn a_literal_outside_the_packed_range_has_no_code() {
5771 let values: Vec<i32> = (0..256).map(|row| 1000 + row).collect();
5772 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
5773 let packed = flat.bit_packed().unwrap();
5774 let parts = packed.packed_parts().expect("packed");
5775 assert_eq!(parts.code_of(1000), Some(0));
5776 assert_eq!(parts.code_of(1100), Some(100));
5777 assert_eq!(parts.code_of(999), None);
5778 assert!(parts.ceiling() >= 1255);
5779 assert_eq!(parts.code_of(parts.ceiling() + 1), None);
5780 }
5781
5782 /// The bits arriving from a file rather than from a flat vector, which is what the form is for.
5783 #[test]
5784 fn packed_bits_can_be_handed_in_without_a_flat_vector_to_start_from() {
5785 let packed = Vector::packed(LogicalType::SmallInt, vec![0x0000_0000_0000_4321], 4, 7, 4)
5786 .expect("four codes of four bits");
5787 assert_eq!(
5788 packed.iter().collect::<Vec<_>>(),
5789 vec![Value::SmallInt(8), Value::SmallInt(9), Value::SmallInt(10), Value::SmallInt(11)]
5790 );
5791 }
5792
5793 #[test]
5794 fn packed_bits_that_could_not_hold_what_they_claim_are_refused() {
5795 assert!(Vector::packed(LogicalType::Varchar, vec![0], 4, 0, 4).is_err(), "not an integer");
5796 assert!(Vector::packed(LogicalType::Integer, vec![0], 0, 0, 4).is_err(), "no width");
5797 assert!(Vector::packed(LogicalType::Integer, vec![0], 64, 0, 4).is_err(), "too wide");
5798 assert!(Vector::packed(LogicalType::Integer, vec![0], 8, 0, 9).is_err(), "too few words");
5799 assert!(Vector::packed(LogicalType::TinyInt, vec![0], 8, 100, 8).is_err(), "would not fit");
5800 }
5801
5802 /// A column of strings long enough that the payload is in the arena rather than in the views.
5803 fn long_strings(count: usize) -> Vector {
5804 let values: Vec<Value> = (0..count)
5805 .map(|row| {
5806 Value::Varchar(format!("a string too long to sit inside a view, number {row}"))
5807 })
5808 .collect();
5809 Vector::from_values(LogicalType::Varchar, &values).unwrap()
5810 }
5811
5812 #[test]
5813 fn a_string_column_in_view_form_reads_back_the_same_strings() {
5814 let flat = long_strings(40);
5815 let shared = flat.clone().shared_text().unwrap();
5816 assert_eq!(shared.form(), Form::StringView);
5817 assert_eq!(shared.len(), 40);
5818 for row in 0..40 {
5819 assert_eq!(shared.value_at(row), flat.value_at(row), "row {row}");
5820 assert_eq!(shared.text_at(row), flat.text_at(row), "row {row}");
5821 }
5822 }
5823
5824 #[test]
5825 fn a_short_string_is_read_out_of_its_view_and_never_out_of_the_arena() {
5826 let flat = Vector::from_values(
5827 LogicalType::Varchar,
5828 &[Value::Varchar("red".into()), Value::Varchar("green".into()), Value::Null],
5829 )
5830 .unwrap();
5831 let shared = flat.shared_text().unwrap();
5832 // Nothing went to the arena, so the whole column resolves with an empty one.
5833 let (views, arena) = shared.text_parts().unwrap();
5834 assert!(arena.is_empty(), "three short strings need no arena");
5835 assert_eq!(views[0].bytes_in(arena), Some(&b"red"[..]));
5836 assert_eq!(shared.value_at(1), Value::Varchar("green".into()));
5837 assert_eq!(shared.value_at(2), Value::Null, "the validity came across");
5838 }
5839
5840 #[test]
5841 fn a_cut_of_a_view_column_shares_the_arena_rather_than_copying_the_bytes() {
5842 let shared = long_strings(64).shared_text().unwrap();
5843 let cut = shared.slice(16, 8).unwrap();
5844 assert_eq!(cut.form(), Form::StringView, "a cut of views is views");
5845 assert_eq!(cut.len(), 8);
5846 assert_eq!(cut.value_at(0), shared.value_at(16));
5847 assert_eq!(cut.value_at(7), shared.value_at(23));
5848 // The arena is the same bytes at the same address, which is the whole point of the form.
5849 let (_, whole) = shared.text_parts().unwrap();
5850 let (_, piece) = cut.text_parts().unwrap();
5851 assert_eq!(piece.as_ptr(), whole.as_ptr(), "the cut shares the page");
5852 assert_eq!(piece.len(), whole.len());
5853 }
5854
5855 #[test]
5856 fn a_flat_string_column_has_to_copy_the_bytes_its_cut_keeps() {
5857 let flat = long_strings(64);
5858 let cut = flat.slice(16, 8).unwrap();
5859 assert_eq!(cut.form(), Form::Flat);
5860 let (_, whole) = flat.text_parts().unwrap();
5861 let (_, piece) = cut.text_parts().unwrap();
5862 assert!(piece.len() < whole.len(), "the flat cut carries only what it kept");
5863 }
5864
5865 #[test]
5866 fn a_gather_of_a_view_column_keeps_the_form_and_a_flatten_copies_out_of_it() {
5867 let shared = long_strings(32).shared_text().unwrap();
5868 let picked: Vec<u32> = (0..32).step_by(3).collect();
5869 let gathered = shared.gather(&picked).unwrap();
5870 assert_eq!(gathered.form(), Form::StringView, "selecting rows moves views, not bytes");
5871 assert_eq!(gathered.len(), picked.len());
5872 for (row, &from) in picked.iter().enumerate() {
5873 assert_eq!(gathered.value_at(row), shared.value_at(from as usize), "row {row}");
5874 }
5875 let flattened = gathered.flatten().unwrap();
5876 assert_eq!(flattened.form(), Form::Flat);
5877 assert_eq!(flattened.iter().collect::<Vec<_>>(), gathered.iter().collect::<Vec<_>>());
5878 // The flatten is what narrows the bytes, so the arena it built holds only the rows it kept.
5879 let (_, narrowed) = flattened.text_parts().unwrap();
5880 let (_, whole) = shared.text_parts().unwrap();
5881 assert!(narrowed.len() < whole.len(), "flattening lets the page go");
5882 }
5883
5884 #[test]
5885 fn a_null_in_a_view_column_survives_being_gathered_and_flattened() {
5886 let shared = long_strings(8)
5887 .with_validity(Validity::from_iter(8, |row| row % 3 != 0))
5888 .shared_text()
5889 .unwrap();
5890 let gathered = shared.gather(&[0, 1, 2, 3, 4]).unwrap();
5891 let expected =
5892 [Value::Null, shared.value_at(1), shared.value_at(2), Value::Null, shared.value_at(4)];
5893 assert_eq!(gathered.iter().collect::<Vec<_>>(), expected);
5894 assert_eq!(gathered.flatten().unwrap().iter().collect::<Vec<_>>(), expected);
5895 }
5896
5897 #[test]
5898 fn both_string_forms_hand_a_kernel_the_same_views_and_the_same_bytes() {
5899 let flat = long_strings(6);
5900 let shared = flat.clone().shared_text().unwrap();
5901 let (flat_views, flat_arena) = flat.text_parts().unwrap();
5902 let (shared_views, shared_arena) = shared.text_parts().unwrap();
5903 assert_eq!(flat_views.len(), shared_views.len());
5904 for row in 0..6 {
5905 assert_eq!(
5906 flat_views[row].bytes_in(flat_arena),
5907 shared_views[row].bytes_in(shared_arena),
5908 "row {row}"
5909 );
5910 }
5911 // Nothing else answers this, which is what keeps a kernel from taking it for a string column.
5912 assert!(Vector::sequence(0, 1, 4).text_parts().is_none());
5913 assert!(integers(&[1, 2, 3]).text_parts().is_none());
5914 }
5915
5916 #[test]
5917 fn a_column_that_is_not_strings_cannot_be_held_as_views() {
5918 let views = vec![StringView::inline("red")];
5919 let arena = Arc::new(Buffer::new());
5920 let wrong = Vector::string_views(LogicalType::Integer, views, arena);
5921 assert!(wrong.is_err(), "an integer column has no views");
5922 assert_eq!(integers(&[1, 2]).shared_text().unwrap().form(), Form::Flat, "left alone");
5923 }
5924
5925 /// A column with enough repeated structure for a symbol table to find something, which is what
5926 /// a real text column has and a column of random bytes does not.
5927 fn sentences(count: usize) -> Vector {
5928 let values: Vec<Value> = (0..count)
5929 .map(|row| {
5930 Value::Varchar(format!(
5931 "http://example.test/catalogue/section/{}/item/{row}",
5932 row % 7
5933 ))
5934 })
5935 .collect();
5936 Vector::from_values(LogicalType::Varchar, &values).unwrap()
5937 }
5938
5939 #[test]
5940 fn a_compressed_column_reads_back_the_strings_that_went_into_it() {
5941 let flat = sentences(64);
5942 let coded = flat.clone().compressed().unwrap();
5943 assert_eq!(coded.form(), Form::Fsst, "a text column compresses");
5944 assert_eq!(coded.len(), 64);
5945 for row in 0..64 {
5946 assert_eq!(coded.value_at(row), flat.value_at(row), "row {row}");
5947 }
5948 assert_eq!(coded.flatten().unwrap(), flat, "flattening is the column it came from");
5949 }
5950
5951 #[test]
5952 fn compressing_halves_the_bytes_or_the_column_is_left_flat() {
5953 let flat = sentences(200);
5954 let coded = flat.clone().compressed().unwrap();
5955 let parts = coded.coded_parts().expect("compressed");
5956 // Read through the flat column, because the compressed one has no bytes to hand back where
5957 // they are and answers `None` to `text_at` rather than decompressing into a borrow.
5958 assert_eq!(coded.text_at(0), None, "nothing to borrow until it is flattened");
5959 let plain: usize = (0..200).map(|row| flat.text_at(row).map_or(0, str::len)).sum();
5960 let codes: usize = (0..200).map(|row| parts.row(row).map_or(0, <[u8]>::len)).sum();
5961 assert!(codes * FSST_PAYS_AT <= plain, "{codes} codes against {plain} bytes");
5962 // Text with no repeated structure in it gives a table nothing longer than a byte to find,
5963 // so the codes are the bytes and the column stays where it is rather than paying a
5964 // decompression per read to save nothing.
5965 let mut seed = 0x2545_f491_4f6c_dd1du64;
5966 let values: Vec<Value> = (0..256)
5967 .map(|_| {
5968 let mut text = String::new();
5969 while text.len() < 12 {
5970 seed = seed.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
5971 text.push(char::from(b'!' + ((seed >> 33) % 90) as u8));
5972 }
5973 Value::Varchar(text)
5974 })
5975 .collect();
5976 let noise = Vector::from_values(LogicalType::Varchar, &values).unwrap();
5977 assert_eq!(noise.compressed().unwrap().form(), Form::Flat);
5978 }
5979
5980 #[test]
5981 fn a_cut_of_a_compressed_column_shares_the_codes_and_the_table() {
5982 let coded = sentences(64).compressed().unwrap();
5983 let cut = coded.slice(8, 16).unwrap();
5984 assert_eq!(cut.form(), Form::Fsst);
5985 assert_eq!(cut.len(), 16);
5986 for row in 0..16 {
5987 assert_eq!(cut.value_at(row), coded.value_at(8 + row), "row {row}");
5988 }
5989 let (whole, piece) = (coded.coded_parts().unwrap(), cut.coded_parts().unwrap());
5990 assert_eq!(piece.row(0), whole.row(8), "the spans point into the same codes");
5991 }
5992
5993 #[test]
5994 fn a_gather_of_a_compressed_column_stays_compressed_and_keeps_the_nulls() {
5995 let coded = sentences(32)
5996 .with_validity(Validity::from_iter(32, |row| row % 5 != 2))
5997 .compressed()
5998 .unwrap();
5999 let picked: Vec<u32> = (0..32).step_by(2).collect();
6000 let gathered = coded.gather(&picked).unwrap();
6001 assert_eq!(gathered.form(), Form::Fsst, "selecting rows moves spans, not bytes");
6002 for (row, &from) in picked.iter().enumerate() {
6003 assert_eq!(gathered.value_at(row), coded.value_at(from as usize), "row {row}");
6004 }
6005 assert_eq!(
6006 gathered.flatten().unwrap().iter().collect::<Vec<_>>(),
6007 gathered.iter().collect::<Vec<_>>()
6008 );
6009 }
6010
6011 #[test]
6012 fn a_literal_lands_in_the_same_codes_the_row_holding_it_does() {
6013 let coded = sentences(40).compressed().unwrap();
6014 let parts = coded.coded_parts().expect("compressed");
6015 let text = coded.value_at(11);
6016 let Value::Varchar(text) = text else { panic!("a string column reads back strings") };
6017 assert_eq!(parts.encode(text.as_bytes()), parts.row(11).expect("row 11"));
6018 assert_ne!(parts.encode(b"something else entirely"), parts.row(11).unwrap());
6019 }
6020
6021 #[test]
6022 fn codes_that_run_past_what_is_there_are_refused() {
6023 let table = Arc::new(SymbolTable::empty());
6024 let codes = Arc::new(vec![1u8, 2, 3, 4]);
6025 let good = vec![(0u32, 2u32), (2, 4)];
6026 assert!(
6027 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), good, Arc::clone(&table))
6028 .is_ok()
6029 );
6030 let past = vec![(0u32, 9u32)];
6031 assert!(
6032 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), past, Arc::clone(&table))
6033 .is_err(),
6034 "a span past the end of the codes"
6035 );
6036 let backwards = vec![(3u32, 1u32)];
6037 assert!(
6038 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), backwards, Arc::clone(&table))
6039 .is_err(),
6040 "a span that ends before it starts"
6041 );
6042 let wrong = vec![(0u32, 2u32)];
6043 assert!(
6044 Vector::coded(LogicalType::Integer, codes, wrong, table).is_err(),
6045 "an integer column has no codes"
6046 );
6047 }
6048
6049 #[test]
6050 fn a_view_pointing_past_its_arena_is_refused_at_construction() {
6051 let long = "a string too long to sit inside a view";
6052 let arena: Arc<Buffer<u8>> = Arc::new(long.as_bytes().to_vec().into());
6053 let good = vec![StringView::over(long.as_bytes(), 0)];
6054 assert!(Vector::string_views(LogicalType::Varchar, good, Arc::clone(&arena)).is_ok());
6055 let bad = vec![StringView::over(long.as_bytes(), 4)];
6056 assert!(
6057 Vector::string_views(LogicalType::Varchar, bad, arena).is_err(),
6058 "four bytes short of what the view claims"
6059 );
6060 }
6061
6062 /// The form at its simplest: an id per row, and the row it names.
6063 #[test]
6064 fn a_gathered_vector_reads_the_source_row_its_id_names() {
6065 let source = Arc::new(integers(&[10, 20, 30, 40]));
6066 let vector = Vector::gathered(source, Arc::new(vec![3, 0, 3, 1])).unwrap();
6067 assert_eq!(vector.form(), Form::Gathered);
6068 assert_eq!(vector.len(), 4);
6069 assert_eq!(
6070 vector.iter().collect::<Vec<_>>(),
6071 vec![Value::Integer(40), Value::Integer(10), Value::Integer(40), Value::Integer(20)]
6072 );
6073 }
6074
6075 /// Section 8.2's lazy validity. The sentinel is a null and it is not in a mask anywhere, which is
6076 /// what lets a left link join gather null for an unmatched child row without allocating one.
6077 #[test]
6078 fn a_gathered_row_with_no_source_row_is_null_without_a_mask() {
6079 let source = Arc::new(integers(&[10, 20]));
6080 let vector = Vector::gathered(source, Arc::new(vec![1, NO_ROW, 0])).unwrap();
6081 assert!(!vector.validity().has_nulls(vector.len()), "the mask at this level says nothing");
6082 assert!(vector.is_null_at(1));
6083 assert!(!vector.is_null_at(0) && !vector.is_null_at(2));
6084 assert_eq!(
6085 vector.iter().collect::<Vec<_>>(),
6086 vec![Value::Integer(20), Value::Null, Value::Integer(10)]
6087 );
6088 assert!(!vector.none_null(), "a sentinel is a null and the bulk answer has to agree");
6089 }
6090
6091 /// The other half of the same rule: a null in the source is a null here, the way a dictionary's
6092 /// nulls live in its values. Two ways for a row to be null and one answer from `is_null_at`.
6093 #[test]
6094 fn a_gather_of_a_null_source_row_is_null() {
6095 let source = Arc::new(
6096 Vector::from_values(LogicalType::Integer, &[Value::Integer(7), Value::Null]).unwrap(),
6097 );
6098 let vector = Vector::gathered(source, Arc::new(vec![1, 0, 1])).unwrap();
6099 assert!(vector.is_null_at(0) && vector.is_null_at(2));
6100 assert_eq!(vector.value_at(1), Value::Integer(7));
6101 assert!(!vector.none_null());
6102 }
6103
6104 /// An id past the end of the source is the one failure in this form that reads whatever happens
6105 /// to be at that offset rather than failing, so it is refused where the vector is built.
6106 #[test]
6107 fn a_gathered_id_past_the_end_of_its_source_is_refused() {
6108 let source = Arc::new(integers(&[1, 2, 3]));
6109 assert!(Vector::gathered(Arc::clone(&source), Arc::new(vec![0, 3])).is_err());
6110 assert!(
6111 Vector::gathered(source, Arc::new(vec![0, NO_ROW])).is_ok(),
6112 "the sentinel is not an id past the end, it is the absence of one"
6113 );
6114 }
6115
6116 /// A cut is the offset and nothing else, which is what keeps a pipeline from copying the ids once
6117 /// per operator. Both ends stay shared and the rows answer the same.
6118 #[test]
6119 fn cutting_a_gather_moves_where_it_starts_and_copies_nothing() {
6120 let source = Arc::new(integers(&[10, 20, 30, 40, 50]));
6121 let rids = Arc::new(vec![4, 3, 2, 1, 0]);
6122 let vector = Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap();
6123 let held = Arc::strong_count(&rids);
6124 let cut = vector.slice(1, 3).unwrap();
6125 assert_eq!(cut.form(), Form::Gathered);
6126 assert_eq!(
6127 Arc::strong_count(&rids),
6128 held + 1,
6129 "the cut shares the ids rather than copying"
6130 );
6131 assert_eq!(
6132 cut.iter().collect::<Vec<_>>(),
6133 vec![Value::Integer(40), Value::Integer(30), Value::Integer(20)]
6134 );
6135 assert_eq!(cut.gathered_parts().unwrap().1, [3, 2, 1]);
6136 }
6137
6138 /// Composition, which is why this is a body and not an operator. A filter over the output of a
6139 /// link join selects into the ids, and what comes out is one level rather than two.
6140 #[test]
6141 fn a_gather_of_a_gather_resolves_to_one_walk_over_the_source() {
6142 let source = Arc::new(integers(&[10, 20, 30, 40]));
6143 let inner = Vector::gathered(source, Arc::new(vec![3, 2, 1, 0])).unwrap();
6144 let outer = inner.gather(&[0, 3]).unwrap();
6145 assert_eq!(outer.iter().collect::<Vec<_>>(), vec![Value::Integer(40), Value::Integer(10)]);
6146 assert_ne!(outer.form(), Form::Gathered, "the walk stops at what the ids point into");
6147 }
6148
6149 /// The sentinel survives being gathered through, which it has to: a filter over a left link
6150 /// join's output keeps the unmatched rows it kept and they are still null.
6151 #[test]
6152 fn gathering_through_a_sentinel_keeps_it_null() {
6153 let source = Arc::new(integers(&[10, 20]));
6154 let inner = Vector::gathered(source, Arc::new(vec![0, NO_ROW, 1])).unwrap();
6155 let outer = inner.gather(&[1, 2, 1]).unwrap();
6156 assert_eq!(
6157 outer.iter().collect::<Vec<_>>(),
6158 vec![Value::Null, Value::Integer(20), Value::Null]
6159 );
6160 }
6161
6162 /// Section 8.2's dispatch rule, which is the whole difference between this form and a dictionary
6163 /// and is one comparison. A gather off a parent larger than the chunk does not want the
6164 /// dictionary arm of any kernel, and a gather off a source smaller than the chunk does.
6165 #[test]
6166 fn folding_over_the_source_is_worth_it_only_when_the_source_is_the_shorter_one() {
6167 let wide = Arc::new(integers(&(0..64).collect::<Vec<i32>>()));
6168 let narrow = Arc::new(integers(&[1, 2]));
6169 let off_wide = Vector::gathered(wide, Arc::new(vec![0, 1, 2])).unwrap();
6170 let off_narrow = Vector::gathered(narrow, Arc::new(vec![0, 1, 0, 1, 0])).unwrap();
6171 assert!(!off_wide.fold_over_source(), "sixty four source rows to answer three");
6172 assert!(off_narrow.fold_over_source(), "two source rows to answer five");
6173 assert!(!integers(&[1, 2]).fold_over_source(), "and every other form says no");
6174 }
6175
6176 /// Strings, which read their bytes where the source already has them rather than through a value.
6177 /// A gather of a string column is four bytes a row and no arena is touched until something asks.
6178 #[test]
6179 fn a_gathered_string_is_read_where_the_source_put_it() {
6180 let mut column = StringColumn::new();
6181 column.push("red");
6182 column.push("a string too long to sit inside a sixteen byte view");
6183 let source = Arc::new(Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap());
6184 let vector = Vector::gathered(source, Arc::new(vec![1, 0, NO_ROW])).unwrap();
6185 assert_eq!(vector.text_at(0), Some("a string too long to sit inside a sixteen byte view"));
6186 assert_eq!(vector.text_at(1), Some("red"));
6187 assert_eq!(vector.text_at(2), None);
6188 assert_eq!(vector.bytes_at(1), Some(b"red".as_slice()));
6189 assert_eq!(vector.value_at(1), Value::Varchar("red".into()));
6190 }
6191
6192 /// The integer accessor a group by keys through, which has to agree with `value_at` at every
6193 /// row or two rows holding one value land in two groups.
6194 #[test]
6195 fn the_signed_reader_of_a_gather_agrees_with_the_value_reader() {
6196 let source = Arc::new(integers(&[10, 20, 30]));
6197 let vector = Vector::gathered(source, Arc::new(vec![2, NO_ROW, 0, 1])).unwrap();
6198 for row in 0..vector.len() {
6199 let signed = vector.signed_at(row);
6200 match vector.value_at(row) {
6201 Value::Null => assert_eq!(signed, None),
6202 Value::Integer(held) => assert_eq!(signed, Some(i128::from(held))),
6203 other => panic!("an integer column answered {other}"),
6204 }
6205 }
6206 }
6207
6208 /// Flattening gives up the form, which is what it is for, and what comes out holds the values the
6209 /// gather stood for, nulls included.
6210 #[test]
6211 fn flattening_a_gather_writes_out_the_rows_it_pointed_at() {
6212 let source = Arc::new(integers(&[10, 20, 30]));
6213 let vector = Vector::gathered(source, Arc::new(vec![2, NO_ROW, 0])).unwrap();
6214 let flat = vector.flatten().unwrap();
6215 assert_eq!(flat.form(), Form::Flat);
6216 assert_eq!(
6217 flat.iter().collect::<Vec<_>>(),
6218 vec![Value::Integer(30), Value::Null, Value::Integer(10)]
6219 );
6220 }
6221
6222 /// A gather counts a share of what it shares, for the reason a dictionary does. Eight columns
6223 /// gathered off one parent are one parent between them, not eight.
6224 #[test]
6225 fn a_parent_gathered_by_many_columns_is_counted_about_once_between_them() {
6226 let source = Arc::new(integers(&(0..4096).collect::<Vec<i32>>()));
6227 let rids = Arc::new(vec![0; 64]);
6228 let alone = Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap().footprint();
6229 let many = (0..8)
6230 .map(|_| Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap())
6231 .collect::<Vec<_>>();
6232 let together = many.iter().map(Vector::footprint).sum::<usize>();
6233 assert!(
6234 together < alone * 2,
6235 "eight gathers off one parent reported {together} against {alone} for one"
6236 );
6237 }
6238}