Skip to main content

rudb_vector/
assemble.rs

1//! One vector built out of pieces that each answer a different set of its rows.
2//!
3//! The inverse of [`Vector::gather`]. A gather says where each output row reads from, so it wants
4//! one source and a position per row. An assembly says where each input row writes to, so it takes
5//! several sources and a position per row of each of them, and the rows no source claims come out
6//! null.
7//!
8//! `CASE` is the shape that wants this. Each arm is evaluated over the rows no earlier arm claimed,
9//! which is a correctness rule rather than a performance one, since `CASE WHEN x <> 0 THEN 1 / x
10//! ELSE 0 END` divides by zero on the rows the arm excludes if the arm is evaluated for them. So the
11//! arms produce several short answers that have to end up interleaved in the order the rows arrived
12//! in, and interleaving them is what this is. A join assembling a payload out of a matched side and
13//! an unmatched side wants the same thing.
14//!
15//! # Why it is not a `Vec<Value>`
16//!
17//! Because that is a heap allocation per string and a drop per string afterwards, on top of the
18//! walk through the enum that a `Value` is. On the ClickBench query that groups by a `CASE` over
19//! `Referer`, building the answer that way was about a quarter of the whole query: a quarter of the
20//! instructions were in `value_at`, the `Value` drop glue, `malloc` and `free`, for an answer whose
21//! bytes were already sitting in a string arena and only needed to be pointed at.
22//!
23//! What happens instead is that the pieces are laid end to end into one run of data and the
24//! interleave is then a single gather over that run, which is a typed loop per physical layout and
25//! is the same loop [`Vector::gather`] already goes down. A string's bytes are copied once, into one
26//! arena that was sized before any of them moved.
27//!
28//! # The shape of the interface
29//!
30//! A builder rather than a function taking a slice of pieces, because the caller producing the
31//! pieces is usually borrowing scratch space to produce each one and cannot hold two of them at
32//! once. [`Assembly::place`] reads a piece and is done with it, so the borrow ends between arms and
33//! nothing has to be cloned to keep it alive.
34//!
35//! # The simpler thing next to it
36//!
37//! [`concat()`] is the case where the pieces arrive in order and claim every row, which is what a row
38//! group of a stored table is built out of. An assembly would answer it, and it would pay for a
39//! position per row and a flatten per piece to answer something that is a run of `memcpy`s, so it is
40//! its own function. What the two share is the typed append underneath both of them.
41
42use std::collections::{HashMap, HashSet};
43use std::ops::Range;
44use std::sync::{Arc, Mutex};
45
46use rudb_common::{Error, LogicalType, Result, Spread, Value};
47
48use crate::buffer::Buffer;
49use crate::string::{Arenas, StringColumn, StringView};
50use crate::validity::Validity;
51use crate::vector::{
52    Data, Form, NOWHERE, Vector, copy_of, data_for, empty_data_for, layout_of, placed_of,
53};
54
55/// A vector being built out of pieces, each landing at the positions it is given.
56///
57/// Build one with [`Assembly::new`], call [`Assembly::place`] once per piece, and finish it with
58/// [`Assembly::finish`]. A row no piece claims is null.
59#[derive(Debug)]
60pub struct Assembly {
61    ty: LogicalType,
62    rows: usize,
63    /// The pieces laid end to end, for a type that has a flat layout to lay them in.
64    data: Data,
65    /// Where each output row reads from in `data`, or [`NOWHERE`] for a row no piece claimed.
66    at: Vec<usize>,
67    /// Whether each output row holds a value rather than a null.
68    live: Vec<bool>,
69    /// The fallback for the nested types, which have no run of data to lay anything end to end in.
70    ///
71    /// A `LIST`, a `STRUCT` and a `MAP` are a child vector and a run of entries rather than a run of
72    /// values, so laying two of them end to end is not an append to one buffer and the copy loop
73    /// this is built around has nothing to walk. They go through values, which is what they did
74    /// before this existed and is not a regression for them. Nothing on a ClickBench or TPC-H path
75    /// reaches it.
76    values: Option<Vec<Value>>,
77}
78
79impl Assembly {
80    /// An assembly of `rows` rows of `ty`, with every row null until a piece claims it.
81    ///
82    /// # Errors
83    ///
84    /// If the type is one there is no flat layout for yet, which today means `ARRAY` and `UNION`.
85    pub fn new(ty: LogicalType, rows: usize) -> Result<Self> {
86        let nested =
87            matches!(ty, LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _));
88        let values = if nested { Some(vec![Value::Null; rows]) } else { None };
89        let data = if nested { Data::Empty } else { empty_data_for(&ty)? };
90        Ok(Self { ty, rows, data, at: vec![NOWHERE; rows], live: vec![false; rows], values })
91    }
92
93    /// How many rows the finished vector will have.
94    #[must_use]
95    pub fn rows(&self) -> usize {
96        self.rows
97    }
98
99    /// Writes row `n` of `piece` at output row `positions[n]`, for every row of `piece`.
100    ///
101    /// A row claimed twice takes the value the later call gave it, which is not a case `CASE`
102    /// produces, since its arms run over disjoint sets of rows, and is defined rather than left
103    /// open so that a caller that does it gets an answer instead of whichever of the two the copy
104    /// loop happened to reach.
105    ///
106    /// # Errors
107    ///
108    /// If `piece` has a different number of rows than there are positions, if a position is past the
109    /// end of the assembly, or if `piece` is not of a layout that can be laid after what is already
110    /// there.
111    pub fn place(&mut self, positions: &[u32], piece: &Vector) -> Result<()> {
112        if positions.len() != piece.len() {
113            return Err(Error::internal(format!(
114                "a piece of {} rows placed at {} positions",
115                piece.len(),
116                positions.len()
117            )));
118        }
119        for &row in positions {
120            if row as usize >= self.rows {
121                return Err(Error::internal(format!(
122                    "row {row} placed in an assembly of {} rows",
123                    self.rows
124                )));
125            }
126        }
127        if let Some(values) = &mut self.values {
128            // row at a time: the nested fallback named on the field above. A `LIST`, a `STRUCT` and
129            // a `MAP` are a child vector and a run of entries rather than a run of values, so there
130            // is no buffer to lay one after another and no typed copy to do the interleave with.
131            for (slot, &row) in positions.iter().enumerate() {
132                values[row as usize] = piece.value_at(slot);
133            }
134            return Ok(());
135        }
136        // flatten: the copy loop that does the interleave reads a run of data, and a piece can
137        // arrive constant, dictionary encoded or bit packed. Flattening is itself a typed loop per
138        // layout, so writing the piece out once here is what stops it being read a value at a time
139        // later, and a piece that is already flat is not copied at all.
140        let flat = piece.flatten()?;
141        let Some(from) = flat.data() else {
142            return Err(Error::internal("a flattened vector with no run of data in it"));
143        };
144        let start = self.data.len();
145        let appended = extend(&mut self.data, from, &mut Arenas::default())?;
146        for (slot, &row) in positions.iter().enumerate() {
147            let row = row as usize;
148            // A piece whose data is empty is the untyped null, so it claims its rows and they are
149            // null, which is what leaving them at `NOWHERE` says.
150            if slot < appended {
151                self.at[row] = start + slot;
152                self.live[row] = !piece.is_null_at(slot);
153            } else {
154                self.at[row] = NOWHERE;
155                self.live[row] = false;
156            }
157        }
158        Ok(())
159    }
160
161    /// The finished vector.
162    ///
163    /// # Errors
164    ///
165    /// If the run of data that came out of the pieces is not one the type can hold.
166    pub fn finish(self) -> Result<Vector> {
167        if let Some(values) = self.values {
168            return Vector::from_values(self.ty, &values);
169        }
170        // An untyped null has no run of data to gather out of, and a gather over one would give a
171        // vector of no values calling itself `rows` long.
172        if matches!(self.data, Data::Empty) {
173            return Ok(Vector::constant(self.ty, Value::Null, self.rows));
174        }
175        let validity = Validity::from_run(&self.live);
176        // A string column is finished by permuting views rather than by copying bytes. Sixteen
177        // bytes a row move and the payload stays in the arena the pieces were appended into, which
178        // is the same trade [`crate::vector::Body::Views`] is for a page. It matters most where the
179        // permutation is the identity and the whole thing is a move, which is every column of a
180        // hash join's gathered side.
181        if let Data::Varlen(column) = self.data {
182            let (laid, arena) = column.into_parts();
183            let arena = Arc::new(arena);
184            if straight(&self.at) {
185                return Ok(Vector::string_views(self.ty, laid, arena)?.with_validity(validity));
186            }
187            let views = self
188                .at
189                .iter()
190                .map(|&index| laid.get(index).copied().unwrap_or_else(StringView::empty))
191                .collect();
192            return Ok(Vector::string_views(self.ty, views, arena)?.with_validity(validity));
193        }
194        // Row `n` reads position `n`, so the copy below would be a copy of the run onto itself. An
195        // assembly whose pieces arrived in order and claimed every row is exactly that, and laying
196        // the chunks of a join's gathered side end to end is exactly that.
197        if straight(&self.at) {
198            return Ok(Vector::flat(self.ty, self.data)?.with_validity(validity));
199        }
200        let gathered = copy_of(&self.data, &self.at);
201        Ok(Vector::flat(self.ty, gathered)?.with_validity(validity))
202    }
203}
204
205/// Several vectors of one type laid end to end as one page, or `None` for a run this will not lay.
206///
207/// What a row group of a stored table is built out of. The chunks arrive one at a time and each one
208/// is a separate allocation, and holding a hundred and twenty of them is a hundred and twenty places
209/// a scan of the column has to jump to instead of one run it walks. So they are copied once, into a
210/// page, and every chunk the table hands out afterwards is a window cut out of that page.
211///
212/// # What it will not lay
213///
214/// Anything that is neither a flat run nor a stable dictionary over the same shared values is
215/// answered with `None` rather than with an error, because a caller that gets one has somewhere to
216/// put the pieces and this is a choice about layout rather than a failure. Stable dictionary pieces
217/// sharing one value vector are the encoded exception: laying them is just appending their codes.
218/// An ordinary dictionary has no cross-piece code-space promise, and flattening it would make it
219/// larger and throw away the thing that made it useful, so it is still left to the caller.
220///
221/// # Strings
222///
223/// A flat varchar piece owns its arena, so a window cut out of a flat varchar page copies every byte
224/// of every long string in the window, which is the whole reason [`Form::StringView`] exists.
225/// So the varlen page comes back as views over one shared arena: the bytes are copied once
226/// here and never again, and a cut afterwards moves sixteen bytes a row the same way it does for a
227/// column of integers.
228///
229/// # Errors
230///
231/// If the type has no flat layout, or if a piece holds fewer values than it says it has rows.
232pub fn concat<V: AsRef<Vector>>(ty: &LogicalType, pieces: &[V]) -> Result<Option<Vector>> {
233    let pieces: Vec<&Vector> = pieces.iter().map(AsRef::as_ref).collect();
234    laid(ty, &pieces)
235}
236
237/// One row out of one of several vectors per pick, into one flat vector.
238///
239/// What a link join does with a chunk whose parent rows are in several parts of the parent. Each
240/// pick names a source and a row of it, and a source past the end of `sources`, such as
241/// [`crate::NO_ROW`], is a null. A source is flat or a dictionary over flat values, which is what a
242/// gather out of a stored part hands back for every form the writer uses. The copy is one typed
243/// loop over the picks, so a chunk that lands in a hundred parts costs what a chunk that lands in
244/// one does, rather than a vector and a lay per part.
245///
246/// Sources that are all codes into one stable dictionary give codes into it, because a table keeps
247/// a column of few distinct strings that way and the kernels above compare codes where they would
248/// otherwise compare strings. That was most of TPC-H q12's link join, see
249/// `spec/perf/64-parent-codes-through-the-link.md`.
250///
251/// `None` when a source is in some other form or the type has no flat layout, which the caller
252/// answers by flattening what it has. A string is copied a string at a time, since the sources have
253/// arenas of their own and a view can point into only one.
254///
255/// # Errors
256///
257/// If a source's layout is not the one the type calls for.
258pub fn picked(
259    ty: &LogicalType,
260    sources: &[&Vector],
261    picks: &[(u32, u32)],
262) -> Result<Option<Vector>> {
263    if let Some(codes) = picked_codes(sources, picks)? {
264        return Ok(Some(codes));
265    }
266    // Each source as the flat run its values are in, and the codes into that run for a dictionary.
267    let mut leaves: Vec<(&Vector, Option<&[u32]>)> = Vec::with_capacity(sources.len());
268    for source in sources {
269        match source.form() {
270            Form::Flat => leaves.push((source, None)),
271            Form::Dictionary => match source.dictionary_parts() {
272                Some((codes, values)) if values.form() == Form::Flat => {
273                    leaves.push((values, Some(codes)));
274                }
275                _ => return Ok(None),
276            },
277            _ => return Ok(None),
278        }
279    }
280    let mut datas = Vec::with_capacity(leaves.len());
281    for (leaf, _) in &leaves {
282        let Some(data) = leaf.data() else { return Ok(None) };
283        datas.push(data);
284    }
285    // Every pick resolved to a row of its leaf once, so the typed loop below is a load and nothing
286    // else. A pick that is null anywhere on the way down is `NO_ROW` from here on.
287    let mut live = Vec::with_capacity(picks.len());
288    let picks: Vec<(u32, u32)> = picks
289        .iter()
290        .map(|&(source, row)| {
291            let found = sources.get(source as usize).zip(leaves.get(source as usize)).and_then(
292                |(held, (leaf, codes))| {
293                    let row = row as usize;
294                    if row >= held.len() || !held.validity().is_valid(row) {
295                        return None;
296                    }
297                    let at =
298                        codes.map_or(Some(row), |codes| codes.get(row).map(|&c| c as usize))?;
299                    (at < leaf.len() && leaf.validity().is_valid(at)).then_some(at)
300                },
301            );
302            live.push(found.is_some());
303            // Under the leaf's length, which a vector keeps under `u32::MAX` rows.
304            found.map_or((crate::NO_ROW, 0), |at| (source, at as u32))
305        })
306        .collect();
307    let first = datas.first().copied();
308    macro_rules! picking {
309        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
310            match first {
311                None | Some(Data::Empty) => return Ok(Some(Vector::constant(ty.clone(), Value::Null, picks.len()))),
312                $(Some(Data::$variant(_)) => {
313                    let mut runs = Vec::with_capacity(datas.len());
314                    for data in &datas {
315                        let Data::$variant(values) = data else {
316                            return Ok(None);
317                        };
318                        runs.push(values.as_slice());
319                    }
320                    let mut out: Vec<$native> = Vec::with_capacity(picks.len());
321                    out.extend(picks.iter().map(|&(source, row)| {
322                        runs.get(source as usize)
323                            .and_then(|run| run.get(row as usize))
324                            .copied()
325                            .unwrap_or($zero)
326                    }));
327                    Data::$variant(Buffer::from_vec(out))
328                })+
329                Some(Data::Varlen(_)) => {
330                    let mut runs = Vec::with_capacity(datas.len());
331                    for data in &datas {
332                        let Data::Varlen(values) = data else {
333                            return Ok(None);
334                        };
335                        runs.push(values);
336                    }
337                    let mut out = StringColumn::with_capacity(picks.len());
338                    for &(source, row) in &picks {
339                        match runs.get(source as usize) {
340                            Some(run) => out.push_from(run, row as usize),
341                            None => out.push(""),
342                        };
343                    }
344                    Data::Varlen(out)
345                }
346            }
347        };
348    }
349    let data = crate::for_each_layout!(fixed, picking);
350    let vector = Vector::flat(ty.clone(), data)?;
351    Ok(Some(if live.iter().all(|&alive| alive) {
352        vector
353    } else {
354        vector.with_validity(Validity::from_run(&live))
355    }))
356}
357
358/// The same, copying the pieces of a string column, or of a long fixed width one, on whatever
359/// threads `spread` has.
360///
361/// # Why this exists at all
362///
363/// Because of where one caller lays its pieces. A link join reads the columns of its parent table in
364/// `Stream::prepare`, which runs once before any instance of the pipeline is handed out, so it runs
365/// with the whole thread lease parked and every nanosecond of it is on the pipeline's wall clock.
366/// Reading the parts of the column on the lease was #1575. This is the step after it, and on TPC-H
367/// q12's parent projection at scale factor one it measured as large as the reads: 18 to 73 ms of
368/// laying against 27 to 84 ms of parallel part reads.
369///
370/// # What it parallelises and what it does not
371///
372/// Strings whose pieces each own an arena, which is the one case where laying is a copy of every byte
373/// of the column rather than a copy of a view a row. Everything else goes down the same path
374/// [`concat()`] does, including the two cases that are already nearly free: pieces that share one
375/// arena, where laying is the views alone, and pieces that are adjacent windows of one page, where it
376/// is a handle.
377///
378/// Fixed width pieces are copied on the threads too, once the column is 65,536 rows or more and the
379/// pieces are not windows of one page. On the projection above the integer column laid in 2 to 12
380/// ms and was left serial, but a join laying out its build side lays whole tables: the `orders` side
381/// of TPC-H q9 is a million and a half keys, and one thread copying them was 11 of the 12 ms the
382/// layout took on eight.
383///
384/// The reason the string case is the expensive one is that a flat varchar piece owns its arena, so the
385/// serial walk has to be in order: each piece's views record offsets into the page being built and
386/// those offsets depend on where the previous piece ended. Every piece's arena length is known before
387/// anything is copied, though, so the offsets can be worked out in one pass over the lengths and then
388/// every piece copies its own bytes into its own slice of the page with nothing to wait for.
389///
390/// # Errors
391///
392/// What [`concat()`] errors on, and whatever `spread` reports. A piece is never the thing that fails
393/// here: by the time the copies start the shape has been checked and a copy into a slice of the right
394/// size cannot fail.
395pub fn concat_on<V: AsRef<Vector>>(
396    ty: &LogicalType,
397    pieces: &[V],
398    spread: &Spread<'_>,
399) -> Result<Option<Vector>> {
400    let pieces: Vec<&Vector> = pieces.iter().map(AsRef::as_ref).collect();
401    if let Some(strung) = strung(ty, &pieces, spread)? {
402        return Ok(Some(strung));
403    }
404    if let Some(tiled) = tiled(ty, &pieces, spread)? {
405        return Ok(Some(tiled));
406    }
407    laid(ty, &pieces)
408}
409
410/// How many rows a fixed width column has to have before [`tiled`] spreads its copy. Below it one
411/// thread copies the column in less time than it takes to wake the others.
412const TILED_ROWS: usize = 1 << 16;
413
414/// Fixed width pieces laid into one page with a piece per task.
415///
416/// The page is zeroed rather than grown, the way [`strung`] makes its arena, so every task has its
417/// own slice to write before any of them starts. A page this long is fresh memory from the kernel,
418/// which comes zeroed already, so the zeroing is not a pass over it. What is left is the copy, and
419/// most of what a copy into fresh memory costs is faulting the memory in, which the threads now do
420/// a slice each rather than one of them for the whole page.
421///
422/// `None` for whatever [`laid`] does as well or better: a column shorter than [`TILED_ROWS`], one
423/// piece, a piece that is not flat or holds fewer values than rows, strings, and pieces that are
424/// adjacent windows of one page, which lay as a handle.
425fn tiled(ty: &LogicalType, pieces: &[&Vector], spread: &Spread<'_>) -> Result<Option<Vector>> {
426    let rows: usize = pieces.iter().map(|piece| piece.len()).sum();
427    if pieces.len() < 2 || rows < TILED_ROWS {
428        return Ok(None);
429    }
430    let flat = pieces.iter().all(|piece| {
431        piece.form() == Form::Flat
432            && piece.logical_type() == ty
433            && !piece.is_empty()
434            && piece.data().is_some_and(|data| data.len() == piece.len())
435    });
436    if !flat || adjoined(pieces).is_some() {
437        return Ok(None);
438    }
439    macro_rules! tiles {
440        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
441            match pieces[0].data() {
442                $(Some(Data::$variant(_)) => {
443                    let mut page: Vec<$native> = vec![$zero; rows];
444                    // A slice of the page per piece, each taken exactly once by exactly one task,
445                    // which is the only way a shared closure can hand out a `&mut`.
446                    let mut rest: &mut [$native] = &mut page;
447                    let mut slots = Vec::with_capacity(pieces.len());
448                    for piece in pieces {
449                        let (head, tail) = rest.split_at_mut(piece.len());
450                        slots.push(Mutex::new(head));
451                        rest = tail;
452                    }
453                    let task = |at: usize| {
454                        let Some(Data::$variant(values)) = pieces[at].data() else { return };
455                        let mut slot = slots[at].lock().unwrap_or_else(|poisoned| poisoned.into_inner());
456                        if let Some(values) = values.as_slice().get(..slot.len()) {
457                            slot.copy_from_slice(values);
458                        }
459                    };
460                    spread(pieces.len(), &task)?;
461                    drop(slots);
462                    Data::$variant(Buffer::from_vec(page))
463                })+
464                _ => return Ok(None),
465            }
466        };
467    }
468    // The first piece's layout is the page's, and a piece of any other layout is not this type.
469    if pieces.iter().any(|piece| layout_of_piece(piece) != layout_of_piece(pieces[0])) {
470        return Ok(None);
471    }
472    let data = crate::for_each_layout!(fixed, tiles);
473    let validity = run_of(pieces, rows);
474    Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity).into_pages()))
475}
476
477/// The layout of a piece's data, for telling that every piece of a column has the same one.
478fn layout_of_piece(piece: &Vector) -> Option<std::mem::Discriminant<Data>> {
479    piece.data().map(std::mem::discriminant)
480}
481
482/// String pieces that each own an arena, laid into one page with a piece per task.
483///
484/// `None` is not a refusal to lay. It says these pieces are not the shape this handles and that
485/// [`laid`] should have them, which is every case where laying is not a copy of the bytes.
486fn strung(ty: &LogicalType, pieces: &[&Vector], spread: &Spread<'_>) -> Result<Option<Vector>> {
487    let Some(columns) = apart(ty, pieces) else {
488        return Ok(None);
489    };
490    // One pass over the lengths, which is the pass that makes the copies independent. `base` is where
491    // this piece's bytes land in the page and so is what its views are shifted by, and `from` is
492    // where its views land among the views.
493    let mut bases = Vec::with_capacity(columns.len());
494    let mut bytes = 0usize;
495    let mut rows = 0usize;
496    for column in &columns {
497        bases.push((bytes, rows));
498        bytes += column.arena().len();
499        rows += column.len();
500    }
501
502    // Zeroed rather than grown, so the page is one allocation of the right size and every task has
503    // somewhere to write before any of them starts. The zeroing of the arena costs nothing worth
504    // measuring because it is whole pages the allocator hands over untouched, and the views are
505    // sixteen bytes a row of `memset` that the copy below would be writing over anyway.
506    let mut arena = vec![0u8; bytes];
507    let mut views = vec![StringView::empty(); rows];
508    // Cut into a piece of arena and a piece of views per piece, because a task writing through a
509    // shared closure cannot be handed a `&mut` any other way and these are disjoint by construction.
510    // The lock is a formality: each one is taken exactly once by exactly one task.
511    let mut arena_rest: &mut [u8] = &mut arena;
512    let mut views_rest: &mut [StringView] = &mut views;
513    let mut slots = Vec::with_capacity(columns.len());
514    for column in &columns {
515        let (arena_head, arena_tail) = arena_rest.split_at_mut(column.arena().len());
516        let (views_head, views_tail) = views_rest.split_at_mut(column.len());
517        slots.push(Mutex::new((arena_head, views_head)));
518        arena_rest = arena_tail;
519        views_rest = views_tail;
520    }
521
522    let task = |at: usize| {
523        let column = columns[at];
524        let (base, _) = bases[at];
525        let mut slot = slots[at].lock().unwrap_or_else(|poisoned| poisoned.into_inner());
526        let (into_arena, into_views) = &mut *slot;
527        into_arena.copy_from_slice(column.arena());
528        let base = base as u64;
529        for (slot, view) in into_views.iter_mut().zip(column.views()) {
530            *slot = view.shifted(base);
531        }
532    };
533    spread(columns.len(), &task)?;
534    drop(slots);
535
536    let validity = run_of(pieces, rows);
537    let page = Vector::string_views(ty.clone(), views, Arc::new(Buffer::from(arena)))?;
538    Ok(Some(page.with_validity(validity)))
539}
540
541/// The pieces as string columns, when they are strings that each hold an arena of their own.
542///
543/// Four things are being asked, and each of them is a case that belongs to [`laid`] rather than a
544/// case this does worse.
545///
546/// More than one piece, because one piece is laid by handing its own arena back and copying it into a
547/// page of the same size would be a copy for nothing.
548///
549/// Flat pieces of this type, which is what [`laid`] requires of the general path anyway, and which
550/// rules out the stable dictionary and shared view shapes it answers earlier and more cheaply.
551///
552/// An arena the piece's own views read nearly all of. [`laid`] copies an arena whole only when it is
553/// mostly read and otherwise copies a string at a time, because a filtered cut of a Parquet page
554/// would drag the rest of the page along for as long as the result lives. A string at a time still
555/// writes a piece's bytes into a piece sized run, so it could be done here too, but a decoded part of
556/// a stored column is always entirely read and the other shape is not what this is for.
557///
558/// Arenas that are all different. Pieces sharing an arena are what a cut up page is, and [`laid`]
559/// copies a shared one once and shifts the views of every piece that points into it. Copying it once
560/// per piece here would be correct and would use more memory than the serial path, which is not a
561/// trade worth making for threads.
562fn apart<'a>(ty: &LogicalType, pieces: &[&'a Vector]) -> Option<Vec<&'a StringColumn>> {
563    if pieces.len() < 2 {
564        return None;
565    }
566    let mut columns = Vec::with_capacity(pieces.len());
567    let mut seen = HashSet::with_capacity(pieces.len());
568    for piece in pieces {
569        if piece.form() != Form::Flat || piece.logical_type() != ty || piece.is_empty() {
570            return None;
571        }
572        let Some(Data::Varlen(column)) = piece.data() else {
573            return None;
574        };
575        if !column.mostly_read() || !seen.insert(column.arena().as_ptr() as usize) {
576            return None;
577        }
578        columns.push(column);
579    }
580    Some(columns)
581}
582
583/// The body of [`concat()`], over borrowed pieces.
584///
585/// A caller holding its pieces inside chunks would otherwise clone each one into a list, and a
586/// clone of a flat vector that owns its values copies every one of them, which is the copy this
587/// function exists to make once.
588fn laid(ty: &LogicalType, pieces: &[&Vector]) -> Result<Option<Vector>> {
589    if pieces.is_empty() {
590        return Ok(None);
591    }
592    let rows = pieces.iter().map(|piece| piece.len()).sum();
593    let shared = pieces[0].stable_dictionary_parts().map(|(_, values)| values).filter(|values| {
594        pieces.iter().all(|piece| {
595            piece.logical_type() == ty
596                && !piece.is_empty()
597                && piece
598                    .stable_dictionary_parts()
599                    .is_some_and(|(_, held)| Arc::ptr_eq(held, values))
600        })
601    });
602    if let Some(values) = shared {
603        let mut codes = Vec::with_capacity(rows);
604        for piece in pieces {
605            if let Some((held, _)) = piece.stable_dictionary_parts() {
606                codes.extend_from_slice(held);
607            }
608        }
609        let validity = run_of(pieces, rows);
610        return Ok(Some(
611            Vector::stable_dictionary(codes, Arc::clone(values))?.with_validity(validity),
612        ));
613    }
614    // String views that all point into one arena, which is what a string column gathered out of a
615    // join's build side is, chunk after chunk. Laid end to end they are the same views over the same
616    // arena, so sixteen bytes a row move and no string is copied.
617    if let Some(arena) = pieces[0].shared_views().map(|(_, arena)| arena).filter(|arena| {
618        pieces.iter().all(|piece| {
619            piece.logical_type() == ty
620                && piece.shared_views().is_some_and(|(_, held)| Arc::ptr_eq(held, arena))
621        })
622    }) {
623        let mut views = Vec::with_capacity(rows);
624        for piece in pieces {
625            if let Some((held, _)) = piece.shared_views() {
626                views.extend_from_slice(held);
627            }
628        }
629        let validity = run_of(pieces, rows);
630        return Ok(Some(
631            Vector::string_views(ty.clone(), views, Arc::clone(arena))?.with_validity(validity),
632        ));
633    }
634    // Checked before anything is copied, because the fallback is for the caller to keep the pieces
635    // it already has and a half built page would be work thrown away.
636    let laid = pieces
637        .iter()
638        .all(|piece| piece.form() == Form::Flat && piece.logical_type() == ty && !piece.is_empty());
639    if !laid {
640        return Ok(None);
641    }
642    if let Some(data) = adjoined(pieces) {
643        let validity = run_of(pieces, rows);
644        return Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity)));
645    }
646    // Sized before the first value moves, so the page is one allocation and holds no more than the
647    // rows that went into it. Growing from empty instead ends at the next power of two, which on a
648    // full row group is eight thousand values of slack carried for the life of the table.
649    let mut data = data_for(ty, rows)?;
650    let mut arenas = arenas_of(pieces);
651    for piece in pieces {
652        let from = piece
653            .data()
654            .ok_or_else(|| Error::internal("a flat vector with no run of data in it"))?;
655        let appended = extend(&mut data, from, &mut arenas)?;
656        if appended != piece.len() {
657            return Err(Error::internal(format!(
658                "a piece of {} rows laid {appended} values end to end",
659                piece.len()
660            )));
661        }
662    }
663    let validity = run_of(pieces, rows);
664    if let Data::Varlen(column) = data {
665        let (views, arena) = column.into_parts();
666        let page = Vector::string_views(ty.clone(), views, Arc::new(arena))?;
667        return Ok(Some(page.with_validity(validity)));
668    }
669    Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity).into_pages()))
670}
671
672/// Several vectors of one type laid end to end and then read back in `order`.
673///
674/// What a sort is. Row `n` of the answer is row `order[n]` of the pieces laid end to end, so the
675/// pieces are laid once and the answer is one gather, which writes the answer front to back. An
676/// [`Assembly`] answers the same question the other way round, with a position per input row that
677/// it scatters into, and that costs it a map of the whole column and a scatter per column, which for
678/// a sort is the same permutation worked out again for every column. Here the caller works it out
679/// once and every column reads it.
680///
681/// A string column comes back as views over the one arena its bytes were laid into, the same as
682/// [`concat()`] gives, so the gather moves sixteen bytes a row.
683///
684/// # Errors
685///
686/// If the type has no layout this can lay, if a piece holds fewer values than it has rows, or if
687/// an entry of `order` is past the end of the pieces.
688pub fn interleave(ty: &LogicalType, pieces: &[Vector], order: &[usize]) -> Result<Vector> {
689    interleave_placed(ty, pieces, order, None)
690}
691
692/// The same as [`interleave()`], writing each row where it goes rather than reading each row from
693/// where it came when the caller also has `inverse`, the place in the answer of every row laid.
694///
695/// Which of the two is cheaper is decided by how many ascending runs `order` is made of, and only
696/// the caller knows that without a pass of its own. Reading through `order` jumps between the runs,
697/// so when there are few of them each row of the answer costs a cache line of the laid column to
698/// use eight bytes of it, and with a dozen columns on a dozen threads that is the memory bus full.
699/// Writing through `inverse` reads the laid column front to back and writes one stream per run,
700/// each of them front to back too. On SF1 `lineitem` sorted by ship month, 84 runs, twelve columns
701/// on twelve threads went from 145ms to 50ms in a standalone test of just these loops. With runs
702/// in the tens of thousands the two come out even and with a run every few rows the writes are the
703/// ones that miss, so a caller with an order like that passes `None`.
704///
705/// This is not the scatter #1365 took out. That one built a map of the whole column per column to
706/// scatter into. This one writes into the answer's own run and the inverse is worked out once.
707///
708/// # Errors
709///
710/// As [`interleave()`], or if `inverse` is given and `order` and `inverse` are not both as long as
711/// the pieces, which is the only shape in which one can be the other turned round.
712pub fn interleave_placed(
713    ty: &LogicalType,
714    pieces: &[Vector],
715    order: &[usize],
716    inverse: Option<&[u32]>,
717) -> Result<Vector> {
718    let rows: usize = pieces.iter().map(Vector::len).sum();
719    if let Some(inverse) = inverse.filter(|inverse| inverse.len() != rows || order.len() != rows) {
720        return Err(Error::internal(format!(
721            "{} places and {} positions for a permutation of {rows} rows",
722            inverse.len(),
723            order.len()
724        )));
725    }
726    if let Some(&past) = order.iter().find(|&&index| index >= rows) {
727        return Err(Error::internal(format!("row {past} read out of pieces of {rows} rows")));
728    }
729    if matches!(ty, LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _)) {
730        // row at a time: the nested types, for the reason `Assembly::values` gives. They have no run
731        // of data to lay end to end and no typed copy to gather with.
732        let laid: Vec<Value> = pieces
733            .iter()
734            .flat_map(|piece| (0..piece.len()).map(|row| piece.value_at(row)))
735            .collect();
736        let values: Vec<Value> =
737            order.iter().map(|&index| laid.get(index).cloned().unwrap_or(Value::Null)).collect();
738        return Vector::from_values(ty.clone(), &values);
739    }
740    if let Some(merged) = merged_dictionary(ty, pieces, order, inverse)? {
741        return Ok(merged);
742    }
743    if let Some(inverse) = inverse {
744        if let Some(placed) = placed_strings(ty, pieces, inverse, 0..rows)? {
745            return Ok(placed);
746        }
747        if let Some(placed) = placed_fixed(ty, pieces, inverse)? {
748            return Ok(placed);
749        }
750    }
751    let mut data = data_for(ty, rows)?;
752    // The untyped null, which has no run of data to lay or to gather out of, and is null whatever
753    // the order is.
754    if matches!(data, Data::Empty) {
755        return Ok(Vector::constant(ty.clone(), Value::Null, order.len()));
756    }
757    let mut arenas = arenas_of(pieces);
758    // Reserved whole, because an arena grown by doubling as the pieces arrive copies what it holds
759    // at every step and faults each new allocation in again. The sorted SF1 comments lay 183MB.
760    if let Data::Varlen(column) = &mut data {
761        column.reserve_bytes(arenas.bytes());
762    }
763    // Each piece's validity, taken after it is flattened, because a constant null keeps its null in
764    // its value rather than in its mask and a flattened one has it in the mask like any other row.
765    let mut masks = Vec::with_capacity(pieces.len());
766    for piece in pieces {
767        // flatten: the gather below reads one run of data, and a piece can arrive dictionary
768        // encoded, constant or bit packed. The flatten is a typed loop per layout, a flat piece is
769        // not copied by it, and one piece is flattened at a time so a column is never held twice.
770        let flat = piece.flatten()?;
771        let from = flat.data().ok_or_else(|| Error::internal("a flattened vector with no data"))?;
772        let appended = extend(&mut data, from, &mut arenas)?;
773        if appended != piece.len() {
774            return Err(Error::internal(format!(
775                "a piece of {} rows laid {appended} values end to end",
776                piece.len()
777            )));
778        }
779        masks.push((flat.len(), flat.validity().clone()));
780    }
781    let laid = if masks.iter().all(|(_, mask)| matches!(mask, Validity::AllValid)) {
782        Validity::AllValid
783    } else {
784        let mut live = Vec::with_capacity(rows);
785        for (len, mask) in &masks {
786            // row at a time: a bit a row for the mixed case, once a column rather than once a
787            // piece of every column the way it would be read otherwise.
788            live.extend((0..*len).map(|row| mask.is_valid(row)));
789        }
790        Validity::from_run(&live)
791    };
792    if laid.count_valid(rows) == 0 {
793        return Ok(Vector::constant(ty.clone(), Value::Null, order.len()));
794    }
795    let validity = match (laid, inverse) {
796        (Validity::AllValid, _) => Validity::AllValid,
797        (laid, Some(inverse)) => {
798            let mut live = vec![false; order.len()];
799            for (row, &to) in inverse.iter().enumerate() {
800                if let Some(slot) = live.get_mut(to as usize) {
801                    *slot = laid.is_valid(row);
802                }
803            }
804            Validity::from_run(&live)
805        }
806        (laid, None) => Validity::from_iter(order.len(), |row| {
807            order.get(row).is_some_and(|&index| laid.is_valid(index))
808        }),
809    };
810    if let Data::Varlen(column) = data {
811        let (views, arena) = column.into_parts();
812        let gathered = match inverse {
813            Some(inverse) => {
814                let mut placed = vec![StringView::empty(); order.len()];
815                for (view, &to) in views.iter().zip(inverse) {
816                    if let Some(slot) = placed.get_mut(to as usize) {
817                        *slot = *view;
818                    }
819                }
820                placed
821            }
822            None => order
823                .iter()
824                .map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
825                .collect(),
826        };
827        return Ok(
828            Vector::string_views(ty.clone(), gathered, Arc::new(arena))?.with_validity(validity)
829        );
830    }
831    let data = match inverse {
832        Some(inverse) => placed_of(&data, inverse),
833        None => copy_of(&data, order),
834    };
835    Ok(Vector::flat(ty.clone(), data)?.with_validity(validity))
836}
837
838/// A fixed width column written through `inverse` straight from its pieces, or `None` for a type
839/// whose layout is not fixed width.
840///
841/// The general path lays every piece end to end first and then writes that run through `inverse`,
842/// and it flattens every piece that is not flat on the way. On the sorted SF1 `lineitem` those were
843/// three passes over every column: the flatten was 7 percent of the busy samples, mostly decoding
844/// the dictionary pieces the Parquet reader hands on, the laying was 5 percent more, and the write
845/// through `inverse` was 6.5. Here each piece is written to its places as it is read, and a
846/// dictionary piece whose values are a flat run with no nulls is written by looking each code up,
847/// so a column is read once and written once. A piece in any other form is flattened on its own and
848/// then written the same way.
849fn placed_fixed(ty: &LogicalType, pieces: &[Vector], inverse: &[u32]) -> Result<Option<Vector>> {
850    let rows = inverse.len();
851    let mut live: Option<Vec<bool>> = None;
852    let mut base = 0;
853    // The nulls of one piece written to their places, once a piece with any has arrived.
854    let mut mark = |mask: &Validity, places: &[u32]| {
855        if matches!(mask, Validity::AllValid) {
856            return;
857        }
858        let live = live.get_or_insert_with(|| vec![true; rows]);
859        for (row, &to) in places.iter().enumerate() {
860            if let Some(slot) = live.get_mut(to as usize) {
861                *slot = mask.is_valid(row);
862            }
863        }
864    };
865    macro_rules! placed {
866        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
867            match data_for(ty, 0)? {
868                $(Data::$variant(_) => {
869                    let mut out: Vec<$native> = vec![$zero; rows];
870                    for piece in pieces {
871                        let len = piece.len();
872                        let places = inverse.get(base..base + len).ok_or_else(|| {
873                            Error::internal("pieces longer than the places they are written to")
874                        })?;
875                        base += len;
876                        let coded = piece.dictionary_parts().and_then(|(codes, values)| {
877                            match (values.form(), values.validity(), values.data()) {
878                                (Form::Flat, Validity::AllValid, Some(Data::$variant(held))) => {
879                                    Some((codes, held.as_slice()))
880                                }
881                                _ => None,
882                            }
883                        });
884                        if let Some((codes, held)) = coded {
885                            for (&code, &to) in codes.iter().zip(places) {
886                                if let (Some(slot), Some(value)) =
887                                    (out.get_mut(to as usize), held.get(code as usize))
888                                {
889                                    *slot = *value;
890                                }
891                            }
892                            mark(piece.validity(), places);
893                            continue;
894                        }
895                        // A flat piece is read where it lies.
896                        let flat;
897                        let piece = if piece.form() == Form::Flat {
898                            piece
899                        } else {
900                            // flatten: a piece that is neither flat nor a dictionary over a flat
901                            // run, which a sort's input rarely is.
902                            flat = piece.flatten()?;
903                            &flat
904                        };
905                        let Some(Data::$variant(values)) = piece.data() else {
906                            return Err(Error::internal(format!(
907                                "a piece of {} laid into a column of {ty}",
908                                piece.logical_type()
909                            )));
910                        };
911                        if values.len() != len {
912                            return Err(Error::internal(format!(
913                                "a piece of {len} rows holds {} values",
914                                values.len()
915                            )));
916                        }
917                        for (value, &to) in values.iter().zip(places) {
918                            if let Some(slot) = out.get_mut(to as usize) {
919                                *slot = *value;
920                            }
921                        }
922                        mark(piece.validity(), places);
923                    }
924                    let validity = match live {
925                        None => Validity::AllValid,
926                        Some(live) if !live.contains(&true) => {
927                            return Ok(Some(Vector::constant(ty.clone(), Value::Null, rows)));
928                        }
929                        Some(live) => Validity::from_run(&live),
930                    };
931                    let data = Data::$variant(Buffer::from_vec(out));
932                    Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity)))
933                })+
934                _ => Ok(None),
935            }
936        };
937    }
938    crate::for_each_layout!(fixed, placed)
939}
940
941/// The string column written through `inverse` into an arena laid in the order of the result.
942///
943/// Laying the pieces' arenas end to end and pushing the views keeps the bytes in the order they
944/// arrived, so everything after the sort that reads the strings in their new order reads the arena
945/// at random. On the sorted `lineitem` that is `l_comment`, whose distinct count in the append
946/// took 550 to 1570 ms of CPU across the threads at full width, nearly all of it waiting on memory,
947/// and takes 190 to 250 ms with the arena in order. A table built by the sort also keeps its strings
948/// in the order it is read in from then on. Here each piece is read once in order, every long
949/// string's length is written to its place first so a prefix sum gives each one its offset, and
950/// then its bytes are copied there. A sort's output is a few long runs of its input, so both
951/// passes write a few streams that each move forward.
952///
953/// `None` when the column is not a string, or when a piece is not flat views and has to be
954/// flattened on the general path first.
955fn placed_strings(
956    ty: &LogicalType,
957    pieces: &[Vector],
958    inverse: &[u32],
959    range: Range<usize>,
960) -> Result<Option<Vector>> {
961    if !strings_placeable(ty, pieces) {
962        return Ok(None);
963    }
964    let first = range.start;
965    let rows = range.len();
966    // The place of a row in this range, or `None` for a row another range lays.
967    let local = |to: u32| (to as usize).checked_sub(first).filter(|&at| at < rows);
968    let mut offsets = vec![0u64; rows + 1];
969    let mut places = inverse.iter();
970    for piece in pieces {
971        let (views, _) = piece.text_parts().unwrap_or_default();
972        for (view, &to) in views.iter().zip(places.by_ref()) {
973            if view.is_inline() {
974                continue;
975            }
976            if let Some(slot) = local(to).and_then(|at| offsets.get_mut(at + 1)) {
977                *slot = view.len() as u64;
978            }
979        }
980    }
981    let mut total = 0;
982    for offset in &mut offsets {
983        total += *offset;
984        *offset = total;
985    }
986    let mut arena =
987        vec![0u8; usize::try_from(total).map_err(|_| Error::internal("an arena too large"))?];
988    let mut placed = vec![StringView::empty(); rows];
989    let mut live = vec![true; rows];
990    let mut places = inverse.iter();
991    for piece in pieces {
992        let (views, from) = piece.text_parts().unwrap_or_default();
993        let validity = piece.validity();
994        for (row, (view, &to)) in views.iter().zip(places.by_ref()).enumerate() {
995            let Some(to) = local(to) else {
996                continue;
997            };
998            if !validity.is_valid(row) {
999                if let Some(slot) = live.get_mut(to) {
1000                    *slot = false;
1001                }
1002                continue;
1003            }
1004            let (Some(bytes), Some(&at), Some(slot)) =
1005                (view.bytes_in(from), offsets.get(to), placed.get_mut(to))
1006            else {
1007                continue;
1008            };
1009            if view.is_inline() {
1010                *slot = *view;
1011                continue;
1012            }
1013            if let Some(into) = arena.get_mut(at as usize..at as usize + bytes.len()) {
1014                into.copy_from_slice(bytes);
1015            }
1016            *slot = StringView::over(bytes, at);
1017        }
1018    }
1019    let validity = if live.iter().all(|&valid| valid) {
1020        Validity::AllValid
1021    } else {
1022        Validity::from_run(&live)
1023    };
1024    let vector = Vector::string_views(ty.clone(), placed, Arc::new(Buffer::from_vec(arena)))?;
1025    Ok(Some(vector.with_validity(validity)))
1026}
1027
1028/// Whether [`interleave_placed`] lays this string column through [`placed_string_rows`], which is
1029/// when it is a string and every piece is flat views.
1030#[must_use]
1031pub fn strings_placeable(ty: &LogicalType, pieces: &[Vector]) -> bool {
1032    matches!(ty, LogicalType::Varchar | LogicalType::Blob)
1033        && pieces.iter().all(|piece| piece.text_parts().is_some())
1034}
1035
1036/// The rows in `range` of the string column [`interleave_placed`] would lay through `inverse`,
1037/// with an arena of their own.
1038///
1039/// This is how a sort builds one long string column on several threads. Each range reads every
1040/// piece and all of `inverse` and copies only its own strings, so each has a few forward streams
1041/// to write the way the whole column does, and the ranges share nothing they write.
1042///
1043/// # Errors
1044///
1045/// If `inverse` is not as long as the pieces or `range` runs past it, or if a piece is not flat
1046/// views, which [`strings_placeable`] says beforehand.
1047pub fn placed_string_rows(
1048    ty: &LogicalType,
1049    pieces: &[Vector],
1050    inverse: &[u32],
1051    range: Range<usize>,
1052) -> Result<Vector> {
1053    let rows: usize = pieces.iter().map(Vector::len).sum();
1054    if inverse.len() != rows || range.end > rows || range.start > range.end {
1055        return Err(Error::internal(format!(
1056            "rows {range:?} of {} places for {rows} rows",
1057            inverse.len()
1058        )));
1059    }
1060    placed_strings(ty, pieces, inverse, range)?
1061        .ok_or_else(|| Error::internal("a string column placed that is not flat views"))
1062}
1063
1064/// How many rows a merged dictionary entry has to stand for on average before a string column is
1065/// gathered as codes rather than as views.
1066///
1067/// A Parquet file carries one dictionary per row group, so a sorted `lineitem` column arrives as
1068/// 733 pieces over 49 dictionaries. The low cardinality columns have 98 to 343 entries between all
1069/// of them, and merging those is nothing next to gathering six million views. A column whose
1070/// dictionaries are nearly as long as the column is one the writer should not have encoded, and
1071/// merging it would hash every value to save nothing, so it is gathered flat.
1072const ROWS_PER_MERGED_ENTRY: usize = 8;
1073
1074/// The string column gathered by `order` as one dictionary, when every piece is a dictionary.
1075///
1076/// The pieces' dictionaries are merged into one with each distinct value once, so the codes mean
1077/// the same thing on every page cut from the result and the result is a stable dictionary. The
1078/// gather is then four bytes a row instead of sixteen, and the append after the sort gets the
1079/// dictionary the scan handed up rather than a flat column it has to read a row at a time.
1080///
1081/// `None` when the column is not a string, when any piece is not a dictionary or has nulls at its
1082/// own level, or when the dictionaries are too long for the merge to pay.
1083fn merged_dictionary(
1084    ty: &LogicalType,
1085    pieces: &[Vector],
1086    order: &[usize],
1087    inverse: Option<&[u32]>,
1088) -> Result<Option<Vector>> {
1089    if !matches!(ty, LogicalType::Varchar | LogicalType::Blob) || pieces.is_empty() {
1090        return Ok(None);
1091    }
1092    let rows: usize = pieces.iter().map(Vector::len).sum();
1093    let mut dictionaries: Vec<&Arc<Vector>> = Vec::new();
1094    let mut which = Vec::with_capacity(pieces.len());
1095    let mut entries = 0;
1096    for piece in pieces {
1097        let Some((_, values)) = piece.shared_dictionary_parts() else {
1098            return Ok(None);
1099        };
1100        if !matches!(piece.validity(), Validity::AllValid) {
1101            return Ok(None);
1102        }
1103        let at = match dictionaries.iter().position(|seen| Arc::ptr_eq(seen, values)) {
1104            Some(at) => at,
1105            None => {
1106                entries += values.len();
1107                if entries.saturating_mul(ROWS_PER_MERGED_ENTRY) > rows {
1108                    return Ok(None);
1109                }
1110                dictionaries.push(values);
1111                dictionaries.len() - 1
1112            }
1113        };
1114        which.push(at);
1115    }
1116    // A null entry has no bytes, so it merges with every other null entry.
1117    let mut merged: HashMap<Option<&[u8]>, u32> = HashMap::new();
1118    let mut values = Vec::new();
1119    let mut remaps = Vec::with_capacity(dictionaries.len());
1120    for dictionary in &dictionaries {
1121        let mut remap = Vec::with_capacity(dictionary.len());
1122        // row at a time: over the dictionary entries, a few hundred of them against millions of
1123        // rows, and only the first sighting of each value becomes one.
1124        for entry in 0..dictionary.len() {
1125            let next = u32::try_from(values.len())
1126                .map_err(|_| Error::internal("a merged dictionary past four billion entries"))?;
1127            let code = *merged.entry(dictionary.bytes_at(entry)).or_insert_with(|| {
1128                values.push(dictionary.value_at(entry));
1129                next
1130            });
1131            remap.push(code);
1132        }
1133        remaps.push(remap);
1134    }
1135    let mut laid = Vec::with_capacity(rows);
1136    for (piece, &at) in pieces.iter().zip(&which) {
1137        let (codes, _) = piece
1138            .dictionary_parts()
1139            .ok_or_else(|| Error::internal("a dictionary piece lost its dictionary"))?;
1140        let remap = &remaps[at];
1141        laid.extend(codes.iter().map(|&code| remap[code as usize]));
1142    }
1143    // Written through the inverse when there is one, for the reason `interleave_placed` gives: a
1144    // few long runs read through `order` spend a cache line on every four byte code.
1145    let codes = match inverse {
1146        Some(inverse) => {
1147            let mut codes = vec![0u32; order.len()];
1148            for (&code, &to) in laid.iter().zip(inverse) {
1149                if let Some(slot) = codes.get_mut(to as usize) {
1150                    *slot = code;
1151                }
1152            }
1153            codes
1154        }
1155        None => order.iter().map(|&index| laid[index]).collect(),
1156    };
1157    let values = Vector::from_values(ty.clone(), &values)?;
1158    Ok(Some(Vector::stable_dictionary(codes, Arc::new(values))?))
1159}
1160
1161/// The validity of the pieces laid end to end, in `rows` rows.
1162///
1163/// The two cheap answers are checked for first because they are the answers real data gives. A
1164/// column that was never null anywhere is a page with no mask on it at all, and a bit per row read
1165/// out of every piece to build a mask that is all ones would be throwing that away.
1166fn run_of(pieces: &[&Vector], rows: usize) -> Validity {
1167    if pieces.iter().all(|piece| matches!(piece.validity(), Validity::AllValid)) {
1168        return Validity::AllValid;
1169    }
1170    if pieces.iter().all(|piece| matches!(piece.validity(), Validity::AllInvalid)) {
1171        return Validity::AllInvalid;
1172    }
1173    let mut live = Vec::with_capacity(rows);
1174    for piece in pieces {
1175        // row at a time: the mixed case, which is a bit per row however it is written, and it runs
1176        // once per column per row group rather than once per chunk.
1177        for row in 0..piece.len() {
1178            live.push(!piece.is_null_at(row));
1179        }
1180    }
1181    Validity::from_run(&live)
1182}
1183
1184/// Whether row `n` reads position `n` for every row, which makes the final gather a copy onto itself.
1185fn straight(at: &[usize]) -> bool {
1186    at.iter().enumerate().all(|(row, &index)| row == index)
1187}
1188
1189/// The arenas the flat string pieces among `pieces` share, counted before any of them is laid.
1190fn arenas_of<V: AsRef<Vector>>(pieces: &[V]) -> Arenas {
1191    let mut arenas = Arenas::default();
1192    for piece in pieces {
1193        if let Some(Data::Varlen(column)) = piece.as_ref().data() {
1194            arenas.count(column);
1195        }
1196    }
1197    arenas
1198}
1199
1200/// The pieces as one window, when they are windows of one page that follow each other in it.
1201///
1202/// A sorted load is the case. Its answer is laid as one page a column and handed on in chunks cut
1203/// out of that page, and a table then lays those chunks end to end into row groups, which without
1204/// this copies every value back into a run the page already holds. A string column joins when its
1205/// views are a page and every piece shares one arena, which is what a sorted string column is.
1206fn adjoined(pieces: &[&Vector]) -> Option<Data> {
1207    macro_rules! joined {
1208        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
1209            match pieces.first()?.data()? {
1210                $(Data::$variant(first) => {
1211                    if !first.is_shared() {
1212                        return None;
1213                    }
1214                    let mut run = first.clone();
1215                    for piece in &pieces[1..] {
1216                        let Some(Data::$variant(next)) = piece.data() else { return None };
1217                        run = run.joined(next)?;
1218                    }
1219                    Some(Data::$variant(run))
1220                })+
1221                Data::Varlen(first) => {
1222                    if !first.is_paged() {
1223                        return None;
1224                    }
1225                    let mut run = first.clone();
1226                    for piece in &pieces[1..] {
1227                        let Some(Data::Varlen(next)) = piece.data() else { return None };
1228                        run = run.joined(next)?;
1229                    }
1230                    Some(Data::Varlen(run))
1231                }
1232                _ => None,
1233            }
1234        };
1235    }
1236    crate::for_each_layout!(fixed, joined)
1237}
1238
1239/// Lays a run of data end to end after another, answering how many values it appended.
1240///
1241/// The typed loop per layout is the whole point: an append of a thousand `i64` is one `memcpy` and
1242/// an append of a thousand strings is at most one copy of an arena and a thousand sixteen byte views,
1243/// neither of which touches a `Value`. `arenas` is what says whether the arena is copied whole.
1244fn extend(into: &mut Data, from: &Data, arenas: &mut Arenas) -> Result<usize> {
1245    macro_rules! extended {
1246        ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
1247            match (&mut *into, from) {
1248                // Nothing to append, which is what an untyped null piece is. The caller reads the
1249                // count and leaves those rows null rather than pointing them anywhere.
1250                (_, Data::Empty) => Ok(0),
1251                $((Data::$variant(out), Data::$variant(values)) => {
1252                    out.extend_from_slice(values.as_slice());
1253                    Ok(values.len())
1254                })+
1255                // The one layout where an append is a copy of bytes rather than a copy of fixed
1256                // width slots, and the column decides whether that is one copy or one a string.
1257                (Data::Varlen(out), Data::Varlen(values)) => {
1258                    out.push_column(values, arenas);
1259                    Ok(values.len())
1260                }
1261                (out, from) => Err(Error::internal(format!(
1262                    "a run of {:?} values cannot be laid after a run of {:?} ones",
1263                    layout_of(from),
1264                    layout_of(out)
1265                ))),
1266            }
1267        };
1268    }
1269    crate::for_each_layout!(fixed, extended)
1270}
1271
1272/// Unit tests for the assembly.
1273///
1274/// That the engine actually goes through here rather than through the old path was checked rather
1275/// than assumed, by gating a panic on [`Assembly::place`] and running the `rudb` suite with it
1276/// armed. Three tests failed and no others: the one that is a `CASE` by name, the one that runs the
1277/// catalog views the engine ships with, and the one over the native frequency synopsis. All three
1278/// have a `CASE` in them and nothing else in the suite does.
1279/// The picks as codes into the one stable dictionary every source shares, or `None` when they do
1280/// not all share one. A pick that names no source, or a row that is null, is null.
1281fn picked_codes(sources: &[&Vector], picks: &[(u32, u32)]) -> Result<Option<Vector>> {
1282    let mut shared: Option<&Arc<Vector>> = None;
1283    let mut runs = Vec::with_capacity(sources.len());
1284    for source in sources {
1285        let Some((codes, values)) = source.stable_dictionary_parts() else { return Ok(None) };
1286        if shared.is_some_and(|held| !Arc::ptr_eq(held, values)) {
1287            return Ok(None);
1288        }
1289        shared = Some(values);
1290        runs.push(codes);
1291    }
1292    // A dictionary with no values has no code to stand in for a null row.
1293    let Some(values) = shared.filter(|values| !values.is_empty()) else { return Ok(None) };
1294    let mut live = Vec::with_capacity(picks.len());
1295    let mut codes = Vec::with_capacity(picks.len());
1296    for &(source, row) in picks {
1297        let code = sources.get(source as usize).and_then(|held| {
1298            let row = row as usize;
1299            let code = runs[source as usize].get(row)?;
1300            held.validity().is_valid(row).then_some(*code)
1301        });
1302        live.push(code.is_some());
1303        codes.push(code.unwrap_or(0));
1304    }
1305    let vector = Vector::stable_dictionary(codes, Arc::clone(values))?;
1306    Ok(Some(if live.iter().all(|&alive| alive) {
1307        vector
1308    } else {
1309        vector.with_validity(Validity::from_run(&live))
1310    }))
1311}
1312
1313#[cfg(test)]
1314mod tests {
1315    use super::*;
1316    use crate::{Chunk, Form};
1317
1318    /// Every row of a vector, as values, which is what an assembly is checked against.
1319    fn values(vector: &Vector) -> Vec<Value> {
1320        (0..vector.len()).map(|row| vector.value_at(row)).collect()
1321    }
1322
1323    /// The answer the assembly has to reach, written the slow obvious way.
1324    ///
1325    /// A `Vec<Value>` filled by scattering and then handed to [`Vector::from_values`] is exactly
1326    /// what `CASE` used to do, so this is the reference rather than a second opinion.
1327    fn scattered(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
1328        let mut answers = vec![Value::Null; rows];
1329        for (positions, piece) in pieces {
1330            for (slot, &row) in positions.iter().enumerate() {
1331                answers[row as usize] = piece.value_at(slot);
1332            }
1333        }
1334        Vector::from_values(ty.clone(), &answers).expect("the reference builds")
1335    }
1336
1337    /// Builds an assembly out of pieces and checks it against the slow way of getting there.
1338    fn agrees(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
1339        let mut assembly = Assembly::new(ty.clone(), rows).expect("an assembly of this type");
1340        for (positions, piece) in pieces {
1341            assembly.place(positions, piece).expect("the piece is placed");
1342        }
1343        let built = assembly.finish().expect("the assembly finishes");
1344        assert_eq!(built.len(), rows, "an assembly of {rows} rows");
1345        assert_eq!(values(&built), values(&scattered(ty, rows, pieces)), "against the slow way");
1346        built
1347    }
1348
1349    #[test]
1350    fn two_pieces_interleave_back_into_the_order_the_rows_came_in() {
1351        let evens = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(0), Value::BigInt(2)])
1352            .expect("a vector");
1353        let odds = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(3)])
1354            .expect("a vector");
1355        let built = agrees(&LogicalType::BigInt, 4, &[(vec![0, 2], evens), (vec![1, 3], odds)]);
1356        assert_eq!(
1357            values(&built),
1358            vec![Value::BigInt(0), Value::BigInt(1), Value::BigInt(2), Value::BigInt(3)]
1359        );
1360    }
1361
1362    #[test]
1363    fn a_row_no_piece_claims_is_null() {
1364        // Which is what a `CASE` with no `ELSE` leaves behind, and the case where a run of data with
1365        // a hole in it would put every value after the hole at the wrong index.
1366        let piece =
1367            Vector::from_values(LogicalType::BigInt, &[Value::BigInt(7)]).expect("a vector");
1368        let built = agrees(&LogicalType::BigInt, 3, &[(vec![1], piece)]);
1369        assert_eq!(values(&built), vec![Value::Null, Value::BigInt(7), Value::Null]);
1370    }
1371
1372    #[test]
1373    fn no_pieces_at_all_is_a_column_of_nulls_of_the_right_length() {
1374        let built = agrees(&LogicalType::Integer, 5, &[]);
1375        assert!(built.is_null_at(4), "every row of it is null");
1376    }
1377
1378    #[test]
1379    fn a_null_inside_a_piece_stays_null_where_the_piece_put_it() {
1380        // The validity has to survive the copy, and the value under it has to not be read, which is
1381        // two different things a single run of data with a mask over it can get wrong separately.
1382        let piece = Vector::from_values(
1383            LogicalType::BigInt,
1384            &[Value::BigInt(1), Value::Null, Value::BigInt(3)],
1385        )
1386        .expect("a vector");
1387        let built = agrees(&LogicalType::BigInt, 3, &[(vec![2, 0, 1], piece)]);
1388        assert!(built.is_null_at(0), "the null landed where the piece put it");
1389        assert_eq!(built.value_at(2), Value::BigInt(1));
1390    }
1391
1392    #[test]
1393    fn strings_are_assembled_without_going_through_a_value_each() {
1394        let left = Vector::from_values(
1395            LogicalType::Varchar,
1396            &[Value::Varchar("a short one".into()), Value::Varchar("another".into())],
1397        )
1398        .expect("a vector");
1399        let right = Vector::from_values(
1400            LogicalType::Varchar,
1401            &[Value::Varchar("a string that is far too long to live inline in a view".into())],
1402        )
1403        .expect("a vector");
1404        let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 2], left), (vec![1], right)]);
1405        assert_eq!(built.value_at(0), Value::Varchar("a short one".into()));
1406        assert_eq!(
1407            built.value_at(1),
1408            Value::Varchar("a string that is far too long to live inline in a view".into())
1409        );
1410        assert_eq!(built.value_at(2), Value::Varchar("another".into()));
1411    }
1412
1413    #[test]
1414    fn strings_laid_end_to_end_in_order_come_back_as_views_over_the_arena_they_went_into() {
1415        // The shape a hash join's gathered side is: chunk after chunk, each claiming the rows
1416        // straight after the last, so the permutation is the identity and nothing needs moving.
1417        let first = Vector::from_values(
1418            LogicalType::Varchar,
1419            &[Value::Varchar("one".into()), Value::Varchar("two".into())],
1420        )
1421        .expect("a vector");
1422        let second = Vector::from_values(
1423            LogicalType::Varchar,
1424            &[Value::Varchar("a third one long enough to be out of line".into())],
1425        )
1426        .expect("a vector");
1427        let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1], first), (vec![2], second)]);
1428        assert_eq!(built.form(), Form::StringView, "the bytes stay where they were appended");
1429        assert_eq!(
1430            built.value_at(2),
1431            Value::Varchar("a third one long enough to be out of line".into())
1432        );
1433    }
1434
1435    #[test]
1436    fn a_string_row_no_piece_claims_is_null_rather_than_empty() {
1437        // The hole a `CASE` with no `ELSE` leaves, on the path that permutes views instead of
1438        // copying bytes, where an unclaimed row has no view to read and has to come out null.
1439        let piece = Vector::from_values(
1440            LogicalType::Varchar,
1441            &[Value::Varchar("a value long enough to be out of line".into())],
1442        )
1443        .expect("a vector");
1444        let built = agrees(&LogicalType::Varchar, 3, &[(vec![2], piece)]);
1445        assert_eq!(built.value_at(0), Value::Null);
1446        assert_eq!(built.value_at(1), Value::Null);
1447        assert_eq!(
1448            built.value_at(2),
1449            Value::Varchar("a value long enough to be out of line".into())
1450        );
1451    }
1452
1453    #[test]
1454    fn a_constant_piece_is_written_out_rather_than_read_a_row_at_a_time() {
1455        // The `ELSE ''` half of the ClickBench query this was built for, which arrives as a constant
1456        // over however many rows the arms did not claim.
1457        let arm = Vector::from_values(LogicalType::Varchar, &[Value::Varchar("kept".into())])
1458            .expect("a vector");
1459        let otherwise = Vector::constant(LogicalType::Varchar, Value::Varchar("".into()), 3);
1460        let built = agrees(&LogicalType::Varchar, 4, &[(vec![2], arm), (vec![0, 1, 3], otherwise)]);
1461        assert_eq!(built.value_at(0), Value::Varchar("".into()));
1462        assert_eq!(built.value_at(2), Value::Varchar("kept".into()));
1463    }
1464
1465    #[test]
1466    fn a_dictionary_piece_is_walked_to_its_values() {
1467        // A scanned string column arrives as codes over a shared dictionary, so this is the form the
1468        // `THEN Referer` arm of the ClickBench query actually hands over.
1469        let dictionary = Vector::from_values(
1470            LogicalType::Varchar,
1471            &[Value::Varchar("one".into()), Value::Varchar("two".into())],
1472        )
1473        .expect("a dictionary");
1474        let piece = Vector::dictionary(vec![1, 0, 1], dictionary).expect("a dictionary vector");
1475        let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1, 2], piece)]);
1476        assert_eq!(
1477            values(&built),
1478            vec![
1479                Value::Varchar("two".into()),
1480                Value::Varchar("one".into()),
1481                Value::Varchar("two".into())
1482            ]
1483        );
1484    }
1485
1486    #[test]
1487    fn a_piece_placed_at_the_wrong_number_of_positions_is_an_error() {
1488        let piece =
1489            Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
1490        let mut assembly = Assembly::new(LogicalType::BigInt, 4).expect("an assembly");
1491        assert!(assembly.place(&[0, 1], &piece).is_err(), "two positions for one row");
1492    }
1493
1494    #[test]
1495    fn a_position_past_the_end_is_an_error_rather_than_a_lost_row() {
1496        let piece =
1497            Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
1498        let mut assembly = Assembly::new(LogicalType::BigInt, 2).expect("an assembly");
1499        assert!(assembly.place(&[9], &piece).is_err(), "a row past the end of the assembly");
1500    }
1501
1502    #[test]
1503    fn a_piece_of_the_wrong_layout_is_an_error_rather_than_a_wrong_answer() {
1504        // Two runs of data that cannot be laid end to end, which is a bug in whoever built the
1505        // pieces and has to say so rather than silently keep the first one.
1506        let piece =
1507            Vector::from_values(LogicalType::Varchar, &[Value::Varchar("x".into())]).expect("text");
1508        let mut assembly = Assembly::new(LogicalType::BigInt, 1).expect("an assembly");
1509        assert!(assembly.place(&[0], &piece).is_err(), "text laid after integers");
1510    }
1511
1512    #[test]
1513    fn every_layout_assembles_the_way_it_scatters() {
1514        // One case per physical layout, because the copy loop is generated per layout and a layout
1515        // missing from it is a wrong answer for that type alone, which no single typed test finds.
1516        let cases: Vec<(LogicalType, Vec<Value>)> = vec![
1517            (LogicalType::Boolean, vec![Value::Boolean(true), Value::Boolean(false)]),
1518            (LogicalType::TinyInt, vec![Value::TinyInt(1), Value::TinyInt(-2)]),
1519            (LogicalType::SmallInt, vec![Value::SmallInt(3), Value::SmallInt(-4)]),
1520            (LogicalType::Integer, vec![Value::Integer(5), Value::Integer(-6)]),
1521            (LogicalType::BigInt, vec![Value::BigInt(7), Value::BigInt(-8)]),
1522            (LogicalType::HugeInt, vec![Value::HugeInt(9), Value::HugeInt(-10)]),
1523            (LogicalType::UTinyInt, vec![Value::UTinyInt(11), Value::UTinyInt(12)]),
1524            (LogicalType::USmallInt, vec![Value::USmallInt(13), Value::USmallInt(14)]),
1525            (LogicalType::UInteger, vec![Value::UInteger(15), Value::UInteger(16)]),
1526            (LogicalType::UBigInt, vec![Value::UBigInt(17), Value::UBigInt(18)]),
1527            (LogicalType::Float, vec![Value::Float(1.5), Value::Float(-2.5)]),
1528            (LogicalType::Double, vec![Value::Double(3.5), Value::Double(-4.5)]),
1529            (
1530                LogicalType::Varchar,
1531                vec![Value::Varchar("first".into()), Value::Varchar("second".into())],
1532            ),
1533            (LogicalType::Date, vec![Value::Date(19), Value::Date(20)]),
1534        ];
1535        for (ty, pair) in cases {
1536            let left = Vector::from_values(ty.clone(), &pair[..1]).expect("a vector");
1537            let right = Vector::from_values(ty.clone(), &pair[1..]).expect("a vector");
1538            let built = agrees(&ty, 2, &[(vec![1], left), (vec![0], right)]);
1539            assert_eq!(built.value_at(0), pair[1], "{ty:?} at row 0");
1540            assert_eq!(built.value_at(1), pair[0], "{ty:?} at row 1");
1541        }
1542    }
1543
1544    #[test]
1545    fn an_assembly_is_a_chunk_column_like_any_other() {
1546        // The point of building a vector rather than a `Vec<Value>` is that what comes out goes
1547        // straight into a chunk, so this checks it actually does.
1548        let piece = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(2)])
1549            .expect("a vector");
1550        let built = agrees(&LogicalType::BigInt, 2, &[(vec![1, 0], piece)]);
1551        let chunk = Chunk::new(vec![built]).expect("a chunk of one column");
1552        assert_eq!(chunk.len(), 2, "two rows");
1553    }
1554
1555    /// A run of pieces, as values, in the order they were given.
1556    fn all_of(pieces: &[Vector]) -> Vec<Value> {
1557        pieces.iter().flat_map(values).collect()
1558    }
1559
1560    /// The pieces laid end to end, checked against the values that went in.
1561    fn laid(ty: &LogicalType, pieces: &[Vector]) -> Vector {
1562        let built = concat(ty, pieces).expect("the pieces lay").expect("this run lays");
1563        assert_eq!(built.len(), pieces.iter().map(Vector::len).sum::<usize>(), "the row count");
1564        assert_eq!(values(&built), all_of(pieces), "the values laid end to end");
1565        built
1566    }
1567
1568    #[test]
1569    fn pieces_laid_end_to_end_read_back_in_the_order_they_were_given() {
1570        let piece = |from: i64, to: i64| {
1571            let held: Vec<Value> = (from..to).map(Value::BigInt).collect();
1572            Vector::from_values(LogicalType::BigInt, &held).expect("a run of bigints")
1573        };
1574        let pieces = [piece(0, 4), piece(4, 9), piece(9, 10)];
1575        let built = laid(&LogicalType::BigInt, &pieces);
1576        assert_eq!(built.form(), Form::Flat, "a run of flat pieces lays flat");
1577        // The point of the page: a window cut out of it is a reference count bump and not a copy,
1578        // which is what the table cuts a chunk with.
1579        let window = built.slice(4, 5).expect("a window into the page");
1580        assert_eq!(values(&window), all_of(&pieces[1..2]), "the second piece, cut back out");
1581    }
1582
1583    /// Windows of one page that follow each other lay as one window over it, and anything else
1584    /// still lays by copying, which is what a sorted load hands a table.
1585    #[test]
1586    fn neighbouring_windows_of_one_page_lay_without_a_copy() {
1587        let held: Vec<Value> =
1588            (0..20).map(|at| if at % 7 == 3 { Value::Null } else { Value::BigInt(at) }).collect();
1589        let page = Vector::from_values(LogicalType::BigInt, &held).expect("a run").into_pages();
1590        let cut = |from: usize, len: usize| page.slice(from, len).expect("a window");
1591        let address = |vector: &Vector| match vector.data() {
1592            Some(Data::Int64(run)) => run.as_slice().as_ptr() as usize,
1593            other => panic!("a bigint run laid as {other:?}"),
1594        };
1595        let built = laid(&LogicalType::BigInt, &[cut(2, 5), cut(7, 8), cut(15, 3)]);
1596        assert_eq!(address(&built), address(&page) + 2 * 8, "the neighbours were copied");
1597        // A gap, a piece out of order, and a piece of another page all fall back to the copy.
1598        let other = Vector::from_values(LogicalType::BigInt, &held).expect("a run").into_pages();
1599        let other_cut = other.slice(7, 3).expect("a window");
1600        for pieces in [
1601            vec![cut(2, 5), cut(8, 3)],
1602            vec![cut(7, 3), cut(2, 5)],
1603            vec![cut(2, 5), other_cut],
1604            vec![Vector::from_values(LogicalType::BigInt, &held[..4]).expect("owned"), cut(4, 2)],
1605        ] {
1606            let built = laid(&LogicalType::BigInt, &pieces);
1607            assert_ne!(address(&built), address(&page) + 2 * 8, "a copy was expected");
1608        }
1609    }
1610
1611    /// The same for strings: cuts of one paged column lay back as a window over its views and
1612    /// its arena, and a cut of a column whose views are its own is copied.
1613    #[test]
1614    fn neighbouring_cuts_of_a_paged_string_column_lay_without_a_copy() {
1615        let held: Vec<Value> = (0..20)
1616            .map(|at| Value::Varchar(format!("a string long enough for the arena {at}")))
1617            .collect();
1618        let page = Vector::from_values(LogicalType::Varchar, &held).expect("a run").into_pages();
1619        let cut = |from: usize, len: usize| page.slice(from, len).expect("a window");
1620        let views = |vector: &Vector| match vector.data() {
1621            Some(Data::Varlen(column)) => column.views().as_ptr() as usize,
1622            other => panic!("a varchar run laid as {other:?}"),
1623        };
1624        let built = laid(&LogicalType::Varchar, &[cut(2, 5), cut(7, 8), cut(15, 3)]);
1625        assert_eq!(views(&built), views(&page) + 2 * size_of::<StringView>(), "views copied");
1626        let owned = Vector::from_values(LogicalType::Varchar, &held).expect("a run");
1627        let copied = laid(&LogicalType::Varchar, &[owned.slice(0, 4).expect("a cut"), cut(4, 2)]);
1628        assert_eq!(copied.len(), 6);
1629    }
1630
1631    #[test]
1632    fn a_null_in_a_piece_is_a_null_in_the_same_row_of_the_page() {
1633        let ty = LogicalType::Integer;
1634        let whole = Vector::from_values(ty.clone(), &[Value::Integer(1), Value::Integer(2)])
1635            .expect("no nulls");
1636        let holed =
1637            Vector::from_values(ty.clone(), &[Value::Null, Value::Integer(4)]).expect("one null");
1638        let built = laid(&ty, &[whole.clone(), holed.clone()]);
1639        assert!(!built.is_null_at(1), "a row that was not null became one");
1640        assert!(built.is_null_at(2), "the null did not come through");
1641        // A run with no null anywhere keeps the cheap answer rather than growing a mask of ones.
1642        let clean = laid(&ty, &[whole.clone(), whole]);
1643        assert_eq!(clean.validity(), &Validity::AllValid, "a mask nothing needed");
1644        let empty = laid(&ty, &[holed.clone(), holed]);
1645        assert!(empty.is_null_at(0) && empty.is_null_at(2), "both nulls came through");
1646    }
1647
1648    /// The string case, which is the one that would be a byte copy per cut if it laid flat.
1649    #[test]
1650    fn strings_lay_into_one_arena_and_come_back_as_views() {
1651        let ty = LogicalType::Varchar;
1652        let word = |text: &str| {
1653            Vector::from_values(ty.clone(), &[Value::Varchar(text.to_string())]).expect("a string")
1654        };
1655        let pieces = [word("a string too long to sit inside a view"), word("short")];
1656        let built = laid(&ty, &pieces);
1657        assert_eq!(
1658            built.form(),
1659            Form::StringView,
1660            "a varchar page that is not views cuts by copying"
1661        );
1662        let window = built.slice(0, 1).expect("a window into the page");
1663        assert_eq!(values(&window), all_of(&pieces[..1]), "the long string, cut back out");
1664    }
1665
1666    #[test]
1667    fn stable_dictionary_pieces_sharing_values_lay_as_codes() {
1668        let ty = LogicalType::Varchar;
1669        let values = Arc::new(
1670            Vector::from_values(
1671                ty.clone(),
1672                &[Value::Varchar("a".to_string()), Value::Varchar("b".to_string())],
1673            )
1674            .expect("dictionary values"),
1675        );
1676        let first = Vector::stable_dictionary(vec![1, 0], Arc::clone(&values)).expect("codes");
1677        let second = Vector::stable_dictionary(vec![1], Arc::clone(&values)).expect("codes");
1678        let built = concat(&ty, &[first, second]).expect("no error").expect("shared codes lay");
1679        let (codes, held) = built.stable_dictionary_parts().expect("the stable form survives");
1680        assert_eq!(codes, &[1, 0, 1]);
1681        assert!(Arc::ptr_eq(held, &values));
1682    }
1683
1684    /// What will not lay, which is a layout answer and not an error.
1685    #[test]
1686    fn an_encoded_piece_is_left_alone_rather_than_flattened() {
1687        let ty = LogicalType::BigInt;
1688        let flat = Vector::from_values(ty.clone(), &[Value::BigInt(1)]).expect("a flat piece");
1689        let values = Vector::from_values(ty.clone(), &[Value::BigInt(7), Value::BigInt(8)])
1690            .expect("two distinct values");
1691        let coded = Vector::dictionary(vec![0, 1, 0], values).expect("a dictionary piece");
1692        let one = std::slice::from_ref(&coded);
1693        assert!(concat(&ty, one).expect("no error").is_none(), "a dictionary laid");
1694        assert!(
1695            concat(&ty, &[flat.clone(), coded]).expect("no error").is_none(),
1696            "a mixed run laid"
1697        );
1698        assert!(
1699            concat::<Vector>(&ty, &[]).expect("no error").is_none(),
1700            "nothing laid into something"
1701        );
1702        // A piece of another type is the caller's mistake and is still answered as a layout it will
1703        // not build, because the fallback keeps the pieces and keeping them is always correct.
1704        let other =
1705            Vector::from_values(LogicalType::Integer, &[Value::Integer(1)]).expect("an int");
1706        assert!(concat(&ty, &[flat, other]).expect("no error").is_none(), "two types laid");
1707    }
1708
1709    /// A [`Spread`] that runs each piece on a thread of its own, in no particular order.
1710    ///
1711    /// Not what the engine passes, which shares the pieces out over a fixed lease off a counter. This
1712    /// is the harsher version on purpose: a thread per piece and nothing deciding who goes first is
1713    /// the widest the interleaving can get, so anything in the copy that depends on piece order
1714    /// happening to be arrival order shows up here.
1715    fn on_a_thread_each(count: usize, task: &(dyn Fn(usize) + Sync)) -> Result<()> {
1716        std::thread::scope(|scope| {
1717            let running: Vec<_> =
1718                (0..count).rev().map(|at| scope.spawn(move || task(at))).collect();
1719            for thread in running {
1720                thread.join().expect("a piece copier panicked");
1721            }
1722        });
1723        Ok(())
1724    }
1725
1726    /// A run of string pieces that each own an arena, which is what the parts of a stored column are.
1727    ///
1728    /// The strings are past the inline limit on purpose. A column of short strings has no arena worth
1729    /// copying and would pass the same test without the offsets ever being exercised.
1730    fn owned_strings(pieces: usize, each: usize) -> Vec<Vector> {
1731        (0..pieces)
1732            .map(|piece| {
1733                let held: Vec<Value> = (0..each)
1734                    .map(|row| match (piece + row) % 4 {
1735                        0 => Value::Null,
1736                        1 => Value::Varchar(format!("short {row}")),
1737                        _ => Value::Varchar(format!(
1738                            "a string of piece {piece} row {row} that is well past twelve bytes"
1739                        )),
1740                    })
1741                    .collect();
1742                Vector::from_values(LogicalType::Varchar, &held).expect("a run of strings")
1743            })
1744            .collect()
1745    }
1746
1747    #[test]
1748    fn string_pieces_laid_on_many_threads_hold_the_same_strings_as_laid_on_one() {
1749        let ty = LogicalType::Varchar;
1750        let pieces = owned_strings(9, 7);
1751        // Asserted rather than assumed. Every case below agrees with the serial path whichever path
1752        // ran, so a test that only compared values would still pass if the shape check quietly
1753        // stopped taking anything, and it is the shape check that this whole file turns on.
1754        let borrowed: Vec<&Vector> = pieces.iter().collect();
1755        assert!(apart(&ty, &borrowed).is_some(), "the parallel lay declined its own case");
1756        let serial = concat(&ty, &pieces).expect("no error").expect("owned arenas lay");
1757        let parallel = concat_on(&ty, &pieces, &on_a_thread_each)
1758            .expect("no error")
1759            .expect("owned arenas lay");
1760        assert_eq!(parallel.len(), serial.len(), "the row count");
1761        assert_eq!(values(&parallel), all_of(&pieces), "the values laid end to end");
1762        assert_eq!(values(&parallel), values(&serial), "the two paths disagree");
1763        // The form matters as much as the values. A gather off this is a gather off one page of views,
1764        // and the serial path ends in the same place, so a caller cannot tell which one ran.
1765        assert_eq!(parallel.form(), serial.form(), "a different body came out");
1766    }
1767
1768    /// The shapes the parallel path hands back, each of which is a case the serial one does better.
1769    #[test]
1770    fn a_run_the_parallel_lay_does_not_own_is_left_to_the_serial_one() {
1771        let ty = LogicalType::Varchar;
1772        let pieces = owned_strings(3, 5);
1773        assert!(apart(&ty, &[&pieces[0]]).is_none(), "one piece was taken");
1774        // Cuts of one page share an arena, and the serial path copies it once and shifts the views of
1775        // every cut. Copying it per cut here would hold it three times over.
1776        let page = concat(&ty, &pieces).expect("no error").expect("a page").into_pages();
1777        let cut = |from: usize, len: usize| page.slice(from, len).expect("a window");
1778        let cuts = [cut(0, 4), cut(4, 6), cut(10, 5)];
1779        let borrowed: Vec<&Vector> = cuts.iter().collect();
1780        assert!(apart(&ty, &borrowed).is_none(), "cuts of one page were taken");
1781        // And a run that goes down the shared view path answers the same either way, which is the
1782        // thing the fall through is there to preserve.
1783        let serial = concat(&ty, &cuts).expect("no error").expect("shared views lay");
1784        let parallel =
1785            concat_on(&ty, &cuts, &on_a_thread_each).expect("no error").expect("shared views");
1786        assert_eq!(values(&parallel), values(&serial), "the fall through changed the answer");
1787    }
1788
1789    /// A piece whose arena holds bytes nobody reads is the filtered cut of a Parquet page, and taking
1790    /// it would carry the rest of the page along for as long as the result lives.
1791    #[test]
1792    fn a_piece_holding_more_arena_than_it_reads_is_left_to_the_serial_lay() {
1793        let ty = LogicalType::Varchar;
1794        let pieces = owned_strings(2, 8);
1795        let page = concat(&ty, &pieces).expect("no error").expect("a page");
1796        // One row out of sixteen, so the arena is far larger than the one string read out of it. The
1797        // slice keeps the whole arena, which is exactly the case being asked about.
1798        let thin = page.slice(2, 1).expect("a window").flatten().expect("flattened");
1799        let fat = page.slice(3, 1).expect("a window").flatten().expect("flattened");
1800        let held = [thin, fat];
1801        let borrowed: Vec<&Vector> = held.iter().collect();
1802        if borrowed.iter().all(|piece| match piece.data() {
1803            Some(Data::Varlen(column)) => !column.mostly_read(),
1804            _ => false,
1805        }) {
1806            assert!(apart(&ty, &borrowed).is_none(), "a mostly unread arena was taken");
1807        }
1808        let serial = concat(&ty, &held).expect("no error").expect("flat pieces lay");
1809        let parallel =
1810            concat_on(&ty, &held, &on_a_thread_each).expect("no error").expect("flat pieces");
1811        assert_eq!(values(&parallel), values(&serial), "the two paths disagree");
1812    }
1813
1814    /// Fixed width pieces long enough to be copied on the threads, some with nulls and one of a
1815    /// different length, lay to the values the serial path lays, and the ones it leaves alone go
1816    /// the serial way.
1817    #[test]
1818    fn fixed_width_pieces_laid_on_many_threads_hold_the_same_values_as_laid_on_one() {
1819        for ty in [LogicalType::BigInt, LogicalType::Integer, LogicalType::Double] {
1820            let pieces: Vec<Vector> = (0..9_i32)
1821                .map(|piece| {
1822                    let rows = if piece == 4 { 1_234 } else { TILED_ROWS / 8 + 7 };
1823                    let held: Vec<Value> = (0..rows)
1824                        .map(|row| {
1825                            let n = piece * 100_000 + i32::try_from(row).expect("fits");
1826                            if piece % 3 == 1 && n % 5 == 0 {
1827                                return Value::Null;
1828                            }
1829                            match ty {
1830                                LogicalType::BigInt => Value::BigInt(i64::from(n)),
1831                                LogicalType::Integer => Value::Integer(n),
1832                                _ => Value::Double(f64::from(n) / 4.0),
1833                            }
1834                        })
1835                        .collect();
1836                    Vector::from_values(ty.clone(), &held).expect("a run of values")
1837                })
1838                .collect();
1839            let borrowed: Vec<&Vector> = pieces.iter().collect();
1840            let wide = tiled(&ty, &borrowed, &on_a_thread_each).expect("no error");
1841            let wide = wide.expect("long flat pieces are taken");
1842            let serial = concat(&ty, &pieces).expect("no error").expect("flat pieces lay");
1843            assert_eq!(values(&wide), all_of(&pieces), "{ty:?} laid end to end");
1844            assert_eq!(values(&wide), values(&serial), "{ty:?} the two paths disagree");
1845            let parallel = concat_on(&ty, &pieces, &on_a_thread_each).expect("no error");
1846            assert_eq!(
1847                values(&parallel.expect("lays")),
1848                values(&serial),
1849                "{ty:?} through concat_on"
1850            );
1851            // Too short, and a single piece, are both the serial path's.
1852            assert!(tiled(&ty, &borrowed[..2], &on_a_thread_each).expect("no error").is_none());
1853            assert!(tiled(&ty, &borrowed[..1], &on_a_thread_each).expect("no error").is_none());
1854        }
1855    }
1856
1857    /// Pieces of every form a sort hands over, read back through an order, against the same order
1858    /// read a value at a time.
1859    #[test]
1860    fn an_interleave_reads_the_pieces_in_the_order_it_is_given() {
1861        let words: Vec<Value> = ["a long enough word to leave the inline view", "b", "c"]
1862            .iter()
1863            .map(|word| Value::Varchar((*word).to_string()))
1864            .collect();
1865        let dictionary = Vector::from_values(LogicalType::Varchar, &words).expect("words");
1866        let strings = [
1867            Vector::dictionary(vec![2, 0, 1], dictionary).expect("a dictionary"),
1868            Vector::from_values(
1869                LogicalType::Varchar,
1870                &[Value::Null, Value::Varchar("another string past twelve bytes".to_string())],
1871            )
1872            .expect("flat"),
1873        ];
1874        let numbers = [
1875            Vector::from_values(
1876                LogicalType::BigInt,
1877                &[Value::BigInt(7), Value::Null, Value::BigInt(9)],
1878            )
1879            .expect("flat"),
1880            Vector::constant(LogicalType::BigInt, Value::BigInt(4), 1),
1881            Vector::constant(LogicalType::BigInt, Value::Null, 1),
1882        ];
1883        let lists = [
1884            Vector::from_values(
1885                LogicalType::List(Box::new(LogicalType::Integer)),
1886                &[
1887                    Value::List { element: LogicalType::Integer, values: vec![Value::Integer(1)] },
1888                    Value::Null,
1889                    Value::List { element: LogicalType::Integer, values: vec![] },
1890                ],
1891            )
1892            .expect("lists"),
1893            Vector::from_values(
1894                LogicalType::List(Box::new(LogicalType::Integer)),
1895                &[
1896                    Value::List {
1897                        element: LogicalType::Integer,
1898                        values: vec![Value::Integer(2), Value::Integer(3)],
1899                    },
1900                    Value::Null,
1901                ],
1902            )
1903            .expect("lists"),
1904        ];
1905        let order = [4, 0, 3, 1, 2, 3];
1906        for pieces in [&strings[..], &numbers[..], &lists[..]] {
1907            let ty = pieces[0].logical_type().clone();
1908            let laid: Vec<Value> = pieces.iter().flat_map(values).collect();
1909            let expected: Vec<Value> = order.iter().map(|&index| laid[index].clone()).collect();
1910            let got = interleave(&ty, pieces, &order).expect("an interleave");
1911            assert_eq!(values(&got), expected, "{ty}");
1912        }
1913        assert!(interleave(&LogicalType::BigInt, &numbers, &[5]).is_err(), "row 5 of 5 rows");
1914        // The same answers written through the inverse of a permutation, which is the way round a
1915        // sort takes when its order is a few long runs.
1916        let order = [4, 0, 3, 1, 2];
1917        let mut inverse = [0u32; 5];
1918        for (at, &row) in order.iter().enumerate() {
1919            inverse[row] = at as u32;
1920        }
1921        let texts: Vec<Value> = ["a string past the twelve bytes of a view", "short", "x"]
1922            .iter()
1923            .map(|text| Value::Varchar((*text).to_string()))
1924            .chain([Value::Varchar("another long string for the arena".to_string())])
1925            .collect();
1926        let valid = [
1927            Vector::from_values(LogicalType::Varchar, &texts[..2]).expect("flat"),
1928            Vector::from_values(LogicalType::Varchar, &texts[2..]).expect("flat"),
1929            Vector::constant(LogicalType::Varchar, Value::Varchar("one more".to_string()), 1),
1930        ];
1931        for pieces in [&strings[..], &numbers[..], &lists[..], &valid[..]] {
1932            let ty = pieces[0].logical_type().clone();
1933            let pulled = interleave(&ty, pieces, &order).expect("an interleave");
1934            let pushed =
1935                interleave_placed(&ty, pieces, &order, Some(&inverse)).expect("a placed one");
1936            assert_eq!(values(&pushed), values(&pulled), "{ty}");
1937        }
1938        assert!(
1939            interleave_placed(&LogicalType::BigInt, &numbers, &order, Some(&inverse[..4])).is_err(),
1940            "four places for five rows"
1941        );
1942        let untyped = [Vector::constant(LogicalType::Null, Value::Null, 3)];
1943        let got = interleave(&LogicalType::Null, &untyped, &[2, 0]).expect("an untyped null");
1944        assert_eq!(values(&got), vec![Value::Null, Value::Null]);
1945    }
1946
1947    /// A fixed width column written through `inverse` from pieces of every form the sort sees,
1948    /// against the answer read through `order`, and a column of nothing but nulls.
1949    #[test]
1950    fn a_fixed_width_column_is_written_to_its_places_from_pieces_of_any_form() {
1951        let ty = LogicalType::BigInt;
1952        let int = Value::BigInt;
1953        let flat = Vector::from_values(ty.clone(), &[int(1), Value::Null, int(3)]).expect("flat");
1954        let paged = Vector::from_values(ty.clone(), &[int(4), int(5)]).expect("flat").into_pages();
1955        let words = Vector::from_values(ty.clone(), &[int(70), int(80)]).expect("values");
1956        let coded = Vector::dictionary(vec![1, 0, 1], words).expect("coded");
1957        let nulled = Vector::from_values(ty.clone(), &[int(90), Value::Null]).expect("values");
1958        let chained = Vector::dictionary(vec![1, 0], nulled).expect("coded over nulls");
1959        let constant = Vector::constant(ty.clone(), int(6), 2);
1960        let pieces = [flat, paged, coded, chained, constant];
1961        let rows: usize = pieces.iter().map(Vector::len).sum();
1962        let order: Vec<usize> = (0..rows).map(|at| (at * 5 + 3) % rows).collect();
1963        let mut inverse = vec![0u32; rows];
1964        for (to, &from) in order.iter().enumerate() {
1965            inverse[from] = u32::try_from(to).expect("a small row");
1966        }
1967        let read = interleave_placed(&ty, &pieces, &order, None).expect("read through order");
1968        let written =
1969            interleave_placed(&ty, &pieces, &order, Some(&inverse)).expect("written to places");
1970        assert_eq!(values(&written), values(&read));
1971        assert_eq!(values(&written)[inverse[1] as usize], Value::Null, "the flat piece's null");
1972        assert_eq!(values(&written)[inverse[8] as usize], Value::Null, "the dictionary's null");
1973
1974        let nothing = Vector::from_values(ty.clone(), &[Value::Null, Value::Null]).expect("nulls");
1975        let written = interleave_placed(&ty, &[nothing], &[1, 0], Some(&[1, 0])).expect("nulls");
1976        assert_eq!(values(&written), [Value::Null, Value::Null]);
1977    }
1978
1979    #[test]
1980    fn placed_strings_are_laid_in_the_order_of_the_result() {
1981        let word = |text: &str| Value::Varchar(text.to_string());
1982        let flat = Vector::from_values(
1983            LogicalType::Varchar,
1984            &[word("the first string past twelve bytes"), Value::Null, word("short")],
1985        )
1986        .expect("flat");
1987        let arena = b"xxa second string past twelve bytesyy".to_vec();
1988        let views = vec![StringView::over(&arena[2..35], 2), StringView::inline("tiny")];
1989        let viewed =
1990            Vector::string_views(LogicalType::Varchar, views, Arc::new(Buffer::from_vec(arena)))
1991                .expect("views");
1992        let pieces = [flat, viewed];
1993        let order = [3, 0, 4, 2, 1];
1994        let mut inverse = vec![0u32; order.len()];
1995        for (to, &from) in order.iter().enumerate() {
1996            inverse[from] = u32::try_from(to).expect("a small row");
1997        }
1998        let laid: Vec<Value> = pieces.iter().flat_map(values).collect();
1999        let expected: Vec<Value> = order.iter().map(|&index| laid[index].clone()).collect();
2000        let got = interleave_placed(&LogicalType::Varchar, &pieces, &order, Some(&inverse))
2001            .expect("a placed interleave");
2002        assert_eq!(values(&got), expected);
2003        let (_, arena) = got.text_parts().expect("views");
2004        assert_eq!(
2005            arena, b"a second string past twelve bytesthe first string past twelve bytes",
2006            "the long strings in the order they come out, and nothing else"
2007        );
2008        assert!(strings_placeable(&LogicalType::Varchar, &pieces));
2009        for split in 0..=order.len() {
2010            let mut joined = Vec::new();
2011            for range in [0..split, split..order.len()] {
2012                let part = placed_string_rows(&LogicalType::Varchar, &pieces, &inverse, range)
2013                    .expect("a range of rows");
2014                joined.extend(values(&part));
2015            }
2016            assert_eq!(joined, expected, "split at {split}");
2017        }
2018        let (_, arena) = placed_string_rows(&LogicalType::Varchar, &pieces, &inverse, 1..3)
2019            .expect("the middle rows")
2020            .text_parts()
2021            .map(|(views, arena)| (views.len(), arena.to_vec()))
2022            .expect("views");
2023        assert_eq!(arena, b"the first string past twelve bytes", "only the range's own strings");
2024        assert!(placed_string_rows(&LogicalType::Varchar, &pieces, &inverse, 4..6).is_err());
2025    }
2026
2027    #[test]
2028    fn an_interleave_of_dictionaries_merges_them_into_one() {
2029        let word = |text: &str| Value::Varchar(text.to_string());
2030        let first = [word("MAIL"), word("a word long enough to leave the inline view")];
2031        let second = [Value::Null, word("MAIL"), word("SHIP")];
2032        let first = Arc::new(Vector::from_values(LogicalType::Varchar, &first).expect("words"));
2033        let second = Arc::new(Vector::from_values(LogicalType::Varchar, &second).expect("words"));
2034        let over = |codes: Vec<u32>, dictionary: &Arc<Vector>| {
2035            Vector::dictionary_over(codes, Arc::clone(dictionary)).expect("a dictionary")
2036        };
2037        let pieces = [
2038            over((0..16).map(|row| row % 2).collect(), &first),
2039            over((0..16).map(|row| row % 3).collect(), &second),
2040            over(vec![1; 8], &first),
2041        ];
2042        let order: Vec<usize> = (0..40).rev().collect();
2043        let laid: Vec<Value> = pieces.iter().flat_map(values).collect();
2044        let expected: Vec<Value> = order.iter().map(|&index| laid[index].clone()).collect();
2045        let got = interleave(&LogicalType::Varchar, &pieces, &order).expect("an interleave");
2046        assert_eq!(values(&got), expected);
2047        let (_, merged) = got.stable_dictionary_parts().expect("one stable dictionary");
2048        assert_eq!(merged.len(), 4, "MAIL once, the long word, the null and SHIP");
2049        let mut inverse = vec![0u32; order.len()];
2050        for (to, &from) in order.iter().enumerate() {
2051            inverse[from] = u32::try_from(to).expect("a small row");
2052        }
2053        let placed = interleave_placed(&LogicalType::Varchar, &pieces, &order, Some(&inverse))
2054            .expect("a placed interleave");
2055        assert_eq!(values(&placed), expected, "placed codes land where pulled ones do");
2056        assert!(placed.stable_dictionary_parts().is_some(), "and stay one dictionary");
2057
2058        let mixed = [pieces[0].clone(), pieces[1].flatten().expect("flat")];
2059        let got = interleave(&LogicalType::Varchar, &mixed, &order[8..]).expect("an interleave");
2060        assert!(got.dictionary_parts().is_none(), "a flat piece gathers flat");
2061        let few = &pieces[..1];
2062        let got = interleave(&LogicalType::Varchar, few, &[3, 2]).expect("an interleave");
2063        assert_eq!(
2064            values(&got),
2065            vec![word("a word long enough to leave the inline view"), word("MAIL")]
2066        );
2067    }
2068
2069    #[test]
2070    fn a_pick_takes_each_row_from_the_source_it_names_and_is_null_where_none_is_named() {
2071        let ty = LogicalType::Integer;
2072        let left =
2073            Vector::from_values(ty.clone(), &[Value::Integer(1), Value::Null, Value::Integer(3)])
2074                .expect("left");
2075        let right = Vector::from_values(ty.clone(), &[Value::Integer(10), Value::Integer(20)])
2076            .expect("right");
2077        let picks = [(1, 1), (0, 0), (crate::NO_ROW, 0), (0, 1), (1, 0), (0, 2)];
2078        let out = picked(&ty, &[&left, &right], &picks).expect("picks").expect("flat sources");
2079        assert_eq!(
2080            values(&out),
2081            vec![
2082                Value::Integer(20),
2083                Value::Integer(1),
2084                Value::Null,
2085                Value::Null,
2086                Value::Integer(10),
2087                Value::Integer(3),
2088            ]
2089        );
2090        let word = |text: &str| Value::Varchar(text.to_string());
2091        let words =
2092            Vector::from_values(LogicalType::Varchar, &[word("a"), word("bb")]).expect("words");
2093        let out = picked(&LogicalType::Varchar, &[&words], &[(0, 1), (0, 0), (0, 1)])
2094            .expect("picks")
2095            .expect("flat source");
2096        assert_eq!(values(&out), vec![word("bb"), word("a"), word("bb")]);
2097        let coded = Vector::dictionary(vec![1, 1, 0], words.clone()).expect("a dictionary");
2098        let out = picked(&LogicalType::Varchar, &[&words, &coded], &[(1, 2), (0, 0), (1, 0)])
2099            .expect("picks")
2100            .expect("flat and dictionary sources");
2101        assert_eq!(values(&out), vec![word("a"), word("a"), word("bb")]);
2102    }
2103
2104    /// Sources that are codes into one stable dictionary give codes into it, with a pick of no
2105    /// source and a null row both null, and two dictionaries give strings.
2106    #[test]
2107    fn picks_over_one_shared_dictionary_stay_codes() {
2108        let word = |text: &str| Value::Varchar(text.to_string());
2109        let words = Arc::new(
2110            Vector::from_values(LogicalType::Varchar, &[word("a"), word("bb")]).expect("words"),
2111        );
2112        let first = Vector::stable_dictionary(vec![1, 0], Arc::clone(&words)).expect("codes");
2113        let second = Vector::stable_dictionary(vec![0, 1], Arc::clone(&words))
2114            .expect("codes")
2115            .with_validity(Validity::from_run(&[true, false]));
2116        let picks = [(1, 0), (0, 0), (crate::NO_ROW, 0), (1, 1), (0, 1)];
2117        let out = picked(&LogicalType::Varchar, &[&first, &second], &picks)
2118            .expect("picks")
2119            .expect("coded sources");
2120        let (_, held) = out.stable_dictionary_parts().expect("still codes");
2121        assert!(Arc::ptr_eq(held, &words), "the codes point somewhere else");
2122        assert_eq!(values(&out), vec![word("a"), word("bb"), Value::Null, Value::Null, word("a")]);
2123        let other = Arc::new(Vector::clone(&words));
2124        let apart = Vector::stable_dictionary(vec![1, 0], other).expect("codes");
2125        let out = picked(&LogicalType::Varchar, &[&first, &apart], &[(1, 0), (0, 0)])
2126            .expect("picks")
2127            .expect("dictionary sources");
2128        assert!(out.stable_dictionary_parts().is_none(), "two dictionaries are not one");
2129        assert_eq!(values(&out), vec![word("bb"), word("bb")]);
2130    }
2131}