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::cell::RefCell;
42use std::cmp::Ordering;
43use std::sync::Arc;
44
45use rudb_common::{Cause, Error, Field, LogicalType, Result, Value, slow};
46
47use crate::buffer::Buffer;
48use crate::fsst::SymbolTable;
49use crate::string::{StringColumn, StringView};
50use crate::validity::Validity;
51
52/// How many values are in a full vector.
53///
54/// 8192, which is four times DuckDB's 2048 and eight times what this was. It started at 1024 for
55/// three reasons: the FastLanes unit is 1024, a validity mask comes out at exactly 16 `u64` words,
56/// and a vector of 16 byte string views is 16 KiB, which is small enough that several of them sit
57/// in L1 at once. The first two are still true of any multiple of 1024. The third was the argument
58/// and it was an argument about the wrong level, because it was also deciding how much of a table
59/// one zone map covered and how much work one call into the pipeline did, and those wanted a much
60/// larger number than L1 did.
61///
62/// #984 separated them: a table in memory is stored in row groups of 122,880 rows now and a chunk
63/// is a window into one, so the vector size is only the execution unit and is free to be chosen for
64/// what an operator costs per call. #480 measured it. On twenty million rows in memory, one thread,
65/// going from 1024 to 8192 takes `count(*)` with a filter from 14.0 milliseconds to 1.9, `sum(v)`
66/// with the same filter from 39.6 to 29.6 and `sum(k + v)` from 66.8 to 52.6. On ClickBench over
67/// Parquet, where the time is decode and hash aggregation rather than per call overhead, the same
68/// move is worth about eight percent on the total of the twenty nine queries that run.
69///
70/// 32768 was measured too and is not better: it wins another few percent on the full scans and
71/// loses on the load, on a needle that the chunk zone maps would otherwise prune, and on anything
72/// with a string column, where a vector of views is half a megabyte. 8192 is where the per call
73/// overhead has stopped mattering and the working set has not started to.
74pub const VECTOR_SIZE: usize = 8192;
75
76/// The smallest and largest of `at`, or `None` when it is empty.
77///
78/// Compared as signed 32 bit numbers with the top bit flipped, which keeps the order and is the
79/// one minimum and maximum SSE2 has, so the loop vectorizes where an unsigned one does not.
80fn extent(at: &[u32]) -> Option<(u32, u32)> {
81 const FLIP: u32 = 1 << 31;
82 #[expect(clippy::cast_possible_wrap, reason = "the flip makes the wrap keep the order")]
83 let signed = |row: u32| (row ^ FLIP) as i32;
84 #[expect(clippy::cast_sign_loss, reason = "undoing the flip above")]
85 let unsigned = |row: i32| (row as u32) ^ FLIP;
86 if at.is_empty() {
87 return None;
88 }
89 let low = at.iter().fold(i32::MAX, |low, &row| low.min(signed(row)));
90 let high = at.iter().fold(i32::MIN, |high, &row| high.max(signed(row)));
91 Some((unsigned(low), unsigned(high)))
92}
93
94/// Whether every one of `codes` is below `len`.
95///
96/// The obvious test is the largest code, and on the baseline x86-64 the release is built for that
97/// loop does not vectorize, because SSE2 has no unsigned 32 bit maximum. It was about half of
98/// `Vector::gather` on q01, where every filtered column asks it of the same positions. An `or` of
99/// every code is at least as large as each of them and does vectorize, so when it is below `len`
100/// every code is too. A filter's positions over a full chunk of 8192 rows always pass that way,
101/// since `len` is then a power of two. Anything the `or` cannot settle takes the maximum.
102#[must_use]
103pub fn below(codes: &[u32], len: usize) -> bool {
104 let Ok(len) = u32::try_from(len) else { return true };
105 if codes.is_empty() || codes.iter().fold(0, |bits, &code| bits | code) < len {
106 return true;
107 }
108 codes.iter().copied().fold(0, u32::max) < len
109}
110
111/// What the key field of a map's child struct is called.
112///
113/// A map is stored as a list of two field structs, and these are the two names. They are DuckDB's, and
114/// they are also the names the Parquet specification gives a map's repeated group, so a reader that
115/// builds one of these from a file finds the names already agreed rather than translated.
116pub const MAP_KEY: &str = "key";
117
118/// What the value field of a map's child struct is called. See [`MAP_KEY`].
119pub const MAP_VALUE: &str = "value";
120
121/// What [`Vector::map_parts`] hands back: one entry per row, then the keys and then the values.
122///
123/// A name rather than the triple written out, because the triple written out is over the complexity
124/// clippy allows and because a kernel that takes these as an argument should be able to say so in one
125/// word.
126pub type MapParts<'a> = (&'a [(u32, u32)], &'a Vector, &'a Vector);
127
128/// Which physical form a vector is in.
129///
130/// An operator asks this once per vector and then takes the path it wants, which is the one branch
131/// per vector that the whole design is willing to spend.
132///
133/// Not exhaustive, and that is a decision rather than an oversight. `Encoded` is the fifth form
134/// and it arrives at layer three with the specialization contract. If this enum were exhaustive,
135/// the day it lands is the day every kernel in the workspace stops compiling, and the pressure at
136/// that moment would be to add an arm to each of them in a hurry rather than to think about what
137/// each one should do with an encoded vector. A required fallback arm means each kernel already
138/// has a correct answer for a form it has never seen, and specializing it is then a change that
139/// can be made one kernel at a time with a benchmark next to it.
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141#[non_exhaustive]
142pub enum Form {
143 /// One value per position.
144 Flat,
145 /// One value, repeated.
146 Constant,
147 /// A start and a step, computed rather than stored.
148 Sequence,
149 /// Codes into a smaller vector of distinct values.
150 Dictionary,
151 /// Integers stored in as many bits as the range of the column needs, offset from a base.
152 ///
153 /// The form a narrow integer column is in. A ClickBench `ResolutionWidth` is a `SMALLINT` whose
154 /// values live between 0 and 2560, which is twelve bits, so the column is three quarters of the
155 /// size it was and the pages behind it are three quarters of the reads. What it costs is a shift
156 /// and a mask per value, which is why this is worth it at storage and at rest and is not a form
157 /// anything should be building in the middle of a pipeline.
158 BitPacked,
159 /// Sixteen byte views over an arena the vector shares rather than owns.
160 ///
161 /// The form a varchar column is in once more than one vector is looking at the same page. A flat
162 /// varchar vector owns its arena, so cutting a chunk out of it copies every byte of every long
163 /// string in the range, and on ClickBench that is most of what reading `URL` costs. Sharing the
164 /// arena makes the cut the views and nothing else, the way a dictionary cut is the codes and
165 /// nothing else.
166 StringView,
167 /// Strings compressed against one symbol table, each row on its own.
168 ///
169 /// The form a text column is in at rest. FSST is about half the bytes on the ClickBench `URL`
170 /// and `Title` columns, and unlike a block compressor it keeps random access, so reading row
171 /// four million does not decompress the four million before it. What it costs is a decompression
172 /// per row read, which is why an equality filter over it is worth writing in code space: the
173 /// literal compresses once and the rows never decompress at all.
174 Fsst,
175 /// One value per run, with the row each run ends at.
176 ///
177 /// The form a clustered column is in. `hits` is written in time order, so `EventDate` is a few
178 /// hundred runs over a hundred million rows, and a sum over it is a few hundred multiplications
179 /// rather than a hundred million additions. Dictionary says which distinct values there are and
180 /// this says where they stop, and a column can want either one without wanting the other.
181 Rle,
182 /// A child vector of every element, and a start and a length per row.
183 ///
184 /// The form a `LIST` column is in, and the only form it has. The others are all ways of writing
185 /// down a column of scalars more cheaply and this is the shape a nested value has at all, so a
186 /// list vector reports this whether or not anything has tried to make it smaller. Making it
187 /// smaller happens in the child, which is an ordinary vector and can be any of the forms above.
188 ///
189 /// A `MAP` column reports this too, because a map is a list whose child is a two field struct and
190 /// the bytes really are a list's. This enum is about the physical layout, and the logical type is
191 /// what remembers the difference, which is the same division `LogicalType::physical` already makes.
192 List,
193 /// One child vector per field, each as long as the vector itself.
194 ///
195 /// The form a `STRUCT` column is in, and the only form it has, for the reason [`Form::List`] is
196 /// the only form a list has. A struct holds exactly one value per field per row rather than a run
197 /// of them, so there are no entries here and the children line up with the rows one to one, which
198 /// makes a cut a cut of every child and a gather a gather of every child. Each child is an
199 /// ordinary vector and can be in any of the forms above, so that is where a struct column gets
200 /// made smaller.
201 Struct,
202 /// One row id per row, into a source vector that is far longer than this one.
203 ///
204 /// The form a link join's parent columns are in, per `spec/graph/08-vector-engine.md` section
205 /// 8.2. Physically it is [`Form::Dictionary`] and logically it is the opposite of one, which is
206 /// why it is a form of its own rather than a dictionary with a note on it. A dictionary promises
207 /// that the values are few and distinct, and every kernel that has a dictionary arm takes that
208 /// promise by folding the operation over the values once and then indexing. A gather's source is
209 /// a whole parent table, so folding over it to answer two thousand rows reads fifteen million
210 /// values for nothing. Both forms want the same code and they want it under opposite conditions,
211 /// so the condition is [`Vector::fold_over_source`] and the form is what makes a kernel ask.
212 Gathered,
213}
214
215/// The values of a flat vector, one Rust vector per physical type.
216///
217/// The variants are physical rather than logical, which is what lets `DATE` and `INTEGER` share
218/// storage and share a kernel. What a run of `i32` means is the vector's logical type's business.
219#[derive(Debug, Clone, PartialEq)]
220#[non_exhaustive]
221pub enum Data {
222 /// No values, for the type of an untyped `NULL`.
223 Empty,
224 /// One byte per value.
225 Bool(Buffer<bool>),
226 /// 8 bit signed.
227 Int8(Buffer<i8>),
228 /// 16 bit signed.
229 Int16(Buffer<i16>),
230 /// 32 bit signed.
231 Int32(Buffer<i32>),
232 /// 64 bit signed.
233 Int64(Buffer<i64>),
234 /// 128 bit signed.
235 Int128(Buffer<i128>),
236 /// 8 bit unsigned.
237 UInt8(Buffer<u8>),
238 /// 16 bit unsigned.
239 UInt16(Buffer<u16>),
240 /// 32 bit unsigned.
241 UInt32(Buffer<u32>),
242 /// 64 bit unsigned.
243 UInt64(Buffer<u64>),
244 /// 128 bit unsigned.
245 UInt128(Buffer<u128>),
246 /// IEEE 754 binary32.
247 Float32(Buffer<f32>),
248 /// IEEE 754 binary64.
249 Float64(Buffer<f64>),
250 /// The months, days and microseconds triple.
251 Interval(Buffer<(i32, i32, i64)>),
252 /// Strings, as 16 byte views plus the arena the long ones live in.
253 Varlen(StringColumn),
254}
255
256impl Data {
257 /// How many values are stored.
258 ///
259 /// The match below has no wildcard arm, and that is what makes this function the check that
260 /// keeps [`for_each_layout`](crate::for_each_layout) honest. A variant added to this enum
261 /// without being added to the `all` group fails to compile here, which is a line in a build log
262 /// rather than a layout quietly missing from six kernels.
263 #[must_use]
264 pub fn len(&self) -> usize {
265 macro_rules! lengths {
266 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
267 match self {
268 Self::Empty => 0,
269 $(Self::$variant(values) => values.len(),)+
270 }
271 };
272 }
273 crate::for_each_layout!(all, lengths)
274 }
275
276 /// Whether there are no values.
277 #[must_use]
278 pub fn is_empty(&self) -> bool {
279 self.len() == 0
280 }
281
282 /// How many bytes of memory these values are holding.
283 ///
284 /// One arm per layout through the same macro as [`Data::len`], for the same reason: a layout
285 /// added without a size here is a layout the memory limit would charge nothing for, and a
286 /// buffer that is free is a buffer that can be grown until the process dies.
287 #[must_use]
288 pub fn footprint(&self) -> usize {
289 macro_rules! sizes {
290 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
291 match self {
292 Self::Empty => 0,
293 $(Self::$variant(values) => values.footprint(),)+
294 }
295 };
296 }
297 crate::for_each_layout!(all, sizes)
298 }
299
300 /// These values held as a page, so that copying or cutting them does not copy the values.
301 ///
302 /// For a producer that is going to hand the same values out many times, which is what a stored
303 /// column is. It costs one `Arc` per layout and moves the run into it without touching a value,
304 /// and after it a write through any reader copies out rather than writing the page, which is
305 /// [`Buffer::to_mut`]. A run that is already a page comes back as it was.
306 #[must_use]
307 pub fn into_pages(self) -> Self {
308 macro_rules! paged {
309 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
310 match self {
311 Self::Empty => Self::Empty,
312 $(Self::$variant(values) => Self::$variant(values.into_page()),)+
313 }
314 };
315 }
316 crate::for_each_layout!(all, paged)
317 }
318
319 /// An integer at `index`, widened, for any of the signed integer layouts.
320 ///
321 /// Used by the decimal path, which needs the unscaled value out of whichever width the width
322 /// and scale picked, and by anything else that would otherwise repeat the same five arms.
323 #[must_use]
324 pub fn signed_at(&self, index: usize) -> Option<i128> {
325 macro_rules! widened {
326 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
327 match self {
328 $(Self::$variant(v) => v.get(index).map(|&x| i128::from(x)),)+
329 _ => None,
330 }
331 };
332 }
333 crate::for_each_layout!(signed, widened)
334 }
335
336 /// The first `len` signed integers, widened to `i64`, appended to `out`.
337 ///
338 /// The bulk form of [`Self::signed_at`]. Four of the five signed layouts, because the fifth is
339 /// 128 bits wide and does not fit what this hands back. `Int64` is a copy of the run and the
340 /// three narrower ones are a sign extension the compiler turns into one instruction per lane.
341 ///
342 /// `false`, leaving `out` as it found it, for the wide layout, for a run shorter than `len` and
343 /// for every layout that is not a signed integer.
344 #[must_use]
345 pub fn signed_block(&self, len: usize, out: &mut Vec<i64>) -> bool {
346 match self {
347 Self::Int8(v) => widen(v.as_slice(), len, out),
348 Self::Int16(v) => widen(v.as_slice(), len, out),
349 Self::Int32(v) => widen(v.as_slice(), len, out),
350 Self::Int64(v) => match v.as_slice().get(..len) {
351 Some(run) => {
352 out.extend_from_slice(run);
353 true
354 }
355 None => false,
356 },
357 _ => false,
358 }
359 }
360
361 /// The signed integers at the rows `at` names among the first `len`, widened to `i64`,
362 /// appended to `out`.
363 ///
364 /// The gathered form of [`Self::signed_block`], for the rows a filter kept. Widening the whole
365 /// run and then picking the kept rows out of it is a pass over every row and a second over the
366 /// kept ones, where this is the one pass. `false`, leaving `out` as it found it, where
367 /// [`Self::signed_block`] says `false`, and for a row that is not among the first `len`.
368 #[must_use]
369 pub fn signed_gather(&self, len: usize, at: &[u32], out: &mut Vec<i64>) -> bool {
370 match self {
371 Self::Int8(v) => gather_widened(v.as_slice(), len, at, out),
372 Self::Int16(v) => gather_widened(v.as_slice(), len, at, out),
373 Self::Int32(v) => gather_widened(v.as_slice(), len, at, out),
374 Self::Int64(v) => gather_widened(v.as_slice(), len, at, out),
375 _ => false,
376 }
377 }
378
379 /// The runs of equal signed integers among rows `from..to` of the first `len`, each as its
380 /// value widened to `i64` and the row it ends before, appended to `out`.
381 ///
382 /// `false`, with `out` cleared, where [`Self::signed_block`] says `false`, for rows past `len`,
383 /// and once there are more than one run for every `every` rows read so far, give or take a
384 /// block, so that a column in no order is given up on after its first few blocks.
385 #[must_use]
386 pub fn signed_runs(
387 &self,
388 len: usize,
389 (from, to): (usize, usize),
390 every: usize,
391 out: &mut Vec<(i64, usize)>,
392 ) -> bool {
393 match self {
394 Self::Int8(v) => runs_widened(v.as_slice(), len, (from, to), every, out),
395 Self::Int16(v) => runs_widened(v.as_slice(), len, (from, to), every, out),
396 Self::Int32(v) => runs_widened(v.as_slice(), len, (from, to), every, out),
397 Self::Int64(v) => runs_widened(v.as_slice(), len, (from, to), every, out),
398 _ => false,
399 }
400 }
401
402 /// An unsigned integer at `index`, widened.
403 #[must_use]
404 pub fn unsigned_at(&self, index: usize) -> Option<u128> {
405 macro_rules! widened {
406 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
407 match self {
408 $(Self::$variant(v) => v.get(index).map(|&x| u128::from(x)),)+
409 _ => None,
410 }
411 };
412 }
413 crate::for_each_layout!(unsigned, widened)
414 }
415
416 /// The string at `index`, for a `Varlen`.
417 #[must_use]
418 pub fn str_at(&self, index: usize) -> Option<&str> {
419 match self {
420 Self::Varlen(column) => column.get(index),
421 _ => None,
422 }
423 }
424
425 /// The bytes at `index`, for a `Varlen`, whatever they are.
426 ///
427 /// What a `BLOB` reads through, since the bytes of one are not required to be text and
428 /// [`Self::str_at`] answers `None` for the ones that are not.
429 #[must_use]
430 pub fn bytes_at(&self, index: usize) -> Option<&[u8]> {
431 match self {
432 Self::Varlen(column) => column.bytes(index),
433 _ => None,
434 }
435 }
436}
437
438/// A type, a length, a validity representation and some data.
439#[derive(Debug, Clone, PartialEq)]
440pub struct Vector {
441 ty: LogicalType,
442 len: usize,
443 validity: Validity,
444 body: Body,
445}
446
447/// What the vector holds, which is what its form is decided by.
448#[derive(Debug, Clone, PartialEq)]
449enum Body {
450 Flat(Data),
451 Constant(Box<Value>),
452 Sequence {
453 start: i64,
454 step: i64,
455 },
456 /// The values are behind an `Arc` rather than a `Box` because slicing shares them.
457 ///
458 /// A dictionary vector is cut once per chunk and the dictionary itself is the same dictionary
459 /// every time, so a `Box` meant a copy of every value in it per cut. On the ClickBench columns
460 /// that are dictionary encoded the dictionary is larger than the chunk of codes pointing into
461 /// it, and copying it was ten percent of the cycles of reading the file.
462 ///
463 /// Nothing here mutates a dictionary in place, so sharing one is only ever a read, and the one
464 /// place that wants an owned copy of the values is [`compose`], which asks for one.
465 Dictionary {
466 codes: Buffer<u32>,
467 values: Arc<Vector>,
468 stable: bool,
469 },
470 /// Integer codes of `width` bits each, packed end to end, each one an offset from `base`.
471 ///
472 /// Row `r` is the `width` bits starting at bit `(offset + r) * width`, read little end first, so
473 /// a code that straddles a word boundary has its low bits in the earlier word. `offset` is what
474 /// lets a cut of a packed column be free: the bits are not byte aligned, so a slice either
475 /// repacks or remembers where it starts, and remembering is one addition per read.
476 ///
477 /// The words are behind an `Arc` for the reason the dictionary's values are. A page is packed
478 /// once and cut into chunk sized pieces, and copying the words per cut would undo most of what
479 /// the packing saved.
480 Packed {
481 words: Arc<Vec<u64>>,
482 width: u32,
483 base: i128,
484 offset: usize,
485 },
486 /// The views of a string column, over an arena that other vectors are reading at the same time.
487 ///
488 /// The views are owned because a cut is a different run of views, and the arena is shared
489 /// because a cut is the same bytes. That split is the whole form: sixteen bytes a row move and
490 /// the payload does not, however many cuts a page is taken in.
491 ///
492 /// A row's bytes are found the same way [`StringColumn`] finds them, through
493 /// [`StringView::bytes_in`], so a short string never reads the arena at all and the two ways of
494 /// holding strings cannot answer a row differently.
495 Views {
496 views: Vec<StringView>,
497 arena: Arc<Buffer<u8>>,
498 },
499 /// Text owned by a storage source and fetched by position.
500 ExternalText {
501 source: Arc<dyn TextSource>,
502 },
503 /// The FSST codes of every row, end to end, with one symbol table over all of them.
504 ///
505 /// A span rather than a run of offsets, because a gather keeps this form and a gather puts the
506 /// rows in an order the codes are not in. Eight bytes a row either way, and the span is the one
507 /// that survives being permuted.
508 ///
509 /// The codes and the table are shared for the reason a dictionary's values are: one table is
510 /// trained per page and every chunk cut out of it points at the same one. A table is sixty five
511 /// thousand hash slots, so a table per chunk would cost more than the compression saves.
512 Coded {
513 codes: Arc<Vec<u8>>,
514 spans: Vec<(u32, u32)>,
515 table: Arc<SymbolTable>,
516 },
517 /// One value per run, with the row each run ends at, exclusive and increasing.
518 ///
519 /// Ends rather than lengths, because every reader of this wants to know which run holds a row
520 /// and ends answer that with a binary search while lengths answer it with a running total. The
521 /// two are the same information and only one of them is the one that gets asked for.
522 ///
523 /// The values are behind an `Arc` for the reason the dictionary's are: a page is cut into chunk
524 /// sized pieces and the values are the same values every time.
525 Runs {
526 ends: Vec<u32>,
527 values: Arc<Vector>,
528 },
529 /// One child vector holding every element of every row, and a start and a length per row.
530 ///
531 /// Start and length rather than the run of offsets Arrow carries, because offsets say where a
532 /// row ends by saying where the next one begins, and that is only true while the rows are in
533 /// order and none is skipped. A gather permutes the rows and a filter drops them, both of which
534 /// this form has to survive without copying the child, so each row says where its own elements
535 /// are and nothing is implied about its neighbour.
536 ///
537 /// The child is behind an `Arc` for the reason a dictionary's values are. A cut of a list column
538 /// is the entries and nothing else, so a page of lists taken in chunk sized pieces holds one
539 /// child however many pieces it is read in, and the elements outside the cut stay reachable but
540 /// unreferenced rather than being copied out.
541 ///
542 /// A null list and an empty list are different rows and this is where the difference lives. A
543 /// null is the validity mask at this level being false, the same as for any other type, and its
544 /// entry is `(start, 0)` and never read. An empty list is a valid row whose entry is `(start, 0)`
545 /// as well. So the entry alone does not say which one a row is, the mask does, which is the same
546 /// division of labour every other form here uses.
547 ///
548 /// A `MAP` is stored here too, with a [`Body::Fields`] child of `key` and `value`. Everything above
549 /// is true of it unchanged, which is the point of storing it this way: the cut, the gather and the
550 /// null rule are written once and a map inherits all three.
551 Nested {
552 entries: Vec<(u32, u32)>,
553 child: Arc<Vector>,
554 },
555 /// One child vector per field, in the order the type names them, each as long as this vector.
556 ///
557 /// No entries, which is the whole difference from [`Body::Nested`]. A list row is a run of
558 /// elements so it needs to say where its run is, and a struct row is one value per field so row
559 /// `r` of field `f` is position `r` of child `f` and there is nothing to record. That makes a cut
560 /// a cut of every child and a gather a gather of every child, both at the same positions, rather
561 /// than a rewrite of an index.
562 ///
563 /// The children are behind an `Arc` for the reason a dictionary's values are, and it pays off less
564 /// often here. A cut of a list column shares its child untouched because the entries carry the
565 /// range, and a cut of a struct column has to cut each child, so the sharing only survives the
566 /// cases where nothing moves. It is still worth having, because a struct of a hundred fields
567 /// handed between operators is a hundred pointers rather than a hundred columns.
568 ///
569 /// A null struct is the validity mask at this level being false and says nothing about the
570 /// children, which still hold whatever was put in them at that row. That is DuckDB's behaviour and
571 /// it is the reason this form cannot decide a row is null by looking down: the mask is the answer,
572 /// the same as it is for a list.
573 Fields {
574 children: Vec<Arc<Vector>>,
575 },
576 /// Row `r` is row `rids[offset + r]` of `source`, and is null where that is [`NO_ROW`].
577 ///
578 /// Late materialization written into the type system. A link join emits one of these per
579 /// projected parent column and reads nothing out of the parent at all, so a column that is
580 /// projected but never inspected is read once at the end for the rows that reached the end, and
581 /// a column used in a filter is filtered in this form over the distinct parent rows that were
582 /// actually reached rather than once per child row.
583 ///
584 /// The `rids` are shared and carry an `offset` for the reason [`Body::Packed`] carries one: a
585 /// link join fills one buffer of parent rows per child chunk and then the pipeline cuts it, and
586 /// a cut that copied the ids would spend more moving them than the gather it is describing
587 /// costs. Sharing makes a cut two words.
588 ///
589 /// [`NO_ROW`] is the whole of the outer join story here. Section 5.2 says a left link join keeps
590 /// the child rows whose link is the no parent sentinel and gathers null for them, and an inner
591 /// one drops them, so the operator decides which rows exist and this decides only what they
592 /// hold. That keeps the validity of a gather derivable rather than stored: a row is null when
593 /// its id is [`NO_ROW`] or when the source row it names is null, which is two loads and no
594 /// allocation, and the bitmap is materialized only when a kernel asks for one.
595 Gathered {
596 source: Arc<Vector>,
597 rids: Arc<Vec<u32>>,
598 offset: usize,
599 },
600}
601
602/// Random access to immutable text kept by a storage reader.
603pub trait TextSource: std::fmt::Debug + Send + Sync {
604 /// Number of values available.
605 fn len(&self) -> usize;
606 /// Whether this source has no values.
607 fn is_empty(&self) -> bool {
608 self.len() == 0
609 }
610 /// Bytes at one position, or no value when the position is outside the source.
611 fn bytes_at(&self, index: usize) -> Result<Option<&[u8]>>;
612 /// Byte length at one position without requiring the payload when the source has an index.
613 fn bytes_len_at(&self, index: usize) -> Result<Option<usize>> {
614 Ok(self.bytes_at(index)?.map(<[u8]>::len))
615 }
616 /// The byte length at each of `indices`, appended to `into` in the same order, and zero for a
617 /// position the source does not have.
618 ///
619 /// The same answers as [`bytes_len_at`](Self::bytes_len_at) a position at a time, which is what
620 /// the default does. A source overrides it when it can answer a run of positions for less than
621 /// the run of calls: a length asked once per row goes through a dispatch here, a dispatch in the
622 /// vector and a `Result` at each, and on a column whose lengths are one load each that was most
623 /// of what `STRLEN` cost. Appended rather than written into place, so that the caller has no
624 /// zeroed buffer to make first only for every slot of it to be written over.
625 fn bytes_lens_at(&self, indices: &[u32], into: &mut Vec<i64>) -> Result<()> {
626 into.reserve(indices.len());
627 for &index in indices {
628 let len = self.bytes_len_at(index as usize)?.unwrap_or_default();
629 into.push(i64::try_from(len).unwrap_or(i64::MAX));
630 }
631 Ok(())
632 }
633 /// The length in characters at each of `indices`, appended to `into` in the same order, and
634 /// zero for a position the source does not have.
635 ///
636 /// What `length` asks for, where [`bytes_lens_at`](Self::bytes_lens_at) is what `strlen` asks
637 /// for. Counting characters means looking at the bytes, and the default does that through
638 /// [`bytes_at`](Self::bytes_at), which is right for a source that keeps its values anyway. A
639 /// source that decodes a block to answer `bytes_at` keeps that block for as long as it lives,
640 /// so a scan of `length` over a whole column ends up holding the whole column decoded. Such a
641 /// source overrides this and keeps the counts instead of the bytes.
642 fn chars_lens_at(&self, indices: &[u32], into: &mut Vec<i64>) -> Result<()> {
643 into.reserve(indices.len());
644 for &index in indices {
645 let bytes = self.bytes_at(index as usize)?.unwrap_or_default();
646 // A continuation byte of UTF-8 is `0b10xx_xxxx`, and every other byte starts a
647 // character, so counting the bytes that are not continuations counts the characters.
648 let characters = bytes.iter().filter(|byte| (**byte as i8) >= -0x40).count();
649 into.push(i64::try_from(characters).unwrap_or(i64::MAX));
650 }
651 Ok(())
652 }
653 /// Hands `body` the values from `first` up to at most `limit`, and answers where it stopped.
654 ///
655 /// The point of it is what it does not do, which is keep what it read.
656 /// [`bytes_at`](Self::bytes_at) hands back a borrow, so a source that decodes a block to answer
657 /// it has to hold that block for as long as the source lives, and a reader that walks the whole
658 /// source therefore ends up holding the whole thing decoded. On the ClickBench `URL` dictionary
659 /// that is 4.2 GB resident to answer one `LIKE`, and none of it is read twice.
660 ///
661 /// A caller that means to walk a stretch of values once calls this instead and gets the bytes
662 /// on loan for the length of the call. The source decides how much it hands over at a time,
663 /// which for a blocked payload is the rest of the block it had to decode anyway, and answers
664 /// with one past the last value it visited so the caller can come back for the next stretch.
665 /// The answer is always above `first` where `first` is a value this source has, so a loop on it
666 /// finishes.
667 ///
668 /// The default hands over one value through `bytes_at` and is correct for every source. It is
669 /// also pointless for a source that keeps everything anyway, which is every source built in
670 /// memory, and that is the right default for exactly that reason.
671 fn sweep(
672 &self,
673 first: usize,
674 limit: usize,
675 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
676 ) -> Result<usize> {
677 if first >= limit.min(self.len()) {
678 return Ok(first);
679 }
680 body(first, self.bytes_at(first)?.unwrap_or_default())?;
681 Ok(first + 1)
682 }
683 /// Hands `body` the value at each of `indices`, in whatever order suits the source, with the
684 /// position in `indices` it belongs to.
685 ///
686 /// The whole vector twin of [`bytes_at`](Self::bytes_at), for a kernel that reads every row of
687 /// a vector once and writes something per row, which is what `lower`, `upper` and `substring`
688 /// do. Read a row at a time, a source that decodes a block to answer `bytes_at` has to keep
689 /// every block a row lands in for as long as the source lives, because the borrow it hands back
690 /// says so. Handed a whole vector of positions at once it can put them in block order, decode
691 /// each block once for the call and decide for itself whether that block is worth keeping.
692 ///
693 /// A position the source does not have gets the empty value, which is what a row at a time
694 /// read turns its missing value into. The default reads through `bytes_at` in the order given,
695 /// which is right for every source that keeps its values anyway.
696 fn visit_at(
697 &self,
698 indices: &[u32],
699 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
700 ) -> Result<()> {
701 for (at, &index) in indices.iter().enumerate() {
702 body(at, self.bytes_at(index as usize)?.unwrap_or_default())?;
703 }
704 Ok(())
705 }
706 /// Whether the payload block holding `first` might contain `literal` in any value.
707 ///
708 /// A false answer is a proof that every value in the block misses. A source without a stored
709 /// substring signature answers true, which keeps the ordinary exact comparison authoritative.
710 fn might_contain(&self, first: usize, literal: &[u8]) -> Result<bool> {
711 let _ = (first, literal);
712 Ok(true)
713 }
714 /// Hands over the values at `indices`, which rise, without keeping what reading them decoded.
715 ///
716 /// The scattered twin of [`sweep`](Self::sweep). A caller that wants a few hundred values spread
717 /// over the whole source once, which is what turning a frequency synopsis's codes into values
718 /// is, would otherwise leave every block it touched decoded and held for the rest of the
719 /// source's life. On ClickBench `SearchPhrase` that is a hundred and twenty five blocks, the
720 /// larger part of what a query answered out of the synopsis was holding.
721 ///
722 /// `body` is told the position in `indices` and the bytes. The default reads through
723 /// `bytes_at`, which is right for every source that keeps everything anyway.
724 fn visit(
725 &self,
726 indices: &[usize],
727 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
728 ) -> Result<()> {
729 for (at, &index) in indices.iter().enumerate() {
730 body(at, self.bytes_at(index)?.unwrap_or_default())?;
731 }
732 Ok(())
733 }
734 /// Resident bytes retained by this source.
735 fn footprint(&self) -> usize;
736 /// How many ranks this source's sorted value order has, when it has one.
737 ///
738 /// A rank is a position in the values sorted by their bytes, so rank zero is the smallest value
739 /// and rank `ranks() - 1` is the largest. A storage format that keeps a dictionary for a whole
740 /// column can afford to sort the distinct values once when it writes the file, and what that
741 /// buys is a binary search where a reader that only knows the values are distinct has to ask
742 /// every one of them whether it matches.
743 ///
744 /// `None` means the source does not know its order, which is the honest answer for anything
745 /// built in memory and for a file written before its format stored one. Nothing is allowed to
746 /// depend on this for correctness, only for speed.
747 ///
748 /// A source that answers with `Some` promises the ranks cover every value it has, and that
749 /// [`compare_rank`](Self::compare_rank) is consistent with an ordering in which the values are
750 /// strictly increasing. Strictly, which is to say the values are distinct, because what reads
751 /// this searches it, and a search of a run of equal values finds one of them rather than all of
752 /// them. A source that holds the same value twice must answer `None` here even though it could
753 /// sort itself perfectly well.
754 fn ranks(&self) -> Option<usize> {
755 None
756 }
757 /// How the value at `rank` compares against `wanted`.
758 ///
759 /// This is a method rather than a slice of positions the caller indexes because the answer is
760 /// the only thing a search wants, and a source that knows that can answer most probes without
761 /// reading a value at all. A file that stores the first few bytes of each value in rank order
762 /// settles every probe from those bytes except the ones where two values start the same way,
763 /// and the payload stays untouched. A caller handed positions instead would have to read a
764 /// value per probe, which for a dictionary of half a million entries spread over thirty
765 /// megabytes is a fresh block of the file every time.
766 ///
767 /// Only called for a rank below [`ranks`](Self::ranks), so the default is the error a source
768 /// that has no order should never be asked to produce.
769 fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
770 let _ = (rank, wanted);
771 Err(Error::internal("a text source without a sorted order was asked to compare a rank"))
772 }
773 /// How many values sort before `wanted`, and whether one of them is `wanted`.
774 ///
775 /// The whole search rather than a probe of it, so that a source which can answer the same
776 /// question twice without repeating the work is allowed to. The default runs the search through
777 /// [`compare_rank`](Self::compare_rank) and remembers nothing, which is right for a source whose
778 /// probes are cheap.
779 ///
780 /// The reason it is on the trait at all is the top N. `ORDER BY <varchar> LIMIT 10` asks once a
781 /// chunk whether anything left can beat the worst candidate, and the worst candidate stops
782 /// changing long before the chunks run out, so nearly every one of those searches is the one
783 /// before it asked again. A probe of a file backed dictionary is not cheap: it settles on the
784 /// stored head where it can and reads a value where it cannot, and reading a value means
785 /// decoding the payload block it sits in. On ClickBench 25 that search was 29 percent of the
786 /// query's instructions and the block decoding under it another 40.
787 ///
788 /// Only called when [`ranks`](Self::ranks) is `Some`, and `ranks` is what it answered.
789 fn below(&self, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)> {
790 search_below(self, ranks, wanted)
791 }
792 /// The position of the value at `rank`, which is what a search returns once it has found one.
793 ///
794 /// Called about once per search rather than once per probe, so unlike
795 /// [`compare_rank`](Self::compare_rank) it is free to be the expensive one.
796 fn code_at_rank(&self, rank: usize) -> Result<u32> {
797 let _ = rank;
798 Err(Error::internal("a text source without a sorted order was asked for a rank"))
799 }
800 /// The rank of every value, in position order, when the source can hand the whole map over.
801 ///
802 /// This is [`code_at_rank`](Self::code_at_rank) turned round, and it is a separate method
803 /// because the two are wanted by opposite kinds of reader. A search wants one code out of a
804 /// rank and probes a handful of times, so it reads the order a block at a time and leaves the
805 /// rest alone. A min or a max over a grouped column wants a rank out of a code once per row,
806 /// and a walk of the order per row costs far more than reading the order once and turning it
807 /// round. What that buys is a comparison of two integers where the alternative is a fetch of
808 /// two strings out of a payload the size of the column.
809 ///
810 /// The slice is indexed by position and is as long as [`len`](Self::len), so a caller holding a
811 /// dictionary code indexes it directly.
812 ///
813 /// `None` from a source with no order, and from one with an order it would rather not invert.
814 /// Nothing depends on this for correctness, only for speed.
815 fn code_ranks(&self) -> Option<&[u32]> {
816 None
817 }
818 /// Whether another source presents the same values.
819 fn equal(&self, other: &dyn TextSource) -> bool {
820 self.len() == other.len()
821 && (0..self.len()).all(|index| {
822 matches!(
823 (self.bytes_at(index), other.bytes_at(index)),
824 (Ok(left), Ok(right)) if left == right
825 )
826 })
827 }
828}
829
830impl PartialEq for dyn TextSource {
831 fn eq(&self, other: &Self) -> bool {
832 self.equal(other)
833 }
834}
835
836/// The binary search behind [`TextSource::below`], written once so an override can still use it.
837///
838/// A source that remembers its answers overrides `below` to look in what it remembers first, and
839/// then it still has to do the search when it does not find one. This is that search. It carries on
840/// past an equal probe to the first rank holding the value, so what it returns is a boundary rather
841/// than wherever the halving happened to touch down, and the values are distinct so there is exactly
842/// one such rank.
843///
844/// # Errors
845///
846/// Whatever [`TextSource::compare_rank`] gives for a probe.
847pub fn search_below<S>(source: &S, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)>
848where
849 S: TextSource + ?Sized,
850{
851 let mut low = 0;
852 let mut high = ranks;
853 let mut equal = false;
854 while low < high {
855 let middle = low + (high - low) / 2;
856 match source.compare_rank(middle, wanted)? {
857 Ordering::Less => low = middle + 1,
858 Ordering::Greater => high = middle,
859 Ordering::Equal => {
860 equal = true;
861 high = middle;
862 }
863 }
864 }
865 Ok((low, equal))
866}
867
868impl Vector {
869 /// A flat vector of `data`, all valid.
870 ///
871 /// # Errors
872 ///
873 /// If the data's physical layout is not the one the type calls for. That check is here rather
874 /// than left to the caller because a vector whose type and layout disagree is a wrong answer
875 /// waiting to be read out, and it costs one comparison at construction to prevent.
876 pub fn flat(ty: LogicalType, data: Data) -> Result<Self> {
877 let len = data.len();
878 if !matches!(data, Data::Empty) && layout_of(&data) != ty.physical() {
879 return Err(Error::internal(format!(
880 "a {ty} vector cannot hold {:?} data",
881 layout_of(&data)
882 )));
883 }
884 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Flat(data) })
885 }
886
887 /// A flat vector built from single values, with the nulls among them turning into validity.
888 ///
889 /// The slow way in, and the only way in that anything outside this crate has. It is what an
890 /// `INSERT`, a `VALUES` clause and a test build a column with, all of which arrive holding
891 /// values rather than a run of `i32`. Nothing on a scan path calls it: a scan produces a run of
892 /// data directly and hands it to [`Self::flat`].
893 ///
894 /// # Errors
895 ///
896 /// If a value is not one the type can hold, or if the type is one there is no vector for yet,
897 /// which today means `ARRAY` and `UNION`. A `LIST`, a `STRUCT` and a `MAP` are routed to their own
898 /// builders and come back built.
899 pub fn from_values(ty: LogicalType, values: &[Value]) -> Result<Self> {
900 match &ty {
901 LogicalType::List(element) => {
902 return Self::list_from_values(element.as_ref().clone(), values);
903 }
904 LogicalType::Struct(fields) => return Self::struct_from_values(fields, values),
905 LogicalType::Map(key, value) => {
906 return Self::map_from_values(key.as_ref().clone(), value.as_ref().clone(), values);
907 }
908 _ => {}
909 }
910 let mut data = empty_data_for(&ty)?;
911 for value in values {
912 let value = stored(&ty, value)?;
913 push_value(&mut data, &value)?;
914 }
915 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
916 Ok(Self { ty, len: values.len(), validity, body: Body::Flat(data) })
917 }
918
919 /// A list vector of `element`, built from one [`Value::List`] per row.
920 ///
921 /// The elements of every row go into one child vector end to end, so a row's elements are a
922 /// contiguous range of it and a row is a start and a length into it. That is what makes a cut of
923 /// this form the entries and nothing else.
924 ///
925 /// A null row contributes no elements and gets an entry of length zero, which is the same entry
926 /// an empty list gets. The two are told apart by the validity mask rather than by the entry, for
927 /// the reason written on [`Body::Nested`].
928 fn list_from_values(element: LogicalType, values: &[Value]) -> Result<Self> {
929 let mut flat = Vec::new();
930 let mut entries = Vec::with_capacity(values.len());
931 for value in values {
932 let start = u32::try_from(flat.len())
933 .map_err(|_| Error::internal("a list column with more than u32 elements in it"))?;
934 match value {
935 Value::Null => entries.push((start, 0)),
936 Value::List { values: held, .. } => {
937 let len = u32::try_from(held.len())
938 .map_err(|_| Error::internal("a list longer than u32"))?;
939 flat.extend_from_slice(held);
940 entries.push((start, len));
941 }
942 other => {
943 return Err(Error::internal(format!(
944 "{other:?} does not belong in a list vector"
945 )));
946 }
947 }
948 }
949 // The element type is the column's rather than any one value's. A `Value::List` carries what
950 // it thinks it is empty of, and a column built from a row of `INTEGER[]` and a row of
951 // `[]::NULL[]` would otherwise take its type from whichever row came first.
952 let child = Self::from_values(element, &flat)?;
953 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
954 Ok(Self {
955 ty: LogicalType::list(child.ty.clone()),
956 len: values.len(),
957 validity,
958 body: Body::Nested { entries, child: Arc::new(child) },
959 })
960 }
961
962 /// A list vector over a child that already exists, one entry per row.
963 ///
964 /// What a scan and a list returning kernel build, both of which produce the elements in bulk and
965 /// then say which row each range belongs to. Every row is valid, since a caller with nulls to
966 /// record adds them with [`Self::with_validity`].
967 ///
968 /// # Errors
969 ///
970 /// If an entry runs past the end of the child, which would be a row that reads elements belonging
971 /// to nobody and is the one mistake this form makes easy.
972 pub fn list(entries: Vec<(u32, u32)>, child: Vector) -> Result<Self> {
973 let reach = child.len();
974 for &(start, len) in &entries {
975 if start as usize + len as usize > reach {
976 return Err(Error::internal(format!(
977 "a list entry of {len} at {start} in a child of {reach}"
978 )));
979 }
980 }
981 Ok(Self {
982 ty: LogicalType::list(child.ty.clone()),
983 len: entries.len(),
984 validity: Validity::AllValid,
985 body: Body::Nested { entries, child: Arc::new(child) },
986 })
987 }
988
989 /// A struct vector of `fields`, built from one [`Value::Struct`] per row.
990 ///
991 /// One pass per field rather than one pass per row, because each field becomes its own child
992 /// vector and a child is built from a run of values of one type. So a struct of three fields over
993 /// a thousand rows is three calls to [`Self::from_values`] and not a thousand.
994 ///
995 /// The fields are matched by name and not by position. A `Value::Struct` carries its names, and a
996 /// caller that built one in a different order from the type's would otherwise get the values
997 /// silently transposed into the wrong columns, which is the kind of wrong answer that reads as
998 /// right. A row missing a field the type names is an error rather than a null for the same reason.
999 ///
1000 /// A null row is a null in every child as well as a false bit in the mask here. [`Body::Fields`]
1001 /// says a null struct is allowed to have readable children and that is about a struct built out of
1002 /// children that already exist, where whatever is underneath is the caller's. Built from values
1003 /// there is nothing underneath to keep, so the children get the null.
1004 fn struct_from_values(fields: &[Field], values: &[Value]) -> Result<Self> {
1005 let mut children = Vec::with_capacity(fields.len());
1006 // An unnamed struct has no names to match on, so its fields are taken by place.
1007 let unnamed = Field::unnamed(fields);
1008 for (at, field) in fields.iter().enumerate() {
1009 let mut column = Vec::with_capacity(values.len());
1010 for value in values {
1011 column.push(match value {
1012 Value::Null => Value::Null,
1013 Value::Struct(held) if unnamed => held
1014 .get(at)
1015 .map(|(_, held)| held.clone())
1016 .ok_or_else(|| Error::internal("a tuple row shorter than its type"))?,
1017 Value::Struct(held) => held
1018 .iter()
1019 .find(|(name, _)| *name == field.name)
1020 .map(|(_, held)| held.clone())
1021 .ok_or_else(|| {
1022 Error::internal(format!(
1023 "a struct row with no {} field in it",
1024 field.name
1025 ))
1026 })?,
1027 other => {
1028 return Err(Error::internal(format!(
1029 "{other:?} does not belong in a struct vector"
1030 )));
1031 }
1032 });
1033 }
1034 children.push(Arc::new(Self::from_values(field.ty.clone(), &column)?));
1035 }
1036 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
1037 Ok(Self {
1038 ty: LogicalType::Struct(fields.to_vec()),
1039 len: values.len(),
1040 validity,
1041 body: Body::Fields { children },
1042 })
1043 }
1044
1045 /// A struct vector over children that already exist, one per field.
1046 ///
1047 /// What a scan and a struct returning kernel build, both of which produce each field as a column
1048 /// and then put them side by side. Every row is valid, since a caller with nulls to record adds
1049 /// them with [`Self::with_validity`].
1050 ///
1051 /// # Errors
1052 ///
1053 /// If there are no fields, or if the children are not all the same length. The first is not a
1054 /// fussy restriction: a struct vector with no children has no child to take its length from, so a
1055 /// zero field struct column would be a length with nothing to check it against, and a caller that
1056 /// wants a column of empty structs wants a constant vector of one.
1057 pub fn structure(children: Vec<(String, Vector)>) -> Result<Self> {
1058 let Some((_, first)) = children.first() else {
1059 return Err(Error::internal("a struct vector of no fields, which has no length"));
1060 };
1061 let len = first.len();
1062 for (name, child) in &children {
1063 if child.len() != len {
1064 return Err(Error::internal(format!(
1065 "a {} field of {} rows beside a struct of {len}",
1066 name,
1067 child.len()
1068 )));
1069 }
1070 }
1071 let fields = children
1072 .iter()
1073 .map(|(name, child)| Field::new(name.clone(), child.ty.clone()))
1074 .collect();
1075 let children = children.into_iter().map(|(_, child)| Arc::new(child)).collect();
1076 Ok(Self {
1077 ty: LogicalType::Struct(fields),
1078 len,
1079 validity: Validity::AllValid,
1080 body: Body::Fields { children },
1081 })
1082 }
1083
1084 /// The children, for a struct vector, and `None` for any other form.
1085 ///
1086 /// The accessor a kernel over a struct column reads, and the reason field extraction is free:
1087 /// picking one field out of a struct is picking one of these, so a projection of `s.a` hands back
1088 /// a vector that already exists rather than reading a row at a time and rebuilding a column.
1089 #[must_use]
1090 pub fn struct_parts(&self) -> Option<&[Arc<Self>]> {
1091 match &self.body {
1092 Body::Fields { children } => Some(children),
1093 _ => None,
1094 }
1095 }
1096
1097 /// A map vector, built from one [`Value::Map`] per row.
1098 ///
1099 /// A map is a list whose child is a two field struct of keys and values, which is what DuckDB
1100 /// stores and what Arrow and Parquet store, so this is the list builder and the struct builder
1101 /// composed rather than a third layout. The keys of every row go into one column end to end, the
1102 /// values into another beside it, and a row is a start and a length into the pair.
1103 ///
1104 /// The field names are [`MAP_KEY`] and [`MAP_VALUE`] because those are the names DuckDB gives them
1105 /// and the names anything reading a Parquet map field will expect to find.
1106 ///
1107 /// A null row and an empty map are both an entry of length zero, told apart by the validity mask,
1108 /// for the reason written on [`Body::Nested`].
1109 fn map_from_values(key: LogicalType, value: LogicalType, values: &[Value]) -> Result<Self> {
1110 let mut keys = Vec::new();
1111 let mut held = Vec::new();
1112 let mut entries = Vec::with_capacity(values.len());
1113 for row in values {
1114 let start = u32::try_from(keys.len())
1115 .map_err(|_| Error::internal("a map column with more than u32 entries in it"))?;
1116 match row {
1117 Value::Null => entries.push((start, 0)),
1118 Value::Map { entries: pairs, .. } => {
1119 let len = u32::try_from(pairs.len())
1120 .map_err(|_| Error::internal("a map with more than u32 entries"))?;
1121 for (one, other) in pairs {
1122 keys.push(one.clone());
1123 held.push(other.clone());
1124 }
1125 entries.push((start, len));
1126 }
1127 other => {
1128 return Err(Error::internal(format!(
1129 "{other:?} does not belong in a map vector"
1130 )));
1131 }
1132 }
1133 }
1134 // The two types are the column's rather than any one row's, for the reason the list builder
1135 // takes the element type from the column: a row that is the empty map carries whatever it was
1136 // built as being empty of, and the column is not entitled to take its type from that.
1137 let child = Self::structure(vec![
1138 (MAP_KEY.to_string(), Self::from_values(key, &keys)?),
1139 (MAP_VALUE.to_string(), Self::from_values(value, &held)?),
1140 ])?;
1141 let ty = LogicalType::map(
1142 fields_of(&child.ty)[0].ty.clone(),
1143 fields_of(&child.ty)[1].ty.clone(),
1144 );
1145 let validity = Validity::from_iter(values.len(), |index| !values[index].is_null());
1146 Ok(Self {
1147 ty,
1148 len: values.len(),
1149 validity,
1150 body: Body::Nested { entries, child: Arc::new(child) },
1151 })
1152 }
1153
1154 /// A map vector over a pair of columns that already exist, one entry per row.
1155 ///
1156 /// What a scan and a map returning kernel build. The keys and the values are two columns of the
1157 /// same length, and each row of the map is the same range of both. Every row is valid, since a
1158 /// caller with nulls to record adds them with [`Self::with_validity`].
1159 ///
1160 /// # Errors
1161 ///
1162 /// If the two columns are different lengths, or if an entry runs past the end of them.
1163 pub fn map(entries: Vec<(u32, u32)>, keys: Vector, values: Vector) -> Result<Self> {
1164 let key = keys.ty.clone();
1165 let value = values.ty.clone();
1166 let child =
1167 Self::structure(vec![(MAP_KEY.to_string(), keys), (MAP_VALUE.to_string(), values)])?;
1168 let mut vector = Self::list(entries, child)?;
1169 vector.ty = LogicalType::map(key, value);
1170 Ok(vector)
1171 }
1172
1173 /// The entries and the two columns, for a map vector, and `None` for anything else.
1174 ///
1175 /// Reaches through the struct child that a map is stored as, so that a kernel over a map column
1176 /// reads the keys and the values as the two columns they are rather than having to know that the
1177 /// pair is spelled as a struct underneath.
1178 #[must_use]
1179 pub fn map_parts(&self) -> Option<MapParts<'_>> {
1180 if !matches!(self.ty, LogicalType::Map(_, _)) {
1181 return None;
1182 }
1183 let (entries, child) = self.list_parts()?;
1184 let [keys, values] = child.struct_parts()? else { return None };
1185 Some((entries, keys, values))
1186 }
1187
1188 /// The entries and the child, for a list vector, and `None` for any other form.
1189 ///
1190 /// The accessor a kernel over a list column reads, for the reason
1191 /// [`Self::dictionary_parts`] exists: `unnest` over 1024 rows wants the child once and the
1192 /// entries once, and reading it through [`Self::value_at`] would build a `Value::List` per row
1193 /// and then throw every one of them away.
1194 ///
1195 /// A map answers here as well, with the struct child it is stored as, because this is a question
1196 /// about the layout and a map's layout is a list's. A caller that wants the keys and the values as
1197 /// two columns wants [`Self::map_parts`], which reaches through that child.
1198 #[must_use]
1199 pub fn list_parts(&self) -> Option<(&[(u32, u32)], &Self)> {
1200 match &self.body {
1201 Body::Nested { entries, child } => Some((entries, child)),
1202 _ => None,
1203 }
1204 }
1205
1206 /// A vector of `len` copies of one value.
1207 ///
1208 /// Costs one value regardless of the length, which is what makes a literal in a predicate free
1209 /// and what makes a projection of a constant free.
1210 #[must_use]
1211 pub fn constant(ty: LogicalType, value: Value, len: usize) -> Self {
1212 let validity = if value.is_null() { Validity::AllInvalid } else { Validity::AllValid };
1213 Self { ty, len, validity, body: Body::Constant(Box::new(value)) }
1214 }
1215
1216 /// A vector of `len` values starting at `start` and stepping by `step`.
1217 ///
1218 /// This is what a row identifier column is, and it costs sixteen bytes rather than eight
1219 /// kilobytes. A scan that produces row ids for a later fetch produces one of these.
1220 #[must_use]
1221 pub fn sequence(start: i64, step: i64, len: usize) -> Self {
1222 Self {
1223 ty: LogicalType::BigInt,
1224 len,
1225 validity: Validity::AllValid,
1226 body: Body::Sequence { start, step },
1227 }
1228 }
1229
1230 /// A vector of codes into a smaller vector of distinct values.
1231 ///
1232 /// The form the whole M3 thesis rests on. A dictionary vector handed to a group by is an
1233 /// integer column, and an aggregate over one is an aggregate over integers no matter what the
1234 /// logical type says.
1235 ///
1236 /// A dictionary over a dictionary is composed into one level here rather than left as two, so
1237 /// the form has a depth of one always and a kernel that reads [`Self::dictionary_parts`] is
1238 /// reading the values rather than another layer of codes. Two filters over the same chunk build
1239 /// the second case and four conjuncts pushed down separately build four of it.
1240 ///
1241 /// The cost of leaving them stacked turned out to be a cliff rather than a slope. Every loop in
1242 /// `rudb-kernels` reaches for the values behind the codes with [`Self::data`], a dictionary
1243 /// pointing at a dictionary has no data to hand back, so the second level does not make the
1244 /// kernels slower, it turns them off and drops the work onto the row at a time path that exists
1245 /// to be correct rather than fast. Measured on server3 over a chunk of two numeric columns and a
1246 /// consumer of two vectorized passes, one level reads at 3.5 nanoseconds a row and two levels at
1247 /// 104, and the third and fourth levels cost almost nothing more because the first one had
1248 /// already given up everything there was to give. Composing is one pass over the outer codes,
1249 /// which the range check above is already making.
1250 ///
1251 /// The one dictionary that is not composed past is one carrying a validity of its own. A
1252 /// dictionary is built all valid and only [`Self::with_validity`] can change that, so such a
1253 /// vector is saying that its nulls are at this level rather than in the values it points at, and
1254 /// composing past it would drop them.
1255 ///
1256 /// # Errors
1257 ///
1258 /// If any code is past the end of the value vector.
1259 pub fn dictionary(codes: Vec<u32>, values: Vector) -> Result<Self> {
1260 Self::dictionary_over(codes, Arc::new(values))
1261 }
1262
1263 /// The same, over a set of values somebody else is holding too.
1264 ///
1265 /// The body holds its values in an `Arc` either way, so a caller that already has one has
1266 /// nothing to hand over but a pointer. The caller this is for is a Parquet chunk: one dictionary
1267 /// page serves every data page of the chunk, and going through [`Self::dictionary`] meant
1268 /// copying the whole dictionary into each page's vector on the way to putting it in an `Arc`
1269 /// that then had a single holder. On a ClickBench scan that copy was sixteen percent of the
1270 /// instructions the query ran.
1271 ///
1272 /// Composing a dictionary over a dictionary keeps the handle too. The leaf of the stack is what
1273 /// the composed dictionary points at and neither its values nor anything about it changes, so
1274 /// there is nothing to own and the new dictionary shares the same leaf the old one did.
1275 ///
1276 /// The range check takes the highest code rather than stopping at the first bad one. Stopping
1277 /// early sounds cheaper and is not, because a loop that can exit anywhere cannot be vectorized
1278 /// and a running maximum can, and the only run that would have exited early is the one about to
1279 /// fail the query anyway. Every other run reads the whole of `codes` either way. It was 5.2
1280 /// percent of a ClickBench scan as a `find`.
1281 ///
1282 /// # Errors
1283 ///
1284 /// If any code is past the end of the value vector.
1285 pub fn dictionary_over(codes: Vec<u32>, values: Arc<Vector>) -> Result<Self> {
1286 if !below(&codes, values.len()) {
1287 let highest = codes.iter().copied().fold(0, u32::max);
1288 return Err(Error::internal(format!(
1289 "dictionary code {highest} is past the end of a {} value dictionary",
1290 values.len()
1291 )));
1292 }
1293 let (codes, values) = compose(codes, values);
1294 Ok(Self {
1295 ty: values.ty.clone(),
1296 len: codes.len(),
1297 validity: Validity::AllValid,
1298 body: Body::Dictionary { codes: Buffer::from_vec(codes), values, stable: false },
1299 })
1300 }
1301
1302 /// A dictionary whose codes keep the same meaning across every page of its source.
1303 pub fn stable_dictionary(codes: Vec<u32>, values: Arc<Vector>) -> Result<Self> {
1304 let mut vector = Self::dictionary_over(codes, values)?;
1305 if let Body::Dictionary { stable, .. } = &mut vector.body {
1306 *stable = true;
1307 }
1308 Ok(vector)
1309 }
1310
1311 /// A stable dictionary whose caller already found the largest code while decoding it.
1312 pub fn stable_dictionary_validated(
1313 codes: Vec<u32>,
1314 values: Arc<Vector>,
1315 highest: Option<u32>,
1316 ) -> Result<Self> {
1317 if highest.is_some_and(|code| code as usize >= values.len()) {
1318 return Err(Error::internal("a stable dictionary code is past its value dictionary"));
1319 }
1320 Ok(Self {
1321 ty: values.ty.clone(),
1322 len: codes.len(),
1323 validity: Validity::AllValid,
1324 body: Body::Dictionary { codes: Buffer::from_vec(codes), values, stable: true },
1325 })
1326 }
1327
1328 /// One row of `source` per id, without reading any of them.
1329 ///
1330 /// What a link join emits for each of its parent columns, per `spec/graph/08-vector-engine.md`
1331 /// section 8.2. Row `r` is row `rids[r]` of `source`, and is null where that is [`NO_ROW`].
1332 ///
1333 /// The ids are taken by `Arc` rather than by value because one link join fills one buffer of
1334 /// parent rows per child chunk and then hands the same buffer to every projected parent column,
1335 /// so a gather of eight columns is eight pointers and one buffer. [`Self::gathered_from`] is the
1336 /// same thing starting part way in, which is what a cut of one produces.
1337 ///
1338 /// # Errors
1339 ///
1340 /// If an id is past the end of the source and is not [`NO_ROW`]. That check is a pass over the
1341 /// ids and it is the only thing standing between a link built against the wrong parent and a
1342 /// read of whatever happens to be at that offset, so it is not optional and it is not deferred:
1343 /// `spec/graph/03-the-file-format.md` section 3.1 says a stale section is ignored rather than
1344 /// repaired, and this is where a stale one stops being ignorable.
1345 pub fn gathered(source: Arc<Vector>, rids: Arc<Vec<u32>>) -> Result<Self> {
1346 let len = rids.len();
1347 Self::gathered_from(source, rids, 0, len)
1348 }
1349
1350 /// The same, reading `len` ids starting at `offset`.
1351 ///
1352 /// # Errors
1353 ///
1354 /// If the range runs past the end of the ids, or if an id in it is past the end of the source.
1355 pub fn gathered_from(
1356 source: Arc<Vector>,
1357 rids: Arc<Vec<u32>>,
1358 offset: usize,
1359 len: usize,
1360 ) -> Result<Self> {
1361 let end = offset.checked_add(len).ok_or_else(|| Error::internal("a gather that wraps"))?;
1362 let Some(taken) = rids.get(offset..end) else {
1363 return Err(Error::internal(format!(
1364 "rows {offset} to {end} of a gather over {} ids",
1365 rids.len()
1366 )));
1367 };
1368 let rows = source.len();
1369 if taken.iter().any(|&rid| rid != NO_ROW && rid as usize >= rows) {
1370 return Err(Error::internal(format!(
1371 "a gathered row id is past the {rows} rows of its source"
1372 )));
1373 }
1374 Ok(Self {
1375 ty: source.ty.clone(),
1376 len,
1377 // The mask is all valid and the nulls are real, which is the same split a dictionary
1378 // makes: this level says every row exists and the body says what each one holds, and
1379 // `is_null_at` reads through to answer. A mask here would be a second copy of what the
1380 // ids already say and the two could disagree.
1381 validity: Validity::AllValid,
1382 body: Body::Gathered { source, rids, offset },
1383 })
1384 }
1385
1386 /// The source and the ids of a gathered vector, and `None` for any other form.
1387 #[must_use]
1388 pub fn gathered_parts(&self) -> Option<(&Arc<Self>, &[u32])> {
1389 match &self.body {
1390 Body::Gathered { source, rids, offset } => {
1391 Some((source, rids.get(*offset..offset + self.len)?))
1392 }
1393 _ => None,
1394 }
1395 }
1396
1397 /// Whether a kernel over this vector should fold over the source once and then index.
1398 ///
1399 /// Section 8.2's dispatch rule, which is one comparison and is the whole difference between a
1400 /// gather and a dictionary. Every kernel with a dictionary arm already folds over the values
1401 /// once and indexes, and that arm is right for a gather exactly when the source is shorter than
1402 /// the rows being answered. A dictionary always is, by construction. A gather off a parent
1403 /// table almost never is, and a kernel that took the dictionary arm anyway would read fifteen
1404 /// million parent rows to answer two thousand child ones.
1405 ///
1406 /// `false` for every other form, so a kernel can ask this without first asking what it has.
1407 #[must_use]
1408 pub fn fold_over_source(&self) -> bool {
1409 match &self.body {
1410 Body::Gathered { source, .. } => source.len() < self.len,
1411 _ => false,
1412 }
1413 }
1414
1415 /// A vector of runs, one value each, with the row each run ends at.
1416 ///
1417 /// `ends` is exclusive and strictly increasing, so run `i` covers the rows from `ends[i - 1]` to
1418 /// `ends[i]` and run zero starts at nothing. The length of the vector is the last end.
1419 ///
1420 /// The depth is one, the same way a dictionary's is, and for a sharper reason. Every kernel that
1421 /// wants runs wants the value of a run without another search, and a run length vector over a
1422 /// run length vector turns one search into two and then into three. Rather than compose, this
1423 /// refuses: nothing in the engine builds a stacked one, because [`Self::run_encoded`] only ever
1424 /// reads a flat body, so a stacked one is a caller doing something by hand and the useful answer
1425 /// is to say so rather than to quietly do a pass of work they did not ask for.
1426 ///
1427 /// A run over a dictionary is fine and is not that case. The two forms answer different
1428 /// questions and a column that is both clustered and low cardinality genuinely wants both.
1429 ///
1430 /// # Errors
1431 ///
1432 /// If there is not exactly one value per run, if the ends do not increase, or if the values are
1433 /// themselves run length encoded.
1434 pub fn runs(ends: Vec<u32>, values: Vector) -> Result<Self> {
1435 if matches!(values.body, Body::Runs { .. }) {
1436 return Err(Error::internal("runs of runs, which is two searches to read one row"));
1437 }
1438 if ends.len() != values.len() {
1439 return Err(Error::internal(format!(
1440 "{} runs and {} values to put in them",
1441 ends.len(),
1442 values.len()
1443 )));
1444 }
1445 if ends.windows(2).any(|pair| pair[0] >= pair[1]) || ends.first() == Some(&0) {
1446 return Err(Error::internal("run ends that do not increase"));
1447 }
1448 let len = ends.last().copied().unwrap_or(0) as usize;
1449 Ok(Self {
1450 ty: values.ty.clone(),
1451 len,
1452 validity: Validity::AllValid,
1453 body: Body::Runs { ends, values: Arc::new(values) },
1454 })
1455 }
1456
1457 /// The same values as runs, when there are few enough runs for that to be smaller.
1458 ///
1459 /// Costs one pass over the column to find out, which is why this is a call somebody makes rather
1460 /// than something a constructor does. The decision is the same arithmetic every time: a row in
1461 /// flat form costs one value, a run costs one value plus the four bytes of its end, so runs are
1462 /// smaller once there are fewer than about half as many runs as rows, and the narrower the
1463 /// column the more runs it takes. `RUNS_PAY_AT` is that ratio, written down rather than spelt
1464 /// into an `if`, because it is the number a sweep will want to move.
1465 ///
1466 /// Only a flat body is looked at. A constant and a sequence are already one value and two
1467 /// numbers, so there is nothing to win, and a dictionary that is also clustered is a real case
1468 /// that wants its codes run length encoded rather than its values, which is a different function
1469 /// and not this one.
1470 ///
1471 /// Two adjacent nulls are one run. Two adjacent equal values with a null between them are three,
1472 /// because the null is a value of the column as far as anything reading it is concerned.
1473 ///
1474 /// # Errors
1475 ///
1476 /// From the gather this does at the end, and nowhere else. A body that is not flat comes back
1477 /// unchanged rather than as an error, so a nested vector never reaches the part that can fail.
1478 pub fn run_encoded(&self) -> Result<Self> {
1479 let Body::Flat(data) = &self.body else {
1480 return Ok(self.clone());
1481 };
1482 let ends = boundaries(data, &self.validity, self.len);
1483 if ends.len().saturating_mul(RUNS_PAY_AT) >= self.len {
1484 return Ok(self.clone());
1485 }
1486 let starts: Vec<u32> =
1487 std::iter::once(0).chain(ends.iter().copied()).take(ends.len()).collect();
1488 Self::runs(ends, self.gather(&starts)?)
1489 }
1490
1491 /// A vector of `len` integers packed `width` bits each, every one an offset from `base`.
1492 ///
1493 /// The way in for a reader that already has the packed bits, which is what a column file holds
1494 /// and what a network frame carries. Nothing unpacks on the way in, so a scan of a packed column
1495 /// hands the bits straight to the chunk and the cost of the form is paid by whoever reads a
1496 /// value rather than by the scan.
1497 ///
1498 /// The range check is on the two ends rather than on every code, which is the whole check. A
1499 /// code is between zero and `2^width - 1` by construction, so if `base` and `base + 2^width - 1`
1500 /// both fit the column's layout then every value does, and that is two comparisons instead of
1501 /// one per row.
1502 ///
1503 /// # Errors
1504 ///
1505 /// If the type is not one of the integer layouts, if the width is not between one and
1506 /// [`PACKED_WIDTH_MAX`], if there are not enough words for the length, or if either end of the
1507 /// range would not fit the type.
1508 pub fn packed(
1509 ty: LogicalType,
1510 words: Vec<u64>,
1511 width: u32,
1512 base: i128,
1513 len: usize,
1514 ) -> Result<Self> {
1515 let Some((low, high)) = layout_range(&ty) else {
1516 return Err(Error::internal(format!("a {ty} vector has no integer layout to pack")));
1517 };
1518 if width == 0 || width > PACKED_WIDTH_MAX {
1519 return Err(Error::internal(format!(
1520 "a packed width of {width}, which is outside 1 to {PACKED_WIDTH_MAX}"
1521 )));
1522 }
1523 let needed = words_for(len, width);
1524 if words.len() < needed {
1525 return Err(Error::internal(format!(
1526 "{} words for {len} values of {width} bits, which needs {needed}",
1527 words.len()
1528 )));
1529 }
1530 let top = base + i128::from(u64::MAX >> (64 - width));
1531 if base < low || top > high {
1532 return Err(Error::internal(format!(
1533 "packed values from {base} to {top}, which a {ty} cannot hold"
1534 )));
1535 }
1536 Ok(Self {
1537 ty,
1538 len,
1539 validity: Validity::AllValid,
1540 body: Body::Packed { words: Arc::new(words), width, base, offset: 0 },
1541 })
1542 }
1543
1544 /// The same values bit packed, when the range of the column makes that smaller.
1545 ///
1546 /// Costs one pass to find the range and one to write the bits, which is why this is a call
1547 /// somebody makes rather than something a constructor does. It is the counterpart of
1548 /// [`Self::run_encoded`] and the decision has the same shape: a row flat costs the width of its
1549 /// layout, a row packed costs the bits the column's range needs, and the form is worth having
1550 /// only when the second is a good deal smaller than the first. [`PACKING_PAYS_AT`] is that
1551 /// ratio, written down rather than spelt into an `if`, because it is the number a sweep will
1552 /// want to move.
1553 ///
1554 /// Only a flat integer body is looked at. A constant and a sequence are already smaller than any
1555 /// packing of them, a dictionary's codes are the thing that would want packing rather than its
1556 /// values, and a float has no range to pack into since the bits of an `f64` are not an integer
1557 /// that arithmetic on the column agrees with.
1558 ///
1559 /// The range is taken over every slot including the null ones, which hold a zero. A column of
1560 /// large values with one null in it therefore packs a range that reaches down to zero and comes
1561 /// out wider than it needed to be. The alternative is a pass that consults the validity per slot
1562 /// to find the range and a second rule for what to write into a null slot, and this form exists
1563 /// to make reads cheap rather than to squeeze the last bit out of a sparse column.
1564 ///
1565 /// A column whose values are all the same packs to nothing at all, and rather than invent a zero
1566 /// bit code this declines and leaves it to [`Self::run_encoded`], which turns that column into
1567 /// one run and is smaller than any packing of it.
1568 ///
1569 /// # Errors
1570 ///
1571 /// If the packed bits and the length disagree, which would be a bug here rather than a caller
1572 /// doing something wrong.
1573 pub fn bit_packed(&self) -> Result<Self> {
1574 let Body::Flat(data) = &self.body else {
1575 return Ok(self.clone());
1576 };
1577 let Some((low, high)) = span_of(data, self.len) else {
1578 return Ok(self.clone());
1579 };
1580 let Some(range) = high.checked_sub(low).and_then(|range| u64::try_from(range).ok()) else {
1581 return Ok(self.clone());
1582 };
1583 let width = u64::BITS - range.leading_zeros();
1584 if width == 0 || width > PACKED_WIDTH_MAX {
1585 return Ok(self.clone());
1586 }
1587 // Against the bytes the rows take and not the footprint, because a window of a shared page
1588 // reports its share of the page. That made the answer, and so the file a load writes,
1589 // depend on how big the page was and how many readers it had.
1590 if words_for(self.len, width) * size_of::<u64>() * PACKING_PAYS_AT
1591 > flat_bytes(data, self.len)
1592 {
1593 return Ok(self.clone());
1594 }
1595 // A range can fit the type while that width up from the smallest value does not: a column
1596 // of a thousand values under `i32::MAX` needs ten bits, and ten bits up from the smallest
1597 // of them runs past `i32::MAX`. The packed form checks both ends of what its width can
1598 // say, so the base moves down until they both fit rather than the column being left flat.
1599 let Some(base) = packing_base(&self.ty, low, high, width) else {
1600 return Ok(self.clone());
1601 };
1602 let words = pack(data, self.len, base, width);
1603 let packed = Self::packed(self.ty.clone(), words, width, base, self.len)?;
1604 Ok(packed.with_validity(self.validity.clone()))
1605 }
1606
1607 /// A vector of string views over an arena somebody else is holding too.
1608 ///
1609 /// The way in for a scan that has a page of strings and wants several chunks over it. Each chunk
1610 /// gets its own run of views and they all share the one arena, so the bytes are read where the
1611 /// page put them and nothing copies them.
1612 ///
1613 /// Every view is checked against the arena here rather than when a row is read. That is a pass
1614 /// over the views at construction, which is the same pass the caller just did to build them, and
1615 /// what it buys is that a row of this form cannot resolve to bytes that are not there. The check
1616 /// is on the offsets and not on the bytes, so it says nothing about whether the payload is text,
1617 /// which is the same promise a `BLOB` column makes.
1618 ///
1619 /// # Errors
1620 ///
1621 /// If the type is not one stored as views, or if a view points past the end of the arena.
1622 pub fn string_views(
1623 ty: LogicalType,
1624 views: Vec<StringView>,
1625 arena: Arc<Buffer<u8>>,
1626 ) -> Result<Self> {
1627 if ty.physical() != rudb_common::PhysicalType::Varlen {
1628 return Err(Error::internal(format!("a {ty} vector cannot hold string views")));
1629 }
1630 if views.iter().any(|view| view.bytes_in(&arena).is_none()) {
1631 return Err(Error::internal("a string view points past the end of its arena"));
1632 }
1633 let len = views.len();
1634 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::Views { views, arena } })
1635 }
1636
1637 /// A text vector whose values remain in a storage source until they are read.
1638 pub fn external_text(ty: LogicalType, source: Arc<dyn TextSource>) -> Result<Self> {
1639 if ty.physical() != rudb_common::PhysicalType::Varlen {
1640 return Err(Error::internal(format!(
1641 "a {ty} vector cannot use an external text source"
1642 )));
1643 }
1644 let len = source.len();
1645 Ok(Self { ty, len, validity: Validity::AllValid, body: Body::ExternalText { source } })
1646 }
1647
1648 /// The same strings, in a form where a cut of them does not copy the bytes.
1649 ///
1650 /// The counterpart of [`Self::run_encoded`] and [`Self::bit_packed`] for a string column, and
1651 /// the only one of the three that takes `self` by value. It has to: what it does is move the
1652 /// arena into an `Arc` so nothing copies it again, and a version taking `&self` would start by
1653 /// copying the arena once to have one to move.
1654 ///
1655 /// Anything that is not a flat string column comes back as it was, which includes a column that
1656 /// is already in this form.
1657 ///
1658 /// # Errors
1659 ///
1660 /// Nothing here fails today. The result is a `Result` because the check inside
1661 /// [`Self::string_views`] is worth running on the views this builds rather than trusting that
1662 /// this function built them right.
1663 pub fn shared_text(self) -> Result<Self> {
1664 let Body::Flat(Data::Varlen(column)) = self.body else {
1665 return Ok(self);
1666 };
1667 let (views, arena) = column.into_parts();
1668 let shared = Self::string_views(self.ty, views, Arc::new(arena))?;
1669 Ok(shared.with_validity(self.validity))
1670 }
1671
1672 /// A vector of FSST codes against a table somebody else trained.
1673 ///
1674 /// The way in for a reader that has a page of compressed strings and the table that goes with
1675 /// it. The codes are not copied and the table is not retrained, so laying several chunks over
1676 /// one page costs the spans and nothing else.
1677 ///
1678 /// # Errors
1679 ///
1680 /// If the type is not one stored as text, or if a span runs past the end of the codes.
1681 pub fn coded(
1682 ty: LogicalType,
1683 codes: Arc<Vec<u8>>,
1684 spans: Vec<(u32, u32)>,
1685 table: Arc<SymbolTable>,
1686 ) -> Result<Self> {
1687 if ty.physical() != rudb_common::PhysicalType::Varlen {
1688 return Err(Error::internal(format!("a {ty} vector cannot hold FSST codes")));
1689 }
1690 let end = u32::try_from(codes.len()).unwrap_or(u32::MAX);
1691 if spans.iter().any(|&(from, to)| from > to || to > end) {
1692 return Err(Error::internal("an FSST span runs past the end of the codes"));
1693 }
1694 let len = spans.len();
1695 Ok(Self {
1696 ty,
1697 len,
1698 validity: Validity::AllValid,
1699 body: Body::Coded { codes, spans, table },
1700 })
1701 }
1702
1703 /// The same strings, compressed against a table trained on them.
1704 ///
1705 /// The counterpart of [`Self::run_encoded`] and [`Self::bit_packed`] for a text column, and it
1706 /// takes `self` by value for the reason [`Self::shared_text`] does.
1707 ///
1708 /// The table is trained on every row rather than on a sample. A vector is at most 1024 rows, so
1709 /// the sample would be most of the column anyway, and the systematic sampling
1710 /// `spec/06-compression.md` section 6.3 asks for is a decision about a page and belongs to
1711 /// whoever is holding one.
1712 ///
1713 /// It declines unless the codes are at most half the bytes the strings are. FSST gets about that
1714 /// on text and rather less on anything already short or already random, and below that the
1715 /// decompression per row read is not bought back. A column it declines on comes back as it was.
1716 ///
1717 /// # Errors
1718 ///
1719 /// Nothing here fails today. The result is a `Result` because the checks inside [`Self::coded`]
1720 /// are worth running on what this builds rather than trusting that this built it right.
1721 pub fn compressed(self) -> Result<Self> {
1722 let Body::Flat(Data::Varlen(column)) = &self.body else {
1723 return Ok(self);
1724 };
1725 let rows: Vec<&[u8]> = (0..self.len).filter_map(|row| column.bytes(row)).collect();
1726 if rows.len() != self.len {
1727 return Ok(self);
1728 }
1729 let plain: usize = rows.iter().map(|row| row.len()).sum();
1730 let table = SymbolTable::train(&rows);
1731 let mut codes = Vec::with_capacity(plain);
1732 let mut spans = Vec::with_capacity(self.len);
1733 for row in &rows {
1734 let from = u32::try_from(codes.len()).unwrap_or(u32::MAX);
1735 table.compress(row, &mut codes);
1736 spans.push((from, u32::try_from(codes.len()).unwrap_or(u32::MAX)));
1737 }
1738 if codes.len() * FSST_PAYS_AT > plain {
1739 return Ok(self);
1740 }
1741 let coded = Self::coded(self.ty.clone(), Arc::new(codes), spans, Arc::new(table))?;
1742 Ok(coded.with_validity(self.validity.clone()))
1743 }
1744
1745 /// The same values under a wider decimal type that stores them the same way.
1746 ///
1747 /// A decimal is kept as its unscaled integer, so two decimal types with one scale and one
1748 /// storage width describe the same bits, and going from the narrower of them to the wider is a
1749 /// relabelling rather than a conversion. The binder writes three of those into
1750 /// `l_extendedprice * (1 - l_discount)`, because a product's operands are given the answer's
1751 /// width and the answer's width is eighteen while both columns are fifteen, and each one was a
1752 /// pass over six million rows that wrote back the bytes it had just read.
1753 ///
1754 /// A flat run only, and deliberately. The general cast flattens whatever it is given, so a
1755 /// dictionary column came out of a width change as a run of values, and a relabelling that kept
1756 /// the dictionary would hand the arithmetic above two columns it has to read through a code per
1757 /// row instead of two it can read end to end. That was measured and it is the worse of the two:
1758 /// on `sum(l_extendedprice * l_discount)` under the filter q6 puts on it, where the rows left
1759 /// are few and scattered and the indirection is a cache miss each, keeping the dictionary cost
1760 /// half again as much as the flattening it saved. The flat case has no such question, since
1761 /// what it hands on is exactly what the pass would have built.
1762 ///
1763 /// Only widening, because a narrower width is a range every value has to be checked against and
1764 /// checking it is the pass this exists to avoid. `None` for anything else, including a narrower
1765 /// width, a changed scale, a changed storage width and any form but the flat one.
1766 #[must_use]
1767 pub fn as_wider_decimal(&self, target: &LogicalType) -> Option<Self> {
1768 let (
1769 LogicalType::Decimal { width: from, scale: held },
1770 LogicalType::Decimal { width: into, scale },
1771 ) = (&self.ty, target)
1772 else {
1773 return None;
1774 };
1775 if held != scale || from > into || self.ty.decimal_storage() != target.decimal_storage() {
1776 return None;
1777 }
1778 // Nothing in a flat run says what its numbers mean, so the relabelling is the type and
1779 // nothing else, and the buffer underneath is shared rather than copied.
1780 if !matches!(self.body, Body::Flat(_)) {
1781 return None;
1782 }
1783 Some(Self {
1784 ty: target.clone(),
1785 len: self.len,
1786 validity: self.validity.clone(),
1787 body: self.body.clone(),
1788 })
1789 }
1790
1791 /// The same vector with a different validity.
1792 #[must_use]
1793 pub fn with_validity(mut self, validity: Validity) -> Self {
1794 self.validity = validity;
1795 self
1796 }
1797
1798 /// What kind of values these are.
1799 #[must_use]
1800 pub fn logical_type(&self) -> &LogicalType {
1801 &self.ty
1802 }
1803
1804 /// How many values there are.
1805 #[must_use]
1806 pub fn len(&self) -> usize {
1807 self.len
1808 }
1809
1810 /// Whether there are no values.
1811 #[must_use]
1812 pub fn is_empty(&self) -> bool {
1813 self.len == 0
1814 }
1815
1816 /// How many bytes of memory this vector is holding.
1817 ///
1818 /// What the memory limit charges for it. A constant and a sequence hold one value and two
1819 /// numbers however long they are, which is the point of both forms, so the number here is the
1820 /// form's cost and not the column's width times its length.
1821 ///
1822 /// A part that is behind an `Arc` counts as one holder's share of it, which is
1823 /// [`Buffer::footprint`]'s rule for a shared page applied to the other shared parts. A
1824 /// dictionary counted in full in every vector sharing it is not a conservative over count, it is
1825 /// a number with the chunk count in it: an aggregate that emits nineteen thousand chunks of
1826 /// groups out of one stable dictionary reported that dictionary nineteen thousand times and
1827 /// refused itself a budget of twenty five gigabytes while the process held one. Dividing by the
1828 /// holders makes the sum over everything sharing the part come to about the part, which is what
1829 /// the number is supposed to mean, and it errs high rather than low whenever the holders arrive
1830 /// one after another, because each of them counts what it sees at the time it asks.
1831 #[must_use]
1832 pub fn footprint(&self) -> usize {
1833 let body = match &self.body {
1834 Body::Flat(data) => data.footprint(),
1835 Body::Constant(value) => value.footprint(),
1836 Body::Sequence { .. } => 0,
1837 Body::Dictionary { codes, values, .. } => {
1838 codes.footprint() + share(values.footprint(), values)
1839 }
1840 Body::Packed { words, .. } => share(words.capacity() * size_of::<u64>(), words),
1841 Body::Views { views, arena } => {
1842 views.capacity() * size_of::<StringView>() + share(arena.footprint(), arena)
1843 }
1844 Body::ExternalText { source } => share(source.footprint(), source),
1845 Body::Coded { codes, spans, table } => {
1846 share(codes.capacity(), codes)
1847 + spans.capacity() * size_of::<(u32, u32)>()
1848 + share(table.footprint(), table)
1849 }
1850 Body::Runs { ends, values } => {
1851 ends.capacity() * size_of::<u32>() + share(values.footprint(), values)
1852 }
1853 // The ids are shared between every cut of one link join's output, and the source is
1854 // shared with every other column gathered off the same parent, so both are divided by
1855 // their holders for the reason the dictionary above is. A gather whose source counted in
1856 // full would report a parent table per projected column per chunk.
1857 Body::Gathered { source, rids, .. } => {
1858 share(rids.capacity() * size_of::<u32>(), rids) + share(source.footprint(), source)
1859 }
1860 Body::Nested { entries, child } => {
1861 entries.capacity() * size_of::<(u32, u32)>() + share(child.footprint(), child)
1862 }
1863 // A struct is as wide as its fields are, so this is the one body whose cost is a sum
1864 // over children rather than one number, and a struct of a hundred narrow fields costs
1865 // what the hundred columns cost.
1866 Body::Fields { children } => {
1867 children.capacity() * size_of::<Arc<Self>>()
1868 + children.iter().map(|child| share(child.footprint(), child)).sum::<usize>()
1869 }
1870 };
1871 size_of::<Self>() + self.validity.footprint() + body
1872 }
1873
1874 /// Which of the values are not null, at this level and no deeper.
1875 ///
1876 /// This is not the same question as [`Self::is_null_at`] and the difference has already cost
1877 /// one wrong answer. A dictionary and a run length vector keep their nulls in the values they
1878 /// point at rather than in a mask of their own, so both are built with every row marked present
1879 /// here and a row whose value is null reads as valid. A caller that wants to know whether a row
1880 /// is null wants the other one. A caller that wants the mask of a flat column, to copy it or to
1881 /// count it, wants this one.
1882 #[must_use]
1883 pub fn validity(&self) -> &Validity {
1884 &self.validity
1885 }
1886
1887 /// Whether the row at `index` is null, in whichever form the vector is in.
1888 ///
1889 /// Reads through a dictionary or a run to the value it stands for, which is where those two
1890 /// forms keep their nulls, and answers from the mask for every other form. A row past the end
1891 /// is null, the same answer [`Self::value_at`] gives it.
1892 #[must_use]
1893 pub fn is_null_at(&self, index: usize) -> bool {
1894 if index >= self.len || !self.validity.is_valid(index) {
1895 return true;
1896 }
1897 match &self.body {
1898 Body::Dictionary { codes, values, .. } => match codes.get(index) {
1899 Some(&code) => values.is_null_at(code as usize),
1900 None => true,
1901 },
1902 Body::Runs { ends, values } => match run_holding(ends, index) {
1903 Some(run) => values.is_null_at(run),
1904 None => true,
1905 },
1906 // Section 8.2's lazy validity, which is this line. A gather has no mask of its own and
1907 // does not need one: the id says whether there is a row and the source says whether that
1908 // row is null, and both of those are already in memory.
1909 Body::Gathered { source, rids, offset } => match rids.get(offset + index) {
1910 Some(&NO_ROW) | None => true,
1911 Some(&rid) => source.is_null_at(rid as usize),
1912 },
1913 _ => false,
1914 }
1915 }
1916
1917 /// Whether no row in range is null, answered without reading a row.
1918 ///
1919 /// This is the cheap side of [`Self::is_null_at`] and has to follow it exactly. A dictionary and
1920 /// a run keep their nulls in the values they stand for, so both levels have to say they have
1921 /// none. Every other form answers from its own mask. A false means only that the cheap answer
1922 /// was not available, so a caller that gets one still has to ask row by row.
1923 ///
1924 /// Public because the alternative a caller has is a pass over the values, and on a dictionary
1925 /// that is the size of a Parquet column chunk's that pass is the thing it was trying to avoid.
1926 #[must_use]
1927 pub fn never_null(&self) -> bool {
1928 if self.validity.has_nulls(self.len) {
1929 return false;
1930 }
1931 match &self.body {
1932 Body::Dictionary { values, .. } | Body::Runs { values, .. } => values.never_null(),
1933 // A gather is never null when no id is the sentinel and the source holds no nulls. The
1934 // first of those is a pass over the ids rather than a constant, which is the one place
1935 // this question is not free, and it is worth paying: the ids are four bytes a row and
1936 // contiguous, and the alternative is reading through to the source once per row for the
1937 // whole vector, which is the random access this form exists to postpone.
1938 Body::Gathered { source, rids, offset } => {
1939 source.never_null()
1940 && !rids[*offset..].iter().take(self.len).any(|&rid| rid == NO_ROW)
1941 }
1942 _ => true,
1943 }
1944 }
1945
1946 /// Which physical form this vector is in.
1947 #[must_use]
1948 pub fn form(&self) -> Form {
1949 match self.body {
1950 Body::Flat(_) => Form::Flat,
1951 Body::Constant(_) => Form::Constant,
1952 Body::Sequence { .. } => Form::Sequence,
1953 Body::Dictionary { .. } => Form::Dictionary,
1954 Body::Packed { .. } => Form::BitPacked,
1955 Body::Views { .. } => Form::StringView,
1956 Body::ExternalText { .. } => Form::StringView,
1957 Body::Coded { .. } => Form::Fsst,
1958 Body::Runs { .. } => Form::Rle,
1959 Body::Nested { .. } => Form::List,
1960 Body::Fields { .. } => Form::Struct,
1961 Body::Gathered { .. } => Form::Gathered,
1962 }
1963 }
1964
1965 /// The data, for a flat vector, and `None` for any other form.
1966 ///
1967 /// A kernel that wants a slice asks for it and takes the flat path if it gets one. A kernel
1968 /// that can do better on a constant or a dictionary checks [`Self::form`] first.
1969 #[must_use]
1970 pub fn data(&self) -> Option<&Data> {
1971 match &self.body {
1972 Body::Flat(data) => Some(data),
1973 _ => None,
1974 }
1975 }
1976
1977 /// The one value, for a constant vector, and `None` for any other form.
1978 ///
1979 /// A kernel comparing a column against a literal wants the literal once rather than 1024
1980 /// times, and [`Self::value_at`] on a constant clones it on every call because it has to be
1981 /// able to hand back a `Value` for any form. This is the accessor that lets the specialized
1982 /// path hoist the clone out of the loop.
1983 #[must_use]
1984 pub fn constant_value(&self) -> Option<&Value> {
1985 match &self.body {
1986 Body::Constant(value) => Some(value.as_ref()),
1987 _ => None,
1988 }
1989 }
1990
1991 /// The codes and the values, for a dictionary vector, and `None` for any other form.
1992 ///
1993 /// The reason a kernel needs this rather than reading the dictionary through
1994 /// [`Self::value_at`] is the entire argument for the form existing. A filter against a
1995 /// dictionary column of 1024 rows and 40 distinct values is 40 comparisons and 1024 lookups,
1996 /// not 1024 comparisons, and there is no way to write that loop without seeing the codes.
1997 ///
1998 /// Note what the validity of the returned vector means. A dictionary keeps its nulls in the
1999 /// vector it points at, and the dictionary's own validity says nothing about them, so a caller
2000 /// deciding whether row `i` is null has to ask the value vector about `codes[i]` rather than
2001 /// asking this vector about `i`. [`Self::flatten`] has the same note on it for the same
2002 /// reason, because getting this wrong is a null that survives being selected and comes out as
2003 /// a zero.
2004 #[must_use]
2005 pub fn dictionary_parts(&self) -> Option<(&[u32], &Self)> {
2006 match &self.body {
2007 Body::Dictionary { codes, values, .. } => Some((codes, values.as_ref())),
2008 _ => None,
2009 }
2010 }
2011
2012 /// The codes and the shared dictionary handle for a dictionary vector.
2013 ///
2014 /// Storage readers use the identity of this handle to prove that codes from separate pages
2015 /// belong to one table-wide dictionary. Kernels that only read values should continue to use
2016 /// [`Self::dictionary_parts`].
2017 #[must_use]
2018 pub fn shared_dictionary_parts(&self) -> Option<(&[u32], &Arc<Self>)> {
2019 match &self.body {
2020 Body::Dictionary { codes, values, .. } => Some((codes, values)),
2021 _ => None,
2022 }
2023 }
2024
2025 /// Stable codes and their shared values, when storage guarantees one code space across pages.
2026 #[must_use]
2027 pub fn stable_dictionary_parts(&self) -> Option<(&[u32], &Arc<Self>)> {
2028 match &self.body {
2029 Body::Dictionary { codes, values, stable: true } => Some((codes, values)),
2030 _ => None,
2031 }
2032 }
2033
2034 /// The run ends and the run values, for a run length vector, and `None` for any other form.
2035 ///
2036 /// The ends are exclusive and increasing, and there is exactly one value per run, so a kernel
2037 /// that wants to walk this walks the pairs and never asks which run a row is in. That is the
2038 /// whole argument for the form: an aggregate over a clustered column is one multiply per run
2039 /// instead of one add per row, and there is no way to write that loop without seeing the ends.
2040 ///
2041 /// The nulls are in the values, the way a dictionary's are, so a caller deciding whether row `i`
2042 /// is null asks the value vector about the run rather than asking this vector about `i`.
2043 #[must_use]
2044 pub fn run_parts(&self) -> Option<(&[u32], &Self)> {
2045 match &self.body {
2046 Body::Runs { ends, values } => Some((ends, values.as_ref())),
2047 _ => None,
2048 }
2049 }
2050
2051 /// Where each row's value is, for the two forms that keep their values somewhere else.
2052 ///
2053 /// A dictionary and a run length vector are the same shape seen from a kernel: a run of
2054 /// positions and a vector to read them out of. The difference is that a dictionary stores the
2055 /// positions and a run length vector works them out, and a kernel writing `values[at[row]]` does
2056 /// not care which. So every specialization written against [`Self::dictionary_parts`] covers
2057 /// both forms by asking this instead, and the day a third form with an indirection arrives it
2058 /// covers that one too without any of those kernels being reopened.
2059 ///
2060 /// The run length side costs an allocation of one position per row and a pass to fill it, which
2061 /// is the same four bytes a row a dictionary was already carrying and is paid once per kernel
2062 /// call rather than once per row. That is the price of this being one accessor rather than a
2063 /// second arm in eighteen kernels, and it is not the last word: a kernel that wants a run at a
2064 /// time reads [`Self::run_parts`] and pays nothing, which is the specialization this makes it
2065 /// possible to skip writing until a sweep says it is worth it.
2066 #[must_use]
2067 pub fn positions(&self) -> Option<(Cow<'_, [u32]>, &Self)> {
2068 match &self.body {
2069 Body::Dictionary { codes, values, .. } => Some((Cow::Borrowed(codes), values.as_ref())),
2070 Body::Runs { ends, values } => {
2071 let mut at = Vec::with_capacity(self.len);
2072 for (run, &stop) in ends.iter().enumerate() {
2073 let run = u32::try_from(run).unwrap_or(u32::MAX);
2074 at.resize(stop as usize, run);
2075 }
2076 Some((Cow::Owned(at), values.as_ref()))
2077 }
2078 _ => None,
2079 }
2080 }
2081
2082 /// The bits and what they mean, for a bit packed vector, and `None` for any other form.
2083 ///
2084 /// What a kernel needs to stay in code space. A comparison against a literal is the case that
2085 /// pays: `column > 900` over a column packed from a base of 40 is `code > 860`, which is the
2086 /// same shift and mask the read was going to do anyway and no unpacking at all, and a literal
2087 /// outside the packed range answers the whole vector without reading a bit of it. None of that
2088 /// can be written without seeing the width and the base.
2089 #[must_use]
2090 pub fn packed_parts(&self) -> Option<Packed<'_>> {
2091 match &self.body {
2092 Body::Packed { words, width, base, offset } => {
2093 Some(Packed { words, width: *width, base: *base, offset: *offset })
2094 }
2095 _ => None,
2096 }
2097 }
2098
2099 /// The views and the arena, for either form that stores strings, and `None` for the rest.
2100 ///
2101 /// This is to the two string forms what [`Self::positions`] is to the two forms that point
2102 /// somewhere else. A flat varchar column owns its arena and a string view column shares one, and
2103 /// a kernel reading a row wants the view and the bytes either way, so every specialization
2104 /// written against this covers both forms and neither has to be reopened when a third way of
2105 /// holding an arena arrives.
2106 ///
2107 /// The arena is whatever the long strings live in, which for a column over a page is the page,
2108 /// including the parts of it no view points at. Only the views say which bytes are a row.
2109 #[must_use]
2110 pub fn text_parts(&self) -> Option<(&[StringView], &[u8])> {
2111 match &self.body {
2112 Body::Flat(Data::Varlen(column)) => Some((column.views(), column.arena())),
2113 Body::Views { views, arena } => Some((views, arena)),
2114 _ => None,
2115 }
2116 }
2117
2118 /// The views and the arena they point into, for a vector of string views and nothing else.
2119 ///
2120 /// [`Self::text_parts`] answers the same question for a flat column too, and gives the arena as
2121 /// bytes. This gives the `Arc`, which is what a caller laying several of these end to end needs
2122 /// to see that they share one arena and can keep it rather than copying out of it.
2123 #[must_use]
2124 pub fn shared_views(&self) -> Option<(&[StringView], &Arc<Buffer<u8>>)> {
2125 match &self.body {
2126 Body::Views { views, arena } => Some((views, arena)),
2127 _ => None,
2128 }
2129 }
2130
2131 /// The codes and the table, for an FSST vector, and `None` for any other form.
2132 ///
2133 /// What a kernel needs to stay in code space. An equality filter is the case that pays, and it
2134 /// pays completely: the literal is compressed once against the same table and after that a row
2135 /// matches exactly when its code bytes match, because compressing is a function and so is
2136 /// decompressing. No row is decompressed at all. An ordering comparison cannot do that, since a
2137 /// symbol code says nothing about where its symbol sorts, so those decompress and say so.
2138 #[must_use]
2139 pub fn coded_parts(&self) -> Option<Coded<'_>> {
2140 match &self.body {
2141 Body::Coded { codes, spans, table } => Some(Coded { codes, spans, table }),
2142 _ => None,
2143 }
2144 }
2145
2146 /// The start and the step, for a sequence vector, and `None` for any other form.
2147 #[must_use]
2148 pub fn sequence_parts(&self) -> Option<(i64, i64)> {
2149 match self.body {
2150 Body::Sequence { start, step } => Some((start, step)),
2151 _ => None,
2152 }
2153 }
2154
2155 /// The positions of an `ENUM` vector, as the unsigned integers they are held in.
2156 ///
2157 /// What `enum_code` answers, and what an `ENUM` is ordered by. A flat vector hands its run over
2158 /// as it is under the new type, and any other form is flattened first, since a dictionary or a
2159 /// gather over one would read its values back out as strings.
2160 ///
2161 /// # Errors
2162 ///
2163 /// If this is not an `ENUM` vector, or a constant holds a string that is not one of the list.
2164 pub fn enum_codes(&self) -> Result<Self> {
2165 if self.ty.labels().is_none() {
2166 return Err(Error::internal(format!("enum_code over a {} vector", self.ty)));
2167 }
2168 let ty = enum_code_type(&self.ty);
2169 if let Body::Constant(value) = &self.body {
2170 return Ok(Self::constant(ty, enum_position(&self.ty, value)?, self.len));
2171 }
2172 // flatten: an enum's codes are its dictionary's codes read as integers, and a dictionary
2173 // or run form would need the same relabelling done inside it, so the one flat copy is it.
2174 let flat = self.flatten()?;
2175 Ok(Self { ty, ..flat })
2176 }
2177
2178 /// The value at `index`, as a single value.
2179 ///
2180 /// This is the slow path on purpose. It is what a result set is read out with and what a test
2181 /// asserts on, and an operator that calls it per row is an operator that has already lost the
2182 /// argument the vector interface exists to win.
2183 #[must_use]
2184 pub fn value_at(&self, index: usize) -> Value {
2185 if index >= self.len || !self.validity.is_valid(index) {
2186 return Value::Null;
2187 }
2188 match &self.body {
2189 Body::Constant(value) => value.as_ref().clone(),
2190 Body::Sequence { start, step } => Value::BigInt(start + step * index as i64),
2191 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2192 Some(&code) => values.value_at(code as usize),
2193 None => Value::Null,
2194 },
2195 Body::Runs { ends, values } => match run_holding(ends, index) {
2196 Some(run) => values.value_at(run),
2197 None => Value::Null,
2198 },
2199 // The one read every other reader of this form is: follow the id, and answer null when
2200 // there is no row to follow. Written out once per reader rather than through a helper
2201 // because each of them returns a different kind of nothing.
2202 Body::Gathered { source, rids, offset } => match rids.get(offset + index) {
2203 Some(&NO_ROW) | None => Value::Null,
2204 Some(&rid) => source.value_at(rid as usize),
2205 },
2206 // One value unpacked into a run of one, so that what a packed value means is decided in
2207 // the same place a flat one is rather than in a second copy of the type mapping that
2208 // could drift from it. It allocates, which this path is allowed to do and the typed
2209 // unpack in `copied` is not, and it is the reason anything about to read a packed
2210 // column a row at a time should flatten it once instead.
2211 Body::Packed { words, width, base, offset } => {
2212 unpack(&self.ty, words, *offset, *width, *base, &[index])
2213 .map_or(Value::Null, |data| value_from(&self.ty, &data, 0))
2214 }
2215 // The bytes are where the arena has them, and what they are read as is the logical
2216 // type's business, so this hands the row to the same reader a flat column goes through
2217 // rather than deciding here that a `BLOB` is a string.
2218 Body::Views { views, arena } => {
2219 match views.get(index).and_then(|v| v.bytes_in(arena)) {
2220 Some(bytes) => bytes_as(&self.ty, bytes),
2221 None => Value::Null,
2222 }
2223 }
2224 Body::ExternalText { source } => source
2225 .bytes_at(index)
2226 .ok()
2227 .flatten()
2228 .map_or(Value::Null, |bytes| bytes_as(&self.ty, bytes)),
2229 // One row decompressed on its own, which is the property the form is chosen for. It
2230 // allocates, which this path is allowed to do, and it is the reason anything about to
2231 // read a compressed column a row at a time should flatten it once instead.
2232 Body::Coded { codes, spans, table } => {
2233 match spans.get(index).and_then(|&(from, to)| {
2234 let mut out = Vec::new();
2235 table.decompress(codes.get(from as usize..to as usize)?, &mut out).ok()?;
2236 Some(out)
2237 }) {
2238 Some(bytes) => bytes_as(&self.ty, &bytes),
2239 None => Value::Null,
2240 }
2241 }
2242 // A row's elements are read out of the child one at a time, which is the slow path this
2243 // whole function is and is why a kernel over a list column reads `list_parts` instead.
2244 // The element type comes from the child rather than from this vector's type, so a list
2245 // whose child was built narrower than the column claims still hands back what is in it.
2246 //
2247 // A map is stored in this body too, so which value comes out is decided by the logical
2248 // type rather than by the body. That is the one place the composition shows: the bytes of
2249 // a map really are the bytes of a list of two field structs, and the only thing that
2250 // remembers it is a map is the type.
2251 Body::Nested { entries, child } => match (entries.get(index), &self.ty) {
2252 (Some(&(start, len)), LogicalType::Map(key, value)) => {
2253 let pairs = child.struct_parts().unwrap_or_default();
2254 Value::map(
2255 key.as_ref().clone(),
2256 value.as_ref().clone(),
2257 (start..start + len)
2258 .filter_map(|at| {
2259 let [keys, values] = pairs else { return None };
2260 Some((keys.value_at(at as usize), values.value_at(at as usize)))
2261 })
2262 .collect(),
2263 )
2264 }
2265 (Some(&(start, len)), _) => Value::List {
2266 element: child.ty.clone(),
2267 values: (start..start + len).map(|at| child.value_at(at as usize)).collect(),
2268 },
2269 (None, _) => Value::Null,
2270 },
2271 // One value read out of each child at the same position, which is the slow path this whole
2272 // function is and is why a kernel over a struct column reads `struct_parts` instead. The
2273 // names come from this vector's type rather than from the children, because a child is a
2274 // vector and a vector has no name, and the type is where the field order is written down.
2275 Body::Fields { children } => Value::Struct(
2276 fields_of(&self.ty)
2277 .iter()
2278 .zip(children)
2279 .map(|(field, child)| (field.name.clone(), child.value_at(index)))
2280 .collect(),
2281 ),
2282 Body::Flat(data) => value_from(&self.ty, data, index),
2283 }
2284 }
2285
2286 /// One value of this vector's type, built out of bytes the caller already holds.
2287 ///
2288 /// [`try_value_at`](Self::try_value_at) finds the bytes itself, which over a dictionary that
2289 /// keeps its payload in a file means a read. A caller that swept the values out has the bytes in
2290 /// hand already and wants nothing from here but the type.
2291 pub fn value_of(&self, bytes: &[u8]) -> Value {
2292 bytes_as(&self.ty, bytes)
2293 }
2294
2295 /// The value at `index`, preserving storage read and validation failures.
2296 pub fn try_value_at(&self, index: usize) -> Result<Value> {
2297 if index >= self.len || !self.validity.is_valid(index) {
2298 return Ok(Value::Null);
2299 }
2300 match &self.body {
2301 Body::ExternalText { source } => {
2302 Ok(source.bytes_at(index)?.map_or(Value::Null, |bytes| bytes_as(&self.ty, bytes)))
2303 }
2304 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2305 Some(&code) => values.try_value_at(code as usize),
2306 None => Ok(Value::Null),
2307 },
2308 Body::Runs { ends, values } => match run_holding(ends, index) {
2309 Some(run) => values.try_value_at(run),
2310 None => Ok(Value::Null),
2311 },
2312 Body::Nested { entries, child } => match (entries.get(index), &self.ty) {
2313 (Some(&(start, len)), LogicalType::Map(key, value)) => {
2314 let pairs = child.struct_parts().unwrap_or_default();
2315 let [keys, values] = pairs else { return Ok(Value::Null) };
2316 let mut entries = Vec::with_capacity(len as usize);
2317 for at in start..start + len {
2318 entries.push((
2319 keys.try_value_at(at as usize)?,
2320 values.try_value_at(at as usize)?,
2321 ));
2322 }
2323 Ok(Value::map(key.as_ref().clone(), value.as_ref().clone(), entries))
2324 }
2325 (Some(&(start, len)), _) => {
2326 let mut values = Vec::with_capacity(len as usize);
2327 for at in start..start + len {
2328 values.push(child.try_value_at(at as usize)?);
2329 }
2330 Ok(Value::List { element: child.ty.clone(), values })
2331 }
2332 (None, _) => Ok(Value::Null),
2333 },
2334 Body::Fields { children } => {
2335 let mut values = Vec::with_capacity(children.len());
2336 for (field, child) in fields_of(&self.ty).iter().zip(children) {
2337 values.push((field.name.clone(), child.try_value_at(index)?));
2338 }
2339 Ok(Value::Struct(values))
2340 }
2341 _ => Ok(self.value_at(index)),
2342 }
2343 }
2344
2345 /// The text at `index`, borrowed rather than copied.
2346 ///
2347 /// [`Self::value_at`] on a `VARCHAR` column allocates a `String` per call, and a group by that
2348 /// reads a string column keys on one string per input row. This hands back the bytes where they
2349 /// already are, so a caller with somewhere to put them does not go to the allocator at all.
2350 ///
2351 /// `None` for a null, for an index past the end, for a column that is not `VARCHAR`, and for the
2352 /// constant and sequence forms, whose values are not stored per position. A caller that gets
2353 /// `None` has to fall back to [`Self::value_at`], which is correct for all of those.
2354 #[must_use]
2355 pub fn text_at(&self, index: usize) -> Option<&str> {
2356 if self.ty != LogicalType::Varchar || index >= self.len || !self.validity.is_valid(index) {
2357 return None;
2358 }
2359 match &self.body {
2360 Body::Flat(data) => data.str_at(index),
2361 Body::Dictionary { codes, values, .. } => {
2362 values.text_at(usize::try_from(*codes.get(index)?).ok()?)
2363 }
2364 Body::Runs { ends, values } => values.text_at(run_holding(ends, index)?),
2365 Body::Gathered { source, rids, offset } => {
2366 source.text_at(row_of(rids, *offset, index)?)
2367 }
2368 Body::Views { views, arena } => {
2369 std::str::from_utf8(views.get(index)?.bytes_in(arena)?).ok()
2370 }
2371 Body::ExternalText { source } => {
2372 std::str::from_utf8(source.bytes_at(index).ok().flatten()?).ok()
2373 }
2374 _ => None,
2375 }
2376 }
2377
2378 /// The variable length bytes at `index`, borrowed without validating or copying them.
2379 ///
2380 /// String data is validated when it enters a vector. Hashing and equality only need its bytes,
2381 /// so those kernels should not pay for UTF-8 validation again on every read.
2382 #[must_use]
2383 pub fn bytes_at(&self, index: usize) -> Option<&[u8]> {
2384 if index >= self.len || !self.validity.is_valid(index) {
2385 return None;
2386 }
2387 match &self.body {
2388 Body::Constant(value) => match value.as_ref() {
2389 Value::Varchar(text) => Some(text.as_bytes()),
2390 Value::Blob(bytes) => Some(bytes),
2391 _ => None,
2392 },
2393 Body::Dictionary { codes, values, .. } => {
2394 values.bytes_at(usize::try_from(*codes.get(index)?).ok()?)
2395 }
2396 Body::Runs { ends, values } => values.bytes_at(run_holding(ends, index)?),
2397 Body::Gathered { source, rids, offset } => {
2398 source.bytes_at(row_of(rids, *offset, index)?)
2399 }
2400 Body::Views { views, arena } => views.get(index)?.bytes_in(arena),
2401 Body::ExternalText { source } => source.bytes_at(index).ok().flatten(),
2402 Body::Flat(data) => data.bytes_at(index),
2403 // The same `None` [`Self::text_at`] gives, for the same reason. A compressed row is not
2404 // anywhere in its plain bytes, so there is nothing here to hand back a borrow of, and a
2405 // caller that gets `None` goes to `value_at` and gets the row decompressed into a value.
2406 // A list row is `None` for a nearer reason: it is not bytes at all, and a caller wanting
2407 // its elements wants [`Self::list_parts`] rather than a borrow of one row.
2408 Body::Coded { .. }
2409 | Body::Sequence { .. }
2410 | Body::Packed { .. }
2411 | Body::Nested { .. }
2412 | Body::Fields { .. } => None,
2413 }
2414 }
2415
2416 /// Variable length bytes at `index`, preserving storage read and validation failures.
2417 pub fn try_bytes_at(&self, index: usize) -> Result<Option<&[u8]>> {
2418 if index >= self.len || !self.validity.is_valid(index) {
2419 return Ok(None);
2420 }
2421 match &self.body {
2422 Body::Constant(value) => Ok(match value.as_ref() {
2423 Value::Varchar(text) => Some(text.as_bytes()),
2424 Value::Blob(bytes) => Some(bytes.as_slice()),
2425 _ => None,
2426 }),
2427 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2428 Some(&code) => values.try_bytes_at(code as usize),
2429 None => Ok(None),
2430 },
2431 Body::Runs { ends, values } => match run_holding(ends, index) {
2432 Some(run) => values.try_bytes_at(run),
2433 None => Ok(None),
2434 },
2435 Body::Gathered { source, rids, offset } => match row_of(rids, *offset, index) {
2436 Some(row) => source.try_bytes_at(row),
2437 None => Ok(None),
2438 },
2439 Body::Views { views, arena } => {
2440 Ok(views.get(index).and_then(|view| view.bytes_in(arena)))
2441 }
2442 Body::ExternalText { source } => source.bytes_at(index),
2443 Body::Flat(data) => Ok(data.bytes_at(index)),
2444 Body::Coded { .. }
2445 | Body::Sequence { .. }
2446 | Body::Packed { .. }
2447 | Body::Nested { .. }
2448 | Body::Fields { .. } => Ok(None),
2449 }
2450 }
2451
2452 /// Walks the values from `first` up to at most `limit`, without keeping what it read.
2453 ///
2454 /// [`TextSource::sweep`] is what this is for and what the doc on it explains. Everything else
2455 /// here is the honest fallback: a vector that is not reading text out of a file has its values
2456 /// already, so there is nothing to avoid keeping, and it hands over one value and lets the
2457 /// caller come back. The answer is one past the last value visited either way, so the loop that
2458 /// calls this is the same loop whichever form it got.
2459 ///
2460 /// Nulls go the slow way. A source that reads a file holds no validity of its own, so the
2461 /// vector's own mask is the only thing that knows, and rather than teach the sweep about it the
2462 /// one form that can have both hands over a value at a time through the reader that checks.
2463 ///
2464 /// # Errors
2465 ///
2466 /// Whatever reading a value raises, and whatever `body` raises.
2467 pub fn sweep_text(
2468 &self,
2469 first: usize,
2470 limit: usize,
2471 body: &mut dyn FnMut(usize, &[u8]) -> Result<()>,
2472 ) -> Result<usize> {
2473 let limit = limit.min(self.len);
2474 if first >= limit {
2475 return Ok(first);
2476 }
2477 if let Body::ExternalText { source } = &self.body
2478 && matches!(self.validity, Validity::AllValid)
2479 {
2480 return source.sweep(first, limit, body);
2481 }
2482 body(first, self.try_bytes_at(first)?.unwrap_or_default())?;
2483 Ok(first + 1)
2484 }
2485
2486 /// A conservative substring test for the payload block holding `first`.
2487 ///
2488 /// Only a file-backed string source with all-valid values can skip a whole block. Every other
2489 /// form returns true and lets the ordinary sweep decide its values.
2490 pub fn text_block_might_contain(&self, first: usize, literal: &[u8]) -> Result<bool> {
2491 match &self.body {
2492 Body::ExternalText { source } if matches!(self.validity, Validity::AllValid) => {
2493 source.might_contain(first, literal)
2494 }
2495 _ => Ok(true),
2496 }
2497 }
2498
2499 /// The values at `indices`, which rise, without keeping what reading them decoded.
2500 ///
2501 /// [`TextSource::visit`] is what this is for. A vector that is not reading text out of a file, or
2502 /// that has nulls of its own, reads a value at a time through the reader that checks.
2503 ///
2504 /// # Errors
2505 ///
2506 /// Whatever reading a value raises.
2507 pub fn try_values_visited(&self, indices: &[usize]) -> Result<Vec<Value>> {
2508 if let Body::ExternalText { source } = &self.body
2509 && matches!(self.validity, Validity::AllValid)
2510 {
2511 let mut out = vec![Value::Null; indices.len()];
2512 let mut own = |at: usize, bytes: &[u8]| {
2513 if indices[at] < self.len {
2514 out[at] = bytes_as(&self.ty, bytes);
2515 }
2516 Ok(())
2517 };
2518 source.visit(indices, &mut own)?;
2519 return Ok(out);
2520 }
2521 indices.iter().map(|&index| self.try_value_at(index)).collect()
2522 }
2523
2524 /// Variable length byte count at `index`, preserving storage failures.
2525 pub fn try_bytes_len_at(&self, index: usize) -> Result<Option<usize>> {
2526 if index >= self.len || !self.validity.is_valid(index) {
2527 return Ok(None);
2528 }
2529 match &self.body {
2530 Body::Dictionary { codes, values, .. } => match codes.get(index) {
2531 Some(&code) => values.try_bytes_len_at(code as usize),
2532 None => Ok(None),
2533 },
2534 Body::Runs { ends, values } => match run_holding(ends, index) {
2535 Some(run) => values.try_bytes_len_at(run),
2536 None => Ok(None),
2537 },
2538 Body::ExternalText { source } => source.bytes_len_at(index),
2539 _ => Ok(self.bytes_at(index).map(<[u8]>::len)),
2540 }
2541 }
2542
2543 /// The byte length of every row, in one call to whatever holds the text, when that is possible.
2544 ///
2545 /// `into` is cleared and given one length per row. The answer is whether it was: a vector with
2546 /// nulls in it,
2547 /// or one whose text is not read from a [`TextSource`], answers `false` and leaves the caller to
2548 /// ask a row at a time through [`Self::try_bytes_len_at`], which is right for every shape. The
2549 /// two shapes taken here are the two a scan of a stored string column hands out, the text itself
2550 /// and a dictionary of codes over it, and each is one call to the source for the whole vector
2551 /// rather than a call per row down through this type.
2552 ///
2553 /// # Errors
2554 ///
2555 /// Whatever reading the lengths out of storage raises.
2556 pub fn try_bytes_lens(&self, into: &mut Vec<i64>) -> Result<bool> {
2557 self.lens_through(into, false, |source, indices, into| source.bytes_lens_at(indices, into))
2558 }
2559
2560 /// The character length of every row, in one call to whatever holds the text, when that is
2561 /// possible.
2562 ///
2563 /// The same shapes as [`Self::try_bytes_lens`], counting characters rather than bytes, which is
2564 /// `length` where that one is `strlen`. It goes through [`TextSource::chars_lens_at`] so that a
2565 /// source reading its text out of a file can keep the counts rather than the text, which is the
2566 /// difference between a scan of `length` over a stored column holding four bytes a distinct
2567 /// value and holding every distinct value decoded.
2568 ///
2569 /// Unlike that one it answers a vector with nulls too, and a null row gets the count of
2570 /// whatever its slot points at, so the caller masks the nulls itself. Declining a vector with
2571 /// nulls sent `length` a row at a time through the bytes, which on a stored column is the path
2572 /// that keeps every block it reads, so one null in a vector was enough to bring that back.
2573 ///
2574 /// # Errors
2575 ///
2576 /// Whatever reading the text out of storage raises.
2577 pub fn try_chars_lens(&self, into: &mut Vec<i64>) -> Result<bool> {
2578 self.lens_through(into, true, |source, indices, into| source.chars_lens_at(indices, into))
2579 }
2580
2581 /// One call to `ask` for every row, over the source this vector reads its text from.
2582 ///
2583 /// `false` for a vector whose text does not come from a [`TextSource`], and for a vector with
2584 /// nulls unless `nulls` says the caller will mask them, for the reasons
2585 /// [`Self::try_bytes_lens`] gives.
2586 fn lens_through(
2587 &self,
2588 into: &mut Vec<i64>,
2589 nulls: bool,
2590 ask: impl Fn(&dyn TextSource, &[u32], &mut Vec<i64>) -> Result<()>,
2591 ) -> Result<bool> {
2592 if !nulls && !matches!(self.validity, Validity::AllValid) {
2593 return Ok(false);
2594 }
2595 into.clear();
2596 match &self.body {
2597 Body::ExternalText { source } => {
2598 let Ok(rows) = u32::try_from(self.len) else { return Ok(false) };
2599 let indices = (0..rows).collect::<Vec<_>>();
2600 ask(source.as_ref(), &indices, into)?;
2601 Ok(true)
2602 }
2603 Body::Dictionary { codes, values, .. } => match &values.body {
2604 Body::ExternalText { source } if matches!(values.validity, Validity::AllValid) => {
2605 let Some(codes) = codes.get(..self.len) else { return Ok(false) };
2606 ask(source.as_ref(), codes, into)?;
2607 Ok(true)
2608 }
2609 _ => Ok(false),
2610 },
2611 _ => Ok(false),
2612 }
2613 }
2614
2615 /// Hands `body` the bytes of every row that is not null, when the text is read from a
2616 /// [`TextSource`], and answers whether it did.
2617 ///
2618 /// The rows come in whatever order the source reads them in, each with its row number, so a
2619 /// caller that writes an answer per row has to put it back in row order itself. That is the
2620 /// price of the source seeing the whole vector at once, which is what lets one that decodes its
2621 /// text a block at a time decode each block once for the call rather than keep every block a
2622 /// row lands in. See [`TextSource::visit_at`]. The shapes taken are the two a scan of a stored
2623 /// string column hands out, the text itself and a dictionary of codes over it, and anything
2624 /// else answers `false` and is read a row at a time through [`Self::try_bytes_at`], which is
2625 /// right for every shape.
2626 ///
2627 /// # Errors
2628 ///
2629 /// Whatever reading the text out of storage raises, and whatever `body` raises.
2630 pub fn try_visit_text(&self, body: &mut dyn FnMut(usize, &[u8]) -> Result<()>) -> Result<bool> {
2631 let (source, codes) = match &self.body {
2632 Body::ExternalText { source } => (source, None),
2633 Body::Dictionary { codes, values, .. } => match &values.body {
2634 Body::ExternalText { source } if matches!(values.validity, Validity::AllValid) => {
2635 let Some(codes) = codes.get(..self.len) else { return Ok(false) };
2636 (source, Some(codes))
2637 }
2638 _ => return Ok(false),
2639 },
2640 _ => return Ok(false),
2641 };
2642 let Ok(len) = u32::try_from(self.len) else { return Ok(false) };
2643 // The rows asked for, which are all of them unless some are null. A null row is left out
2644 // rather than read, because a row at a time read answers it with no value at all.
2645 let rows: Option<Vec<u32>> = match &self.validity {
2646 Validity::AllValid => None,
2647 Validity::AllInvalid => return Ok(true),
2648 Validity::Mask(mask) => Some((0..len).filter(|&row| mask.get(row as usize)).collect()),
2649 };
2650 let indices = match (codes, &rows) {
2651 (Some(codes), None) => Cow::Borrowed(codes),
2652 (Some(codes), Some(rows)) => rows.iter().map(|&row| codes[row as usize]).collect(),
2653 (None, None) => (0..len).collect(),
2654 (None, Some(rows)) => Cow::Borrowed(rows.as_slice()),
2655 };
2656 source.visit_at(&indices, &mut |at, bytes| {
2657 let row = rows.as_ref().map_or(at, |rows| rows[at] as usize);
2658 body(row, bytes)
2659 })?;
2660 Ok(true)
2661 }
2662
2663 /// How many ranks this vector's values have in sorted order, when whatever holds them knows.
2664 ///
2665 /// See [`TextSource::ranks`] for what a rank is and what a source promises by answering with
2666 /// one. Only a vector whose values come from storage can answer, because only storage is in a
2667 /// position to have sorted them once and written the answer down.
2668 #[must_use]
2669 pub fn ranks(&self) -> Option<usize> {
2670 match &self.body {
2671 Body::ExternalText { source } => source.ranks(),
2672 _ => None,
2673 }
2674 }
2675
2676 /// How the value at `rank` compares against `wanted`. See [`TextSource::compare_rank`].
2677 pub fn compare_rank(&self, rank: usize, wanted: &[u8]) -> Result<Ordering> {
2678 match &self.body {
2679 Body::ExternalText { source } => source.compare_rank(rank, wanted),
2680 _ => {
2681 Err(Error::internal("a vector without a sorted order was asked to compare a rank"))
2682 }
2683 }
2684 }
2685
2686 /// Where `wanted` would go in the sorted order. See [`TextSource::below`].
2687 ///
2688 /// # Errors
2689 ///
2690 /// If this vector has no sorted order, or if a probe of it fails.
2691 pub fn below(&self, ranks: usize, wanted: &[u8]) -> Result<(usize, bool)> {
2692 match &self.body {
2693 Body::ExternalText { source } => source.below(ranks, wanted),
2694 _ => Err(Error::internal("a vector without a sorted order was asked for a boundary")),
2695 }
2696 }
2697
2698 /// The position of the value at `rank`. See [`TextSource::code_at_rank`].
2699 pub fn code_at_rank(&self, rank: usize) -> Result<u32> {
2700 match &self.body {
2701 Body::ExternalText { source } => source.code_at_rank(rank),
2702 _ => Err(Error::internal("a vector without a sorted order was asked for a rank")),
2703 }
2704 }
2705
2706 /// The rank of every value, indexed by position. See [`TextSource::code_ranks`].
2707 #[must_use]
2708 pub fn code_ranks(&self) -> Option<&[u32]> {
2709 match &self.body {
2710 Body::ExternalText { source } => source.code_ranks(),
2711 _ => None,
2712 }
2713 }
2714
2715 /// Text at `index`, preserving storage read, validation and UTF-8 failures.
2716 pub fn try_text_at(&self, index: usize) -> Result<Option<&str>> {
2717 if self.ty != LogicalType::Varchar {
2718 return Ok(None);
2719 }
2720 self.try_bytes_at(index)?
2721 .map(|bytes| {
2722 std::str::from_utf8(bytes).map_err(|error| {
2723 Error::conversion(format!("invalid UTF-8 in VARCHAR: {error}"))
2724 })
2725 })
2726 .transpose()
2727 }
2728
2729 /// Read every storage-backed value reachable through this vector.
2730 pub fn validate_external(&self) -> Result<()> {
2731 match &self.body {
2732 Body::ExternalText { source } => {
2733 for index in 0..source.len() {
2734 source.bytes_at(index)?;
2735 }
2736 }
2737 Body::Dictionary { codes, values, .. } => {
2738 if values.reaches_storage() {
2739 for &code in codes.iter() {
2740 values.try_bytes_at(code as usize)?;
2741 }
2742 }
2743 }
2744 Body::Runs { values, .. } | Body::Gathered { source: values, .. } => {
2745 values.validate_external()?;
2746 }
2747 Body::Nested { child, .. } => child.validate_external()?,
2748 Body::Fields { children } => {
2749 for child in children {
2750 child.validate_external()?;
2751 }
2752 }
2753 _ => {}
2754 }
2755 Ok(())
2756 }
2757
2758 /// Whether any value of this vector is read from storage when it is asked for.
2759 ///
2760 /// A dictionary over values already in memory has nothing that can fail to read, and checking
2761 /// it a code at a time cost the thread that drains a query about a fifth of a sorted table
2762 /// copy for no answer at all.
2763 fn reaches_storage(&self) -> bool {
2764 match &self.body {
2765 Body::ExternalText { .. } => true,
2766 Body::Dictionary { values, .. }
2767 | Body::Runs { values, .. }
2768 | Body::Gathered { source: values, .. } => values.reaches_storage(),
2769 Body::Nested { child, .. } => child.reaches_storage(),
2770 Body::Fields { children } => children.iter().any(|child| child.reaches_storage()),
2771 _ => false,
2772 }
2773 }
2774
2775 /// The signed integer at `index`, widened, read without building a [`Value`].
2776 ///
2777 /// The integer sibling of [`Self::bytes_at`], and it is here for the same caller. A group by on
2778 /// an integer column compares one key per input row against the group it probed, and doing that
2779 /// through [`Self::value_at`] built and dropped a sixty four byte value a row at a time for a
2780 /// number that was already sitting in the column.
2781 ///
2782 /// Widened to `i128` because that is what [`Data::signed_at`] hands back underneath, and one
2783 /// method that covers every signed width is worth more than five that do not. A caller that
2784 /// wants a narrower type narrows it, which is a range check against a value in a register.
2785 ///
2786 /// The types this answers for are the ones whose flat data is read through `signed_at`, so the
2787 /// five signed integer widths and the decimal, date, time and timestamp types that are stored
2788 /// in them. A decimal answers with its unscaled value, which is the number the column holds.
2789 ///
2790 /// `None` for a null, for an index past the end, for a column of any other type, and for the
2791 /// compressed form. Packed integers stay in code space and answer `base + code` directly. A
2792 /// caller that gets `None` falls back to [`Self::value_at`], which is correct for the remaining
2793 /// forms.
2794 #[must_use]
2795 pub fn signed_at(&self, index: usize) -> Option<i128> {
2796 if index >= self.len || !self.validity.is_valid(index) {
2797 return None;
2798 }
2799 match &self.body {
2800 Body::Flat(data) => data.signed_at(index),
2801 Body::Constant(value) => match value.as_ref() {
2802 Value::TinyInt(x) => Some(i128::from(*x)),
2803 Value::SmallInt(x) => Some(i128::from(*x)),
2804 Value::Integer(x) | Value::Date(x) => Some(i128::from(*x)),
2805 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => Some(i128::from(*x)),
2806 Value::HugeInt(x) | Value::Decimal { unscaled: x, .. } => Some(*x),
2807 _ => None,
2808 },
2809 // The same arithmetic [`Self::value_at`] does on a sequence, so the two agree about a
2810 // sequence that runs off the end of the width it is stored in.
2811 Body::Sequence { start, step } => {
2812 Some(i128::from(start.wrapping_add(step.wrapping_mul(index as i64))))
2813 }
2814 Body::Dictionary { codes, values, .. } => {
2815 values.signed_at(usize::try_from(*codes.get(index)?).ok()?)
2816 }
2817 Body::Runs { ends, values } => values.signed_at(run_holding(ends, index)?),
2818 Body::Gathered { source, rids, offset } => {
2819 source.signed_at(row_of(rids, *offset, index)?)
2820 }
2821 Body::Packed { words, width, base, offset } => Some(
2822 *base + i128::from(code_at(words, (*offset + index) * *width as usize, *width)),
2823 ),
2824 // The same `None` [`Self::bytes_at`] gives, for the same reason. A compressed row is not
2825 // an integer anywhere until it has been unpacked, and a caller that gets
2826 // `None` goes to `value_at` and gets the row unpacked into a value. A list row is not an
2827 // integer in any form, however many integers are in it, and a struct row is not one even
2828 // when it has exactly one integer field, since the row is the struct and not the field.
2829 Body::Coded { .. }
2830 | Body::Views { .. }
2831 | Body::ExternalText { .. }
2832 | Body::Nested { .. }
2833 | Body::Fields { .. } => None,
2834 }
2835 }
2836
2837 /// The rows `at` names, read as signed integers, widened and written into `out`.
2838 ///
2839 /// The gathered form of [`Self::signed_block`] for a flat vector, which is what a filter's
2840 /// selection over a flat integer column wants. `false`, with `out` cleared, for every other
2841 /// form and for a row past the end, and the caller then goes the way it went before.
2842 #[must_use]
2843 pub fn signed_gather(&self, at: &[u32], out: &mut Vec<i64>) -> bool {
2844 out.clear();
2845 match &self.body {
2846 Body::Flat(data) => data.signed_gather(self.len, at, out),
2847 _ => false,
2848 }
2849 }
2850
2851 /// The runs of equal values among rows `from..to`, each as its value widened to `i64` and the
2852 /// row it ends before, written into `out`.
2853 ///
2854 /// For a flat signed integer vector, the form a sorted key column is in under a filter's
2855 /// selection. `false`, with `out` cleared, for every other form, and once the runs come more
2856 /// often than one in every `every` rows. See [`Data::signed_runs`].
2857 #[must_use]
2858 pub fn signed_runs(
2859 &self,
2860 (from, to): (usize, usize),
2861 every: usize,
2862 out: &mut Vec<(i64, usize)>,
2863 ) -> bool {
2864 out.clear();
2865 match &self.body {
2866 Body::Flat(data) => data.signed_runs(self.len, (from, to), every, out),
2867 _ => false,
2868 }
2869 }
2870
2871 /// Every signed value in order, widened to `i64`, written into `out`.
2872 ///
2873 /// The bulk form of [`Self::signed_at`], for a caller that is going to read the whole vector
2874 /// anyway. A group by on two integer columns called `signed_at` once per column per row, and
2875 /// every one of those matched on the body, called into the data and matched again on the
2876 /// layout, which is about sixty five instructions to read a number that was already sitting in
2877 /// a slice. It was a fifth of ClickBench 32 on its own.
2878 ///
2879 /// A null writes whatever the body holds under it, which is the zero a flat column keeps behind
2880 /// its mask. Nulls are a separate question and the caller asks it separately, from
2881 /// [`Self::none_null`] once for the vector when that answers and a row at a time when it does
2882 /// not.
2883 ///
2884 /// `false`, with `out` left empty, for a vector this cannot hand over as a block: `HUGEINT` and
2885 /// the wide decimals, whose values do not fit an `i64`, the string and nested forms, the
2886 /// compressed form, and the run form. A caller that gets `false` reads the vector the way it
2887 /// read it before, with [`Self::signed_at`].
2888 ///
2889 /// A dictionary is read as its entries widened once and then a gather through the codes. That
2890 /// is the form a Parquet integer column arrives in, because DuckDB writes most of them with a
2891 /// dictionary, and reading one a row at a time was 4 percent of the CPU of loading the 10m
2892 /// ClickBench file, all of it in the sieve the writer builds for each part. A dictionary whose
2893 /// entries hold a null is refused, since the row that points at one is null and the only null
2894 /// check a caller of this makes on a dictionary may be on its codes.
2895 #[must_use]
2896 pub fn signed_block(&self, out: &mut Vec<i64>) -> bool {
2897 out.clear();
2898 match &self.body {
2899 Body::Flat(data) => data.signed_block(self.len, out),
2900 Body::Constant(value) => {
2901 let held = match value.as_ref() {
2902 Value::TinyInt(x) => i64::from(*x),
2903 Value::SmallInt(x) => i64::from(*x),
2904 Value::Integer(x) | Value::Date(x) => i64::from(*x),
2905 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => *x,
2906 _ => return false,
2907 };
2908 out.resize(self.len, held);
2909 true
2910 }
2911 // The same arithmetic [`Self::signed_at`] does on a sequence, once per row rather than
2912 // once per call, and it wraps where that one wraps.
2913 Body::Sequence { start, step } => {
2914 out.extend(
2915 (0..self.len).map(|index| start.wrapping_add(step.wrapping_mul(index as i64))),
2916 );
2917 true
2918 }
2919 // Sixty four codes at a time through [`Packed::unpack`], with the blocks lined up on the
2920 // words so that every one after the first is the constant width loop rather than a
2921 // code at a time. A code at a time was about twenty instructions a row, and q21 reads
2922 // two packed columns of lineitem through here for every line of the orders it keeps.
2923 Body::Packed { words, width, base, offset } => match i64::try_from(*base) {
2924 Ok(base) => {
2925 let packed =
2926 Packed { words, width: *width, base: i128::from(base), offset: *offset };
2927 let mut block = [0u64; 64];
2928 let mut from = 0;
2929 out.reserve(self.len);
2930 while from < self.len {
2931 let rows = (64 - (*offset + from) % 64).min(self.len - from);
2932 let codes = &mut block[..rows];
2933 packed.unpack(from, codes);
2934 out.extend(codes.iter().map(|&code| base.wrapping_add(code as i64)));
2935 from += rows;
2936 }
2937 true
2938 }
2939 Err(_) => false,
2940 },
2941 Body::Dictionary { codes, values, .. } => {
2942 // A selection over row numbers is a dictionary over a sequence as long as the part
2943 // it came from, and working each code out is cheaper than laying all of those out.
2944 if let Some((start, step)) = values.sequence_parts() {
2945 let Some(codes) = codes.get(..self.len) else {
2946 return false;
2947 };
2948 if codes.iter().any(|&code| code as usize >= values.len()) {
2949 return false;
2950 }
2951 out.extend(
2952 codes
2953 .iter()
2954 .map(|&code| start.wrapping_add(step.wrapping_mul(i64::from(code)))),
2955 );
2956 return true;
2957 }
2958 let mut entries = Vec::new();
2959 if !values.none_null() || !values.signed_block(&mut entries) {
2960 return false;
2961 }
2962 let Some(codes) = codes.get(..self.len) else {
2963 return false;
2964 };
2965 out.reserve(codes.len());
2966 for &code in codes {
2967 match entries.get(code as usize) {
2968 Some(&entry) => out.push(entry),
2969 None => {
2970 out.clear();
2971 return false;
2972 }
2973 }
2974 }
2975 true
2976 }
2977 Body::Runs { .. }
2978 | Body::Gathered { .. }
2979 | Body::Coded { .. }
2980 | Body::Views { .. }
2981 | Body::ExternalText { .. }
2982 | Body::Nested { .. }
2983 | Body::Fields { .. } => false,
2984 }
2985 }
2986
2987 /// Whether the vector holds no nulls at all, asked once rather than a row at a time.
2988 ///
2989 /// The bulk form of [`Self::is_null_at`], and it answers the same question that one does, so a
2990 /// dictionary and a run are read through to the values behind them where those two keep their
2991 /// nulls. A dictionary that holds a null no code points at answers `false` here and `false` at
2992 /// every row, which is the safe direction and is the only place the two can differ.
2993 ///
2994 /// A caller that gets `false` goes back to asking a row at a time.
2995 #[must_use]
2996 pub fn none_null(&self) -> bool {
2997 if self.validity.has_nulls(self.len) {
2998 return false;
2999 }
3000 match &self.body {
3001 Body::Dictionary { values, .. } | Body::Runs { values, .. } => values.none_null(),
3002 Body::Gathered { source, rids, offset } => {
3003 source.none_null()
3004 && !rids[*offset..].iter().take(self.len).any(|&rid| rid == NO_ROW)
3005 }
3006 _ => true,
3007 }
3008 }
3009
3010 /// Every value in order, as single values.
3011 pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
3012 (0..self.len).map(|index| self.value_at(index))
3013 }
3014
3015 /// This vector with its payload held as a page, so that copying or cutting it is free.
3016 ///
3017 /// For a producer that means to hand the same values out many times, which is what a stored
3018 /// column is. A flat body, a dictionary and a string body are the forms this changes, because
3019 /// each owns a run a copy would have to copy: the values of a flat body, the codes of a
3020 /// dictionary and the arena of a string body. The rest come back as they were, because a packed
3021 /// body shares its words, an FSST body shares its codes and its table, and a constant and a
3022 /// sequence have nothing to share.
3023 ///
3024 /// The string body is the one worth spelling out, because an `Arc` around the arena looks like
3025 /// sharing and is not the sharing that matters. Every reader that wants a run of an arena
3026 /// without copying the bytes asks [`Buffer::is_shared`], which is a question about the store
3027 /// inside the `Arc` and not about the `Arc`: an owned store clones by copying every byte and a
3028 /// page clones by taking a handle. So an arena that was built rather than read stays a thing
3029 /// each reader copies out of until somebody calls this, however many `Arc`s point at it. The
3030 /// reader this is for is [`Self::gather`] over a parent column, which without it copies the
3031 /// bytes of every gathered string once per chunk.
3032 ///
3033 /// Only when the arena is this vector's alone, which is the case a producer that has just built
3034 /// one is in. An arena with another holder is left as it is, because turning it into a page
3035 /// behind their back would mean copying it, which is the cost this exists to avoid.
3036 ///
3037 /// Not recursive into a nested column's children, because a `LIST` or a `STRUCT` holds its
3038 /// children behind an `Arc` already.
3039 #[must_use]
3040 pub fn into_pages(self) -> Self {
3041 let body = match self.body {
3042 Body::Flat(data) => Body::Flat(data.into_pages()),
3043 Body::Dictionary { codes, values, stable } => {
3044 Body::Dictionary { codes: codes.into_page(), values, stable }
3045 }
3046 Body::Views { views, arena } => Body::Views { views, arena: paged(arena) },
3047 other => other,
3048 };
3049 Self { body, ..self }
3050 }
3051
3052 /// A contiguous run of the values, in the form they are already in.
3053 ///
3054 /// This is the cut [`Self::gather`] cannot do. A gather walks a dictionary to its leaf and
3055 /// copies, so gathering a piece of a dictionary encoded column hands back a flat one, and a
3056 /// caller that only wanted the first thousand rows of a page has silently paid for a copy and
3057 /// thrown the dictionary away. A group by over a dictionary encoded column is the case that
3058 /// cares, and it is most of ClickBench.
3059 ///
3060 /// So each form is cut as itself. A dictionary keeps its dictionary and slices its codes, a
3061 /// sequence stays arithmetic with its start moved along, a constant stays a shorter constant,
3062 /// and a flat body is a window into its page when it has one and a copy of its range when it
3063 /// does not, which [`Self::into_pages`] is how a producer decides.
3064 ///
3065 /// The dictionary itself is shared rather than copied, so a cut is the codes and nothing else.
3066 /// It used to be copied, and on a read of a ClickBench partition that copy was ten percent of
3067 /// the cycles: a page holds one dictionary and is cut into chunk sized pieces, so the whole
3068 /// dictionary was copied once per chunk to be read the same way each time.
3069 ///
3070 /// # Errors
3071 ///
3072 /// If the range runs past the end of the vector, or if the type has no flat layout and the
3073 /// body is one that has to be copied.
3074 pub fn slice(&self, at: usize, len: usize) -> Result<Self> {
3075 let end = at.checked_add(len).ok_or_else(|| Error::internal("a slice that wraps"))?;
3076 if end > self.len {
3077 return Err(Error::internal(format!("rows {at} to {end} of a vector of {}", self.len)));
3078 }
3079 if at == 0 && len == self.len {
3080 return Ok(self.clone());
3081 }
3082 let validity = self.validity.slice(at, len);
3083 let body = match &self.body {
3084 Body::Constant(value) => Body::Constant(value.clone()),
3085 Body::Sequence { start, step } => {
3086 Body::Sequence { start: start + step * at as i64, step: *step }
3087 }
3088 Body::Dictionary { codes, values, stable } => Body::Dictionary {
3089 codes: codes.slice(at, len),
3090 values: Arc::clone(values),
3091 stable: *stable,
3092 },
3093 // The same cut [`Body::Packed`] below takes and for the same reason, and here it is free
3094 // rather than merely cheap: a link join fills one buffer of parent rows per child chunk
3095 // and the pipeline cuts it, so moving the starting row is what keeps the ids from being
3096 // copied once per cut. Both ends of the gather stay shared, the ids and the source.
3097 Body::Gathered { source, rids, offset } => Body::Gathered {
3098 source: Arc::clone(source),
3099 rids: Arc::clone(rids),
3100 offset: offset + at,
3101 },
3102 // The bits are not byte aligned, so a cut either repacks them or moves the row the
3103 // reading starts at. Moving it is one addition and repacking is a pass, and a page is
3104 // cut into chunk sized pieces often enough that the difference is the form.
3105 Body::Packed { words, width, base, offset } => Body::Packed {
3106 words: Arc::clone(words),
3107 width: *width,
3108 base: *base,
3109 offset: offset + at,
3110 },
3111 // The cut a flat string column cannot do. Sixteen bytes a row move and the payload stays
3112 // where the page put it, so taking a chunk out of a column of long strings costs the
3113 // same as taking one out of a column of integers. A flat varchar body copies every byte
3114 // of every long string in the range instead, which is the measurement written down in
3115 // `Chunk::compact`: compaction loses on a varchar column, and this is the half of the
3116 // reason that is about cutting rather than about selecting.
3117 Body::Views { views, arena } => {
3118 Body::Views { views: views[at..end].to_vec(), arena: Arc::clone(arena) }
3119 }
3120 // The spans are absolute positions in the shared codes, so a cut is a run of them and
3121 // nothing has to be rebased. One page of compressed strings, one table, and as many
3122 // chunks over it as the reader wants.
3123 Body::Coded { codes, spans, table } => Body::Coded {
3124 codes: Arc::clone(codes),
3125 spans: spans[at..end].to_vec(),
3126 table: Arc::clone(table),
3127 },
3128 // Only the runs the range touches survive, the first and last of them cut back to where
3129 // the range starts and stops, and every end moved to be relative to the new row zero. A
3130 // cut of a hundred rows out of a column of a hundred million is a handful of runs, which
3131 // is the reason this form is worth cutting as itself rather than copying out.
3132 Body::Runs { ends, values } if len > 0 => {
3133 let first = run_holding(ends, at).unwrap_or(0);
3134 let last = run_holding(ends, end - 1).unwrap_or(first);
3135 let cut: Vec<u32> = ends[first..=last]
3136 .iter()
3137 .map(|&stop| stop.min(end as u32) - at as u32)
3138 .collect();
3139 let values = values.slice(first, last - first + 1)?;
3140 Body::Runs { ends: cut, values: Arc::new(values) }
3141 }
3142 // An empty cut has no run to point at and an empty run length body would be a vector of
3143 // no runs claiming a length, so it comes back as the empty flat vector instead.
3144 Body::Runs { .. } => return self.gather(&[]),
3145 // The entries are absolute positions in the shared child, so a cut is a run of them and
3146 // nothing has to be rebased, the same as a cut of FSST spans. The elements outside the
3147 // range stay in the child unreferenced, which is the trade this form makes: a chunk cut
3148 // out of a page of lists moves eight bytes a row and copies no elements at all.
3149 Body::Nested { entries, child } => {
3150 Body::Nested { entries: entries[at..end].to_vec(), child: Arc::clone(child) }
3151 }
3152 // Every child cut at the same place, because a struct row is one value per field at the
3153 // same position in each and there is no entry standing between the row and the child to
3154 // rewrite instead. So this is the one nested form whose cut is not free, and what it costs
3155 // is whatever cutting each field costs, which for a field of string views is sixteen bytes
3156 // a row and for a field of packed integers is one addition.
3157 Body::Fields { children } => Body::Fields {
3158 children: children
3159 .iter()
3160 .map(|child| child.slice(at, len).map(Arc::new))
3161 .collect::<Result<Vec<_>>>()?,
3162 },
3163 Body::ExternalText { source } => {
3164 let mut out = StringColumn::with_capacity(len);
3165 for index in at..end {
3166 out.push_bytes(source.bytes_at(index)?.unwrap_or_default());
3167 }
3168 Body::Flat(Data::Varlen(out))
3169 }
3170 // The one form with nowhere to point, so its range is copied out. A run and not a
3171 // gather: this used to build a vector of the positions `at..end` and hand it to
3172 // `gather`, which then built a vector of `usize` from it, a vector of `bool` beside
3173 // that, and read the values back one bounds checked index at a time. That is five
3174 // passes and three allocations to say `memcpy`, and on a scan it was the largest thing
3175 // in the program after the aggregation itself, because every chunk of every column of
3176 // every page comes through here.
3177 Body::Flat(data) => Body::Flat(run_of(data, at, end)),
3178 };
3179 Ok(Self { ty: self.ty.clone(), len, validity, body })
3180 }
3181
3182 /// The same values in flat form.
3183 ///
3184 /// Flattening a vector that is already flat is free. Flattening any other form costs a copy,
3185 /// which is exactly why the other forms exist and why nothing on the hot path should call
3186 /// this. It is here for the operators that genuinely cannot do better and for the tests that
3187 /// check the other forms against it.
3188 ///
3189 /// A call that copies counts itself against [`Cause::Flatten`], because a flatten on a hot path
3190 /// is the most expensive thing in this crate and the only way to find one is to have the number.
3191 /// A call on a vector that is already flat does not count, since it neither copies nor gives
3192 /// anything up.
3193 ///
3194 /// # Errors
3195 ///
3196 /// If the type is one there is no vector for yet, which today means `ARRAY` and `UNION`. A `LIST`
3197 /// and a `MAP` flatten to themselves and a `STRUCT` to a struct of flattened fields, since none of
3198 /// the three has a data slice in any form and there is nothing flatter to become.
3199 pub fn flatten(&self) -> Result<Self> {
3200 if let Body::Flat(_) = self.body {
3201 return Ok(self.clone());
3202 }
3203 slow::took(Cause::Flatten);
3204 if let Some(flat) = self.decoded_codes() {
3205 return Ok(flat);
3206 }
3207 if let Some(flat) = self.unpacked_whole() {
3208 return Ok(flat);
3209 }
3210 self.copied((0..self.len).collect(), false)
3211 }
3212
3213 /// A packed column with no nulls written out whole, a block of 64 codes at a time.
3214 ///
3215 /// The general copy builds a list of every position and then reads each code on its own, working
3216 /// out its word and whether it straddles into the next every time. Every row of the column is
3217 /// wanted in order, so [`Packed::unpack_mapped`] unpacks whole blocks with the width a constant
3218 /// and hands each code to the value it stands for as it goes. Laying out the `orders` side of
3219 /// TPC-H q9 flattens a million and a half packed dates, and the copy was a third of the layout.
3220 fn unpacked_whole(&self) -> Option<Self> {
3221 let Body::Packed { words, width, base, offset } = &self.body else {
3222 return None;
3223 };
3224 if self.validity.has_nulls(self.len) {
3225 return None;
3226 }
3227 let packed = Packed { words, width: *width, base: *base, offset: *offset };
3228 let low = i64::try_from(packed.base()).ok()?;
3229 i64::try_from(packed.ceiling()).ok()?;
3230 // The same arithmetic as [`Self::unpacked_at`]: both ends fit, so every value does.
3231 #[expect(clippy::cast_possible_wrap, reason = "a code is below the span, which fits")]
3232 let value = |code: u64| low.wrapping_add(code as i64);
3233 let rows = self.len;
3234 #[expect(clippy::cast_possible_truncation, reason = "the layout holds every value")]
3235 let data = match self.ty.physical() {
3236 rudb_common::PhysicalType::Int64 => {
3237 let mut out = Vec::with_capacity(rows);
3238 packed.unpack_mapped(0, rows, &mut out, value);
3239 Data::Int64(Buffer::from_vec(out))
3240 }
3241 rudb_common::PhysicalType::Int32 => {
3242 let mut out = Vec::with_capacity(rows);
3243 packed.unpack_mapped(0, rows, &mut out, |code| value(code) as i32);
3244 Data::Int32(Buffer::from_vec(out))
3245 }
3246 rudb_common::PhysicalType::Int16 => {
3247 let mut out = Vec::with_capacity(rows);
3248 packed.unpack_mapped(0, rows, &mut out, |code| value(code) as i16);
3249 Data::Int16(Buffer::from_vec(out))
3250 }
3251 _ => return None,
3252 };
3253 Some(Self {
3254 ty: self.ty.clone(),
3255 len: rows,
3256 validity: Validity::AllValid,
3257 body: Body::Flat(data),
3258 })
3259 }
3260
3261 /// A dictionary with no nulls over flat values with none, written out by its codes.
3262 ///
3263 /// The general copy walks the positions down through every layer and marks each one that
3264 /// lands on a null, and then builds the validity back up from those marks. With no null on
3265 /// either side the codes are already the positions and the validity is already known, so that
3266 /// is one pass over the codes rather than four. A Parquet column that was dictionary encoded
3267 /// comes in as this form, and flattening columns on the way to the file was four percent of a
3268 /// ClickBench load.
3269 fn decoded_codes(&self) -> Option<Self> {
3270 let Body::Dictionary { codes, values, .. } = &self.body else {
3271 return None;
3272 };
3273 if !matches!(self.validity, Validity::AllValid)
3274 || !matches!(values.validity, Validity::AllValid)
3275 {
3276 return None;
3277 }
3278 let Body::Flat(data) = &values.body else {
3279 return None;
3280 };
3281 if matches!(data, Data::Empty) {
3282 return None;
3283 }
3284 let codes = codes.as_slice().get(..self.len)?;
3285 if !below(codes, values.len) {
3286 return None;
3287 }
3288 let at = codes.iter().map(|&code| code as usize).collect::<Vec<_>>();
3289 Some(Self {
3290 ty: self.ty.clone(),
3291 len: self.len,
3292 validity: Validity::AllValid,
3293 body: Body::Flat(copy_of(data, &at)),
3294 })
3295 }
3296
3297 /// The same values in flat form, taking the vector rather than borrowing it.
3298 ///
3299 /// A vector that is already flat comes back as itself, which is the whole reason this exists
3300 /// beside [`Self::flatten`]. Flattening through a borrow has to clone that vector, and a clone
3301 /// of a flat vector that owns its values copies every one of them to produce a vector that is
3302 /// identical to the one it was handed. Anything not already flat goes the same way it does
3303 /// through [`Self::flatten`], since the copy is real work there rather than work for nothing.
3304 ///
3305 /// # Errors
3306 ///
3307 /// The same values flat, for a kernel that has a loop over runs and was handed a form it has
3308 /// no way to index into.
3309 ///
3310 /// This is [`Self::flatten`] without the count against [`Cause::Flatten`], and the difference
3311 /// is who is calling. A flatten is counted because it is usually a shortcut past a loop nobody
3312 /// wrote. This is for the caller that has the loop and whose alternative is a `Value` per row,
3313 /// which costs a good deal more than the copy. ClickBench q40 adds three `SMALLINT` columns out
3314 /// of Parquet, a packed one and runs over the others after the filter, and every `+` went a
3315 /// row at a time.
3316 ///
3317 /// # Errors
3318 ///
3319 /// Whatever the copy raises.
3320 pub fn opened(&self) -> Result<Self> {
3321 if let Body::Flat(_) = self.body {
3322 return Ok(self.clone());
3323 }
3324 if let Some(flat) = self.decoded_codes() {
3325 return Ok(flat);
3326 }
3327 self.copied((0..self.len).collect(), false)
3328 }
3329
3330 /// The same as [`Self::flatten`].
3331 pub fn into_flat(self) -> Result<Self> {
3332 if let Body::Flat(_) = self.body {
3333 return Ok(self);
3334 }
3335 // flatten: the caller asked for flat, and the form that is already flat took the branch
3336 // above, so this is the one case where the copy is what was wanted rather than a shortcut
3337 // somebody took instead of reading the column where it lies.
3338 self.flatten()
3339 }
3340
3341 /// The values at the given positions, copied, in a form that does not point back at this vector.
3342 ///
3343 /// This is the copying counterpart to [`Self::dictionary`], and the two are the two halves of
3344 /// the decision `spec/07-execution.md` section 7.1 describes. Which half is right is measured
3345 /// rather than argued, and [`Chunk::compact`](crate::Chunk::compact) is where the measurement
3346 /// is written down.
3347 ///
3348 /// A dictionary chain is walked to its leaf first and the codes composed on the way down, so the
3349 /// copy runs once over the data rather than once per level, and a position that is null at any
3350 /// level comes out null here. The copy is a typed loop per physical layout rather than a `Value`
3351 /// per row, which is the whole point of it and is what [`Self::flatten`] now goes through too.
3352 ///
3353 /// # Errors
3354 ///
3355 /// If the type is one there is no vector for yet, which today means `ARRAY` and `UNION`. A `LIST`
3356 /// and a `MAP` gather by permuting their entries and a `STRUCT` by gathering every field.
3357 pub fn gather(&self, indices: &[u32]) -> Result<Self> {
3358 // Straight off the positions a filter handed over, since a gather of a stable dictionary is
3359 // its codes gathered and nothing else, and widening every position first was a pass and an
3360 // allocation per filtered chunk of `URL` on ClickBench 28.
3361 if let Body::Dictionary { codes, values, stable: true } = &self.body {
3362 let inside = below(indices, codes.len());
3363 return self.stable_gathered(codes, values, indices, inside, |index| index as usize);
3364 }
3365 // A constant gathered is the same constant at the new length, as long as every position is
3366 // a row of it or the value is null anyway. A join's probe gathers every column of its driving
3367 // side, and a scan hands up a null constant for a column only its filter read.
3368 if let Body::Constant(value) = &self.body {
3369 let null = value.is_null() && matches!(self.validity, Validity::AllInvalid);
3370 let valid = matches!(self.validity, Validity::AllValid) && !value.is_null();
3371 if null || (valid && below(indices, self.len)) {
3372 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), indices.len()));
3373 }
3374 }
3375 if let Some(gathered) = self.unpacked_at(indices) {
3376 return Ok(gathered);
3377 }
3378 if let Some(gathered) = self.flat_at(indices) {
3379 return Ok(gathered);
3380 }
3381 self.copied(indices.iter().map(|&index| index as usize).collect(), true)
3382 }
3383
3384 /// A gather off a flat run of fixed width values with no nulls, every position inside it.
3385 ///
3386 /// That is what a join hands out on both of its sides, and the general copy below made a run of
3387 /// wide positions, walked them for nulls, made a flag per row and a validity out of the flags
3388 /// before it moved a value. On q09 at SF1 those passes were about half of the gathers. Here it is
3389 /// one pass for the range and one for the values, and `None` for anything else.
3390 fn flat_at(&self, indices: &[u32]) -> Option<Self> {
3391 let Body::Flat(data) = &self.body else { return None };
3392 if self.validity.has_nulls(self.len) {
3393 return None;
3394 }
3395 if !below(indices, self.len) {
3396 return None;
3397 }
3398 macro_rules! gathered {
3399 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
3400 match data {
3401 $(Data::$variant(values) => {
3402 let values = values.as_slice();
3403 let out: Vec<$native> =
3404 indices.iter().map(|&index| values[index as usize]).collect();
3405 Data::$variant(Buffer::from_vec(out))
3406 })+
3407 Data::Empty | Data::Varlen(_) => return None,
3408 }
3409 };
3410 }
3411 let data = crate::for_each_layout!(fixed, gathered);
3412 Some(Self {
3413 ty: self.ty.clone(),
3414 len: indices.len(),
3415 validity: Validity::AllValid,
3416 body: Body::Flat(data),
3417 })
3418 }
3419
3420 /// A gather off a stable dictionary, which is its codes gathered over the same values.
3421 ///
3422 /// Generic over the position type because a filter hands over `u32` positions and a nested
3423 /// gather hands over `usize` ones, and each is read where it lies rather than widened first.
3424 fn stable_gathered<T: Copy>(
3425 &self,
3426 codes: &Buffer<u32>,
3427 values: &Arc<Vector>,
3428 at: &[T],
3429 inside: bool,
3430 index: impl Fn(T) -> usize,
3431 ) -> Result<Self> {
3432 let rows = at.len();
3433 // The ordinary case, a column with no nulls and a filter's rows all inside it, in one pass
3434 // for the range and one for the gather. Every code taken is one of this vector's codes,
3435 // which were range checked when it was built, so the result is not checked again the way
3436 // a dictionary from outside is. On q1 the two passes this replaces and the check after
3437 // them were a tenth of the instructions of the scan.
3438 if inside && self.never_null() {
3439 return Ok(Self {
3440 ty: values.ty.clone(),
3441 len: rows,
3442 validity: Validity::AllValid,
3443 body: Body::Dictionary {
3444 codes: at.iter().map(|&at| codes[index(at)]).collect(),
3445 values: Arc::clone(values),
3446 stable: true,
3447 },
3448 });
3449 }
3450 // Otherwise the rows past the end and the nulls are found one row at a time. The per row
3451 // question reads through the dictionary to the value it stands for, which is why the case
3452 // above answers it for the whole column at once.
3453 let validity = if self.never_null() && at.iter().all(|&at| index(at) < self.len) {
3454 Validity::AllValid
3455 } else {
3456 Validity::from_iter(rows, |row| {
3457 at.get(row)
3458 .map(|&at| index(at))
3459 .is_some_and(|index| index < self.len && !self.is_null_at(index))
3460 })
3461 };
3462 let gathered: Vec<u32> =
3463 at.iter().map(|&at| codes.get(index(at)).copied().unwrap_or(0)).collect();
3464 // Every code here is one this vector already held, which was checked against the same
3465 // values on the way in, or the zero a row past the end is written as. So the only code that
3466 // can be out of range is that zero over no values at all, and the pass that looks for the
3467 // largest code is not needed to find it. On ClickBench 28 that pass was four percent of the
3468 // query, because every filtered chunk of `URL` came through here.
3469 // Values that are themselves a dictionary are composed through by the constructor, and this
3470 // skips the constructor, so that shape still goes the checked way.
3471 if matches!(values.body, Body::Dictionary { .. }) {
3472 return Ok(
3473 Self::stable_dictionary(gathered, Arc::clone(values))?.with_validity(validity)
3474 );
3475 }
3476 let highest = (values.is_empty() && !gathered.is_empty()).then_some(0);
3477 Ok(Self::stable_dictionary_validated(gathered, Arc::clone(values), highest)?
3478 .with_validity(validity))
3479 }
3480
3481 /// A packed column's rows at `indices`, unpacked in bulk into a flat column.
3482 ///
3483 /// The general copy reads a packed row a code at a time, which is what [`Packed::codes_at`]
3484 /// exists to avoid. `None` for anything but a packed column with no nulls, every index in range
3485 /// and both ends of its range inside an `i64`, which is every packed column of TPC-H.
3486 fn unpacked_at(&self, indices: &[u32]) -> Option<Self> {
3487 let Body::Packed { words, width, base, offset } = &self.body else {
3488 return None;
3489 };
3490 if self.validity.has_nulls(self.len) {
3491 return None;
3492 }
3493 if !below(indices, self.len) {
3494 return None;
3495 }
3496 let packed = Packed { words, width: *width, base: *base, offset: *offset };
3497 let low = i64::try_from(packed.base()).ok()?;
3498 i64::try_from(packed.ceiling()).ok()?;
3499 // Every value is between the two ends, which both fit, so the add lands without wrapping
3500 // and the narrowing below keeps every value, since the layout was chosen to hold them.
3501 #[expect(clippy::cast_possible_wrap, reason = "a code is below the span, which fits")]
3502 let value = |code: u64| low.wrapping_add(code as i64);
3503 #[expect(clippy::cast_possible_truncation, reason = "the layout holds every value")]
3504 let data = match self.ty.physical() {
3505 rudb_common::PhysicalType::Int64 => {
3506 Data::Int64(Buffer::from_vec(packed.values_at(indices, value)))
3507 }
3508 rudb_common::PhysicalType::Int32 => {
3509 Data::Int32(Buffer::from_vec(packed.values_at(indices, |code| value(code) as i32)))
3510 }
3511 rudb_common::PhysicalType::Int16 => {
3512 Data::Int16(Buffer::from_vec(packed.values_at(indices, |code| value(code) as i16)))
3513 }
3514 _ => return None,
3515 };
3516 Some(Self {
3517 ty: self.ty.clone(),
3518 len: indices.len(),
3519 validity: Validity::AllValid,
3520 body: Body::Flat(data),
3521 })
3522 }
3523
3524 /// The copy both [`Self::gather`] and [`Self::flatten`] are.
3525 ///
3526 /// `forms_stay` is the one thing the two want differently. A gather of a constant is a shorter
3527 /// constant and copying it out would be a thousand writes of the same value for nothing, and a
3528 /// gather of string views is a shorter run of views over the same arena rather than a copy of
3529 /// the bytes. Flattening promises flat form to a caller that is about to read the data slice, so
3530 /// for that one both of them have to be written out.
3531 fn copied(&self, at: Vec<usize>, forms_stay: bool) -> Result<Self> {
3532 let rows = at.len();
3533 if forms_stay && let Body::Dictionary { codes, values, stable: true } = &self.body {
3534 let inside = at.iter().max().is_none_or(|&top| top < codes.len());
3535 return self.stable_gathered(codes, values, &at, inside, |index| index);
3536 }
3537 let (at, leaf) = self.resolve(at);
3538 let live: Vec<bool> = at.iter().map(|&index| index != NOWHERE).collect();
3539 let validity = Validity::from_run(&live);
3540 let body = match &leaf.body {
3541 // The same gather the arm below is, for a type that has no flat layout to be written out
3542 // into. It goes through the nested builders rather than through a run of data, because they
3543 // are the one place that knows a row of a list column is a range of a child and a row of a
3544 // struct column is one position in each of several, and a second copy of that here would
3545 // be a second thing to keep in step with them.
3546 Body::Constant(value)
3547 if matches!(
3548 self.ty,
3549 LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _)
3550 ) =>
3551 {
3552 if forms_stay && matches!(validity, Validity::AllValid) {
3553 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
3554 }
3555 let rows: Vec<Value> = at
3556 .iter()
3557 .map(
3558 |&index| {
3559 if index == NOWHERE { Value::Null } else { value.as_ref().clone() }
3560 },
3561 )
3562 .collect();
3563 return Self::from_values(self.ty.clone(), &rows);
3564 }
3565 // Every position holds the same value, so the only thing the gather can change is the
3566 // length and which positions are null. A gather with no null in it is still a constant.
3567 Body::Constant(value) => {
3568 if forms_stay && matches!(validity, Validity::AllValid) {
3569 return Ok(Self::constant(self.ty.clone(), value.as_ref().clone(), rows));
3570 }
3571 let mut data = empty_data_for(&self.ty)?;
3572 let value = stored(&self.ty, value)?;
3573 for &index in &at {
3574 push_value(&mut data, if index == NOWHERE { &Value::Null } else { &value })?;
3575 }
3576 Body::Flat(data)
3577 }
3578 // A sequence is arithmetic rather than storage, so the gather is the arithmetic done at
3579 // the positions asked for, and a null writes the zero every other layout writes.
3580 Body::Sequence { start, step } => Body::Flat(Data::Int64(
3581 at.iter()
3582 .map(|&index| if index == NOWHERE { 0 } else { start + step * index as i64 })
3583 .collect(),
3584 )),
3585 // A flat body with no values is the untyped null, so every position asked for is null
3586 // whatever was asked for. Going through the copy would build a run of no values and
3587 // call it `rows` long, which is a vector whose length and data disagree.
3588 Body::Flat(Data::Empty) => {
3589 return Ok(Self::constant(self.ty.clone(), Value::Null, rows));
3590 }
3591 Body::Flat(data) => Body::Flat(copy_of(data, &at)),
3592 // The one form whose copy is arithmetic rather than a move of bytes. It goes through a
3593 // typed loop per layout the way the flat copy does, because the alternative is a `Value`
3594 // per row and this is the path a flatten of a scanned column takes.
3595 Body::Packed { words, width, base, offset } => {
3596 Body::Flat(unpack(&self.ty, words, *offset, *width, *base, &at)?)
3597 }
3598 // A gather keeps the form, which is what makes selecting rows out of a string column
3599 // cost sixteen bytes a row instead of the bytes of the strings. The arena it shares is
3600 // the whole arena and not the part the kept rows point at, so a selection that throws
3601 // most of a page away goes on holding the page. That is the trade the form is: a cut and
3602 // a filter are cheap and the memory comes back when the last vector over the page goes,
3603 // and a caller that wants the bytes narrowed asks for a flatten.
3604 Body::Views { views, arena } if forms_stay => Body::Views {
3605 views: at
3606 .iter()
3607 .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
3608 .collect(),
3609 arena: Arc::clone(arena),
3610 },
3611 // Flattening promises a data slice, and a flat string column is views over an arena
3612 // just as this form is, so when the arena is a page the flatten is the views and
3613 // nothing else. The form is given up, which is what was asked for, and not the sharing,
3614 // which nobody asked to have given up: a result set of six million strings used to copy
3615 // every byte of them out of the pages they were already sitting in.
3616 Body::Views { views, arena } if arena.is_shared() => {
3617 Body::Flat(Data::Varlen(StringColumn::from_parts(
3618 at.iter()
3619 .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
3620 .collect(),
3621 (**arena).clone(),
3622 )))
3623 }
3624 // The arena is this vector's own, so there is nothing to share and the bytes are copied
3625 // out into an arena of their own. The total is known before any of it is copied, the
3626 // way the flat copy works it out, so the new arena is one allocation.
3627 Body::Views { views, arena } => {
3628 let mut out = StringColumn::with_capacity(at.len());
3629 out.reserve_bytes(
3630 at.iter()
3631 .filter_map(|&index| views.get(index))
3632 .filter(|view| !view.is_inline())
3633 .map(StringView::len)
3634 .sum(),
3635 );
3636 for &index in &at {
3637 let bytes = views.get(index).and_then(|view| view.bytes_in(arena));
3638 out.push_bytes(bytes.unwrap_or_default());
3639 }
3640 Body::Flat(Data::Varlen(out))
3641 }
3642 Body::ExternalText { source } => {
3643 let mut out = StringColumn::with_capacity(at.len());
3644 for &index in &at {
3645 out.push_bytes(source.bytes_at(index)?.unwrap_or_default());
3646 }
3647 Body::Flat(Data::Varlen(out))
3648 }
3649 // A gather keeps the form, because the codes do not move and a span survives being put
3650 // in an order the codes are not in. A position that resolved to nowhere gets the empty
3651 // span, which decompresses to no bytes, which is the zero every other layout writes.
3652 Body::Coded { codes, spans, table } if forms_stay => Body::Coded {
3653 codes: Arc::clone(codes),
3654 spans: at
3655 .iter()
3656 .map(|&index| spans.get(index).copied().unwrap_or((0, 0)))
3657 .collect(),
3658 table: Arc::clone(table),
3659 },
3660 // Flattening decompresses, which is the price of the data slice it promises. The scratch
3661 // buffer is reused across rows, so this is one allocation for the whole column rather
3662 // than one per row the way reading it a value at a time would be.
3663 Body::Coded { codes, spans, table } => {
3664 let mut out = StringColumn::with_capacity(at.len());
3665 let mut scratch = Vec::new();
3666 for &index in &at {
3667 scratch.clear();
3668 let span = spans
3669 .get(index)
3670 .and_then(|&(from, to)| codes.get(from as usize..to as usize));
3671 if let Some(span) = span {
3672 table.decompress(span, &mut scratch)?;
3673 }
3674 out.push_bytes(&scratch);
3675 }
3676 Body::Flat(Data::Varlen(out))
3677 }
3678 // The entries move and the child does not, which is the same trade the string forms
3679 // make and is why a gather of a list column costs eight bytes a row however long the
3680 // lists are. A position that resolved to nowhere gets a zero length entry, and the mask
3681 // already says it is null, so the entry is never read.
3682 //
3683 // This arm ignores `forms_stay`, unlike every arm above it, because there is nothing
3684 // flatter for a list to become. The other forms are all cheaper ways of writing down a
3685 // column of scalars and flattening gives up the saving to hand back a data slice, and a
3686 // list has no data slice in any form, so a flatten of one is this and a caller reading it
3687 // goes through `list_parts` either way.
3688 Body::Nested { entries, child } => Body::Nested {
3689 entries: at
3690 .iter()
3691 .map(|&index| entries.get(index).copied().unwrap_or((0, 0)))
3692 .collect(),
3693 child: Arc::clone(child),
3694 },
3695 // Every child gathered at the same positions, for the reason the cut cuts every child:
3696 // there are no entries to permute instead, so the permutation happens once per field. The
3697 // positions handed down are the resolved ones, sentinel and all, so a row that resolved to
3698 // nowhere comes back null in each field as well as null here.
3699 //
3700 // `forms_stay` is passed straight through rather than ignored, which is the opposite of
3701 // what the list arm does, and the difference is real. There is nothing flatter for a list
3702 // to become, and a struct is only as flat as its fields are, so a flatten of a struct
3703 // column is a flatten of each field and a caller that asked for data slices gets them.
3704 Body::Fields { children } => Body::Fields {
3705 children: children
3706 .iter()
3707 .map(|child| child.copied(at.clone(), forms_stay).map(Arc::new))
3708 .collect::<Result<Vec<_>>>()?,
3709 },
3710 // Unreachable, because `resolve` walks past every form that points at another vector
3711 // and stops at the first body that does not.
3712 Body::Dictionary { .. } | Body::Runs { .. } | Body::Gathered { .. } => {
3713 return Err(Error::internal(
3714 "a form that points somewhere survived being resolved",
3715 ));
3716 }
3717 };
3718 Ok(Self { ty: self.ty.clone(), len: rows, validity, body })
3719 }
3720
3721 /// Where each wanted position lives in the first body that points nowhere else, and that body.
3722 ///
3723 /// A position that is null anywhere on the way down, or past the end of anything on the way
3724 /// down, comes back as [`NOWHERE`]. That single sentinel is what keeps the copy loop from
3725 /// carrying a validity mask alongside the positions it is already walking.
3726 fn resolve(&self, mut at: Vec<usize>) -> (Vec<usize>, &Self) {
3727 let mut source = self;
3728 loop {
3729 for slot in &mut at {
3730 if *slot >= source.len || !source.validity.is_valid(*slot) {
3731 *slot = NOWHERE;
3732 }
3733 }
3734 source = match &source.body {
3735 Body::Dictionary { codes, values, .. } => {
3736 for slot in &mut at {
3737 *slot = match codes.get(*slot) {
3738 Some(&code) => code as usize,
3739 None => NOWHERE,
3740 };
3741 }
3742 values.as_ref()
3743 }
3744 // A run length body is a dictionary whose code is worked out from the position
3745 // rather than stored, so the walk down is the same walk with a search where the
3746 // lookup was. `NOWHERE` searches for nothing and stays `NOWHERE`.
3747 Body::Runs { ends, values } => {
3748 for slot in &mut at {
3749 *slot = run_holding(ends, *slot).unwrap_or(NOWHERE);
3750 }
3751 values.as_ref()
3752 }
3753 // The same walk the dictionary above takes, with the sentinel folded into the one
3754 // this loop already has. That composition is the whole reason a gather is a body
3755 // rather than an operator: a filter over the output of a link join selects into the
3756 // ids and copies nothing, and a gather off a gather is one walk down to whatever is
3757 // at the bottom rather than two passes over the parent.
3758 Body::Gathered { source: below, rids, offset } => {
3759 for slot in &mut at {
3760 *slot = if *slot == NOWHERE {
3761 NOWHERE
3762 } else {
3763 row_of(rids, *offset, *slot).unwrap_or(NOWHERE)
3764 };
3765 }
3766 below.as_ref()
3767 }
3768 _ => return (at, source),
3769 };
3770 }
3771 }
3772}
3773
3774/// So that a kernel can take its operands as either a list of vectors or a list of references.
3775///
3776/// A caller that built a `Vec<Vector>` and a caller whose operands are already somewhere else, in a
3777/// chunk or in an evaluator's scratch, want the same kernel. Without this the second kind has to
3778/// clone every operand into a `Vec` to satisfy the signature, and a clone of a vector is a copy of
3779/// the whole column, so the type would be charging real memory traffic for nothing.
3780impl AsRef<Vector> for Vector {
3781 fn as_ref(&self) -> &Vector {
3782 self
3783 }
3784}
3785
3786/// The bits of a packed vector and what they mean, for a kernel that wants to stay in code space.
3787///
3788/// Borrowed from the vector rather than owning anything, so getting one costs nothing and a kernel
3789/// that finds it cannot use them has given up nothing by asking.
3790#[derive(Debug, Clone, Copy)]
3791pub struct Packed<'a> {
3792 words: &'a [u64],
3793 width: u32,
3794 base: i128,
3795 offset: usize,
3796}
3797
3798impl Packed<'_> {
3799 /// Packed words. A persisted vector also records [`Self::offset`].
3800 #[must_use]
3801 pub fn words(&self) -> &[u64] {
3802 self.words
3803 }
3804
3805 /// Bit offset, in rows, of the first value.
3806 #[must_use]
3807 pub fn offset(&self) -> usize {
3808 self.offset
3809 }
3810
3811 /// How many bits one code takes, between one and [`PACKED_WIDTH_MAX`].
3812 #[must_use]
3813 pub fn width(&self) -> u32 {
3814 self.width
3815 }
3816
3817 /// What zero means, so that the value of a row is the base plus its code.
3818 #[must_use]
3819 pub fn base(&self) -> i128 {
3820 self.base
3821 }
3822
3823 /// The largest value this vector can be holding, whatever it is actually holding.
3824 ///
3825 /// With [`Self::base`] this is the pair a comparison kernel wants first. A literal outside the
3826 /// two answers every row of the vector the same way, which is a whole chunk decided without a
3827 /// bit being read, and that is the case a zone map would have caught if there were one here.
3828 #[must_use]
3829 pub fn ceiling(&self) -> i128 {
3830 self.base + i128::from(u64::MAX >> (u64::BITS - self.width))
3831 }
3832
3833 /// The code of row `row`, which is its value minus [`Self::base`].
3834 ///
3835 /// Out of range rows read as zero rather than panicking, the way every other accessor in this
3836 /// file answers for a row that is not there.
3837 ///
3838 /// Marked inline because every caller that matters is a kernel in another crate reading one code
3839 /// per row, and thin LTO was leaving it as a call there. On TPC-H SF1 that call was 1.5 percent of
3840 /// the suite and a tenth of q12.
3841 #[must_use]
3842 #[inline]
3843 pub fn code(&self, row: usize) -> u64 {
3844 code_at(self.words, (self.offset + row) * self.width as usize, self.width)
3845 }
3846
3847 /// Which code a value would have, and `None` for a value this vector cannot be holding.
3848 ///
3849 /// The translation a comparison does once per vector so that it does not have to unpack once per
3850 /// row. `None` is the useful answer rather than a failure: it says the literal is outside the
3851 /// packed range, so every row compares against it the same way.
3852 #[must_use]
3853 pub fn code_of(&self, value: i128) -> Option<u64> {
3854 u64::try_from(value.checked_sub(self.base)?).ok().filter(|&code| code <= self.mask())
3855 }
3856
3857 /// The largest code the width allows.
3858 fn mask(&self) -> u64 {
3859 u64::MAX >> (u64::BITS - self.width)
3860 }
3861
3862 /// The codes of rows `from` to `from + out.len()`, in one pass over the words.
3863 ///
3864 /// [`Self::code`] is a code at a time, and every one of them works out which word it is in, reads
3865 /// it through a bound, and asks whether it straddles into the next. Sixty four codes of one
3866 /// width fill exactly that many words and the straddles fall in the same places every time, so a
3867 /// block of them is unpacked by a loop the width is a constant in, where every shift and every
3868 /// straddle is known before it runs. On TPC-H q1 the code at a time reads were a third of the
3869 /// instructions the query ran. The rows before the first whole block and after the last one
3870 /// still go a code at a time.
3871 pub fn unpack(&self, from: usize, out: &mut [u64]) {
3872 let width = self.width as usize;
3873 let start = self.offset + from;
3874 let end = start + out.len();
3875 let first = start.next_multiple_of(64).min(end);
3876 let mut at = 0;
3877 for row in start..first {
3878 out[at] = code_at(self.words, row * width, self.width);
3879 at += 1;
3880 }
3881 let mut row = first;
3882 while row + 64 <= end {
3883 let word = row / 64 * width;
3884 let Some(words) = self.words.get(word..word + width) else { break };
3885 let Some(Ok(block)) = out.get_mut(at..at + 64).map(<&mut [u64; 64]>::try_from) else {
3886 break;
3887 };
3888 unpack_block(words, self.width, block);
3889 row += 64;
3890 at += 64;
3891 }
3892 for row in row..end {
3893 out[at] = code_at(self.words, row * width, self.width);
3894 at += 1;
3895 }
3896 }
3897
3898 /// The codes of rows `from` to `from + rows`, each of them through `value`, appended to `out`.
3899 ///
3900 /// [`Self::unpack`] leaves its codes in a slice of `u64` that a caller wanting something else then
3901 /// walks a second time, which costs a vector to allocate, that vector zeroed before a single code
3902 /// is written into it, and a pass over every row that loads and stores it again. A caller reading a
3903 /// whole chunk in order wants one vector and one pass, so the block this unpacks into is 64 codes
3904 /// of stack that the next block writes over, and what reaches `out` is already the value asked
3905 /// for. The vector grows into room it reserved once, so nothing here is zeroed at all.
3906 ///
3907 /// Unpacking a block at a time was tried for random rows and lost, see [`Self::codes_into`], but
3908 /// that walk pays to ask which block each row falls in and this one goes straight through.
3909 pub fn unpack_mapped<U: Copy>(
3910 &self,
3911 from: usize,
3912 rows: usize,
3913 out: &mut Vec<U>,
3914 value: impl Fn(u64) -> U,
3915 ) {
3916 let width = self.width as usize;
3917 let start = self.offset + from;
3918 let end = start + rows;
3919 let first = start.next_multiple_of(64).min(end);
3920 out.reserve(rows);
3921 for row in start..first {
3922 out.push(value(code_at(self.words, row * width, self.width)));
3923 }
3924 let mut row = first;
3925 let mut block = [0_u64; 64];
3926 while row + 64 <= end {
3927 let word = row / 64 * width;
3928 let Some(words) = self.words.get(word..word + width) else { break };
3929 unpack_block(words, self.width, &mut block);
3930 out.extend(block.iter().map(|&code| value(code)));
3931 row += 64;
3932 }
3933 // Whatever the blocks did not cover, which is the tail and also everything after a width that
3934 // ran out of words, the same way [`Self::unpack`] leaves it to `code_at` to read as zero.
3935 for row in row..end {
3936 out.push(value(code_at(self.words, row * width, self.width)));
3937 }
3938 }
3939
3940 /// The code of each of `rows` rows `at` names, in order.
3941 ///
3942 /// [`Self::codes_into`] into a vector of its own. A caller reading a column a chunk at a time
3943 /// wants that vector once rather than once a chunk, and calls the other one.
3944 pub fn codes_at<M: Fn(usize) -> usize>(&self, at: M, rows: usize) -> Vec<u64> {
3945 let mut codes = vec![0; rows];
3946 self.codes_into(at, rows, &mut codes);
3947 codes
3948 }
3949
3950 /// The code of each of `rows` rows `at` names, in order, left in `out[..rows]`.
3951 ///
3952 /// A filter's selection names rows close together and in order, so the span they cover is
3953 /// unpacked whole with [`Self::unpack`] and each row read out of it. Rows spread too far apart
3954 /// for that to pay are read a code at a time.
3955 ///
3956 /// Unpacking a block at a time into a buffer on the stack, and reading each row out of the
3957 /// block it falls in, keeps less in the cache and was tried. The question of which block a row
3958 /// is in, asked for every row, cost more than the misses it saved, 40.2 G instructions for ten
3959 /// runs of q1 against 34.1 G this way.
3960 ///
3961 /// Rows that turn out to be a run, which is every row of the vector in order and is what a
3962 /// comparison over a whole chunk asks for, are unpacked straight into the answer. The span and
3963 /// the answer are the same rows in the same order there, so the buffer, the zeroing of it and
3964 /// the pass copying it out are all a copy of a thing onto itself. A filter over a packed `DATE`
3965 /// column of six million rows spent 37 percent of the query in here and the compare it fed 4.8
3966 /// percent, which is the shape of paying three passes for one. Whether the rows are a run is one
3967 /// compare a row in the pass that was already reading them.
3968 ///
3969 /// Rows that are not a run, which is the second conjunct of a filter reading only the rows the
3970 /// first one kept, unpack the span they cover into a buffer each thread keeps rather than a
3971 /// fresh one. The span of a selection over a chunk is about as wide as the chunk whatever the
3972 /// selection keeps, so the fresh buffer was an allocation and a page of zeroes a chunk for a run
3973 /// of zeroes that the unpack immediately writes over. [`Self::values_at`] below keeps its span
3974 /// the same way and for the same reason.
3975 ///
3976 /// `out` is grown to hold `rows` and is not otherwise touched, so a buffer longer than the rows
3977 /// keeps whatever is past them, and a buffer already long enough is not zeroed on the way in.
3978 /// Every one of `out[..rows]` is written before this returns.
3979 pub fn codes_into<M: Fn(usize) -> usize>(&self, at: M, rows: usize, out: &mut Vec<u64>) {
3980 thread_local! {
3981 static SPAN: RefCell<Vec<u64>> = const { RefCell::new(Vec::new()) };
3982 }
3983 if out.len() < rows {
3984 out.resize(rows, 0);
3985 }
3986 if rows == 0 {
3987 return;
3988 }
3989 let first = at(0);
3990 let (mut low, mut high) = (first, first);
3991 let mut ascends = true;
3992 for index in 1..rows {
3993 let row = at(index);
3994 low = low.min(row);
3995 high = high.max(row);
3996 ascends &= row == first + index;
3997 }
3998 if ascends {
3999 self.unpack(first, &mut out[..rows]);
4000 return;
4001 }
4002 if high - low >= rows.saturating_mul(4) {
4003 for (index, code) in out[..rows].iter_mut().enumerate() {
4004 *code = self.code(at(index));
4005 }
4006 return;
4007 }
4008 // Taken out of the thread's slot and put back rather than borrowed for the body, so that the
4009 // body is the straight line it was when it allocated. Handing the buffer to a closure and
4010 // calling that closure from both arms of a borrow left the gather a call rather than a loop.
4011 let span = high - low + 1;
4012 let mut run = SPAN.with_borrow_mut(std::mem::take);
4013 if run.len() < span {
4014 run.resize(span, 0);
4015 }
4016 self.unpack(low, &mut run[..span]);
4017 for (index, code) in out[..rows].iter_mut().enumerate() {
4018 *code = run[at(index) - low];
4019 }
4020 SPAN.with_borrow_mut(|held| *held = run);
4021 }
4022
4023 /// The value of each row `at` names, in order, made from its code by `value`.
4024 ///
4025 /// [`Self::codes_at`] for a filter's `u32` positions, with the value made as each row is read
4026 /// rather than in a second pass over the codes. Three things it did cost more than the reads on
4027 /// q01, where a filter keeps nearly every row of every packed column. The smallest and largest
4028 /// position were a scalar compare and move a row, because SSE2 has no unsigned or 64 bit
4029 /// minimum, and here they are signed 32 bit ones, which it has. The span was a fresh buffer
4030 /// of zeroes, and here each thread keeps one. And the codes were written out whole before the
4031 /// values were made from them.
4032 pub fn values_at<T>(&self, at: &[u32], value: impl Fn(u64) -> T) -> Vec<T> {
4033 thread_local! {
4034 static SPAN: RefCell<Vec<u64>> = const { RefCell::new(Vec::new()) };
4035 }
4036 let Some((low, high)) = extent(at) else { return Vec::new() };
4037 let (low, high) = (low as usize, high as usize);
4038 if high - low >= at.len().saturating_mul(4) {
4039 return at.iter().map(|&row| value(self.code(row as usize))).collect();
4040 }
4041 let span = high - low + 1;
4042 let gathered = |run: &mut Vec<u64>| {
4043 if run.len() < span {
4044 run.resize(span, 0);
4045 }
4046 let run = &mut run[..span];
4047 self.unpack(low, run);
4048 at.iter().map(|&row| value(run[row as usize - low])).collect()
4049 };
4050 SPAN.with(|held| match held.try_borrow_mut() {
4051 Ok(mut held) => gathered(&mut held),
4052 Err(_) => gathered(&mut Vec::new()),
4053 })
4054 }
4055}
4056
4057/// Sixty four codes of `width` bits out of the `width` words that hold them, with the width made a
4058/// constant so that the loop in [`unpack_width`] has nothing left to work out as it goes.
4059fn unpack_block(words: &[u64], width: u32, out: &mut [u64; 64]) {
4060 macro_rules! widths {
4061 ($($width:literal)*) => {
4062 match width {
4063 $($width => unpack_width::<$width>(words, out),)*
4064 _ => {
4065 for (at, code) in out.iter_mut().enumerate() {
4066 *code = code_at(words, at * width as usize, width);
4067 }
4068 }
4069 }
4070 };
4071 }
4072 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
4073 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);
4074}
4075
4076#[inline(always)]
4077fn unpack_width<const WIDTH: usize>(words: &[u64], out: &mut [u64; 64]) {
4078 let Ok(words) = <&[u64; WIDTH]>::try_from(&words[..WIDTH]) else { return };
4079 // Written out sixty four times rather than as a loop, because the compiler kept the loop and
4080 // with it a shift and a branch on the straddle for every code. Spelled out, the row is a
4081 // constant in each step, so its word, its shift and whether it straddles are all worked out
4082 // before the program runs and a code is a shift, an or where it straddles and a mask.
4083 macro_rules! steps {
4084 ($($at:literal)*) => {
4085 $(unpack_step::<WIDTH, $at>(words, out);)*
4086 };
4087 }
4088 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
4089 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);
4090}
4091
4092#[inline(always)]
4093fn unpack_step<const WIDTH: usize, const AT: usize>(words: &[u64; WIDTH], out: &mut [u64; 64]) {
4094 let bit = AT * WIDTH;
4095 let word = bit / 64;
4096 let shift = bit % 64;
4097 let mut value = words[word] >> shift;
4098 if shift + WIDTH > 64 {
4099 value |= words[word + 1] << (64 - shift);
4100 }
4101 out[AT] = value & (u64::MAX >> (64 - WIDTH));
4102}
4103
4104/// The widest a packed code is allowed to be.
4105///
4106/// Sixty three rather than sixty four so that a mask is `u64::MAX >> (64 - width)` with no shift of
4107/// a whole word in it, and reading a code is one branch on whether it straddles rather than two. A
4108/// sixty four bit code saves nothing anyway, since it is the layout it came from.
4109pub const PACKED_WIDTH_MAX: u32 = 63;
4110
4111/// How much smaller packing has to be before it is worth the shift and the mask on every read.
4112///
4113/// Two, so a column packs when the bits come to half the flat size or less. A column that would save
4114/// a tenth stays flat, because a tenth of a column is not worth turning every read of it into
4115/// arithmetic, and the whole argument for the form is that a narrow column saves most of itself.
4116pub const PACKING_PAYS_AT: usize = 2;
4117
4118/// How much smaller compressing has to be before it is worth a decompression on every read.
4119///
4120/// Two, the same rule packing follows and for the same reason. FSST gets about that on text, so a
4121/// column of English or of URLs compresses and a column of short codes or of random bytes does not,
4122/// which is the right answer for both.
4123pub const FSST_PAYS_AT: usize = 2;
4124
4125/// The codes of a compressed column and the table they are against.
4126///
4127/// Handed out by [`Vector::coded_parts`] so a kernel can work in code space. Nothing here
4128/// decompresses, which is the point: [`Self::encode`] puts the literal into the same space the rows
4129/// are already in, and after that an equality test is a byte slice comparison.
4130#[derive(Debug, Clone, Copy)]
4131pub struct Coded<'a> {
4132 codes: &'a [u8],
4133 spans: &'a [(u32, u32)],
4134 table: &'a SymbolTable,
4135}
4136
4137impl Coded<'_> {
4138 /// The table every row in this vector is compressed against.
4139 #[must_use]
4140 pub fn table(&self) -> &SymbolTable {
4141 self.table
4142 }
4143
4144 /// The code bytes of one row, still compressed.
4145 #[must_use]
4146 pub fn row(&self, row: usize) -> Option<&[u8]> {
4147 let &(from, to) = self.spans.get(row)?;
4148 self.codes.get(from as usize..to as usize)
4149 }
4150
4151 /// Some bytes in the code space this vector is in.
4152 ///
4153 /// The literal side of an equality filter. Compressing is a function of the table and the bytes,
4154 /// so two strings compress to the same codes exactly when they are the same string, and an
4155 /// equality test on the codes is an equality test on the strings with no decompression in it.
4156 #[must_use]
4157 pub fn encode(&self, bytes: &[u8]) -> Vec<u8> {
4158 let mut out = Vec::with_capacity(bytes.len());
4159 self.table.compress(bytes, &mut out);
4160 out
4161 }
4162}
4163
4164/// The first `len` of a run of some narrower signed width, sign extended into `out`.
4165///
4166/// Written once and called from the three narrow arms of [`Data::signed_block`], so that the sign
4167/// extension is one loop the compiler can widen rather than three written out by hand.
4168fn widen<T: Copy + Into<i64>>(run: &[T], len: usize, out: &mut Vec<i64>) -> bool {
4169 match run.get(..len) {
4170 Some(run) => {
4171 out.extend(run.iter().map(|&x| x.into()));
4172 true
4173 }
4174 None => false,
4175 }
4176}
4177
4178/// The rows `at` of the first `len` of `run`, widened, appended to `out`. The range is checked
4179/// with a maximum first, because a maximum vectorizes and a check on every read would not.
4180fn gather_widened<T: Copy + Into<i64>>(
4181 run: &[T],
4182 len: usize,
4183 at: &[u32],
4184 out: &mut Vec<i64>,
4185) -> bool {
4186 let Some(run) = run.get(..len) else {
4187 return false;
4188 };
4189 // See `below`: the largest of `at` is a scalar loop here and was three quarters of this.
4190 if !below(at, run.len()) {
4191 return false;
4192 }
4193 out.extend(at.iter().map(|&row| run[row as usize].into()));
4194 true
4195}
4196
4197/// See [`Data::signed_runs`]. Sixteen values are compared against the current one at once, which
4198/// the compiler turns into a few vector compares, and only a block where something changed is
4199/// walked a value at a time.
4200fn runs_widened<T: Copy + Eq + Into<i64>>(
4201 run: &[T],
4202 len: usize,
4203 (from, to): (usize, usize),
4204 every: usize,
4205 out: &mut Vec<(i64, usize)>,
4206) -> bool {
4207 out.clear();
4208 let Some(values) = run.get(..len).and_then(|run| run.get(from..to)) else {
4209 return false;
4210 };
4211 let Some(&first) = values.first() else {
4212 return true;
4213 };
4214 let mut current = first;
4215 for (block, stretch) in values.chunks(16).enumerate() {
4216 if !stretch.iter().fold(false, |differ, &value| differ | (value != current)) {
4217 continue;
4218 }
4219 let start = from + block * 16;
4220 for (row, &value) in stretch.iter().enumerate() {
4221 if value != current {
4222 out.push((current.into(), start + row));
4223 current = value;
4224 }
4225 }
4226 if out.len() > (block * 16) / every.max(1) + 64 {
4227 out.clear();
4228 return false;
4229 }
4230 }
4231 out.push((current.into(), to));
4232 true
4233}
4234
4235/// One holder's share of a part that several vectors are reading at the same time.
4236///
4237/// The rule [`Buffer::footprint`] already uses for a shared page. Everything holding the part asks
4238/// this, so what they say between them comes to about what the part costs rather than to the part
4239/// times the number of them, and the answer is never zero for a part that costs anything, because a
4240/// caller with a reference is at least one holder.
4241fn share<T: ?Sized>(bytes: usize, held: &Arc<T>) -> usize {
4242 bytes / Arc::strong_count(held).max(1)
4243}
4244
4245/// How many words hold `len` codes of `width` bits.
4246fn words_for(len: usize, width: u32) -> usize {
4247 (len * width as usize).div_ceil(u64::BITS as usize)
4248}
4249
4250/// The lowest and highest value a type's layout can hold, and `None` for a type with no integer one.
4251///
4252/// This is also the test of whether a type can be packed at all, and it is the only one, so the
4253/// layouts listed here and the layouts [`pack`] and [`unpack`] know how to walk are the same list
4254/// from the same macro and cannot drift apart.
4255fn layout_range(ty: &LogicalType) -> Option<(i128, i128)> {
4256 use rudb_common::PhysicalType as P;
4257 macro_rules! ranges {
4258 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4259 match ty.physical() {
4260 $(P::$variant => Some((i128::from(<$native>::MIN), i128::from(<$native>::MAX))),)+
4261 _ => None,
4262 }
4263 };
4264 }
4265 crate::for_each_layout!(exact, ranges)
4266}
4267
4268/// The bytes the first `len` slots of a run take laid flat, whether the run is owned or a window.
4269fn flat_bytes(data: &Data, len: usize) -> usize {
4270 macro_rules! widths {
4271 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4272 match data {
4273 Data::Empty => 0,
4274 $(Data::$variant(_) => len * size_of::<$native>(),)+
4275 }
4276 };
4277 }
4278 crate::for_each_layout!(all, widths)
4279}
4280
4281/// What to subtract before packing, so that the whole code range lands inside the column's type.
4282///
4283/// The smallest value in the column is the obvious base and it is the wrong one near the top of a
4284/// type. [`Vector::packed`] checks the two ends of what the codes could say rather than the values
4285/// that are actually there, which is one check instead of one per row and is what makes reading a
4286/// packed column cheap. An `INTEGER` column of a thousand values just under `i32::MAX` needs ten
4287/// bits, and based at its own smallest value those ten bits could say a number an `INTEGER` cannot
4288/// hold, so the column was refused and the table would not write at all.
4289///
4290/// The base does not have to be the smallest value. Any base works where every code is still
4291/// non-negative and the widest code the width allows still fits the type, which is `base <= low`,
4292/// `high - base <= 2^width - 1`, `type low <= base` and `base + 2^width - 1 <= type high` together.
4293///
4294/// The largest base meeting all four is the one below, and it exists whenever the values fit the
4295/// type at all: `high - (2^width - 1) <= low` because that is how the width was chosen, and
4296/// `type low <= type high - (2^width - 1)` because a width wider than the type's own span is
4297/// already refused. `None` is for a type with no integer layout, which cannot be packed anyway.
4298fn packing_base(ty: &LogicalType, low: i128, high: i128, width: u32) -> Option<i128> {
4299 let (floor, ceiling) = layout_range(ty)?;
4300 let span = i128::from(u64::MAX >> (64 - width));
4301 let base = low.min(ceiling - span);
4302 (base >= floor && base >= high - span).then_some(base)
4303}
4304
4305/// The lowest and highest value in the first `len` slots of a run of integer data.
4306///
4307/// `None` for data that is not integers, which is what says a column cannot be packed. The null
4308/// slots are in the span, holding whatever zero was written into them, which
4309/// [`Vector::bit_packed`] says more about.
4310fn span_of(data: &Data, len: usize) -> Option<(i128, i128)> {
4311 macro_rules! spans {
4312 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4313 match data {
4314 $(Data::$variant(values) => {
4315 // In the value's own type and one end at a time, which the compiler turns
4316 // into vector compares. Widening each value to `i128` first kept both ends in
4317 // register pairs and made this two percent of a ClickBench load.
4318 let values = values.as_slice();
4319 let values = &values[..len.min(values.len())];
4320 let low = values.iter().copied().min()?;
4321 let high = values.iter().copied().max()?;
4322 Some((i128::from(low), i128::from(high)))
4323 })+
4324 _ => None,
4325 }
4326 };
4327 }
4328 crate::for_each_layout!(exact, spans)
4329}
4330
4331/// The first `len` values of a run of integer data, written out as codes of `width` bits from `base`.
4332fn pack(data: &Data, len: usize, base: i128, width: u32) -> Vec<u64> {
4333 let mut words = vec![0u64; words_for(len, width)];
4334 macro_rules! packing {
4335 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4336 match data {
4337 $(Data::$variant(values) => {
4338 for (row, &value) in values.as_slice().iter().take(len).enumerate() {
4339 // In range because `base` and `width` came from the span of this same run.
4340 let code = u64::try_from(i128::from(value) - base).unwrap_or(0);
4341 write_code(&mut words, row * width as usize, width, code);
4342 }
4343 })+
4344 _ => {}
4345 }
4346 };
4347 }
4348 crate::for_each_layout!(exact, packing);
4349 words
4350}
4351
4352/// The codes at the given rows, unpacked into the flat layout the type calls for.
4353///
4354/// A row of [`NOWHERE`] writes the layout's zero, which is the rule [`copy_of`] follows for the same
4355/// reason: every layout here is a parallel array to a validity mask, so a null takes a slot.
4356///
4357/// # Errors
4358///
4359/// If the type has no flat layout, which a packed vector cannot have and which is checked when one
4360/// is built, so an error here is a bug rather than a caller mistake.
4361fn unpack(
4362 ty: &LogicalType,
4363 words: &[u64],
4364 offset: usize,
4365 width: u32,
4366 base: i128,
4367 at: &[usize],
4368) -> Result<Data> {
4369 let mut out = empty_data_for(ty)?;
4370 let value_of = |row: usize| {
4371 if row == NOWHERE {
4372 return None;
4373 }
4374 Some(base + i128::from(code_at(words, (offset + row) * width as usize, width)))
4375 };
4376 macro_rules! unpacking {
4377 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4378 match &mut out {
4379 $(Data::$variant(values) => {
4380 values.reserve(at.len());
4381 for &row in at {
4382 // In range because both ends of it were checked when the vector was built.
4383 let value = value_of(row)
4384 .and_then(|value| <$native>::try_from(value).ok())
4385 .unwrap_or($zero);
4386 values.push(value);
4387 }
4388 })+
4389 _ => {
4390 return Err(Error::internal(format!(
4391 "a {ty} vector was packed, which no integer layout allows"
4392 )));
4393 }
4394 }
4395 };
4396 }
4397 crate::for_each_layout!(exact, unpacking);
4398 Ok(out)
4399}
4400
4401/// The `width` bits starting at `bit`, low end first.
4402///
4403/// Zero for bits past the end of the words, which keeps a read of a row that is not there from
4404/// panicking and matches what every other accessor here does with one.
4405#[inline]
4406fn code_at(words: &[u64], bit: usize, width: u32) -> u64 {
4407 let word = bit / u64::BITS as usize;
4408 let shift = (bit % u64::BITS as usize) as u32;
4409 let mask = u64::MAX >> (u64::BITS - width);
4410 let low = words.get(word).copied().unwrap_or(0) >> shift;
4411 let taken = u64::BITS - shift;
4412 if taken >= width {
4413 return low & mask;
4414 }
4415 // The code straddles two words, and `taken` is under the width here so it is under sixty four,
4416 // which is what makes the shift below one the hardware will do rather than one it refuses.
4417 let high = words.get(word + 1).copied().unwrap_or(0) << taken;
4418 (low | high) & mask
4419}
4420
4421/// Writes `width` bits of `code` starting at `bit`, over words that started out zero.
4422fn write_code(words: &mut [u64], bit: usize, width: u32, code: u64) {
4423 let word = bit / u64::BITS as usize;
4424 let shift = (bit % u64::BITS as usize) as u32;
4425 words[word] |= code << shift;
4426 let taken = u64::BITS - shift;
4427 if taken < width {
4428 words[word + 1] |= code >> taken;
4429 }
4430}
4431
4432/// One level of dictionary out of however many levels were handed to [`Vector::dictionary`].
4433///
4434/// Every dictionary in the system is built through that constructor and every one of them comes
4435/// through here first, so the invariant this maintains is that the vector a dictionary points at is
4436/// never itself a dictionary that could have been composed away. That makes the work a single `if`
4437/// rather than a loop: the inner vector was already composed when it was built, so composing the
4438/// outer codes through it leaves the result no deeper than the inner vector already was.
4439///
4440/// The codes are indexed rather than fetched with `get`, because the caller has already walked the
4441/// whole outer array to check that every code is in range and the inner array is exactly as long as
4442/// the vector those codes were checked against.
4443fn compose(codes: Vec<u32>, values: Arc<Vector>) -> (Vec<u32>, Arc<Vector>) {
4444 // A dictionary carrying a validity of its own is one whose nulls live at this level rather than
4445 // in the values, which is the one thing composition cannot carry down with it.
4446 if !matches!(values.validity, Validity::AllValid) {
4447 return (codes, values);
4448 }
4449 let Body::Dictionary { codes: inner, values: leaf, .. } = &values.body else {
4450 return (codes, values);
4451 };
4452 debug_assert!(
4453 !matches!(leaf.body, Body::Dictionary { .. })
4454 || !matches!(leaf.validity, Validity::AllValid),
4455 "a dictionary was stacked on a dictionary without going through the constructor"
4456 );
4457 // The leaf is handed on as the handle it already is. Nothing here reads it and nothing here
4458 // changes it, so the composed dictionary points at the same values the stacked one did and
4459 // whoever else is holding them keeps holding them. This used to take them out of the `Arc`,
4460 // which copied the whole leaf whenever anybody else was still reading it, and a scan selecting
4461 // rows out of a chunk whose column came from a shared page dictionary is exactly that: the page
4462 // holds the leaf, every chunk cut from the page composes through it, and every one of those
4463 // cuts copied the page's dictionary. TPC-H q21 does it once per thousand rows of `lineitem`.
4464 let composed = codes.iter().map(|&code| inner[code as usize]).collect();
4465 (composed, Arc::clone(leaf))
4466}
4467
4468/// How many rows a run has to cover on average before run length encoding is smaller.
4469///
4470/// A run costs its value plus the four bytes of its end, so on a four byte column a run of two rows
4471/// breaks even and a run of three wins. Wider columns win sooner and narrower ones later, and this
4472/// is the one ratio for all of them because a threshold per width is a table that has to be right
4473/// nine times rather than once. It is a constant with a name so that the sweep that eventually moves
4474/// it has something to move.
4475const RUNS_PAY_AT: usize = 2;
4476
4477/// A string body's arena as a page, when this is the only holder of it.
4478///
4479/// The move out of the `Arc` and back into one is what makes this free: [`Buffer::into_page`] takes
4480/// the run by value and puts it behind an `Arc` without touching a byte of it, so the whole of this
4481/// is two allocations of a pointer's worth each however large the arena is.
4482///
4483/// An arena somebody else is holding comes back untouched. Paging it would mean copying it, since
4484/// the other holder's view of it has to go on meaning what it meant, and a copy is what the caller
4485/// asked to avoid.
4486fn paged(arena: Arc<Buffer<u8>>) -> Arc<Buffer<u8>> {
4487 if arena.is_shared() {
4488 return arena;
4489 }
4490 match Arc::try_unwrap(arena) {
4491 Ok(owned) => Arc::new(owned.into_page()),
4492 Err(held) => held,
4493 }
4494}
4495
4496/// Which run holds `row`, given ends that are exclusive and increasing.
4497///
4498/// A binary search rather than a scan, because the callers that ask this are the ones that are not
4499/// walking the runs in order: a single value read out of a result set, or a gather at scattered
4500/// positions. Anything walking in order should be reading [`Vector::run_parts`] instead, which is
4501/// what the form is for.
4502fn run_holding(ends: &[u32], row: usize) -> Option<usize> {
4503 let row = u32::try_from(row).ok()?;
4504 let run = match ends.binary_search(&row) {
4505 // The ends are exclusive, so landing exactly on one means the row is the first of the next.
4506 Ok(at) => at + 1,
4507 Err(at) => at,
4508 };
4509 (run < ends.len()).then_some(run)
4510}
4511
4512/// The row each run ends at, for a flat body read alongside the validity that goes with it.
4513///
4514/// Two adjacent nulls are one run, because a reader of either gets a null and cannot tell them
4515/// apart. A null between two equal values is three runs for the same reason, since the null is a
4516/// value of the column as far as anything reading it is concerned.
4517///
4518/// The comparison is per layout rather than per `Value`, which is the whole reason this is a macro.
4519/// A `Value` a row would allocate a string per row on a `VARCHAR` column and would be the exact
4520/// defect `cargo xtask rowloop` exists to fail the build on.
4521fn boundaries(data: &Data, validity: &Validity, len: usize) -> Vec<u32> {
4522 if len == 0 {
4523 return Vec::new();
4524 }
4525 let breaks = |ends: &mut Vec<u32>, mut differs: Box<dyn FnMut(usize, usize) -> bool + '_>| {
4526 for row in 1..len {
4527 let same = match (validity.is_valid(row), validity.is_valid(row - 1)) {
4528 (false, false) => true,
4529 (true, true) => !differs(row, row - 1),
4530 _ => false,
4531 };
4532 if !same {
4533 ends.push(u32::try_from(row).unwrap_or(u32::MAX));
4534 }
4535 }
4536 ends.push(u32::try_from(len).unwrap_or(u32::MAX));
4537 };
4538 let mut ends = Vec::new();
4539 macro_rules! walked {
4540 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4541 match data {
4542 // No values at all, so every row is the same null and the column is one run.
4543 Data::Empty => ends.push(u32::try_from(len).unwrap_or(u32::MAX)),
4544 $(Data::$variant(values) => {
4545 breaks(&mut ends, Box::new(|a, b| values.get(a) != values.get(b)));
4546 })+
4547 Data::Varlen(values) => {
4548 breaks(&mut ends, Box::new(|a, b| values.bytes(a) != values.bytes(b)));
4549 }
4550 }
4551 };
4552 }
4553 crate::for_each_layout!(fixed, walked);
4554 ends
4555}
4556
4557/// The position of a value that is not anywhere, because it is null or out of range.
4558///
4559/// `usize::MAX` rather than an `Option<usize>`, because the copy loop's bounds check rejects it for
4560/// free and an `Option` would put a second branch next to the one already there.
4561pub(crate) const NOWHERE: usize = usize::MAX;
4562
4563/// The row id of a row that is not in the source, which reads as null.
4564///
4565/// Public because whoever builds a [`Form::Gathered`] vector has to write it, and it is `u32::MAX`
4566/// for the reason the crate's own offset sentinel is `usize::MAX`: a bounds check the reader is
4567/// doing anyway rejects it, where an `Option<u32>` would be eight bytes a row instead of four and a
4568/// second branch beside the one already there. It costs the last row of a four billion row source,
4569/// which is a source no column in this engine has.
4570pub const NO_ROW: u32 = u32::MAX;
4571
4572/// Which source row a gathered row names, and `None` when it names none.
4573///
4574/// The `Option` is what every reader of [`Body::Gathered`] that returns an `Option` wants, so the
4575/// three cases that are all *there is nothing here*, past the end of the ids, the sentinel, and an
4576/// id that does not fit a `usize`, are collapsed once here rather than three times each.
4577fn row_of(rids: &[u32], offset: usize, index: usize) -> Option<usize> {
4578 match rids.get(offset + index) {
4579 Some(&NO_ROW) | None => None,
4580 Some(&rid) => Some(rid as usize),
4581 }
4582}
4583
4584/// A run of data copied at the given positions, with a zero wherever the position is [`NOWHERE`].
4585///
4586/// A zero and not a skip, because every layout here is a parallel array to a validity mask and a
4587/// short one would put every value after the first null at the wrong index. It is the same rule
4588/// [`push_value`] follows for a null.
4589/// A contiguous run of a flat body, copied out.
4590///
4591/// The counterpart to [`copy_of`] for the one case that is a range rather than a set of positions,
4592/// which is what [`Vector::slice`] asks for. Every fixed width layout is one `memcpy` and the
4593/// string layout is a run of views and their bytes, where `copy_of` is a bounds checked index and a
4594/// null test per row.
4595///
4596/// The caller has already checked that `end` is inside the vector, and a body whose data is shorter
4597/// than its vector claims is a bug elsewhere, so a short run is clamped rather than reported.
4598///
4599/// A fixed width run over a buffer that is a window into a page does not copy anything, because
4600/// [`Buffer::slice`] moves the offset instead. That is the case a scan over stored memory is in, and
4601/// it is why the flat body is no longer the one form of a vector whose cut costs an allocation.
4602fn run_of(data: &Data, at: usize, end: usize) -> Data {
4603 macro_rules! run {
4604 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4605 match data {
4606 Data::Empty => Data::Empty,
4607 $(Data::$variant(values) => {
4608 let held = values.len();
4609 let from = at.min(held);
4610 let to = end.max(from).min(held);
4611 if to == end {
4612 // The whole run is there, so this is a window on a shared page and a copy on
4613 // an owned one, decided inside the buffer rather than here.
4614 Data::$variant(values.slice(from, end - from))
4615 } else {
4616 let values = values.as_slice();
4617 let mut out = Buffer::with_capacity(end - at);
4618 out.extend_from_slice(&values[from..to]);
4619 // A body shorter than the rows asked for pads with the zero every layout
4620 // uses for a null, which is the answer `copy_of` gives for a position past
4621 // the end.
4622 // row at a time: never runs on a vector whose data matches its length.
4623 for _ in to..end {
4624 out.push($zero);
4625 }
4626 Data::$variant(out)
4627 }
4628 })+
4629 // A view says where its bytes are, so a run of rows is not a run of bytes and this
4630 // is the one layout whose cut is still a loop. The total is known before any of it
4631 // is copied, so the arena is one allocation.
4632 //
4633 // Unless the payload is a page, in which case the cut points at the same page the
4634 // column does and no byte of it moves. That is the case a scan of a stored column
4635 // is in, and it is the whole of why a producer pages its payload: a page cut into
4636 // chunk sized pieces used to copy every byte of every long string once per piece.
4637 Data::Varlen(values) => {
4638 if let Some(shared) =
4639 values.window(at, end).or_else(|| values.viewing(at..end))
4640 {
4641 return Data::Varlen(shared);
4642 }
4643 let views = values.views();
4644 let mut out = StringColumn::with_capacity(end - at);
4645 out.reserve_bytes(
4646 views
4647 .get(at.min(views.len())..end.min(views.len()))
4648 .unwrap_or(&[])
4649 .iter()
4650 .filter(|view| !view.is_inline())
4651 .map(StringView::len)
4652 .sum(),
4653 );
4654 // row at a time: see above, the bytes of consecutive rows need not be next to
4655 // each other.
4656 for index in at..end {
4657 out.push_from(values, index);
4658 }
4659 Data::Varlen(out)
4660 }
4661 }
4662 };
4663 }
4664 crate::for_each_layout!(fixed, run)
4665}
4666
4667/// The values of `data` written to the places `inverse` gives them, the other way round from
4668/// [`copy_of`]: value `n` lands at `inverse[n]`.
4669///
4670/// `inverse` is a permutation of the positions of `data` and the answer is as long as it. A place
4671/// past the end is dropped rather than trusted, and a place nobody wrote keeps the zero, the same
4672/// zero a gather writes for a position that resolved to nowhere. Strings are turned back into
4673/// positions and gathered, because their one caller moves the views itself and never sends them.
4674pub(crate) fn placed_of(data: &Data, inverse: &[u32]) -> Data {
4675 macro_rules! placed {
4676 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4677 match data {
4678 $(Data::$variant(values) => {
4679 let mut out: Vec<$native> = vec![$zero; inverse.len()];
4680 for (value, &to) in values.as_slice().iter().zip(inverse) {
4681 if let Some(slot) = out.get_mut(to as usize) {
4682 *slot = *value;
4683 }
4684 }
4685 Data::$variant(Buffer::from_vec(out))
4686 })+
4687 Data::Empty => Data::Empty,
4688 // Turned back round into positions and gathered, so a caller that does hand this
4689 // strings gets the right answer rather than a missing arm.
4690 Data::Varlen(_) => {
4691 let mut at = vec![NOWHERE; inverse.len()];
4692 for (row, &to) in inverse.iter().enumerate() {
4693 if let Some(slot) = at.get_mut(to as usize) {
4694 *slot = row;
4695 }
4696 }
4697 copy_of(data, &at)
4698 }
4699 }
4700 };
4701 }
4702 crate::for_each_layout!(fixed, placed)
4703}
4704
4705pub(crate) fn copy_of(data: &Data, at: &[usize]) -> Data {
4706 macro_rules! copied {
4707 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4708 match data {
4709 Data::Empty => Data::Empty,
4710 $(Data::$variant(values) => {
4711 let values = values.as_slice();
4712 // Into a `Vec` and then into a buffer, rather than pushing at the buffer. A
4713 // push asks the buffer whether it owns its run and copies the page out if it
4714 // does not, which is the copy on write point and is the right answer for a
4715 // caller writing one value. This caller is writing `at.len()` of them into a
4716 // run it made itself one line earlier, so the question has one answer and it
4717 // is asked once by not being asked at all. The map is exact sized, so the
4718 // extend reserves once and writes without a capacity check per value.
4719 let mut out: Vec<$native> = Vec::with_capacity(at.len());
4720 // One bounds check rather than a null test and a bounds check, because
4721 // `NOWHERE` is past the end of every slice there can be.
4722 out.extend(at.iter().map(|&index| values.get(index).copied().unwrap_or($zero)));
4723 Data::$variant(Buffer::from_vec(out))
4724 })+
4725 // The one layout where a gather is a copy of bytes rather than a copy of fixed
4726 // width slots, and the reason compaction is a decision rather than a default on a
4727 // string column. A payload that is a page is the exception: the gathered views
4728 // point at the page the column already points at, so the gather is sixteen bytes a
4729 // row and the bytes stay where the page put them.
4730 Data::Varlen(values) => {
4731 if let Some(shared) = values.viewing(at.iter().copied()) {
4732 return Data::Varlen(shared);
4733 }
4734 let mut out = StringColumn::with_capacity(at.len());
4735 // The bytes are known before any of them are copied, because a view carries its
4736 // length and the wanted positions are already in hand, so the arena is one
4737 // allocation rather than a run of doublings that each copy what the last one
4738 // copied.
4739 let views = values.views();
4740 out.reserve_bytes(
4741 at.iter()
4742 .filter_map(|&index| views.get(index))
4743 .filter(|view| !view.is_inline())
4744 .map(StringView::len)
4745 .sum(),
4746 );
4747 for &index in at {
4748 out.push_from(values, index);
4749 }
4750 Data::Varlen(out)
4751 }
4752 }
4753 };
4754 }
4755 crate::for_each_layout!(fixed, copied)
4756}
4757
4758/// The physical layout a run of data is in, for the check that it matches its type.
4759///
4760/// The two enums name their variants the same way on purpose, so this is one generated arm rather
4761/// than sixteen chances to pair the wrong two up.
4762pub(crate) fn layout_of(data: &Data) -> rudb_common::PhysicalType {
4763 use rudb_common::PhysicalType as P;
4764 macro_rules! layouts {
4765 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4766 match data {
4767 Data::Empty => P::Empty,
4768 $(Data::$variant(_) => P::$variant,)+
4769 }
4770 };
4771 }
4772 crate::for_each_layout!(all, layouts)
4773}
4774
4775/// One value out of a run of data, given what the run means.
4776///
4777/// The match is on the logical type rather than on the data, because the data cannot tell a `DATE`
4778/// from an `INTEGER` and that is the whole reason the two are kept apart.
4779fn value_from(ty: &LogicalType, data: &Data, index: usize) -> Value {
4780 let signed = || data.signed_at(index);
4781 let unsigned = || data.unsigned_at(index);
4782 let value = match ty {
4783 LogicalType::Boolean => match data {
4784 Data::Bool(v) => v.get(index).map(|&x| Value::Boolean(x)),
4785 _ => None,
4786 },
4787 LogicalType::TinyInt => signed().and_then(|x| i8::try_from(x).ok()).map(Value::TinyInt),
4788 LogicalType::SmallInt => signed().and_then(|x| i16::try_from(x).ok()).map(Value::SmallInt),
4789 LogicalType::Integer => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Integer),
4790 LogicalType::BigInt => signed().and_then(|x| i64::try_from(x).ok()).map(Value::BigInt),
4791 LogicalType::HugeInt => signed().map(Value::HugeInt),
4792 LogicalType::UTinyInt => unsigned().and_then(|x| u8::try_from(x).ok()).map(Value::UTinyInt),
4793 LogicalType::USmallInt => {
4794 unsigned().and_then(|x| u16::try_from(x).ok()).map(Value::USmallInt)
4795 }
4796 LogicalType::UInteger => {
4797 unsigned().and_then(|x| u32::try_from(x).ok()).map(Value::UInteger)
4798 }
4799 LogicalType::UBigInt => unsigned().and_then(|x| u64::try_from(x).ok()).map(Value::UBigInt),
4800 LogicalType::UHugeInt => unsigned().map(Value::UHugeInt),
4801 LogicalType::Float => match data {
4802 Data::Float32(v) => v.get(index).map(|&x| Value::Float(x)),
4803 _ => None,
4804 },
4805 LogicalType::Double => match data {
4806 Data::Float64(v) => v.get(index).map(|&x| Value::Double(x)),
4807 _ => None,
4808 },
4809 LogicalType::Decimal { width, scale } => {
4810 signed().map(|unscaled| Value::Decimal { unscaled, width: *width, scale: *scale })
4811 }
4812 LogicalType::Varchar | LogicalType::Blob | LogicalType::Bit => {
4813 data.bytes_at(index).map(|bytes| bytes_as(ty, bytes))
4814 }
4815 LogicalType::Enum(labels) => unsigned()
4816 .and_then(|code| labels.get(usize::try_from(code).ok()?))
4817 .map(|label| Value::Varchar(label.clone())),
4818 LogicalType::Date => signed().and_then(|x| i32::try_from(x).ok()).map(Value::Date),
4819 LogicalType::Time => signed().and_then(|x| i64::try_from(x).ok()).map(Value::Time),
4820 LogicalType::TimeTz => signed().and_then(|x| i64::try_from(x).ok()).map(Value::TimeTz),
4821 LogicalType::Timestamp
4822 | LogicalType::TimestampS
4823 | LogicalType::TimestampMs
4824 | LogicalType::TimestampNs => {
4825 signed().and_then(|x| i64::try_from(x).ok()).map(Value::Timestamp)
4826 }
4827 LogicalType::TimestampTz => {
4828 signed().and_then(|x| i64::try_from(x).ok()).map(Value::TimestampTz)
4829 }
4830 LogicalType::Interval => match data {
4831 Data::Interval(v) => {
4832 v.get(index).map(|&(months, days, micros)| Value::Interval { months, days, micros })
4833 }
4834 _ => None,
4835 },
4836 _ => None,
4837 };
4838 value.unwrap_or(Value::Null)
4839}
4840
4841/// The fields a struct type names, and nothing for any other type.
4842///
4843/// Only a `STRUCT` vector has a [`Body::Fields`] body, and the two are built together, so in practice
4844/// the empty slice is unreachable and is here so that reading a field name is not a panic if that ever
4845/// stops being true. A struct vector whose type has fewer fields than it has children answers about
4846/// the fields it can name, because the zip stops at the shorter of the two.
4847fn fields_of(ty: &LogicalType) -> &[Field] {
4848 match ty {
4849 LogicalType::Struct(fields) => fields,
4850 _ => &[],
4851 }
4852}
4853
4854/// One row of a string column as a value, given what its bytes are meant to be read as.
4855///
4856/// Both forms that hold strings come through here, so a row that is a `BLOB` in a flat column is a
4857/// `BLOB` in a string view column too. Bytes that are not text in a `VARCHAR` column are a null
4858/// rather than a panic, since everything that got in went in as a string and a column that has
4859/// something else in it is a bug somewhere earlier that a read should not turn into a crash.
4860fn bytes_as(ty: &LogicalType, bytes: &[u8]) -> Value {
4861 match ty {
4862 LogicalType::Varchar => {
4863 std::str::from_utf8(bytes).map_or(Value::Null, |text| Value::Varchar(text.to_owned()))
4864 }
4865 LogicalType::Blob | LogicalType::Bit => Value::Blob(bytes.to_vec()),
4866 _ => Value::Null,
4867 }
4868}
4869
4870/// An empty run of data of the right layout for a type.
4871pub(crate) fn empty_data_for(ty: &LogicalType) -> Result<Data> {
4872 use rudb_common::PhysicalType as P;
4873 macro_rules! empties {
4874 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4875 match ty.physical() {
4876 P::Empty => Data::Empty,
4877 $(P::$variant => Data::$variant(Buffer::new()),)+
4878 P::Varlen => Data::Varlen(StringColumn::new()),
4879 other => {
4880 return Err(Error::not_implemented(format!(
4881 "a flat vector of {other:?} data, which arrives with the storage layer"
4882 )));
4883 }
4884 }
4885 };
4886 }
4887 Ok(crate::for_each_layout!(fixed, empties))
4888}
4889
4890/// An empty run of the type's layout with room for `rows` values already taken.
4891///
4892/// For a caller that knows how many values are going in before the first one does, which is a
4893/// producer laying pieces end to end. Growing from empty instead reallocates once per doubling and
4894/// finishes holding a run rounded up to the next power of two, and on a row group of 122,880 values
4895/// that rounding is the last 8,192 of them carried for the life of the table.
4896///
4897/// Bytes are not reserved for a varlen run, because how many of them there are is not the number of
4898/// rows and the caller appending them is the one that can work it out.
4899///
4900/// # Errors
4901///
4902/// If the type has no flat layout, the same as [`empty_data_for`].
4903pub(crate) fn data_for(ty: &LogicalType, rows: usize) -> Result<Data> {
4904 let mut data = empty_data_for(ty)?;
4905 macro_rules! reserved {
4906 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
4907 match &mut data {
4908 Data::Empty => {}
4909 $(Data::$variant(values) => values.reserve(rows),)+
4910 Data::Varlen(values) => values.reserve_views(rows),
4911 }
4912 };
4913 }
4914 crate::for_each_layout!(fixed, reserved);
4915 Ok(data)
4916}
4917
4918/// A value the way a run of this type holds it.
4919///
4920/// Only an `ENUM` holds something other than the value itself. A value of one is its string,
4921/// which is what a result reads out and what a test asserts on, and the run holds the position of
4922/// the string in the list instead. Everything else comes back as it went in.
4923fn stored<'v>(ty: &LogicalType, value: &'v Value) -> Result<Cow<'v, Value>> {
4924 match (ty, value) {
4925 (LogicalType::Enum(_), Value::Varchar(_)) => enum_position(ty, value).map(Cow::Owned),
4926 _ => Ok(Cow::Borrowed(value)),
4927 }
4928}
4929
4930/// Where a value of an `ENUM` sits in its list, as the unsigned integer a run of the type holds,
4931/// with a null staying null.
4932///
4933/// # Errors
4934///
4935/// If the type is not an `ENUM` or the value is not one of its strings.
4936pub fn enum_position(ty: &LogicalType, value: &Value) -> Result<Value> {
4937 let label = match (ty, value) {
4938 (_, Value::Null) => return Ok(Value::Null),
4939 (LogicalType::Enum(_), Value::Varchar(label)) => label,
4940 _ => return Err(Error::internal(format!("{value:?} is not a value of {ty}"))),
4941 };
4942 let code = ty
4943 .labels()
4944 .and_then(|labels| labels.iter().position(|one| one == label))
4945 .and_then(|code| u32::try_from(code).ok())
4946 .ok_or_else(|| Error::internal(format!("{label:?} is not a value of {ty}")))?;
4947 Ok(match enum_code_type(ty) {
4948 LogicalType::UTinyInt => Value::UTinyInt(code as u8),
4949 LogicalType::USmallInt => Value::USmallInt(code as u16),
4950 _ => Value::UInteger(code),
4951 })
4952}
4953
4954/// The unsigned integer type the positions of an `ENUM` are held in, which is what `enum_code`
4955/// answers with.
4956#[must_use]
4957pub fn enum_code_type(ty: &LogicalType) -> LogicalType {
4958 match ty.physical() {
4959 rudb_common::PhysicalType::UInt8 => LogicalType::UTinyInt,
4960 rudb_common::PhysicalType::UInt16 => LogicalType::USmallInt,
4961 _ => LogicalType::UInteger,
4962 }
4963}
4964
4965/// Appends one value to a run of data, or a zero of the right shape when it is null.
4966///
4967/// The zero matters. A null still occupies a position, the validity mask is what says it is null,
4968/// and a run of data with a hole in it would put every value after the hole in the wrong place.
4969fn push_value(data: &mut Data, value: &Value) -> Result<()> {
4970 macro_rules! push {
4971 ($vec:expr, $variant:path, $zero:expr) => {
4972 match value {
4973 Value::Null => $vec.push($zero),
4974 $variant(x) => $vec.push(*x),
4975 other => {
4976 return Err(Error::internal(format!(
4977 "{other:?} does not belong in this vector"
4978 )));
4979 }
4980 }
4981 };
4982 }
4983 // A decimal is stored as its unscaled integer in whatever width its precision needs, which
4984 // `LogicalType::physical` decides and which is why the same `Value::Decimal` is at home in four
4985 // different runs. The narrowing cannot fail for a value the binder produced, because the width
4986 // that chose the run is the width in the value, but it is checked rather than assumed because
4987 // an unchecked cast here would silently store a different number.
4988 macro_rules! decimal {
4989 ($vec:expr, $ty:ty, $unscaled:expr) => {
4990 match <$ty>::try_from(*$unscaled) {
4991 Ok(x) => $vec.push(x),
4992 Err(_) => {
4993 return Err(Error::internal(format!(
4994 "an unscaled decimal of {} does not fit the run its precision chose",
4995 $unscaled
4996 )));
4997 }
4998 }
4999 };
5000 }
5001 match data {
5002 Data::Empty => {}
5003 Data::Bool(v) => push!(v, Value::Boolean, false),
5004 Data::Int8(v) => push!(v, Value::TinyInt, 0),
5005 Data::Int16(v) => match value {
5006 Value::Null => v.push(0),
5007 Value::SmallInt(x) => v.push(*x),
5008 Value::Decimal { unscaled, .. } => decimal!(v, i16, unscaled),
5009 other => return Err(Error::internal(format!("{other:?} is not a 16 bit value"))),
5010 },
5011 Data::Int32(v) => match value {
5012 Value::Null => v.push(0),
5013 Value::Integer(x) | Value::Date(x) => v.push(*x),
5014 Value::Decimal { unscaled, .. } => decimal!(v, i32, unscaled),
5015 other => return Err(Error::internal(format!("{other:?} is not a 32 bit value"))),
5016 },
5017 Data::Int64(v) => match value {
5018 Value::Null => v.push(0),
5019 Value::BigInt(x)
5020 | Value::Time(x)
5021 | Value::TimeTz(x)
5022 | Value::Timestamp(x)
5023 | Value::TimestampTz(x) => v.push(*x),
5024 Value::Decimal { unscaled, .. } => decimal!(v, i64, unscaled),
5025 other => return Err(Error::internal(format!("{other:?} is not a 64 bit value"))),
5026 },
5027 Data::Int128(v) => match value {
5028 Value::Null => v.push(0),
5029 Value::HugeInt(x) => v.push(*x),
5030 Value::Decimal { unscaled, .. } => v.push(*unscaled),
5031 other => return Err(Error::internal(format!("{other:?} is not a 128 bit value"))),
5032 },
5033 Data::UInt8(v) => push!(v, Value::UTinyInt, 0),
5034 Data::UInt16(v) => push!(v, Value::USmallInt, 0),
5035 Data::UInt32(v) => push!(v, Value::UInteger, 0),
5036 Data::UInt64(v) => push!(v, Value::UBigInt, 0),
5037 Data::UInt128(v) => push!(v, Value::UHugeInt, 0),
5038 Data::Float32(v) => push!(v, Value::Float, 0.0),
5039 Data::Float64(v) => push!(v, Value::Double, 0.0),
5040 Data::Interval(v) => match value {
5041 Value::Null => v.push((0, 0, 0)),
5042 Value::Interval { months, days, micros } => v.push((*months, *days, *micros)),
5043 other => return Err(Error::internal(format!("{other:?} is not an interval"))),
5044 },
5045 Data::Varlen(column) => match value {
5046 Value::Null => {
5047 column.push("");
5048 }
5049 Value::Varchar(text) => {
5050 column.push(text);
5051 }
5052 // A blob goes in as the bytes it is. The column stores a length and some bytes either
5053 // way, so text is the reading of one rather than a different column, and a blob that
5054 // is not UTF-8 is stored exactly like one that happens to be.
5055 Value::Blob(bytes) => {
5056 column.push_bytes(bytes);
5057 }
5058 other => return Err(Error::internal(format!("{other:?} is not a string"))),
5059 },
5060 }
5061 Ok(())
5062}
5063
5064#[cfg(test)]
5065mod tests {
5066 use std::sync::Arc;
5067
5068 use rudb_common::{Field, LogicalType, Value};
5069
5070 use super::{
5071 Body, Data, FSST_PAYS_AT, Form, MAP_KEY, MAP_VALUE, NO_ROW, VECTOR_SIZE, Vector, below,
5072 packing_base,
5073 };
5074 use crate::buffer::Buffer;
5075 use crate::fsst::SymbolTable;
5076 use crate::string::{StringColumn, StringView};
5077 use crate::validity::Validity;
5078
5079 fn integers(values: &[i32]) -> Vector {
5080 Vector::flat(LogicalType::Integer, Data::Int32(values.to_vec().into())).unwrap()
5081 }
5082
5083 #[test]
5084 fn below_agrees_with_the_largest_code_whether_the_or_settles_it_or_not() {
5085 let cases: [(&[u32], usize); 8] = [
5086 (&[], 0),
5087 (&[], 5),
5088 (&[0, 1, 8191], 8192),
5089 (&[0, 8192], 8192),
5090 // The `or` of 4 and 1 is 5, which is not below 5, so these take the maximum.
5091 (&[4, 1], 5),
5092 (&[4, 5], 5),
5093 (&[3, 4, 2], 5),
5094 (&[7], 7),
5095 ];
5096 for (codes, len) in cases {
5097 let expected = codes.iter().all(|&code| (code as usize) < len);
5098 assert_eq!(below(codes, len), expected, "{codes:?} below {len}");
5099 }
5100 }
5101
5102 #[test]
5103 fn flattening_a_dictionary_by_its_codes_matches_the_general_copy() {
5104 let words = Vector::from_values(
5105 LogicalType::Varchar,
5106 &["alpha", "a string past the inline length", ""]
5107 .map(|text| Value::Varchar(text.into())),
5108 )
5109 .unwrap();
5110 let codes = vec![2, 0, 1, 1, 0, 2, 1];
5111 let cases = [
5112 Vector::dictionary(codes.clone(), integers(&[7, -3, 40])).unwrap(),
5113 Vector::dictionary(codes.clone(), words.clone()).unwrap(),
5114 Vector::dictionary(codes.clone(), words.clone()).unwrap().slice(2, 4).unwrap(),
5115 // The ones the codes cannot answer alone, which take the general copy.
5116 Vector::dictionary(codes.clone(), words.clone())
5117 .unwrap()
5118 .with_validity(Validity::from_run(&[true, false, true, true, true, true, false])),
5119 Vector::dictionary(
5120 vec![0, 1, 1],
5121 integers(&[1, 2]).with_validity(Validity::from_run(&[true, false])),
5122 )
5123 .unwrap(),
5124 ];
5125 for (case, vector) in cases.iter().enumerate() {
5126 let flat = vector.flatten().unwrap();
5127 let general = vector.copied((0..vector.len()).collect(), false).unwrap();
5128 assert!(matches!(flat.body, Body::Flat(_)), "case {case}");
5129 assert_eq!(flat.validity, general.validity, "case {case}");
5130 for row in 0..vector.len() {
5131 assert_eq!(flat.value_at(row), general.value_at(row), "case {case} row {row}");
5132 }
5133 assert_eq!(flat, vector.opened().unwrap(), "case {case}");
5134 }
5135 }
5136
5137 #[test]
5138 fn extent_keeps_the_unsigned_order_across_the_sign_bit() {
5139 assert_eq!(super::extent(&[]), None);
5140 assert_eq!(super::extent(&[7]), Some((7, 7)));
5141 let rows = [0x8000_0000, 3, u32::MAX, 0x7fff_ffff, 9];
5142 assert_eq!(super::extent(&rows), Some((3, u32::MAX)));
5143 }
5144
5145 #[test]
5146 fn unpacking_in_bulk_reads_what_a_code_at_a_time_reads_at_every_width() {
5147 let mut state = 0x5eed_0b17_u64;
5148 let mut next = || {
5149 state ^= state << 13;
5150 state ^= state >> 7;
5151 state ^= state << 17;
5152 state
5153 };
5154 let words: Vec<u64> = (0..700).map(|_| next()).collect();
5155 for width in 1..=super::PACKED_WIDTH_MAX {
5156 for offset in [0, 1, 63, 64, 65] {
5157 let packed = super::Packed { words: &words, width, base: 0, offset };
5158 for (from, rows) in [(0, 0), (0, 1), (0, 64), (3, 200), (61, 130), (128, 512)] {
5159 let mut out = vec![u64::MAX; rows];
5160 packed.unpack(from, &mut out);
5161 let want: Vec<u64> = (from..from + rows).map(|row| packed.code(row)).collect();
5162 assert_eq!(out, want, "width {width} offset {offset} from {from}");
5163 // The mapped unpack reads the same codes in one pass, and appends, so a vector
5164 // with something in it already keeps it and the rows land after.
5165 let mut mapped = vec![-1_i64];
5166 packed.unpack_mapped(from, rows, &mut mapped, |code| 7 - code as i64);
5167 let wanted: Vec<i64> = std::iter::once(-1)
5168 .chain(want.iter().map(|&code| 7 - code as i64))
5169 .collect();
5170 assert_eq!(mapped, wanted, "mapped width {width} offset {offset} from {from}");
5171 }
5172 let at = [5_usize, 9, 9, 70, 6, 200, 131];
5173 let want: Vec<u64> = at.iter().map(|&row| packed.code(row)).collect();
5174 assert_eq!(packed.codes_at(|index| at[index], at.len()), want);
5175 let far = [0_usize, 5000];
5176 let want: Vec<u64> = far.iter().map(|&row| packed.code(row)).collect();
5177 assert_eq!(packed.codes_at(|index| far[index], far.len()), want);
5178 // A run, which is the shape unpacked straight into the answer, and two shapes that
5179 // cover the same rows and are not one: reversed and with a row repeated. All three
5180 // have to answer what a code at a time answers, whichever path they take.
5181 for start in [0_usize, 1, 63, 64, 65, 130] {
5182 for rows in [1_usize, 2, 63, 64, 65, 200] {
5183 let run: Vec<usize> = (start..start + rows).collect();
5184 let back: Vec<usize> = run.iter().rev().copied().collect();
5185 let mut same = run.clone();
5186 same[rows - 1] = start;
5187 for shape in [&run, &back, &same] {
5188 let want: Vec<u64> =
5189 shape.iter().map(|&row| packed.code(row)).collect();
5190 assert_eq!(
5191 packed.codes_at(|index| shape[index], shape.len()),
5192 want,
5193 "width {width} offset {offset} start {start} rows {rows}"
5194 );
5195 }
5196 }
5197 }
5198 // The same shapes into a buffer the caller keeps, filled with a code no width can
5199 // hold first, so that a row left as it arrived is a wrong answer rather than a zero
5200 // that happens to be right. A buffer wider than the rows asked for keeps the rest.
5201 let mut held = vec![u64::MAX; 260];
5202 for start in [0_usize, 1, 64, 130] {
5203 for rows in [1_usize, 63, 64, 200] {
5204 let run: Vec<usize> = (start..start + rows).collect();
5205 let back: Vec<usize> = run.iter().rev().copied().collect();
5206 for shape in [&run, &back] {
5207 held.iter_mut().for_each(|code| *code = u64::MAX);
5208 packed.codes_into(|index| shape[index], shape.len(), &mut held);
5209 let want: Vec<u64> =
5210 shape.iter().map(|&row| packed.code(row)).collect();
5211 assert_eq!(
5212 &held[..rows],
5213 &want[..],
5214 "width {width} offset {offset} start {start} rows {rows}"
5215 );
5216 assert!(
5217 held[rows..].iter().all(|&code| code == u64::MAX),
5218 "width {width} wrote past the {rows} rows it was asked for"
5219 );
5220 }
5221 }
5222 }
5223 for rows in [&[][..], &[5, 9, 9, 70, 6, 200, 131], &[0, 5000], &[3, 4, 5, 6]] {
5224 let want: Vec<u64> =
5225 rows.iter().map(|&row| packed.code(row as usize)).collect();
5226 assert_eq!(packed.values_at(rows, |code| code), want, "width {width}");
5227 }
5228 }
5229 }
5230 }
5231
5232 /// A `Value::List` of integers, which is what a row of a list column arrives as.
5233 fn list(values: &[i32]) -> Value {
5234 Value::List {
5235 element: LogicalType::Integer,
5236 values: values.iter().map(|&v| Value::Integer(v)).collect(),
5237 }
5238 }
5239
5240 fn list_column(rows: &[Value]) -> Vector {
5241 Vector::from_values(LogicalType::list(LogicalType::Integer), rows).unwrap()
5242 }
5243
5244 #[test]
5245 fn a_list_column_is_one_child_and_a_range_per_row() {
5246 let rows = vec![list(&[1, 2, 3]), list(&[]), Value::Null, list(&[4])];
5247 let column = list_column(&rows);
5248 assert_eq!(column.form(), Form::List);
5249 assert_eq!(column.len(), 4);
5250 assert_eq!(column.logical_type(), &LogicalType::list(LogicalType::Integer));
5251 // Four rows and four elements, because a null and an empty list both contribute none.
5252 let (entries, child) = column.list_parts().expect("a list");
5253 assert_eq!(entries, [(0, 3), (3, 0), (3, 0), (3, 1)]);
5254 assert_eq!(child.len(), 4);
5255 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
5256 }
5257
5258 /// The one thing the entries cannot say on their own, so it has to be checked that the mask says
5259 /// it. An empty list is a row that is there and holds nothing, a null is a row that is not there,
5260 /// and both of them have an entry of length zero.
5261 #[test]
5262 fn an_empty_list_and_a_null_list_have_the_same_entry_and_are_different_rows() {
5263 let column = list_column(&[list(&[]), Value::Null]);
5264 let (entries, _) = column.list_parts().expect("a list");
5265 assert_eq!(entries[0].1, entries[1].1, "both entries are empty");
5266 assert!(!column.is_null_at(0), "an empty list is not null");
5267 assert!(column.is_null_at(1), "a null list is null");
5268 assert_eq!(column.value_at(0), list(&[]));
5269 assert_eq!(column.value_at(1), Value::Null);
5270 }
5271
5272 #[test]
5273 fn slicing_a_list_column_shares_the_child_rather_than_copying_it() {
5274 let rows: Vec<Value> = (0..64).map(|row| list(&[row, row + 1, row + 2])).collect();
5275 let column = list_column(&rows);
5276 let cut = column.slice(8, 4).unwrap();
5277 assert_eq!(cut.form(), Form::List);
5278 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[8..12]);
5279 // The entries are absolute positions in a child that was not cut, which is what makes the
5280 // cut eight bytes a row however long the lists are. The elements outside the range are still
5281 // there and nothing points at them.
5282 let (entries, child) = cut.list_parts().expect("a list");
5283 assert_eq!(entries[0], (24, 3));
5284 assert_eq!(child.len(), 192);
5285 }
5286
5287 #[test]
5288 fn gathering_a_list_column_permutes_the_entries_and_leaves_the_child_alone() {
5289 let rows = vec![list(&[1]), list(&[2, 2]), list(&[3, 3, 3])];
5290 let column = list_column(&rows);
5291 let picked = column.gather(&[2, 0, 2]).unwrap();
5292 assert_eq!(
5293 picked.iter().collect::<Vec<_>>(),
5294 [list(&[3, 3, 3]), list(&[1]), list(&[3, 3, 3])]
5295 );
5296 // Two of the three rows are the same row, which is the case a run of offsets cannot write
5297 // down and a start and a length can. That is the whole reason this form carries both.
5298 assert_eq!(picked.list_parts().expect("a list").1.len(), 6);
5299 }
5300
5301 #[test]
5302 fn a_gather_past_the_end_of_a_list_column_is_null_rather_than_somebody_elses_elements() {
5303 let column = list_column(&[list(&[1, 2]), list(&[3])]);
5304 let picked = column.gather(&[1, 9]).unwrap();
5305 assert_eq!(picked.value_at(0), list(&[3]));
5306 assert_eq!(picked.value_at(1), Value::Null);
5307 }
5308
5309 #[test]
5310 fn a_list_of_lists_nests_as_far_as_it_is_written() {
5311 let outer = Value::List {
5312 element: LogicalType::list(LogicalType::Integer),
5313 values: vec![list(&[1, 2]), list(&[3])],
5314 };
5315 let column = Vector::from_values(
5316 LogicalType::list(LogicalType::list(LogicalType::Integer)),
5317 std::slice::from_ref(&outer),
5318 )
5319 .unwrap();
5320 assert_eq!(column.value_at(0), outer);
5321 assert_eq!(column.list_parts().expect("a list").1.form(), Form::List);
5322 }
5323
5324 /// A list row is not bytes and not an integer, and a caller that asks for either gets nothing
5325 /// rather than the first element or a length. Both of those would be a wrong answer that a
5326 /// group by or a hash would read without complaining.
5327 #[test]
5328 fn the_scalar_readers_decline_a_list_instead_of_answering_about_its_elements() {
5329 let column = list_column(&[list(&[7])]);
5330 assert_eq!(column.signed_at(0), None);
5331 assert_eq!(column.bytes_at(0), None);
5332 assert_eq!(column.data(), None);
5333 }
5334
5335 fn pair(a: i32, b: &str) -> Value {
5336 Value::Struct(vec![
5337 ("a".to_string(), Value::Integer(a)),
5338 ("b".to_string(), Value::Varchar(b.to_string())),
5339 ])
5340 }
5341
5342 fn pair_type() -> LogicalType {
5343 LogicalType::Struct(vec![
5344 Field::new("a", LogicalType::Integer),
5345 Field::new("b", LogicalType::Varchar),
5346 ])
5347 }
5348
5349 fn pair_column(rows: &[Value]) -> Vector {
5350 Vector::from_values(pair_type(), rows).unwrap()
5351 }
5352
5353 #[test]
5354 fn a_struct_column_is_one_child_per_field_as_long_as_the_column() {
5355 let rows = vec![pair(1, "x"), pair(2, "y"), pair(3, "z")];
5356 let column = pair_column(&rows);
5357 assert_eq!(column.form(), Form::Struct);
5358 assert_eq!(column.len(), 3);
5359 assert_eq!(column.logical_type(), &pair_type());
5360 // Two children rather than two entries and a child, and both of them as long as the column,
5361 // which is the whole difference between this form and the list one.
5362 let children = column.struct_parts().expect("a struct");
5363 assert_eq!(children.len(), 2);
5364 assert_eq!(children[0].len(), 3);
5365 assert_eq!(children[1].len(), 3);
5366 assert_eq!(children[0].logical_type(), &LogicalType::Integer);
5367 assert_eq!(children[1].logical_type(), &LogicalType::Varchar);
5368 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
5369 }
5370
5371 /// Picking one field out of a struct is picking one child, which is the reason this accessor is
5372 /// public. A projection of `s.a` hands back a vector that already exists, so it costs a pointer
5373 /// rather than a pass over the rows, and that is only true while the children are full length.
5374 #[test]
5375 fn one_field_of_a_struct_column_is_a_column_that_is_already_there() {
5376 let column = pair_column(&[pair(10, "x"), pair(20, "y")]);
5377 let field = &column.struct_parts().expect("a struct")[0];
5378 assert_eq!(field.iter().collect::<Vec<_>>(), [Value::Integer(10), Value::Integer(20)]);
5379 assert_eq!(field.signed_at(1), Some(20), "the field is a scalar column and reads like one");
5380 }
5381
5382 /// A null struct is a bit in the mask at the top and nothing deeper, which is how every other type
5383 /// records a null and is what DuckDB does. The row reads as a single null rather than as a struct of
5384 /// nulls, and the fields underneath are still their own columns.
5385 #[test]
5386 fn a_null_struct_is_the_mask_at_the_top_and_not_a_struct_full_of_nulls() {
5387 let column = pair_column(&[pair(1, "x"), Value::Null]);
5388 assert!(!column.is_null_at(0));
5389 assert!(column.is_null_at(1));
5390 assert_eq!(column.value_at(1), Value::Null);
5391 // A struct row whose every field happens to be null is a different row, and it is not null.
5392 let all_null = pair_column(&[Value::Struct(vec![
5393 ("a".to_string(), Value::Null),
5394 ("b".to_string(), Value::Null),
5395 ])]);
5396 assert!(!all_null.is_null_at(0), "a struct of nulls is a row that is there");
5397 assert_ne!(all_null.value_at(0), Value::Null);
5398 }
5399
5400 #[test]
5401 fn slicing_a_struct_column_cuts_every_field_at_the_same_place() {
5402 let rows: Vec<Value> = (0..64).map(|row| pair(row, "s")).collect();
5403 let column = pair_column(&rows);
5404 let cut = column.slice(8, 4).unwrap();
5405 assert_eq!(cut.form(), Form::Struct);
5406 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[8..12]);
5407 // The cut a list column does not have to do. A list shares its child untouched because the
5408 // entries carry the range, and a struct has no entry standing between the row and the child,
5409 // so every child is four rows long here rather than sixty four.
5410 for child in cut.struct_parts().expect("a struct") {
5411 assert_eq!(child.len(), 4);
5412 }
5413 }
5414
5415 #[test]
5416 fn gathering_a_struct_column_gathers_every_field_at_the_same_positions() {
5417 let column = pair_column(&[pair(1, "x"), pair(2, "y"), pair(3, "z")]);
5418 let picked = column.gather(&[2, 0, 2]).unwrap();
5419 assert_eq!(picked.iter().collect::<Vec<_>>(), [pair(3, "z"), pair(1, "x"), pair(3, "z")]);
5420 for child in picked.struct_parts().expect("a struct") {
5421 assert_eq!(child.len(), 3, "a field is as long as the gather, not as the source");
5422 }
5423 }
5424
5425 #[test]
5426 fn a_gather_past_the_end_of_a_struct_column_is_null_in_every_field_and_at_the_top() {
5427 let column = pair_column(&[pair(1, "x"), pair(2, "y")]);
5428 let picked = column.gather(&[1, 9]).unwrap();
5429 assert_eq!(picked.value_at(0), pair(2, "y"));
5430 assert_eq!(picked.value_at(1), Value::Null);
5431 for child in picked.struct_parts().expect("a struct") {
5432 assert!(child.is_null_at(1), "a row that came from nowhere has no field value either");
5433 }
5434 }
5435
5436 /// The names are matched and not counted, because a caller holding a struct value built in a
5437 /// different order from the type's would otherwise get its columns transposed, and that is a wrong
5438 /// answer that reads as a right one.
5439 #[test]
5440 fn the_fields_of_a_struct_value_go_in_by_name_rather_than_by_position() {
5441 let swapped = Value::Struct(vec![
5442 ("b".to_string(), Value::Varchar("x".to_string())),
5443 ("a".to_string(), Value::Integer(1)),
5444 ]);
5445 let column = pair_column(&[swapped]);
5446 assert_eq!(column.value_at(0), pair(1, "x"));
5447 let wrong = Value::Struct(vec![
5448 ("a".to_string(), Value::Integer(1)),
5449 ("c".to_string(), Value::Varchar("x".to_string())),
5450 ]);
5451 let failed = Vector::from_values(pair_type(), &[wrong]);
5452 assert!(failed.is_err(), "a row with no b field is an error rather than a null b");
5453 }
5454
5455 #[test]
5456 fn a_struct_built_from_children_takes_its_field_names_from_the_caller() {
5457 let column = Vector::structure(vec![
5458 ("a".to_string(), integers(&[1, 2, 3])),
5459 ("b".to_string(), integers(&[4, 5, 6])),
5460 ])
5461 .expect("two columns of three");
5462 assert_eq!(column.len(), 3);
5463 assert_eq!(
5464 column.logical_type(),
5465 &LogicalType::Struct(vec![
5466 Field::new("a", LogicalType::Integer),
5467 Field::new("b", LogicalType::Integer),
5468 ])
5469 );
5470 assert_eq!(
5471 column.value_at(1),
5472 Value::Struct(vec![
5473 ("a".to_string(), Value::Integer(2)),
5474 ("b".to_string(), Value::Integer(5)),
5475 ])
5476 );
5477 }
5478
5479 /// The two mistakes this constructor makes easy, both refused rather than stored. A short field is
5480 /// the one that matters: it would be a struct that reads past the end of one of its own children,
5481 /// which is the same mistake `Vector::list` checks for at the other end.
5482 #[test]
5483 fn a_struct_of_uneven_children_or_of_no_children_is_refused() {
5484 let uneven = Vector::structure(vec![
5485 ("a".to_string(), integers(&[1, 2, 3])),
5486 ("b".to_string(), integers(&[4, 5])),
5487 ]);
5488 assert!(uneven.is_err(), "a field shorter than the struct");
5489 assert!(Vector::structure(vec![]).is_err(), "no field to take a length from");
5490 }
5491
5492 #[test]
5493 fn a_struct_of_lists_and_a_list_of_structs_both_nest() {
5494 let ty =
5495 LogicalType::Struct(vec![Field::new("a", LogicalType::list(LogicalType::Integer))]);
5496 let row = Value::Struct(vec![("a".to_string(), list(&[1, 2]))]);
5497 let column = Vector::from_values(ty, std::slice::from_ref(&row)).unwrap();
5498 assert_eq!(column.value_at(0), row);
5499 assert_eq!(column.struct_parts().expect("a struct")[0].form(), Form::List);
5500
5501 let outer = Value::List { element: pair_type(), values: vec![pair(1, "x"), pair(2, "y")] };
5502 let lists =
5503 Vector::from_values(LogicalType::list(pair_type()), std::slice::from_ref(&outer))
5504 .unwrap();
5505 assert_eq!(lists.value_at(0), outer);
5506 assert_eq!(lists.list_parts().expect("a list").1.form(), Form::Struct);
5507 }
5508
5509 fn tags(pairs: &[(&str, &str)]) -> Value {
5510 Value::map(
5511 LogicalType::Varchar,
5512 LogicalType::Varchar,
5513 pairs
5514 .iter()
5515 .map(|&(key, value)| {
5516 (Value::Varchar(key.to_string()), Value::Varchar(value.to_string()))
5517 })
5518 .collect(),
5519 )
5520 }
5521
5522 fn tag_column(rows: &[Value]) -> Vector {
5523 Vector::from_values(LogicalType::map(LogicalType::Varchar, LogicalType::Varchar), rows)
5524 .unwrap()
5525 }
5526
5527 /// A map is a list of two field structs, which is the whole design, so the test that says so is
5528 /// the one that reaches through both layers and finds the pieces where each of them puts them.
5529 #[test]
5530 fn a_map_column_is_a_list_whose_child_is_a_struct_of_keys_and_values() {
5531 let rows =
5532 vec![tags(&[("a", "b"), ("c", "d")]), tags(&[]), Value::Null, tags(&[("e", "f")])];
5533 let column = tag_column(&rows);
5534 assert_eq!(column.len(), 4);
5535 assert_eq!(
5536 column.logical_type(),
5537 &LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
5538 );
5539 // The physical form is a list's, because the bytes are a list's. The logical type is what
5540 // remembers it is a map, which is the same split `LogicalType::physical` already makes.
5541 assert_eq!(column.form(), Form::List);
5542 let (entries, child) = column.list_parts().expect("the layout of a list");
5543 assert_eq!(entries, [(0, 2), (2, 0), (2, 0), (2, 1)]);
5544 assert_eq!(child.form(), Form::Struct);
5545 assert_eq!(
5546 child.logical_type(),
5547 &LogicalType::Struct(vec![
5548 Field::new(MAP_KEY, LogicalType::Varchar),
5549 Field::new(MAP_VALUE, LogicalType::Varchar),
5550 ])
5551 );
5552 // And the accessor that reaches through it hands back the two columns rather than the struct.
5553 let (entries, keys, values) = column.map_parts().expect("a map");
5554 assert_eq!(entries.len(), 4);
5555 assert_eq!(keys.text_at(0), Some("a"));
5556 assert_eq!(values.text_at(0), Some("b"));
5557 assert_eq!(column.iter().collect::<Vec<_>>(), rows);
5558 }
5559
5560 /// The same distinction a list has, checked again here rather than assumed from the composition,
5561 /// because the empty map is the one every catalog table in D2 is full of and a null map is what a
5562 /// column with no tags at all would be.
5563 #[test]
5564 fn an_empty_map_and_a_null_map_are_different_rows() {
5565 let column = tag_column(&[tags(&[]), Value::Null]);
5566 assert!(!column.is_null_at(0), "an empty map is a row that is there");
5567 assert!(column.is_null_at(1));
5568 assert_eq!(column.value_at(0), tags(&[]));
5569 assert_eq!(column.value_at(1), Value::Null);
5570 assert_eq!(column.value_at(0).to_string(), "{}");
5571 assert_eq!(column.value_at(1).to_string(), "NULL");
5572 }
5573
5574 /// A map prints `{a=b}` and a struct prints `{'a': b}`, both measured off the pin. They share a
5575 /// layout and they cannot share a printer, which is the one thing about this composition that does
5576 /// not fall out of it.
5577 #[test]
5578 fn a_map_prints_with_equals_signs_and_a_struct_prints_with_quoted_names() {
5579 assert_eq!(tags(&[("a", "b"), ("c", "d")]).to_string(), "{a=b, c=d}");
5580 assert_eq!(pair(1, "x").to_string(), "{'a': 1, 'b': x}");
5581 let numbers = Value::map(
5582 LogicalType::Integer,
5583 LogicalType::Integer,
5584 vec![(Value::Integer(1), Value::Integer(3)), (Value::Integer(2), Value::Integer(4))],
5585 );
5586 assert_eq!(numbers.to_string(), "{1=3, 2=4}");
5587 let null_value = Value::map(
5588 LogicalType::Varchar,
5589 LogicalType::Varchar,
5590 vec![(Value::Varchar("x".to_string()), Value::Null)],
5591 );
5592 assert_eq!(null_value.to_string(), "{x=NULL}");
5593 }
5594
5595 /// A map inherits the list's cut and the list's gather, which is the payoff for storing it as one.
5596 /// Neither of these is code written for maps and both of them are worth a test that says the
5597 /// inheritance works, since the type is rewritten on the way through and a form that came back as a
5598 /// list would still read.
5599 #[test]
5600 fn cutting_and_gathering_a_map_keeps_it_a_map() {
5601 let rows: Vec<Value> =
5602 (0..16).map(|row| tags(&[("k", if row % 2 == 0 { "e" } else { "o" })])).collect();
5603 let column = tag_column(&rows);
5604
5605 let cut = column.slice(4, 3).unwrap();
5606 assert!(matches!(cut.logical_type(), LogicalType::Map(_, _)), "still a map after a cut");
5607 assert_eq!(cut.iter().collect::<Vec<_>>(), rows[4..7]);
5608 // The child was not cut, the same as for a list, which is what makes the cut eight bytes a row.
5609 assert_eq!(cut.map_parts().expect("a map").1.len(), 16);
5610
5611 let picked = column.gather(&[3, 0, 3]).unwrap();
5612 assert!(matches!(picked.logical_type(), LogicalType::Map(_, _)));
5613 assert_eq!(
5614 picked.iter().collect::<Vec<_>>(),
5615 [rows[3].clone(), rows[0].clone(), rows[3].clone()]
5616 );
5617 let past = column.gather(&[0, 99]).unwrap();
5618 assert_eq!(past.value_at(1), Value::Null);
5619 }
5620
5621 #[test]
5622 fn a_map_built_from_two_columns_pairs_them_by_position() {
5623 let keys = Vector::from_values(
5624 LogicalType::Varchar,
5625 &[Value::Varchar("a".to_string()), Value::Varchar("c".to_string())],
5626 )
5627 .unwrap();
5628 let values = Vector::from_values(
5629 LogicalType::Varchar,
5630 &[Value::Varchar("b".to_string()), Value::Varchar("d".to_string())],
5631 )
5632 .unwrap();
5633 let column = Vector::map(vec![(0, 2), (2, 0)], keys, values).expect("two rows");
5634 assert_eq!(column.len(), 2);
5635 assert_eq!(
5636 column.logical_type(),
5637 &LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
5638 );
5639 assert_eq!(column.value_at(0), tags(&[("a", "b"), ("c", "d")]));
5640 assert_eq!(column.value_at(1), tags(&[]));
5641 // The entry check the list constructor does is the one a map gets, so an entry past the end of
5642 // the pair of columns is refused here too rather than read as somebody else's keys.
5643 let short =
5644 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("a".to_string())]).unwrap();
5645 let other =
5646 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("b".to_string())]).unwrap();
5647 assert!(Vector::map(vec![(0, 9)], short, other).is_err(), "an entry past the end");
5648 }
5649
5650 /// `map_parts` is about the logical type and `list_parts` is about the layout, so a list has to
5651 /// decline the first and a map has to answer the second. Getting that backwards would let a kernel
5652 /// written for maps read a list of two field structs as if it were one.
5653 #[test]
5654 fn a_list_is_not_a_map_however_much_its_child_looks_like_one() {
5655 let pairs = Value::List { element: pair_type(), values: vec![pair(1, "x")] };
5656 let column =
5657 Vector::from_values(LogicalType::list(pair_type()), std::slice::from_ref(&pairs))
5658 .unwrap();
5659 assert!(column.map_parts().is_none(), "a list of structs is a list");
5660 assert!(column.list_parts().is_some());
5661 let map = tag_column(&[tags(&[("a", "b")])]);
5662 assert!(map.map_parts().is_some());
5663 assert!(map.list_parts().is_some(), "a map has a list's layout and says so");
5664 }
5665
5666 /// A struct row is not bytes and not an integer, and it stays that way when it has exactly one
5667 /// integer field, which is the case where answering about the field would look reasonable and would
5668 /// be a hash keyed on the wrong thing.
5669 #[test]
5670 fn the_scalar_readers_decline_a_struct_of_one_integer_field() {
5671 let ty = LogicalType::Struct(vec![Field::new("a", LogicalType::Integer)]);
5672 let row = Value::Struct(vec![("a".to_string(), Value::Integer(7))]);
5673 let column = Vector::from_values(ty, &[row]).unwrap();
5674 assert_eq!(column.signed_at(0), None);
5675 assert_eq!(column.bytes_at(0), None);
5676 assert_eq!(column.data(), None);
5677 }
5678
5679 #[test]
5680 fn a_clustered_column_becomes_runs_and_reads_back_the_same() {
5681 let mut values = Vec::new();
5682 for (value, times) in [(7, 400), (8, 300), (7, 324)] {
5683 values.extend(std::iter::repeat_n(value, times));
5684 }
5685 let flat = integers(&values);
5686 let runs = flat.run_encoded().unwrap();
5687 assert_eq!(runs.form(), Form::Rle);
5688 assert_eq!(runs.run_parts().expect("runs").0, [400, 700, 1024]);
5689 assert_eq!(runs.len(), flat.len());
5690 assert_eq!(runs.iter().collect::<Vec<_>>(), flat.iter().collect::<Vec<_>>());
5691 assert!(
5692 runs.footprint() * 10 < flat.footprint(),
5693 "three runs against a thousand rows: {} against {}",
5694 runs.footprint(),
5695 flat.footprint()
5696 );
5697 }
5698
5699 /// The check is worth having in both directions. A form that is only ever bigger than what it
5700 /// replaced is a form that costs a pass over the column to decide not to use.
5701 #[test]
5702 fn a_column_that_does_not_repeat_is_left_flat() {
5703 let flat = integers(&(0..1024).collect::<Vec<i32>>());
5704 assert_eq!(flat.run_encoded().unwrap().form(), Form::Flat);
5705 // Two runs over four rows is exactly break even on a four byte column, and break even is
5706 // not a reason to change form.
5707 assert_eq!(integers(&[1, 1, 2, 2]).run_encoded().unwrap().form(), Form::Flat);
5708 assert_eq!(integers(&[1, 1, 1, 2, 2]).run_encoded().unwrap().form(), Form::Rle);
5709 }
5710
5711 #[test]
5712 fn two_nulls_beside_each_other_are_one_run_and_a_null_between_two_equals_is_a_break() {
5713 let mut values = vec![Value::Integer(4), Value::Integer(4)];
5714 values.extend([Value::Null, Value::Null, Value::Null]);
5715 values.extend(std::iter::repeat_n(Value::Integer(4), 5));
5716 let flat = Vector::from_values(LogicalType::Integer, &values).unwrap();
5717 let runs = flat.run_encoded().unwrap();
5718 assert_eq!(runs.run_parts().expect("runs").0, [2, 5, 10]);
5719 assert_eq!(runs.iter().collect::<Vec<_>>(), values);
5720 }
5721
5722 #[test]
5723 fn slicing_runs_keeps_them_runs_and_cuts_the_first_and_last_one_back() {
5724 let flat = integers(&[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]);
5725 let runs = flat.run_encoded().unwrap();
5726 let piece = runs.slice(3, 6).unwrap();
5727 assert_eq!(piece.form(), Form::Rle, "the form is the whole point");
5728 assert_eq!(piece.run_parts().expect("runs").0, [1, 5, 6]);
5729 assert_eq!(
5730 piece.iter().collect::<Vec<_>>(),
5731 flat.slice(3, 6).unwrap().iter().collect::<Vec<_>>()
5732 );
5733 assert_eq!(runs.slice(0, 0).unwrap().len(), 0);
5734 assert_eq!(runs.slice(0, 12).unwrap().form(), Form::Rle);
5735 }
5736
5737 #[test]
5738 fn gathering_out_of_runs_walks_to_the_values_the_way_it_walks_a_dictionary() {
5739 let mut values = vec![Value::Varchar("red".into()); 4];
5740 values.extend([Value::Null, Value::Null, Value::Null]);
5741 values.extend(vec![Value::Varchar("blue".into()); 4]);
5742 let runs =
5743 Vector::from_values(LogicalType::Varchar, &values).unwrap().run_encoded().unwrap();
5744 assert_eq!(runs.form(), Form::Rle);
5745 let picked = runs.gather(&[8, 0, 5, 2]).unwrap();
5746 assert_eq!(picked.form(), Form::Flat, "a gather copies, whatever it gathered from");
5747 assert_eq!(
5748 picked.iter().collect::<Vec<_>>(),
5749 [values[8].clone(), values[0].clone(), Value::Null, values[2].clone()]
5750 );
5751 assert_eq!(runs.text_at(1), Some("red"));
5752 assert_eq!(runs.text_at(5), None, "a null has no text");
5753 assert_eq!(runs.flatten().unwrap().iter().collect::<Vec<_>>(), values);
5754 }
5755
5756 /// A run length vector over a run length vector turns one search per row into two, and there is
5757 /// nothing in the engine that builds one, so it is refused rather than composed.
5758 #[test]
5759 fn runs_of_runs_are_refused_and_runs_of_a_dictionary_are_not() {
5760 let inner = integers(&[1, 1, 1, 1, 2]).run_encoded().unwrap();
5761 assert_eq!(inner.form(), Form::Rle);
5762 let error = Vector::runs(vec![2, 8], inner).unwrap_err();
5763 assert!(error.to_string().contains("runs of runs"), "{error}");
5764
5765 let words = Vector::from_values(
5766 LogicalType::Varchar,
5767 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5768 )
5769 .unwrap();
5770 let dictionary = Vector::dictionary(vec![1, 0], words).unwrap();
5771 let stacked = Vector::runs(vec![4, 9], dictionary).unwrap();
5772 assert_eq!(stacked.len(), 9);
5773 assert_eq!(stacked.value_at(3), Value::Varchar("blue".into()));
5774 assert_eq!(stacked.value_at(4), Value::Varchar("red".into()));
5775 }
5776
5777 #[test]
5778 fn run_ends_have_to_increase_and_there_is_one_value_for_each_of_them() {
5779 let values = integers(&[1, 2]);
5780 assert!(Vector::runs(vec![4], values.clone()).is_err(), "two values and one run");
5781 assert!(Vector::runs(vec![4, 4], values.clone()).is_err(), "an end that repeats");
5782 assert!(Vector::runs(vec![4, 2], values.clone()).is_err(), "an end that goes backwards");
5783 assert!(Vector::runs(vec![0, 2], values.clone()).is_err(), "a first run holding no rows");
5784 assert_eq!(Vector::runs(vec![4, 9], values).unwrap().len(), 9);
5785 }
5786
5787 #[test]
5788 fn a_form_that_is_already_compact_is_left_where_it_is() {
5789 let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1000);
5790 assert_eq!(constant.run_encoded().unwrap().form(), Form::Constant);
5791 assert_eq!(Vector::sequence(0, 1, 1000).run_encoded().unwrap().form(), Form::Sequence);
5792 }
5793
5794 /// What makes one accessor cover both forms. A dictionary hands back the codes it stores and a
5795 /// run length vector works the same numbers out, and a kernel writing `values[at[row]]` reads
5796 /// the same rows out of either.
5797 #[test]
5798 fn both_forms_that_point_somewhere_hand_back_a_position_per_row() {
5799 let words = Vector::from_values(
5800 LogicalType::Varchar,
5801 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5802 )
5803 .unwrap();
5804 let runs = Vector::runs(vec![3, 5], words.clone()).unwrap();
5805 let (at, values) = runs.positions().expect("runs point somewhere");
5806 assert_eq!(at.as_ref(), [0, 0, 0, 1, 1]);
5807 assert_eq!(values.value_at(at[3] as usize), runs.value_at(3));
5808
5809 let dictionary = Vector::dictionary(vec![1, 0, 1], words).unwrap();
5810 let (at, values) = dictionary.positions().expect("a dictionary points somewhere");
5811 assert_eq!(at.as_ref(), [1, 0, 1]);
5812 assert_eq!(values.value_at(at[0] as usize), dictionary.value_at(0));
5813
5814 assert!(integers(&[1, 2, 3]).positions().is_none(), "a flat vector points at itself");
5815 assert!(Vector::sequence(0, 1, 4).positions().is_none(), "a sequence stores nothing");
5816 }
5817
5818 #[test]
5819 fn slicing_a_dictionary_keeps_it_a_dictionary_where_gathering_would_not() {
5820 let values = Vector::from_values(
5821 LogicalType::Varchar,
5822 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5823 )
5824 .unwrap();
5825 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
5826
5827 let piece = vector.slice(1, 3).unwrap();
5828 assert_eq!(piece.form(), Form::Dictionary, "the form is the whole point");
5829 assert_eq!(piece.len(), 3);
5830 assert_eq!(
5831 piece.iter().collect::<Vec<_>>(),
5832 [
5833 Value::Varchar("blue".into()),
5834 Value::Varchar("blue".into()),
5835 Value::Varchar("red".into())
5836 ]
5837 );
5838 assert_eq!(vector.gather(&[1, 2, 3]).unwrap().form(), Form::Flat, "which a gather loses");
5839 }
5840
5841 #[test]
5842 fn slicing_a_dictionary_shares_the_dictionary_rather_than_copying_it() {
5843 // The assertion is about the address and not about the values, because the values were
5844 // right when the dictionary was copied too. A page holds one dictionary and is cut into a
5845 // chunk of codes at a time, so copying the dictionary here is a copy of every string in it
5846 // per chunk, and on a read of a ClickBench partition it was ten percent of the cycles.
5847 let values = Vector::from_values(
5848 LogicalType::Varchar,
5849 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5850 )
5851 .unwrap();
5852 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap();
5853 let Body::Dictionary { values: whole, .. } = &vector.body else {
5854 panic!("a dictionary vector holds a dictionary");
5855 };
5856
5857 let piece = vector.slice(1, 3).unwrap();
5858 let Body::Dictionary { codes, values: cut, .. } = &piece.body else {
5859 panic!("a slice of a dictionary is a dictionary");
5860 };
5861 assert!(Arc::ptr_eq(whole, cut), "the cut copied the dictionary");
5862 assert_eq!(codes.as_slice(), &[1, 1, 0], "the codes are the part that is cut");
5863
5864 // And a cut of a cut shares it too, since that is what a scan does to a page it reads twice.
5865 let again = piece.slice(1, 2).unwrap();
5866 let Body::Dictionary { values: cut, .. } = &again.body else {
5867 panic!("a slice of a slice of a dictionary is a dictionary");
5868 };
5869 assert!(Arc::ptr_eq(whole, cut), "the second cut copied the dictionary");
5870 assert_eq!(
5871 again.iter().collect::<Vec<_>>(),
5872 [Value::Varchar("blue".into()), Value::Varchar("red".into())]
5873 );
5874 }
5875
5876 /// A parent column read for a link join, and the copy per chunk that not paging it was.
5877 ///
5878 /// The path is the one a kernel takes. A link join emits [`Body::Gathered`] over the parent and
5879 /// reads nothing, and the kernel that first wants the values flattens it, which is where the
5880 /// arena is either taken by handle or copied out of. The arena was already behind an `Arc`
5881 /// before this and every flatten still copied every byte it reached, because the question
5882 /// [`Buffer::is_shared`] answers is about the store inside the `Arc` rather than the `Arc`. On
5883 /// TPC-H q12 that was fourteen hundred copies a query out of a column of five distinct values.
5884 #[test]
5885 fn flattening_a_gather_off_a_paged_parent_takes_the_arena_rather_than_copying_it() {
5886 let arena = Arc::new(Buffer::from_vec(b"1-URGENT2-HIGH".to_vec()));
5887 let views = vec![
5888 StringView::over(b"1-URGENT", 0),
5889 StringView::over(b"2-HIGH", 8),
5890 StringView::over(b"1-URGENT", 0),
5891 ];
5892 let built = Vector::string_views(LogicalType::Varchar, views, arena).unwrap();
5893 let owned = match &built.body {
5894 Body::Views { arena, .. } => arena.is_shared(),
5895 _ => panic!("string views are a views body"),
5896 };
5897 assert!(!owned, "concat builds an arena rather than reading one, so it starts owned");
5898
5899 let bytes = |vector: &Vector| match &vector.body {
5900 Body::Views { arena, .. } => arena.as_slice().as_ptr() as usize,
5901 Body::Flat(Data::Varlen(column)) => column.arena().as_ptr() as usize,
5902 _ => panic!("a string vector holds string bytes"),
5903 };
5904 let gathered = |parent: &Vector| {
5905 Vector::gathered(Arc::new(parent.clone()), Arc::new(vec![1, 0])).unwrap()
5906 };
5907
5908 // Built again rather than cloned, because a clone would be a second holder of the arena and
5909 // paging would decline it, which is the case the test below this one is about.
5910 let paged = Vector::string_views(
5911 LogicalType::Varchar,
5912 built.shared_views().unwrap().0.to_vec(),
5913 Arc::new(Buffer::from_vec(b"1-URGENT2-HIGH".to_vec())),
5914 )
5915 .unwrap()
5916 .into_pages();
5917 assert_eq!(
5918 bytes(&gathered(&paged).flatten().unwrap()),
5919 bytes(&paged),
5920 "a flatten off a page shares the arena"
5921 );
5922 assert_ne!(
5923 bytes(&gathered(&built).flatten().unwrap()),
5924 bytes(&built),
5925 "and off an owned arena it copies, which is what this changed"
5926 );
5927 assert_eq!(
5928 gathered(&paged).flatten().unwrap().iter().collect::<Vec<_>>(),
5929 [Value::Varchar("2-HIGH".into()), Value::Varchar("1-URGENT".into())]
5930 );
5931 }
5932
5933 /// An arena somebody else is still holding is left as it was, because the only way to page it
5934 /// would be to copy it and a copy is the thing the caller asked not to pay for.
5935 #[test]
5936 fn paging_a_string_column_whose_arena_has_another_holder_leaves_it_alone() {
5937 let arena = Arc::new(Buffer::from_vec(b"red".to_vec()));
5938 let vector =
5939 Vector::string_views(LogicalType::Varchar, vec![StringView::over(b"red", 0)], arena)
5940 .unwrap();
5941 // The clone is the other holder: both vectors point at the one arena.
5942 let paged = vector.clone().into_pages();
5943 match &paged.body {
5944 Body::Views { arena, .. } => assert!(!arena.is_shared(), "it was not ours to move"),
5945 _ => panic!("string views are a views body"),
5946 }
5947 assert_eq!(paged.iter().collect::<Vec<_>>(), [Value::Varchar("red".into())]);
5948 }
5949
5950 /// Once the codes are a page, a cut and a clone of a coded column point at the same codes, which
5951 /// is what a scan does to every page of a dictionary encoded Parquet column.
5952 #[test]
5953 fn a_paged_dictionary_shares_its_codes_with_its_cuts_and_clones() {
5954 let values = Vector::from_values(
5955 LogicalType::Varchar,
5956 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
5957 )
5958 .unwrap();
5959 let vector = Vector::dictionary(vec![0, 1, 1, 0, 1], values).unwrap().into_pages();
5960 let codes = |vector: &Vector| match &vector.body {
5961 Body::Dictionary { codes, .. } => codes.as_slice().as_ptr() as usize,
5962 _ => panic!("a dictionary vector holds a dictionary"),
5963 };
5964 assert_eq!(codes(&vector.slice(1, 3).unwrap()), codes(&vector) + 4, "the cut copied");
5965 assert_eq!(codes(&vector.clone()), codes(&vector), "the clone copied");
5966 assert_eq!(
5967 vector.slice(1, 3).unwrap().iter().collect::<Vec<_>>(),
5968 [
5969 Value::Varchar("blue".into()),
5970 Value::Varchar("blue".into()),
5971 Value::Varchar("red".into())
5972 ]
5973 );
5974 }
5975
5976 #[test]
5977 fn a_slice_carries_the_nulls_that_were_in_its_range_and_not_the_others() {
5978 let vector =
5979 integers(&[1, 2, 3, 4]).with_validity(Validity::from_run(&[false, true, false, true]));
5980 let piece = vector.slice(1, 2).unwrap();
5981 assert!(piece.validity().is_valid(0));
5982 assert!(!piece.validity().is_valid(1));
5983 assert_eq!(piece.value_at(1), Value::Null);
5984 }
5985
5986 #[test]
5987 fn slicing_a_sequence_moves_its_start_rather_than_writing_the_values_out() {
5988 let vector = Vector::sequence(100, 5, 10);
5989 let piece = vector.slice(3, 4).unwrap();
5990 assert_eq!(piece.form(), Form::Sequence);
5991 assert_eq!(
5992 piece.iter().collect::<Vec<_>>(),
5993 [Value::BigInt(115), Value::BigInt(120), Value::BigInt(125), Value::BigInt(130)]
5994 );
5995 }
5996
5997 #[test]
5998 fn slicing_a_constant_is_a_shorter_constant() {
5999 let vector = Vector::constant(LogicalType::Integer, Value::Integer(9), 8);
6000 let piece = vector.slice(2, 3).unwrap();
6001 assert_eq!(piece.form(), Form::Constant);
6002 assert_eq!(piece.len(), 3);
6003 assert_eq!(piece.value_at(2), Value::Integer(9));
6004 }
6005
6006 #[test]
6007 fn slicing_the_whole_vector_hands_it_back_as_it_was() {
6008 let vector = integers(&[1, 2, 3]);
6009 assert_eq!(
6010 vector.slice(0, 3).unwrap().iter().collect::<Vec<_>>(),
6011 [Value::Integer(1), Value::Integer(2), Value::Integer(3)]
6012 );
6013 }
6014
6015 /// The short way through a gather, a flat run with no nulls, answers what the long way does,
6016 /// and a position past the end still takes the long way and comes back null.
6017 #[test]
6018 fn a_gather_off_a_flat_run_with_no_nulls_answers_what_the_general_copy_does() {
6019 let rows: Vec<i32> = (0..50).map(|row| row * 3 - 20).collect();
6020 let vector = integers(&rows);
6021 let positions: Vec<u32> = [49, 0, 7, 7, 31, 2].into_iter().collect();
6022 let gathered = vector.gather(&positions).unwrap();
6023 assert_eq!(gathered.form(), Form::Flat);
6024 assert_eq!(
6025 gathered.iter().collect::<Vec<_>>(),
6026 positions.iter().map(|&at| Value::Integer(rows[at as usize])).collect::<Vec<_>>()
6027 );
6028 let past = vector.gather(&[3, 50]).unwrap();
6029 assert_eq!(past.iter().collect::<Vec<_>>(), [Value::Integer(-11), Value::Null]);
6030 }
6031
6032 #[test]
6033 fn cutting_a_flat_body_answers_what_gathering_the_same_rows_answers() {
6034 // The cut of a flat body used to be written as a gather over the positions in the range,
6035 // and it is now a run copied out, so the two have to keep saying the same thing. Every
6036 // start and every length, with nulls in the range and out of it, since the validity is the
6037 // half of this that changed shape.
6038 let rows: Vec<i32> = (0..70).collect();
6039 let valid: Vec<bool> = (0..70).map(|row| row % 7 != 0 && row % 11 != 3).collect();
6040 let vector = integers(&rows).with_validity(Validity::from_run(&valid));
6041 for at in 0..70usize {
6042 for len in 0..=(70 - at) {
6043 let cut = vector.slice(at, len).unwrap();
6044 let positions: Vec<u32> = (at..at + len).map(|row| row as u32).collect();
6045 let gathered = vector.gather(&positions).unwrap();
6046 assert_eq!(cut.len(), len, "rows {at} to {}", at + len);
6047 assert_eq!(
6048 cut.iter().collect::<Vec<_>>(),
6049 gathered.iter().collect::<Vec<_>>(),
6050 "rows {at} to {}",
6051 at + len
6052 );
6053 }
6054 }
6055 }
6056
6057 /// The flat body used to be the one form of a vector whose cut cost an allocation and a copy,
6058 /// and it is not any more when its buffer is a run inside a page. Asserted on the address,
6059 /// because the values are the same either way and the address is the whole claim.
6060 #[test]
6061 fn cutting_a_flat_body_over_a_page_does_not_copy_it() {
6062 let page = Arc::new((0i64..64).collect::<Vec<_>>());
6063 let address = page.as_ptr() as usize;
6064 let data = Data::Int64(Buffer::from_arc(Arc::clone(&page)));
6065 let vector = Vector::flat(LogicalType::BigInt, data).unwrap();
6066 let cut = vector.slice(16, 8).unwrap();
6067 assert_eq!(cut.form(), Form::Flat);
6068 assert_eq!(cut.len(), 8);
6069 let Some(Data::Int64(run)) = cut.data() else {
6070 panic!("the layout changed under the test")
6071 };
6072 assert!(run.is_shared(), "the cut copied the run out of the page");
6073 assert_eq!(run.as_slice().as_ptr() as usize, address + 16 * 8);
6074 assert_eq!(run.as_slice(), &(16i64..24).collect::<Vec<_>>()[..]);
6075 assert_eq!(cut.value_at(0), Value::BigInt(16));
6076 // And the same cut of an owned run says the same thing, by copying it.
6077 let owned = Vector::flat(LogicalType::BigInt, Data::Int64((0i64..64).collect())).unwrap();
6078 let copied = owned.slice(16, 8).unwrap();
6079 let Some(Data::Int64(run)) = copied.data() else {
6080 panic!("the layout changed under the test")
6081 };
6082 assert!(!run.is_shared());
6083 assert_eq!(run.as_slice(), &(16i64..24).collect::<Vec<_>>()[..]);
6084 }
6085
6086 /// `into_pages` is how a producer says its values will be handed out many times. A flat body is
6087 /// the form it changes, and after it a copy of the vector is a reference count bump.
6088 #[test]
6089 fn a_vector_over_pages_is_copied_and_cut_without_its_values_moving() {
6090 let vector = integers(&[1, 2, 3, 4, 5, 6, 7, 8]).into_pages();
6091 let address = |vector: &Vector| match vector.data() {
6092 Some(Data::Int32(values)) => values.as_slice().as_ptr() as usize,
6093 _ => panic!("the layout changed under the test"),
6094 };
6095 let stored = address(&vector);
6096 assert_eq!(address(&vector.clone()), stored, "a copy moved the values");
6097 assert_eq!(address(&vector.slice(2, 4).unwrap()), stored + 2 * 4, "a cut moved the values");
6098 assert_eq!(
6099 vector.slice(2, 4).unwrap().iter().collect::<Vec<_>>(),
6100 [Value::Integer(3), Value::Integer(4), Value::Integer(5), Value::Integer(6)]
6101 );
6102 // Twice is not two pages.
6103 assert_eq!(address(&vector.clone().into_pages()), stored);
6104 }
6105
6106 /// A cut, a gather and a flatten of a string column over a page all move views and no bytes.
6107 ///
6108 /// This is the string half of the paging that `a_vector_over_pages_is_copied_and_cut_without_
6109 /// its_values_moving` checks for a fixed width column, and it is worth its own test because a
6110 /// string column is two allocations rather than one: the cut that matters is the payload
6111 /// staying where it is while the views move.
6112 #[test]
6113 fn a_string_column_over_a_page_is_cut_and_gathered_without_its_payload_moving() {
6114 let long = ["the first of the long strings", "the second one", "and a third long one here"];
6115 let mut built = StringColumn::with_capacity(long.len());
6116 for text in long {
6117 built.push(text);
6118 }
6119 let vector = Vector::flat(LogicalType::Varchar, Data::Varlen(built.into_page())).unwrap();
6120 let payload = |vector: &Vector| match vector.data() {
6121 Some(Data::Varlen(column)) => column.arena().as_ptr() as usize,
6122 _ => panic!("the layout changed under the test"),
6123 };
6124 let stored = payload(&vector);
6125 let cut = vector.slice(1, 2).unwrap();
6126 assert_eq!(payload(&cut), stored, "a cut moved the payload");
6127 assert_eq!(cut.text_at(0), Some(long[1]));
6128 assert_eq!(cut.text_at(1), Some(long[2]));
6129 let gathered = vector.gather(&[2, 0]).unwrap();
6130 assert_eq!(payload(&gathered), stored, "a gather moved the payload");
6131 assert_eq!(gathered.text_at(0), Some(long[2]));
6132 assert_eq!(gathered.text_at(1), Some(long[0]));
6133 // And the same column with its own arena still copies, because sharing an owned arena
6134 // means cloning every byte of it including the bytes nobody asked for.
6135 let mut owned = StringColumn::with_capacity(long.len());
6136 for text in long {
6137 owned.push(text);
6138 }
6139 let held = Vector::flat(LogicalType::Varchar, Data::Varlen(owned)).unwrap();
6140 let copied = held.slice(1, 2).unwrap();
6141 assert_ne!(payload(&copied), payload(&held), "an owned payload was shared");
6142 assert_eq!(copied.text_at(0), Some(long[1]));
6143 }
6144
6145 /// A flatten gives up the form and not the sharing. The views form is already views over an
6146 /// arena, so flattening one over a page is the views and nothing else, and the flat column
6147 /// that comes out reads the same strings out of the same bytes.
6148 #[test]
6149 fn flattening_string_views_over_a_page_keeps_the_page() {
6150 let mut built = StringColumn::with_capacity(2);
6151 built.push("a string too long to sit inside a view");
6152 built.push("another string that is also too long");
6153 let (views, arena) = built.into_page().into_parts();
6154 let stored = arena.as_slice().as_ptr() as usize;
6155 let vector = Vector::string_views(LogicalType::Varchar, views, Arc::new(arena)).unwrap();
6156 assert_eq!(vector.form(), Form::StringView);
6157 let flat = vector.flatten().unwrap();
6158 assert_eq!(flat.form(), Form::Flat);
6159 let Some(Data::Varlen(column)) = flat.data() else {
6160 panic!("the layout changed under the test")
6161 };
6162 assert_eq!(column.arena().as_ptr() as usize, stored, "the flatten moved the payload");
6163 assert_eq!(flat.text_at(0), Some("a string too long to sit inside a view"));
6164 assert_eq!(flat.text_at(1), Some("another string that is also too long"));
6165 }
6166
6167 /// Every form that is not flat already shares what is expensive, so this is a no op on them and
6168 /// in particular does not flatten anything. A form that came back flat would be a column that
6169 /// lost its encoding on the way into a table.
6170 #[test]
6171 fn putting_a_vector_on_pages_does_not_change_any_other_form() {
6172 let dictionary = Vector::dictionary(
6173 vec![0, 1, 0, 1],
6174 Vector::from_values(
6175 LogicalType::Varchar,
6176 &[Value::Varchar("a".into()), Value::Varchar("b".into())],
6177 )
6178 .unwrap(),
6179 )
6180 .unwrap();
6181 let cases = [
6182 Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
6183 Vector::sequence(4, 0, 1),
6184 dictionary,
6185 ];
6186 for vector in cases {
6187 let form = vector.form();
6188 let paged = vector.clone().into_pages();
6189 assert_eq!(paged.form(), form, "{form:?} changed form");
6190 assert_eq!(paged.iter().collect::<Vec<_>>(), vector.iter().collect::<Vec<_>>());
6191 }
6192 }
6193
6194 #[test]
6195 fn cutting_a_flat_string_column_answers_what_gathering_it_answers() {
6196 // The string layout is the one whose cut is still a loop, and it is also the one where a
6197 // row is a view into an arena rather than a slot, so it gets the same treatment separately.
6198 // Both inline and out of line strings, since they are copied by different paths.
6199 let rows: Vec<String> =
6200 (0..40).map(|row| "x".repeat(row % 30) + &row.to_string()).collect();
6201 let values: Vec<Value> = rows.iter().map(|row| Value::Varchar(row.clone())).collect();
6202 let vector = Vector::from_values(LogicalType::Varchar, &values).unwrap().flatten().unwrap();
6203 assert_eq!(vector.form(), Form::Flat, "the cut under test is the flat one");
6204 for at in 0..40usize {
6205 for len in 0..=(40 - at) {
6206 let cut = vector.slice(at, len).unwrap();
6207 let positions: Vec<u32> = (at..at + len).map(|row| row as u32).collect();
6208 let gathered = vector.gather(&positions).unwrap();
6209 assert_eq!(
6210 cut.iter().collect::<Vec<_>>(),
6211 gathered.iter().collect::<Vec<_>>(),
6212 "rows {at} to {}",
6213 at + len
6214 );
6215 }
6216 }
6217 }
6218
6219 #[test]
6220 fn a_slice_past_the_end_is_an_error_rather_than_a_short_vector() {
6221 let error = integers(&[1, 2, 3]).slice(2, 2).unwrap_err();
6222 assert!(error.to_string().contains("of a vector of 3"), "{error}");
6223 }
6224
6225 #[test]
6226 fn the_vector_size_is_the_one_the_design_is_built_around() {
6227 // 8192, which is four times DuckDB's 2048, measured in #480 against 1024, 2048, 4096 and
6228 // 32768. What the rest of the code assumes about it is not the value but the shape: a
6229 // multiple of 1024, which is the FastLanes unit and is what makes a validity mask a whole
6230 // number of u64 words with none of them half used.
6231 assert_eq!(VECTOR_SIZE, 8192);
6232 assert_eq!(VECTOR_SIZE % 1024, 0);
6233 assert_eq!(VECTOR_SIZE % 64, 0);
6234 assert_eq!(VECTOR_SIZE / 64, 128, "the words in a validity mask");
6235 }
6236
6237 #[test]
6238 fn a_flat_vector_reads_back_what_was_put_in_it() {
6239 let vector = integers(&[1, 2, 3]);
6240 assert_eq!(vector.form(), Form::Flat);
6241 assert_eq!(vector.len(), 3);
6242 assert_eq!(vector.value_at(1), Value::Integer(2));
6243 assert_eq!(
6244 vector.iter().collect::<Vec<_>>(),
6245 vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)]
6246 );
6247 }
6248
6249 #[test]
6250 fn a_vector_built_from_values_reads_the_same_values_back() {
6251 let vector = Vector::from_values(
6252 LogicalType::Varchar,
6253 &[
6254 Value::Varchar("a".to_string()),
6255 Value::Null,
6256 Value::Varchar("a string too long to sit inside a view".to_string()),
6257 ],
6258 )
6259 .expect("strings and a null");
6260 assert_eq!(vector.len(), 3);
6261 assert_eq!(vector.value_at(0), Value::Varchar("a".to_string()));
6262 assert_eq!(vector.value_at(1), Value::Null);
6263 assert_eq!(
6264 vector.value_at(2),
6265 Value::Varchar("a string too long to sit inside a view".to_string())
6266 );
6267 }
6268
6269 /// A null still occupies a position. If it did not then every value after it would read back
6270 /// one place to the left, which is the kind of bug that looks like a storage bug for a week.
6271 #[test]
6272 fn a_null_in_the_middle_does_not_move_the_values_after_it() {
6273 let vector = Vector::from_values(
6274 LogicalType::Integer,
6275 &[Value::Integer(1), Value::Null, Value::Integer(3)],
6276 )
6277 .expect("integers and a null");
6278 assert_eq!(vector.value_at(2), Value::Integer(3));
6279 assert!(vector.validity().has_nulls(3), "the middle one is null");
6280 }
6281
6282 #[test]
6283 fn a_value_the_type_cannot_hold_is_refused() {
6284 let wrong = Vector::from_values(LogicalType::Integer, &[Value::Varchar("x".to_string())]);
6285 assert!(wrong.is_err(), "a string is not an integer");
6286 }
6287
6288 #[test]
6289 fn a_type_that_does_not_match_its_layout_is_refused_at_construction() {
6290 // One comparison here against a wrong answer read out three layers later.
6291 let wrong = Vector::flat(LogicalType::Varchar, Data::Int32(vec![1].into()));
6292 assert!(wrong.is_err());
6293 let right = Vector::flat(LogicalType::Date, Data::Int32(vec![1].into()));
6294 assert!(right.is_ok(), "a date is stored in an i32 and that has to be allowed");
6295 }
6296
6297 #[test]
6298 fn a_constant_vector_costs_one_value_whatever_its_length() {
6299 let vector = Vector::constant(LogicalType::Integer, Value::Integer(7), VECTOR_SIZE);
6300 assert_eq!(vector.form(), Form::Constant);
6301 assert_eq!(vector.len(), VECTOR_SIZE);
6302 assert_eq!(vector.value_at(0), Value::Integer(7));
6303 assert_eq!(vector.value_at(VECTOR_SIZE - 1), Value::Integer(7));
6304 assert_eq!(vector.value_at(VECTOR_SIZE), Value::Null, "past the end is null, not a panic");
6305 }
6306
6307 #[test]
6308 fn a_constant_null_is_all_invalid_without_being_told() {
6309 let vector = Vector::constant(LogicalType::Integer, Value::Null, 8);
6310 assert_eq!(vector.validity(), &Validity::AllInvalid);
6311 assert_eq!(vector.value_at(3), Value::Null);
6312 }
6313
6314 #[test]
6315 fn a_sequence_vector_is_sixteen_bytes_of_row_identifiers() {
6316 let vector = Vector::sequence(100, 1, VECTOR_SIZE);
6317 assert_eq!(vector.form(), Form::Sequence);
6318 assert_eq!(vector.value_at(0), Value::BigInt(100));
6319 assert_eq!(vector.value_at(923), Value::BigInt(1023));
6320 let stepped = Vector::sequence(0, 5, 4);
6321 assert_eq!(
6322 stepped.iter().collect::<Vec<_>>(),
6323 vec![Value::BigInt(0), Value::BigInt(5), Value::BigInt(10), Value::BigInt(15)]
6324 );
6325 }
6326
6327 #[test]
6328 fn a_dictionary_vector_reads_through_its_codes() {
6329 let mut column = StringColumn::new();
6330 column.push("red");
6331 column.push("green");
6332 let values = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
6333 let vector = Vector::dictionary(vec![0, 1, 1, 0], values).unwrap();
6334 assert_eq!(vector.form(), Form::Dictionary);
6335 assert_eq!(vector.logical_type(), &LogicalType::Varchar);
6336 assert_eq!(vector.value_at(2), Value::Varchar("green".into()));
6337 assert_eq!(vector.len(), 4);
6338 }
6339
6340 /// The accessor a group by keys a string column through, which has to agree with `value_at` on
6341 /// every position or two rows holding one string end up in two groups.
6342 #[test]
6343 fn text_is_read_where_it_already_is_for_the_forms_that_store_it() {
6344 let mut column = StringColumn::new();
6345 column.push("red");
6346 column.push("green");
6347 column.push("");
6348 let flat = Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap();
6349 for index in 0..flat.len() {
6350 assert_eq!(flat.text_at(index).map(str::to_string), text_of(&flat.value_at(index)));
6351 }
6352 let dictionary = Vector::dictionary(vec![1, 0, 1, 2], flat).unwrap();
6353 for index in 0..dictionary.len() {
6354 assert_eq!(
6355 dictionary.text_at(index).map(str::to_string),
6356 text_of(&dictionary.value_at(index))
6357 );
6358 }
6359 assert_eq!(dictionary.text_at(4), None, "past the end");
6360 }
6361
6362 /// The forms and types that have no text to hand back, which a caller answers by falling back
6363 /// to `value_at`. A blob is the one that would be a correctness bug rather than a slow path,
6364 /// since its bytes are not required to be text and it is not a `VARCHAR` either way.
6365 #[test]
6366 fn text_is_refused_where_it_is_not_stored_as_itself() {
6367 let nulls =
6368 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into()), Value::Null])
6369 .unwrap();
6370 assert_eq!(nulls.text_at(0), Some("red"));
6371 assert_eq!(nulls.text_at(1), None, "a null has no text");
6372 let constant = Vector::constant(LogicalType::Varchar, Value::Varchar("red".into()), 3);
6373 assert_eq!(constant.text_at(0), None, "a constant is not stored per position");
6374 assert_eq!(integers(&[1, 2]).text_at(0), None, "an integer is not text");
6375 let mut bytes = StringColumn::new();
6376 bytes.push("red");
6377 let blob = Vector::flat(LogicalType::Blob, Data::Varlen(bytes)).unwrap();
6378 assert_eq!(blob.text_at(0), None, "a blob is not a varchar");
6379 }
6380
6381 /// The accessor a group by keys an integer column through, which has to agree with `value_at`
6382 /// on every position or two rows holding one number end up in two groups.
6383 #[test]
6384 fn a_signed_integer_is_read_where_it_already_is_for_the_forms_that_store_it() {
6385 let flat = integers(&[7, -3, 0, 2]);
6386 for index in 0..flat.len() {
6387 assert_eq!(flat.signed_at(index), signed_of(&flat.value_at(index)), "flat {index}");
6388 }
6389 let dictionary = Vector::dictionary(vec![1, 0, 3, 2], flat).unwrap();
6390 for index in 0..dictionary.len() {
6391 assert_eq!(
6392 dictionary.signed_at(index),
6393 signed_of(&dictionary.value_at(index)),
6394 "dictionary {index}"
6395 );
6396 }
6397 assert_eq!(dictionary.signed_at(4), None, "past the end");
6398
6399 let runs = Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap();
6400 for index in 0..runs.len() {
6401 assert_eq!(runs.signed_at(index), signed_of(&runs.value_at(index)), "run {index}");
6402 }
6403 let constant = Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3);
6404 assert_eq!(constant.signed_at(2), Some(11));
6405 let sequence = Vector::sequence(100, 5, 4);
6406 for index in 0..sequence.len() {
6407 assert_eq!(
6408 sequence.signed_at(index),
6409 signed_of(&sequence.value_at(index)),
6410 "sequence {index}"
6411 );
6412 }
6413 }
6414
6415 /// A window of a shared page packs exactly when the same rows owned would, and a range its
6416 /// type cannot hold at the width it needs stays flat rather than failing. A load of ClickBench
6417 /// `hits` hit both: its windows were judged by their share of the page, packed at 32 bits, and
6418 /// the packed form refused a range that ran past `i32::MAX`.
6419 #[test]
6420 fn a_window_of_a_page_packs_the_way_the_same_rows_owned_do() {
6421 let wide: Vec<i32> = (0..122_880)
6422 .map(|at| if at % 2 == 0 { i32::MIN + 5 + at } else { i32::MAX - 9 - at })
6423 .collect();
6424 let narrow: Vec<i32> = (0..122_880).map(|at| 1_000 + at % 200).collect();
6425 for values in [wide, narrow] {
6426 let page = integers(&values).into_pages();
6427 let window = page.slice(0, 8_192).unwrap();
6428 let owned = integers(&values[..8_192]);
6429 let packed_window = window.bit_packed().unwrap();
6430 let packed_owned = owned.bit_packed().unwrap();
6431 assert_eq!(
6432 packed_window.packed_parts().is_some(),
6433 packed_owned.packed_parts().is_some()
6434 );
6435 for at in [0, 1, 4_095, 8_191] {
6436 assert_eq!(packed_window.value_at(at), owned.value_at(at));
6437 }
6438 }
6439 }
6440
6441 /// The forms and types that have no integer to hand back, which a caller answers by falling
6442 /// back to `value_at`.
6443 #[test]
6444 fn a_signed_integer_is_refused_where_it_is_not_stored_as_itself() {
6445 let nulls =
6446 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
6447 assert_eq!(nulls.signed_at(0), Some(4));
6448 assert_eq!(nulls.signed_at(1), None, "a null is not a number");
6449 let packed = integers(&[1, 2, 3, 1]).bit_packed().unwrap();
6450 assert_eq!(packed.signed_at(0), Some(1), "a packed integer is read in code space");
6451 let mut bytes = StringColumn::new();
6452 bytes.push("red");
6453 let text = Vector::flat(LogicalType::Varchar, Data::Varlen(bytes)).unwrap();
6454 assert_eq!(text.signed_at(0), None, "a string is not a number");
6455 let double = Vector::flat(LogicalType::Double, Data::Float64(vec![1.5].into())).unwrap();
6456 assert_eq!(double.signed_at(0), None, "a double is not a signed integer");
6457 }
6458
6459 /// The block form has to agree with the row at a time form on every position of every shape it
6460 /// answers for, because a caller picks one of the two and a group by that read two different
6461 /// numbers for one row would put that row in two groups.
6462 #[test]
6463 fn a_block_of_signed_integers_holds_what_the_row_at_a_time_accessor_hands_back() {
6464 let mut out = Vec::new();
6465 let shapes = [
6466 integers(&[7, -3, 0, 2]),
6467 Vector::flat(LogicalType::Integer, Data::Int32(vec![5, -6, 7].into())).unwrap(),
6468 Vector::flat(LogicalType::SmallInt, Data::Int16(vec![1, -2].into())).unwrap(),
6469 Vector::flat(LogicalType::TinyInt, Data::Int8(vec![-128, 127].into())).unwrap(),
6470 Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3),
6471 Vector::sequence(100, 5, 4),
6472 integers(&[1, 2, 3, 1]).bit_packed().unwrap(),
6473 Vector::dictionary(vec![1, 0, 1, 3], integers(&[7, -3, 0, 2])).unwrap(),
6474 Vector::dictionary(
6475 vec![2, 2, 0],
6476 Vector::flat(LogicalType::SmallInt, Data::Int16(vec![9, -9, 4].into())).unwrap(),
6477 )
6478 .unwrap(),
6479 ];
6480 for column in &shapes {
6481 assert!(column.signed_block(&mut out), "{:?} hands over a block", column.form());
6482 assert_eq!(out.len(), column.len(), "{:?} filled the whole chunk", column.form());
6483 for (index, &held) in out.iter().enumerate() {
6484 assert_eq!(
6485 Some(i128::from(held)),
6486 column.signed_at(index),
6487 "{:?} at {index}",
6488 column.form()
6489 );
6490 }
6491 }
6492 }
6493
6494 /// The gathered form reads what the row at a time accessor reads at the rows it is given, and
6495 /// refuses a row past the end and a vector that is not flat, leaving nothing behind.
6496 #[test]
6497 fn a_gather_of_signed_integers_holds_what_the_row_at_a_time_accessor_hands_back() {
6498 let mut out = Vec::new();
6499 let at = [0, 2, 2, 3];
6500 let shapes = [
6501 integers(&[7, -3, 0, 2]),
6502 Vector::flat(LogicalType::Integer, Data::Int32(vec![5, -6, 7, -8].into())).unwrap(),
6503 Vector::flat(LogicalType::TinyInt, Data::Int8(vec![-128, 127, 1, 0].into())).unwrap(),
6504 ];
6505 for column in &shapes {
6506 assert!(column.signed_gather(&at, &mut out), "{:?} is gathered", column.logical_type());
6507 let wanted: Vec<i64> = at
6508 .iter()
6509 .map(|&row| i64::try_from(column.signed_at(row as usize).unwrap()).unwrap())
6510 .collect();
6511 assert_eq!(out, wanted);
6512 }
6513 let short = integers(&[1, 2, 3]);
6514 assert!(!short.signed_gather(&at, &mut out), "row 3 is past the end");
6515 assert!(out.is_empty());
6516 assert!(!Vector::sequence(100, 5, 4).signed_gather(&at, &mut out));
6517 assert!(integers(&[1]).signed_gather(&[], &mut out) && out.is_empty());
6518 }
6519
6520 /// The runs of a flat column are its values where they change and the rows they end before,
6521 /// counted from the row the runs were asked from, and a column that changes on every row is
6522 /// given up on.
6523 #[test]
6524 fn the_runs_of_a_flat_column_end_where_its_values_change() {
6525 let mut out = Vec::new();
6526 let column =
6527 Vector::flat(LogicalType::SmallInt, Data::Int16(vec![4, 4, 4, -1, -1, 4, 9].into()))
6528 .unwrap();
6529 assert!(column.signed_runs((1, 7), 1, &mut out));
6530 assert_eq!(out, [(4, 3), (-1, 5), (4, 6), (9, 7)]);
6531 assert!(!column.signed_runs((1, 8), 1, &mut out), "row 7 is past the end");
6532 assert!(out.is_empty());
6533 let changing = integers(&(0..1000).collect::<Vec<_>>());
6534 assert!(!changing.signed_runs((0, 1000), 8, &mut out));
6535 assert!(out.is_empty());
6536 assert!(!Vector::sequence(100, 5, 4).signed_runs((0, 4), 8, &mut out));
6537 }
6538
6539 /// The rows a filter kept out of a part's row numbers are a dictionary over the numbers of the
6540 /// whole part, and the block holds the numbers the codes pick without laying the rest out.
6541 #[test]
6542 fn a_block_of_picked_row_numbers_holds_the_numbers_picked() {
6543 let mut out = Vec::new();
6544 let picked =
6545 Vector::dictionary(vec![0, 3, 3, 8191], Vector::sequence(100, 5, 8192)).unwrap();
6546 assert!(picked.signed_block(&mut out));
6547 assert_eq!(out, [100, 115, 115, 100 + 5 * 8191]);
6548 }
6549
6550 /// What the block form will not answer for, where the caller reads the vector a row at a time
6551 /// instead. A null is not one of them: it writes whatever sits under it and the caller reads the
6552 /// null from the column.
6553 #[test]
6554 fn a_block_is_refused_for_the_shapes_it_would_have_to_gather_or_widen() {
6555 let mut out = Vec::new();
6556 let nulled =
6557 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
6558 assert!(
6559 !Vector::dictionary(vec![1, 0], nulled).unwrap().signed_block(&mut out),
6560 "a dictionary with a null entry would hand its row over as a number"
6561 );
6562 assert!(!Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap().signed_block(&mut out));
6563 let wide = Vector::flat(LogicalType::HugeInt, Data::Int128(vec![1, 2].into())).unwrap();
6564 assert!(!wide.signed_block(&mut out), "a hugeint does not fit sixty four bits");
6565 let double = Vector::flat(LogicalType::Double, Data::Float64(vec![1.5].into())).unwrap();
6566 assert!(!double.signed_block(&mut out), "a double is not a signed integer");
6567 assert!(out.is_empty(), "a refusal leaves the buffer empty");
6568
6569 let nulls =
6570 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
6571 assert!(nulls.signed_block(&mut out), "a flat column with nulls still hands over");
6572 assert_eq!(out[0], 4);
6573 }
6574
6575 /// Asked once for a chunk, and it has to agree with `is_null_at` asked for every row of it.
6576 #[test]
6577 fn a_vector_says_whether_it_holds_any_null_at_all() {
6578 let flat = integers(&[7, -3, 0, 2]);
6579 assert!(flat.none_null());
6580 let nulls =
6581 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(4), Value::Null]).unwrap();
6582 assert!(!nulls.none_null());
6583 assert!(Vector::dictionary(vec![1, 0], flat.clone()).unwrap().none_null());
6584 // The null is in the dictionary rather than in the mask, which is the case the row at a time
6585 // form reads through for and the reason this one does too.
6586 let holed = Vector::dictionary(vec![0, 0], nulls.clone()).unwrap();
6587 assert!(!holed.none_null(), "a dictionary is read through to its values");
6588 assert!(!holed.is_null_at(0), "and no code points at the null it holds");
6589 assert!(Vector::runs(vec![2, 5], integers(&[4, 9])).unwrap().none_null());
6590 assert!(!Vector::runs(vec![1, 2], nulls).unwrap().none_null());
6591 assert!(Vector::constant(LogicalType::BigInt, Value::BigInt(11), 3).none_null());
6592 assert!(!Vector::constant(LogicalType::BigInt, Value::Null, 3).none_null());
6593 }
6594
6595 /// The integer of a value, for comparing `signed_at` against `value_at` position by position.
6596 fn signed_of(value: &Value) -> Option<i128> {
6597 match value {
6598 Value::TinyInt(x) => Some(i128::from(*x)),
6599 Value::SmallInt(x) => Some(i128::from(*x)),
6600 Value::Integer(x) | Value::Date(x) => Some(i128::from(*x)),
6601 Value::BigInt(x) | Value::Time(x) | Value::Timestamp(x) => Some(i128::from(*x)),
6602 Value::HugeInt(x) | Value::Decimal { unscaled: x, .. } => Some(*x),
6603 _ => None,
6604 }
6605 }
6606
6607 /// The text of a value, for comparing `text_at` against `value_at` position by position.
6608 fn text_of(value: &Value) -> Option<String> {
6609 match value {
6610 Value::Varchar(text) => Some(text.clone()),
6611 _ => None,
6612 }
6613 }
6614
6615 #[test]
6616 fn a_dictionary_code_past_the_end_is_refused() {
6617 // The alternative is a silent read of the wrong value, which is the failure mode the
6618 // entire M3 design has to be careful about.
6619 let values = integers(&[1, 2]);
6620 assert!(Vector::dictionary(vec![0, 2], values).is_err());
6621 // The check runs on the highest code rather than the first bad one, so it has to say that
6622 // no codes at all is fine even when there are no values for them to point at either.
6623 let empty = Vector::dictionary(Vec::new(), integers(&[])).expect("no codes, no values");
6624 assert_eq!(empty.len(), 0);
6625 // And a code of zero against an empty dictionary is still past the end.
6626 assert!(Vector::dictionary(vec![0], integers(&[])).is_err());
6627 }
6628
6629 #[test]
6630 fn every_form_flattens_to_the_same_values_it_reads_out() {
6631 // This is the shape of the equivalence testing in spec/16-testing.md section 16.2, in
6632 // miniature and long before there is an encoded kernel to point it at. A form that reads
6633 // out one way and flattens another is the exact bug that testing exists to catch.
6634 let mut column = StringColumn::new();
6635 column.push("alpha");
6636 column.push("beta");
6637 let dictionary = Vector::dictionary(
6638 vec![1, 0, 1],
6639 Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
6640 )
6641 .unwrap();
6642 let cases = [
6643 Vector::constant(LogicalType::Integer, Value::Integer(3), 5),
6644 Vector::sequence(7, -2, 5),
6645 dictionary,
6646 ];
6647 for vector in cases {
6648 let flat = vector.flatten().unwrap();
6649 assert_eq!(flat.form(), Form::Flat);
6650 assert_eq!(flat.len(), vector.len());
6651 for index in 0..vector.len() {
6652 assert_eq!(flat.value_at(index), vector.value_at(index), "at {index}");
6653 }
6654 }
6655 }
6656
6657 #[test]
6658 fn a_null_still_occupies_a_position_after_flattening() {
6659 // The reason push_value writes a zero for a null rather than skipping it. A run of data
6660 // with a hole in it puts every value after the hole in the wrong place, and the validity
6661 // mask is what says the position is null.
6662 let vector = Vector::sequence(0, 1, 4).with_validity(Validity::from_iter(4, |i| i != 1));
6663 let flat = vector.flatten().unwrap();
6664 assert_eq!(flat.value_at(0), Value::BigInt(0));
6665 assert_eq!(flat.value_at(1), Value::Null);
6666 assert_eq!(flat.value_at(2), Value::BigInt(2));
6667 assert_eq!(flat.value_at(3), Value::BigInt(3));
6668 }
6669
6670 /// A dictionary holds its nulls in the vector it points at, so its own validity is all valid
6671 /// and reading that instead of the values turns a null into whatever zero means for the type.
6672 /// A filter over a nullable column produces exactly this vector, so the bug reaches a result
6673 /// set as `LEFT JOIN` padding that comes back as zeros.
6674 #[test]
6675 fn a_null_behind_a_dictionary_survives_flattening() {
6676 let values =
6677 Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
6678 let dictionary = Vector::dictionary(vec![1, 0, 1], values).unwrap();
6679 let flat = dictionary.flatten().unwrap();
6680 assert_eq!(flat.value_at(0), Value::Null);
6681 assert_eq!(flat.value_at(1), Value::Integer(3));
6682 assert_eq!(flat.value_at(2), Value::Null);
6683 }
6684
6685 /// The property that makes `gather` usable at all: it has to be the same function as reading the
6686 /// wanted positions one at a time, over every form, or compaction changes answers.
6687 #[test]
6688 fn gathering_reads_what_reading_one_position_at_a_time_reads() {
6689 let mut column = StringColumn::new();
6690 column.push("alpha");
6691 column.push("beta");
6692 column.push("gamma");
6693 let cases = [
6694 integers(&[10, 20, 30, 40]),
6695 integers(&[10, 20, 30, 40]).with_validity(Validity::from_iter(4, |i| i != 2)),
6696 Vector::constant(LogicalType::Integer, Value::Integer(9), 4),
6697 Vector::sequence(100, -7, 4),
6698 Vector::sequence(100, -7, 4).with_validity(Validity::from_iter(4, |i| i % 2 == 0)),
6699 Vector::dictionary(
6700 vec![2, 0, 1, 2],
6701 Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap(),
6702 )
6703 .unwrap(),
6704 Vector::dictionary(
6705 vec![1, 0, 1, 0],
6706 Vector::from_values(LogicalType::Integer, &[Value::Integer(5), Value::Null])
6707 .unwrap(),
6708 )
6709 .unwrap(),
6710 ];
6711 let wanted = [3_u32, 0, 2, 2, 1];
6712 for vector in cases {
6713 let gathered = vector.gather(&wanted).unwrap();
6714 assert_eq!(gathered.len(), wanted.len());
6715 assert_eq!(gathered.logical_type(), vector.logical_type());
6716 for (slot, &index) in wanted.iter().enumerate() {
6717 assert_eq!(
6718 gathered.value_at(slot),
6719 vector.value_at(index as usize),
6720 "slot {slot} of {:?}",
6721 vector.form()
6722 );
6723 }
6724 }
6725 }
6726
6727 /// A gather past the end is not an error, because the selection that produced the indices is
6728 /// checked by its caller and the one thing that must not happen here is a read of the wrong
6729 /// value. An index nothing answers is null, which is what an outer join pad needs anyway.
6730 #[test]
6731 fn gathering_a_position_that_is_not_there_is_a_null_and_not_a_wrong_value() {
6732 let vector = integers(&[1, 2, 3]);
6733 let gathered = vector.gather(&[2, 9]).unwrap();
6734 assert_eq!(gathered.value_at(0), Value::Integer(3));
6735 assert_eq!(gathered.value_at(1), Value::Null);
6736 }
6737
6738 /// The vector with nothing in it at all, which is what an untyped `NULL` is stored as. Every
6739 /// position asked for is past its end, so the answer is nulls and the length has to be the
6740 /// length that was asked for rather than the length that was there.
6741 #[test]
6742 fn gathering_from_a_vector_of_no_values_is_that_many_nulls() {
6743 let vector = Vector::flat(LogicalType::Null, Data::Empty).unwrap();
6744 let gathered = vector.gather(&[0, 1, 2]).unwrap();
6745 assert_eq!(gathered.len(), 3);
6746 assert_eq!(gathered.value_at(0), Value::Null);
6747 assert_eq!(gathered.value_at(2), Value::Null);
6748 }
6749
6750 /// Every position holds the same value, so a gather with no hole in it has nothing to copy and
6751 /// the result is the constant again rather than a run of a thousand copies of it.
6752 #[test]
6753 fn gathering_a_constant_stays_a_constant() {
6754 let vector = Vector::constant(LogicalType::Integer, Value::Integer(4), 100);
6755 let gathered = vector.gather(&[7, 7, 99]).unwrap();
6756 assert_eq!(gathered.form(), Form::Constant);
6757 assert_eq!(gathered.len(), 3);
6758 assert_eq!(gathered.value_at(2), Value::Integer(4));
6759 }
6760
6761 /// A dictionary over a dictionary is what a second filter over an already filtered chunk builds,
6762 /// and the gather has to walk to the bottom of that chain rather than one step down it. The
6763 /// constructor composes the ordinary chain away, so the one built here is the kind it cannot,
6764 /// which is a level holding nulls of its own.
6765 #[test]
6766 fn gathering_walks_a_dictionary_over_a_dictionary_to_the_values() {
6767 let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9]))
6768 .unwrap()
6769 .with_validity(Validity::from_iter(3, |index| index != 2));
6770 let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
6771 let gathered = outer.gather(&[0, 1]).unwrap();
6772 assert_eq!(gathered.form(), Form::Flat);
6773 assert_eq!(gathered.value_at(0), Value::Integer(8));
6774 assert_eq!(gathered.value_at(1), Value::Null);
6775 }
6776
6777 /// Two filters over one chunk build a dictionary over a dictionary, four conjuncts pushed down
6778 /// separately build four levels of it, and every level is a dependent load on every later read
6779 /// of every row plus a code array that cannot be freed. Composing at construction is one pass
6780 /// over the codes the range check was walking anyway.
6781 #[test]
6782 fn a_dictionary_over_a_dictionary_is_composed_into_one_level() {
6783 let inner = Vector::dictionary(vec![2, 1, 0], integers(&[7, 8, 9])).unwrap();
6784 let outer = Vector::dictionary(vec![1, 2], inner).unwrap();
6785 let (codes, values) = outer.dictionary_parts().unwrap();
6786 assert_eq!(codes, [1, 0]);
6787 assert_eq!(values.form(), Form::Flat);
6788 assert_eq!(outer.value_at(0), Value::Integer(8));
6789 assert_eq!(outer.value_at(1), Value::Integer(7));
6790 }
6791
6792 /// The invariant stated as the thing it is there for, which is that the depth does not grow with
6793 /// the number of filters. Four levels stacked one at a time are one level at the end of it.
6794 #[test]
6795 fn stacking_dictionaries_does_not_make_them_deeper() {
6796 let mut vector = integers(&[10, 20, 30, 40]);
6797 for _ in 0..4 {
6798 vector = Vector::dictionary(vec![3, 2, 1, 0], vector).unwrap();
6799 }
6800 let (codes, values) = vector.dictionary_parts().unwrap();
6801 assert_eq!(values.form(), Form::Flat);
6802 assert_eq!(codes, [0, 1, 2, 3]);
6803 assert_eq!(
6804 vector.iter().collect::<Vec<_>>(),
6805 integers(&[10, 20, 30, 40]).iter().collect::<Vec<_>>()
6806 );
6807 }
6808
6809 /// Composing has to carry the nulls down with it. The values hold them, the codes point at them,
6810 /// and a composed code that lands on a null position is still a null.
6811 #[test]
6812 fn composing_a_dictionary_keeps_the_nulls_its_values_hold() {
6813 let values =
6814 Vector::from_values(LogicalType::Integer, &[Value::Integer(3), Value::Null]).unwrap();
6815 let inner = Vector::dictionary(vec![1, 0, 1], values).unwrap();
6816 let outer = Vector::dictionary(vec![0, 1], inner).unwrap();
6817 assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Flat);
6818 assert_eq!(outer.value_at(0), Value::Null);
6819 assert_eq!(outer.value_at(1), Value::Integer(3));
6820 }
6821
6822 /// The one level composition cannot go past. A dictionary that was given a validity of its own is
6823 /// saying its nulls are at that level rather than in the values, and pointing the outer codes
6824 /// straight at the values would read through the holes instead of stopping at them.
6825 #[test]
6826 fn a_dictionary_holding_its_own_nulls_is_not_composed_past() {
6827 let inner = Vector::dictionary(vec![0, 1, 2], integers(&[1, 2, 3]))
6828 .unwrap()
6829 .with_validity(Validity::from_iter(3, |index| index != 1));
6830 let outer = Vector::dictionary(vec![1, 2, 0], inner).unwrap();
6831 assert_eq!(outer.dictionary_parts().unwrap().1.form(), Form::Dictionary);
6832 assert_eq!(outer.value_at(0), Value::Null);
6833 assert_eq!(outer.value_at(1), Value::Integer(3));
6834 assert_eq!(outer.value_at(2), Value::Integer(1));
6835 }
6836
6837 /// The difference between the two questions about nulls, which a group by got wrong. A filtered
6838 /// chunk is dictionary vectors, those are built with every row marked present at their own
6839 /// level, and the nulls are down in the values. So the mask says the row has a value and the
6840 /// row does not.
6841 #[test]
6842 fn a_null_behind_a_dictionary_reads_as_null_even_though_the_mask_says_otherwise() {
6843 let values = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
6844 .unwrap()
6845 .with_validity(Validity::from_iter(2, |index| index != 0));
6846 let vector = Vector::dictionary(vec![0, 1, 0], values).unwrap();
6847 assert!(vector.validity().is_valid(0), "the mask at this level says present");
6848 assert!(vector.is_null_at(0));
6849 assert!(!vector.is_null_at(1));
6850 assert!(vector.is_null_at(2));
6851 assert!(vector.is_null_at(3), "a row past the end is null");
6852 }
6853
6854 /// The same for runs, which are built the same way and keep their nulls in the same place.
6855 #[test]
6856 fn a_null_inside_a_run_reads_as_null_even_though_the_mask_says_otherwise() {
6857 let values = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
6858 .unwrap()
6859 .with_validity(Validity::from_iter(2, |index| index != 0));
6860 let vector = Vector::runs(vec![2, 3], values).unwrap();
6861 assert!(vector.validity().is_valid(0));
6862 assert!(vector.is_null_at(0));
6863 assert!(vector.is_null_at(1));
6864 assert!(!vector.is_null_at(2));
6865 }
6866
6867 /// Every other form keeps its nulls in its own mask, so the two answers agree there.
6868 #[test]
6869 fn the_forms_that_hold_their_own_nulls_answer_the_same_either_way() {
6870 let flat = Vector::flat(LogicalType::Integer, Data::Int32(vec![0, 7].into()))
6871 .unwrap()
6872 .with_validity(Validity::from_iter(2, |index| index != 0));
6873 let constant = Vector::constant(LogicalType::Integer, Value::Null, 2);
6874 let sequence = Vector::sequence(10, 2, 2);
6875 for vector in [flat, constant, sequence] {
6876 for row in 0..vector.len() {
6877 assert_eq!(vector.is_null_at(row), !vector.validity().is_valid(row));
6878 }
6879 }
6880 }
6881
6882 #[test]
6883 fn flattening_a_flat_vector_is_the_same_vector() {
6884 let vector = integers(&[1, 2, 3]);
6885 assert_eq!(vector.flatten().unwrap(), vector);
6886 }
6887
6888 /// The same answer as `flatten` and, for the vector that is already flat and owns its values,
6889 /// the same allocation. Asserted on the address because that is the whole claim: the values
6890 /// come back where they were rather than in a copy of themselves. A flatten through a borrow
6891 /// cannot do that, and at the top of a query it copied every column of every chunk of the
6892 /// result to hand back the bytes it was given.
6893 #[test]
6894 fn flattening_a_vector_that_owns_its_values_moves_them_rather_than_copying_them() {
6895 let vector = integers(&[1, 2, 3, 4]);
6896 let address = |vector: &Vector| match vector.data() {
6897 Some(Data::Int32(values)) => values.as_slice().as_ptr() as usize,
6898 _ => panic!("the layout changed under the test"),
6899 };
6900 let stored = address(&vector);
6901 let flat = vector.into_flat().unwrap();
6902 assert_eq!(address(&flat), stored, "the values moved");
6903 assert_eq!(
6904 flat.iter().collect::<Vec<_>>(),
6905 (1..=4).map(Value::Integer).collect::<Vec<_>>()
6906 );
6907 // And a form that is not flat is flattened, which is the case the copy is deserved in.
6908 let dictionary = Vector::dictionary(vec![1, 0, 1], integers(&[7, 8])).unwrap();
6909 let flat = dictionary.clone().into_flat().unwrap();
6910 assert_eq!(flat.form(), Form::Flat);
6911 assert_eq!(flat.iter().collect::<Vec<_>>(), dictionary.iter().collect::<Vec<_>>());
6912 }
6913
6914 #[test]
6915 fn a_decimal_reads_its_width_and_scale_from_the_type_and_not_the_data() {
6916 let ty = LogicalType::decimal(9, 2).unwrap();
6917 let vector = Vector::flat(ty, Data::Int32(vec![1234].into())).unwrap();
6918 assert_eq!(vector.value_at(0), Value::Decimal { unscaled: 1234, width: 9, scale: 2 });
6919 assert_eq!(vector.value_at(0).to_string(), "12.34");
6920 }
6921
6922 #[test]
6923 fn a_decimal_writes_into_whichever_of_the_four_runs_its_precision_chose() {
6924 // The read path worked at every width and the write path only accepted the 128 bit run, so
6925 // `SELECT 2.5` produced a value nothing could store. All four widths round trip now.
6926 for (width, scale, unscaled) in
6927 [(4u8, 1u8, 25i128), (9, 2, 1234), (18, 3, 123_456), (38, 4, 1_234_567)]
6928 {
6929 let ty = LogicalType::decimal(width, scale).unwrap();
6930 let value = Value::Decimal { unscaled, width, scale };
6931 let vector = Vector::from_values(ty, &[value.clone(), Value::Null]).unwrap();
6932 assert_eq!(vector.value_at(0), value, "a decimal of width {width}");
6933 assert_eq!(vector.value_at(1), Value::Null, "a null decimal of width {width}");
6934 }
6935 }
6936
6937 /// The bytes a blob holds are not required to be text, and a vector of them used to refuse the
6938 /// ones that were not. A byte array column in a Parquet file that nothing annotated is a blob,
6939 /// which is what ClickHouse writes and what ten of the ClickBench queries compare against, so
6940 /// this is the path those take rather than a corner of the type system.
6941 #[test]
6942 fn a_blob_holds_bytes_that_are_not_text() {
6943 let bytes = |raw: &[u8]| Value::Blob(raw.to_vec());
6944 let values = [
6945 bytes(b"a\xffb"),
6946 bytes(b"\x00\x01\x02"),
6947 Value::Null,
6948 bytes(b"\xed\xa0\x80 and long enough to leave the view"),
6949 bytes(b""),
6950 ];
6951 let vector = Vector::from_values(LogicalType::Blob, &values).unwrap();
6952 for (index, value) in values.iter().enumerate() {
6953 assert_eq!(&vector.value_at(index), value, "row {index}");
6954 }
6955 }
6956
6957 #[test]
6958 fn a_decimal_too_wide_for_the_run_its_type_chose_is_an_error_and_not_a_wrong_number() {
6959 // Only reachable by hand, since a value's width is what picked the run. Truncating here
6960 // would store a different number and say nothing about it.
6961 let ty = LogicalType::decimal(4, 1).unwrap();
6962 let value = Value::Decimal { unscaled: 1_000_000, width: 4, scale: 1 };
6963 let error = Vector::from_values(ty, &[value]).unwrap_err();
6964 assert!(error.to_string().contains("does not fit"), "{error}");
6965 }
6966
6967 #[test]
6968 fn a_flat_vector_costs_its_values_and_a_constant_costs_one() {
6969 let flat = integers(&[1; 1000]);
6970 assert!(
6971 flat.footprint() >= 4000,
6972 "a thousand i32 are four thousand bytes: {}",
6973 flat.footprint()
6974 );
6975 // The forms that compute their values rather than storing them cost nothing per value,
6976 // which is the point of having them and is what the memory limit should see.
6977 let constant = Vector::constant(LogicalType::Integer, Value::Integer(1), 1_000_000);
6978 assert!(constant.footprint() < 200, "a constant is one value: {}", constant.footprint());
6979 let sequence = Vector::sequence(0, 1, 1_000_000);
6980 assert!(sequence.footprint() < 200, "a sequence is two numbers: {}", sequence.footprint());
6981 }
6982
6983 #[test]
6984 fn a_gather_off_a_dictionary_answers_the_same_nulls_either_way_round() {
6985 let words = [Value::Varchar("north".into()), Value::Null, Value::Varchar("south".into())];
6986 let plain: Vec<Value> =
6987 ["north", "east", "south"].iter().map(|word| Value::Varchar((*word).into())).collect();
6988 let clean = Arc::new(Vector::from_values(LogicalType::Varchar, &plain).unwrap());
6989 let dirty = Arc::new(Vector::from_values(LogicalType::Varchar, &words).unwrap());
6990 let codes = vec![0, 1, 2, 0, 1, 2];
6991 let sources = [
6992 Vector::stable_dictionary(codes.clone(), Arc::clone(&clean)).unwrap(),
6993 Vector::stable_dictionary(codes.clone(), Arc::clone(&dirty)).unwrap(),
6994 Vector::stable_dictionary(codes, Arc::clone(&clean))
6995 .unwrap()
6996 .with_validity(Validity::from_run(&[true, true, false, true, true, true])),
6997 ];
6998 // What a gather says about a row has to be what the column it came out of says about the
6999 // row it was taken from, whichever of the two ways the nulls are reached: the mask over the
7000 // codes, or the value a code stands for. The fast answer is only allowed when neither has
7001 // any, and an index past the end is null in both readings.
7002 for source in &sources {
7003 let picks: Vec<u32> = vec![5, 0, 3, 2, 1, 99, 4];
7004 let taken = source.gather(&picks).unwrap();
7005 for (row, &pick) in picks.iter().enumerate() {
7006 assert_eq!(
7007 taken.is_null_at(row),
7008 source.is_null_at(pick as usize),
7009 "row {row} of a gather of {picks:?}"
7010 );
7011 }
7012 }
7013 }
7014
7015 #[test]
7016 fn a_dictionary_read_by_many_cuts_is_counted_about_once_between_them() {
7017 let strings: Vec<Value> = (0..2000)
7018 .map(|at| Value::Varchar(format!("a value well past the inline limit, number {at}")))
7019 .collect();
7020 let values = Arc::new(Vector::from_values(LogicalType::Varchar, &strings).unwrap());
7021 let dictionary = values.footprint();
7022 let cuts: Vec<Vector> = (0..500)
7023 .map(|_| Vector::stable_dictionary(vec![0; 8], Arc::clone(&values)).unwrap())
7024 .collect();
7025 let together: usize = cuts.iter().map(Vector::footprint).sum();
7026 // Five hundred chunks cut out of one page hold one dictionary, and what they say they hold
7027 // has to be about one dictionary. Before this it was five hundred of them, which is a
7028 // reading that grows with the answer and refuses a query holding a gigabyte a budget of
7029 // twenty five.
7030 assert!(
7031 together < dictionary * 2,
7032 "five hundred cuts are not five hundred dictionaries: {together} against {dictionary}"
7033 );
7034 assert!(
7035 together > dictionary / 2,
7036 "the dictionary is still counted: {together} against {dictionary}"
7037 );
7038 }
7039
7040 #[test]
7041 fn a_string_vector_costs_the_bytes_of_its_long_strings() {
7042 let short =
7043 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("red".into())]).unwrap();
7044 let long = "a string well past the sixteen bytes a view holds inline".to_string();
7045 let spilled =
7046 Vector::from_values(LogicalType::Varchar, &[Value::Varchar(long.clone())]).unwrap();
7047 assert!(
7048 spilled.footprint() >= short.footprint() + long.len(),
7049 "the arena is counted: {} against {}",
7050 spilled.footprint(),
7051 short.footprint()
7052 );
7053 }
7054
7055 /// The cases worth checking are the widths where a code straddles a word boundary, which is
7056 /// every width that does not divide sixty four, and the two ends of the range.
7057 #[test]
7058 fn a_narrow_column_packs_and_reads_back_the_same_at_every_width() {
7059 for width in 1..=20u32 {
7060 let span = (1i64 << width) - 1;
7061 let values: Vec<i64> =
7062 (0..1000).map(|row| 1_000_000 + (row * 7919) % (span + 1)).collect();
7063 let flat =
7064 Vector::flat(LogicalType::BigInt, Data::Int64(values.clone().into())).unwrap();
7065 let packed = flat.bit_packed().unwrap();
7066 assert_eq!(packed.len(), flat.len());
7067 assert_eq!(
7068 packed.iter().collect::<Vec<_>>(),
7069 flat.iter().collect::<Vec<_>>(),
7070 "width {width} read back differently"
7071 );
7072 }
7073 }
7074
7075 #[test]
7076 fn the_width_is_the_bits_the_range_needs_and_not_the_bits_the_type_has() {
7077 let values: Vec<i32> = (0..1024).map(|row| 40 + (row * 2560) / 1023).collect();
7078 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
7079 let packed = flat.bit_packed().unwrap();
7080 assert_eq!(packed.form(), Form::BitPacked);
7081 let parts = packed.packed_parts().expect("packed");
7082 assert_eq!(parts.width(), 12, "0 to 2560 is twelve bits");
7083 assert_eq!(parts.base(), 40);
7084 assert!(
7085 packed.footprint() * 2 < flat.footprint(),
7086 "twelve bits against thirty two: {} against {}",
7087 packed.footprint(),
7088 flat.footprint()
7089 );
7090 }
7091
7092 /// The check is worth having in both directions, the way the run length one is. A form that is
7093 /// only ever bigger than what it replaced costs a pass over the column to decide not to use.
7094 #[test]
7095 fn a_column_that_uses_its_whole_type_is_left_flat() {
7096 let values: Vec<i32> = (0..1024).map(|row| row * 2_000_000 - 1_000_000_000).collect();
7097 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
7098 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
7099 }
7100
7101 /// The column that would not write. A thousand values just under `i32::MAX` need ten bits, and
7102 /// based at the smallest of them those ten bits could say a number an `INTEGER` cannot hold, so
7103 /// the range check refused the column and `CREATE TABLE` came back with an internal error. The
7104 /// base is what moves, not the check: it drops to where the widest code the width allows is the
7105 /// largest value the type has.
7106 #[test]
7107 fn a_column_against_the_top_of_its_type_packs_rather_than_being_refused() {
7108 let values: Vec<i32> = (0..4096).map(|row| i32::MAX - (row % 1000)).collect();
7109 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into())).unwrap();
7110 let packed = flat.bit_packed().unwrap();
7111 assert_eq!(packed.form(), Form::BitPacked);
7112 let parts = packed.packed_parts().expect("packed");
7113 assert_eq!(parts.width(), 10, "a thousand values apart is ten bits");
7114 assert_eq!(
7115 parts.base() + i128::from(u64::MAX >> (64 - parts.width())),
7116 i128::from(i32::MAX),
7117 "the widest code the width allows is the largest value the type holds"
7118 );
7119 assert_eq!(
7120 packed.iter().collect::<Vec<_>>(),
7121 flat.iter().collect::<Vec<_>>(),
7122 "the values came back different"
7123 );
7124 }
7125
7126 /// The other end of the same thing. A column that reaches both ends of its type needs every bit
7127 /// the type has, and the only base that leaves room for those codes is the bottom of the type.
7128 #[test]
7129 fn a_column_that_reaches_both_ends_of_its_type_bases_at_the_bottom_of_it() {
7130 let values: Vec<i32> = (0..4096)
7131 .map(|row| if row % 2 == 0 { i32::MIN + row } else { i32::MAX - row })
7132 .collect();
7133 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.clone().into())).unwrap();
7134 // Thirty two bits of codes for a thirty two bit type buys nothing, so the size check leaves
7135 // it flat. What matters is that it is left flat rather than refused.
7136 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
7137 assert_eq!(
7138 packing_base(&LogicalType::Integer, i128::from(i32::MIN), i128::from(i32::MAX), 32),
7139 Some(i128::from(i32::MIN))
7140 );
7141 }
7142
7143 /// A column of one value would pack to no bits at all, and one run is smaller than any packing
7144 /// of it, so the two forms do not fight over that column.
7145 #[test]
7146 fn a_column_of_one_value_is_left_to_the_run_length_form() {
7147 let flat = integers(&[9; 1024]);
7148 assert_eq!(flat.bit_packed().unwrap().form(), Form::Flat);
7149 assert_eq!(flat.run_encoded().unwrap().form(), Form::Rle);
7150 }
7151
7152 #[test]
7153 fn a_string_column_has_no_range_to_pack() {
7154 let text = Vector::from_values(
7155 LogicalType::Varchar,
7156 &[Value::Varchar("red".into()), Value::Varchar("blue".into())],
7157 )
7158 .unwrap();
7159 assert_eq!(text.bit_packed().unwrap().form(), Form::Flat);
7160 }
7161
7162 /// The cut is the reason the form carries a row to start reading at. It stays packed, it shares
7163 /// the same words, and it reads the rows the range asked for.
7164 #[test]
7165 fn a_cut_of_a_packed_column_stays_packed_and_shares_its_bits() {
7166 let values: Vec<i32> = (0..1024).map(|row| 100 + row % 300).collect();
7167 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
7168 let packed = flat.bit_packed().unwrap();
7169 let cut = packed.slice(500, 24).unwrap();
7170 assert_eq!(cut.form(), Form::BitPacked);
7171 assert_eq!(cut.len(), 24);
7172 assert_eq!(
7173 cut.iter().collect::<Vec<_>>(),
7174 flat.slice(500, 24).unwrap().iter().collect::<Vec<_>>()
7175 );
7176 assert!(
7177 cut.footprint() >= packed.footprint(),
7178 "a cut shares the words rather than copying a piece of them"
7179 );
7180 }
7181
7182 #[test]
7183 fn a_gather_of_a_packed_column_comes_out_flat_and_keeps_the_nulls() {
7184 let values: Vec<i32> = (0..64).map(|row| 10 + row).collect();
7185 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
7186 let packed =
7187 flat.bit_packed().unwrap().with_validity(Validity::from_iter(64, |row| row % 3 != 0));
7188 let taken = packed.gather(&[0, 1, 2, 3, 62]).unwrap();
7189 assert_eq!(taken.form(), Form::Flat);
7190 assert_eq!(
7191 taken.iter().collect::<Vec<_>>(),
7192 vec![
7193 Value::Null,
7194 Value::Integer(11),
7195 Value::Integer(12),
7196 Value::Null,
7197 Value::Integer(72)
7198 ]
7199 );
7200 }
7201
7202 /// The pair a comparison kernel asks for before it reads a bit. A literal inside the range has a
7203 /// code and a literal outside it does not, which answers the whole vector at once.
7204 #[test]
7205 fn a_literal_outside_the_packed_range_has_no_code() {
7206 let values: Vec<i32> = (0..256).map(|row| 1000 + row).collect();
7207 let flat = Vector::flat(LogicalType::Integer, Data::Int32(values.into())).unwrap();
7208 let packed = flat.bit_packed().unwrap();
7209 let parts = packed.packed_parts().expect("packed");
7210 assert_eq!(parts.code_of(1000), Some(0));
7211 assert_eq!(parts.code_of(1100), Some(100));
7212 assert_eq!(parts.code_of(999), None);
7213 assert!(parts.ceiling() >= 1255);
7214 assert_eq!(parts.code_of(parts.ceiling() + 1), None);
7215 }
7216
7217 /// The bits arriving from a file rather than from a flat vector, which is what the form is for.
7218 #[test]
7219 fn packed_bits_can_be_handed_in_without_a_flat_vector_to_start_from() {
7220 let packed = Vector::packed(LogicalType::SmallInt, vec![0x0000_0000_0000_4321], 4, 7, 4)
7221 .expect("four codes of four bits");
7222 assert_eq!(
7223 packed.iter().collect::<Vec<_>>(),
7224 vec![Value::SmallInt(8), Value::SmallInt(9), Value::SmallInt(10), Value::SmallInt(11)]
7225 );
7226 }
7227
7228 /// A packed column read as a block, cut at rows that do and do not start a word, at widths
7229 /// that do and do not straddle, answers what a row at a time answers.
7230 #[test]
7231 fn a_packed_block_reads_what_each_row_reads() {
7232 let words: Vec<u64> =
7233 (0..400_u64).map(|word| word.wrapping_mul(0x9E37_79B9_7F4A_7C15)).collect();
7234 for width in [1, 7, 13, 32, 33, 50] {
7235 let whole = Vector::packed(LogicalType::BigInt, words.clone(), width, -1_000, 300)
7236 .expect("enough words for 300 codes");
7237 for (at, len) in [(0, 300), (1, 299), (63, 130), (64, 64), (100, 5), (250, 50)] {
7238 let cut = whole.slice(at, len).expect("a cut inside the column");
7239 let mut block = Vec::new();
7240 assert!(cut.signed_block(&mut block));
7241 let want: Vec<i64> = (0..len)
7242 .map(|row| i64::try_from(cut.signed_at(row).expect("a row")).expect("fits"))
7243 .collect();
7244 assert_eq!(block, want, "width {width} cut at {at} for {len}");
7245 }
7246 }
7247 }
7248
7249 /// A packed column flattened whole, cut at rows that do and do not start a word, answers what
7250 /// a row at a time answers, and a column with nulls in it keeps them.
7251 #[test]
7252 fn a_packed_column_flattened_whole_reads_what_each_row_reads() {
7253 let words: Vec<u64> =
7254 (0..400_u64).map(|word| word.wrapping_mul(0x9E37_79B9_7F4A_7C15)).collect();
7255 for (ty, width) in [
7256 (LogicalType::BigInt, 50),
7257 (LogicalType::Integer, 13),
7258 (LogicalType::SmallInt, 7),
7259 (LogicalType::Date, 1),
7260 ] {
7261 let whole = Vector::packed(ty.clone(), words.clone(), width, -1_000, 300)
7262 .expect("enough words for 300 codes");
7263 for (at, len) in [(0, 300), (1, 299), (63, 130), (64, 64), (100, 5)] {
7264 let cut = whole.slice(at, len).expect("a cut inside the column");
7265 let flat = cut.flatten().expect("a packed column flattens");
7266 assert_eq!(flat.form(), Form::Flat, "{ty:?} cut at {at}");
7267 assert_eq!(
7268 flat.iter().collect::<Vec<_>>(),
7269 cut.iter().collect::<Vec<_>>(),
7270 "{ty:?} width {width} cut at {at} for {len}"
7271 );
7272 }
7273 }
7274 let nulls = Vector::packed(LogicalType::Integer, words, 13, 0, 300)
7275 .expect("300 codes")
7276 .with_validity(Validity::from_iter(300, |row| row % 5 != 0));
7277 let flat = nulls.flatten().expect("flattens");
7278 assert_eq!(flat.iter().collect::<Vec<_>>(), nulls.iter().collect::<Vec<_>>());
7279 assert!(flat.is_null_at(0) && !flat.is_null_at(1));
7280 }
7281
7282 #[test]
7283 fn packed_bits_that_could_not_hold_what_they_claim_are_refused() {
7284 assert!(Vector::packed(LogicalType::Varchar, vec![0], 4, 0, 4).is_err(), "not an integer");
7285 assert!(Vector::packed(LogicalType::Integer, vec![0], 0, 0, 4).is_err(), "no width");
7286 assert!(Vector::packed(LogicalType::Integer, vec![0], 64, 0, 4).is_err(), "too wide");
7287 assert!(Vector::packed(LogicalType::Integer, vec![0], 8, 0, 9).is_err(), "too few words");
7288 assert!(Vector::packed(LogicalType::TinyInt, vec![0], 8, 100, 8).is_err(), "would not fit");
7289 }
7290
7291 /// A column of strings long enough that the payload is in the arena rather than in the views.
7292 fn long_strings(count: usize) -> Vector {
7293 let values: Vec<Value> = (0..count)
7294 .map(|row| {
7295 Value::Varchar(format!("a string too long to sit inside a view, number {row}"))
7296 })
7297 .collect();
7298 Vector::from_values(LogicalType::Varchar, &values).unwrap()
7299 }
7300
7301 #[test]
7302 fn a_string_column_in_view_form_reads_back_the_same_strings() {
7303 let flat = long_strings(40);
7304 let shared = flat.clone().shared_text().unwrap();
7305 assert_eq!(shared.form(), Form::StringView);
7306 assert_eq!(shared.len(), 40);
7307 for row in 0..40 {
7308 assert_eq!(shared.value_at(row), flat.value_at(row), "row {row}");
7309 assert_eq!(shared.text_at(row), flat.text_at(row), "row {row}");
7310 }
7311 }
7312
7313 #[test]
7314 fn a_short_string_is_read_out_of_its_view_and_never_out_of_the_arena() {
7315 let flat = Vector::from_values(
7316 LogicalType::Varchar,
7317 &[Value::Varchar("red".into()), Value::Varchar("green".into()), Value::Null],
7318 )
7319 .unwrap();
7320 let shared = flat.shared_text().unwrap();
7321 // Nothing went to the arena, so the whole column resolves with an empty one.
7322 let (views, arena) = shared.text_parts().unwrap();
7323 assert!(arena.is_empty(), "three short strings need no arena");
7324 assert_eq!(views[0].bytes_in(arena), Some(&b"red"[..]));
7325 assert_eq!(shared.value_at(1), Value::Varchar("green".into()));
7326 assert_eq!(shared.value_at(2), Value::Null, "the validity came across");
7327 }
7328
7329 #[test]
7330 fn a_cut_of_a_view_column_shares_the_arena_rather_than_copying_the_bytes() {
7331 let shared = long_strings(64).shared_text().unwrap();
7332 let cut = shared.slice(16, 8).unwrap();
7333 assert_eq!(cut.form(), Form::StringView, "a cut of views is views");
7334 assert_eq!(cut.len(), 8);
7335 assert_eq!(cut.value_at(0), shared.value_at(16));
7336 assert_eq!(cut.value_at(7), shared.value_at(23));
7337 // The arena is the same bytes at the same address, which is the whole point of the form.
7338 let (_, whole) = shared.text_parts().unwrap();
7339 let (_, piece) = cut.text_parts().unwrap();
7340 assert_eq!(piece.as_ptr(), whole.as_ptr(), "the cut shares the page");
7341 assert_eq!(piece.len(), whole.len());
7342 }
7343
7344 #[test]
7345 fn a_flat_string_column_has_to_copy_the_bytes_its_cut_keeps() {
7346 let flat = long_strings(64);
7347 let cut = flat.slice(16, 8).unwrap();
7348 assert_eq!(cut.form(), Form::Flat);
7349 let (_, whole) = flat.text_parts().unwrap();
7350 let (_, piece) = cut.text_parts().unwrap();
7351 assert!(piece.len() < whole.len(), "the flat cut carries only what it kept");
7352 }
7353
7354 #[test]
7355 fn a_gather_of_a_view_column_keeps_the_form_and_a_flatten_copies_out_of_it() {
7356 let shared = long_strings(32).shared_text().unwrap();
7357 let picked: Vec<u32> = (0..32).step_by(3).collect();
7358 let gathered = shared.gather(&picked).unwrap();
7359 assert_eq!(gathered.form(), Form::StringView, "selecting rows moves views, not bytes");
7360 assert_eq!(gathered.len(), picked.len());
7361 for (row, &from) in picked.iter().enumerate() {
7362 assert_eq!(gathered.value_at(row), shared.value_at(from as usize), "row {row}");
7363 }
7364 let flattened = gathered.flatten().unwrap();
7365 assert_eq!(flattened.form(), Form::Flat);
7366 assert_eq!(flattened.iter().collect::<Vec<_>>(), gathered.iter().collect::<Vec<_>>());
7367 // The flatten is what narrows the bytes, so the arena it built holds only the rows it kept.
7368 let (_, narrowed) = flattened.text_parts().unwrap();
7369 let (_, whole) = shared.text_parts().unwrap();
7370 assert!(narrowed.len() < whole.len(), "flattening lets the page go");
7371 }
7372
7373 #[test]
7374 fn a_null_in_a_view_column_survives_being_gathered_and_flattened() {
7375 let shared = long_strings(8)
7376 .with_validity(Validity::from_iter(8, |row| row % 3 != 0))
7377 .shared_text()
7378 .unwrap();
7379 let gathered = shared.gather(&[0, 1, 2, 3, 4]).unwrap();
7380 let expected =
7381 [Value::Null, shared.value_at(1), shared.value_at(2), Value::Null, shared.value_at(4)];
7382 assert_eq!(gathered.iter().collect::<Vec<_>>(), expected);
7383 assert_eq!(gathered.flatten().unwrap().iter().collect::<Vec<_>>(), expected);
7384 }
7385
7386 #[test]
7387 fn both_string_forms_hand_a_kernel_the_same_views_and_the_same_bytes() {
7388 let flat = long_strings(6);
7389 let shared = flat.clone().shared_text().unwrap();
7390 let (flat_views, flat_arena) = flat.text_parts().unwrap();
7391 let (shared_views, shared_arena) = shared.text_parts().unwrap();
7392 assert_eq!(flat_views.len(), shared_views.len());
7393 for row in 0..6 {
7394 assert_eq!(
7395 flat_views[row].bytes_in(flat_arena),
7396 shared_views[row].bytes_in(shared_arena),
7397 "row {row}"
7398 );
7399 }
7400 // Nothing else answers this, which is what keeps a kernel from taking it for a string column.
7401 assert!(Vector::sequence(0, 1, 4).text_parts().is_none());
7402 assert!(integers(&[1, 2, 3]).text_parts().is_none());
7403 }
7404
7405 #[test]
7406 fn a_column_that_is_not_strings_cannot_be_held_as_views() {
7407 let views = vec![StringView::inline("red")];
7408 let arena = Arc::new(Buffer::new());
7409 let wrong = Vector::string_views(LogicalType::Integer, views, arena);
7410 assert!(wrong.is_err(), "an integer column has no views");
7411 assert_eq!(integers(&[1, 2]).shared_text().unwrap().form(), Form::Flat, "left alone");
7412 }
7413
7414 /// A column with enough repeated structure for a symbol table to find something, which is what
7415 /// a real text column has and a column of random bytes does not.
7416 fn sentences(count: usize) -> Vector {
7417 let values: Vec<Value> = (0..count)
7418 .map(|row| {
7419 Value::Varchar(format!(
7420 "http://example.test/catalogue/section/{}/item/{row}",
7421 row % 7
7422 ))
7423 })
7424 .collect();
7425 Vector::from_values(LogicalType::Varchar, &values).unwrap()
7426 }
7427
7428 #[test]
7429 fn a_compressed_column_reads_back_the_strings_that_went_into_it() {
7430 let flat = sentences(64);
7431 let coded = flat.clone().compressed().unwrap();
7432 assert_eq!(coded.form(), Form::Fsst, "a text column compresses");
7433 assert_eq!(coded.len(), 64);
7434 for row in 0..64 {
7435 assert_eq!(coded.value_at(row), flat.value_at(row), "row {row}");
7436 }
7437 assert_eq!(coded.flatten().unwrap(), flat, "flattening is the column it came from");
7438 }
7439
7440 #[test]
7441 fn compressing_halves_the_bytes_or_the_column_is_left_flat() {
7442 let flat = sentences(200);
7443 let coded = flat.clone().compressed().unwrap();
7444 let parts = coded.coded_parts().expect("compressed");
7445 // Read through the flat column, because the compressed one has no bytes to hand back where
7446 // they are and answers `None` to `text_at` rather than decompressing into a borrow.
7447 assert_eq!(coded.text_at(0), None, "nothing to borrow until it is flattened");
7448 let plain: usize = (0..200).map(|row| flat.text_at(row).map_or(0, str::len)).sum();
7449 let codes: usize = (0..200).map(|row| parts.row(row).map_or(0, <[u8]>::len)).sum();
7450 assert!(codes * FSST_PAYS_AT <= plain, "{codes} codes against {plain} bytes");
7451 // Text with no repeated structure in it gives a table nothing longer than a byte to find,
7452 // so the codes are the bytes and the column stays where it is rather than paying a
7453 // decompression per read to save nothing.
7454 let mut seed = 0x2545_f491_4f6c_dd1du64;
7455 let values: Vec<Value> = (0..256)
7456 .map(|_| {
7457 let mut text = String::new();
7458 while text.len() < 12 {
7459 seed = seed.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
7460 text.push(char::from(b'!' + ((seed >> 33) % 90) as u8));
7461 }
7462 Value::Varchar(text)
7463 })
7464 .collect();
7465 let noise = Vector::from_values(LogicalType::Varchar, &values).unwrap();
7466 assert_eq!(noise.compressed().unwrap().form(), Form::Flat);
7467 }
7468
7469 #[test]
7470 fn a_cut_of_a_compressed_column_shares_the_codes_and_the_table() {
7471 let coded = sentences(64).compressed().unwrap();
7472 let cut = coded.slice(8, 16).unwrap();
7473 assert_eq!(cut.form(), Form::Fsst);
7474 assert_eq!(cut.len(), 16);
7475 for row in 0..16 {
7476 assert_eq!(cut.value_at(row), coded.value_at(8 + row), "row {row}");
7477 }
7478 let (whole, piece) = (coded.coded_parts().unwrap(), cut.coded_parts().unwrap());
7479 assert_eq!(piece.row(0), whole.row(8), "the spans point into the same codes");
7480 }
7481
7482 #[test]
7483 fn a_gather_of_a_compressed_column_stays_compressed_and_keeps_the_nulls() {
7484 let coded = sentences(32)
7485 .with_validity(Validity::from_iter(32, |row| row % 5 != 2))
7486 .compressed()
7487 .unwrap();
7488 let picked: Vec<u32> = (0..32).step_by(2).collect();
7489 let gathered = coded.gather(&picked).unwrap();
7490 assert_eq!(gathered.form(), Form::Fsst, "selecting rows moves spans, not bytes");
7491 for (row, &from) in picked.iter().enumerate() {
7492 assert_eq!(gathered.value_at(row), coded.value_at(from as usize), "row {row}");
7493 }
7494 assert_eq!(
7495 gathered.flatten().unwrap().iter().collect::<Vec<_>>(),
7496 gathered.iter().collect::<Vec<_>>()
7497 );
7498 }
7499
7500 #[test]
7501 fn a_literal_lands_in_the_same_codes_the_row_holding_it_does() {
7502 let coded = sentences(40).compressed().unwrap();
7503 let parts = coded.coded_parts().expect("compressed");
7504 let text = coded.value_at(11);
7505 let Value::Varchar(text) = text else { panic!("a string column reads back strings") };
7506 assert_eq!(parts.encode(text.as_bytes()), parts.row(11).expect("row 11"));
7507 assert_ne!(parts.encode(b"something else entirely"), parts.row(11).unwrap());
7508 }
7509
7510 #[test]
7511 fn codes_that_run_past_what_is_there_are_refused() {
7512 let table = Arc::new(SymbolTable::empty());
7513 let codes = Arc::new(vec![1u8, 2, 3, 4]);
7514 let good = vec![(0u32, 2u32), (2, 4)];
7515 assert!(
7516 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), good, Arc::clone(&table))
7517 .is_ok()
7518 );
7519 let past = vec![(0u32, 9u32)];
7520 assert!(
7521 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), past, Arc::clone(&table))
7522 .is_err(),
7523 "a span past the end of the codes"
7524 );
7525 let backwards = vec![(3u32, 1u32)];
7526 assert!(
7527 Vector::coded(LogicalType::Varchar, Arc::clone(&codes), backwards, Arc::clone(&table))
7528 .is_err(),
7529 "a span that ends before it starts"
7530 );
7531 let wrong = vec![(0u32, 2u32)];
7532 assert!(
7533 Vector::coded(LogicalType::Integer, codes, wrong, table).is_err(),
7534 "an integer column has no codes"
7535 );
7536 }
7537
7538 #[test]
7539 fn a_view_pointing_past_its_arena_is_refused_at_construction() {
7540 let long = "a string too long to sit inside a view";
7541 let arena: Arc<Buffer<u8>> = Arc::new(long.as_bytes().to_vec().into());
7542 let good = vec![StringView::over(long.as_bytes(), 0)];
7543 assert!(Vector::string_views(LogicalType::Varchar, good, Arc::clone(&arena)).is_ok());
7544 let bad = vec![StringView::over(long.as_bytes(), 4)];
7545 assert!(
7546 Vector::string_views(LogicalType::Varchar, bad, arena).is_err(),
7547 "four bytes short of what the view claims"
7548 );
7549 }
7550
7551 /// The form at its simplest: an id per row, and the row it names.
7552 #[test]
7553 fn a_gathered_vector_reads_the_source_row_its_id_names() {
7554 let source = Arc::new(integers(&[10, 20, 30, 40]));
7555 let vector = Vector::gathered(source, Arc::new(vec![3, 0, 3, 1])).unwrap();
7556 assert_eq!(vector.form(), Form::Gathered);
7557 assert_eq!(vector.len(), 4);
7558 assert_eq!(
7559 vector.iter().collect::<Vec<_>>(),
7560 vec![Value::Integer(40), Value::Integer(10), Value::Integer(40), Value::Integer(20)]
7561 );
7562 }
7563
7564 /// Section 8.2's lazy validity. The sentinel is a null and it is not in a mask anywhere, which is
7565 /// what lets a left link join gather null for an unmatched child row without allocating one.
7566 #[test]
7567 fn a_gathered_row_with_no_source_row_is_null_without_a_mask() {
7568 let source = Arc::new(integers(&[10, 20]));
7569 let vector = Vector::gathered(source, Arc::new(vec![1, NO_ROW, 0])).unwrap();
7570 assert!(!vector.validity().has_nulls(vector.len()), "the mask at this level says nothing");
7571 assert!(vector.is_null_at(1));
7572 assert!(!vector.is_null_at(0) && !vector.is_null_at(2));
7573 assert_eq!(
7574 vector.iter().collect::<Vec<_>>(),
7575 vec![Value::Integer(20), Value::Null, Value::Integer(10)]
7576 );
7577 assert!(!vector.none_null(), "a sentinel is a null and the bulk answer has to agree");
7578 }
7579
7580 /// The other half of the same rule: a null in the source is a null here, the way a dictionary's
7581 /// nulls live in its values. Two ways for a row to be null and one answer from `is_null_at`.
7582 #[test]
7583 fn a_gather_of_a_null_source_row_is_null() {
7584 let source = Arc::new(
7585 Vector::from_values(LogicalType::Integer, &[Value::Integer(7), Value::Null]).unwrap(),
7586 );
7587 let vector = Vector::gathered(source, Arc::new(vec![1, 0, 1])).unwrap();
7588 assert!(vector.is_null_at(0) && vector.is_null_at(2));
7589 assert_eq!(vector.value_at(1), Value::Integer(7));
7590 assert!(!vector.none_null());
7591 }
7592
7593 /// An id past the end of the source is the one failure in this form that reads whatever happens
7594 /// to be at that offset rather than failing, so it is refused where the vector is built.
7595 #[test]
7596 fn a_gathered_id_past_the_end_of_its_source_is_refused() {
7597 let source = Arc::new(integers(&[1, 2, 3]));
7598 assert!(Vector::gathered(Arc::clone(&source), Arc::new(vec![0, 3])).is_err());
7599 assert!(
7600 Vector::gathered(source, Arc::new(vec![0, NO_ROW])).is_ok(),
7601 "the sentinel is not an id past the end, it is the absence of one"
7602 );
7603 }
7604
7605 /// A cut is the offset and nothing else, which is what keeps a pipeline from copying the ids once
7606 /// per operator. Both ends stay shared and the rows answer the same.
7607 #[test]
7608 fn cutting_a_gather_moves_where_it_starts_and_copies_nothing() {
7609 let source = Arc::new(integers(&[10, 20, 30, 40, 50]));
7610 let rids = Arc::new(vec![4, 3, 2, 1, 0]);
7611 let vector = Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap();
7612 let held = Arc::strong_count(&rids);
7613 let cut = vector.slice(1, 3).unwrap();
7614 assert_eq!(cut.form(), Form::Gathered);
7615 assert_eq!(
7616 Arc::strong_count(&rids),
7617 held + 1,
7618 "the cut shares the ids rather than copying"
7619 );
7620 assert_eq!(
7621 cut.iter().collect::<Vec<_>>(),
7622 vec![Value::Integer(40), Value::Integer(30), Value::Integer(20)]
7623 );
7624 assert_eq!(cut.gathered_parts().unwrap().1, [3, 2, 1]);
7625 }
7626
7627 /// Composition, which is why this is a body and not an operator. A filter over the output of a
7628 /// link join selects into the ids, and what comes out is one level rather than two.
7629 #[test]
7630 fn a_gather_of_a_gather_resolves_to_one_walk_over_the_source() {
7631 let source = Arc::new(integers(&[10, 20, 30, 40]));
7632 let inner = Vector::gathered(source, Arc::new(vec![3, 2, 1, 0])).unwrap();
7633 let outer = inner.gather(&[0, 3]).unwrap();
7634 assert_eq!(outer.iter().collect::<Vec<_>>(), vec![Value::Integer(40), Value::Integer(10)]);
7635 assert_ne!(outer.form(), Form::Gathered, "the walk stops at what the ids point into");
7636 }
7637
7638 /// The sentinel survives being gathered through, which it has to: a filter over a left link
7639 /// join's output keeps the unmatched rows it kept and they are still null.
7640 #[test]
7641 fn gathering_through_a_sentinel_keeps_it_null() {
7642 let source = Arc::new(integers(&[10, 20]));
7643 let inner = Vector::gathered(source, Arc::new(vec![0, NO_ROW, 1])).unwrap();
7644 let outer = inner.gather(&[1, 2, 1]).unwrap();
7645 assert_eq!(
7646 outer.iter().collect::<Vec<_>>(),
7647 vec![Value::Null, Value::Integer(20), Value::Null]
7648 );
7649 }
7650
7651 /// Section 8.2's dispatch rule, which is the whole difference between this form and a dictionary
7652 /// and is one comparison. A gather off a parent larger than the chunk does not want the
7653 /// dictionary arm of any kernel, and a gather off a source smaller than the chunk does.
7654 #[test]
7655 fn folding_over_the_source_is_worth_it_only_when_the_source_is_the_shorter_one() {
7656 let wide = Arc::new(integers(&(0..64).collect::<Vec<i32>>()));
7657 let narrow = Arc::new(integers(&[1, 2]));
7658 let off_wide = Vector::gathered(wide, Arc::new(vec![0, 1, 2])).unwrap();
7659 let off_narrow = Vector::gathered(narrow, Arc::new(vec![0, 1, 0, 1, 0])).unwrap();
7660 assert!(!off_wide.fold_over_source(), "sixty four source rows to answer three");
7661 assert!(off_narrow.fold_over_source(), "two source rows to answer five");
7662 assert!(!integers(&[1, 2]).fold_over_source(), "and every other form says no");
7663 }
7664
7665 /// Strings, which read their bytes where the source already has them rather than through a value.
7666 /// A gather of a string column is four bytes a row and no arena is touched until something asks.
7667 #[test]
7668 fn a_gathered_string_is_read_where_the_source_put_it() {
7669 let mut column = StringColumn::new();
7670 column.push("red");
7671 column.push("a string too long to sit inside a sixteen byte view");
7672 let source = Arc::new(Vector::flat(LogicalType::Varchar, Data::Varlen(column)).unwrap());
7673 let vector = Vector::gathered(source, Arc::new(vec![1, 0, NO_ROW])).unwrap();
7674 assert_eq!(vector.text_at(0), Some("a string too long to sit inside a sixteen byte view"));
7675 assert_eq!(vector.text_at(1), Some("red"));
7676 assert_eq!(vector.text_at(2), None);
7677 assert_eq!(vector.bytes_at(1), Some(b"red".as_slice()));
7678 assert_eq!(vector.value_at(1), Value::Varchar("red".into()));
7679 }
7680
7681 /// The integer accessor a group by keys through, which has to agree with `value_at` at every
7682 /// row or two rows holding one value land in two groups.
7683 #[test]
7684 fn the_signed_reader_of_a_gather_agrees_with_the_value_reader() {
7685 let source = Arc::new(integers(&[10, 20, 30]));
7686 let vector = Vector::gathered(source, Arc::new(vec![2, NO_ROW, 0, 1])).unwrap();
7687 for row in 0..vector.len() {
7688 let signed = vector.signed_at(row);
7689 match vector.value_at(row) {
7690 Value::Null => assert_eq!(signed, None),
7691 Value::Integer(held) => assert_eq!(signed, Some(i128::from(held))),
7692 other => panic!("an integer column answered {other}"),
7693 }
7694 }
7695 }
7696
7697 /// Flattening gives up the form, which is what it is for, and what comes out holds the values the
7698 /// gather stood for, nulls included.
7699 #[test]
7700 fn flattening_a_gather_writes_out_the_rows_it_pointed_at() {
7701 let source = Arc::new(integers(&[10, 20, 30]));
7702 let vector = Vector::gathered(source, Arc::new(vec![2, NO_ROW, 0])).unwrap();
7703 let flat = vector.flatten().unwrap();
7704 assert_eq!(flat.form(), Form::Flat);
7705 assert_eq!(
7706 flat.iter().collect::<Vec<_>>(),
7707 vec![Value::Integer(30), Value::Null, Value::Integer(10)]
7708 );
7709 }
7710
7711 /// A gather counts a share of what it shares, for the reason a dictionary does. Eight columns
7712 /// gathered off one parent are one parent between them, not eight.
7713 #[test]
7714 fn a_parent_gathered_by_many_columns_is_counted_about_once_between_them() {
7715 let source = Arc::new(integers(&(0..4096).collect::<Vec<i32>>()));
7716 let rids = Arc::new(vec![0; 64]);
7717 let alone = Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap().footprint();
7718 let many = (0..8)
7719 .map(|_| Vector::gathered(Arc::clone(&source), Arc::clone(&rids)).unwrap())
7720 .collect::<Vec<_>>();
7721 let together = many.iter().map(Vector::footprint).sum::<usize>();
7722 assert!(
7723 together < alone * 2,
7724 "eight gathers off one parent reported {together} against {alone} for one"
7725 );
7726 }
7727}