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: Buffer<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: Buffer::from_vec(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: Buffer::from_vec(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 // Against the bytes the rows take and not the footprint, because a window of a shared page
1459 // reports its share of the page. That made the answer, and so the file a load writes,
1460 // depend on how big the page was and how many readers it had.
1461 if words_for(self.len, width) * size_of::<u64>() * PACKING_PAYS_AT
1462 > flat_bytes(data, self.len)
1463 {
1464 return Ok(self.clone());
1465 }
1466 // A range can fit the type while that width up from the smallest value does not: a column
1467 // of a thousand values under `i32::MAX` needs ten bits, and ten bits up from the smallest
1468 // of them runs past `i32::MAX`. The packed form checks both ends of what its width can
1469 // say, so the base moves down until they both fit rather than the column being left flat.
1470 let Some(base) = packing_base(&self.ty, low, high, width) else {
1471 return Ok(self.clone());
1472 };
1473 let words = pack(data, self.len, base, width);
1474 let packed = Self::packed(self.ty.clone(), words, width, base, self.len)?;
1475 Ok(packed.with_validity(self.validity.clone()))
1476 }
1477
1478 /// A vector of string views over an arena somebody else is holding too.
1479 ///
1480 /// The way in for a scan that has a page of strings and wants several chunks over it. Each chunk
1481 /// gets its own run of views and they all share the one arena, so the bytes are read where the
1482 /// page put them and nothing copies them.
1483 ///
1484 /// Every view is checked against the arena here rather than when a row is read. That is a pass
1485 /// over the views at construction, which is the same pass the caller just did to build them, and
1486 /// what it buys is that a row of this form cannot resolve to bytes that are not there. The check
1487 /// is on the offsets and not on the bytes, so it says nothing about whether the payload is text,
1488 /// which is the same promise a `BLOB` column makes.
1489 ///
1490 /// # Errors
1491 ///
1492 /// If the type is not one stored as views, or if a view points past the end of the arena.
1493 pub fn string_views(
1494 ty: LogicalType,
1495 views: Vec<StringView>,
1496 arena: Arc<Buffer<u8>>,
1497 ) -> Result<Self> {
1498 if ty.physical() != rudb_common::PhysicalType::Varlen {
1499 return Err(Error::internal(format!("a {ty} vector cannot hold string views")));
1500 }
1501 if views.iter().any(|view| view.bytes_in(&arena).is_none()) {
1502 return Err(Error::internal("a string view points past the end of its arena"));
1503 }
1504 let len = views.len();
1505 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Views { views, arena } })
1506 }
1507
1508 /// A text vector whose values remain in a storage source until they are read.
1509 pub fn external_text(ty: LogicalType, source: Arc<dyn TextSource>) -> Result<Self> {
1510 if ty.physical() != rudb_common::PhysicalType::Varlen {
1511 return Err(Error::internal(format!(
1512 "a {ty} vector cannot use an external text source"
1513 )));
1514 }
1515 let len = source.len();
1516 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::ExternalText { source } })
1517 }
1518
1519 /// The same strings, in a form where a cut of them does not copy the bytes.
1520 ///
1521 /// The counterpart of [`Self::run_encoded`] and [`Self::bit_packed`] for a string column, and
1522 /// the only one of the three that takes `self` by value. It has to: what it does is move the
1523 /// arena into an `Arc` so nothing copies it again, and a version taking `&self` would start by
1524 /// copying the arena once to have one to move.
1525 ///
1526 /// Anything that is not a flat string column comes back as it was, which includes a column that
1527 /// is already in this form.
1528 ///
1529 /// # Errors
1530 ///
1531 /// Nothing here fails today. The result is a `Result` because the check inside
1532 /// [`Self::string_views`] is worth running on the views this builds rather than trusting that
1533 /// this function built them right.
1534 pub fn shared_text(self) -> Result<Self> {
1535 let Body::Flat(Data::Varlen(column)) = self.body else {
1536 return Ok(self);
1537 };
1538 let (views, arena) = column.into_parts();
1539 let shared = Self::string_views(self.ty, views, Arc::new(arena))?;
1540 Ok(shared.with_validity(self.validity))
1541 }
1542
1543 /// A vector of FSST codes against a table somebody else trained.
1544 ///
1545 /// The way in for a reader that has a page of compressed strings and the table that goes with
1546 /// it. The codes are not copied and the table is not retrained, so laying several chunks over
1547 /// one page costs the spans and nothing else.
1548 ///
1549 /// # Errors
1550 ///
1551 /// If the type is not one stored as text, or if a span runs past the end of the codes.
1552 pub fn coded(
1553 ty: LogicalType,
1554 codes: Arc<Vec<u8>>,
1555 spans: Vec<(u32, u32)>,
1556 table: Arc<SymbolTable>,
1557 ) -> Result<Self> {
1558 if ty.physical() != rudb_common::PhysicalType::Varlen {
1559 return Err(Error::internal(format!("a {ty} vector cannot hold FSST codes")));
1560 }
1561 let end = u32::try_from(codes.len()).unwrap_or(u32::MAX);
1562 if spans.iter().any(|&(from, to)| from > to || to > end) {
1563 return Err(Error::internal("an FSST span runs past the end of the codes"));
1564 }
1565 let len = spans.len();
1566 Ok(Self {
1567 ty,
1568 len,
1569 validity: Validity::AllValid,
1570 body: Body::Coded { codes, spans, table },
1571 })
1572 }
1573
1574 /// The same strings, compressed against a table trained on them.
1575 ///
1576 /// The counterpart of [`Self::run_encoded`] and [`Self::bit_packed`] for a text column, and it
1577 /// takes `self` by value for the reason [`Self::shared_text`] does.
1578 ///
1579 /// The table is trained on every row rather than on a sample. A vector is at most 1024 rows, so
1580 /// the sample would be most of the column anyway, and the systematic sampling
1581 /// `spec/06-compression.md` section 6.3 asks for is a decision about a page and belongs to
1582 /// whoever is holding one.
1583 ///
1584 /// It declines unless the codes are at most half the bytes the strings are. FSST gets about that
1585 /// on text and rather less on anything already short or already random, and below that the
1586 /// decompression per row read is not bought back. A column it declines on comes back as it was.
1587 ///
1588 /// # Errors
1589 ///
1590 /// Nothing here fails today. The result is a `Result` because the checks inside [`Self::coded`]
1591 /// are worth running on what this builds rather than trusting that this built it right.
1592 pub fn compressed(self) -> Result<Self> {
1593 let Body::Flat(Data::Varlen(column)) = &self.body else {
1594 return Ok(self);
1595 };
1596 let rows: Vec<&[u8]> = (0..self.len).filter_map(|row| column.bytes(row)).collect();
1597 if rows.len() != self.len {
1598 return Ok(self);
1599 }
1600 let plain: usize = rows.iter().map(|row| row.len()).sum();
1601 let table = SymbolTable::train(&rows);
1602 let mut codes = Vec::with_capacity(plain);
1603 let mut spans = Vec::with_capacity(self.len);
1604 for row in &rows {
1605 let from = u32::try_from(codes.len()).unwrap_or(u32::MAX);
1606 table.compress(row, &mut codes);
1607 spans.push((from, u32::try_from(codes.len()).unwrap_or(u32::MAX)));
1608 }
1609 if codes.len() * FSST_PAYS_AT > plain {
1610 return Ok(self);
1611 }
1612 let coded = Self::coded(self.ty.clone(), Arc::new(codes), spans, Arc::new(table))?;
1613 Ok(coded.with_validity(self.validity.clone()))
1614 }
1615
1616 /// The same values under a wider decimal type that stores them the same way.
1617 ///
1618 /// A decimal is kept as its unscaled integer, so two decimal types with one scale and one
1619 /// storage width describe the same bits, and going from the narrower of them to the wider is a
1620 /// relabelling rather than a conversion. The binder writes three of those into
1621 /// `l_extendedprice * (1 - l_discount)`, because a product's operands are given the answer's
1622 /// width and the answer's width is eighteen while both columns are fifteen, and each one was a
1623 /// pass over six million rows that wrote back the bytes it had just read.
1624 ///
1625 /// A flat run only, and deliberately. The general cast flattens whatever it is given, so a
1626 /// dictionary column came out of a width change as a run of values, and a relabelling that kept
1627 /// the dictionary would hand the arithmetic above two columns it has to read through a code per
1628 /// row instead of two it can read end to end. That was measured and it is the worse of the two:
1629 /// on `sum(l_extendedprice * l_discount)` under the filter q6 puts on it, where the rows left
1630 /// are few and scattered and the indirection is a cache miss each, keeping the dictionary cost
1631 /// half again as much as the flattening it saved. The flat case has no such question, since
1632 /// what it hands on is exactly what the pass would have built.
1633 ///
1634 /// Only widening, because a narrower width is a range every value has to be checked against and
1635 /// checking it is the pass this exists to avoid. `None` for anything else, including a narrower
1636 /// width, a changed scale, a changed storage width and any form but the flat one.
1637 #[must_use]
1638 pub fn as_wider_decimal(&self, target: &LogicalType) -> Option<Self> {
1639 let (
1640 LogicalType::Decimal { width: from, scale: held },
1641 LogicalType::Decimal { width: into, scale },
1642 ) = (&self.ty, target)
1643 else {
1644 return None;
1645 };
1646 if held != scale || from > into || self.ty.decimal_storage() != target.decimal_storage() {
1647 return None;
1648 }
1649 // Nothing in a flat run says what its numbers mean, so the relabelling is the type and
1650 // nothing else, and the buffer underneath is shared rather than copied.
1651 if !matches!(self.body, Body::Flat(_)) {
1652 return None;
1653 }
1654 Some(Self {
1655 ty: target.clone(),
1656 len: self.len,
1657 validity: self.validity.clone(),
1658 body: self.body.clone(),
1659 })
1660 }
1661
1662 /// The same vector with a different validity.
1663 #[must_use]
1664 pub fn with_validity(mut self, validity: Validity) -> Self {
1665 self.validity = validity;
1666 self
1667 }
1668
1669 /// What kind of values these are.
1670 #[must_use]
1671 pub fn logical_type(&self) -> &LogicalType {
1672 &self.ty
1673 }
1674
1675 /// How many values there are.
1676 #[must_use]
1677 pub fn len(&self) -> usize {
1678 self.len
1679 }
1680
1681 /// Whether there are no values.
1682 #[must_use]
1683 pub fn is_empty(&self) -> bool {
1684 self.len == 0
1685 }
1686
1687 /// How many bytes of memory this vector is holding.
1688 ///
1689 /// What the memory limit charges for it. A constant and a sequence hold one value and two
1690 /// numbers however long they are, which is the point of both forms, so the number here is the
1691 /// form's cost and not the column's width times its length.
1692 ///
1693 /// A part that is behind an `Arc` counts as one holder's share of it, which is
1694 /// [`Buffer::footprint`]'s rule for a shared page applied to the other shared parts. A
1695 /// dictionary counted in full in every vector sharing it is not a conservative over count, it is
1696 /// a number with the chunk count in it: an aggregate that emits nineteen thousand chunks of
1697 /// groups out of one stable dictionary reported that dictionary nineteen thousand times and
1698 /// refused itself a budget of twenty five gigabytes while the process held one. Dividing by the
1699 /// holders makes the sum over everything sharing the part come to about the part, which is what
1700 /// the number is supposed to mean, and it errs high rather than low whenever the holders arrive
1701 /// one after another, because each of them counts what it sees at the time it asks.
1702 #[must_use]
1703 pub fn footprint(&self) -> usize {
1704 let body = match &self.body {
1705 Body::Flat(data) => data.footprint(),
1706 Body::Constant(value) => value.footprint(),
1707 Body::Sequence { .. } => 0,
1708 Body::Dictionary { codes, values, .. } => {
1709 codes.footprint() + share(values.footprint(), values)
1710 }
1711 Body::Packed { words, .. } => share(words.capacity() * size_of::<u64>(), words),
1712 Body::Views { views, arena } => {
1713 views.capacity() * size_of::<StringView>() + share(arena.footprint(), arena)
1714 }
1715 Body::ExternalText { source } => share(source.footprint(), source),
1716 Body::Coded { codes, spans, table } => {
1717 share(codes.capacity(), codes)
1718 + spans.capacity() * size_of::<(u32, u32)>()
1719 + share(table.footprint(), table)
1720 }
1721 Body::Runs { ends, values } => {
1722 ends.capacity() * size_of::<u32>() + share(values.footprint(), values)
1723 }
1724 // The ids are shared between every cut of one link join's output, and the source is
1725 // shared with every other column gathered off the same parent, so both are divided by
1726 // their holders for the reason the dictionary above is. A gather whose source counted in
1727 // full would report a parent table per projected column per chunk.
1728 Body::Gathered { source, rids, .. } => {
1729 share(rids.capacity() * size_of::<u32>(), rids) + share(source.footprint(), source)
1730 }
1731 Body::Nested { entries, child } => {
1732 entries.capacity() * size_of::<(u32, u32)>() + share(child.footprint(), child)
1733 }
1734 // A struct is as wide as its fields are, so this is the one body whose cost is a sum
1735 // over children rather than one number, and a struct of a hundred narrow fields costs
1736 // what the hundred columns cost.
1737 Body::Fields { children } => {
1738 children.capacity() * size_of::<Arc<Self>>()
1739 + children.iter().map(|child| share(child.footprint(), child)).sum::<usize>()
1740 }
1741 };
1742 size_of::<Self>() + self.validity.footprint() + body
1743 }
1744
1745 /// Which of the values are not null, at this level and no deeper.
1746 ///
1747 /// This is not the same question as [`Self::is_null_at`] and the difference has already cost
1748 /// one wrong answer. A dictionary and a run length vector keep their nulls in the values they
1749 /// point at rather than in a mask of their own, so both are built with every row marked present
1750 /// here and a row whose value is null reads as valid. A caller that wants to know whether a row
1751 /// is null wants the other one. A caller that wants the mask of a flat column, to copy it or to
1752 /// count it, wants this one.
1753 #[must_use]
1754 pub fn validity(&self) -> &Validity {
1755 &self.validity
1756 }
1757
1758 /// Whether the row at `index` is null, in whichever form the vector is in.
1759 ///
1760 /// Reads through a dictionary or a run to the value it stands for, which is where those two
1761 /// forms keep their nulls, and answers from the mask for every other form. A row past the end
1762 /// is null, the same answer [`Self::value_at`] gives it.
1763 #[must_use]
1764 pub fn is_null_at(&self, index: usize) -> bool {
1765 if index >= self.len || !self.validity.is_valid(index) {
1766 return true;
1767 }
1768 match &self.body {
1769 Body::Dictionary { codes, values, .. } => match codes.get(index) {
1770 Some(&code) => values.is_null_at(code as usize),
1771 None => true,
1772 },
1773 Body::Runs { ends, values } => match run_holding(ends, index) {
1774 Some(run) => values.is_null_at(run),
1775 None => true,
1776 },
1777 // Section 8.2's lazy validity, which is this line. A gather has no mask of its own and
1778 // does not need one: the id says whether there is a row and the source says whether that
1779 // row is null, and both of those are already in memory.
1780 Body::Gathered { source, rids, offset } => match rids.get(offset + index) {
1781 Some(&NO_ROW) | None => true,
1782 Some(&rid) => source.is_null_at(rid as usize),
1783 },
1784 _ => false,
1785 }
1786 }
1787
1788 /// Whether no row in range is null, answered without reading a row.
1789 ///
1790 /// This is the cheap side of [`Self::is_null_at`] and has to follow it exactly. A dictionary and
1791 /// a run keep their nulls in the values they stand for, so both levels have to say they have
1792 /// none. Every other form answers from its own mask. A false means only that the cheap answer
1793 /// was not available, so a caller that gets one still has to ask row by row.
1794 ///
1795 /// Public because the alternative a caller has is a pass over the values, and on a dictionary
1796 /// that is the size of a Parquet column chunk's that pass is the thing it was trying to avoid.
1797 #[must_use]
1798 pub fn never_null(&self) -> bool {
1799 if self.validity.has_nulls(self.len) {
1800 return false;
1801 }
1802 match &self.body {
1803 Body::Dictionary { values, .. } | Body::Runs { values, .. } => values.never_null(),
1804 // A gather is never null when no id is the sentinel and the source holds no nulls. The
1805 // first of those is a pass over the ids rather than a constant, which is the one place
1806 // this question is not free, and it is worth paying: the ids are four bytes a row and
1807 // contiguous, and the alternative is reading through to the source once per row for the
1808 // whole vector, which is the random access this form exists to postpone.
1809 Body::Gathered { source, rids, offset } => {
1810 source.never_null()
1811 && !rids[*offset..].iter().take(self.len).any(|&rid| rid == NO_ROW)
1812 }
1813 _ => true,
1814 }
1815 }
1816
1817 /// Which physical form this vector is in.
1818 #[must_use]
1819 pub fn form(&self) -> Form {
1820 match self.body {
1821 Body::Flat(_) => Form::Flat,
1822 Body::Constant(_) => Form::Constant,
1823 Body::Sequence { .. } => Form::Sequence,
1824 Body::Dictionary { .. } => Form::Dictionary,
1825 Body::Packed { .. } => Form::BitPacked,
1826 Body::Views { .. } => Form::StringView,
1827 Body::ExternalText { .. } => Form::StringView,
1828 Body::Coded { .. } => Form::Fsst,
1829 Body::Runs { .. } => Form::Rle,
1830 Body::Nested { .. } => Form::List,
1831 Body::Fields { .. } => Form::Struct,
1832 Body::Gathered { .. } => Form::Gathered,
1833 }
1834 }
1835
1836 /// The data, for a flat vector, and `None` for any other form.
1837 ///
1838 /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
1839 /// that can do better on a constant or a dictionary checks [`Self::form`] first.
1840 #[must_use]
1841 pub fn data(&self) -> Option<&Data> {
1842 match &self.body {
1843 Body::Flat(data) => Some(data),
1844 _ => None,
1845 }
1846 }
1847
1848 /// The one value, for a constant vector, and `None` for any other form.
1849 ///
1850 /// A kernel comparing a column against a literal wants the literal once rather than 1024
1851 /// times, and [`Self::value_at`] on a constant clones it on every call because it has to be
1852 /// able to hand back a `Value` for any form. This is the accessor that lets the specialized
1853 /// path hoist the clone out of the loop.
1854 #[must_use]
1855 pub fn constant_value(&self) -> Option<&Value> {
1856 match &self.body {
1857 Body::Constant(value) => Some(value.as_ref()),
1858 _ => None,
1859 }
1860 }
1861
1862 /// The codes and the values, for a dictionary vector, and `None` for any other form.
1863 ///
1864 /// The reason a kernel needs this rather than reading the dictionary through
1865 /// [`Self::value_at`] is the entire argument for the form existing. A filter against a
1866 /// dictionary column of 1024 rows and 40 distinct values is 40 comparisons and 1024 lookups,
1867 /// not 1024 comparisons, and there is no way to write that loop without seeing the codes.
1868 ///
1869 /// Note what the validity of the returned vector means. A dictionary keeps its nulls in the
1870 /// vector it points at, and the dictionary's own validity says nothing about them, so a caller
1871 /// deciding whether row `i` is null has to ask the value vector about `codes[i]` rather than
1872 /// asking this vector about `i`. [`Self::flatten`] has the same note on it for the same
1873 /// reason, because getting this wrong is a null that survives being selected and comes out as
1874 /// a zero.
1875 #[must_use]
1876 pub fn dictionary_parts(&self) -> Option<(&[u32], &Self)> {
1877 match &self.body {
1878 Body::Dictionary { codes, values, .. } => Some((codes, values.as_ref())),
1879 _ => None,
1880 }
1881 }
1882
1883 /// The codes and the shared dictionary handle for a dictionary vector.
1884 ///
1885 /// Storage readers use the identity of this handle to prove that codes from separate pages
1886 /// belong to one table-wide dictionary. Kernels that only read values should continue to use
1887 /// [`Self::dictionary_parts`].
1888 #[must_use]
1889 pub fn shared_dictionary_parts(&self) -> Option<(&[u32], &Arc<Self>)> {
1890 match &self.body {
1891 Body::Dictionary { codes, values, .. } => Some((codes, values)),
1892 _ => None,
1893 }
1894 }
1895
1896 /// Stable codes and their shared values, when storage guarantees one code space across pages.
1897 #[must_use]
1898 pub fn stable_dictionary_parts(&self) -> Option<(&[u32], &Arc<Self>)> {
1899 match &self.body {
1900 Body::Dictionary { codes, values, stable: true } => Some((codes, values)),
1901 _ => None,
1902 }
1903 }
1904
1905 /// The run ends and the run values, for a run length vector, and `None` for any other form.
1906 ///
1907 /// The ends are exclusive and increasing, and there is exactly one value per run, so a kernel
1908 /// that wants to walk this walks the pairs and never asks which run a row is in. That is the
1909 /// whole argument for the form: an aggregate over a clustered column is one multiply per run
1910 /// instead of one add per row, and there is no way to write that loop without seeing the ends.
1911 ///
1912 /// The nulls are in the values, the way a dictionary's are, so a caller deciding whether row `i`
1913 /// is null asks the value vector about the run rather than asking this vector about `i`.
1914 #[must_use]
1915 pub fn run_parts(&self) -> Option<(&[u32], &Self)> {
1916 match &self.body {
1917 Body::Runs { ends, values } => Some((ends, values.as_ref())),
1918 _ => None,
1919 }
1920 }
1921
1922 /// Where each row's value is, for the two forms that keep their values somewhere else.
1923 ///
1924 /// A dictionary and a run length vector are the same shape seen from a kernel: a run of
1925 /// positions and a vector to read them out of. The difference is that a dictionary stores the
1926 /// positions and a run length vector works them out, and a kernel writing `values[at[row]]` does
1927 /// not care which. So every specialization written against [`Self::dictionary_parts`] covers
1928 /// both forms by asking this instead, and the day a third form with an indirection arrives it
1929 /// covers that one too without any of those kernels being reopened.
1930 ///
1931 /// The run length side costs an allocation of one position per row and a pass to fill it, which
1932 /// is the same four bytes a row a dictionary was already carrying and is paid once per kernel
1933 /// call rather than once per row. That is the price of this being one accessor rather than a
1934 /// second arm in eighteen kernels, and it is not the last word: a kernel that wants a run at a
1935 /// time reads [`Self::run_parts`] and pays nothing, which is the specialization this makes it
1936 /// possible to skip writing until a sweep says it is worth it.
1937 #[must_use]
1938 pub fn positions(&self) -> Option<(Cow<'_, [u32]>, &Self)> {
1939 match &self.body {
1940 Body::Dictionary { codes, values, .. } => Some((Cow::Borrowed(codes), values.as_ref())),
1941 Body::Runs { ends, values } => {
1942 let mut at = Vec::with_capacity(self.len);
1943 for (run, &stop) in ends.iter().enumerate() {
1944 let run = u32::try_from(run).unwrap_or(u32::MAX);
1945 at.resize(stop as usize, run);
1946 }
1947 Some((Cow::Owned(at), values.as_ref()))
1948 }
1949 _ => None,
1950 }
1951 }
1952
1953 /// The bits and what they mean, for a bit packed vector, and `None` for any other form.
1954 ///
1955 /// What a kernel needs to stay in code space. A comparison against a literal is the case that
1956 /// pays: `column > 900` over a column packed from a base of 40 is `code > 860`, which is the
1957 /// same shift and mask the read was going to do anyway and no unpacking at all, and a literal
1958 /// outside the packed range answers the whole vector without reading a bit of it. None of that
1959 /// can be written without seeing the width and the base.
1960 #[must_use]
1961 pub fn packed_parts(&self) -> Option<Packed<'_>> {
1962 match &self.body {
1963 Body::Packed { words, width, base, offset } => {
1964 Some(Packed { words, width: *width, base: *base, offset: *offset })
1965 }
1966 _ => None,
1967 }
1968 }
1969
1970 /// The views and the arena, for either form that stores strings, and `None` for the rest.
1971 ///
1972 /// This is to the two string forms what [`Self::positions`] is to the two forms that point
1973 /// somewhere else. A flat varchar column owns its arena and a string view column shares one, and
1974 /// a kernel reading a row wants the view and the bytes either way, so every specialization
1975 /// written against this covers both forms and neither has to be reopened when a third way of
1976 /// holding an arena arrives.
1977 ///
1978 /// The arena is whatever the long strings live in, which for a column over a page is the page,
1979 /// including the parts of it no view points at. Only the views say which bytes are a row.
1980 #[must_use]
1981 pub fn text_parts(&self) -> Option<(&[StringView], &[u8])> {
1982 match &self.body {
1983 Body::Flat(Data::Varlen(column)) => Some((column.views(), column.arena())),
1984 Body::Views { views, arena } => Some((views, arena)),
1985 _ => None,
1986 }
1987 }
1988
1989 /// The views and the arena they point into, for a vector of string views and nothing else.
1990 ///
1991 /// [`Self::text_parts`] answers the same question for a flat column too, and gives the arena as
1992 /// bytes. This gives the `Arc`, which is what a caller laying several of these end to end needs
1993 /// to see that they share one arena and can keep it rather than copying out of it.
1994 #[must_use]
1995 pub fn shared_views(&self) -> Option<(&[StringView], &Arc<Buffer<u8>>)> {
1996 match &self.body {
1997 Body::Views { views, arena } => Some((views, arena)),
1998 _ => None,
1999 }
2000 }
2001
2002 /// The codes and the table, for an FSST vector, and `None` for any other form.
2003 ///
2004 /// What a kernel needs to stay in code space. An equality filter is the case that pays, and it
2005 /// pays completely: the literal is compressed once against the same table and after that a row
2006 /// matches exactly when its code bytes match, because compressing is a function and so is
2007 /// decompressing. No row is decompressed at all. An ordering comparison cannot do that, since a
2008 /// symbol code says nothing about where its symbol sorts, so those decompress and say so.
2009 #[must_use]
2010 pub fn coded_parts(&self) -> Option<Coded<'_>> {
2011 match &self.body {
2012 Body::Coded { codes, spans, table } => Some(Coded { codes, spans, table }),
2013 _ => None,
2014 }
2015 }
2016
2017 /// The start and the step, for a sequence vector, and `None` for any other form.
2018 #[must_use]
2019 pub fn sequence_parts(&self) -> Option<(i64, i64)> {
2020 match self.body {
2021 Body::Sequence { start, step } => Some((start, step)),
2022 _ => None,
2023 }
2024 }
2025
2026 /// The value at `index`, as a single value.
2027 ///
2028 /// This is the slow path on purpose. It is what a result set is read out with and what a test
2029 /// asserts on, and an operator that calls it per row is an operator that has already lost the
2030 /// argument the vector interface exists to win.
2031 #[must_use]
2032 pub fn value_at(&self, index: usize) -> Value {
2033 if index >= self.len || !self.validity.is_valid(index) {
2034 return Value::Null;
2035 }
2036 match &self.body {
2037 Body::Constant(value) => value.as_ref().clone(),
2038 Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
2039 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2040 Some(&code) => values.value_at(code as usize),
2041 None => Value::Null,
2042 },
2043 Body::Runs { ends, values } => match run_holding(ends, index) {
2044 Some(run) => values.value_at(run),
2045 None => Value::Null,
2046 },
2047 // The one read every other reader of this form is: follow the id, and answer null when
2048 // there is no row to follow. Written out once per reader rather than through a helper
2049 // because each of them returns a different kind of nothing.
2050 Body::Gathered { source, rids, offset } => match rids.get(offset + index) {
2051 Some(&NO_ROW) | None => Value::Null,
2052 Some(&rid) => source.value_at(rid as usize),
2053 },
2054 // One value unpacked into a run of one, so that what a packed value means is decided in
2055 // the same place a flat one is rather than in a second copy of the type mapping that
2056 // could drift from it. It allocates, which this path is allowed to do and the typed
2057 // unpack in `copied` is not, and it is the reason anything about to read a packed
2058 // column a row at a time should flatten it once instead.
2059 Body::Packed { words, width, base, offset } => {
2060 unpack(&self.ty, words, *offset, *width, *base, &[index])
2061 .map_or(Value::Null, |data| value_from(&self.ty, &data, 0))
2062 }
2063 // The bytes are where the arena has them, and what they are read as is the logical
2064 // type's business, so this hands the row to the same reader a flat column goes through
2065 // rather than deciding here that a `BLOB` is a string.
2066 Body::Views { views, arena } => {
2067 match views.get(index).and_then(|v| v.bytes_in(arena)) {
2068 Some(bytes) => bytes_as(&self.ty, bytes),
2069 None => Value::Null,
2070 }
2071 }
2072 Body::ExternalText { source } => source
2073 .bytes_at(index)
2074 .ok()
2075 .flatten()
2076 .map_or(Value::Null, |bytes| bytes_as(&self.ty, bytes)),
2077 // One row decompressed on its own, which is the property the form is chosen for. It
2078 // allocates, which this path is allowed to do, and it is the reason anything about to
2079 // read a compressed column a row at a time should flatten it once instead.
2080 Body::Coded { codes, spans, table } => {
2081 match spans.get(index).and_then(|&(from, to)| {
2082 let mut out = Vec::new();
2083 table.decompress(codes.get(from as usize..to as usize)?, &mut out).ok()?;
2084 Some(out)
2085 }) {
2086 Some(bytes) => bytes_as(&self.ty, &bytes),
2087 None => Value::Null,
2088 }
2089 }
2090 // A row's elements are read out of the child one at a time, which is the slow path this
2091 // whole function is and is why a kernel over a list column reads `list_parts` instead.
2092 // The element type comes from the child rather than from this vector's type, so a list
2093 // whose child was built narrower than the column claims still hands back what is in it.
2094 //
2095 // A map is stored in this body too, so which value comes out is decided by the logical
2096 // type rather than by the body. That is the one place the composition shows: the bytes of
2097 // a map really are the bytes of a list of two field structs, and the only thing that
2098 // remembers it is a map is the type.
2099 Body::Nested { entries, child } => match (entries.get(index), &self.ty) {
2100 (Some(&(start, len)), LogicalType::Map(key, value)) => {
2101 let pairs = child.struct_parts().unwrap_or_default();
2102 Value::map(
2103 key.as_ref().clone(),
2104 value.as_ref().clone(),
2105 (start..start + len)
2106 .filter_map(|at| {
2107 let [keys, values] = pairs else { return None };
2108 Some((keys.value_at(at as usize), values.value_at(at as usize)))
2109 })
2110 .collect(),
2111 )
2112 }
2113 (Some(&(start, len)), _) => Value::List {
2114 element: child.ty.clone(),
2115 values: (start..start + len).map(|at| child.value_at(at as usize)).collect(),
2116 },
2117 (None, _) => Value::Null,
2118 },
2119 // One value read out of each child at the same position, which is the slow path this whole
2120 // function is and is why a kernel over a struct column reads `struct_parts` instead. The
2121 // names come from this vector's type rather than from the children, because a child is a
2122 // vector and a vector has no name, and the type is where the field order is written down.
2123 Body::Fields { children } => Value::Struct(
2124 fields_of(&self.ty)
2125 .iter()
2126 .zip(children)
2127 .map(|(field, child)| (field.name.clone(), child.value_at(index)))
2128 .collect(),
2129 ),
2130 Body::Flat(data) => value_from(&self.ty, data, index),
2131 }
2132 }
2133
2134 /// One value of this vector's type, built out of bytes the caller already holds.
2135 ///
2136 /// [`try_value_at`](Self::try_value_at) finds the bytes itself, which over a dictionary that
2137 /// keeps its payload in a file means a read. A caller that swept the values out has the bytes in
2138 /// hand already and wants nothing from here but the type.
2139 pub fn value_of(&self, bytes: &[u8]) -> Value {
2140 bytes_as(&self.ty, bytes)
2141 }
2142
2143 /// The value at `index`, preserving storage read and validation failures.
2144 pub fn try_value_at(&self, index: usize) -> Result<Value> {
2145 if index >= self.len || !self.validity.is_valid(index) {
2146 return Ok(Value::Null);
2147 }
2148 match &self.body {
2149 Body::ExternalText { source } => {
2150 Ok(source.bytes_at(index)?.map_or(Value::Null, |bytes| bytes_as(&self.ty, bytes)))
2151 }
2152 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2153 Some(&code) => values.try_value_at(code as usize),
2154 None => Ok(Value::Null),
2155 },
2156 Body::Runs { ends, values } => match run_holding(ends, index) {
2157 Some(run) => values.try_value_at(run),
2158 None => Ok(Value::Null),
2159 },
2160 Body::Nested { entries, child } => match (entries.get(index), &self.ty) {
2161 (Some(&(start, len)), LogicalType::Map(key, value)) => {
2162 let pairs = child.struct_parts().unwrap_or_default();
2163 let [keys, values] = pairs else { return Ok(Value::Null) };
2164 let mut entries = Vec::with_capacity(len as usize);
2165 for at in start..start + len {
2166 entries.push((
2167 keys.try_value_at(at as usize)?,
2168 values.try_value_at(at as usize)?,
2169 ));
2170 }
2171 Ok(Value::map(key.as_ref().clone(), value.as_ref().clone(), entries))
2172 }
2173 (Some(&(start, len)), _) => {
2174 let mut values = Vec::with_capacity(len as usize);
2175 for at in start..start + len {
2176 values.push(child.try_value_at(at as usize)?);
2177 }
2178 Ok(Value::List { element: child.ty.clone(), values })
2179 }
2180 (None, _) => Ok(Value::Null),
2181 },
2182 Body::Fields { children } => {
2183 let mut values = Vec::with_capacity(children.len());
2184 for (field, child) in fields_of(&self.ty).iter().zip(children) {
2185 values.push((field.name.clone(), child.try_value_at(index)?));
2186 }
2187 Ok(Value::Struct(values))
2188 }
2189 _ => Ok(self.value_at(index)),
2190 }
2191 }
2192
2193 /// The text at `index`, borrowed rather than copied.
2194 ///
2195 /// [`Self::value_at`] on a `VARCHAR` column allocates a `String` per call, and a group by that
2196 /// reads a string column keys on one string per input row. This hands back the bytes where they
2197 /// already are, so a caller with somewhere to put them does not go to the allocator at all.
2198 ///
2199 /// `None` for a null, for an index past the end, for a column that is not `VARCHAR`, and for the
2200 /// constant and sequence forms, whose values are not stored per position. A caller that gets
2201 /// `None` has to fall back to [`Self::value_at`], which is correct for all of those.
2202 #[must_use]
2203 pub fn text_at(&self, index: usize) -> Option<&str> {
2204 if self.ty != LogicalType::Varchar || index >= self.len || !self.validity.is_valid(index) {
2205 return None;
2206 }
2207 match &self.body {
2208 Body::Flat(data) => data.str_at(index),
2209 Body::Dictionary { codes, values, .. } => {
2210 values.text_at(usize::try_from(*codes.get(index)?).ok()?)
2211 }
2212 Body::Runs { ends, values } => values.text_at(run_holding(ends, index)?),
2213 Body::Gathered { source, rids, offset } => {
2214 source.text_at(row_of(rids, *offset, index)?)
2215 }
2216 Body::Views { views, arena } => {
2217 std::str::from_utf8(views.get(index)?.bytes_in(arena)?).ok()
2218 }
2219 Body::ExternalText { source } => {
2220 std::str::from_utf8(source.bytes_at(index).ok().flatten()?).ok()
2221 }
2222 _ => None,
2223 }
2224 }
2225
2226 /// The variable length bytes at `index`, borrowed without validating or copying them.
2227 ///
2228 /// String data is validated when it enters a vector. Hashing and equality only need its bytes,
2229 /// so those kernels should not pay for UTF-8 validation again on every read.
2230 #[must_use]
2231 pub fn bytes_at(&self, index: usize) -> Option<&[u8]> {
2232 if index >= self.len || !self.validity.is_valid(index) {
2233 return None;
2234 }
2235 match &self.body {
2236 Body::Constant(value) => match value.as_ref() {
2237 Value::Varchar(text) => Some(text.as_bytes()),
2238 Value::Blob(bytes) => Some(bytes),
2239 _ => None,
2240 },
2241 Body::Dictionary { codes, values, .. } => {
2242 values.bytes_at(usize::try_from(*codes.get(index)?).ok()?)
2243 }
2244 Body::Runs { ends, values } => values.bytes_at(run_holding(ends, index)?),
2245 Body::Gathered { source, rids, offset } => {
2246 source.bytes_at(row_of(rids, *offset, index)?)
2247 }
2248 Body::Views { views, arena } => views.get(index)?.bytes_in(arena),
2249 Body::ExternalText { source } => source.bytes_at(index).ok().flatten(),
2250 Body::Flat(data) => data.bytes_at(index),
2251 // The same `None` [`Self::text_at`] gives, for the same reason. A compressed row is not
2252 // anywhere in its plain bytes, so there is nothing here to hand back a borrow of, and a
2253 // caller that gets `None` goes to `value_at` and gets the row decompressed into a value.
2254 // A list row is `None` for a nearer reason: it is not bytes at all, and a caller wanting
2255 // its elements wants [`Self::list_parts`] rather than a borrow of one row.
2256 Body::Coded { .. }
2257 | Body::Sequence { .. }
2258 | Body::Packed { .. }
2259 | Body::Nested { .. }
2260 | Body::Fields { .. } => None,
2261 }
2262 }
2263
2264 /// Variable length bytes at `index`, preserving storage read and validation failures.
2265 pub fn try_bytes_at(&self, index: usize) -> Result<Option<&[u8]>> {
2266 if index >= self.len || !self.validity.is_valid(index) {
2267 return Ok(None);
2268 }
2269 match &self.body {
2270 Body::Constant(value) => Ok(match value.as_ref() {
2271 Value::Varchar(text) => Some(text.as_bytes()),
2272 Value::Blob(bytes) => Some(bytes.as_slice()),
2273 _ => None,
2274 }),
2275 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2276 Some(&code) => values.try_bytes_at(code as usize),
2277 None => Ok(None),
2278 },
2279 Body::Runs { ends, values } => match run_holding(ends, index) {
2280 Some(run) => values.try_bytes_at(run),
2281 None => Ok(None),
2282 },
2283 Body::Gathered { source, rids, offset } => match row_of(rids, *offset, index) {
2284 Some(row) => source.try_bytes_at(row),
2285 None => Ok(None),
2286 },
2287 Body::Views { views, arena } => {
2288 Ok(views.get(index).and_then(|view| view.bytes_in(arena)))
2289 }
2290 Body::ExternalText { source } => source.bytes_at(index),
2291 Body::Flat(data) => Ok(data.bytes_at(index)),
2292 Body::Coded { .. }
2293 | Body::Sequence { .. }
2294 | Body::Packed { .. }
2295 | Body::Nested { .. }
2296 | Body::Fields { .. } => Ok(None),
2297 }
2298 }
2299
2300 /// Walks the values from `first` up to at most `limit`, without keeping what it read.
2301 ///
2302 /// [`TextSource::sweep`] is what this is for and what the doc on it explains. Everything else
2303 /// here is the honest fallback: a vector that is not reading text out of a file has its values
2304 /// already, so there is nothing to avoid keeping, and it hands over one value and lets the
2305 /// caller come back. The answer is one past the last value visited either way, so the loop that
2306 /// calls this is the same loop whichever form it got.
2307 ///
2308 /// Nulls go the slow way. A source that reads a file holds no validity of its own, so the
2309 /// vector's own mask is the only thing that knows, and rather than teach the sweep about it the
2310 /// one form that can have both hands over a value at a time through the reader that checks.
2311 ///
2312 /// # Errors
2313 ///
2314 /// Whatever reading a value raises, and whatever `body` raises.
2315 pub fn sweep_text(
2316 &self,
2317 first: usize,
2318 limit: usize,
2319 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
2320 ) -> Result<usize> {
2321 let limit = limit.min(self.len);
2322 if first >= limit {
2323 return Ok(first);
2324 }
2325 if let Body::ExternalText { source } = &self.body {
2326 if matches!(self.validity, Validity::AllValid) {
2327 return source.sweep(first, limit, body);
2328 }
2329 }
2330 body(first, self.try_bytes_at(first)?.unwrap_or_default())?;
2331 Ok(first + 1)
2332 }
2333
2334 /// A conservative substring test for the payload block holding `first`.
2335 ///
2336 /// Only a file-backed string source with all-valid values can skip a whole block. Every other
2337 /// form returns true and lets the ordinary sweep decide its values.
2338 pub fn text_block_might_contain(&self, first: usize, literal: &[u8]) -> Result<bool> {
2339 match &self.body {
2340 Body::ExternalText { source } if matches!(self.validity, Validity::AllValid) => {
2341 source.might_contain(first, literal)
2342 }
2343 _ => Ok(true),
2344 }
2345 }
2346
2347 /// The values at `indices`, which rise, without keeping what reading them decoded.
2348 ///
2349 /// [`TextSource::visit`] is what this is for. A vector that is not reading text out of a file, or
2350 /// that has nulls of its own, reads a value at a time through the reader that checks.
2351 ///
2352 /// # Errors
2353 ///
2354 /// Whatever reading a value raises.
2355 pub fn try_values_visited(&self, indices: &[usize]) -> Result<Vec<Value>> {
2356 if let Body::ExternalText { source } = &self.body {
2357 if matches!(self.validity, Validity::AllValid) {
2358 let mut out = vec![Value::Null; indices.len()];
2359 let mut own = |at: usize, bytes: &[u8]| {
2360 if indices[at] < self.len {
2361 out[at] = bytes_as(&self.ty, bytes);
2362 }
2363 Ok(())
2364 };
2365 source.visit(indices, &mut own)?;
2366 return Ok(out);
2367 }
2368 }
2369 indices.iter().map(|&index| self.try_value_at(index)).collect()
2370 }
2371
2372 /// Variable length byte count at `index`, preserving storage failures.
2373 pub fn try_bytes_len_at(&self, index: usize) -> Result<Option<usize>> {
2374 if index >= self.len || !self.validity.is_valid(index) {
2375 return Ok(None);
2376 }
2377 match &self.body {
2378 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2379 Some(&code) => values.try_bytes_len_at(code as usize),
2380 None => Ok(None),
2381 },
2382 Body::Runs { ends, values } => match run_holding(ends, index) {
2383 Some(run) => values.try_bytes_len_at(run),
2384 None => Ok(None),
2385 },
2386 Body::ExternalText { source } => source.bytes_len_at(index),
2387 _ => Ok(self.bytes_at(index).map(<[u8]>::len)),
2388 }
2389 }
2390
2391 /// The byte length of every row, in one call to whatever holds the text, when that is possible.
2392 ///
2393 /// `into` is one slot per row. The answer is whether it was filled: a vector with nulls in it,
2394 /// or one whose text is not read from a [`TextSource`], answers `false` and leaves the caller to
2395 /// ask a row at a time through [`Self::try_bytes_len_at`], which is right for every shape. The
2396 /// two shapes taken here are the two a scan of a stored string column hands out, the text itself
2397 /// and a dictionary of codes over it, and each is one call to the source for the whole vector
2398 /// rather than a call per row down through this type.
2399 ///
2400 /// # Errors
2401 ///
2402 /// Whatever reading the lengths out of storage raises.
2403 pub fn try_bytes_lens(&self, into: &mut [i64]) -> Result<bool> {
2404 if into.len() != self.len || !matches!(self.validity, Validity::AllValid) {
2405 return Ok(false);
2406 }
2407 match &self.body {
2408 Body::ExternalText { source } => {
2409 let Ok(rows) = u32::try_from(self.len) else { return Ok(false) };
2410 let indices = (0..rows).collect::<Vec<_>>();
2411 source.bytes_lens_at(&indices, into)?;
2412 Ok(true)
2413 }
2414 Body::Dictionary { codes, values, .. } => match &values.body {
2415 Body::ExternalText { source } if matches!(values.validity, Validity::AllValid) => {
2416 source.bytes_lens_at(codes, into)?;
2417 Ok(true)
2418 }
2419 _ => Ok(false),
2420 },
2421 _ => Ok(false),
2422 }
2423 }
2424
2425 /// How many ranks this vector's values have in sorted order, when whatever holds them knows.
2426 ///
2427 /// See [`TextSource::ranks`] for what a rank is and what a source promises by answering with
2428 /// one. Only a vector whose values come from storage can answer, because only storage is in a
2429 /// position to have sorted them once and written the answer down.
2430 #[must_use]
2431 pub fn ranks(&self) -> Option<usize> {
2432 match &self.body {
2433 Body::ExternalText { source } => source.ranks(),
2434 _ => None,
2435 }
2436 }
2437
2438 /// How the value at `rank` compares against `wanted`. See [`TextSource::compare_rank`].
2439 pub fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
2440 match &self.body {
2441 Body::ExternalText { source } => source.compare_rank(rank, wanted),
2442 _ => {
2443 Err(Error::internal("a vector without a sorted order was asked to compare a rank"))
2444 }
2445 }
2446 }
2447
2448 /// Where `wanted` would go in the sorted order. See [`TextSource::below`].
2449 ///
2450 /// # Errors
2451 ///
2452 /// If this vector has no sorted order, or if a probe of it fails.
2453 pub fn below(&self, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)> {
2454 match &self.body {
2455 Body::ExternalText { source } => source.below(ranks, wanted),
2456 _ => Err(Error::internal("a vector without a sorted order was asked for a boundary")),
2457 }
2458 }
2459
2460 /// The position of the value at `rank`. See [`TextSource::code_at_rank`].
2461 pub fn code_at_rank(&self, rank: usize) -> Result<u32> {
2462 match &self.body {
2463 Body::ExternalText { source } => source.code_at_rank(rank),
2464 _ => Err(Error::internal("a vector without a sorted order was asked for a rank")),
2465 }
2466 }
2467
2468 /// The rank of every value, indexed by position. See [`TextSource::code_ranks`].
2469 #[must_use]
2470 pub fn code_ranks(&self) -> Option<&[u32]> {
2471 match &self.body {
2472 Body::ExternalText { source } => source.code_ranks(),
2473 _ => None,
2474 }
2475 }
2476
2477 /// Text at `index`, preserving storage read, validation and UTF-8 failures.
2478 pub fn try_text_at(&self, index: usize) -> Result<Option<&str>> {
2479 if self.ty != LogicalType::Varchar {
2480 return Ok(None);
2481 }
2482 self.try_bytes_at(index)?
2483 .map(|bytes| {
2484 std::str::from_utf8(bytes).map_err(|error| {
2485 Error::conversion(format!("invalid UTF-8 in VARCHAR: {error}"))
2486 })
2487 })
2488 .transpose()
2489 }
2490
2491 /// Read every storage-backed value reachable through this vector.
2492 pub fn validate_external(&self) -> Result<()> {
2493 match &self.body {
2494 Body::ExternalText { source } => {
2495 for index in 0..source.len() {
2496 source.bytes_at(index)?;
2497 }
2498 }
2499 Body::Dictionary { codes, values, .. } => {
2500 if values.reaches_storage() {
2501 for &code in codes.iter() {
2502 values.try_bytes_at(code as usize)?;
2503 }
2504 }
2505 }
2506 Body::Runs { values, .. } | Body::Gathered { source: values, .. } => {
2507 values.validate_external()?;
2508 }
2509 Body::Nested { child, .. } => child.validate_external()?,
2510 Body::Fields { children } => {
2511 for child in children {
2512 child.validate_external()?;
2513 }
2514 }
2515 _ => {}
2516 }
2517 Ok(())
2518 }
2519
2520 /// Whether any value of this vector is read from storage when it is asked for.
2521 ///
2522 /// A dictionary over values already in memory has nothing that can fail to read, and checking
2523 /// it a code at a time cost the thread that drains a query about a fifth of a sorted table
2524 /// copy for no answer at all.
2525 fn reaches_storage(&self) -> bool {
2526 match &self.body {
2527 Body::ExternalText { .. } => true,
2528 Body::Dictionary { values, .. }
2529 | Body::Runs { values, .. }
2530 | Body::Gathered { source: values, .. } => values.reaches_storage(),
2531 Body::Nested { child, .. } => child.reaches_storage(),
2532 Body::Fields { children } => children.iter().any(|child| child.reaches_storage()),
2533 _ => false,
2534 }
2535 }
2536
2537 /// The signed integer at `index`, widened, read without building a [`Value`].
2538 ///
2539 /// The integer sibling of [`Self::bytes_at`], and it is here for the same caller. A group by on
2540 /// an integer column compares one key per input row against the group it probed, and doing that
2541 /// through [`Self::value_at`] built and dropped a sixty four byte value a row at a time for a
2542 /// number that was already sitting in the column.
2543 ///
2544 /// Widened to `i128` because that is what [`Data::signed_at`] hands back underneath, and one
2545 /// method that covers every signed width is worth more than five that do not. A caller that
2546 /// wants a narrower type narrows it, which is a range check against a value in a register.
2547 ///
2548 /// The types this answers for are the ones whose flat data is read through `signed_at`, so the
2549 /// five signed integer widths and the decimal, date, time and timestamp types that are stored
2550 /// in them. A decimal answers with its unscaled value, which is the number the column holds.
2551 ///
2552 /// `None` for a null, for an index past the end, for a column of any other type, and for the
2553 /// compressed form. Packed integers stay in code space and answer `base + code` directly. A
2554 /// caller that gets `None` falls back to [`Self::value_at`], which is correct for the remaining
2555 /// forms.
2556 #[must_use]
2557 pub fn signed_at(&self, index: usize) -> Option<i128> {
2558 if index >= self.len || !self.validity.is_valid(index) {
2559 return None;
2560 }
2561 match &self.body {
2562 Body::Flat(data) => data.signed_at(index),
2563 Body::Constant(value) => match value.as_ref() {
2564 Value::TinyInt(x) => Some(i128::from(*x)),
2565 Value::SmallInt(x) => Some(i128::from(*x)),
2566 Value::Integer(x) | Value::Date(x) => Some(i128::from(*x)),
2567 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => Some(i128::from(*x)),
2568 Value::HugeInt(x) | Value::Decimal { unscaled: x, .. } => Some(*x),
2569 _ => None,
2570 },
2571 // The same arithmetic [`Self::value_at`] does on a sequence, so the two agree about a
2572 // sequence that runs off the end of the width it is stored in.
2573 Body::Sequence { start, step } => {
2574 Some(i128::from(start.wrapping_add(step.wrapping_mul(index as i64))))
2575 }
2576 Body::Dictionary { codes, values, .. } => {
2577 values.signed_at(usize::try_from(*codes.get(index)?).ok()?)
2578 }
2579 Body::Runs { ends, values } => values.signed_at(run_holding(ends, index)?),
2580 Body::Gathered { source, rids, offset } => {
2581 source.signed_at(row_of(rids, *offset, index)?)
2582 }
2583 Body::Packed { words, width, base, offset } => Some(
2584 *base + i128::from(code_at(words, (*offset + index) * *width as usize, *width)),
2585 ),
2586 // The same `None` [`Self::bytes_at`] gives, for the same reason. A compressed row is not
2587 // an integer anywhere until it has been unpacked, and a caller that gets
2588 // `None` goes to `value_at` and gets the row unpacked into a value. A list row is not an
2589 // integer in any form, however many integers are in it, and a struct row is not one even
2590 // when it has exactly one integer field, since the row is the struct and not the field.
2591 Body::Coded { .. }
2592 | Body::Views { .. }
2593 | Body::ExternalText { .. }
2594 | Body::Nested { .. }
2595 | Body::Fields { .. } => None,
2596 }
2597 }
2598
2599 /// Every signed value in order, widened to `i64`, written into `out`.
2600 ///
2601 /// The bulk form of [`Self::signed_at`], for a caller that is going to read the whole vector
2602 /// anyway. A group by on two integer columns called `signed_at` once per column per row, and
2603 /// every one of those matched on the body, called into the data and matched again on the
2604 /// layout, which is about sixty five instructions to read a number that was already sitting in
2605 /// a slice. It was a fifth of ClickBench 32 on its own.
2606 ///
2607 /// A null writes whatever the body holds under it, which is the zero a flat column keeps behind
2608 /// its mask. Nulls are a separate question and the caller asks it separately, from
2609 /// [`Self::none_null`] once for the vector when that answers and a row at a time when it does
2610 /// not.
2611 ///
2612 /// `false`, with `out` left empty, for a vector this cannot hand over as a block: `HUGEINT` and
2613 /// the wide decimals, whose values do not fit an `i64`, the string and nested forms, the
2614 /// compressed form, and the dictionary and run forms, which are a gather rather than a copy and
2615 /// are left until something wants them. A caller that gets `false` reads the vector the way it
2616 /// read it before, with [`Self::signed_at`].
2617 #[must_use]
2618 pub fn signed_block(&self, out: &mut Vec<i64>) -> bool {
2619 out.clear();
2620 match &self.body {
2621 Body::Flat(data) => data.signed_block(self.len, out),
2622 Body::Constant(value) => {
2623 let held = match value.as_ref() {
2624 Value::TinyInt(x) => i64::from(*x),
2625 Value::SmallInt(x) => i64::from(*x),
2626 Value::Integer(x) | Value::Date(x) => i64::from(*x),
2627 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => *x,
2628 _ => return false,
2629 };
2630 out.resize(self.len, held);
2631 true
2632 }
2633 // The same arithmetic [`Self::signed_at`] does on a sequence, once per row rather than
2634 // once per call, and it wraps where that one wraps.
2635 Body::Sequence { start, step } => {
2636 out.extend(
2637 (0..self.len).map(|index| start.wrapping_add(step.wrapping_mul(index as i64))),
2638 );
2639 true
2640 }
2641 Body::Packed { words, width, base, offset } => match i64::try_from(*base) {
2642 Ok(base) => {
2643 out.extend((0..self.len).map(|index| {
2644 base.wrapping_add(code_at(
2645 words,
2646 (*offset + index) * *width as usize,
2647 *width,
2648 ) as i64)
2649 }));
2650 true
2651 }
2652 Err(_) => false,
2653 },
2654 Body::Dictionary { .. }
2655 | Body::Runs { .. }
2656 | Body::Gathered { .. }
2657 | Body::Coded { .. }
2658 | Body::Views { .. }
2659 | Body::ExternalText { .. }
2660 | Body::Nested { .. }
2661 | Body::Fields { .. } => false,
2662 }
2663 }
2664
2665 /// Whether the vector holds no nulls at all, asked once rather than a row at a time.
2666 ///
2667 /// The bulk form of [`Self::is_null_at`], and it answers the same question that one does, so a
2668 /// dictionary and a run are read through to the values behind them where those two keep their
2669 /// nulls. A dictionary that holds a null no code points at answers `false` here and `false` at
2670 /// every row, which is the safe direction and is the only place the two can differ.
2671 ///
2672 /// A caller that gets `false` goes back to asking a row at a time.
2673 #[must_use]
2674 pub fn none_null(&self) -> bool {
2675 if self.validity.has_nulls(self.len) {
2676 return false;
2677 }
2678 match &self.body {
2679 Body::Dictionary { values, .. } | Body::Runs { values, .. } => values.none_null(),
2680 Body::Gathered { source, rids, offset } => {
2681 source.none_null()
2682 && !rids[*offset..].iter().take(self.len).any(|&rid| rid == NO_ROW)
2683 }
2684 _ => true,
2685 }
2686 }
2687
2688 /// Every value in order, as single values.
2689 pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
2690 (0..self.len).map(|index| self.value_at(index))
2691 }
2692
2693 /// This vector with its payload held as a page, so that copying or cutting it is free.
2694 ///
2695 /// For a producer that means to hand the same values out many times, which is what a stored
2696 /// column is. A flat body, a dictionary and a string body are the forms this changes, because
2697 /// each owns a run a copy would have to copy: the values of a flat body, the codes of a
2698 /// dictionary and the arena of a string body. The rest come back as they were, because a packed
2699 /// body shares its words, an FSST body shares its codes and its table, and a constant and a
2700 /// sequence have nothing to share.
2701 ///
2702 /// The string body is the one worth spelling out, because an `Arc` around the arena looks like
2703 /// sharing and is not the sharing that matters. Every reader that wants a run of an arena
2704 /// without copying the bytes asks [`Buffer::is_shared`], which is a question about the store
2705 /// inside the `Arc` and not about the `Arc`: an owned store clones by copying every byte and a
2706 /// page clones by taking a handle. So an arena that was built rather than read stays a thing
2707 /// each reader copies out of until somebody calls this, however many `Arc`s point at it. The
2708 /// reader this is for is [`Self::gather`] over a parent column, which without it copies the
2709 /// bytes of every gathered string once per chunk.
2710 ///
2711 /// Only when the arena is this vector's alone, which is the case a producer that has just built
2712 /// one is in. An arena with another holder is left as it is, because turning it into a page
2713 /// behind their back would mean copying it, which is the cost this exists to avoid.
2714 ///
2715 /// Not recursive into a nested column's children, because a `LIST` or a `STRUCT` holds its
2716 /// children behind an `Arc` already.
2717 #[must_use]
2718 pub fn into_pages(self) -> Self {
2719 let body = match self.body {
2720 Body::Flat(data) => Body::Flat(data.into_pages()),
2721 Body::Dictionary { codes, values, stable } => {
2722 Body::Dictionary { codes: codes.into_page(), values, stable }
2723 }
2724 Body::Views { views, arena } => Body::Views { views, arena: paged(arena) },
2725 other => other,
2726 };
2727 Self { body, ..self }
2728 }
2729
2730 /// A contiguous run of the values, in the form they are already in.
2731 ///
2732 /// This is the cut [`Self::gather`] cannot do. A gather walks a dictionary to its leaf and
2733 /// copies, so gathering a piece of a dictionary encoded column hands back a flat one, and a
2734 /// caller that only wanted the first thousand rows of a page has silently paid for a copy and
2735 /// thrown the dictionary away. A group by over a dictionary encoded column is the case that
2736 /// cares, and it is most of ClickBench.
2737 ///
2738 /// So each form is cut as itself. A dictionary keeps its dictionary and slices its codes, a
2739 /// sequence stays arithmetic with its start moved along, a constant stays a shorter constant,
2740 /// and a flat body is a window into its page when it has one and a copy of its range when it
2741 /// does not, which [`Self::into_pages`] is how a producer decides.
2742 ///
2743 /// The dictionary itself is shared rather than copied, so a cut is the codes and nothing else.
2744 /// It used to be copied, and on a read of a ClickBench partition that copy was ten percent of
2745 /// the cycles: a page holds one dictionary and is cut into chunk sized pieces, so the whole
2746 /// dictionary was copied once per chunk to be read the same way each time.
2747 ///
2748 /// # Errors
2749 ///
2750 /// If the range runs past the end of the vector, or if the type has no flat layout and the
2751 /// body is one that has to be copied.
2752 pub fn slice(&self, at: usize, len: usize) -> Result<Self> {
2753 let end = at.checked_add(len).ok_or_else(|| Error::internal("a slice that wraps"))?;
2754 if end > self.len {
2755 return Err(Error::internal(format!("rows {at} to {end} of a vector of {}", self.len)));
2756 }
2757 if at == 0 && len == self.len {
2758 return Ok(self.clone());
2759 }
2760 let validity = self.validity.slice(at, len);
2761 let body = match &self.body {
2762 Body::Constant(value) => Body::Constant(value.clone()),
2763 Body::Sequence { start, step } => {
2764 Body::Sequence { start: start + step * at as i64, step: *step }
2765 }
2766 Body::Dictionary { codes, values, stable } => Body::Dictionary {
2767 codes: codes.slice(at, len),
2768 values: Arc::clone(values),
2769 stable: *stable,
2770 },
2771 // The same cut [`Body::Packed`] below takes and for the same reason, and here it is free
2772 // rather than merely cheap: a link join fills one buffer of parent rows per child chunk
2773 // and the pipeline cuts it, so moving the starting row is what keeps the ids from being
2774 // copied once per cut. Both ends of the gather stay shared, the ids and the source.
2775 Body::Gathered { source, rids, offset } => Body::Gathered {
2776 source: Arc::clone(source),
2777 rids: Arc::clone(rids),
2778 offset: offset + at,
2779 },
2780 // The bits are not byte aligned, so a cut either repacks them or moves the row the
2781 // reading starts at. Moving it is one addition and repacking is a pass, and a page is
2782 // cut into chunk sized pieces often enough that the difference is the form.
2783 Body::Packed { words, width, base, offset } => Body::Packed {
2784 words: Arc::clone(words),
2785 width: *width,
2786 base: *base,
2787 offset: offset + at,
2788 },
2789 // The cut a flat string column cannot do. Sixteen bytes a row move and the payload stays
2790 // where the page put it, so taking a chunk out of a column of long strings costs the
2791 // same as taking one out of a column of integers. A flat varchar body copies every byte
2792 // of every long string in the range instead, which is the measurement written down in
2793 // `Chunk::compact`: compaction loses on a varchar column, and this is the half of the
2794 // reason that is about cutting rather than about selecting.
2795 Body::Views { views, arena } => {
2796 Body::Views { views: views[at..end].to_vec(), arena: Arc::clone(arena) }
2797 }
2798 // The spans are absolute positions in the shared codes, so a cut is a run of them and
2799 // nothing has to be rebased. One page of compressed strings, one table, and as many
2800 // chunks over it as the reader wants.
2801 Body::Coded { codes, spans, table } => Body::Coded {
2802 codes: Arc::clone(codes),
2803 spans: spans[at..end].to_vec(),
2804 table: Arc::clone(table),
2805 },
2806 // Only the runs the range touches survive, the first and last of them cut back to where
2807 // the range starts and stops, and every end moved to be relative to the new row zero. A
2808 // cut of a hundred rows out of a column of a hundred million is a handful of runs, which
2809 // is the reason this form is worth cutting as itself rather than copying out.
2810 Body::Runs { ends, values } if len > 0 => {
2811 let first = run_holding(ends, at).unwrap_or(0);
2812 let last = run_holding(ends, end - 1).unwrap_or(first);
2813 let cut: Vec<u32> = ends[first..=last]
2814 .iter()
2815 .map(|&stop| stop.min(end as u32) - at as u32)
2816 .collect();
2817 let values = values.slice(first, last - first + 1)?;
2818 Body::Runs { ends: cut, values: Arc::new(values) }
2819 }
2820 // An empty cut has no run to point at and an empty run length body would be a vector of
2821 // no runs claiming a length, so it comes back as the empty flat vector instead.
2822 Body::Runs { .. } => return self.gather(&[]),
2823 // The entries are absolute positions in the shared child, so a cut is a run of them and
2824 // nothing has to be rebased, the same as a cut of FSST spans. The elements outside the
2825 // range stay in the child unreferenced, which is the trade this form makes: a chunk cut
2826 // out of a page of lists moves eight bytes a row and copies no elements at all.
2827 Body::Nested { entries, child } => {
2828 Body::Nested { entries: entries[at..end].to_vec(), child: Arc::clone(child) }
2829 }
2830 // Every child cut at the same place, because a struct row is one value per field at the
2831 // same position in each and there is no entry standing between the row and the child to
2832 // rewrite instead. So this is the one nested form whose cut is not free, and what it costs
2833 // is whatever cutting each field costs, which for a field of string views is sixteen bytes
2834 // a row and for a field of packed integers is one addition.
2835 Body::Fields { children } => Body::Fields {
2836 children: children
2837 .iter()
2838 .map(|child| child.slice(at, len).map(Arc::new))
2839 .collect::<Result<Vec<_>>>()?,
2840 },
2841 Body::ExternalText { source } => {
2842 let mut out = StringColumn::with_capacity(len);
2843 for index in at..end {
2844 out.push_bytes(source.bytes_at(index)?.unwrap_or_default());
2845 }
2846 Body::Flat(Data::Varlen(out))
2847 }
2848 // The one form with nowhere to point, so its range is copied out. A run and not a
2849 // gather: this used to build a vector of the positions `at..end` and hand it to
2850 // `gather`, which then built a vector of `usize` from it, a vector of `bool` beside
2851 // that, and read the values back one bounds checked index at a time. That is five
2852 // passes and three allocations to say `memcpy`, and on a scan it was the largest thing
2853 // in the program after the aggregation itself, because every chunk of every column of
2854 // every page comes through here.
2855 Body::Flat(data) => Body::Flat(run_of(data, at, end)),
2856 };
2857 Ok(Self { ty: self.ty.clone(), len, validity, body })
2858 }
2859
2860 /// The same values in flat form.
2861 ///
2862 /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
2863 /// which is exactly why the other forms exist and why nothing on the hot path should call
2864 /// this. It is here for the operators that genuinely cannot do better and for the tests that
2865 /// check the other forms against it.
2866 ///
2867 /// A call that copies counts itself against [`Cause::Flatten`], because a flatten on a hot path
2868 /// is the most expensive thing in this crate and the only way to find one is to have the number.
2869 /// A call on a vector that is already flat does not count, since it neither copies nor gives
2870 /// anything up.
2871 ///
2872 /// # Errors
2873 ///
2874 /// If the type is one there is no vector for yet, which today means `ARRAY` and `UNION`. A `LIST`
2875 /// and a `MAP` flatten to themselves and a `STRUCT` to a struct of flattened fields, since none of
2876 /// the three has a data slice in any form and there is nothing flatter to become.
2877 pub fn flatten(&self) -> Result<Self> {
2878 if let Body::Flat(_) = self.body {
2879 return Ok(self.clone());
2880 }
2881 slow::took(Cause::Flatten);
2882 self.copied((0..self.len).collect(), false)
2883 }
2884
2885 /// The same values in flat form, taking the vector rather than borrowing it.
2886 ///
2887 /// A vector that is already flat comes back as itself, which is the whole reason this exists
2888 /// beside [`Self::flatten`]. Flattening through a borrow has to clone that vector, and a clone
2889 /// of a flat vector that owns its values copies every one of them to produce a vector that is
2890 /// identical to the one it was handed. Anything not already flat goes the same way it does
2891 /// through [`Self::flatten`], since the copy is real work there rather than work for nothing.
2892 ///
2893 /// # Errors
2894 ///
2895 /// The same values flat, for a kernel that has a loop over runs and was handed a form it has
2896 /// no way to index into.
2897 ///
2898 /// This is [`Self::flatten`] without the count against [`Cause::Flatten`], and the difference
2899 /// is who is calling. A flatten is counted because it is usually a shortcut past a loop nobody
2900 /// wrote. This is for the caller that has the loop and whose alternative is a `Value` per row,
2901 /// which costs a good deal more than the copy. ClickBench q40 adds three `SMALLINT` columns out
2902 /// of Parquet, a packed one and runs over the others after the filter, and every `+` went a
2903 /// row at a time.
2904 ///
2905 /// # Errors
2906 ///
2907 /// Whatever the copy raises.
2908 pub fn opened(&self) -> Result<Self> {
2909 if let Body::Flat(_) = self.body {
2910 return Ok(self.clone());
2911 }
2912 self.copied((0..self.len).collect(), false)
2913 }
2914
2915 /// The same as [`Self::flatten`].
2916 pub fn into_flat(self) -> Result<Self> {
2917 if let Body::Flat(_) = self.body {
2918 return Ok(self);
2919 }
2920 // flatten: the caller asked for flat, and the form that is already flat took the branch
2921 // above, so this is the one case where the copy is what was wanted rather than a shortcut
2922 // somebody took instead of reading the column where it lies.
2923 self.flatten()
2924 }
2925
2926 /// The values at the given positions, copied, in a form that does not point back at this vector.
2927 ///
2928 /// This is the copying counterpart to [`Self::dictionary`], and the two are the two halves of
2929 /// the decision `spec/07-execution.md` section 7.1 describes. Which half is right is measured
2930 /// rather than argued, and [`Chunk::compact`](crate::Chunk::compact) is where the measurement
2931 /// is written down.
2932 ///
2933 /// A dictionary chain is walked to its leaf first and the codes composed on the way down, so the
2934 /// copy runs once over the data rather than once per level, and a position that is null at any
2935 /// level comes out null here. The copy is a typed loop per physical layout rather than a `Value`
2936 /// per row, which is the whole point of it and is what [`Self::flatten`] now goes through too.
2937 ///
2938 /// # Errors
2939 ///
2940 /// If the type is one there is no vector for yet, which today means `ARRAY` and `UNION`. A `LIST`
2941 /// and a `MAP` gather by permuting their entries and a `STRUCT` by gathering every field.
2942 pub fn gather(&self, indices: &[u32]) -> Result<Self> {
2943 // Straight off the positions a filter handed over, since a gather of a stable dictionary is
2944 // its codes gathered and nothing else, and widening every position first was a pass and an
2945 // allocation per filtered chunk of `URL` on ClickBench 28.
2946 if let Body::Dictionary { codes, values, stable: true } = &self.body {
2947 return self.stable_gathered(codes, values, indices, |index| index as usize);
2948 }
2949 if let Some(gathered) = self.unpacked_at(indices) {
2950 return Ok(gathered);
2951 }
2952 self.copied(indices.iter().map(|&index| index as usize).collect(), true)
2953 }
2954
2955 /// A gather off a stable dictionary, which is its codes gathered over the same values.
2956 ///
2957 /// Generic over the position type because a filter hands over `u32` positions and a nested
2958 /// gather hands over `usize` ones, and each is read where it lies rather than widened first.
2959 fn stable_gathered<T: Copy>(
2960 &self,
2961 codes: &Buffer<u32>,
2962 values: &Arc<Vector>,
2963 at: &[T],
2964 index: impl Fn(T) -> usize,
2965 ) -> Result<Self> {
2966 let rows = at.len();
2967 // The range is the largest position, because a maximum is a loop the compiler vectorizes
2968 // and a search that can stop early is not.
2969 let inside = at.iter().map(|&at| index(at)).max().is_none_or(|top| top < codes.len());
2970 // The ordinary case, a column with no nulls and a filter's rows all inside it, in one pass
2971 // for the range and one for the gather. Every code taken is one of this vector's codes,
2972 // which were range checked when it was built, so the result is not checked again the way
2973 // a dictionary from outside is. On q1 the two passes this replaces and the check after
2974 // them were a tenth of the instructions of the scan.
2975 if inside && self.never_null() {
2976 return Ok(Self {
2977 ty: values.ty.clone(),
2978 len: rows,
2979 validity: Validity::AllValid,
2980 body: Body::Dictionary {
2981 codes: at.iter().map(|&at| codes[index(at)]).collect(),
2982 values: Arc::clone(values),
2983 stable: true,
2984 },
2985 });
2986 }
2987 // Otherwise the rows past the end and the nulls are found one row at a time. The per row
2988 // question reads through the dictionary to the value it stands for, which is why the case
2989 // above answers it for the whole column at once.
2990 let validity = if self.never_null() && at.iter().all(|&at| index(at) < self.len) {
2991 Validity::AllValid
2992 } else {
2993 Validity::from_iter(rows, |row| {
2994 at.get(row)
2995 .map(|&at| index(at))
2996 .is_some_and(|index| index < self.len && !self.is_null_at(index))
2997 })
2998 };
2999 let gathered: Vec<u32> =
3000 at.iter().map(|&at| codes.get(index(at)).copied().unwrap_or(0)).collect();
3001 // Every code here is one this vector already held, which was checked against the same
3002 // values on the way in, or the zero a row past the end is written as. So the only code that
3003 // can be out of range is that zero over no values at all, and the pass that looks for the
3004 // largest code is not needed to find it. On ClickBench 28 that pass was four percent of the
3005 // query, because every filtered chunk of `URL` came through here.
3006 // Values that are themselves a dictionary are composed through by the constructor, and this
3007 // skips the constructor, so that shape still goes the checked way.
3008 if matches!(values.body, Body::Dictionary { .. }) {
3009 return Ok(
3010 Self::stable_dictionary(gathered, Arc::clone(values))?.with_validity(validity)
3011 );
3012 }
3013 let highest = (values.is_empty() && !gathered.is_empty()).then_some(0);
3014 Ok(Self::stable_dictionary_validated(gathered, Arc::clone(values), highest)?
3015 .with_validity(validity))
3016 }
3017
3018 /// A packed column's rows at `indices`, unpacked in bulk into a flat column.
3019 ///
3020 /// The general copy reads a packed row a code at a time, which is what [`Packed::codes_at`]
3021 /// exists to avoid. `None` for anything but a packed column with no nulls, every index in range
3022 /// and both ends of its range inside an `i64`, which is every packed column of TPC-H.
3023 fn unpacked_at(&self, indices: &[u32]) -> Option<Self> {
3024 let Body::Packed { words, width, base, offset } = &self.body else {
3025 return None;
3026 };
3027 if self.validity.has_nulls(self.len) {
3028 return None;
3029 }
3030 let highest = indices.iter().copied().fold(0, u32::max) as usize;
3031 if !indices.is_empty() && highest >= self.len {
3032 return None;
3033 }
3034 let packed = Packed { words, width: *width, base: *base, offset: *offset };
3035 let low = i64::try_from(packed.base()).ok()?;
3036 i64::try_from(packed.ceiling()).ok()?;
3037 let codes = packed.codes_at(|index| indices[index] as usize, indices.len());
3038 // Every value is between the two ends, which both fit, so the add lands without wrapping
3039 // and the narrowing below keeps every value, since the layout was chosen to hold them.
3040 #[expect(clippy::cast_possible_wrap, reason = "a code is below the span, which fits")]
3041 let value = |code: u64| low.wrapping_add(code as i64);
3042 #[expect(clippy::cast_possible_truncation, reason = "the layout holds every value")]
3043 let data = match self.ty.physical() {
3044 rudb_common::PhysicalType::Int64 => {
3045 Data::Int64(codes.iter().map(|&code| value(code)).collect())
3046 }
3047 rudb_common::PhysicalType::Int32 => {
3048 Data::Int32(codes.iter().map(|&code| value(code) as i32).collect())
3049 }
3050 rudb_common::PhysicalType::Int16 => {
3051 Data::Int16(codes.iter().map(|&code| value(code) as i16).collect())
3052 }
3053 _ => return None,
3054 };
3055 Some(Self {
3056 ty: self.ty.clone(),
3057 len: indices.len(),
3058 validity: Validity::AllValid,
3059 body: Body::Flat(data),
3060 })
3061 }
3062
3063 /// The copy both [`Self::gather`] and [`Self::flatten`] are.
3064 ///
3065 /// `forms_stay` is the one thing the two want differently. A gather of a constant is a shorter
3066 /// constant and copying it out would be a thousand writes of the same value for nothing, and a
3067 /// gather of string views is a shorter run of views over the same arena rather than a copy of
3068 /// the bytes. Flattening promises flat form to a caller that is about to read the data slice, so
3069 /// for that one both of them have to be written out.
3070 fn copied(&self, at: Vec<usize>, forms_stay: bool) -> Result<Self> {
3071 let rows = at.len();
3072 if forms_stay {
3073 if let Body::Dictionary { codes, values, stable: true } = &self.body {
3074 return self.stable_gathered(codes, values, &at, |index| index);
3075 }
3076 }
3077 let (at, leaf) = self.resolve(at);
3078 let live: Vec<bool> = at.iter().map(|&index| index != NOWHERE).collect();
3079 let validity = Validity::from_run(&live);
3080 let body = match &leaf.body {
3081 // The same gather the arm below is, for a type that has no flat layout to be written out
3082 // into. It goes through the nested builders rather than through a run of data, because they
3083 // are the one place that knows a row of a list column is a range of a child and a row of a
3084 // struct column is one position in each of several, and a second copy of that here would
3085 // be a second thing to keep in step with them.
3086 Body::Constant(value)
3087 if matches!(
3088 self.ty,
3089 LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _)
3090 ) =>
3091 {
3092 if forms_stay && matches!(validity, Validity::AllValid) {
3093 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
3094 }
3095 let rows: Vec<Value> = at
3096 .iter()
3097 .map(
3098 |&index| {
3099 if index == NOWHERE { Value::Null } else { value.as_ref().clone() }
3100 },
3101 )
3102 .collect();
3103 return Self::from_values(self.ty.clone(), &rows);
3104 }
3105 // Every position holds the same value, so the only thing the gather can change is the
3106 // length and which positions are null. A gather with no null in it is still a constant.
3107 Body::Constant(value) => {
3108 if forms_stay && matches!(validity, Validity::AllValid) {
3109 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
3110 }
3111 let mut data = empty_data_for(&self.ty)?;
3112 for &index in &at {
3113 push_value(&mut data, if index == NOWHERE { &Value::Null } else { value })?;
3114 }
3115 Body::Flat(data)
3116 }
3117 // A sequence is arithmetic rather than storage, so the gather is the arithmetic done at
3118 // the positions asked for, and a null writes the zero every other layout writes.
3119 Body::Sequence { start, step } => Body::Flat(Data::Int64(
3120 at.iter()
3121 .map(|&index| if index == NOWHERE { 0 } else { start + step * index as i64 })
3122 .collect(),
3123 )),
3124 // A flat body with no values is the untyped null, so every position asked for is null
3125 // whatever was asked for. Going through the copy would build a run of no values and
3126 // call it `rows` long, which is a vector whose length and data disagree.
3127 Body::Flat(Data::Empty) => {
3128 return Ok(Self::constant(self.ty.clone(), Value::Null, rows));
3129 }
3130 Body::Flat(data) => Body::Flat(copy_of(data, &at)),
3131 // The one form whose copy is arithmetic rather than a move of bytes. It goes through a
3132 // typed loop per layout the way the flat copy does, because the alternative is a `Value`
3133 // per row and this is the path a flatten of a scanned column takes.
3134 Body::Packed { words, width, base, offset } => {
3135 Body::Flat(unpack(&self.ty, words, *offset, *width, *base, &at)?)
3136 }
3137 // A gather keeps the form, which is what makes selecting rows out of a string column
3138 // cost sixteen bytes a row instead of the bytes of the strings. The arena it shares is
3139 // the whole arena and not the part the kept rows point at, so a selection that throws
3140 // most of a page away goes on holding the page. That is the trade the form is: a cut and
3141 // a filter are cheap and the memory comes back when the last vector over the page goes,
3142 // and a caller that wants the bytes narrowed asks for a flatten.
3143 Body::Views { views, arena } if forms_stay => Body::Views {
3144 views: at
3145 .iter()
3146 .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
3147 .collect(),
3148 arena: Arc::clone(arena),
3149 },
3150 // Flattening promises a data slice, and a flat string column is views over an arena
3151 // just as this form is, so when the arena is a page the flatten is the views and
3152 // nothing else. The form is given up, which is what was asked for, and not the sharing,
3153 // which nobody asked to have given up: a result set of six million strings used to copy
3154 // every byte of them out of the pages they were already sitting in.
3155 Body::Views { views, arena } if arena.is_shared() => {
3156 Body::Flat(Data::Varlen(StringColumn::from_parts(
3157 at.iter()
3158 .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
3159 .collect(),
3160 (**arena).clone(),
3161 )))
3162 }
3163 // The arena is this vector's own, so there is nothing to share and the bytes are copied
3164 // out into an arena of their own. The total is known before any of it is copied, the
3165 // way the flat copy works it out, so the new arena is one allocation.
3166 Body::Views { views, arena } => {
3167 let mut out = StringColumn::with_capacity(at.len());
3168 out.reserve_bytes(
3169 at.iter()
3170 .filter_map(|&index| views.get(index))
3171 .filter(|view| !view.is_inline())
3172 .map(StringView::len)
3173 .sum(),
3174 );
3175 for &index in &at {
3176 let bytes = views.get(index).and_then(|view| view.bytes_in(arena));
3177 out.push_bytes(bytes.unwrap_or_default());
3178 }
3179 Body::Flat(Data::Varlen(out))
3180 }
3181 Body::ExternalText { source } => {
3182 let mut out = StringColumn::with_capacity(at.len());
3183 for &index in &at {
3184 out.push_bytes(source.bytes_at(index)?.unwrap_or_default());
3185 }
3186 Body::Flat(Data::Varlen(out))
3187 }
3188 // A gather keeps the form, because the codes do not move and a span survives being put
3189 // in an order the codes are not in. A position that resolved to nowhere gets the empty
3190 // span, which decompresses to no bytes, which is the zero every other layout writes.
3191 Body::Coded { codes, spans, table } if forms_stay => Body::Coded {
3192 codes: Arc::clone(codes),
3193 spans: at
3194 .iter()
3195 .map(|&index| spans.get(index).copied().unwrap_or((0, 0)))
3196 .collect(),
3197 table: Arc::clone(table),
3198 },
3199 // Flattening decompresses, which is the price of the data slice it promises. The scratch
3200 // buffer is reused across rows, so this is one allocation for the whole column rather
3201 // than one per row the way reading it a value at a time would be.
3202 Body::Coded { codes, spans, table } => {
3203 let mut out = StringColumn::with_capacity(at.len());
3204 let mut scratch = Vec::new();
3205 for &index in &at {
3206 scratch.clear();
3207 let span = spans
3208 .get(index)
3209 .and_then(|&(from, to)| codes.get(from as usize..to as usize));
3210 if let Some(span) = span {
3211 table.decompress(span, &mut scratch)?;
3212 }
3213 out.push_bytes(&scratch);
3214 }
3215 Body::Flat(Data::Varlen(out))
3216 }
3217 // The entries move and the child does not, which is the same trade the string forms
3218 // make and is why a gather of a list column costs eight bytes a row however long the
3219 // lists are. A position that resolved to nowhere gets a zero length entry, and the mask
3220 // already says it is null, so the entry is never read.
3221 //
3222 // This arm ignores `forms_stay`, unlike every arm above it, because there is nothing
3223 // flatter for a list to become. The other forms are all cheaper ways of writing down a
3224 // column of scalars and flattening gives up the saving to hand back a data slice, and a
3225 // list has no data slice in any form, so a flatten of one is this and a caller reading it
3226 // goes through `list_parts` either way.
3227 Body::Nested { entries, child } => Body::Nested {
3228 entries: at
3229 .iter()
3230 .map(|&index| entries.get(index).copied().unwrap_or((0, 0)))
3231 .collect(),
3232 child: Arc::clone(child),
3233 },
3234 // Every child gathered at the same positions, for the reason the cut cuts every child:
3235 // there are no entries to permute instead, so the permutation happens once per field. The
3236 // positions handed down are the resolved ones, sentinel and all, so a row that resolved to
3237 // nowhere comes back null in each field as well as null here.
3238 //
3239 // `forms_stay` is passed straight through rather than ignored, which is the opposite of
3240 // what the list arm does, and the difference is real. There is nothing flatter for a list
3241 // to become, and a struct is only as flat as its fields are, so a flatten of a struct
3242 // column is a flatten of each field and a caller that asked for data slices gets them.
3243 Body::Fields { children } => Body::Fields {
3244 children: children
3245 .iter()
3246 .map(|child| child.copied(at.clone(), forms_stay).map(Arc::new))
3247 .collect::<Result<Vec<_>>>()?,
3248 },
3249 // Unreachable, because `resolve` walks past every form that points at another vector
3250 // and stops at the first body that does not.
3251 Body::Dictionary { .. } | Body::Runs { .. } | Body::Gathered { .. } => {
3252 return Err(Error::internal(
3253 "a form that points somewhere survived being resolved",
3254 ));
3255 }
3256 };
3257 Ok(Self { ty: self.ty.clone(), len: rows, validity, body })
3258 }
3259
3260 /// Where each wanted position lives in the first body that points nowhere else, and that body.
3261 ///
3262 /// A position that is null anywhere on the way down, or past the end of anything on the way
3263 /// down, comes back as [`NOWHERE`]. That single sentinel is what keeps the copy loop from
3264 /// carrying a validity mask alongside the positions it is already walking.
3265 fn resolve(&self, mut at: Vec<usize>) -> (Vec<usize>, &Self) {
3266 let mut source = self;
3267 loop {
3268 for slot in &mut at {
3269 if *slot >= source.len || !source.validity.is_valid(*slot) {
3270 *slot = NOWHERE;
3271 }
3272 }
3273 source = match &source.body {
3274 Body::Dictionary { codes, values, .. } => {
3275 for slot in &mut at {
3276 *slot = match codes.get(*slot) {
3277 Some(&code) => code as usize,
3278 None => NOWHERE,
3279 };
3280 }
3281 values.as_ref()
3282 }
3283 // A run length body is a dictionary whose code is worked out from the position
3284 // rather than stored, so the walk down is the same walk with a search where the
3285 // lookup was. `NOWHERE` searches for nothing and stays `NOWHERE`.
3286 Body::Runs { ends, values } => {
3287 for slot in &mut at {
3288 *slot = run_holding(ends, *slot).unwrap_or(NOWHERE);
3289 }
3290 values.as_ref()
3291 }
3292 // The same walk the dictionary above takes, with the sentinel folded into the one
3293 // this loop already has. That composition is the whole reason a gather is a body
3294 // rather than an operator: a filter over the output of a link join selects into the
3295 // ids and copies nothing, and a gather off a gather is one walk down to whatever is
3296 // at the bottom rather than two passes over the parent.
3297 Body::Gathered { source: below, rids, offset } => {
3298 for slot in &mut at {
3299 *slot = if *slot == NOWHERE {
3300 NOWHERE
3301 } else {
3302 row_of(rids, *offset, *slot).unwrap_or(NOWHERE)
3303 };
3304 }
3305 below.as_ref()
3306 }
3307 _ => return (at, source),
3308 };
3309 }
3310 }
3311}
3312
3313/// So that a kernel can take its operands as either a list of vectors or a list of references.
3314///
3315/// A caller that built a `Vec<Vector>` and a caller whose operands are already somewhere else, in a
3316/// chunk or in an evaluator's scratch, want the same kernel. Without this the second kind has to
3317/// clone every operand into a `Vec` to satisfy the signature, and a clone of a vector is a copy of
3318/// the whole column, so the type would be charging real memory traffic for nothing.
3319impl AsRef<Vector> for Vector {
3320 fn as_ref(&self) -> &Vector {
3321 self
3322 }
3323}
3324
3325/// The bits of a packed vector and what they mean, for a kernel that wants to stay in code space.
3326///
3327/// Borrowed from the vector rather than owning anything, so getting one costs nothing and a kernel
3328/// that finds it cannot use them has given up nothing by asking.
3329#[derive(Debug, Clone, Copy)]
3330pub struct Packed<'a> {
3331 words: &'a [u64],
3332 width: u32,
3333 base: i128,
3334 offset: usize,
3335}
3336
3337impl Packed<'_> {
3338 /// Packed words. A persisted vector also records [`Self::offset`].
3339 #[must_use]
3340 pub fn words(&self) -> &[u64] {
3341 self.words
3342 }
3343
3344 /// Bit offset, in rows, of the first value.
3345 #[must_use]
3346 pub fn offset(&self) -> usize {
3347 self.offset
3348 }
3349
3350 /// How many bits one code takes, between one and [`PACKED_WIDTH_MAX`].
3351 #[must_use]
3352 pub fn width(&self) -> u32 {
3353 self.width
3354 }
3355
3356 /// What zero means, so that the value of a row is the base plus its code.
3357 #[must_use]
3358 pub fn base(&self) -> i128 {
3359 self.base
3360 }
3361
3362 /// The largest value this vector can be holding, whatever it is actually holding.
3363 ///
3364 /// With [`Self::base`] this is the pair a comparison kernel wants first. A literal outside the
3365 /// two answers every row of the vector the same way, which is a whole chunk decided without a
3366 /// bit being read, and that is the case a zone map would have caught if there were one here.
3367 #[must_use]
3368 pub fn ceiling(&self) -> i128 {
3369 self.base + i128::from(u64::MAX >> (u64::BITS - self.width))
3370 }
3371
3372 /// The code of row `row`, which is its value minus [`Self::base`].
3373 ///
3374 /// Out of range rows read as zero rather than panicking, the way every other accessor in this
3375 /// file answers for a row that is not there.
3376 ///
3377 /// Marked inline because every caller that matters is a kernel in another crate reading one code
3378 /// per row, and thin LTO was leaving it as a call there. On TPC-H SF1 that call was 1.5 percent of
3379 /// the suite and a tenth of q12.
3380 #[must_use]
3381 #[inline]
3382 pub fn code(&self, row: usize) -> u64 {
3383 code_at(self.words, (self.offset + row) * self.width as usize, self.width)
3384 }
3385
3386 /// Which code a value would have, and `None` for a value this vector cannot be holding.
3387 ///
3388 /// The translation a comparison does once per vector so that it does not have to unpack once per
3389 /// row. `None` is the useful answer rather than a failure: it says the literal is outside the
3390 /// packed range, so every row compares against it the same way.
3391 #[must_use]
3392 pub fn code_of(&self, value: i128) -> Option<u64> {
3393 u64::try_from(value.checked_sub(self.base)?).ok().filter(|&code| code <= self.mask())
3394 }
3395
3396 /// The largest code the width allows.
3397 fn mask(&self) -> u64 {
3398 u64::MAX >> (u64::BITS - self.width)
3399 }
3400
3401 /// The codes of rows `from` to `from + out.len()`, in one pass over the words.
3402 ///
3403 /// [`Self::code`] is a code at a time, and every one of them works out which word it is in, reads
3404 /// it through a bound, and asks whether it straddles into the next. Sixty four codes of one
3405 /// width fill exactly that many words and the straddles fall in the same places every time, so a
3406 /// block of them is unpacked by a loop the width is a constant in, where every shift and every
3407 /// straddle is known before it runs. On TPC-H q1 the code at a time reads were a third of the
3408 /// instructions the query ran. The rows before the first whole block and after the last one
3409 /// still go a code at a time.
3410 pub fn unpack(&self, from: usize, out: &mut [u64]) {
3411 let width = self.width as usize;
3412 let start = self.offset + from;
3413 let end = start + out.len();
3414 let first = start.next_multiple_of(64).min(end);
3415 let mut at = 0;
3416 for row in start..first {
3417 out[at] = code_at(self.words, row * width, self.width);
3418 at += 1;
3419 }
3420 let mut row = first;
3421 while row + 64 <= end {
3422 let word = row / 64 * width;
3423 let Some(words) = self.words.get(word..word + width) else { break };
3424 let Some(Ok(block)) = out.get_mut(at..at + 64).map(<&mut [u64; 64]>::try_from) else {
3425 break;
3426 };
3427 unpack_block(words, self.width, block);
3428 row += 64;
3429 at += 64;
3430 }
3431 for row in row..end {
3432 out[at] = code_at(self.words, row * width, self.width);
3433 at += 1;
3434 }
3435 }
3436
3437 /// The code of each of `rows` rows `at` names, in order.
3438 ///
3439 /// A filter's selection names rows close together and in order, so the span they cover is
3440 /// unpacked whole with [`Self::unpack`] and each row read out of it. Rows spread too far apart
3441 /// for that to pay are read a code at a time.
3442 ///
3443 /// Unpacking a block at a time into a buffer on the stack, and reading each row out of the
3444 /// block it falls in, keeps less in the cache and was tried. The question of which block a row
3445 /// is in, asked for every row, cost more than the misses it saved, 40.2 G instructions for ten
3446 /// runs of q1 against 34.1 G this way.
3447 pub fn codes_at<M: Fn(usize) -> usize>(&self, at: M, rows: usize) -> Vec<u64> {
3448 let (mut low, mut high) = (usize::MAX, 0);
3449 for index in 0..rows {
3450 let row = at(index);
3451 low = low.min(row);
3452 high = high.max(row);
3453 }
3454 if rows == 0 || high - low >= rows.saturating_mul(4) {
3455 return (0..rows).map(|index| self.code(at(index))).collect();
3456 }
3457 let mut run = vec![0; high - low + 1];
3458 self.unpack(low, &mut run);
3459 (0..rows).map(|index| run[at(index) - low]).collect()
3460 }
3461}
3462
3463/// Sixty four codes of `width` bits out of the `width` words that hold them, with the width made a
3464/// constant so that the loop in [`unpack_width`] has nothing left to work out as it goes.
3465fn unpack_block(words: &[u64], width: u32, out: &mut [u64; 64]) {
3466 macro_rules! widths {
3467 ($($width:literal)*) => {
3468 match width {
3469 $($width => unpack_width::<$width>(words, out),)*
3470 _ => {
3471 for (at, code) in out.iter_mut().enumerate() {
3472 *code = code_at(words, at * width as usize, width);
3473 }
3474 }
3475 }
3476 };
3477 }
3478 widths!(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
3479 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63);
3480}
3481
3482#[inline(always)]
3483fn unpack_width<const WIDTH: usize>(words: &[u64], out: &mut [u64; 64]) {
3484 let Ok(words) = <&[u64; WIDTH]>::try_from(&words[..WIDTH]) else { return };
3485 // Written out sixty four times rather than as a loop, because the compiler kept the loop and
3486 // with it a shift and a branch on the straddle for every code. Spelled out, the row is a
3487 // constant in each step, so its word, its shift and whether it straddles are all worked out
3488 // before the program runs and a code is a shift, an or where it straddles and a mask.
3489 macro_rules! steps {
3490 ($($at:literal)*) => {
3491 $(unpack_step::<WIDTH, $at>(words, out);)*
3492 };
3493 }
3494 steps!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
3495 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63);
3496}
3497
3498#[inline(always)]
3499fn unpack_step<const WIDTH: usize, const AT: usize>(words: &[u64; WIDTH], out: &mut [u64; 64]) {
3500 let bit = AT * WIDTH;
3501 let word = bit / 64;
3502 let shift = bit % 64;
3503 let mut value = words[word] >> shift;
3504 if shift + WIDTH > 64 {
3505 value |= words[word + 1] << (64 - shift);
3506 }
3507 out[AT] = value & (u64::MAX >> (64 - WIDTH));
3508}
3509
3510/// The widest a packed code is allowed to be.
3511///
3512/// Sixty three rather than sixty four so that a mask is `u64::MAX >> (64 - width)` with no shift of
3513/// a whole word in it, and reading a code is one branch on whether it straddles rather than two. A
3514/// sixty four bit code saves nothing anyway, since it is the layout it came from.
3515pub const PACKED_WIDTH_MAX: u32 = 63;
3516
3517/// How much smaller packing has to be before it is worth the shift and the mask on every read.
3518///
3519/// Two, so a column packs when the bits come to half the flat size or less. A column that would save
3520/// a tenth stays flat, because a tenth of a column is not worth turning every read of it into
3521/// arithmetic, and the whole argument for the form is that a narrow column saves most of itself.
3522pub const PACKING_PAYS_AT: usize = 2;
3523
3524/// How much smaller compressing has to be before it is worth a decompression on every read.
3525///
3526/// Two, the same rule packing follows and for the same reason. FSST gets about that on text, so a
3527/// column of English or of URLs compresses and a column of short codes or of random bytes does not,
3528/// which is the right answer for both.
3529pub const FSST_PAYS_AT: usize = 2;
3530
3531/// The codes of a compressed column and the table they are against.
3532///
3533/// Handed out by [`Vector::coded_parts`] so a kernel can work in code space. Nothing here
3534/// decompresses, which is the point: [`Self::encode`] puts the literal into the same space the rows
3535/// are already in, and after that an equality test is a byte slice comparison.
3536#[derive(Debug, Clone, Copy)]
3537pub struct Coded<'a> {
3538 codes: &'a [u8],
3539 spans: &'a [(u32, u32)],
3540 table: &'a SymbolTable,
3541}
3542
3543impl Coded<'_> {
3544 /// The table every row in this vector is compressed against.
3545 #[must_use]
3546 pub fn table(&self) -> &SymbolTable {
3547 self.table
3548 }
3549
3550 /// The code bytes of one row, still compressed.
3551 #[must_use]
3552 pub fn row(&self, row: usize) -> Option<&[u8]> {
3553 let &(from, to) = self.spans.get(row)?;
3554 self.codes.get(from as usize..to as usize)
3555 }
3556
3557 /// Some bytes in the code space this vector is in.
3558 ///
3559 /// The literal side of an equality filter. Compressing is a function of the table and the bytes,
3560 /// so two strings compress to the same codes exactly when they are the same string, and an
3561 /// equality test on the codes is an equality test on the strings with no decompression in it.
3562 #[must_use]
3563 pub fn encode(&self, bytes: &[u8]) -> Vec<u8> {
3564 let mut out = Vec::with_capacity(bytes.len());
3565 self.table.compress(bytes, &mut out);
3566 out
3567 }
3568}
3569
3570/// The first `len` of a run of some narrower signed width, sign extended into `out`.
3571///
3572/// Written once and called from the three narrow arms of [`Data::signed_block`], so that the sign
3573/// extension is one loop the compiler can widen rather than three written out by hand.
3574fn widen<T: Copy + Into<i64>>(run: &[T], len: usize, out: &mut Vec<i64>) -> bool {
3575 match run.get(..len) {
3576 Some(run) => {
3577 out.extend(run.iter().map(|&x| x.into()));
3578 true
3579 }
3580 None => false,
3581 }
3582}
3583
3584/// One holder's share of a part that several vectors are reading at the same time.
3585///
3586/// The rule [`Buffer::footprint`] already uses for a shared page. Everything holding the part asks
3587/// this, so what they say between them comes to about what the part costs rather than to the part
3588/// times the number of them, and the answer is never zero for a part that costs anything, because a
3589/// caller with a reference is at least one holder.
3590fn share<T: ?Sized>(bytes: usize, held: &Arc<T>) -> usize {
3591 bytes / Arc::strong_count(held).max(1)
3592}
3593
3594/// How many words hold `len` codes of `width` bits.
3595fn words_for(len: usize, width: u32) -> usize {
3596 (len * width as usize).div_ceil(u64::BITS as usize)
3597}
3598
3599/// The lowest and highest value a type's layout can hold, and `None` for a type with no integer one.
3600///
3601/// This is also the test of whether a type can be packed at all, and it is the only one, so the
3602/// layouts listed here and the layouts [`pack`] and [`unpack`] know how to walk are the same list
3603/// from the same macro and cannot drift apart.
3604fn layout_range(ty: &LogicalType) -> Option<(i128, i128)> {
3605 use rudb_common::PhysicalType as P;
3606 macro_rules! ranges {
3607 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3608 match ty.physical() {
3609 $(P::$variant => Some((i128::from(<$native>::MIN), i128::from(<$native>::MAX))),)+
3610 _ => None,
3611 }
3612 };
3613 }
3614 crate::for_each_layout!(exact, ranges)
3615}
3616
3617/// The bytes the first `len` slots of a run take laid flat, whether the run is owned or a window.
3618fn flat_bytes(data: &Data, len: usize) -> usize {
3619 macro_rules! widths {
3620 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3621 match data {
3622 Data::Empty => 0,
3623 $(Data::$variant(_) => len * size_of::<$native>(),)+
3624 }
3625 };
3626 }
3627 crate::for_each_layout!(all, widths)
3628}
3629
3630/// What to subtract before packing, so that the whole code range lands inside the column's type.
3631///
3632/// The smallest value in the column is the obvious base and it is the wrong one near the top of a
3633/// type. [`Vector::packed`] checks the two ends of what the codes could say rather than the values
3634/// that are actually there, which is one check instead of one per row and is what makes reading a
3635/// packed column cheap. An `INTEGER` column of a thousand values just under `i32::MAX` needs ten
3636/// bits, and based at its own smallest value those ten bits could say a number an `INTEGER` cannot
3637/// hold, so the column was refused and the table would not write at all.
3638///
3639/// The base does not have to be the smallest value. Any base works where every code is still
3640/// non-negative and the widest code the width allows still fits the type, which is `base <= low`,
3641/// `high - base <= 2^width - 1`, `type low <= base` and `base + 2^width - 1 <= type high` together.
3642///
3643/// The largest base meeting all four is the one below, and it exists whenever the values fit the
3644/// type at all: `high - (2^width - 1) <= low` because that is how the width was chosen, and
3645/// `type low <= type high - (2^width - 1)` because a width wider than the type's own span is
3646/// already refused. `None` is for a type with no integer layout, which cannot be packed anyway.
3647fn packing_base(ty: &LogicalType, low: i128, high: i128, width: u32) -> Option<i128> {
3648 let (floor, ceiling) = layout_range(ty)?;
3649 let span = i128::from(u64::MAX >> (64 - width));
3650 let base = low.min(ceiling - span);
3651 (base >= floor && base >= high - span).then_some(base)
3652}
3653
3654/// The lowest and highest value in the first `len` slots of a run of integer data.
3655///
3656/// `None` for data that is not integers, which is what says a column cannot be packed. The null
3657/// slots are in the span, holding whatever zero was written into them, which
3658/// [`Vector::bit_packed`] says more about.
3659fn span_of(data: &Data, len: usize) -> Option<(i128, i128)> {
3660 macro_rules! spans {
3661 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3662 match data {
3663 $(Data::$variant(values) => {
3664 let mut low = i128::MAX;
3665 let mut high = i128::MIN;
3666 for &value in values.as_slice().iter().take(len) {
3667 let value = i128::from(value);
3668 low = low.min(value);
3669 high = high.max(value);
3670 }
3671 (low <= high).then_some((low, high))
3672 })+
3673 _ => None,
3674 }
3675 };
3676 }
3677 crate::for_each_layout!(exact, spans)
3678}
3679
3680/// The first `len` values of a run of integer data, written out as codes of `width` bits from `base`.
3681fn pack(data: &Data, len: usize, base: i128, width: u32) -> Vec<u64> {
3682 let mut words = vec![0u64; words_for(len, width)];
3683 macro_rules! packing {
3684 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3685 match data {
3686 $(Data::$variant(values) => {
3687 for (row, &value) in values.as_slice().iter().take(len).enumerate() {
3688 // In range because `base` and `width` came from the span of this same run.
3689 let code = u64::try_from(i128::from(value) - base).unwrap_or(0);
3690 write_code(&mut words, row * width as usize, width, code);
3691 }
3692 })+
3693 _ => {}
3694 }
3695 };
3696 }
3697 crate::for_each_layout!(exact, packing);
3698 words
3699}
3700
3701/// The codes at the given rows, unpacked into the flat layout the type calls for.
3702///
3703/// A row of [`NOWHERE`] writes the layout's zero, which is the rule [`copy_of`] follows for the same
3704/// reason: every layout here is a parallel array to a validity mask, so a null takes a slot.
3705///
3706/// # Errors
3707///
3708/// If the type has no flat layout, which a packed vector cannot have and which is checked when one
3709/// is built, so an error here is a bug rather than a caller mistake.
3710fn unpack(
3711 ty: &LogicalType,
3712 words: &[u64],
3713 offset: usize,
3714 width: u32,
3715 base: i128,
3716 at: &[usize],
3717) -> Result<Data> {
3718 let mut out = empty_data_for(ty)?;
3719 let value_of = |row: usize| {
3720 if row == NOWHERE {
3721 return None;
3722 }
3723 Some(base + i128::from(code_at(words, (offset + row) * width as usize, width)))
3724 };
3725 macro_rules! unpacking {
3726 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3727 match &mut out {
3728 $(Data::$variant(values) => {
3729 values.reserve(at.len());
3730 for &row in at {
3731 // In range because both ends of it were checked when the vector was built.
3732 let value = value_of(row)
3733 .and_then(|value| <$native>::try_from(value).ok())
3734 .unwrap_or($zero);
3735 values.push(value);
3736 }
3737 })+
3738 _ => {
3739 return Err(Error::internal(format!(
3740 "a {ty} vector was packed, which no integer layout allows"
3741 )));
3742 }
3743 }
3744 };
3745 }
3746 crate::for_each_layout!(exact, unpacking);
3747 Ok(out)
3748}
3749
3750/// The `width` bits starting at `bit`, low end first.
3751///
3752/// Zero for bits past the end of the words, which keeps a read of a row that is not there from
3753/// panicking and matches what every other accessor here does with one.
3754#[inline]
3755fn code_at(words: &[u64], bit: usize, width: u32) -> u64 {
3756 let word = bit / u64::BITS as usize;
3757 let shift = (bit % u64::BITS as usize) as u32;
3758 let mask = u64::MAX >> (u64::BITS - width);
3759 let low = words.get(word).copied().unwrap_or(0) >> shift;
3760 let taken = u64::BITS - shift;
3761 if taken >= width {
3762 return low & mask;
3763 }
3764 // The code straddles two words, and `taken` is under the width here so it is under sixty four,
3765 // which is what makes the shift below one the hardware will do rather than one it refuses.
3766 let high = words.get(word + 1).copied().unwrap_or(0) << taken;
3767 (low | high) & mask
3768}
3769
3770/// Writes `width` bits of `code` starting at `bit`, over words that started out zero.
3771fn write_code(words: &mut [u64], bit: usize, width: u32, code: u64) {
3772 let word = bit / u64::BITS as usize;
3773 let shift = (bit % u64::BITS as usize) as u32;
3774 words[word] |= code << shift;
3775 let taken = u64::BITS - shift;
3776 if taken < width {
3777 words[word + 1] |= code >> taken;
3778 }
3779}
3780
3781/// One level of dictionary out of however many levels were handed to [`Vector::dictionary`].
3782///
3783/// Every dictionary in the system is built through that constructor and every one of them comes
3784/// through here first, so the invariant this maintains is that the vector a dictionary points at is
3785/// never itself a dictionary that could have been composed away. That makes the work a single `if`
3786/// rather than a loop: the inner vector was already composed when it was built, so composing the
3787/// outer codes through it leaves the result no deeper than the inner vector already was.
3788///
3789/// The codes are indexed rather than fetched with `get`, because the caller has already walked the
3790/// whole outer array to check that every code is in range and the inner array is exactly as long as
3791/// the vector those codes were checked against.
3792fn compose(codes: Vec<u32>, values: Arc<Vector>) -> (Vec<u32>, Arc<Vector>) {
3793 // A dictionary carrying a validity of its own is one whose nulls live at this level rather than
3794 // in the values, which is the one thing composition cannot carry down with it.
3795 if !matches!(values.validity, Validity::AllValid) {
3796 return (codes, values);
3797 }
3798 let Body::Dictionary { codes: inner, values: leaf, .. } = &values.body else {
3799 return (codes, values);
3800 };
3801 debug_assert!(
3802 !matches!(leaf.body, Body::Dictionary { .. })
3803 || !matches!(leaf.validity, Validity::AllValid),
3804 "a dictionary was stacked on a dictionary without going through the constructor"
3805 );
3806 // The leaf is handed on as the handle it already is. Nothing here reads it and nothing here
3807 // changes it, so the composed dictionary points at the same values the stacked one did and
3808 // whoever else is holding them keeps holding them. This used to take them out of the `Arc`,
3809 // which copied the whole leaf whenever anybody else was still reading it, and a scan selecting
3810 // rows out of a chunk whose column came from a shared page dictionary is exactly that: the page
3811 // holds the leaf, every chunk cut from the page composes through it, and every one of those
3812 // cuts copied the page's dictionary. TPC-H q21 does it once per thousand rows of `lineitem`.
3813 let composed = codes.iter().map(|&code| inner[code as usize]).collect();
3814 (composed, Arc::clone(leaf))
3815}
3816
3817/// How many rows a run has to cover on average before run length encoding is smaller.
3818///
3819/// A run costs its value plus the four bytes of its end, so on a four byte column a run of two rows
3820/// breaks even and a run of three wins. Wider columns win sooner and narrower ones later, and this
3821/// is the one ratio for all of them because a threshold per width is a table that has to be right
3822/// nine times rather than once. It is a constant with a name so that the sweep that eventually moves
3823/// it has something to move.
3824const RUNS_PAY_AT: usize = 2;
3825
3826/// A string body's arena as a page, when this is the only holder of it.
3827///
3828/// The move out of the `Arc` and back into one is what makes this free: [`Buffer::into_page`] takes
3829/// the run by value and puts it behind an `Arc` without touching a byte of it, so the whole of this
3830/// is two allocations of a pointer's worth each however large the arena is.
3831///
3832/// An arena somebody else is holding comes back untouched. Paging it would mean copying it, since
3833/// the other holder's view of it has to go on meaning what it meant, and a copy is what the caller
3834/// asked to avoid.
3835fn paged(arena: Arc<Buffer<u8>>) -> Arc<Buffer<u8>> {
3836 if arena.is_shared() {
3837 return arena;
3838 }
3839 match Arc::try_unwrap(arena) {
3840 Ok(owned) => Arc::new(owned.into_page()),
3841 Err(held) => held,
3842 }
3843}
3844
3845/// Which run holds `row`, given ends that are exclusive and increasing.
3846///
3847/// A binary search rather than a scan, because the callers that ask this are the ones that are not
3848/// walking the runs in order: a single value read out of a result set, or a gather at scattered
3849/// positions. Anything walking in order should be reading [`Vector::run_parts`] instead, which is
3850/// what the form is for.
3851fn run_holding(ends: &[u32], row: usize) -> Option<usize> {
3852 let row = u32::try_from(row).ok()?;
3853 let run = match ends.binary_search(&row) {
3854 // The ends are exclusive, so landing exactly on one means the row is the first of the next.
3855 Ok(at) => at + 1,
3856 Err(at) => at,
3857 };
3858 (run < ends.len()).then_some(run)
3859}
3860
3861/// The row each run ends at, for a flat body read alongside the validity that goes with it.
3862///
3863/// Two adjacent nulls are one run, because a reader of either gets a null and cannot tell them
3864/// apart. A null between two equal values is three runs for the same reason, since the null is a
3865/// value of the column as far as anything reading it is concerned.
3866///
3867/// The comparison is per layout rather than per `Value`, which is the whole reason this is a macro.
3868/// A `Value` a row would allocate a string per row on a `VARCHAR` column and would be the exact
3869/// defect `cargo xtask rowloop` exists to fail the build on.
3870fn boundaries(data: &Data, validity: &Validity, len: usize) -> Vec<u32> {
3871 if len == 0 {
3872 return Vec::new();
3873 }
3874 let breaks = |ends: &mut Vec<u32>, mut differs: Box<dyn FnMut(usize, usize) -> bool + '_>| {
3875 for row in 1..len {
3876 let same = match (validity.is_valid(row), validity.is_valid(row - 1)) {
3877 (false, false) => true,
3878 (true, true) => !differs(row, row - 1),
3879 _ => false,
3880 };
3881 if !same {
3882 ends.push(u32::try_from(row).unwrap_or(u32::MAX));
3883 }
3884 }
3885 ends.push(u32::try_from(len).unwrap_or(u32::MAX));
3886 };
3887 let mut ends = Vec::new();
3888 macro_rules! walked {
3889 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3890 match data {
3891 // No values at all, so every row is the same null and the column is one run.
3892 Data::Empty => ends.push(u32::try_from(len).unwrap_or(u32::MAX)),
3893 $(Data::$variant(values) => {
3894 breaks(&mut ends, Box::new(|a, b| values.get(a) != values.get(b)));
3895 })+
3896 Data::Varlen(values) => {
3897 breaks(&mut ends, Box::new(|a, b| values.bytes(a) != values.bytes(b)));
3898 }
3899 }
3900 };
3901 }
3902 crate::for_each_layout!(fixed, walked);
3903 ends
3904}
3905
3906/// The position of a value that is not anywhere, because it is null or out of range.
3907///
3908/// `usize::MAX` rather than an `Option<usize>`, because the copy loop's bounds check rejects it for
3909/// free and an `Option` would put a second branch next to the one already there.
3910pub(crate) const NOWHERE: usize = usize::MAX;
3911
3912/// The row id of a row that is not in the source, which reads as null.
3913///
3914/// Public because whoever builds a [`Form::Gathered`] vector has to write it, and it is `u32::MAX`
3915/// for the reason the crate's own offset sentinel is `usize::MAX`: a bounds check the reader is
3916/// doing anyway rejects it, where an `Option<u32>` would be eight bytes a row instead of four and a
3917/// second branch beside the one already there. It costs the last row of a four billion row source,
3918/// which is a source no column in this engine has.
3919pub const NO_ROW: u32 = u32::MAX;
3920
3921/// Which source row a gathered row names, and `None` when it names none.
3922///
3923/// The `Option` is what every reader of [`Body::Gathered`] that returns an `Option` wants, so the
3924/// three cases that are all *there is nothing here*, past the end of the ids, the sentinel, and an
3925/// id that does not fit a `usize`, are collapsed once here rather than three times each.
3926fn row_of(rids: &[u32], offset: usize, index: usize) -> Option<usize> {
3927 match rids.get(offset + index) {
3928 Some(&NO_ROW) | None => None,
3929 Some(&rid) => Some(rid as usize),
3930 }
3931}
3932
3933/// A run of data copied at the given positions, with a zero wherever the position is [`NOWHERE`].
3934///
3935/// A zero and not a skip, because every layout here is a parallel array to a validity mask and a
3936/// short one would put every value after the first null at the wrong index. It is the same rule
3937/// [`push_value`] follows for a null.
3938/// A contiguous run of a flat body, copied out.
3939///
3940/// The counterpart to [`copy_of`] for the one case that is a range rather than a set of positions,
3941/// which is what [`Vector::slice`] asks for. Every fixed width layout is one `memcpy` and the
3942/// string layout is a run of views and their bytes, where `copy_of` is a bounds checked index and a
3943/// null test per row.
3944///
3945/// The caller has already checked that `end` is inside the vector, and a body whose data is shorter
3946/// than its vector claims is a bug elsewhere, so a short run is clamped rather than reported.
3947///
3948/// A fixed width run over a buffer that is a window into a page does not copy anything, because
3949/// [`Buffer::slice`] moves the offset instead. That is the case a scan over stored memory is in, and
3950/// it is why the flat body is no longer the one form of a vector whose cut costs an allocation.
3951fn run_of(data: &Data, at: usize, end: usize) -> Data {
3952 macro_rules! run {
3953 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3954 match data {
3955 Data::Empty => Data::Empty,
3956 $(Data::$variant(values) => {
3957 let held = values.len();
3958 let from = at.min(held);
3959 let to = end.max(from).min(held);
3960 if to == end {
3961 // The whole run is there, so this is a window on a shared page and a copy on
3962 // an owned one, decided inside the buffer rather than here.
3963 Data::$variant(values.slice(from, end - from))
3964 } else {
3965 let values = values.as_slice();
3966 let mut out = Buffer::with_capacity(end - at);
3967 out.extend_from_slice(&values[from..to]);
3968 // A body shorter than the rows asked for pads with the zero every layout
3969 // uses for a null, which is the answer `copy_of` gives for a position past
3970 // the end.
3971 // row at a time: never runs on a vector whose data matches its length.
3972 for _ in to..end {
3973 out.push($zero);
3974 }
3975 Data::$variant(out)
3976 }
3977 })+
3978 // A view says where its bytes are, so a run of rows is not a run of bytes and this
3979 // is the one layout whose cut is still a loop. The total is known before any of it
3980 // is copied, so the arena is one allocation.
3981 //
3982 // Unless the payload is a page, in which case the cut points at the same page the
3983 // column does and no byte of it moves. That is the case a scan of a stored column
3984 // is in, and it is the whole of why a producer pages its payload: a page cut into
3985 // chunk sized pieces used to copy every byte of every long string once per piece.
3986 Data::Varlen(values) => {
3987 if let Some(shared) =
3988 values.window(at, end).or_else(|| values.viewing(at..end))
3989 {
3990 return Data::Varlen(shared);
3991 }
3992 let views = values.views();
3993 let mut out = StringColumn::with_capacity(end - at);
3994 out.reserve_bytes(
3995 views
3996 .get(at.min(views.len())..end.min(views.len()))
3997 .unwrap_or(&[])
3998 .iter()
3999 .filter(|view| !view.is_inline())
4000 .map(StringView::len)
4001 .sum(),
4002 );
4003 // row at a time: see above, the bytes of consecutive rows need not be next to
4004 // each other.
4005 for index in at..end {
4006 out.push_from(values, index);
4007 }
4008 Data::Varlen(out)
4009 }
4010 }
4011 };
4012 }
4013 crate::for_each_layout!(fixed, run)
4014}
4015
4016/// The values of `data` written to the places `inverse` gives them, the other way round from
4017/// [`copy_of`]: value `n` lands at `inverse[n]`.
4018///
4019/// `inverse` is a permutation of the positions of `data` and the answer is as long as it. A place
4020/// past the end is dropped rather than trusted, and a place nobody wrote keeps the zero, the same
4021/// zero a gather writes for a position that resolved to nowhere. Strings are turned back into
4022/// positions and gathered, because their one caller moves the views itself and never sends them.
4023pub(crate) fn placed_of(data: &Data, inverse: &[u32]) -> Data {
4024 macro_rules! placed {
4025 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4026 match data {
4027 $(Data::$variant(values) => {
4028 let mut out: Vec<$native> = vec![$zero; inverse.len()];
4029 for (value, &to) in values.as_slice().iter().zip(inverse) {
4030 if let Some(slot) = out.get_mut(to as usize) {
4031 *slot = *value;
4032 }
4033 }
4034 Data::$variant(Buffer::from_vec(out))
4035 })+
4036 Data::Empty => Data::Empty,
4037 // Turned back round into positions and gathered, so a caller that does hand this
4038 // strings gets the right answer rather than a missing arm.
4039 Data::Varlen(_) => {
4040 let mut at = vec![NOWHERE; inverse.len()];
4041 for (row, &to) in inverse.iter().enumerate() {
4042 if let Some(slot) = at.get_mut(to as usize) {
4043 *slot = row;
4044 }
4045 }
4046 copy_of(data, &at)
4047 }
4048 }
4049 };
4050 }
4051 crate::for_each_layout!(fixed, placed)
4052}
4053
4054pub(crate) fn copy_of(data: &Data, at: &[usize]) -> Data {
4055 macro_rules! copied {
4056 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4057 match data {
4058 Data::Empty => Data::Empty,
4059 $(Data::$variant(values) => {
4060 let values = values.as_slice();
4061 // Into a `Vec` and then into a buffer, rather than pushing at the buffer. A
4062 // push asks the buffer whether it owns its run and copies the page out if it
4063 // does not, which is the copy on write point and is the right answer for a
4064 // caller writing one value. This caller is writing `at.len()` of them into a
4065 // run it made itself one line earlier, so the question has one answer and it
4066 // is asked once by not being asked at all. The map is exact sized, so the
4067 // extend reserves once and writes without a capacity check per value.
4068 let mut out: Vec<$native> = Vec::with_capacity(at.len());
4069 // One bounds check rather than a null test and a bounds check, because
4070 // `NOWHERE` is past the end of every slice there can be.
4071 out.extend(at.iter().map(|&index| values.get(index).copied().unwrap_or($zero)));
4072 Data::$variant(Buffer::from_vec(out))
4073 })+
4074 // The one layout where a gather is a copy of bytes rather than a copy of fixed
4075 // width slots, and the reason compaction is a decision rather than a default on a
4076 // string column. A payload that is a page is the exception: the gathered views
4077 // point at the page the column already points at, so the gather is sixteen bytes a
4078 // row and the bytes stay where the page put them.
4079 Data::Varlen(values) => {
4080 if let Some(shared) = values.viewing(at.iter().copied()) {
4081 return Data::Varlen(shared);
4082 }
4083 let mut out = StringColumn::with_capacity(at.len());
4084 // The bytes are known before any of them are copied, because a view carries its
4085 // length and the wanted positions are already in hand, so the arena is one
4086 // allocation rather than a run of doublings that each copy what the last one
4087 // copied.
4088 let views = values.views();
4089 out.reserve_bytes(
4090 at.iter()
4091 .filter_map(|&index| views.get(index))
4092 .filter(|view| !view.is_inline())
4093 .map(StringView::len)
4094 .sum(),
4095 );
4096 for &index in at {
4097 out.push_from(values, index);
4098 }
4099 Data::Varlen(out)
4100 }
4101 }
4102 };
4103 }
4104 crate::for_each_layout!(fixed, copied)
4105}
4106
4107/// The physical layout a run of data is in, for the check that it matches its type.
4108///
4109/// The two enums name their variants the same way on purpose, so this is one generated arm rather
4110/// than sixteen chances to pair the wrong two up.
4111pub(crate) fn layout_of(data: &Data) -> rudb_common::PhysicalType {
4112 use rudb_common::PhysicalType as P;
4113 macro_rules! layouts {
4114 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4115 match data {
4116 Data::Empty => P::Empty,
4117 $(Data::$variant(_) => P::$variant,)+
4118 }
4119 };
4120 }
4121 crate::for_each_layout!(all, layouts)
4122}
4123
4124/// One value out of a run of data, given what the run means.
4125///
4126/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
4127/// from an `INTEGER` and that is the whole reason the two are kept apart.
4128fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
4129 let signed = || data.signed_at(index);
4130 let unsigned = || data.unsigned_at(index);
4131 let value = match ty {
4132 LogicalType::Boolean => match data {
4133 Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
4134 _ => None,
4135 },
4136 LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
4137 LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
4138 LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
4139 LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
4140 LogicalType::HugeInt => signed().map(Value::HugeInt),
4141 LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
4142 LogicalType::USmallInt => {
4143 unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
4144 }
4145 LogicalType::UInteger => {
4146 unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
4147 }
4148 LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
4149 LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
4150 LogicalType::Float => match data {
4151 Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
4152 _ => None,
4153 },
4154 LogicalType::Double => match data {
4155 Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
4156 _ => None,
4157 },
4158 LogicalType::Decimal { width, scale } => {
4159 signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
4160 }
4161 LogicalType::Varchar | LogicalType::Blob | LogicalType::Bit => {
4162 data.bytes_at(index).map(|bytes| bytes_as(ty, bytes))
4163 }
4164 LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
4165 LogicalType::Time => signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time),
4166 LogicalType::TimeTz => signed().and_then(|x| i64::try_from(x).ok()).map(Value::TimeTz),
4167 LogicalType::Timestamp
4168 | LogicalType::TimestampS
4169 | LogicalType::TimestampMs
4170 | LogicalType::TimestampNs => {
4171 signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
4172 }
4173 LogicalType::TimestampTz => {
4174 signed().and_then(|x| i64::try_from(x).ok()).map(Value::TimestampTz)
4175 }
4176 LogicalType::Interval => match data {
4177 Data::Interval(v) => {
4178 v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
4179 }
4180 _ => None,
4181 },
4182 _ => None,
4183 };
4184 value.unwrap_or(Value::Null)
4185}
4186
4187/// The fields a struct type names, and nothing for any other type.
4188///
4189/// Only a `STRUCT` vector has a [`Body::Fields`] body, and the two are built together, so in practice
4190/// the empty slice is unreachable and is here so that reading a field name is not a panic if that ever
4191/// stops being true. A struct vector whose type has fewer fields than it has children answers about
4192/// the fields it can name, because the zip stops at the shorter of the two.
4193fn fields_of(ty: &LogicalType) -> &[Field] {
4194 match ty {
4195 LogicalType::Struct(fields) => fields,
4196 _ => &[],
4197 }
4198}
4199
4200/// One row of a string column as a value, given what its bytes are meant to be read as.
4201///
4202/// Both forms that hold strings come through here, so a row that is a `BLOB` in a flat column is a
4203/// `BLOB` in a string view column too. Bytes that are not text in a `VARCHAR` column are a null
4204/// rather than a panic, since everything that got in went in as a string and a column that has
4205/// something else in it is a bug somewhere earlier that a read should not turn into a crash.
4206fn bytes_as(ty: &LogicalType, bytes: &[u8]) -> Value {
4207 match ty {
4208 LogicalType::Varchar => {
4209 std::str::from_utf8(bytes).map_or(Value::Null, |text| Value::Varchar(text.to_owned()))
4210 }
4211 LogicalType::Blob | LogicalType::Bit => Value::Blob(bytes.to_vec()),
4212 _ => Value::Null,
4213 }
4214}
4215
4216/// An empty run of data of the right layout for a type.
4217pub(crate) fn empty_data_for(ty: &LogicalType) -> Result<Data> {
4218 use rudb_common::PhysicalType as P;
4219 macro_rules! empties {
4220 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4221 match ty.physical() {
4222 P::Empty => Data::Empty,
4223 $(P::$variant => Data::$variant(Buffer::new()),)+
4224 P::Varlen => Data::Varlen(StringColumn::new()),
4225 other => {
4226 return Err(Error::not_implemented(format!(
4227 "a flat vector of {other:?} data, which arrives with the storage layer"
4228 )));
4229 }
4230 }
4231 };
4232 }
4233 Ok(crate::for_each_layout!(fixed, empties))
4234}
4235
4236/// An empty run of the type's layout with room for `rows` values already taken.
4237///
4238/// For a caller that knows how many values are going in before the first one does, which is a
4239/// producer laying pieces end to end. Growing from empty instead reallocates once per doubling and
4240/// finishes holding a run rounded up to the next power of two, and on a row group of 122,880 values
4241/// that rounding is the last 8,192 of them carried for the life of the table.
4242///
4243/// Bytes are not reserved for a varlen run, because how many of them there are is not the number of
4244/// rows and the caller appending them is the one that can work it out.
4245///
4246/// # Errors
4247///
4248/// If the type has no flat layout, the same as [`empty_data_for`].
4249pub(crate) fn data_for(ty: &LogicalType, rows: usize) -> Result<Data> {
4250 let mut data = empty_data_for(ty)?;
4251 macro_rules! reserved {
4252 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4253 match &mut data {
4254 Data::Empty => {}
4255 $(Data::$variant(values) => values.reserve(rows),)+
4256 Data::Varlen(values) => values.reserve_views(rows),
4257 }
4258 };
4259 }
4260 crate::for_each_layout!(fixed, reserved);
4261 Ok(data)
4262}
4263
4264/// Appends one value to a run of data, or a zero of the right shape when it is null.
4265///
4266/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
4267/// and a run of data with a hole in it would put every value after the hole in the wrong place.
4268fn push_value(data: &mut Data, value: &Value) -> Result<()> {
4269 macro_rules! push {
4270 ($vec:expr, $variant:path, $zero:expr) => {
4271 match value {
4272 Value::Null => $vec.push($zero),
4273 $variant(x) => $vec.push(*x),
4274 other => {
4275 return Err(Error::internal(format!(
4276 "{other:?} does not belong in this vector"
4277 )));
4278 }
4279 }
4280 };
4281 }
4282 // A decimal is stored as its unscaled integer in whatever width its precision needs, which
4283 // `LogicalType::physical` decides and which is why the same `Value::Decimal` is at home in four
4284 // different runs. The narrowing cannot fail for a value the binder produced, because the width
4285 // that chose the run is the width in the value, but it is checked rather than assumed because
4286 // an unchecked cast here would silently store a different number.
4287 macro_rules! decimal {
4288 ($vec:expr, $ty:ty, $unscaled:expr) => {
4289 match <$ty>::try_from(*$unscaled) {
4290 Ok(x) => $vec.push(x),
4291 Err(_) => {
4292 return Err(Error::internal(format!(
4293 "an unscaled decimal of {} does not fit the run its precision chose",
4294 $unscaled
4295 )));
4296 }
4297 }
4298 };
4299 }
4300 match data {
4301 Data::Empty => {}
4302 Data::Bool(v) => push!(v, Value::Boolean, false),
4303 Data::Int8(v) => push!(v, Value::TinyInt, 0),
4304 Data::Int16(v) => match value {
4305 Value::Null => v.push(0),
4306 Value::SmallInt(x) => v.push(*x),
4307 Value::Decimal { unscaled, .. } => decimal!(v, i16, unscaled),
4308 other => return Err(Error::internal(format!("{other:?} is not a 16 bit value"))),
4309 },
4310 Data::Int32(v) => match value {
4311 Value::Null => v.push(0),
4312 Value::Integer(x) | Value::Date(x) => v.push(*x),
4313 Value::Decimal { unscaled, .. } => decimal!(v, i32, unscaled),
4314 other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
4315 },
4316 Data::Int64(v) => match value {
4317 Value::Null => v.push(0),
4318 Value::BigInt(x)
4319 | Value::Time(x)
4320 | Value::TimeTz(x)
4321 | Value::Timestamp(x)
4322 | Value::TimestampTz(x) => v.push(*x),
4323 Value::Decimal { unscaled, .. } => decimal!(v, i64, unscaled),
4324 other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
4325 },
4326 Data::Int128(v) => match value {
4327 Value::Null => v.push(0),
4328 Value::HugeInt(x) => v.push(*x),
4329 Value::Decimal { unscaled, .. } => v.push(*unscaled),
4330 other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
4331 },
4332 Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
4333 Data::UInt16(v) => push!(v, Value::USmallInt, 0),
4334 Data::UInt32(v) => push!(v, Value::UInteger, 0),
4335 Data::UInt64(v) => push!(v, Value::UBigInt, 0),
4336 Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
4337 Data::Float32(v) => push!(v, Value::Float, 0.0),
4338 Data::Float64(v) => push!(v, Value::Double, 0.0),
4339 Data::Interval(v) => match value {
4340 Value::Null => v.push((0, 0, 0)),
4341 Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
4342 other => return Err(Error::internal(format!("{other:?} is not an interval"))),
4343 },
4344 Data::Varlen(column) => match value {
4345 Value::Null => {
4346 column.push("");
4347 }
4348 Value::Varchar(text) => {
4349 column.push(text);
4350 }
4351 // A blob goes in as the bytes it is. The column stores a length and some bytes either
4352 // way, so text is the reading of one rather than a different column, and a blob that
4353 // is not UTF-8 is stored exactly like one that happens to be.
4354 Value::Blob(bytes) => {
4355 column.push_bytes(bytes);
4356 }
4357 other => return Err(Error::internal(format!("{other:?} is not a string"))),
4358 },
4359 }
4360 Ok(())
4361}
4362
4363#[cfg(test)]
4364mod tests {
4365 use std::sync::Arc;
4366
4367 use rudb_common::{Field, LogicalType, Value};
4368
4369 use super::{
4370 Body, Data, FSST_PAYS_AT, Form, MAP_KEY, MAP_VALUE, NO_ROW, VECTOR_SIZE, Vector,
4371 packing_base,
4372 };
4373 use crate::buffer::Buffer;
4374 use crate::fsst::SymbolTable;
4375 use crate::string::{StringColumn, StringView};
4376 use crate::validity::Validity;
4377
4378 fn integers(values: &[i32]) -> Vector {
4379 Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec().into())).unwrap()
4380 }
4381
4382 #[test]
4383 fn unpacking_in_bulk_reads_what_a_code_at_a_time_reads_at_every_width() {
4384 let mut state = 0x5eed_0b17_u64;
4385 let mut next = || {
4386 state ^= state << 13;
4387 state ^= state >> 7;
4388 state ^= state << 17;
4389 state
4390 };
4391 let words: Vec<u64> = (0..700).map(|_| next()).collect();
4392 for width in 1..=super::PACKED_WIDTH_MAX {
4393 for offset in [0, 1, 63, 64, 65] {
4394 let packed = super::Packed { words: &words, width, base: 0, offset };
4395 for (from, rows) in [(0, 0), (0, 1), (0, 64), (3, 200), (61, 130), (128, 512)] {
4396 let mut out = vec![u64::MAX; rows];
4397 packed.unpack(from, &mut out);
4398 let want: Vec<u64> = (from..from + rows).map(|row| packed.code(row)).collect();
4399 assert_eq!(out, want, "width {width} offset {offset} from {from}");
4400 }
4401 let at = [5_usize, 9, 9, 70, 6, 200, 131];
4402 let want: Vec<u64> = at.iter().map(|&row| packed.code(row)).collect();
4403 assert_eq!(packed.codes_at(|index| at[index], at.len()), want);
4404 let far = [0_usize, 5000];
4405 let want: Vec<u64> = far.iter().map(|&row| packed.code(row)).collect();
4406 assert_eq!(packed.codes_at(|index| far[index], far.len()), want);
4407 }
4408 }
4409 }
4410
4411 /// A `Value::List` of integers, which is what a row of a list column arrives as.
4412 fn list(values: &[i32]) -> Value {
4413 Value::List {
4414 element: LogicalType::Integer,
4415 values: values.iter().map(|&v| Value::Integer(v)).collect(),
4416 }
4417 }
4418
4419 fn list_column(rows: &[Value]) -> Vector {
4420 Vector::from_values(LogicalType::list(LogicalType::Integer), rows).unwrap()
4421 }
4422
4423 #[test]
4424 fn a_list_column_is_one_child_and_a_range_per_row() {
4425 let rows = vec![list(&[1, 2, 3]), list(&[]), Value::Null, list(&[4])];
4426 let column = list_column(&rows);
4427 assert_eq!(column.form(), Form::List);
4428 assert_eq!(column.len(), 4);
4429 assert_eq!(column.logical_type(), &LogicalType::list(LogicalType::Integer));
4430 // Four rows and four elements, because a null and an empty list both contribute none.
4431 let (entries, child) = column.list_parts().expect("a list");
4432 assert_eq!(entries, [(0, 3), (3, 0), (3, 0), (3, 1)]);
4433 assert_eq!(child.len(), 4);
4434 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
4435 }
4436
4437 /// The one thing the entries cannot say on their own, so it has to be checked that the mask says
4438 /// it. An empty list is a row that is there and holds nothing, a null is a row that is not there,
4439 /// and both of them have an entry of length zero.
4440 #[test]
4441 fn an_empty_list_and_a_null_list_have_the_same_entry_and_are_different_rows() {
4442 let column = list_column(&[list(&[]), Value::Null]);
4443 let (entries, _) = column.list_parts().expect("a list");
4444 assert_eq!(entries[0].1, entries[1].1, "both entries are empty");
4445 assert!(!column.is_null_at(0), "an empty list is not null");
4446 assert!(column.is_null_at(1), "a null list is null");
4447 assert_eq!(column.value_at(0), list(&[]));
4448 assert_eq!(column.value_at(1), Value::Null);
4449 }
4450
4451 #[test]
4452 fn slicing_a_list_column_shares_the_child_rather_than_copying_it() {
4453 let rows: Vec<Value> = (0..64).map(|row| list(&[row, row + 1, row + 2])).collect();
4454 let column = list_column(&rows);
4455 let cut = column.slice(8, 4).unwrap();
4456 assert_eq!(cut.form(), Form::List);
4457 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[8..12]);
4458 // The entries are absolute positions in a child that was not cut, which is what makes the
4459 // cut eight bytes a row however long the lists are. The elements outside the range are still
4460 // there and nothing points at them.
4461 let (entries, child) = cut.list_parts().expect("a list");
4462 assert_eq!(entries[0], (24, 3));
4463 assert_eq!(child.len(), 192);
4464 }
4465
4466 #[test]
4467 fn gathering_a_list_column_permutes_the_entries_and_leaves_the_child_alone() {
4468 let rows = vec![list(&[1]), list(&[2, 2]), list(&[3, 3, 3])];
4469 let column = list_column(&rows);
4470 let picked = column.gather(&[2, 0, 2]).unwrap();
4471 assert_eq!(
4472 picked.iter().collect::<Vec<_>>(),
4473 [list(&[3, 3, 3]), list(&[1]), list(&[3, 3, 3])]
4474 );
4475 // Two of the three rows are the same row, which is the case a run of offsets cannot write
4476 // down and a start and a length can. That is the whole reason this form carries both.
4477 assert_eq!(picked.list_parts().expect("a list").1.len(), 6);
4478 }
4479
4480 #[test]
4481 fn a_gather_past_the_end_of_a_list_column_is_null_rather_than_somebody_elses_elements() {
4482 let column = list_column(&[list(&[1, 2]), list(&[3])]);
4483 let picked = column.gather(&[1, 9]).unwrap();
4484 assert_eq!(picked.value_at(0), list(&[3]));
4485 assert_eq!(picked.value_at(1), Value::Null);
4486 }
4487
4488 #[test]
4489 fn a_list_of_lists_nests_as_far_as_it_is_written() {
4490 let outer = Value::List {
4491 element: LogicalType::list(LogicalType::Integer),
4492 values: vec![list(&[1, 2]), list(&[3])],
4493 };
4494 let column = Vector::from_values(
4495 LogicalType::list(LogicalType::list(LogicalType::Integer)),
4496 std::slice::from_ref(&outer),
4497 )
4498 .unwrap();
4499 assert_eq!(column.value_at(0), outer);
4500 assert_eq!(column.list_parts().expect("a list").1.form(), Form::List);
4501 }
4502
4503 /// A list row is not bytes and not an integer, and a caller that asks for either gets nothing
4504 /// rather than the first element or a length. Both of those would be a wrong answer that a
4505 /// group by or a hash would read without complaining.
4506 #[test]
4507 fn the_scalar_readers_decline_a_list_instead_of_answering_about_its_elements() {
4508 let column = list_column(&[list(&[7])]);
4509 assert_eq!(column.signed_at(0), None);
4510 assert_eq!(column.bytes_at(0), None);
4511 assert_eq!(column.data(), None);
4512 }
4513
4514 fn pair(a: i32, b: &str) -> Value {
4515 Value::Struct(vec![
4516 ("a".to_string(), Value::Integer(a)),
4517 ("b".to_string(), Value::Varchar(b.to_string())),
4518 ])
4519 }
4520
4521 fn pair_type() -> LogicalType {
4522 LogicalType::Struct(vec![
4523 Field::new("a", LogicalType::Integer),
4524 Field::new("b", LogicalType::Varchar),
4525 ])
4526 }
4527
4528 fn pair_column(rows: &[Value]) -> Vector {
4529 Vector::from_values(pair_type(), rows).unwrap()
4530 }
4531
4532 #[test]
4533 fn a_struct_column_is_one_child_per_field_as_long_as_the_column() {
4534 let rows = vec![pair(1, "x"), pair(2, "y"), pair(3, "z")];
4535 let column = pair_column(&rows);
4536 assert_eq!(column.form(), Form::Struct);
4537 assert_eq!(column.len(), 3);
4538 assert_eq!(column.logical_type(), &pair_type());
4539 // Two children rather than two entries and a child, and both of them as long as the column,
4540 // which is the whole difference between this form and the list one.
4541 let children = column.struct_parts().expect("a struct");
4542 assert_eq!(children.len(), 2);
4543 assert_eq!(children[0].len(), 3);
4544 assert_eq!(children[1].len(), 3);
4545 assert_eq!(children[0].logical_type(), &LogicalType::Integer);
4546 assert_eq!(children[1].logical_type(), &LogicalType::Varchar);
4547 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
4548 }
4549
4550 /// Picking one field out of a struct is picking one child, which is the reason this accessor is
4551 /// public. A projection of `s.a` hands back a vector that already exists, so it costs a pointer
4552 /// rather than a pass over the rows, and that is only true while the children are full length.
4553 #[test]
4554 fn one_field_of_a_struct_column_is_a_column_that_is_already_there() {
4555 let column = pair_column(&[pair(10, "x"), pair(20, "y")]);
4556 let field = &column.struct_parts().expect("a struct")[0];
4557 assert_eq!(field.iter().collect::<Vec<_>>(), [Value::Integer(10), Value::Integer(20)]);
4558 assert_eq!(field.signed_at(1), Some(20), "the field is a scalar column and reads like one");
4559 }
4560
4561 /// A null struct is a bit in the mask at the top and nothing deeper, which is how every other type
4562 /// records a null and is what DuckDB does. The row reads as a single null rather than as a struct of
4563 /// nulls, and the fields underneath are still their own columns.
4564 #[test]
4565 fn a_null_struct_is_the_mask_at_the_top_and_not_a_struct_full_of_nulls() {
4566 let column = pair_column(&[pair(1, "x"), Value::Null]);
4567 assert!(!column.is_null_at(0));
4568 assert!(column.is_null_at(1));
4569 assert_eq!(column.value_at(1), Value::Null);
4570 // A struct row whose every field happens to be null is a different row, and it is not null.
4571 let all_null = pair_column(&[Value::Struct(vec![
4572 ("a".to_string(), Value::Null),
4573 ("b".to_string(), Value::Null),
4574 ])]);
4575 assert!(!all_null.is_null_at(0), "a struct of nulls is a row that is there");
4576 assert_ne!(all_null.value_at(0), Value::Null);
4577 }
4578
4579 #[test]
4580 fn slicing_a_struct_column_cuts_every_field_at_the_same_place() {
4581 let rows: Vec<Value> = (0..64).map(|row| pair(row, "s")).collect();
4582 let column = pair_column(&rows);
4583 let cut = column.slice(8, 4).unwrap();
4584 assert_eq!(cut.form(), Form::Struct);
4585 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[8..12]);
4586 // The cut a list column does not have to do. A list shares its child untouched because the
4587 // entries carry the range, and a struct has no entry standing between the row and the child,
4588 // so every child is four rows long here rather than sixty four.
4589 for child in cut.struct_parts().expect("a struct") {
4590 assert_eq!(child.len(), 4);
4591 }
4592 }
4593
4594 #[test]
4595 fn gathering_a_struct_column_gathers_every_field_at_the_same_positions() {
4596 let column = pair_column(&[pair(1, "x"), pair(2, "y"), pair(3, "z")]);
4597 let picked = column.gather(&[2, 0, 2]).unwrap();
4598 assert_eq!(picked.iter().collect::<Vec<_>>(), [pair(3, "z"), pair(1, "x"), pair(3, "z")]);
4599 for child in picked.struct_parts().expect("a struct") {
4600 assert_eq!(child.len(), 3, "a field is as long as the gather, not as the source");
4601 }
4602 }
4603
4604 #[test]
4605 fn a_gather_past_the_end_of_a_struct_column_is_null_in_every_field_and_at_the_top() {
4606 let column = pair_column(&[pair(1, "x"), pair(2, "y")]);
4607 let picked = column.gather(&[1, 9]).unwrap();
4608 assert_eq!(picked.value_at(0), pair(2, "y"));
4609 assert_eq!(picked.value_at(1), Value::Null);
4610 for child in picked.struct_parts().expect("a struct") {
4611 assert!(child.is_null_at(1), "a row that came from nowhere has no field value either");
4612 }
4613 }
4614
4615 /// The names are matched and not counted, because a caller holding a struct value built in a
4616 /// different order from the type's would otherwise get its columns transposed, and that is a wrong
4617 /// answer that reads as a right one.
4618 #[test]
4619 fn the_fields_of_a_struct_value_go_in_by_name_rather_than_by_position() {
4620 let swapped = Value::Struct(vec![
4621 ("b".to_string(), Value::Varchar("x".to_string())),
4622 ("a".to_string(), Value::Integer(1)),
4623 ]);
4624 let column = pair_column(&[swapped]);
4625 assert_eq!(column.value_at(0), pair(1, "x"));
4626 let wrong = Value::Struct(vec![
4627 ("a".to_string(), Value::Integer(1)),
4628 ("c".to_string(), Value::Varchar("x".to_string())),
4629 ]);
4630 let failed = Vector::from_values(pair_type(), &[wrong]);
4631 assert!(failed.is_err(), "a row with no b field is an error rather than a null b");
4632 }
4633
4634 #[test]
4635 fn a_struct_built_from_children_takes_its_field_names_from_the_caller() {
4636 let column = Vector::structure(vec![
4637 ("a".to_string(), integers(&[1, 2, 3])),
4638 ("b".to_string(), integers(&[4, 5, 6])),
4639 ])
4640 .expect("two columns of three");
4641 assert_eq!(column.len(), 3);
4642 assert_eq!(
4643 column.logical_type(),
4644 &LogicalType::Struct(vec![
4645 Field::new("a", LogicalType::Integer),
4646 Field::new("b", LogicalType::Integer),
4647 ])
4648 );
4649 assert_eq!(
4650 column.value_at(1),
4651 Value::Struct(vec![
4652 ("a".to_string(), Value::Integer(2)),
4653 ("b".to_string(), Value::Integer(5)),
4654 ])
4655 );
4656 }
4657
4658 /// The two mistakes this constructor makes easy, both refused rather than stored. A short field is
4659 /// the one that matters: it would be a struct that reads past the end of one of its own children,
4660 /// which is the same mistake `Vector::list` checks for at the other end.
4661 #[test]
4662 fn a_struct_of_uneven_children_or_of_no_children_is_refused() {
4663 let uneven = Vector::structure(vec![
4664 ("a".to_string(), integers(&[1, 2, 3])),
4665 ("b".to_string(), integers(&[4, 5])),
4666 ]);
4667 assert!(uneven.is_err(), "a field shorter than the struct");
4668 assert!(Vector::structure(vec![]).is_err(), "no field to take a length from");
4669 }
4670
4671 #[test]
4672 fn a_struct_of_lists_and_a_list_of_structs_both_nest() {
4673 let ty =
4674 LogicalType::Struct(vec![Field::new("a", LogicalType::list(LogicalType::Integer))]);
4675 let row = Value::Struct(vec![("a".to_string(), list(&[1, 2]))]);
4676 let column = Vector::from_values(ty, std::slice::from_ref(&row)).unwrap();
4677 assert_eq!(column.value_at(0), row);
4678 assert_eq!(column.struct_parts().expect("a struct")[0].form(), Form::List);
4679
4680 let outer = Value::List { element: pair_type(), values: vec![pair(1, "x"), pair(2, "y")] };
4681 let lists =
4682 Vector::from_values(LogicalType::list(pair_type()), std::slice::from_ref(&outer))
4683 .unwrap();
4684 assert_eq!(lists.value_at(0), outer);
4685 assert_eq!(lists.list_parts().expect("a list").1.form(), Form::Struct);
4686 }
4687
4688 fn tags(pairs: &[(&str, &str)]) -> Value {
4689 Value::map(
4690 LogicalType::Varchar,
4691 LogicalType::Varchar,
4692 pairs
4693 .iter()
4694 .map(|&(key, value)| {
4695 (Value::Varchar(key.to_string()), Value::Varchar(value.to_string()))
4696 })
4697 .collect(),
4698 )
4699 }
4700
4701 fn tag_column(rows: &[Value]) -> Vector {
4702 Vector::from_values(LogicalType::map(LogicalType::Varchar, LogicalType::Varchar), rows)
4703 .unwrap()
4704 }
4705
4706 /// A map is a list of two field structs, which is the whole design, so the test that says so is
4707 /// the one that reaches through both layers and finds the pieces where each of them puts them.
4708 #[test]
4709 fn a_map_column_is_a_list_whose_child_is_a_struct_of_keys_and_values() {
4710 let rows =
4711 vec![tags(&[("a", "b"), ("c", "d")]), tags(&[]), Value::Null, tags(&[("e", "f")])];
4712 let column = tag_column(&rows);
4713 assert_eq!(column.len(), 4);
4714 assert_eq!(
4715 column.logical_type(),
4716 &LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
4717 );
4718 // The physical form is a list's, because the bytes are a list's. The logical type is what
4719 // remembers it is a map, which is the same split `LogicalType::physical` already makes.
4720 assert_eq!(column.form(), Form::List);
4721 let (entries, child) = column.list_parts().expect("the layout of a list");
4722 assert_eq!(entries, [(0, 2), (2, 0), (2, 0), (2, 1)]);
4723 assert_eq!(child.form(), Form::Struct);
4724 assert_eq!(
4725 child.logical_type(),
4726 &LogicalType::Struct(vec![
4727 Field::new(MAP_KEY, LogicalType::Varchar),
4728 Field::new(MAP_VALUE, LogicalType::Varchar),
4729 ])
4730 );
4731 // And the accessor that reaches through it hands back the two columns rather than the struct.
4732 let (entries, keys, values) = column.map_parts().expect("a map");
4733 assert_eq!(entries.len(), 4);
4734 assert_eq!(keys.text_at(0), Some("a"));
4735 assert_eq!(values.text_at(0), Some("b"));
4736 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
4737 }
4738
4739 /// The same distinction a list has, checked again here rather than assumed from the composition,
4740 /// because the empty map is the one every catalog table in D2 is full of and a null map is what a
4741 /// column with no tags at all would be.
4742 #[test]
4743 fn an_empty_map_and_a_null_map_are_different_rows() {
4744 let column = tag_column(&[tags(&[]), Value::Null]);
4745 assert!(!column.is_null_at(0), "an empty map is a row that is there");
4746 assert!(column.is_null_at(1));
4747 assert_eq!(column.value_at(0), tags(&[]));
4748 assert_eq!(column.value_at(1), Value::Null);
4749 assert_eq!(column.value_at(0).to_string(), "{}");
4750 assert_eq!(column.value_at(1).to_string(), "NULL");
4751 }
4752
4753 /// A map prints `{a=b}` and a struct prints `{'a': b}`, both measured off the pin. They share a
4754 /// layout and they cannot share a printer, which is the one thing about this composition that does
4755 /// not fall out of it.
4756 #[test]
4757 fn a_map_prints_with_equals_signs_and_a_struct_prints_with_quoted_names() {
4758 assert_eq!(tags(&[("a", "b"), ("c", "d")]).to_string(), "{a=b, c=d}");
4759 assert_eq!(pair(1, "x").to_string(), "{'a': 1, 'b': x}");
4760 let numbers = Value::map(
4761 LogicalType::Integer,
4762 LogicalType::Integer,
4763 vec![(Value::Integer(1), Value::Integer(3)), (Value::Integer(2), Value::Integer(4))],
4764 );
4765 assert_eq!(numbers.to_string(), "{1=3, 2=4}");
4766 let null_value = Value::map(
4767 LogicalType::Varchar,
4768 LogicalType::Varchar,
4769 vec![(Value::Varchar("x".to_string()), Value::Null)],
4770 );
4771 assert_eq!(null_value.to_string(), "{x=NULL}");
4772 }
4773
4774 /// A map inherits the list's cut and the list's gather, which is the payoff for storing it as one.
4775 /// Neither of these is code written for maps and both of them are worth a test that says the
4776 /// inheritance works, since the type is rewritten on the way through and a form that came back as a
4777 /// list would still read.
4778 #[test]
4779 fn cutting_and_gathering_a_map_keeps_it_a_map() {
4780 let rows: Vec<Value> =
4781 (0..16).map(|row| tags(&[("k", if row % 2 == 0 { "e" } else { "o" })])).collect();
4782 let column = tag_column(&rows);
4783
4784 let cut = column.slice(4, 3).unwrap();
4785 assert!(matches!(cut.logical_type(), LogicalType::Map(_, _)), "still a map after a cut");
4786 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[4..7]);
4787 // The child was not cut, the same as for a list, which is what makes the cut eight bytes a row.
4788 assert_eq!(cut.map_parts().expect("a map").1.len(), 16);
4789
4790 let picked = column.gather(&[3, 0, 3]).unwrap();
4791 assert!(matches!(picked.logical_type(), LogicalType::Map(_, _)));
4792 assert_eq!(
4793 picked.iter().collect::<Vec<_>>(),
4794 [rows[3].clone(), rows[0].clone(), rows[3].clone()]
4795 );
4796 let past = column.gather(&[0, 99]).unwrap();
4797 assert_eq!(past.value_at(1), Value::Null);
4798 }
4799
4800 #[test]
4801 fn a_map_built_from_two_columns_pairs_them_by_position() {
4802 let keys = Vector::from_values(
4803 LogicalType::Varchar,
4804 &[Value::Varchar("a".to_string()), Value::Varchar("c".to_string())],
4805 )
4806 .unwrap();
4807 let values = Vector::from_values(
4808 LogicalType::Varchar,
4809 &[Value::Varchar("b".to_string()), Value::Varchar("d".to_string())],
4810 )
4811 .unwrap();
4812 let column = Vector::map(vec![(0, 2), (2, 0)], keys, values).expect("two rows");
4813 assert_eq!(column.len(), 2);
4814 assert_eq!(
4815 column.logical_type(),
4816 &LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
4817 );
4818 assert_eq!(column.value_at(0), tags(&[("a", "b"), ("c", "d")]));
4819 assert_eq!(column.value_at(1), tags(&[]));
4820 // The entry check the list constructor does is the one a map gets, so an entry past the end of
4821 // the pair of columns is refused here too rather than read as somebody else's keys.
4822 let short =
4823 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("a".to_string())]).unwrap();
4824 let other =
4825 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("b".to_string())]).unwrap();
4826 assert!(Vector::map(vec![(0, 9)], short, other).is_err(), "an entry past the end");
4827 }
4828
4829 /// `map_parts` is about the logical type and `list_parts` is about the layout, so a list has to
4830 /// decline the first and a map has to answer the second. Getting that backwards would let a kernel
4831 /// written for maps read a list of two field structs as if it were one.
4832 #[test]
4833 fn a_list_is_not_a_map_however_much_its_child_looks_like_one() {
4834 let pairs = Value::List { element: pair_type(), values: vec![pair(1, "x")] };
4835 let column =
4836 Vector::from_values(LogicalType::list(pair_type()), std::slice::from_ref(&pairs))
4837 .unwrap();
4838 assert!(column.map_parts().is_none(), "a list of structs is a list");
4839 assert!(column.list_parts().is_some());
4840 let map = tag_column(&[tags(&[("a", "b")])]);
4841 assert!(map.map_parts().is_some());
4842 assert!(map.list_parts().is_some(), "a map has a list's layout and says so");
4843 }
4844
4845 /// A struct row is not bytes and not an integer, and it stays that way when it has exactly one
4846 /// integer field, which is the case where answering about the field would look reasonable and would
4847 /// be a hash keyed on the wrong thing.
4848 #[test]
4849 fn the_scalar_readers_decline_a_struct_of_one_integer_field() {
4850 let ty = LogicalType::Struct(vec![Field::new("a", LogicalType::Integer)]);
4851 let row = Value::Struct(vec![("a".to_string(), Value::Integer(7))]);
4852 let column = Vector::from_values(ty, &[row]).unwrap();
4853 assert_eq!(column.signed_at(0), None);
4854 assert_eq!(column.bytes_at(0), None);
4855 assert_eq!(column.data(), None);
4856 }
4857
4858 #[test]
4859 fn a_clustered_column_becomes_runs_and_reads_back_the_same() {
4860 let mut values = Vec::new();
4861 for (value, times) in [(7, 400), (8, 300), (7, 324)] {
4862 values.extend(std::iter::repeat_n(value, times));
4863 }
4864 let flat = integers(&values);
4865 let runs = flat.run_encoded().unwrap();
4866 assert_eq!(runs.form(), Form::Rle);
4867 assert_eq!(runs.run_parts().expect("runs").0, [400, 700, 1024]);
4868 assert_eq!(runs.len(), flat.len());
4869 assert_eq!(runs.iter().collect::<Vec<_>>(), flat.iter().collect::<Vec<_>>());
4870 assert!(
4871 runs.footprint() * 10 < flat.footprint(),
4872 "three runs against a thousand rows: {} against {}",
4873 runs.footprint(),
4874 flat.footprint()
4875 );
4876 }
4877
4878 /// The check is worth having in both directions. A form that is only ever bigger than what it
4879 /// replaced is a form that costs a pass over the column to decide not to use.
4880 #[test]
4881 fn a_column_that_does_not_repeat_is_left_flat() {
4882 let flat = integers(&(0..1024).collect::<Vec<i32>>());
4883 assert_eq!(flat.run_encoded().unwrap().form(), Form::Flat);
4884 // Two runs over four rows is exactly break even on a four byte column, and break even is
4885 // not a reason to change form.
4886 assert_eq!(integers(&[1, 1, 2, 2]).run_encoded().unwrap().form(), Form::Flat);
4887 assert_eq!(integers(&[1, 1, 1, 2, 2]).run_encoded().unwrap().form(), Form::Rle);
4888 }
4889
4890 #[test]
4891 fn two_nulls_beside_each_other_are_one_run_and_a_null_between_two_equals_is_a_break() {
4892 let mut values = vec![Value::Integer(4), Value::Integer(4)];
4893 values.extend([Value::Null, Value::Null, Value::Null]);
4894 values.extend(std::iter::repeat_n(Value::Integer(4), 5));
4895 let flat = Vector::from_values(LogicalType::Integer, &values).unwrap();
4896 let runs = flat.run_encoded().unwrap();
4897 assert_eq!(runs.run_parts().expect("runs").0, [2, 5, 10]);
4898 assert_eq!(runs.iter().collect::<Vec<_>>(), values);
4899 }
4900
4901 #[test]
4902 fn slicing_runs_keeps_them_runs_and_cuts_the_first_and_last_one_back() {
4903 let flat = integers(&[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]);
4904 let runs = flat.run_encoded().unwrap();
4905 let piece = runs.slice(3, 6).unwrap();
4906 assert_eq!(piece.form(), Form::Rle, "the form is the whole point");
4907 assert_eq!(piece.run_parts().expect("runs").0, [1, 5, 6]);
4908 assert_eq!(
4909 piece.iter().collect::<Vec<_>>(),
4910 flat.slice(3, 6).unwrap().iter().collect::<Vec<_>>()
4911 );
4912 assert_eq!(runs.slice(0, 0).unwrap().len(), 0);
4913 assert_eq!(runs.slice(0, 12).unwrap().form(), Form::Rle);
4914 }
4915
4916 #[test]
4917 fn gathering_out_of_runs_walks_to_the_values_the_way_it_walks_a_dictionary() {
4918 let mut values = vec![Value::Varchar("red".into()); 4];
4919 values.extend([Value::Null, Value::Null, Value::Null]);
4920 values.extend(vec![Value::Varchar("blue".into()); 4]);
4921 let runs =
4922 Vector::from_values(LogicalType::Varchar, &values).unwrap().run_encoded().unwrap();
4923 assert_eq!(runs.form(), Form::Rle);
4924 let picked = runs.gather(&[8, 0, 5, 2]).unwrap();
4925 assert_eq!(picked.form(), Form::Flat, "a gather copies, whatever it gathered from");
4926 assert_eq!(
4927 picked.iter().collect::<Vec<_>>(),
4928 [values[8].clone(), values[0].clone(), Value::Null, values[2].clone()]
4929 );
4930 assert_eq!(runs.text_at(1), Some("red"));
4931 assert_eq!(runs.text_at(5), None, "a null has no text");
4932 assert_eq!(runs.flatten().unwrap().iter().collect::<Vec<_>>(), values);
4933 }
4934
4935 /// A run length vector over a run length vector turns one search per row into two, and there is
4936 /// nothing in the engine that builds one, so it is refused rather than composed.
4937 #[test]
4938 fn runs_of_runs_are_refused_and_runs_of_a_dictionary_are_not() {
4939 let inner = integers(&[1, 1, 1, 1, 2]).run_encoded().unwrap();
4940 assert_eq!(inner.form(), Form::Rle);
4941 let error = Vector::runs(vec![2, 8], inner).unwrap_err();
4942 assert!(error.to_string().contains("runs of runs"), "{error}");
4943
4944 let words = Vector::from_values(
4945 LogicalType::Varchar,
4946 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
4947 )
4948 .unwrap();
4949 let dictionary = Vector::dictionary(vec![1, 0], words).unwrap();
4950 let stacked = Vector::runs(vec![4, 9], dictionary).unwrap();
4951 assert_eq!(stacked.len(), 9);
4952 assert_eq!(stacked.value_at(3), Value::Varchar("blue".into()));
4953 assert_eq!(stacked.value_at(4), Value::Varchar("red".into()));
4954 }
4955
4956 #[test]
4957 fn run_ends_have_to_increase_and_there_is_one_value_for_each_of_them() {
4958 let values = integers(&[1, 2]);
4959 assert!(Vector::runs(vec![4], values.clone()).is_err(), "two values and one run");
4960 assert!(Vector::runs(vec![4, 4], values.clone()).is_err(), "an end that repeats");
4961 assert!(Vector::runs(vec![4, 2], values.clone()).is_err(), "an end that goes backwards");
4962 assert!(Vector::runs(vec![0, 2], values.clone()).is_err(), "a first run holding no rows");
4963 assert_eq!(Vector::runs(vec![4, 9], values).unwrap().len(), 9);
4964 }
4965
4966 #[test]
4967 fn a_form_that_is_already_compact_is_left_where_it_is() {
4968 let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1000);
4969 assert_eq!(constant.run_encoded().unwrap().form(), Form::Constant);
4970 assert_eq!(Vector::sequence(0, 1, 1000).run_encoded().unwrap().form(), Form::Sequence);
4971 }
4972
4973 /// What makes one accessor cover both forms. A dictionary hands back the codes it stores and a
4974 /// run length vector works the same numbers out, and a kernel writing `values[at[row]]` reads
4975 /// the same rows out of either.
4976 #[test]
4977 fn both_forms_that_point_somewhere_hand_back_a_position_per_row() {
4978 let words = Vector::from_values(
4979 LogicalType::Varchar,
4980 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
4981 )
4982 .unwrap();
4983 let runs = Vector::runs(vec![3, 5], words.clone()).unwrap();
4984 let (at, values) = runs.positions().expect("runs point somewhere");
4985 assert_eq!(at.as_ref(), [0, 0, 0, 1, 1]);
4986 assert_eq!(values.value_at(at[3] as usize), runs.value_at(3));
4987
4988 let dictionary = Vector::dictionary(vec![1, 0, 1], words).unwrap();
4989 let (at, values) = dictionary.positions().expect("a dictionary points somewhere");
4990 assert_eq!(at.as_ref(), [1, 0, 1]);
4991 assert_eq!(values.value_at(at[0] as usize), dictionary.value_at(0));
4992
4993 assert!(integers(&[1, 2, 3]).positions().is_none(), "a flat vector points at itself");
4994 assert!(Vector::sequence(0, 1, 4).positions().is_none(), "a sequence stores nothing");
4995 }
4996
4997 #[test]
4998 fn slicing_a_dictionary_keeps_it_a_dictionary_where_gathering_would_not() {
4999 let values = Vector::from_values(
5000 LogicalType::Varchar,
5001 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5002 )
5003 .unwrap();
5004 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
5005
5006 let piece = vector.slice(1, 3).unwrap();
5007 assert_eq!(piece.form(), Form::Dictionary, "the form is the whole point");
5008 assert_eq!(piece.len(), 3);
5009 assert_eq!(
5010 piece.iter().collect::<Vec<_>>(),
5011 [
5012 Value::Varchar("blue".into()),
5013 Value::Varchar("blue".into()),
5014 Value::Varchar("red".into())
5015 ]
5016 );
5017 assert_eq!(vector.gather(&[1, 2, 3]).unwrap().form(), Form::Flat, "which a gather loses");
5018 }
5019
5020 #[test]
5021 fn slicing_a_dictionary_shares_the_dictionary_rather_than_copying_it() {
5022 // The assertion is about the address and not about the values, because the values were
5023 // right when the dictionary was copied too. A page holds one dictionary and is cut into a
5024 // chunk of codes at a time, so copying the dictionary here is a copy of every string in it
5025 // per chunk, and on a read of a ClickBench partition it was ten percent of the cycles.
5026 let values = Vector::from_values(
5027 LogicalType::Varchar,
5028 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5029 )
5030 .unwrap();
5031 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
5032 let Body::Dictionary { values: whole, .. } = &vector.body else {
5033 panic!("a dictionary vector holds a dictionary");
5034 };
5035
5036 let piece = vector.slice(1, 3).unwrap();
5037 let Body::Dictionary { codes, values: cut, .. } = &piece.body else {
5038 panic!("a slice of a dictionary is a dictionary");
5039 };
5040 assert!(Arc::ptr_eq(whole, cut), "the cut copied the dictionary");
5041 assert_eq!(codes.as_slice(), &[1, 1, 0], "the codes are the part that is cut");
5042
5043 // And a cut of a cut shares it too, since that is what a scan does to a page it reads twice.
5044 let again = piece.slice(1, 2).unwrap();
5045 let Body::Dictionary { values: cut, .. } = &again.body else {
5046 panic!("a slice of a slice of a dictionary is a dictionary");
5047 };
5048 assert!(Arc::ptr_eq(whole, cut), "the second cut copied the dictionary");
5049 assert_eq!(
5050 again.iter().collect::<Vec<_>>(),
5051 [Value::Varchar("blue".into()), Value::Varchar("red".into())]
5052 );
5053 }
5054
5055 /// A parent column read for a link join, and the copy per chunk that not paging it was.
5056 ///
5057 /// The path is the one a kernel takes. A link join emits [`Body::Gathered`] over the parent and
5058 /// reads nothing, and the kernel that first wants the values flattens it, which is where the
5059 /// arena is either taken by handle or copied out of. The arena was already behind an `Arc`
5060 /// before this and every flatten still copied every byte it reached, because the question
5061 /// [`Buffer::is_shared`] answers is about the store inside the `Arc` rather than the `Arc`. On
5062 /// TPC-H q12 that was fourteen hundred copies a query out of a column of five distinct values.
5063 #[test]
5064 fn flattening_a_gather_off_a_paged_parent_takes_the_arena_rather_than_copying_it() {
5065 let arena = Arc::new(Buffer::from_vec(b"1-URGENT2-HIGH".to_vec()));
5066 let views = vec![
5067 StringView::over(b"1-URGENT", 0),
5068 StringView::over(b"2-HIGH", 8),
5069 StringView::over(b"1-URGENT", 0),
5070 ];
5071 let built = Vector::string_views(LogicalType::Varchar, views, arena).unwrap();
5072 let owned = match &built.body {
5073 Body::Views { arena, .. } => arena.is_shared(),
5074 _ => panic!("string views are a views body"),
5075 };
5076 assert!(!owned, "concat builds an arena rather than reading one, so it starts owned");
5077
5078 let bytes = |vector: &Vector| match &vector.body {
5079 Body::Views { arena, .. } => arena.as_slice().as_ptr() as usize,
5080 Body::Flat(Data::Varlen(column)) => column.arena().as_ptr() as usize,
5081 _ => panic!("a string vector holds string bytes"),
5082 };
5083 let gathered = |parent: &Vector| {
5084 Vector::gathered(Arc::new(parent.clone()), Arc::new(vec![1, 0])).unwrap()
5085 };
5086
5087 // Built again rather than cloned, because a clone would be a second holder of the arena and
5088 // paging would decline it, which is the case the test below this one is about.
5089 let paged = Vector::string_views(
5090 LogicalType::Varchar,
5091 built.shared_views().unwrap().0.to_vec(),
5092 Arc::new(Buffer::from_vec(b"1-URGENT2-HIGH".to_vec())),
5093 )
5094 .unwrap()
5095 .into_pages();
5096 assert_eq!(
5097 bytes(&gathered(&paged).flatten().unwrap()),
5098 bytes(&paged),
5099 "a flatten off a page shares the arena"
5100 );
5101 assert_ne!(
5102 bytes(&gathered(&built).flatten().unwrap()),
5103 bytes(&built),
5104 "and off an owned arena it copies, which is what this changed"
5105 );
5106 assert_eq!(
5107 gathered(&paged).flatten().unwrap().iter().collect::<Vec<_>>(),
5108 [Value::Varchar("2-HIGH".into()), Value::Varchar("1-URGENT".into())]
5109 );
5110 }
5111
5112 /// An arena somebody else is still holding is left as it was, because the only way to page it
5113 /// would be to copy it and a copy is the thing the caller asked not to pay for.
5114 #[test]
5115 fn paging_a_string_column_whose_arena_has_another_holder_leaves_it_alone() {
5116 let arena = Arc::new(Buffer::from_vec(b"red".to_vec()));
5117 let vector =
5118 Vector::string_views(LogicalType::Varchar, vec![StringView::over(b"red", 0)], arena)
5119 .unwrap();
5120 // The clone is the other holder: both vectors point at the one arena.
5121 let paged = vector.clone().into_pages();
5122 match &paged.body {
5123 Body::Views { arena, .. } => assert!(!arena.is_shared(), "it was not ours to move"),
5124 _ => panic!("string views are a views body"),
5125 }
5126 assert_eq!(paged.iter().collect::<Vec<_>>(), [Value::Varchar("red".into())]);
5127 }
5128
5129 /// Once the codes are a page, a cut and a clone of a coded column point at the same codes, which
5130 /// is what a scan does to every page of a dictionary encoded Parquet column.
5131 #[test]
5132 fn a_paged_dictionary_shares_its_codes_with_its_cuts_and_clones() {
5133 let values = Vector::from_values(
5134 LogicalType::Varchar,
5135 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5136 )
5137 .unwrap();
5138 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap().into_pages();
5139 let codes = |vector: &Vector| match &vector.body {
5140 Body::Dictionary { codes, .. } => codes.as_slice().as_ptr() as usize,
5141 _ => panic!("a dictionary vector holds a dictionary"),
5142 };
5143 assert_eq!(codes(&vector.slice(1, 3).unwrap()), codes(&vector) + 4, "the cut copied");
5144 assert_eq!(codes(&vector.clone()), codes(&vector), "the clone copied");
5145 assert_eq!(
5146 vector.slice(1, 3).unwrap().iter().collect::<Vec<_>>(),
5147 [
5148 Value::Varchar("blue".into()),
5149 Value::Varchar("blue".into()),
5150 Value::Varchar("red".into())
5151 ]
5152 );
5153 }
5154
5155 #[test]
5156 fn a_slice_carries_the_nulls_that_were_in_its_range_and_not_the_others() {
5157 let vector =
5158 integers(&[1, 2, 3, 4]).with_validity(Validity::from_run(&[false, true, false, true]));
5159 let piece = vector.slice(1, 2).unwrap();
5160 assert!(piece.validity().is_valid(0));
5161 assert!(!piece.validity().is_valid(1));
5162 assert_eq!(piece.value_at(1), Value::Null);
5163 }
5164
5165 #[test]
5166 fn slicing_a_sequence_moves_its_start_rather_than_writing_the_values_out() {
5167 let vector = Vector::sequence(100, 5, 10);
5168 let piece = vector.slice(3, 4).unwrap();
5169 assert_eq!(piece.form(), Form::Sequence);
5170 assert_eq!(
5171 piece.iter().collect::<Vec<_>>(),
5172 [Value::BigInt(115), Value::BigInt(120), Value::BigInt(125), Value::BigInt(130)]
5173 );
5174 }
5175
5176 #[test]
5177 fn slicing_a_constant_is_a_shorter_constant() {
5178 let vector = Vector::constant(LogicalType::Integer, Value::Integer(9), 8);
5179 let piece = vector.slice(2, 3).unwrap();
5180 assert_eq!(piece.form(), Form::Constant);
5181 assert_eq!(piece.len(), 3);
5182 assert_eq!(piece.value_at(2), Value::Integer(9));
5183 }
5184
5185 #[test]
5186 fn slicing_the_whole_vector_hands_it_back_as_it_was() {
5187 let vector = integers(&[1, 2, 3]);
5188 assert_eq!(
5189 vector.slice(0, 3).unwrap().iter().collect::<Vec<_>>(),
5190 [Value::Integer(1), Value::Integer(2), Value::Integer(3)]
5191 );
5192 }
5193
5194 #[test]
5195 fn cutting_a_flat_body_answers_what_gathering_the_same_rows_answers() {
5196 // The cut of a flat body used to be written as a gather over the positions in the range,
5197 // and it is now a run copied out, so the two have to keep saying the same thing. Every
5198 // start and every length, with nulls in the range and out of it, since the validity is the
5199 // half of this that changed shape.
5200 let rows: Vec<i32> = (0..70).collect();
5201 let valid: Vec<bool> = (0..70).map(|row| row % 7 != 0 && row % 11 != 3).collect();
5202 let vector = integers(&rows).with_validity(Validity::from_run(&valid));
5203 for at in 0..70usize {
5204 for len in 0..=(70 - at) {
5205 let cut = vector.slice(at, len).unwrap();
5206 let positions: Vec<u32> = (at..at + len).map(|row| row as u32).collect();
5207 let gathered = vector.gather(&positions).unwrap();
5208 assert_eq!(cut.len(), len, "rows {at} to {}", at + len);
5209 assert_eq!(
5210 cut.iter().collect::<Vec<_>>(),
5211 gathered.iter().collect::<Vec<_>>(),
5212 "rows {at} to {}",
5213 at + len
5214 );
5215 }
5216 }
5217 }
5218
5219 /// The flat body used to be the one form of a vector whose cut cost an allocation and a copy,
5220 /// and it is not any more when its buffer is a run inside a page. Asserted on the address,
5221 /// because the values are the same either way and the address is the whole claim.
5222 #[test]
5223 fn cutting_a_flat_body_over_a_page_does_not_copy_it() {
5224 let page = Arc::new((0i64..64).collect::<Vec<_>>());
5225 let address = page.as_ptr() as usize;
5226 let data = Data::Int64(Buffer::from_arc(Arc::clone(&page)));
5227 let vector = Vector::flat(LogicalType::BigInt, data).unwrap();
5228 let cut = vector.slice(16, 8).unwrap();
5229 assert_eq!(cut.form(), Form::Flat);
5230 assert_eq!(cut.len(), 8);
5231 let Some(Data::Int64(run)) = cut.data() else {
5232 panic!("the layout changed under the test")
5233 };
5234 assert!(run.is_shared(), "the cut copied the run out of the page");
5235 assert_eq!(run.as_slice().as_ptr() as usize, address + 16 * 8);
5236 assert_eq!(run.as_slice(), &(16i64..24).collect::<Vec<_>>()[..]);
5237 assert_eq!(cut.value_at(0), Value::BigInt(16));
5238 // And the same cut of an owned run says the same thing, by copying it.
5239 let owned = Vector::flat(LogicalType::BigInt, Data::Int64((0i64..64).collect())).unwrap();
5240 let copied = owned.slice(16, 8).unwrap();
5241 let Some(Data::Int64(run)) = copied.data() else {
5242 panic!("the layout changed under the test")
5243 };
5244 assert!(!run.is_shared());
5245 assert_eq!(run.as_slice(), &(16i64..24).collect::<Vec<_>>()[..]);
5246 }
5247
5248 /// `into_pages` is how a producer says its values will be handed out many times. A flat body is
5249 /// the form it changes, and after it a copy of the vector is a reference count bump.
5250 #[test]
5251 fn a_vector_over_pages_is_copied_and_cut_without_its_values_moving() {
5252 let vector = integers(&[1, 2, 3, 4, 5, 6, 7, 8]).into_pages();
5253 let address = |vector: &Vector| match vector.data() {
5254 Some(Data::Int32(values)) => values.as_slice().as_ptr() as usize,
5255 _ => panic!("the layout changed under the test"),
5256 };
5257 let stored = address(&vector);
5258 assert_eq!(address(&vector.clone()), stored, "a copy moved the values");
5259 assert_eq!(address(&vector.slice(2, 4).unwrap()), stored + 2 * 4, "a cut moved the values");
5260 assert_eq!(
5261 vector.slice(2, 4).unwrap().iter().collect::<Vec<_>>(),
5262 [Value::Integer(3), Value::Integer(4), Value::Integer(5), Value::Integer(6)]
5263 );
5264 // Twice is not two pages.
5265 assert_eq!(address(&vector.clone().into_pages()), stored);
5266 }
5267
5268 /// A cut, a gather and a flatten of a string column over a page all move views and no bytes.
5269 ///
5270 /// This is the string half of the paging that `a_vector_over_pages_is_copied_and_cut_without_
5271 /// its_values_moving` checks for a fixed width column, and it is worth its own test because a
5272 /// string column is two allocations rather than one: the cut that matters is the payload
5273 /// staying where it is while the views move.
5274 #[test]
5275 fn a_string_column_over_a_page_is_cut_and_gathered_without_its_payload_moving() {
5276 let long = ["the first of the long strings", "the second one", "and a third long one here"];
5277 let mut built = StringColumn::with_capacity(long.len());
5278 for text in long {
5279 built.push(text);
5280 }
5281 let vector = Vector::flat(LogicalType::Varchar, Data::Varlen(built.into_page())).unwrap();
5282 let payload = |vector: &Vector| match vector.data() {
5283 Some(Data::Varlen(column)) => column.arena().as_ptr() as usize,
5284 _ => panic!("the layout changed under the test"),
5285 };
5286 let stored = payload(&vector);
5287 let cut = vector.slice(1, 2).unwrap();
5288 assert_eq!(payload(&cut), stored, "a cut moved the payload");
5289 assert_eq!(cut.text_at(0), Some(long[1]));
5290 assert_eq!(cut.text_at(1), Some(long[2]));
5291 let gathered = vector.gather(&[2, 0]).unwrap();
5292 assert_eq!(payload(&gathered), stored, "a gather moved the payload");
5293 assert_eq!(gathered.text_at(0), Some(long[2]));
5294 assert_eq!(gathered.text_at(1), Some(long[0]));
5295 // And the same column with its own arena still copies, because sharing an owned arena
5296 // means cloning every byte of it including the bytes nobody asked for.
5297 let mut owned = StringColumn::with_capacity(long.len());
5298 for text in long {
5299 owned.push(text);
5300 }
5301 let held = Vector::flat(LogicalType::Varchar, Data::Varlen(owned)).unwrap();
5302 let copied = held.slice(1, 2).unwrap();
5303 assert_ne!(payload(&copied), payload(&held), "an owned payload was shared");
5304 assert_eq!(copied.text_at(0), Some(long[1]));
5305 }
5306
5307 /// A flatten gives up the form and not the sharing. The views form is already views over an
5308 /// arena, so flattening one over a page is the views and nothing else, and the flat column
5309 /// that comes out reads the same strings out of the same bytes.
5310 #[test]
5311 fn flattening_string_views_over_a_page_keeps_the_page() {
5312 let mut built = StringColumn::with_capacity(2);
5313 built.push("a string too long to sit inside a view");
5314 built.push("another string that is also too long");
5315 let (views, arena) = built.into_page().into_parts();
5316 let stored = arena.as_slice().as_ptr() as usize;
5317 let vector = Vector::string_views(LogicalType::Varchar, views, Arc::new(arena)).unwrap();
5318 assert_eq!(vector.form(), Form::StringView);
5319 let flat = vector.flatten().unwrap();
5320 assert_eq!(flat.form(), Form::Flat);
5321 let Some(Data::Varlen(column)) = flat.data() else {
5322 panic!("the layout changed under the test")
5323 };
5324 assert_eq!(column.arena().as_ptr() as usize, stored, "the flatten moved the payload");
5325 assert_eq!(flat.text_at(0), Some("a string too long to sit inside a view"));
5326 assert_eq!(flat.text_at(1), Some("another string that is also too long"));
5327 }
5328
5329 /// Every form that is not flat already shares what is expensive, so this is a no op on them and
5330 /// in particular does not flatten anything. A form that came back flat would be a column that
5331 /// lost its encoding on the way into a table.
5332 #[test]
5333 fn putting_a_vector_on_pages_does_not_change_any_other_form() {
5334 let dictionary = Vector::dictionary(
5335 vec![0, 1, 0, 1],
5336 Vector::from_values(
5337 LogicalType::Varchar,
5338 &[Value::Varchar("a".into()), Value::Varchar("b".into())],
5339 )
5340 .unwrap(),
5341 )
5342 .unwrap();
5343 let cases = [
5344 Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
5345 Vector::sequence(4, 0, 1),
5346 dictionary,
5347 ];
5348 for vector in cases {
5349 let form = vector.form();
5350 let paged = vector.clone().into_pages();
5351 assert_eq!(paged.form(), form, "{form:?} changed form");
5352 assert_eq!(paged.iter().collect::<Vec<_>>(), vector.iter().collect::<Vec<_>>());
5353 }
5354 }
5355
5356 #[test]
5357 fn cutting_a_flat_string_column_answers_what_gathering_it_answers() {
5358 // The string layout is the one whose cut is still a loop, and it is also the one where a
5359 // row is a view into an arena rather than a slot, so it gets the same treatment separately.
5360 // Both inline and out of line strings, since they are copied by different paths.
5361 let rows: Vec<String> =
5362 (0..40).map(|row| "x".repeat(row % 30) + &row.to_string()).collect();
5363 let values: Vec<Value> = rows.iter().map(|row| Value::Varchar(row.clone())).collect();
5364 let vector = Vector::from_values(LogicalType::Varchar, &values).unwrap().flatten().unwrap();
5365 assert_eq!(vector.form(), Form::Flat, "the cut under test is the flat one");
5366 for at in 0..40usize {
5367 for len in 0..=(40 - at) {
5368 let cut = vector.slice(at, len).unwrap();
5369 let positions: Vec<u32> = (at..at + len).map(|row| row as u32).collect();
5370 let gathered = vector.gather(&positions).unwrap();
5371 assert_eq!(
5372 cut.iter().collect::<Vec<_>>(),
5373 gathered.iter().collect::<Vec<_>>(),
5374 "rows {at} to {}",
5375 at + len
5376 );
5377 }
5378 }
5379 }
5380
5381 #[test]
5382 fn a_slice_past_the_end_is_an_error_rather_than_a_short_vector() {
5383 let error = integers(&[1, 2, 3]).slice(2, 2).unwrap_err();
5384 assert!(error.to_string().contains("of a vector of 3"), "{error}");
5385 }
5386
5387 #[test]
5388 fn the_vector_size_is_the_one_the_design_is_built_around() {
5389 // 8192, which is four times DuckDB's 2048, measured in #480 against 1024, 2048, 4096 and
5390 // 32768. What the rest of the code assumes about it is not the value but the shape: a
5391 // multiple of 1024, which is the FastLanes unit and is what makes a validity mask a whole
5392 // number of u64 words with none of them half used.
5393 assert_eq!(VECTOR_SIZE, 8192);
5394 assert_eq!(VECTOR_SIZE % 1024, 0);
5395 assert_eq!(VECTOR_SIZE % 64, 0);
5396 assert_eq!(VECTOR_SIZE / 64, 128, "the words in a validity mask");
5397 }
5398
5399 #[test]
5400 fn a_flat_vector_reads_back_what_was_put_in_it() {
5401 let vector = integers(&[1, 2, 3]);
5402 assert_eq!(vector.form(), Form::Flat);
5403 assert_eq!(vector.len(), 3);
5404 assert_eq!(vector.value_at(1), Value::Integer(2));
5405 assert_eq!(
5406 vector.iter().collect::<Vec<_>>(),
5407 vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
5408 );
5409 }
5410
5411 #[test]
5412 fn a_vector_built_from_values_reads_the_same_values_back() {
5413 let vector = Vector::from_values(
5414 LogicalType::Varchar,
5415 &[
5416 Value::Varchar("a".to_string()),
5417 Value::Null,
5418 Value::Varchar("a string too long to sit inside a view".to_string()),
5419 ],
5420 )
5421 .expect("strings and a null");
5422 assert_eq!(vector.len(), 3);
5423 assert_eq!(vector.value_at(0), Value::Varchar("a".to_string()));
5424 assert_eq!(vector.value_at(1), Value::Null);
5425 assert_eq!(
5426 vector.value_at(2),
5427 Value::Varchar("a string too long to sit inside a view".to_string())
5428 );
5429 }
5430
5431 /// A null still occupies a position. If it did not then every value after it would read back
5432 /// one place to the left, which is the kind of bug that looks like a storage bug for a week.
5433 #[test]
5434 fn a_null_in_the_middle_does_not_move_the_values_after_it() {
5435 let vector = Vector::from_values(
5436 LogicalType::Integer,
5437 &[Value::Integer(1), Value::Null, Value::Integer(3)],
5438 )
5439 .expect("integers and a null");
5440 assert_eq!(vector.value_at(2), Value::Integer(3));
5441 assert!(vector.validity().has_nulls(3), "the middle one is null");
5442 }
5443
5444 #[test]
5445 fn a_value_the_type_cannot_hold_is_refused() {
5446 let wrong = Vector::from_values(LogicalType::Integer, &[Value::Varchar("x".to_string())]);
5447 assert!(wrong.is_err(), "a string is not an integer");
5448 }
5449
5450 #[test]
5451 fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
5452 // One comparison here against a wrong answer read out three layers later.
5453 let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1].into()));
5454 assert!(wrong.is_err());
5455 let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1].into()));
5456 assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
5457 }
5458
5459 #[test]
5460 fn a_constant_vector_costs_one_value_whatever_its_length() {
5461 let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
5462 assert_eq!(vector.form(), Form::Constant);
5463 assert_eq!(vector.len(), VECTOR_SIZE);
5464 assert_eq!(vector.value_at(0), Value::Integer(7));
5465 assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
5466 assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
5467 }
5468
5469 #[test]
5470 fn a_constant_null_is_all_invalid_without_being_told() {
5471 let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
5472 assert_eq!(vector.validity(), &Validity::AllInvalid);
5473 assert_eq!(vector.value_at(3), Value::Null);
5474 }
5475
5476 #[test]
5477 fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
5478 let vector = Vector::sequence(100, 1, VECTOR_SIZE);
5479 assert_eq!(vector.form(), Form::Sequence);
5480 assert_eq!(vector.value_at(0), Value::BigInt(100));
5481 assert_eq!(vector.value_at(923), Value::BigInt(1023));
5482 let stepped = Vector::sequence(0, 5, 4);
5483 assert_eq!(
5484 stepped.iter().collect::<Vec<_>>(),
5485 vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
5486 );
5487 }
5488
5489 #[test]
5490 fn a_dictionary_vector_reads_through_its_codes() {
5491 let mut column = StringColumn::new();
5492 column.push("red");
5493 column.push("green");
5494 let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
5495 let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
5496 assert_eq!(vector.form(), Form::Dictionary);
5497 assert_eq!(vector.logical_type(), &LogicalType::Varchar);
5498 assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
5499 assert_eq!(vector.len(), 4);
5500 }
5501
5502 /// The accessor a group by keys a string column through, which has to agree with `value_at` on
5503 /// every position or two rows holding one string end up in two groups.
5504 #[test]
5505 fn text_is_read_where_it_already_is_for_the_forms_that_store_it() {
5506 let mut column = StringColumn::new();
5507 column.push("red");
5508 column.push("green");
5509 column.push("");
5510 let flat = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
5511 for index in 0..flat.len() {
5512 assert_eq!(flat.text_at(index).map(str::to_string), text_of(&flat.value_at(index)));
5513 }
5514 let dictionary = Vector::dictionary(vec![1, 0, 1, 2], flat).unwrap();
5515 for index in 0..dictionary.len() {
5516 assert_eq!(
5517 dictionary.text_at(index).map(str::to_string),
5518 text_of(&dictionary.value_at(index))
5519 );
5520 }
5521 assert_eq!(dictionary.text_at(4), None, "past the end");
5522 }
5523
5524 /// The forms and types that have no text to hand back, which a caller answers by falling back
5525 /// to `value_at`. A blob is the one that would be a correctness bug rather than a slow path,
5526 /// since its bytes are not required to be text and it is not a `VARCHAR` either way.
5527 #[test]
5528 fn text_is_refused_where_it_is_not_stored_as_itself() {
5529 let nulls =
5530 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into()), Value::Null])
5531 .unwrap();
5532 assert_eq!(nulls.text_at(0), Some("red"));
5533 assert_eq!(nulls.text_at(1), None, "a null has no text");
5534 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("red".into()), 3);
5535 assert_eq!(constant.text_at(0), None, "a constant is not stored per position");
5536 assert_eq!(integers(&[1, 2]).text_at(0), None, "an integer is not text");
5537 let mut bytes = StringColumn::new();
5538 bytes.push("red");
5539 let blob = Vector::flat(LogicalType::Blob, Data::Varlen(bytes)).unwrap();
5540 assert_eq!(blob.text_at(0), None, "a blob is not a varchar");
5541 }
5542
5543 /// The accessor a group by keys an integer column through, which has to agree with `value_at`
5544 /// on every position or two rows holding one number end up in two groups.
5545 #[test]
5546 fn a_signed_integer_is_read_where_it_already_is_for_the_forms_that_store_it() {
5547 let flat = integers(&[7, -3, 0, 2]);
5548 for index in 0..flat.len() {
5549 assert_eq!(flat.signed_at(index), signed_of(&flat.value_at(index)), "flat {index}");
5550 }
5551 let dictionary = Vector::dictionary(vec![1, 0, 3, 2], flat).unwrap();
5552 for index in 0..dictionary.len() {
5553 assert_eq!(
5554 dictionary.signed_at(index),
5555 signed_of(&dictionary.value_at(index)),
5556 "dictionary {index}"
5557 );
5558 }
5559 assert_eq!(dictionary.signed_at(4), None, "past the end");
5560
5561 let runs = Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap();
5562 for index in 0..runs.len() {
5563 assert_eq!(runs.signed_at(index), signed_of(&runs.value_at(index)), "run {index}");
5564 }
5565 let constant = Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3);
5566 assert_eq!(constant.signed_at(2), Some(11));
5567 let sequence = Vector::sequence(100, 5, 4);
5568 for index in 0..sequence.len() {
5569 assert_eq!(
5570 sequence.signed_at(index),
5571 signed_of(&sequence.value_at(index)),
5572 "sequence {index}"
5573 );
5574 }
5575 }
5576
5577 /// A window of a shared page packs exactly when the same rows owned would, and a range its
5578 /// type cannot hold at the width it needs stays flat rather than failing. A load of ClickBench
5579 /// `hits` hit both: its windows were judged by their share of the page, packed at 32 bits, and
5580 /// the packed form refused a range that ran past `i32::MAX`.
5581 #[test]
5582 fn a_window_of_a_page_packs_the_way_the_same_rows_owned_do() {
5583 let wide: Vec<i32> = (0..122_880)
5584 .map(|at| if at % 2 == 0 { i32::MIN + 5 + at } else { i32::MAX - 9 - at })
5585 .collect();
5586 let narrow: Vec<i32> = (0..122_880).map(|at| 1_000 + at % 200).collect();
5587 for values in [wide, narrow] {
5588 let page = integers(&values).into_pages();
5589 let window = page.slice(0, 8_192).unwrap();
5590 let owned = integers(&values[..8_192]);
5591 let packed_window = window.bit_packed().unwrap();
5592 let packed_owned = owned.bit_packed().unwrap();
5593 assert_eq!(
5594 packed_window.packed_parts().is_some(),
5595 packed_owned.packed_parts().is_some()
5596 );
5597 for at in [0, 1, 4_095, 8_191] {
5598 assert_eq!(packed_window.value_at(at), owned.value_at(at));
5599 }
5600 }
5601 }
5602
5603 /// The forms and types that have no integer to hand back, which a caller answers by falling
5604 /// back to `value_at`.
5605 #[test]
5606 fn a_signed_integer_is_refused_where_it_is_not_stored_as_itself() {
5607 let nulls =
5608 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
5609 assert_eq!(nulls.signed_at(0), Some(4));
5610 assert_eq!(nulls.signed_at(1), None, "a null is not a number");
5611 let packed = integers(&[1, 2, 3, 1]).bit_packed().unwrap();
5612 assert_eq!(packed.signed_at(0), Some(1), "a packed integer is read in code space");
5613 let mut bytes = StringColumn::new();
5614 bytes.push("red");
5615 let text = Vector::flat(LogicalType::Varchar, Data::Varlen(bytes)).unwrap();
5616 assert_eq!(text.signed_at(0), None, "a string is not a number");
5617 let double = Vector::flat(LogicalType::Double, Data::Float64(vec![1.5].into())).unwrap();
5618 assert_eq!(double.signed_at(0), None, "a double is not a signed integer");
5619 }
5620
5621 /// The block form has to agree with the row at a time form on every position of every shape it
5622 /// answers for, because a caller picks one of the two and a group by that read two different
5623 /// numbers for one row would put that row in two groups.
5624 #[test]
5625 fn a_block_of_signed_integers_holds_what_the_row_at_a_time_accessor_hands_back() {
5626 let mut out = Vec::new();
5627 let shapes = [
5628 integers(&[7, -3, 0, 2]),
5629 Vector::flat(LogicalType::Integer, Data::Int32(vec![5, -6, 7].into())).unwrap(),
5630 Vector::flat(LogicalType::SmallInt, Data::Int16(vec![1, -2].into())).unwrap(),
5631 Vector::flat(LogicalType::TinyInt, Data::Int8(vec![-128, 127].into())).unwrap(),
5632 Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3),
5633 Vector::sequence(100, 5, 4),
5634 integers(&[1, 2, 3, 1]).bit_packed().unwrap(),
5635 ];
5636 for column in &shapes {
5637 assert!(column.signed_block(&mut out), "{:?} hands over a block", column.form());
5638 assert_eq!(out.len(), column.len(), "{:?} filled the whole chunk", column.form());
5639 for (index, &held) in out.iter().enumerate() {
5640 assert_eq!(
5641 Some(i128::from(held)),
5642 column.signed_at(index),
5643 "{:?} at {index}",
5644 column.form()
5645 );
5646 }
5647 }
5648 }
5649
5650 /// What the block form will not answer for, where the caller reads the vector a row at a time
5651 /// instead. A null is not one of them: it writes whatever sits under it and the caller reads the
5652 /// null from the column.
5653 #[test]
5654 fn a_block_is_refused_for_the_shapes_it_would_have_to_gather_or_widen() {
5655 let mut out = Vec::new();
5656 let flat = integers(&[7, -3, 0, 2]);
5657 assert!(!Vector::dictionary(vec![1, 0], flat.clone()).unwrap().signed_block(&mut out));
5658 assert!(!Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap().signed_block(&mut out));
5659 let wide = Vector::flat(LogicalType::HugeInt, Data::Int128(vec![1, 2].into())).unwrap();
5660 assert!(!wide.signed_block(&mut out), "a hugeint does not fit sixty four bits");
5661 let double = Vector::flat(LogicalType::Double, Data::Float64(vec![1.5].into())).unwrap();
5662 assert!(!double.signed_block(&mut out), "a double is not a signed integer");
5663 assert!(out.is_empty(), "a refusal leaves the buffer empty");
5664
5665 let nulls =
5666 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
5667 assert!(nulls.signed_block(&mut out), "a flat column with nulls still hands over");
5668 assert_eq!(out[0], 4);
5669 }
5670
5671 /// Asked once for a chunk, and it has to agree with `is_null_at` asked for every row of it.
5672 #[test]
5673 fn a_vector_says_whether_it_holds_any_null_at_all() {
5674 let flat = integers(&[7, -3, 0, 2]);
5675 assert!(flat.none_null());
5676 let nulls =
5677 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
5678 assert!(!nulls.none_null());
5679 assert!(Vector::dictionary(vec![1, 0], flat.clone()).unwrap().none_null());
5680 // The null is in the dictionary rather than in the mask, which is the case the row at a time
5681 // form reads through for and the reason this one does too.
5682 let holed = Vector::dictionary(vec![0, 0], nulls.clone()).unwrap();
5683 assert!(!holed.none_null(), "a dictionary is read through to its values");
5684 assert!(!holed.is_null_at(0), "and no code points at the null it holds");
5685 assert!(Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap().none_null());
5686 assert!(!Vector::runs(vec![1, 2], nulls).unwrap().none_null());
5687 assert!(Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3).none_null());
5688 assert!(!Vector::constant(LogicalType::BigInt, Value::Null, 3).none_null());
5689 }
5690
5691 /// The integer of a value, for comparing `signed_at` against `value_at` position by position.
5692 fn signed_of(value: &Value) -> Option<i128> {
5693 match value {
5694 Value::TinyInt(x) => Some(i128::from(*x)),
5695 Value::SmallInt(x) => Some(i128::from(*x)),
5696 Value::Integer(x) | Value::Date(x) => Some(i128::from(*x)),
5697 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => Some(i128::from(*x)),
5698 Value::HugeInt(x) | Value::Decimal { unscaled: x, .. } => Some(*x),
5699 _ => None,
5700 }
5701 }
5702
5703 /// The text of a value, for comparing `text_at` against `value_at` position by position.
5704 fn text_of(value: &Value) -> Option<String> {
5705 match value {
5706 Value::Varchar(text) => Some(text.clone()),
5707 _ => None,
5708 }
5709 }
5710
5711 #[test]
5712 fn a_dictionary_code_past_the_end_is_refused() {
5713 // The alternative is a silent read of the wrong value, which is the failure mode the
5714 // entire M3 design has to be careful about.
5715 let values = integers(&[1, 2]);
5716 assert!(Vector::dictionary(vec![0, 2], values).is_err());
5717 // The check runs on the highest code rather than the first bad one, so it has to say that
5718 // no codes at all is fine even when there are no values for them to point at either.
5719 let empty = Vector::dictionary(Vec::new(), integers(&[])).expect("no codes, no values");
5720 assert_eq!(empty.len(), 0);
5721 // And a code of zero against an empty dictionary is still past the end.
5722 assert!(Vector::dictionary(vec![0], integers(&[])).is_err());
5723 }
5724
5725 #[test]
5726 fn every_form_flattens_to_the_same_values_it_reads_out() {
5727 // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
5728 // miniature and long before there is an encoded kernel to point it at. A form that reads
5729 // out one way and flattens another is the exact bug that testing exists to catch.
5730 let mut column = StringColumn::new();
5731 column.push("alpha");
5732 column.push("beta");
5733 let dictionary = Vector::dictionary(
5734 vec![1, 0, 1],
5735 Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
5736 )
5737 .unwrap();
5738 let cases = [
5739 Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
5740 Vector::sequence(7, -2, 5),
5741 dictionary,
5742 ];
5743 for vector in cases {
5744 let flat = vector.flatten().unwrap();
5745 assert_eq!(flat.form(), Form::Flat);
5746 assert_eq!(flat.len(), vector.len());
5747 for index in 0..vector.len() {
5748 assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
5749 }
5750 }
5751 }
5752
5753 #[test]
5754 fn a_null_still_occupies_a_position_after_flattening() {
5755 // The reason push_value writes a zero for a null rather than skipping it. A run of data
5756 // with a hole in it puts every value after the hole in the wrong place, and the validity
5757 // mask is what says the position is null.
5758 let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
5759 let flat = vector.flatten().unwrap();
5760 assert_eq!(flat.value_at(0), Value::BigInt(0));
5761 assert_eq!(flat.value_at(1), Value::Null);
5762 assert_eq!(flat.value_at(2), Value::BigInt(2));
5763 assert_eq!(flat.value_at(3), Value::BigInt(3));
5764 }
5765
5766 /// A dictionary holds its nulls in the vector it points at, so its own validity is all valid
5767 /// and reading that instead of the values turns a null into whatever zero means for the type.
5768 /// A filter over a nullable column produces exactly this vector, so the bug reaches a result
5769 /// set as `LEFT JOIN` padding that comes back as zeros.
5770 #[test]
5771 fn a_null_behind_a_dictionary_survives_flattening() {
5772 let values =
5773 Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
5774 let dictionary = Vector::dictionary(vec![1, 0, 1], values).unwrap();
5775 let flat = dictionary.flatten().unwrap();
5776 assert_eq!(flat.value_at(0), Value::Null);
5777 assert_eq!(flat.value_at(1), Value::Integer(3));
5778 assert_eq!(flat.value_at(2), Value::Null);
5779 }
5780
5781 /// The property that makes `gather` usable at all: it has to be the same function as reading the
5782 /// wanted positions one at a time, over every form, or compaction changes answers.
5783 #[test]
5784 fn gathering_reads_what_reading_one_position_at_a_time_reads() {
5785 let mut column = StringColumn::new();
5786 column.push("alpha");
5787 column.push("beta");
5788 column.push("gamma");
5789 let cases = [
5790 integers(&[10, 20, 30, 40]),
5791 integers(&[10, 20, 30, 40]).with_validity(Validity::from_iter(4, |i| i != 2)),
5792 Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
5793 Vector::sequence(100, -7, 4),
5794 Vector::sequence(100, -7, 4).with_validity(Validity::from_iter(4, |i| i % 2 == 0)),
5795 Vector::dictionary(
5796 vec![2, 0, 1, 2],
5797 Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
5798 )
5799 .unwrap(),
5800 Vector::dictionary(
5801 vec![1, 0, 1, 0],
5802 Vector::from_values(LogicalType::Integer, &[Value::Integer(5), Value::Null])
5803 .unwrap(),
5804 )
5805 .unwrap(),
5806 ];
5807 let wanted = [3_u32, 0, 2, 2, 1];
5808 for vector in cases {
5809 let gathered = vector.gather(&wanted).unwrap();
5810 assert_eq!(gathered.len(), wanted.len());
5811 assert_eq!(gathered.logical_type(), vector.logical_type());
5812 for (slot, &index) in wanted.iter().enumerate() {
5813 assert_eq!(
5814 gathered.value_at(slot),
5815 vector.value_at(index as usize),
5816 "slot {slot} of {:?}",
5817 vector.form()
5818 );
5819 }
5820 }
5821 }
5822
5823 /// A gather past the end is not an error, because the selection that produced the indices is
5824 /// checked by its caller and the one thing that must not happen here is a read of the wrong
5825 /// value. An index nothing answers is null, which is what an outer join pad needs anyway.
5826 #[test]
5827 fn gathering_a_position_that_is_not_there_is_a_null_and_not_a_wrong_value() {
5828 let vector = integers(&[1, 2, 3]);
5829 let gathered = vector.gather(&[2, 9]).unwrap();
5830 assert_eq!(gathered.value_at(0), Value::Integer(3));
5831 assert_eq!(gathered.value_at(1), Value::Null);
5832 }
5833
5834 /// The vector with nothing in it at all, which is what an untyped `NULL` is stored as. Every
5835 /// position asked for is past its end, so the answer is nulls and the length has to be the
5836 /// length that was asked for rather than the length that was there.
5837 #[test]
5838 fn gathering_from_a_vector_of_no_values_is_that_many_nulls() {
5839 let vector = Vector::flat(LogicalType::Null, Data::Empty).unwrap();
5840 let gathered = vector.gather(&[0, 1, 2]).unwrap();
5841 assert_eq!(gathered.len(), 3);
5842 assert_eq!(gathered.value_at(0), Value::Null);
5843 assert_eq!(gathered.value_at(2), Value::Null);
5844 }
5845
5846 /// Every position holds the same value, so a gather with no hole in it has nothing to copy and
5847 /// the result is the constant again rather than a run of a thousand copies of it.
5848 #[test]
5849 fn gathering_a_constant_stays_a_constant() {
5850 let vector = Vector::constant(LogicalType::Integer, Value::Integer(4), 100);
5851 let gathered = vector.gather(&[7, 7, 99]).unwrap();
5852 assert_eq!(gathered.form(), Form::Constant);
5853 assert_eq!(gathered.len(), 3);
5854 assert_eq!(gathered.value_at(2), Value::Integer(4));
5855 }
5856
5857 /// A dictionary over a dictionary is what a second filter over an already filtered chunk builds,
5858 /// and the gather has to walk to the bottom of that chain rather than one step down it. The
5859 /// constructor composes the ordinary chain away, so the one built here is the kind it cannot,
5860 /// which is a level holding nulls of its own.
5861 #[test]
5862 fn gathering_walks_a_dictionary_over_a_dictionary_to_the_values() {
5863 let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9]))
5864 .unwrap()
5865 .with_validity(Validity::from_iter(3, |index| index != 2));
5866 let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
5867 let gathered = outer.gather(&[0, 1]).unwrap();
5868 assert_eq!(gathered.form(), Form::Flat);
5869 assert_eq!(gathered.value_at(0), Value::Integer(8));
5870 assert_eq!(gathered.value_at(1), Value::Null);
5871 }
5872
5873 /// Two filters over one chunk build a dictionary over a dictionary, four conjuncts pushed down
5874 /// separately build four levels of it, and every level is a dependent load on every later read
5875 /// of every row plus a code array that cannot be freed. Composing at construction is one pass
5876 /// over the codes the range check was walking anyway.
5877 #[test]
5878 fn a_dictionary_over_a_dictionary_is_composed_into_one_level() {
5879 let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9])).unwrap();
5880 let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
5881 let (codes, values) = outer.dictionary_parts().unwrap();
5882 assert_eq!(codes, [1, 0]);
5883 assert_eq!(values.form(), Form::Flat);
5884 assert_eq!(outer.value_at(0), Value::Integer(8));
5885 assert_eq!(outer.value_at(1), Value::Integer(7));
5886 }
5887
5888 /// The invariant stated as the thing it is there for, which is that the depth does not grow with
5889 /// the number of filters. Four levels stacked one at a time are one level at the end of it.
5890 #[test]
5891 fn stacking_dictionaries_does_not_make_them_deeper() {
5892 let mut vector = integers(&[10, 20, 30, 40]);
5893 for _ in 0..4 {
5894 vector = Vector::dictionary(vec![3, 2, 1, 0], vector).unwrap();
5895 }
5896 let (codes, values) = vector.dictionary_parts().unwrap();
5897 assert_eq!(values.form(), Form::Flat);
5898 assert_eq!(codes, [0, 1, 2, 3]);
5899 assert_eq!(
5900 vector.iter().collect::<Vec<_>>(),
5901 integers(&[10, 20, 30, 40]).iter().collect::<Vec<_>>()
5902 );
5903 }
5904
5905 /// Composing has to carry the nulls down with it. The values hold them, the codes point at them,
5906 /// and a composed code that lands on a null position is still a null.
5907 #[test]
5908 fn composing_a_dictionary_keeps_the_nulls_its_values_hold() {
5909 let values =
5910 Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
5911 let inner = Vector::dictionary(vec![1, 0, 1], values).unwrap();
5912 let outer = Vector::dictionary(vec![0, 1], inner).unwrap();
5913 assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Flat);
5914 assert_eq!(outer.value_at(0), Value::Null);
5915 assert_eq!(outer.value_at(1), Value::Integer(3));
5916 }
5917
5918 /// The one level composition cannot go past. A dictionary that was given a validity of its own is
5919 /// saying its nulls are at that level rather than in the values, and pointing the outer codes
5920 /// straight at the values would read through the holes instead of stopping at them.
5921 #[test]
5922 fn a_dictionary_holding_its_own_nulls_is_not_composed_past() {
5923 let inner = Vector::dictionary(vec![0, 1, 2], integers(&[1, 2, 3]))
5924 .unwrap()
5925 .with_validity(Validity::from_iter(3, |index| index != 1));
5926 let outer = Vector::dictionary(vec![1, 2, 0], inner).unwrap();
5927 assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Dictionary);
5928 assert_eq!(outer.value_at(0), Value::Null);
5929 assert_eq!(outer.value_at(1), Value::Integer(3));
5930 assert_eq!(outer.value_at(2), Value::Integer(1));
5931 }
5932
5933 /// The difference between the two questions about nulls, which a group by got wrong. A filtered
5934 /// chunk is dictionary vectors, those are built with every row marked present at their own
5935 /// level, and the nulls are down in the values. So the mask says the row has a value and the
5936 /// row does not.
5937 #[test]
5938 fn a_null_behind_a_dictionary_reads_as_null_even_though_the_mask_says_otherwise() {
5939 let values = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
5940 .unwrap()
5941 .with_validity(Validity::from_iter(2, |index| index != 0));
5942 let vector = Vector::dictionary(vec![0, 1, 0], values).unwrap();
5943 assert!(vector.validity().is_valid(0), "the mask at this level says present");
5944 assert!(vector.is_null_at(0));
5945 assert!(!vector.is_null_at(1));
5946 assert!(vector.is_null_at(2));
5947 assert!(vector.is_null_at(3), "a row past the end is null");
5948 }
5949
5950 /// The same for runs, which are built the same way and keep their nulls in the same place.
5951 #[test]
5952 fn a_null_inside_a_run_reads_as_null_even_though_the_mask_says_otherwise() {
5953 let values = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
5954 .unwrap()
5955 .with_validity(Validity::from_iter(2, |index| index != 0));
5956 let vector = Vector::runs(vec![2, 3], values).unwrap();
5957 assert!(vector.validity().is_valid(0));
5958 assert!(vector.is_null_at(0));
5959 assert!(vector.is_null_at(1));
5960 assert!(!vector.is_null_at(2));
5961 }
5962
5963 /// Every other form keeps its nulls in its own mask, so the two answers agree there.
5964 #[test]
5965 fn the_forms_that_hold_their_own_nulls_answer_the_same_either_way() {
5966 let flat = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
5967 .unwrap()
5968 .with_validity(Validity::from_iter(2, |index| index != 0));
5969 let constant = Vector::constant(LogicalType::Integer, Value::Null, 2);
5970 let sequence = Vector::sequence(10, 2, 2);
5971 for vector in [flat, constant, sequence] {
5972 for row in 0..vector.len() {
5973 assert_eq!(vector.is_null_at(row), !vector.validity().is_valid(row));
5974 }
5975 }
5976 }
5977
5978 #[test]
5979 fn flattening_a_flat_vector_is_the_same_vector() {
5980 let vector = integers(&[1, 2, 3]);
5981 assert_eq!(vector.flatten().unwrap(), vector);
5982 }
5983
5984 /// The same answer as `flatten` and, for the vector that is already flat and owns its values,
5985 /// the same allocation. Asserted on the address because that is the whole claim: the values
5986 /// come back where they were rather than in a copy of themselves. A flatten through a borrow
5987 /// cannot do that, and at the top of a query it copied every column of every chunk of the
5988 /// result to hand back the bytes it was given.
5989 #[test]
5990 fn flattening_a_vector_that_owns_its_values_moves_them_rather_than_copying_them() {
5991 let vector = integers(&[1, 2, 3, 4]);
5992 let address = |vector: &Vector| match vector.data() {
5993 Some(Data::Int32(values)) => values.as_slice().as_ptr() as usize,
5994 _ => panic!("the layout changed under the test"),
5995 };
5996 let stored = address(&vector);
5997 let flat = vector.into_flat().unwrap();
5998 assert_eq!(address(&flat), stored, "the values moved");
5999 assert_eq!(
6000 flat.iter().collect::<Vec<_>>(),
6001 (1..=4).map(Value::Integer).collect::<Vec<_>>()
6002 );
6003 // And a form that is not flat is flattened, which is the case the copy is deserved in.
6004 let dictionary = Vector::dictionary(vec![1, 0, 1], integers(&[7, 8])).unwrap();
6005 let flat = dictionary.clone().into_flat().unwrap();
6006 assert_eq!(flat.form(), Form::Flat);
6007 assert_eq!(flat.iter().collect::<Vec<_>>(), dictionary.iter().collect::<Vec<_>>());
6008 }
6009
6010 #[test]
6011 fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
6012 let ty = LogicalType::decimal(9, 2).unwrap();
6013 let vector = Vector::flat(ty, Data::Int32(vec![1234].into())).unwrap();
6014 assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
6015 assert_eq!(vector.value_at(0).to_string(), "12.34");
6016 }
6017
6018 #[test]
6019 fn a_decimal_writes_into_whichever_of_the_four_runs_its_precision_chose() {
6020 // The read path worked at every width and the write path only accepted the 128 bit run, so
6021 // `SELECT 2.5` produced a value nothing could store. All four widths round trip now.
6022 for (width, scale, unscaled) in
6023 [(4u8, 1u8, 25i128), (9, 2, 1234), (18, 3, 123_456), (38, 4, 1_234_567)]
6024 {
6025 let ty = LogicalType::decimal(width, scale).unwrap();
6026 let value = Value::Decimal { unscaled, width, scale };
6027 let vector = Vector::from_values(ty, &[value.clone(), Value::Null]).unwrap();
6028 assert_eq!(vector.value_at(0), value, "a decimal of width {width}");
6029 assert_eq!(vector.value_at(1), Value::Null, "a null decimal of width {width}");
6030 }
6031 }
6032
6033 /// The bytes a blob holds are not required to be text, and a vector of them used to refuse the
6034 /// ones that were not. A byte array column in a Parquet file that nothing annotated is a blob,
6035 /// which is what ClickHouse writes and what ten of the ClickBench queries compare against, so
6036 /// this is the path those take rather than a corner of the type system.
6037 #[test]
6038 fn a_blob_holds_bytes_that_are_not_text() {
6039 let bytes = |raw: &[u8]| Value::Blob(raw.to_vec());
6040 let values = [
6041 bytes(b"a\xffb"),
6042 bytes(b"\x00\x01\x02"),
6043 Value::Null,
6044 bytes(b"\xed\xa0\x80 and long enough to leave the view"),
6045 bytes(b""),
6046 ];
6047 let vector = Vector::from_values(LogicalType::Blob, &values).unwrap();
6048 for (index, value) in values.iter().enumerate() {
6049 assert_eq!(&vector.value_at(index), value, "row {index}");
6050 }
6051 }
6052
6053 #[test]
6054 fn a_decimal_too_wide_for_the_run_its_type_chose_is_an_error_and_not_a_wrong_number() {
6055 // Only reachable by hand, since a value's width is what picked the run. Truncating here
6056 // would store a different number and say nothing about it.
6057 let ty = LogicalType::decimal(4, 1).unwrap();
6058 let value = Value::Decimal { unscaled: 1_000_000, width: 4, scale: 1 };
6059 let error = Vector::from_values(ty, &[value]).unwrap_err();
6060 assert!(error.to_string().contains("does not fit"), "{error}");
6061 }
6062
6063 #[test]
6064 fn a_flat_vector_costs_its_values_and_a_constant_costs_one() {
6065 let flat = integers(&[1; 1000]);
6066 assert!(
6067 flat.footprint() >= 4000,
6068 "a thousand i32 are four thousand bytes: {}",
6069 flat.footprint()
6070 );
6071 // The forms that compute their values rather than storing them cost nothing per value,
6072 // which is the point of having them and is what the memory limit should see.
6073 let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1_000_000);
6074 assert!(constant.footprint() < 200, "a constant is one value: {}", constant.footprint());
6075 let sequence = Vector::sequence(0, 1, 1_000_000);
6076 assert!(sequence.footprint() < 200, "a sequence is two numbers: {}", sequence.footprint());
6077 }
6078
6079 #[test]
6080 fn a_gather_off_a_dictionary_answers_the_same_nulls_either_way_round() {
6081 let words = [Value::Varchar("north".into()), Value::Null, Value::Varchar("south".into())];
6082 let plain: Vec<Value> =
6083 ["north", "east", "south"].iter().map(|word| Value::Varchar((*word).into())).collect();
6084 let clean = Arc::new(Vector::from_values(LogicalType::Varchar, &plain).unwrap());
6085 let dirty = Arc::new(Vector::from_values(LogicalType::Varchar, &words).unwrap());
6086 let codes = vec![0, 1, 2, 0, 1, 2];
6087 let sources = [
6088 Vector::stable_dictionary(codes.clone(), Arc::clone(&clean)).unwrap(),
6089 Vector::stable_dictionary(codes.clone(), Arc::clone(&dirty)).unwrap(),
6090 Vector::stable_dictionary(codes, Arc::clone(&clean))
6091 .unwrap()
6092 .with_validity(Validity::from_run(&[true, true, false, true, true, true])),
6093 ];
6094 // What a gather says about a row has to be what the column it came out of says about the
6095 // row it was taken from, whichever of the two ways the nulls are reached: the mask over the
6096 // codes, or the value a code stands for. The fast answer is only allowed when neither has
6097 // any, and an index past the end is null in both readings.
6098 for source in &sources {
6099 let picks: Vec<u32> = vec![5, 0, 3, 2, 1, 99, 4];
6100 let taken = source.gather(&picks).unwrap();
6101 for (row, &pick) in picks.iter().enumerate() {
6102 assert_eq!(
6103 taken.is_null_at(row),
6104 source.is_null_at(pick as usize),
6105 "row {row} of a gather of {picks:?}"
6106 );
6107 }
6108 }
6109 }
6110
6111 #[test]
6112 fn a_dictionary_read_by_many_cuts_is_counted_about_once_between_them() {
6113 let strings: Vec<Value> = (0..2000)
6114 .map(|at| Value::Varchar(format!("a value well past the inline limit, number {at}")))
6115 .collect();
6116 let values = Arc::new(Vector::from_values(LogicalType::Varchar, &strings).unwrap());
6117 let dictionary = values.footprint();
6118 let cuts: Vec<Vector> = (0..500)
6119 .map(|_| Vector::stable_dictionary(vec![0; 8], Arc::clone(&values)).unwrap())
6120 .collect();
6121 let together: usize = cuts.iter().map(Vector::footprint).sum();
6122 // Five hundred chunks cut out of one page hold one dictionary, and what they say they hold
6123 // has to be about one dictionary. Before this it was five hundred of them, which is a
6124 // reading that grows with the answer and refuses a query holding a gigabyte a budget of
6125 // twenty five.
6126 assert!(
6127 together < dictionary * 2,
6128 "five hundred cuts are not five hundred dictionaries: {together} against {dictionary}"
6129 );
6130 assert!(
6131 together > dictionary / 2,
6132 "the dictionary is still counted: {together} against {dictionary}"
6133 );
6134 }
6135
6136 #[test]
6137 fn a_string_vector_costs_the_bytes_of_its_long_strings() {
6138 let short =
6139 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into())]).unwrap();
6140 let long = "a string well past the sixteen bytes a view holds inline".to_string();
6141 let spilled =
6142 Vector::from_values(LogicalType::Varchar, &[Value::Varchar(long.clone())]).unwrap();
6143 assert!(
6144 spilled.footprint() >= short.footprint() + long.len(),
6145 "the arena is counted: {} against {}",
6146 spilled.footprint(),
6147 short.footprint()
6148 );
6149 }
6150
6151 /// The cases worth checking are the widths where a code straddles a word boundary, which is
6152 /// every width that does not divide sixty four, and the two ends of the range.
6153 #[test]
6154 fn a_narrow_column_packs_and_reads_back_the_same_at_every_width() {
6155 for width in 1..=20u32 {
6156 let span = (1i64 << width) - 1;
6157 let values: Vec<i64> =
6158 (0..1000).map(|row| 1_000_000 + (row * 7919) % (span + 1)).collect();
6159 let flat =
6160 Vector::flat(LogicalType::BigInt, Data::Int64(values.clone().into())).unwrap();
6161 let packed = flat.bit_packed().unwrap();
6162 assert_eq!(packed.len(), flat.len());
6163 assert_eq!(
6164 packed.iter().collect::<Vec<_>>(),
6165 flat.iter().collect::<Vec<_>>(),
6166 "width {width} read back differently"
6167 );
6168 }
6169 }
6170
6171 #[test]
6172 fn the_width_is_the_bits_the_range_needs_and_not_the_bits_the_type_has() {
6173 let values: Vec<i32> = (0..1024).map(|row| 40 + (row * 2560) / 1023).collect();
6174 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
6175 let packed = flat.bit_packed().unwrap();
6176 assert_eq!(packed.form(), Form::BitPacked);
6177 let parts = packed.packed_parts().expect("packed");
6178 assert_eq!(parts.width(), 12, "0 to 2560 is twelve bits");
6179 assert_eq!(parts.base(), 40);
6180 assert!(
6181 packed.footprint() * 2 < flat.footprint(),
6182 "twelve bits against thirty two: {} against {}",
6183 packed.footprint(),
6184 flat.footprint()
6185 );
6186 }
6187
6188 /// The check is worth having in both directions, the way the run length one is. A form that is
6189 /// only ever bigger than what it replaced costs a pass over the column to decide not to use.
6190 #[test]
6191 fn a_column_that_uses_its_whole_type_is_left_flat() {
6192 let values: Vec<i32> = (0..1024).map(|row| row * 2_000_000 - 1_000_000_000).collect();
6193 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
6194 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
6195 }
6196
6197 /// The column that would not write. A thousand values just under `i32::MAX` need ten bits, and
6198 /// based at the smallest of them those ten bits could say a number an `INTEGER` cannot hold, so
6199 /// the range check refused the column and `CREATE TABLE` came back with an internal error. The
6200 /// base is what moves, not the check: it drops to where the widest code the width allows is the
6201 /// largest value the type has.
6202 #[test]
6203 fn a_column_against_the_top_of_its_type_packs_rather_than_being_refused() {
6204 let values: Vec<i32> = (0..4096).map(|row| i32::MAX - (row % 1000)).collect();
6205 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into())).unwrap();
6206 let packed = flat.bit_packed().unwrap();
6207 assert_eq!(packed.form(), Form::BitPacked);
6208 let parts = packed.packed_parts().expect("packed");
6209 assert_eq!(parts.width(), 10, "a thousand values apart is ten bits");
6210 assert_eq!(
6211 parts.base() + i128::from(u64::MAX >> (64 - parts.width())),
6212 i128::from(i32::MAX),
6213 "the widest code the width allows is the largest value the type holds"
6214 );
6215 assert_eq!(
6216 packed.iter().collect::<Vec<_>>(),
6217 flat.iter().collect::<Vec<_>>(),
6218 "the values came back different"
6219 );
6220 }
6221
6222 /// The other end of the same thing. A column that reaches both ends of its type needs every bit
6223 /// the type has, and the only base that leaves room for those codes is the bottom of the type.
6224 #[test]
6225 fn a_column_that_reaches_both_ends_of_its_type_bases_at_the_bottom_of_it() {
6226 let values: Vec<i32> = (0..4096)
6227 .map(|row| if row % 2 == 0 { i32::MIN + row } else { i32::MAX - row })
6228 .collect();
6229 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into())).unwrap();
6230 // Thirty two bits of codes for a thirty two bit type buys nothing, so the size check leaves
6231 // it flat. What matters is that it is left flat rather than refused.
6232 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
6233 assert_eq!(
6234 packing_base(&LogicalType::Integer, i128::from(i32::MIN), i128::from(i32::MAX), 32),
6235 Some(i128::from(i32::MIN))
6236 );
6237 }
6238
6239 /// A column of one value would pack to no bits at all, and one run is smaller than any packing
6240 /// of it, so the two forms do not fight over that column.
6241 #[test]
6242 fn a_column_of_one_value_is_left_to_the_run_length_form() {
6243 let flat = integers(&[9; 1024]);
6244 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
6245 assert_eq!(flat.run_encoded().unwrap().form(), Form::Rle);
6246 }
6247
6248 #[test]
6249 fn a_string_column_has_no_range_to_pack() {
6250 let text = Vector::from_values(
6251 LogicalType::Varchar,
6252 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
6253 )
6254 .unwrap();
6255 assert_eq!(text.bit_packed().unwrap().form(), Form::Flat);
6256 }
6257
6258 /// The cut is the reason the form carries a row to start reading at. It stays packed, it shares
6259 /// the same words, and it reads the rows the range asked for.
6260 #[test]
6261 fn a_cut_of_a_packed_column_stays_packed_and_shares_its_bits() {
6262 let values: Vec<i32> = (0..1024).map(|row| 100 + row % 300).collect();
6263 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
6264 let packed = flat.bit_packed().unwrap();
6265 let cut = packed.slice(500, 24).unwrap();
6266 assert_eq!(cut.form(), Form::BitPacked);
6267 assert_eq!(cut.len(), 24);
6268 assert_eq!(
6269 cut.iter().collect::<Vec<_>>(),
6270 flat.slice(500, 24).unwrap().iter().collect::<Vec<_>>()
6271 );
6272 assert!(
6273 cut.footprint() >= packed.footprint(),
6274 "a cut shares the words rather than copying a piece of them"
6275 );
6276 }
6277
6278 #[test]
6279 fn a_gather_of_a_packed_column_comes_out_flat_and_keeps_the_nulls() {
6280 let values: Vec<i32> = (0..64).map(|row| 10 + row).collect();
6281 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
6282 let packed =
6283 flat.bit_packed().unwrap().with_validity(Validity::from_iter(64, |row| row % 3 != 0));
6284 let taken = packed.gather(&[0, 1, 2, 3, 62]).unwrap();
6285 assert_eq!(taken.form(), Form::Flat);
6286 assert_eq!(
6287 taken.iter().collect::<Vec<_>>(),
6288 vec![
6289 Value::Null,
6290 Value::Integer(11),
6291 Value::Integer(12),
6292 Value::Null,
6293 Value::Integer(72)
6294 ]
6295 );
6296 }
6297
6298 /// The pair a comparison kernel asks for before it reads a bit. A literal inside the range has a
6299 /// code and a literal outside it does not, which answers the whole vector at once.
6300 #[test]
6301 fn a_literal_outside_the_packed_range_has_no_code() {
6302 let values: Vec<i32> = (0..256).map(|row| 1000 + row).collect();
6303 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
6304 let packed = flat.bit_packed().unwrap();
6305 let parts = packed.packed_parts().expect("packed");
6306 assert_eq!(parts.code_of(1000), Some(0));
6307 assert_eq!(parts.code_of(1100), Some(100));
6308 assert_eq!(parts.code_of(999), None);
6309 assert!(parts.ceiling() >= 1255);
6310 assert_eq!(parts.code_of(parts.ceiling() + 1), None);
6311 }
6312
6313 /// The bits arriving from a file rather than from a flat vector, which is what the form is for.
6314 #[test]
6315 fn packed_bits_can_be_handed_in_without_a_flat_vector_to_start_from() {
6316 let packed = Vector::packed(LogicalType::SmallInt, vec![0x0000_0000_0000_4321], 4, 7, 4)
6317 .expect("four codes of four bits");
6318 assert_eq!(
6319 packed.iter().collect::<Vec<_>>(),
6320 vec![Value::SmallInt(8), Value::SmallInt(9), Value::SmallInt(10), Value::SmallInt(11)]
6321 );
6322 }
6323
6324 #[test]
6325 fn packed_bits_that_could_not_hold_what_they_claim_are_refused() {
6326 assert!(Vector::packed(LogicalType::Varchar, vec![0], 4, 0, 4).is_err(), "not an integer");
6327 assert!(Vector::packed(LogicalType::Integer, vec![0], 0, 0, 4).is_err(), "no width");
6328 assert!(Vector::packed(LogicalType::Integer, vec![0], 64, 0, 4).is_err(), "too wide");
6329 assert!(Vector::packed(LogicalType::Integer, vec![0], 8, 0, 9).is_err(), "too few words");
6330 assert!(Vector::packed(LogicalType::TinyInt, vec![0], 8, 100, 8).is_err(), "would not fit");
6331 }
6332
6333 /// A column of strings long enough that the payload is in the arena rather than in the views.
6334 fn long_strings(count: usize) -> Vector {
6335 let values: Vec<Value> = (0..count)
6336 .map(|row| {
6337 Value::Varchar(format!("a string too long to sit inside a view, number {row}"))
6338 })
6339 .collect();
6340 Vector::from_values(LogicalType::Varchar, &values).unwrap()
6341 }
6342
6343 #[test]
6344 fn a_string_column_in_view_form_reads_back_the_same_strings() {
6345 let flat = long_strings(40);
6346 let shared = flat.clone().shared_text().unwrap();
6347 assert_eq!(shared.form(), Form::StringView);
6348 assert_eq!(shared.len(), 40);
6349 for row in 0..40 {
6350 assert_eq!(shared.value_at(row), flat.value_at(row), "row {row}");
6351 assert_eq!(shared.text_at(row), flat.text_at(row), "row {row}");
6352 }
6353 }
6354
6355 #[test]
6356 fn a_short_string_is_read_out_of_its_view_and_never_out_of_the_arena() {
6357 let flat = Vector::from_values(
6358 LogicalType::Varchar,
6359 &[Value::Varchar("red".into()), Value::Varchar("green".into()), Value::Null],
6360 )
6361 .unwrap();
6362 let shared = flat.shared_text().unwrap();
6363 // Nothing went to the arena, so the whole column resolves with an empty one.
6364 let (views, arena) = shared.text_parts().unwrap();
6365 assert!(arena.is_empty(), "three short strings need no arena");
6366 assert_eq!(views[0].bytes_in(arena), Some(&b"red"[..]));
6367 assert_eq!(shared.value_at(1), Value::Varchar("green".into()));
6368 assert_eq!(shared.value_at(2), Value::Null, "the validity came across");
6369 }
6370
6371 #[test]
6372 fn a_cut_of_a_view_column_shares_the_arena_rather_than_copying_the_bytes() {
6373 let shared = long_strings(64).shared_text().unwrap();
6374 let cut = shared.slice(16, 8).unwrap();
6375 assert_eq!(cut.form(), Form::StringView, "a cut of views is views");
6376 assert_eq!(cut.len(), 8);
6377 assert_eq!(cut.value_at(0), shared.value_at(16));
6378 assert_eq!(cut.value_at(7), shared.value_at(23));
6379 // The arena is the same bytes at the same address, which is the whole point of the form.
6380 let (_, whole) = shared.text_parts().unwrap();
6381 let (_, piece) = cut.text_parts().unwrap();
6382 assert_eq!(piece.as_ptr(), whole.as_ptr(), "the cut shares the page");
6383 assert_eq!(piece.len(), whole.len());
6384 }
6385
6386 #[test]
6387 fn a_flat_string_column_has_to_copy_the_bytes_its_cut_keeps() {
6388 let flat = long_strings(64);
6389 let cut = flat.slice(16, 8).unwrap();
6390 assert_eq!(cut.form(), Form::Flat);
6391 let (_, whole) = flat.text_parts().unwrap();
6392 let (_, piece) = cut.text_parts().unwrap();
6393 assert!(piece.len() < whole.len(), "the flat cut carries only what it kept");
6394 }
6395
6396 #[test]
6397 fn a_gather_of_a_view_column_keeps_the_form_and_a_flatten_copies_out_of_it() {
6398 let shared = long_strings(32).shared_text().unwrap();
6399 let picked: Vec<u32> = (0..32).step_by(3).collect();
6400 let gathered = shared.gather(&picked).unwrap();
6401 assert_eq!(gathered.form(), Form::StringView, "selecting rows moves views, not bytes");
6402 assert_eq!(gathered.len(), picked.len());
6403 for (row, &from) in picked.iter().enumerate() {
6404 assert_eq!(gathered.value_at(row), shared.value_at(from as usize), "row {row}");
6405 }
6406 let flattened = gathered.flatten().unwrap();
6407 assert_eq!(flattened.form(), Form::Flat);
6408 assert_eq!(flattened.iter().collect::<Vec<_>>(), gathered.iter().collect::<Vec<_>>());
6409 // The flatten is what narrows the bytes, so the arena it built holds only the rows it kept.
6410 let (_, narrowed) = flattened.text_parts().unwrap();
6411 let (_, whole) = shared.text_parts().unwrap();
6412 assert!(narrowed.len() < whole.len(), "flattening lets the page go");
6413 }
6414
6415 #[test]
6416 fn a_null_in_a_view_column_survives_being_gathered_and_flattened() {
6417 let shared = long_strings(8)
6418 .with_validity(Validity::from_iter(8, |row| row % 3 != 0))
6419 .shared_text()
6420 .unwrap();
6421 let gathered = shared.gather(&[0, 1, 2, 3, 4]).unwrap();
6422 let expected =
6423 [Value::Null, shared.value_at(1), shared.value_at(2), Value::Null, shared.value_at(4)];
6424 assert_eq!(gathered.iter().collect::<Vec<_>>(), expected);
6425 assert_eq!(gathered.flatten().unwrap().iter().collect::<Vec<_>>(), expected);
6426 }
6427
6428 #[test]
6429 fn both_string_forms_hand_a_kernel_the_same_views_and_the_same_bytes() {
6430 let flat = long_strings(6);
6431 let shared = flat.clone().shared_text().unwrap();
6432 let (flat_views, flat_arena) = flat.text_parts().unwrap();
6433 let (shared_views, shared_arena) = shared.text_parts().unwrap();
6434 assert_eq!(flat_views.len(), shared_views.len());
6435 for row in 0..6 {
6436 assert_eq!(
6437 flat_views[row].bytes_in(flat_arena),
6438 shared_views[row].bytes_in(shared_arena),
6439 "row {row}"
6440 );
6441 }
6442 // Nothing else answers this, which is what keeps a kernel from taking it for a string column.
6443 assert!(Vector::sequence(0, 1, 4).text_parts().is_none());
6444 assert!(integers(&[1, 2, 3]).text_parts().is_none());
6445 }
6446
6447 #[test]
6448 fn a_column_that_is_not_strings_cannot_be_held_as_views() {
6449 let views = vec![StringView::inline("red")];
6450 let arena = Arc::new(Buffer::new());
6451 let wrong = Vector::string_views(LogicalType::Integer, views, arena);
6452 assert!(wrong.is_err(), "an integer column has no views");
6453 assert_eq!(integers(&[1, 2]).shared_text().unwrap().form(), Form::Flat, "left alone");
6454 }
6455
6456 /// A column with enough repeated structure for a symbol table to find something, which is what
6457 /// a real text column has and a column of random bytes does not.
6458 fn sentences(count: usize) -> Vector {
6459 let values: Vec<Value> = (0..count)
6460 .map(|row| {
6461 Value::Varchar(format!(
6462 "http://example.test/catalogue/section/{}/item/{row}",
6463 row % 7
6464 ))
6465 })
6466 .collect();
6467 Vector::from_values(LogicalType::Varchar, &values).unwrap()
6468 }
6469
6470 #[test]
6471 fn a_compressed_column_reads_back_the_strings_that_went_into_it() {
6472 let flat = sentences(64);
6473 let coded = flat.clone().compressed().unwrap();
6474 assert_eq!(coded.form(), Form::Fsst, "a text column compresses");
6475 assert_eq!(coded.len(), 64);
6476 for row in 0..64 {
6477 assert_eq!(coded.value_at(row), flat.value_at(row), "row {row}");
6478 }
6479 assert_eq!(coded.flatten().unwrap(), flat, "flattening is the column it came from");
6480 }
6481
6482 #[test]
6483 fn compressing_halves_the_bytes_or_the_column_is_left_flat() {
6484 let flat = sentences(200);
6485 let coded = flat.clone().compressed().unwrap();
6486 let parts = coded.coded_parts().expect("compressed");
6487 // Read through the flat column, because the compressed one has no bytes to hand back where
6488 // they are and answers `None` to `text_at` rather than decompressing into a borrow.
6489 assert_eq!(coded.text_at(0), None, "nothing to borrow until it is flattened");
6490 let plain: usize = (0..200).map(|row| flat.text_at(row).map_or(0, str::len)).sum();
6491 let codes: usize = (0..200).map(|row| parts.row(row).map_or(0, <[u8]>::len)).sum();
6492 assert!(codes * FSST_PAYS_AT <= plain, "{codes} codes against {plain} bytes");
6493 // Text with no repeated structure in it gives a table nothing longer than a byte to find,
6494 // so the codes are the bytes and the column stays where it is rather than paying a
6495 // decompression per read to save nothing.
6496 let mut seed = 0x2545_f491_4f6c_dd1du64;
6497 let values: Vec<Value> = (0..256)
6498 .map(|_| {
6499 let mut text = String::new();
6500 while text.len() < 12 {
6501 seed = seed.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
6502 text.push(char::from(b'!' + ((seed >> 33) % 90) as u8));
6503 }
6504 Value::Varchar(text)
6505 })
6506 .collect();
6507 let noise = Vector::from_values(LogicalType::Varchar, &values).unwrap();
6508 assert_eq!(noise.compressed().unwrap().form(), Form::Flat);
6509 }
6510
6511 #[test]
6512 fn a_cut_of_a_compressed_column_shares_the_codes_and_the_table() {
6513 let coded = sentences(64).compressed().unwrap();
6514 let cut = coded.slice(8, 16).unwrap();
6515 assert_eq!(cut.form(), Form::Fsst);
6516 assert_eq!(cut.len(), 16);
6517 for row in 0..16 {
6518 assert_eq!(cut.value_at(row), coded.value_at(8 + row), "row {row}");
6519 }
6520 let (whole, piece) = (coded.coded_parts().unwrap(), cut.coded_parts().unwrap());
6521 assert_eq!(piece.row(0), whole.row(8), "the spans point into the same codes");
6522 }
6523
6524 #[test]
6525 fn a_gather_of_a_compressed_column_stays_compressed_and_keeps_the_nulls() {
6526 let coded = sentences(32)
6527 .with_validity(Validity::from_iter(32, |row| row % 5 != 2))
6528 .compressed()
6529 .unwrap();
6530 let picked: Vec<u32> = (0..32).step_by(2).collect();
6531 let gathered = coded.gather(&picked).unwrap();
6532 assert_eq!(gathered.form(), Form::Fsst, "selecting rows moves spans, not bytes");
6533 for (row, &from) in picked.iter().enumerate() {
6534 assert_eq!(gathered.value_at(row), coded.value_at(from as usize), "row {row}");
6535 }
6536 assert_eq!(
6537 gathered.flatten().unwrap().iter().collect::<Vec<_>>(),
6538 gathered.iter().collect::<Vec<_>>()
6539 );
6540 }
6541
6542 #[test]
6543 fn a_literal_lands_in_the_same_codes_the_row_holding_it_does() {
6544 let coded = sentences(40).compressed().unwrap();
6545 let parts = coded.coded_parts().expect("compressed");
6546 let text = coded.value_at(11);
6547 let Value::Varchar(text) = text else { panic!("a string column reads back strings") };
6548 assert_eq!(parts.encode(text.as_bytes()), parts.row(11).expect("row 11"));
6549 assert_ne!(parts.encode(b"something else entirely"), parts.row(11).unwrap());
6550 }
6551
6552 #[test]
6553 fn codes_that_run_past_what_is_there_are_refused() {
6554 let table = Arc::new(SymbolTable::empty());
6555 let codes = Arc::new(vec![1u8, 2, 3, 4]);
6556 let good = vec![(0u32, 2u32), (2, 4)];
6557 assert!(
6558 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), good, Arc::clone(&table))
6559 .is_ok()
6560 );
6561 let past = vec![(0u32, 9u32)];
6562 assert!(
6563 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), past, Arc::clone(&table))
6564 .is_err(),
6565 "a span past the end of the codes"
6566 );
6567 let backwards = vec![(3u32, 1u32)];
6568 assert!(
6569 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), backwards, Arc::clone(&table))
6570 .is_err(),
6571 "a span that ends before it starts"
6572 );
6573 let wrong = vec![(0u32, 2u32)];
6574 assert!(
6575 Vector::coded(LogicalType::Integer, codes, wrong, table).is_err(),
6576 "an integer column has no codes"
6577 );
6578 }
6579
6580 #[test]
6581 fn a_view_pointing_past_its_arena_is_refused_at_construction() {
6582 let long = "a string too long to sit inside a view";
6583 let arena: Arc<Buffer<u8>> = Arc::new(long.as_bytes().to_vec().into());
6584 let good = vec![StringView::over(long.as_bytes(), 0)];
6585 assert!(Vector::string_views(LogicalType::Varchar, good, Arc::clone(&arena)).is_ok());
6586 let bad = vec![StringView::over(long.as_bytes(), 4)];
6587 assert!(
6588 Vector::string_views(LogicalType::Varchar, bad, arena).is_err(),
6589 "four bytes short of what the view claims"
6590 );
6591 }
6592
6593 /// The form at its simplest: an id per row, and the row it names.
6594 #[test]
6595 fn a_gathered_vector_reads_the_source_row_its_id_names() {
6596 let source = Arc::new(integers(&[10, 20, 30, 40]));
6597 let vector = Vector::gathered(source, Arc::new(vec![3, 0, 3, 1])).unwrap();
6598 assert_eq!(vector.form(), Form::Gathered);
6599 assert_eq!(vector.len(), 4);
6600 assert_eq!(
6601 vector.iter().collect::<Vec<_>>(),
6602 vec![Value::Integer(40), Value::Integer(10), Value::Integer(40), Value::Integer(20)]
6603 );
6604 }
6605
6606 /// Section 8.2's lazy validity. The sentinel is a null and it is not in a mask anywhere, which is
6607 /// what lets a left link join gather null for an unmatched child row without allocating one.
6608 #[test]
6609 fn a_gathered_row_with_no_source_row_is_null_without_a_mask() {
6610 let source = Arc::new(integers(&[10, 20]));
6611 let vector = Vector::gathered(source, Arc::new(vec![1, NO_ROW, 0])).unwrap();
6612 assert!(!vector.validity().has_nulls(vector.len()), "the mask at this level says nothing");
6613 assert!(vector.is_null_at(1));
6614 assert!(!vector.is_null_at(0) && !vector.is_null_at(2));
6615 assert_eq!(
6616 vector.iter().collect::<Vec<_>>(),
6617 vec![Value::Integer(20), Value::Null, Value::Integer(10)]
6618 );
6619 assert!(!vector.none_null(), "a sentinel is a null and the bulk answer has to agree");
6620 }
6621
6622 /// The other half of the same rule: a null in the source is a null here, the way a dictionary's
6623 /// nulls live in its values. Two ways for a row to be null and one answer from `is_null_at`.
6624 #[test]
6625 fn a_gather_of_a_null_source_row_is_null() {
6626 let source = Arc::new(
6627 Vector::from_values(LogicalType::Integer, &[Value::Integer(7), Value::Null]).unwrap(),
6628 );
6629 let vector = Vector::gathered(source, Arc::new(vec![1, 0, 1])).unwrap();
6630 assert!(vector.is_null_at(0) && vector.is_null_at(2));
6631 assert_eq!(vector.value_at(1), Value::Integer(7));
6632 assert!(!vector.none_null());
6633 }
6634
6635 /// An id past the end of the source is the one failure in this form that reads whatever happens
6636 /// to be at that offset rather than failing, so it is refused where the vector is built.
6637 #[test]
6638 fn a_gathered_id_past_the_end_of_its_source_is_refused() {
6639 let source = Arc::new(integers(&[1, 2, 3]));
6640 assert!(Vector::gathered(Arc::clone(&source), Arc::new(vec![0, 3])).is_err());
6641 assert!(
6642 Vector::gathered(source, Arc::new(vec![0, NO_ROW])).is_ok(),
6643 "the sentinel is not an id past the end, it is the absence of one"
6644 );
6645 }
6646
6647 /// A cut is the offset and nothing else, which is what keeps a pipeline from copying the ids once
6648 /// per operator. Both ends stay shared and the rows answer the same.
6649 #[test]
6650 fn cutting_a_gather_moves_where_it_starts_and_copies_nothing() {
6651 let source = Arc::new(integers(&[10, 20, 30, 40, 50]));
6652 let rids = Arc::new(vec![4, 3, 2, 1, 0]);
6653 let vector = Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap();
6654 let held = Arc::strong_count(&rids);
6655 let cut = vector.slice(1, 3).unwrap();
6656 assert_eq!(cut.form(), Form::Gathered);
6657 assert_eq!(
6658 Arc::strong_count(&rids),
6659 held + 1,
6660 "the cut shares the ids rather than copying"
6661 );
6662 assert_eq!(
6663 cut.iter().collect::<Vec<_>>(),
6664 vec![Value::Integer(40), Value::Integer(30), Value::Integer(20)]
6665 );
6666 assert_eq!(cut.gathered_parts().unwrap().1, [3, 2, 1]);
6667 }
6668
6669 /// Composition, which is why this is a body and not an operator. A filter over the output of a
6670 /// link join selects into the ids, and what comes out is one level rather than two.
6671 #[test]
6672 fn a_gather_of_a_gather_resolves_to_one_walk_over_the_source() {
6673 let source = Arc::new(integers(&[10, 20, 30, 40]));
6674 let inner = Vector::gathered(source, Arc::new(vec![3, 2, 1, 0])).unwrap();
6675 let outer = inner.gather(&[0, 3]).unwrap();
6676 assert_eq!(outer.iter().collect::<Vec<_>>(), vec![Value::Integer(40), Value::Integer(10)]);
6677 assert_ne!(outer.form(), Form::Gathered, "the walk stops at what the ids point into");
6678 }
6679
6680 /// The sentinel survives being gathered through, which it has to: a filter over a left link
6681 /// join's output keeps the unmatched rows it kept and they are still null.
6682 #[test]
6683 fn gathering_through_a_sentinel_keeps_it_null() {
6684 let source = Arc::new(integers(&[10, 20]));
6685 let inner = Vector::gathered(source, Arc::new(vec![0, NO_ROW, 1])).unwrap();
6686 let outer = inner.gather(&[1, 2, 1]).unwrap();
6687 assert_eq!(
6688 outer.iter().collect::<Vec<_>>(),
6689 vec![Value::Null, Value::Integer(20), Value::Null]
6690 );
6691 }
6692
6693 /// Section 8.2's dispatch rule, which is the whole difference between this form and a dictionary
6694 /// and is one comparison. A gather off a parent larger than the chunk does not want the
6695 /// dictionary arm of any kernel, and a gather off a source smaller than the chunk does.
6696 #[test]
6697 fn folding_over_the_source_is_worth_it_only_when_the_source_is_the_shorter_one() {
6698 let wide = Arc::new(integers(&(0..64).collect::<Vec<i32>>()));
6699 let narrow = Arc::new(integers(&[1, 2]));
6700 let off_wide = Vector::gathered(wide, Arc::new(vec![0, 1, 2])).unwrap();
6701 let off_narrow = Vector::gathered(narrow, Arc::new(vec![0, 1, 0, 1, 0])).unwrap();
6702 assert!(!off_wide.fold_over_source(), "sixty four source rows to answer three");
6703 assert!(off_narrow.fold_over_source(), "two source rows to answer five");
6704 assert!(!integers(&[1, 2]).fold_over_source(), "and every other form says no");
6705 }
6706
6707 /// Strings, which read their bytes where the source already has them rather than through a value.
6708 /// A gather of a string column is four bytes a row and no arena is touched until something asks.
6709 #[test]
6710 fn a_gathered_string_is_read_where_the_source_put_it() {
6711 let mut column = StringColumn::new();
6712 column.push("red");
6713 column.push("a string too long to sit inside a sixteen byte view");
6714 let source = Arc::new(Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap());
6715 let vector = Vector::gathered(source, Arc::new(vec![1, 0, NO_ROW])).unwrap();
6716 assert_eq!(vector.text_at(0), Some("a string too long to sit inside a sixteen byte view"));
6717 assert_eq!(vector.text_at(1), Some("red"));
6718 assert_eq!(vector.text_at(2), None);
6719 assert_eq!(vector.bytes_at(1), Some(b"red".as_slice()));
6720 assert_eq!(vector.value_at(1), Value::Varchar("red".into()));
6721 }
6722
6723 /// The integer accessor a group by keys through, which has to agree with `value_at` at every
6724 /// row or two rows holding one value land in two groups.
6725 #[test]
6726 fn the_signed_reader_of_a_gather_agrees_with_the_value_reader() {
6727 let source = Arc::new(integers(&[10, 20, 30]));
6728 let vector = Vector::gathered(source, Arc::new(vec![2, NO_ROW, 0, 1])).unwrap();
6729 for row in 0..vector.len() {
6730 let signed = vector.signed_at(row);
6731 match vector.value_at(row) {
6732 Value::Null => assert_eq!(signed, None),
6733 Value::Integer(held) => assert_eq!(signed, Some(i128::from(held))),
6734 other => panic!("an integer column answered {other}"),
6735 }
6736 }
6737 }
6738
6739 /// Flattening gives up the form, which is what it is for, and what comes out holds the values the
6740 /// gather stood for, nulls included.
6741 #[test]
6742 fn flattening_a_gather_writes_out_the_rows_it_pointed_at() {
6743 let source = Arc::new(integers(&[10, 20, 30]));
6744 let vector = Vector::gathered(source, Arc::new(vec![2, NO_ROW, 0])).unwrap();
6745 let flat = vector.flatten().unwrap();
6746 assert_eq!(flat.form(), Form::Flat);
6747 assert_eq!(
6748 flat.iter().collect::<Vec<_>>(),
6749 vec![Value::Integer(30), Value::Null, Value::Integer(10)]
6750 );
6751 }
6752
6753 /// A gather counts a share of what it shares, for the reason a dictionary does. Eight columns
6754 /// gathered off one parent are one parent between them, not eight.
6755 #[test]
6756 fn a_parent_gathered_by_many_columns_is_counted_about_once_between_them() {
6757 let source = Arc::new(integers(&(0..4096).collect::<Vec<i32>>()));
6758 let rids = Arc::new(vec![0; 64]);
6759 let alone = Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap().footprint();
6760 let many = (0..8)
6761 .map(|_| Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap())
6762 .collect::<Vec<_>>();
6763 let together = many.iter().map(Vector::footprint).sum::<usize>();
6764 assert!(
6765 together < alone * 2,
6766 "eight gathers off one parent reported {together} against {alone} for one"
6767 );
6768 }
6769}