use std::collections::{HashMap, HashSet};
use std::ops::Range;
use std::sync::{Arc, Mutex};
use rudb_common::{Error, LogicalType, Result, Spread, Value};
use crate::buffer::Buffer;
use crate::string::{Arenas, StringColumn, StringView};
use crate::validity::Validity;
use crate::vector::{
Data, Form, NOWHERE, Vector, copy_of, data_for, empty_data_for, layout_of, placed_of,
};
#[derive(Debug)]
pub struct Assembly {
ty: LogicalType,
rows: usize,
data: Data,
at: Vec<usize>,
live: Vec<bool>,
values: Option<Vec<Value>>,
}
impl Assembly {
pub fn new(ty: LogicalType, rows: usize) -> Result<Self> {
let nested =
matches!(ty, LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _));
let values = if nested { Some(vec![Value::Null; rows]) } else { None };
let data = if nested { Data::Empty } else { empty_data_for(&ty)? };
Ok(Self { ty, rows, data, at: vec![NOWHERE; rows], live: vec![false; rows], values })
}
#[must_use]
pub fn rows(&self) -> usize {
self.rows
}
pub fn place(&mut self, positions: &[u32], piece: &Vector) -> Result<()> {
if positions.len() != piece.len() {
return Err(Error::internal(format!(
"a piece of {} rows placed at {} positions",
piece.len(),
positions.len()
)));
}
for &row in positions {
if row as usize >= self.rows {
return Err(Error::internal(format!(
"row {row} placed in an assembly of {} rows",
self.rows
)));
}
}
if let Some(values) = &mut self.values {
for (slot, &row) in positions.iter().enumerate() {
values[row as usize] = piece.value_at(slot);
}
return Ok(());
}
let flat = piece.flatten()?;
let Some(from) = flat.data() else {
return Err(Error::internal("a flattened vector with no run of data in it"));
};
let start = self.data.len();
let appended = extend(&mut self.data, from, &mut Arenas::default())?;
for (slot, &row) in positions.iter().enumerate() {
let row = row as usize;
if slot < appended {
self.at[row] = start + slot;
self.live[row] = !piece.is_null_at(slot);
} else {
self.at[row] = NOWHERE;
self.live[row] = false;
}
}
Ok(())
}
pub fn finish(self) -> Result<Vector> {
if let Some(values) = self.values {
return Vector::from_values(self.ty, &values);
}
if matches!(self.data, Data::Empty) {
return Ok(Vector::constant(self.ty, Value::Null, self.rows));
}
let validity = Validity::from_run(&self.live);
if let Data::Varlen(column) = self.data {
let (laid, arena) = column.into_parts();
let arena = Arc::new(arena);
if straight(&self.at) {
return Ok(Vector::string_views(self.ty, laid, arena)?.with_validity(validity));
}
let views = self
.at
.iter()
.map(|&index| laid.get(index).copied().unwrap_or_else(StringView::empty))
.collect();
return Ok(Vector::string_views(self.ty, views, arena)?.with_validity(validity));
}
if straight(&self.at) {
return Ok(Vector::flat(self.ty, self.data)?.with_validity(validity));
}
let gathered = copy_of(&self.data, &self.at);
Ok(Vector::flat(self.ty, gathered)?.with_validity(validity))
}
}
pub fn concat<V: AsRef<Vector>>(ty: &LogicalType, pieces: &[V]) -> Result<Option<Vector>> {
let pieces: Vec<&Vector> = pieces.iter().map(AsRef::as_ref).collect();
laid(ty, &pieces)
}
pub fn concat_on<V: AsRef<Vector>>(
ty: &LogicalType,
pieces: &[V],
spread: &Spread<'_>,
) -> Result<Option<Vector>> {
let pieces: Vec<&Vector> = pieces.iter().map(AsRef::as_ref).collect();
if let Some(strung) = strung(ty, &pieces, spread)? {
return Ok(Some(strung));
}
laid(ty, &pieces)
}
fn strung(ty: &LogicalType, pieces: &[&Vector], spread: &Spread<'_>) -> Result<Option<Vector>> {
let Some(columns) = apart(ty, pieces) else {
return Ok(None);
};
let mut bases = Vec::with_capacity(columns.len());
let mut bytes = 0usize;
let mut rows = 0usize;
for column in &columns {
bases.push((bytes, rows));
bytes += column.arena().len();
rows += column.len();
}
let mut arena = vec![0u8; bytes];
let mut views = vec![StringView::empty(); rows];
let mut arena_rest: &mut [u8] = &mut arena;
let mut views_rest: &mut [StringView] = &mut views;
let mut slots = Vec::with_capacity(columns.len());
for column in &columns {
let (arena_head, arena_tail) = arena_rest.split_at_mut(column.arena().len());
let (views_head, views_tail) = views_rest.split_at_mut(column.len());
slots.push(Mutex::new((arena_head, views_head)));
arena_rest = arena_tail;
views_rest = views_tail;
}
let task = |at: usize| {
let column = columns[at];
let (base, _) = bases[at];
let mut slot = slots[at].lock().unwrap_or_else(|poisoned| poisoned.into_inner());
let (into_arena, into_views) = &mut *slot;
into_arena.copy_from_slice(column.arena());
let base = base as u64;
for (slot, view) in into_views.iter_mut().zip(column.views()) {
*slot = view.shifted(base);
}
};
spread(columns.len(), &task)?;
drop(slots);
let validity = run_of(pieces, rows);
let page = Vector::string_views(ty.clone(), views, Arc::new(Buffer::from(arena)))?;
Ok(Some(page.with_validity(validity)))
}
fn apart<'a>(ty: &LogicalType, pieces: &[&'a Vector]) -> Option<Vec<&'a StringColumn>> {
if pieces.len() < 2 {
return None;
}
let mut columns = Vec::with_capacity(pieces.len());
let mut seen = HashSet::with_capacity(pieces.len());
for piece in pieces {
if piece.form() != Form::Flat || piece.logical_type() != ty || piece.is_empty() {
return None;
}
let Some(Data::Varlen(column)) = piece.data() else {
return None;
};
if !column.mostly_read() || !seen.insert(column.arena().as_ptr() as usize) {
return None;
}
columns.push(column);
}
Some(columns)
}
fn laid(ty: &LogicalType, pieces: &[&Vector]) -> Result<Option<Vector>> {
if pieces.is_empty() {
return Ok(None);
}
let rows = pieces.iter().map(|piece| piece.len()).sum();
let shared = pieces[0].stable_dictionary_parts().map(|(_, values)| values).filter(|values| {
pieces.iter().all(|piece| {
piece.logical_type() == ty
&& !piece.is_empty()
&& piece
.stable_dictionary_parts()
.is_some_and(|(_, held)| Arc::ptr_eq(held, values))
})
});
if let Some(values) = shared {
let mut codes = Vec::with_capacity(rows);
for piece in pieces {
if let Some((held, _)) = piece.stable_dictionary_parts() {
codes.extend_from_slice(held);
}
}
let validity = run_of(pieces, rows);
return Ok(Some(
Vector::stable_dictionary(codes, Arc::clone(values))?.with_validity(validity),
));
}
if let Some(arena) = pieces[0].shared_views().map(|(_, arena)| arena).filter(|arena| {
pieces.iter().all(|piece| {
piece.logical_type() == ty
&& piece.shared_views().is_some_and(|(_, held)| Arc::ptr_eq(held, arena))
})
}) {
let mut views = Vec::with_capacity(rows);
for piece in pieces {
if let Some((held, _)) = piece.shared_views() {
views.extend_from_slice(held);
}
}
let validity = run_of(pieces, rows);
return Ok(Some(
Vector::string_views(ty.clone(), views, Arc::clone(arena))?.with_validity(validity),
));
}
let laid = pieces
.iter()
.all(|piece| piece.form() == Form::Flat && piece.logical_type() == ty && !piece.is_empty());
if !laid {
return Ok(None);
}
if let Some(data) = adjoined(pieces) {
let validity = run_of(pieces, rows);
return Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity)));
}
let mut data = data_for(ty, rows)?;
let mut arenas = arenas_of(pieces);
for piece in pieces {
let from = piece
.data()
.ok_or_else(|| Error::internal("a flat vector with no run of data in it"))?;
let appended = extend(&mut data, from, &mut arenas)?;
if appended != piece.len() {
return Err(Error::internal(format!(
"a piece of {} rows laid {appended} values end to end",
piece.len()
)));
}
}
let validity = run_of(pieces, rows);
if let Data::Varlen(column) = data {
let (views, arena) = column.into_parts();
let page = Vector::string_views(ty.clone(), views, Arc::new(arena))?;
return Ok(Some(page.with_validity(validity)));
}
Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity).into_pages()))
}
pub fn interleave(ty: &LogicalType, pieces: &[Vector], order: &[usize]) -> Result<Vector> {
interleave_placed(ty, pieces, order, None)
}
pub fn interleave_placed(
ty: &LogicalType,
pieces: &[Vector],
order: &[usize],
inverse: Option<&[u32]>,
) -> Result<Vector> {
let rows: usize = pieces.iter().map(Vector::len).sum();
if let Some(inverse) = inverse.filter(|inverse| inverse.len() != rows || order.len() != rows) {
return Err(Error::internal(format!(
"{} places and {} positions for a permutation of {rows} rows",
inverse.len(),
order.len()
)));
}
if let Some(&past) = order.iter().find(|&&index| index >= rows) {
return Err(Error::internal(format!("row {past} read out of pieces of {rows} rows")));
}
if matches!(ty, LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _)) {
let laid: Vec<Value> = pieces
.iter()
.flat_map(|piece| (0..piece.len()).map(|row| piece.value_at(row)))
.collect();
let values: Vec<Value> =
order.iter().map(|&index| laid.get(index).cloned().unwrap_or(Value::Null)).collect();
return Vector::from_values(ty.clone(), &values);
}
if let Some(merged) = merged_dictionary(ty, pieces, order, inverse)? {
return Ok(merged);
}
if let Some(inverse) = inverse {
if let Some(placed) = placed_strings(ty, pieces, inverse, 0..rows)? {
return Ok(placed);
}
if let Some(placed) = placed_fixed(ty, pieces, inverse)? {
return Ok(placed);
}
}
let mut data = data_for(ty, rows)?;
if matches!(data, Data::Empty) {
return Ok(Vector::constant(ty.clone(), Value::Null, order.len()));
}
let mut arenas = arenas_of(pieces);
if let Data::Varlen(column) = &mut data {
column.reserve_bytes(arenas.bytes());
}
let mut masks = Vec::with_capacity(pieces.len());
for piece in pieces {
let flat = piece.flatten()?;
let from = flat.data().ok_or_else(|| Error::internal("a flattened vector with no data"))?;
let appended = extend(&mut data, from, &mut arenas)?;
if appended != piece.len() {
return Err(Error::internal(format!(
"a piece of {} rows laid {appended} values end to end",
piece.len()
)));
}
masks.push((flat.len(), flat.validity().clone()));
}
let laid = if masks.iter().all(|(_, mask)| matches!(mask, Validity::AllValid)) {
Validity::AllValid
} else {
let mut live = Vec::with_capacity(rows);
for (len, mask) in &masks {
live.extend((0..*len).map(|row| mask.is_valid(row)));
}
Validity::from_run(&live)
};
if laid.count_valid(rows) == 0 {
return Ok(Vector::constant(ty.clone(), Value::Null, order.len()));
}
let validity = match (laid, inverse) {
(Validity::AllValid, _) => Validity::AllValid,
(laid, Some(inverse)) => {
let mut live = vec![false; order.len()];
for (row, &to) in inverse.iter().enumerate() {
if let Some(slot) = live.get_mut(to as usize) {
*slot = laid.is_valid(row);
}
}
Validity::from_run(&live)
}
(laid, None) => Validity::from_iter(order.len(), |row| {
order.get(row).is_some_and(|&index| laid.is_valid(index))
}),
};
if let Data::Varlen(column) = data {
let (views, arena) = column.into_parts();
let gathered = match inverse {
Some(inverse) => {
let mut placed = vec![StringView::empty(); order.len()];
for (view, &to) in views.iter().zip(inverse) {
if let Some(slot) = placed.get_mut(to as usize) {
*slot = *view;
}
}
placed
}
None => order
.iter()
.map(|&index| views.get(index).copied().unwrap_or_else(StringView::empty))
.collect(),
};
return Ok(
Vector::string_views(ty.clone(), gathered, Arc::new(arena))?.with_validity(validity)
);
}
let data = match inverse {
Some(inverse) => placed_of(&data, inverse),
None => copy_of(&data, order),
};
Ok(Vector::flat(ty.clone(), data)?.with_validity(validity))
}
fn placed_fixed(ty: &LogicalType, pieces: &[Vector], inverse: &[u32]) -> Result<Option<Vector>> {
let rows = inverse.len();
let mut live: Option<Vec<bool>> = None;
let mut base = 0;
let mut mark = |mask: &Validity, places: &[u32]| {
if matches!(mask, Validity::AllValid) {
return;
}
let live = live.get_or_insert_with(|| vec![true; rows]);
for (row, &to) in places.iter().enumerate() {
if let Some(slot) = live.get_mut(to as usize) {
*slot = mask.is_valid(row);
}
}
};
macro_rules! placed {
($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
match data_for(ty, 0)? {
$(Data::$variant(_) => {
let mut out: Vec<$native> = vec![$zero; rows];
for piece in pieces {
let len = piece.len();
let places = inverse.get(base..base + len).ok_or_else(|| {
Error::internal("pieces longer than the places they are written to")
})?;
base += len;
let coded = piece.dictionary_parts().and_then(|(codes, values)| {
match (values.form(), values.validity(), values.data()) {
(Form::Flat, Validity::AllValid, Some(Data::$variant(held))) => {
Some((codes, held.as_slice()))
}
_ => None,
}
});
if let Some((codes, held)) = coded {
for (&code, &to) in codes.iter().zip(places) {
if let (Some(slot), Some(value)) =
(out.get_mut(to as usize), held.get(code as usize))
{
*slot = *value;
}
}
mark(piece.validity(), places);
continue;
}
let flat;
let piece = if piece.form() == Form::Flat {
piece
} else {
flat = piece.flatten()?;
&flat
};
let Some(Data::$variant(values)) = piece.data() else {
return Err(Error::internal(format!(
"a piece of {} laid into a column of {ty}",
piece.logical_type()
)));
};
if values.len() != len {
return Err(Error::internal(format!(
"a piece of {len} rows holds {} values",
values.len()
)));
}
for (value, &to) in values.iter().zip(places) {
if let Some(slot) = out.get_mut(to as usize) {
*slot = *value;
}
}
mark(piece.validity(), places);
}
let validity = match live {
None => Validity::AllValid,
Some(live) if !live.contains(&true) => {
return Ok(Some(Vector::constant(ty.clone(), Value::Null, rows)));
}
Some(live) => Validity::from_run(&live),
};
let data = Data::$variant(Buffer::from_vec(out));
Ok(Some(Vector::flat(ty.clone(), data)?.with_validity(validity)))
})+
_ => Ok(None),
}
};
}
crate::for_each_layout!(fixed, placed)
}
fn placed_strings(
ty: &LogicalType,
pieces: &[Vector],
inverse: &[u32],
range: Range<usize>,
) -> Result<Option<Vector>> {
if !strings_placeable(ty, pieces) {
return Ok(None);
}
let first = range.start;
let rows = range.len();
let local = |to: u32| (to as usize).checked_sub(first).filter(|&at| at < rows);
let mut offsets = vec![0u64; rows + 1];
let mut places = inverse.iter();
for piece in pieces {
let (views, _) = piece.text_parts().unwrap_or_default();
for (view, &to) in views.iter().zip(places.by_ref()) {
if view.is_inline() {
continue;
}
if let Some(slot) = local(to).and_then(|at| offsets.get_mut(at + 1)) {
*slot = view.len() as u64;
}
}
}
let mut total = 0;
for offset in &mut offsets {
total += *offset;
*offset = total;
}
let mut arena =
vec![0u8; usize::try_from(total).map_err(|_| Error::internal("an arena too large"))?];
let mut placed = vec![StringView::empty(); rows];
let mut live = vec![true; rows];
let mut places = inverse.iter();
for piece in pieces {
let (views, from) = piece.text_parts().unwrap_or_default();
let validity = piece.validity();
for (row, (view, &to)) in views.iter().zip(places.by_ref()).enumerate() {
let Some(to) = local(to) else {
continue;
};
if !validity.is_valid(row) {
if let Some(slot) = live.get_mut(to) {
*slot = false;
}
continue;
}
let (Some(bytes), Some(&at), Some(slot)) =
(view.bytes_in(from), offsets.get(to), placed.get_mut(to))
else {
continue;
};
if view.is_inline() {
*slot = *view;
continue;
}
if let Some(into) = arena.get_mut(at as usize..at as usize + bytes.len()) {
into.copy_from_slice(bytes);
}
*slot = StringView::over(bytes, at);
}
}
let validity = if live.iter().all(|&valid| valid) {
Validity::AllValid
} else {
Validity::from_run(&live)
};
let vector = Vector::string_views(ty.clone(), placed, Arc::new(Buffer::from_vec(arena)))?;
Ok(Some(vector.with_validity(validity)))
}
#[must_use]
pub fn strings_placeable(ty: &LogicalType, pieces: &[Vector]) -> bool {
matches!(ty, LogicalType::Varchar | LogicalType::Blob)
&& pieces.iter().all(|piece| piece.text_parts().is_some())
}
pub fn placed_string_rows(
ty: &LogicalType,
pieces: &[Vector],
inverse: &[u32],
range: Range<usize>,
) -> Result<Vector> {
let rows: usize = pieces.iter().map(Vector::len).sum();
if inverse.len() != rows || range.end > rows || range.start > range.end {
return Err(Error::internal(format!(
"rows {range:?} of {} places for {rows} rows",
inverse.len()
)));
}
placed_strings(ty, pieces, inverse, range)?
.ok_or_else(|| Error::internal("a string column placed that is not flat views"))
}
const ROWS_PER_MERGED_ENTRY: usize = 8;
fn merged_dictionary(
ty: &LogicalType,
pieces: &[Vector],
order: &[usize],
inverse: Option<&[u32]>,
) -> Result<Option<Vector>> {
if !matches!(ty, LogicalType::Varchar | LogicalType::Blob) || pieces.is_empty() {
return Ok(None);
}
let rows: usize = pieces.iter().map(Vector::len).sum();
let mut dictionaries: Vec<&Arc<Vector>> = Vec::new();
let mut which = Vec::with_capacity(pieces.len());
let mut entries = 0;
for piece in pieces {
let Some((_, values)) = piece.shared_dictionary_parts() else {
return Ok(None);
};
if !matches!(piece.validity(), Validity::AllValid) {
return Ok(None);
}
let at = match dictionaries.iter().position(|seen| Arc::ptr_eq(seen, values)) {
Some(at) => at,
None => {
entries += values.len();
if entries.saturating_mul(ROWS_PER_MERGED_ENTRY) > rows {
return Ok(None);
}
dictionaries.push(values);
dictionaries.len() - 1
}
};
which.push(at);
}
let mut merged: HashMap<Option<&[u8]>, u32> = HashMap::new();
let mut values = Vec::new();
let mut remaps = Vec::with_capacity(dictionaries.len());
for dictionary in &dictionaries {
let mut remap = Vec::with_capacity(dictionary.len());
for entry in 0..dictionary.len() {
let next = u32::try_from(values.len())
.map_err(|_| Error::internal("a merged dictionary past four billion entries"))?;
let code = *merged.entry(dictionary.bytes_at(entry)).or_insert_with(|| {
values.push(dictionary.value_at(entry));
next
});
remap.push(code);
}
remaps.push(remap);
}
let mut laid = Vec::with_capacity(rows);
for (piece, &at) in pieces.iter().zip(&which) {
let (codes, _) = piece
.dictionary_parts()
.ok_or_else(|| Error::internal("a dictionary piece lost its dictionary"))?;
let remap = &remaps[at];
laid.extend(codes.iter().map(|&code| remap[code as usize]));
}
let codes = match inverse {
Some(inverse) => {
let mut codes = vec![0u32; order.len()];
for (&code, &to) in laid.iter().zip(inverse) {
if let Some(slot) = codes.get_mut(to as usize) {
*slot = code;
}
}
codes
}
None => order.iter().map(|&index| laid[index]).collect(),
};
let values = Vector::from_values(ty.clone(), &values)?;
Ok(Some(Vector::stable_dictionary(codes, Arc::new(values))?))
}
fn run_of(pieces: &[&Vector], rows: usize) -> Validity {
if pieces.iter().all(|piece| matches!(piece.validity(), Validity::AllValid)) {
return Validity::AllValid;
}
if pieces.iter().all(|piece| matches!(piece.validity(), Validity::AllInvalid)) {
return Validity::AllInvalid;
}
let mut live = Vec::with_capacity(rows);
for piece in pieces {
for row in 0..piece.len() {
live.push(!piece.is_null_at(row));
}
}
Validity::from_run(&live)
}
fn straight(at: &[usize]) -> bool {
at.iter().enumerate().all(|(row, &index)| row == index)
}
fn arenas_of<V: AsRef<Vector>>(pieces: &[V]) -> Arenas {
let mut arenas = Arenas::default();
for piece in pieces {
if let Some(Data::Varlen(column)) = piece.as_ref().data() {
arenas.count(column);
}
}
arenas
}
fn adjoined(pieces: &[&Vector]) -> Option<Data> {
macro_rules! joined {
($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
match pieces.first()?.data()? {
$(Data::$variant(first) => {
if !first.is_shared() {
return None;
}
let mut run = first.clone();
for piece in &pieces[1..] {
let Some(Data::$variant(next)) = piece.data() else { return None };
run = run.joined(next)?;
}
Some(Data::$variant(run))
})+
Data::Varlen(first) => {
if !first.is_paged() {
return None;
}
let mut run = first.clone();
for piece in &pieces[1..] {
let Some(Data::Varlen(next)) = piece.data() else { return None };
run = run.joined(next)?;
}
Some(Data::Varlen(run))
}
_ => None,
}
};
}
crate::for_each_layout!(fixed, joined)
}
fn extend(into: &mut Data, from: &Data, arenas: &mut Arenas) -> Result<usize> {
macro_rules! extended {
($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
match (&mut *into, from) {
(_, Data::Empty) => Ok(0),
$((Data::$variant(out), Data::$variant(values)) => {
out.extend_from_slice(values.as_slice());
Ok(values.len())
})+
(Data::Varlen(out), Data::Varlen(values)) => {
out.push_column(values, arenas);
Ok(values.len())
}
(out, from) => Err(Error::internal(format!(
"a run of {:?} values cannot be laid after a run of {:?} ones",
layout_of(from),
layout_of(out)
))),
}
};
}
crate::for_each_layout!(fixed, extended)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Chunk, Form};
fn values(vector: &Vector) -> Vec<Value> {
(0..vector.len()).map(|row| vector.value_at(row)).collect()
}
fn scattered(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
let mut answers = vec![Value::Null; rows];
for (positions, piece) in pieces {
for (slot, &row) in positions.iter().enumerate() {
answers[row as usize] = piece.value_at(slot);
}
}
Vector::from_values(ty.clone(), &answers).expect("the reference builds")
}
fn agrees(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
let mut assembly = Assembly::new(ty.clone(), rows).expect("an assembly of this type");
for (positions, piece) in pieces {
assembly.place(positions, piece).expect("the piece is placed");
}
let built = assembly.finish().expect("the assembly finishes");
assert_eq!(built.len(), rows, "an assembly of {rows} rows");
assert_eq!(values(&built), values(&scattered(ty, rows, pieces)), "against the slow way");
built
}
#[test]
fn two_pieces_interleave_back_into_the_order_the_rows_came_in() {
let evens = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(0), Value::BigInt(2)])
.expect("a vector");
let odds = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(3)])
.expect("a vector");
let built = agrees(&LogicalType::BigInt, 4, &[(vec![0, 2], evens), (vec![1, 3], odds)]);
assert_eq!(
values(&built),
vec![Value::BigInt(0), Value::BigInt(1), Value::BigInt(2), Value::BigInt(3)]
);
}
#[test]
fn a_row_no_piece_claims_is_null() {
let piece =
Vector::from_values(LogicalType::BigInt, &[Value::BigInt(7)]).expect("a vector");
let built = agrees(&LogicalType::BigInt, 3, &[(vec![1], piece)]);
assert_eq!(values(&built), vec![Value::Null, Value::BigInt(7), Value::Null]);
}
#[test]
fn no_pieces_at_all_is_a_column_of_nulls_of_the_right_length() {
let built = agrees(&LogicalType::Integer, 5, &[]);
assert!(built.is_null_at(4), "every row of it is null");
}
#[test]
fn a_null_inside_a_piece_stays_null_where_the_piece_put_it() {
let piece = Vector::from_values(
LogicalType::BigInt,
&[Value::BigInt(1), Value::Null, Value::BigInt(3)],
)
.expect("a vector");
let built = agrees(&LogicalType::BigInt, 3, &[(vec![2, 0, 1], piece)]);
assert!(built.is_null_at(0), "the null landed where the piece put it");
assert_eq!(built.value_at(2), Value::BigInt(1));
}
#[test]
fn strings_are_assembled_without_going_through_a_value_each() {
let left = Vector::from_values(
LogicalType::Varchar,
&[Value::Varchar("a short one".into()), Value::Varchar("another".into())],
)
.expect("a vector");
let right = Vector::from_values(
LogicalType::Varchar,
&[Value::Varchar("a string that is far too long to live inline in a view".into())],
)
.expect("a vector");
let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 2], left), (vec![1], right)]);
assert_eq!(built.value_at(0), Value::Varchar("a short one".into()));
assert_eq!(
built.value_at(1),
Value::Varchar("a string that is far too long to live inline in a view".into())
);
assert_eq!(built.value_at(2), Value::Varchar("another".into()));
}
#[test]
fn strings_laid_end_to_end_in_order_come_back_as_views_over_the_arena_they_went_into() {
let first = Vector::from_values(
LogicalType::Varchar,
&[Value::Varchar("one".into()), Value::Varchar("two".into())],
)
.expect("a vector");
let second = Vector::from_values(
LogicalType::Varchar,
&[Value::Varchar("a third one long enough to be out of line".into())],
)
.expect("a vector");
let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1], first), (vec![2], second)]);
assert_eq!(built.form(), Form::StringView, "the bytes stay where they were appended");
assert_eq!(
built.value_at(2),
Value::Varchar("a third one long enough to be out of line".into())
);
}
#[test]
fn a_string_row_no_piece_claims_is_null_rather_than_empty() {
let piece = Vector::from_values(
LogicalType::Varchar,
&[Value::Varchar("a value long enough to be out of line".into())],
)
.expect("a vector");
let built = agrees(&LogicalType::Varchar, 3, &[(vec![2], piece)]);
assert_eq!(built.value_at(0), Value::Null);
assert_eq!(built.value_at(1), Value::Null);
assert_eq!(
built.value_at(2),
Value::Varchar("a value long enough to be out of line".into())
);
}
#[test]
fn a_constant_piece_is_written_out_rather_than_read_a_row_at_a_time() {
let arm = Vector::from_values(LogicalType::Varchar, &[Value::Varchar("kept".into())])
.expect("a vector");
let otherwise = Vector::constant(LogicalType::Varchar, Value::Varchar("".into()), 3);
let built = agrees(&LogicalType::Varchar, 4, &[(vec![2], arm), (vec![0, 1, 3], otherwise)]);
assert_eq!(built.value_at(0), Value::Varchar("".into()));
assert_eq!(built.value_at(2), Value::Varchar("kept".into()));
}
#[test]
fn a_dictionary_piece_is_walked_to_its_values() {
let dictionary = Vector::from_values(
LogicalType::Varchar,
&[Value::Varchar("one".into()), Value::Varchar("two".into())],
)
.expect("a dictionary");
let piece = Vector::dictionary(vec![1, 0, 1], dictionary).expect("a dictionary vector");
let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1, 2], piece)]);
assert_eq!(
values(&built),
vec![
Value::Varchar("two".into()),
Value::Varchar("one".into()),
Value::Varchar("two".into())
]
);
}
#[test]
fn a_piece_placed_at_the_wrong_number_of_positions_is_an_error() {
let piece =
Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
let mut assembly = Assembly::new(LogicalType::BigInt, 4).expect("an assembly");
assert!(assembly.place(&[0, 1], &piece).is_err(), "two positions for one row");
}
#[test]
fn a_position_past_the_end_is_an_error_rather_than_a_lost_row() {
let piece =
Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
let mut assembly = Assembly::new(LogicalType::BigInt, 2).expect("an assembly");
assert!(assembly.place(&[9], &piece).is_err(), "a row past the end of the assembly");
}
#[test]
fn a_piece_of_the_wrong_layout_is_an_error_rather_than_a_wrong_answer() {
let piece =
Vector::from_values(LogicalType::Varchar, &[Value::Varchar("x".into())]).expect("text");
let mut assembly = Assembly::new(LogicalType::BigInt, 1).expect("an assembly");
assert!(assembly.place(&[0], &piece).is_err(), "text laid after integers");
}
#[test]
fn every_layout_assembles_the_way_it_scatters() {
let cases: Vec<(LogicalType, Vec<Value>)> = vec![
(LogicalType::Boolean, vec![Value::Boolean(true), Value::Boolean(false)]),
(LogicalType::TinyInt, vec![Value::TinyInt(1), Value::TinyInt(-2)]),
(LogicalType::SmallInt, vec![Value::SmallInt(3), Value::SmallInt(-4)]),
(LogicalType::Integer, vec![Value::Integer(5), Value::Integer(-6)]),
(LogicalType::BigInt, vec![Value::BigInt(7), Value::BigInt(-8)]),
(LogicalType::HugeInt, vec![Value::HugeInt(9), Value::HugeInt(-10)]),
(LogicalType::UTinyInt, vec![Value::UTinyInt(11), Value::UTinyInt(12)]),
(LogicalType::USmallInt, vec![Value::USmallInt(13), Value::USmallInt(14)]),
(LogicalType::UInteger, vec![Value::UInteger(15), Value::UInteger(16)]),
(LogicalType::UBigInt, vec![Value::UBigInt(17), Value::UBigInt(18)]),
(LogicalType::Float, vec![Value::Float(1.5), Value::Float(-2.5)]),
(LogicalType::Double, vec![Value::Double(3.5), Value::Double(-4.5)]),
(
LogicalType::Varchar,
vec![Value::Varchar("first".into()), Value::Varchar("second".into())],
),
(LogicalType::Date, vec![Value::Date(19), Value::Date(20)]),
];
for (ty, pair) in cases {
let left = Vector::from_values(ty.clone(), &pair[..1]).expect("a vector");
let right = Vector::from_values(ty.clone(), &pair[1..]).expect("a vector");
let built = agrees(&ty, 2, &[(vec![1], left), (vec![0], right)]);
assert_eq!(built.value_at(0), pair[1], "{ty:?} at row 0");
assert_eq!(built.value_at(1), pair[0], "{ty:?} at row 1");
}
}
#[test]
fn an_assembly_is_a_chunk_column_like_any_other() {
let piece = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(2)])
.expect("a vector");
let built = agrees(&LogicalType::BigInt, 2, &[(vec![1, 0], piece)]);
let chunk = Chunk::new(vec![built]).expect("a chunk of one column");
assert_eq!(chunk.len(), 2, "two rows");
}
fn all_of(pieces: &[Vector]) -> Vec<Value> {
pieces.iter().flat_map(values).collect()
}
fn laid(ty: &LogicalType, pieces: &[Vector]) -> Vector {
let built = concat(ty, pieces).expect("the pieces lay").expect("this run lays");
assert_eq!(built.len(), pieces.iter().map(Vector::len).sum::<usize>(), "the row count");
assert_eq!(values(&built), all_of(pieces), "the values laid end to end");
built
}
#[test]
fn pieces_laid_end_to_end_read_back_in_the_order_they_were_given() {
let piece = |from: i64, to: i64| {
let held: Vec<Value> = (from..to).map(Value::BigInt).collect();
Vector::from_values(LogicalType::BigInt, &held).expect("a run of bigints")
};
let pieces = [piece(0, 4), piece(4, 9), piece(9, 10)];
let built = laid(&LogicalType::BigInt, &pieces);
assert_eq!(built.form(), Form::Flat, "a run of flat pieces lays flat");
let window = built.slice(4, 5).expect("a window into the page");
assert_eq!(values(&window), all_of(&pieces[1..2]), "the second piece, cut back out");
}
#[test]
fn neighbouring_windows_of_one_page_lay_without_a_copy() {
let held: Vec<Value> =
(0..20).map(|at| if at % 7 == 3 { Value::Null } else { Value::BigInt(at) }).collect();
let page = Vector::from_values(LogicalType::BigInt, &held).expect("a run").into_pages();
let cut = |from: usize, len: usize| page.slice(from, len).expect("a window");
let address = |vector: &Vector| match vector.data() {
Some(Data::Int64(run)) => run.as_slice().as_ptr() as usize,
other => panic!("a bigint run laid as {other:?}"),
};
let built = laid(&LogicalType::BigInt, &[cut(2, 5), cut(7, 8), cut(15, 3)]);
assert_eq!(address(&built), address(&page) + 2 * 8, "the neighbours were copied");
let other = Vector::from_values(LogicalType::BigInt, &held).expect("a run").into_pages();
let other_cut = other.slice(7, 3).expect("a window");
for pieces in [
vec![cut(2, 5), cut(8, 3)],
vec![cut(7, 3), cut(2, 5)],
vec![cut(2, 5), other_cut],
vec![Vector::from_values(LogicalType::BigInt, &held[..4]).expect("owned"), cut(4, 2)],
] {
let built = laid(&LogicalType::BigInt, &pieces);
assert_ne!(address(&built), address(&page) + 2 * 8, "a copy was expected");
}
}
#[test]
fn neighbouring_cuts_of_a_paged_string_column_lay_without_a_copy() {
let held: Vec<Value> = (0..20)
.map(|at| Value::Varchar(format!("a string long enough for the arena {at}")))
.collect();
let page = Vector::from_values(LogicalType::Varchar, &held).expect("a run").into_pages();
let cut = |from: usize, len: usize| page.slice(from, len).expect("a window");
let views = |vector: &Vector| match vector.data() {
Some(Data::Varlen(column)) => column.views().as_ptr() as usize,
other => panic!("a varchar run laid as {other:?}"),
};
let built = laid(&LogicalType::Varchar, &[cut(2, 5), cut(7, 8), cut(15, 3)]);
assert_eq!(views(&built), views(&page) + 2 * size_of::<StringView>(), "views copied");
let owned = Vector::from_values(LogicalType::Varchar, &held).expect("a run");
let copied = laid(&LogicalType::Varchar, &[owned.slice(0, 4).expect("a cut"), cut(4, 2)]);
assert_eq!(copied.len(), 6);
}
#[test]
fn a_null_in_a_piece_is_a_null_in_the_same_row_of_the_page() {
let ty = LogicalType::Integer;
let whole = Vector::from_values(ty.clone(), &[Value::Integer(1), Value::Integer(2)])
.expect("no nulls");
let holed =
Vector::from_values(ty.clone(), &[Value::Null, Value::Integer(4)]).expect("one null");
let built = laid(&ty, &[whole.clone(), holed.clone()]);
assert!(!built.is_null_at(1), "a row that was not null became one");
assert!(built.is_null_at(2), "the null did not come through");
let clean = laid(&ty, &[whole.clone(), whole]);
assert_eq!(clean.validity(), &Validity::AllValid, "a mask nothing needed");
let empty = laid(&ty, &[holed.clone(), holed]);
assert!(empty.is_null_at(0) && empty.is_null_at(2), "both nulls came through");
}
#[test]
fn strings_lay_into_one_arena_and_come_back_as_views() {
let ty = LogicalType::Varchar;
let word = |text: &str| {
Vector::from_values(ty.clone(), &[Value::Varchar(text.to_string())]).expect("a string")
};
let pieces = [word("a string too long to sit inside a view"), word("short")];
let built = laid(&ty, &pieces);
assert_eq!(
built.form(),
Form::StringView,
"a varchar page that is not views cuts by copying"
);
let window = built.slice(0, 1).expect("a window into the page");
assert_eq!(values(&window), all_of(&pieces[..1]), "the long string, cut back out");
}
#[test]
fn stable_dictionary_pieces_sharing_values_lay_as_codes() {
let ty = LogicalType::Varchar;
let values = Arc::new(
Vector::from_values(
ty.clone(),
&[Value::Varchar("a".to_string()), Value::Varchar("b".to_string())],
)
.expect("dictionary values"),
);
let first = Vector::stable_dictionary(vec![1, 0], Arc::clone(&values)).expect("codes");
let second = Vector::stable_dictionary(vec![1], Arc::clone(&values)).expect("codes");
let built = concat(&ty, &[first, second]).expect("no error").expect("shared codes lay");
let (codes, held) = built.stable_dictionary_parts().expect("the stable form survives");
assert_eq!(codes, &[1, 0, 1]);
assert!(Arc::ptr_eq(held, &values));
}
#[test]
fn an_encoded_piece_is_left_alone_rather_than_flattened() {
let ty = LogicalType::BigInt;
let flat = Vector::from_values(ty.clone(), &[Value::BigInt(1)]).expect("a flat piece");
let values = Vector::from_values(ty.clone(), &[Value::BigInt(7), Value::BigInt(8)])
.expect("two distinct values");
let coded = Vector::dictionary(vec![0, 1, 0], values).expect("a dictionary piece");
let one = std::slice::from_ref(&coded);
assert!(concat(&ty, one).expect("no error").is_none(), "a dictionary laid");
assert!(
concat(&ty, &[flat.clone(), coded]).expect("no error").is_none(),
"a mixed run laid"
);
assert!(
concat::<Vector>(&ty, &[]).expect("no error").is_none(),
"nothing laid into something"
);
let other =
Vector::from_values(LogicalType::Integer, &[Value::Integer(1)]).expect("an int");
assert!(concat(&ty, &[flat, other]).expect("no error").is_none(), "two types laid");
}
fn on_a_thread_each(count: usize, task: &(dyn Fn(usize) + Sync)) -> Result<()> {
std::thread::scope(|scope| {
let running: Vec<_> =
(0..count).rev().map(|at| scope.spawn(move || task(at))).collect();
for thread in running {
thread.join().expect("a piece copier panicked");
}
});
Ok(())
}
fn owned_strings(pieces: usize, each: usize) -> Vec<Vector> {
(0..pieces)
.map(|piece| {
let held: Vec<Value> = (0..each)
.map(|row| match (piece + row) % 4 {
0 => Value::Null,
1 => Value::Varchar(format!("short {row}")),
_ => Value::Varchar(format!(
"a string of piece {piece} row {row} that is well past twelve bytes"
)),
})
.collect();
Vector::from_values(LogicalType::Varchar, &held).expect("a run of strings")
})
.collect()
}
#[test]
fn string_pieces_laid_on_many_threads_hold_the_same_strings_as_laid_on_one() {
let ty = LogicalType::Varchar;
let pieces = owned_strings(9, 7);
let borrowed: Vec<&Vector> = pieces.iter().collect();
assert!(apart(&ty, &borrowed).is_some(), "the parallel lay declined its own case");
let serial = concat(&ty, &pieces).expect("no error").expect("owned arenas lay");
let parallel = concat_on(&ty, &pieces, &on_a_thread_each)
.expect("no error")
.expect("owned arenas lay");
assert_eq!(parallel.len(), serial.len(), "the row count");
assert_eq!(values(¶llel), all_of(&pieces), "the values laid end to end");
assert_eq!(values(¶llel), values(&serial), "the two paths disagree");
assert_eq!(parallel.form(), serial.form(), "a different body came out");
}
#[test]
fn a_run_the_parallel_lay_does_not_own_is_left_to_the_serial_one() {
let ty = LogicalType::Varchar;
let pieces = owned_strings(3, 5);
assert!(apart(&ty, &[&pieces[0]]).is_none(), "one piece was taken");
let page = concat(&ty, &pieces).expect("no error").expect("a page").into_pages();
let cut = |from: usize, len: usize| page.slice(from, len).expect("a window");
let cuts = [cut(0, 4), cut(4, 6), cut(10, 5)];
let borrowed: Vec<&Vector> = cuts.iter().collect();
assert!(apart(&ty, &borrowed).is_none(), "cuts of one page were taken");
let serial = concat(&ty, &cuts).expect("no error").expect("shared views lay");
let parallel =
concat_on(&ty, &cuts, &on_a_thread_each).expect("no error").expect("shared views");
assert_eq!(values(¶llel), values(&serial), "the fall through changed the answer");
}
#[test]
fn a_piece_holding_more_arena_than_it_reads_is_left_to_the_serial_lay() {
let ty = LogicalType::Varchar;
let pieces = owned_strings(2, 8);
let page = concat(&ty, &pieces).expect("no error").expect("a page");
let thin = page.slice(2, 1).expect("a window").flatten().expect("flattened");
let fat = page.slice(3, 1).expect("a window").flatten().expect("flattened");
let held = [thin, fat];
let borrowed: Vec<&Vector> = held.iter().collect();
if borrowed.iter().all(|piece| match piece.data() {
Some(Data::Varlen(column)) => !column.mostly_read(),
_ => false,
}) {
assert!(apart(&ty, &borrowed).is_none(), "a mostly unread arena was taken");
}
let serial = concat(&ty, &held).expect("no error").expect("flat pieces lay");
let parallel =
concat_on(&ty, &held, &on_a_thread_each).expect("no error").expect("flat pieces");
assert_eq!(values(¶llel), values(&serial), "the two paths disagree");
}
#[test]
fn an_interleave_reads_the_pieces_in_the_order_it_is_given() {
let words: Vec<Value> = ["a long enough word to leave the inline view", "b", "c"]
.iter()
.map(|word| Value::Varchar((*word).to_string()))
.collect();
let dictionary = Vector::from_values(LogicalType::Varchar, &words).expect("words");
let strings = [
Vector::dictionary(vec![2, 0, 1], dictionary).expect("a dictionary"),
Vector::from_values(
LogicalType::Varchar,
&[Value::Null, Value::Varchar("another string past twelve bytes".to_string())],
)
.expect("flat"),
];
let numbers = [
Vector::from_values(
LogicalType::BigInt,
&[Value::BigInt(7), Value::Null, Value::BigInt(9)],
)
.expect("flat"),
Vector::constant(LogicalType::BigInt, Value::BigInt(4), 1),
Vector::constant(LogicalType::BigInt, Value::Null, 1),
];
let lists = [
Vector::from_values(
LogicalType::List(Box::new(LogicalType::Integer)),
&[
Value::List { element: LogicalType::Integer, values: vec![Value::Integer(1)] },
Value::Null,
Value::List { element: LogicalType::Integer, values: vec![] },
],
)
.expect("lists"),
Vector::from_values(
LogicalType::List(Box::new(LogicalType::Integer)),
&[
Value::List {
element: LogicalType::Integer,
values: vec![Value::Integer(2), Value::Integer(3)],
},
Value::Null,
],
)
.expect("lists"),
];
let order = [4, 0, 3, 1, 2, 3];
for pieces in [&strings[..], &numbers[..], &lists[..]] {
let ty = pieces[0].logical_type().clone();
let laid: Vec<Value> = pieces.iter().flat_map(values).collect();
let expected: Vec<Value> = order.iter().map(|&index| laid[index].clone()).collect();
let got = interleave(&ty, pieces, &order).expect("an interleave");
assert_eq!(values(&got), expected, "{ty}");
}
assert!(interleave(&LogicalType::BigInt, &numbers, &[5]).is_err(), "row 5 of 5 rows");
let order = [4, 0, 3, 1, 2];
let mut inverse = [0u32; 5];
for (at, &row) in order.iter().enumerate() {
inverse[row] = at as u32;
}
let texts: Vec<Value> = ["a string past the twelve bytes of a view", "short", "x"]
.iter()
.map(|text| Value::Varchar((*text).to_string()))
.chain([Value::Varchar("another long string for the arena".to_string())])
.collect();
let valid = [
Vector::from_values(LogicalType::Varchar, &texts[..2]).expect("flat"),
Vector::from_values(LogicalType::Varchar, &texts[2..]).expect("flat"),
Vector::constant(LogicalType::Varchar, Value::Varchar("one more".to_string()), 1),
];
for pieces in [&strings[..], &numbers[..], &lists[..], &valid[..]] {
let ty = pieces[0].logical_type().clone();
let pulled = interleave(&ty, pieces, &order).expect("an interleave");
let pushed =
interleave_placed(&ty, pieces, &order, Some(&inverse)).expect("a placed one");
assert_eq!(values(&pushed), values(&pulled), "{ty}");
}
assert!(
interleave_placed(&LogicalType::BigInt, &numbers, &order, Some(&inverse[..4])).is_err(),
"four places for five rows"
);
let untyped = [Vector::constant(LogicalType::Null, Value::Null, 3)];
let got = interleave(&LogicalType::Null, &untyped, &[2, 0]).expect("an untyped null");
assert_eq!(values(&got), vec![Value::Null, Value::Null]);
}
#[test]
fn a_fixed_width_column_is_written_to_its_places_from_pieces_of_any_form() {
let ty = LogicalType::BigInt;
let int = Value::BigInt;
let flat = Vector::from_values(ty.clone(), &[int(1), Value::Null, int(3)]).expect("flat");
let paged = Vector::from_values(ty.clone(), &[int(4), int(5)]).expect("flat").into_pages();
let words = Vector::from_values(ty.clone(), &[int(70), int(80)]).expect("values");
let coded = Vector::dictionary(vec![1, 0, 1], words).expect("coded");
let nulled = Vector::from_values(ty.clone(), &[int(90), Value::Null]).expect("values");
let chained = Vector::dictionary(vec![1, 0], nulled).expect("coded over nulls");
let constant = Vector::constant(ty.clone(), int(6), 2);
let pieces = [flat, paged, coded, chained, constant];
let rows: usize = pieces.iter().map(Vector::len).sum();
let order: Vec<usize> = (0..rows).map(|at| (at * 5 + 3) % rows).collect();
let mut inverse = vec![0u32; rows];
for (to, &from) in order.iter().enumerate() {
inverse[from] = u32::try_from(to).expect("a small row");
}
let read = interleave_placed(&ty, &pieces, &order, None).expect("read through order");
let written =
interleave_placed(&ty, &pieces, &order, Some(&inverse)).expect("written to places");
assert_eq!(values(&written), values(&read));
assert_eq!(values(&written)[inverse[1] as usize], Value::Null, "the flat piece's null");
assert_eq!(values(&written)[inverse[8] as usize], Value::Null, "the dictionary's null");
let nothing = Vector::from_values(ty.clone(), &[Value::Null, Value::Null]).expect("nulls");
let written = interleave_placed(&ty, &[nothing], &[1, 0], Some(&[1, 0])).expect("nulls");
assert_eq!(values(&written), [Value::Null, Value::Null]);
}
#[test]
fn placed_strings_are_laid_in_the_order_of_the_result() {
let word = |text: &str| Value::Varchar(text.to_string());
let flat = Vector::from_values(
LogicalType::Varchar,
&[word("the first string past twelve bytes"), Value::Null, word("short")],
)
.expect("flat");
let arena = b"xxa second string past twelve bytesyy".to_vec();
let views = vec![StringView::over(&arena[2..35], 2), StringView::inline("tiny")];
let viewed =
Vector::string_views(LogicalType::Varchar, views, Arc::new(Buffer::from_vec(arena)))
.expect("views");
let pieces = [flat, viewed];
let order = [3, 0, 4, 2, 1];
let mut inverse = vec![0u32; order.len()];
for (to, &from) in order.iter().enumerate() {
inverse[from] = u32::try_from(to).expect("a small row");
}
let laid: Vec<Value> = pieces.iter().flat_map(values).collect();
let expected: Vec<Value> = order.iter().map(|&index| laid[index].clone()).collect();
let got = interleave_placed(&LogicalType::Varchar, &pieces, &order, Some(&inverse))
.expect("a placed interleave");
assert_eq!(values(&got), expected);
let (_, arena) = got.text_parts().expect("views");
assert_eq!(
arena, b"a second string past twelve bytesthe first string past twelve bytes",
"the long strings in the order they come out, and nothing else"
);
assert!(strings_placeable(&LogicalType::Varchar, &pieces));
for split in 0..=order.len() {
let mut joined = Vec::new();
for range in [0..split, split..order.len()] {
let part = placed_string_rows(&LogicalType::Varchar, &pieces, &inverse, range)
.expect("a range of rows");
joined.extend(values(&part));
}
assert_eq!(joined, expected, "split at {split}");
}
let (_, arena) = placed_string_rows(&LogicalType::Varchar, &pieces, &inverse, 1..3)
.expect("the middle rows")
.text_parts()
.map(|(views, arena)| (views.len(), arena.to_vec()))
.expect("views");
assert_eq!(arena, b"the first string past twelve bytes", "only the range's own strings");
assert!(placed_string_rows(&LogicalType::Varchar, &pieces, &inverse, 4..6).is_err());
}
#[test]
fn an_interleave_of_dictionaries_merges_them_into_one() {
let word = |text: &str| Value::Varchar(text.to_string());
let first = [word("MAIL"), word("a word long enough to leave the inline view")];
let second = [Value::Null, word("MAIL"), word("SHIP")];
let first = Arc::new(Vector::from_values(LogicalType::Varchar, &first).expect("words"));
let second = Arc::new(Vector::from_values(LogicalType::Varchar, &second).expect("words"));
let over = |codes: Vec<u32>, dictionary: &Arc<Vector>| {
Vector::dictionary_over(codes, Arc::clone(dictionary)).expect("a dictionary")
};
let pieces = [
over((0..16).map(|row| row % 2).collect(), &first),
over((0..16).map(|row| row % 3).collect(), &second),
over(vec![1; 8], &first),
];
let order: Vec<usize> = (0..40).rev().collect();
let laid: Vec<Value> = pieces.iter().flat_map(values).collect();
let expected: Vec<Value> = order.iter().map(|&index| laid[index].clone()).collect();
let got = interleave(&LogicalType::Varchar, &pieces, &order).expect("an interleave");
assert_eq!(values(&got), expected);
let (_, merged) = got.stable_dictionary_parts().expect("one stable dictionary");
assert_eq!(merged.len(), 4, "MAIL once, the long word, the null and SHIP");
let mut inverse = vec![0u32; order.len()];
for (to, &from) in order.iter().enumerate() {
inverse[from] = u32::try_from(to).expect("a small row");
}
let placed = interleave_placed(&LogicalType::Varchar, &pieces, &order, Some(&inverse))
.expect("a placed interleave");
assert_eq!(values(&placed), expected, "placed codes land where pulled ones do");
assert!(placed.stable_dictionary_parts().is_some(), "and stay one dictionary");
let mixed = [pieces[0].clone(), pieces[1].flatten().expect("flat")];
let got = interleave(&LogicalType::Varchar, &mixed, &order[8..]).expect("an interleave");
assert!(got.dictionary_parts().is_none(), "a flat piece gathers flat");
let few = &pieces[..1];
let got = interleave(&LogicalType::Varchar, few, &[3, 2]).expect("an interleave");
assert_eq!(
values(&got),
vec![word("a word long enough to leave the inline view"), word("MAIL")]
);
}
}