1use std::sync::Arc;
36
37use rudb_common::{Error, LogicalType, Result, Value};
38
39use crate::string::StringView;
40use crate::validity::Validity;
41use crate::vector::{Data, NOWHERE, Vector, copy_of, empty_data_for, layout_of};
42
43#[derive(Debug)]
48pub struct Assembly {
49 ty: LogicalType,
50 rows: usize,
51 data: Data,
53 at: Vec<usize>,
55 live: Vec<bool>,
57 values: Option<Vec<Value>>,
65}
66
67impl Assembly {
68 pub fn new(ty: LogicalType, rows: usize) -> Result<Self> {
74 let nested =
75 matches!(ty, LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _));
76 let values = if nested { Some(vec![Value::Null; rows]) } else { None };
77 let data = if nested { Data::Empty } else { empty_data_for(&ty)? };
78 Ok(Self { ty, rows, data, at: vec![NOWHERE; rows], live: vec![false; rows], values })
79 }
80
81 #[must_use]
83 pub fn rows(&self) -> usize {
84 self.rows
85 }
86
87 pub fn place(&mut self, positions: &[u32], piece: &Vector) -> Result<()> {
100 if positions.len() != piece.len() {
101 return Err(Error::internal(format!(
102 "a piece of {} rows placed at {} positions",
103 piece.len(),
104 positions.len()
105 )));
106 }
107 for &row in positions {
108 if row as usize >= self.rows {
109 return Err(Error::internal(format!(
110 "row {row} placed in an assembly of {} rows",
111 self.rows
112 )));
113 }
114 }
115 if let Some(values) = &mut self.values {
116 for (slot, &row) in positions.iter().enumerate() {
120 values[row as usize] = piece.value_at(slot);
121 }
122 return Ok(());
123 }
124 let flat = piece.flatten()?;
129 let Some(from) = flat.data() else {
130 return Err(Error::internal("a flattened vector with no run of data in it"));
131 };
132 let start = self.data.len();
133 let appended = extend(&mut self.data, from)?;
134 for (slot, &row) in positions.iter().enumerate() {
135 let row = row as usize;
136 if slot < appended {
139 self.at[row] = start + slot;
140 self.live[row] = !piece.is_null_at(slot);
141 } else {
142 self.at[row] = NOWHERE;
143 self.live[row] = false;
144 }
145 }
146 Ok(())
147 }
148
149 pub fn finish(self) -> Result<Vector> {
155 if let Some(values) = self.values {
156 return Vector::from_values(self.ty, &values);
157 }
158 if matches!(self.data, Data::Empty) {
161 return Ok(Vector::constant(self.ty, Value::Null, self.rows));
162 }
163 let validity = Validity::from_run(&self.live);
164 if let Data::Varlen(column) = self.data {
170 let (laid, arena) = column.into_parts();
171 let arena = Arc::new(arena);
172 if straight(&self.at) {
173 return Ok(Vector::string_views(self.ty, laid, arena)?.with_validity(validity));
174 }
175 let views = self
176 .at
177 .iter()
178 .map(|&index| laid.get(index).copied().unwrap_or_else(StringView::empty))
179 .collect();
180 return Ok(Vector::string_views(self.ty, views, arena)?.with_validity(validity));
181 }
182 if straight(&self.at) {
186 return Ok(Vector::flat(self.ty, self.data)?.with_validity(validity));
187 }
188 let gathered = copy_of(&self.data, &self.at);
189 Ok(Vector::flat(self.ty, gathered)?.with_validity(validity))
190 }
191}
192
193fn straight(at: &[usize]) -> bool {
195 at.iter().enumerate().all(|(row, &index)| row == index)
196}
197
198fn extend(into: &mut Data, from: &Data) -> Result<usize> {
204 macro_rules! extended {
205 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
206 match (&mut *into, from) {
207 (_, Data::Empty) => Ok(0),
210 $((Data::$variant(out), Data::$variant(values)) => {
211 out.extend_from_slice(values.as_slice());
212 Ok(values.len())
213 })+
214 (Data::Varlen(out), Data::Varlen(values)) => {
218 out.reserve_views(values.len());
219 out.reserve_bytes(
220 values
221 .views()
222 .iter()
223 .filter(|view| !view.is_inline())
224 .map(StringView::len)
225 .sum(),
226 );
227 for index in 0..values.len() {
228 out.push_from(values, index);
229 }
230 Ok(values.len())
231 }
232 (out, from) => Err(Error::internal(format!(
233 "a run of {:?} values cannot be laid after a run of {:?} ones",
234 layout_of(from),
235 layout_of(out)
236 ))),
237 }
238 };
239 }
240 crate::for_each_layout!(fixed, extended)
241}
242
243#[cfg(test)]
251mod tests {
252 use super::*;
253 use crate::{Chunk, Form};
254
255 fn values(vector: &Vector) -> Vec<Value> {
257 (0..vector.len()).map(|row| vector.value_at(row)).collect()
258 }
259
260 fn scattered(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
265 let mut answers = vec![Value::Null; rows];
266 for (positions, piece) in pieces {
267 for (slot, &row) in positions.iter().enumerate() {
268 answers[row as usize] = piece.value_at(slot);
269 }
270 }
271 Vector::from_values(ty.clone(), &answers).expect("the reference builds")
272 }
273
274 fn agrees(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
276 let mut assembly = Assembly::new(ty.clone(), rows).expect("an assembly of this type");
277 for (positions, piece) in pieces {
278 assembly.place(positions, piece).expect("the piece is placed");
279 }
280 let built = assembly.finish().expect("the assembly finishes");
281 assert_eq!(built.len(), rows, "an assembly of {rows} rows");
282 assert_eq!(values(&built), values(&scattered(ty, rows, pieces)), "against the slow way");
283 built
284 }
285
286 #[test]
287 fn two_pieces_interleave_back_into_the_order_the_rows_came_in() {
288 let evens = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(0), Value::BigInt(2)])
289 .expect("a vector");
290 let odds = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(3)])
291 .expect("a vector");
292 let built = agrees(&LogicalType::BigInt, 4, &[(vec![0, 2], evens), (vec![1, 3], odds)]);
293 assert_eq!(
294 values(&built),
295 vec![Value::BigInt(0), Value::BigInt(1), Value::BigInt(2), Value::BigInt(3)]
296 );
297 }
298
299 #[test]
300 fn a_row_no_piece_claims_is_null() {
301 let piece =
304 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(7)]).expect("a vector");
305 let built = agrees(&LogicalType::BigInt, 3, &[(vec![1], piece)]);
306 assert_eq!(values(&built), vec![Value::Null, Value::BigInt(7), Value::Null]);
307 }
308
309 #[test]
310 fn no_pieces_at_all_is_a_column_of_nulls_of_the_right_length() {
311 let built = agrees(&LogicalType::Integer, 5, &[]);
312 assert!(built.is_null_at(4), "every row of it is null");
313 }
314
315 #[test]
316 fn a_null_inside_a_piece_stays_null_where_the_piece_put_it() {
317 let piece = Vector::from_values(
320 LogicalType::BigInt,
321 &[Value::BigInt(1), Value::Null, Value::BigInt(3)],
322 )
323 .expect("a vector");
324 let built = agrees(&LogicalType::BigInt, 3, &[(vec![2, 0, 1], piece)]);
325 assert!(built.is_null_at(0), "the null landed where the piece put it");
326 assert_eq!(built.value_at(2), Value::BigInt(1));
327 }
328
329 #[test]
330 fn strings_are_assembled_without_going_through_a_value_each() {
331 let left = Vector::from_values(
332 LogicalType::Varchar,
333 &[Value::Varchar("a short one".into()), Value::Varchar("another".into())],
334 )
335 .expect("a vector");
336 let right = Vector::from_values(
337 LogicalType::Varchar,
338 &[Value::Varchar("a string that is far too long to live inline in a view".into())],
339 )
340 .expect("a vector");
341 let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 2], left), (vec![1], right)]);
342 assert_eq!(built.value_at(0), Value::Varchar("a short one".into()));
343 assert_eq!(
344 built.value_at(1),
345 Value::Varchar("a string that is far too long to live inline in a view".into())
346 );
347 assert_eq!(built.value_at(2), Value::Varchar("another".into()));
348 }
349
350 #[test]
351 fn strings_laid_end_to_end_in_order_come_back_as_views_over_the_arena_they_went_into() {
352 let first = Vector::from_values(
355 LogicalType::Varchar,
356 &[Value::Varchar("one".into()), Value::Varchar("two".into())],
357 )
358 .expect("a vector");
359 let second = Vector::from_values(
360 LogicalType::Varchar,
361 &[Value::Varchar("a third one long enough to be out of line".into())],
362 )
363 .expect("a vector");
364 let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1], first), (vec![2], second)]);
365 assert_eq!(built.form(), Form::StringView, "the bytes stay where they were appended");
366 assert_eq!(
367 built.value_at(2),
368 Value::Varchar("a third one long enough to be out of line".into())
369 );
370 }
371
372 #[test]
373 fn a_string_row_no_piece_claims_is_null_rather_than_empty() {
374 let piece = Vector::from_values(
377 LogicalType::Varchar,
378 &[Value::Varchar("a value long enough to be out of line".into())],
379 )
380 .expect("a vector");
381 let built = agrees(&LogicalType::Varchar, 3, &[(vec![2], piece)]);
382 assert_eq!(built.value_at(0), Value::Null);
383 assert_eq!(built.value_at(1), Value::Null);
384 assert_eq!(
385 built.value_at(2),
386 Value::Varchar("a value long enough to be out of line".into())
387 );
388 }
389
390 #[test]
391 fn a_constant_piece_is_written_out_rather_than_read_a_row_at_a_time() {
392 let arm = Vector::from_values(LogicalType::Varchar, &[Value::Varchar("kept".into())])
395 .expect("a vector");
396 let otherwise = Vector::constant(LogicalType::Varchar, Value::Varchar("".into()), 3);
397 let built = agrees(&LogicalType::Varchar, 4, &[(vec![2], arm), (vec![0, 1, 3], otherwise)]);
398 assert_eq!(built.value_at(0), Value::Varchar("".into()));
399 assert_eq!(built.value_at(2), Value::Varchar("kept".into()));
400 }
401
402 #[test]
403 fn a_dictionary_piece_is_walked_to_its_values() {
404 let dictionary = Vector::from_values(
407 LogicalType::Varchar,
408 &[Value::Varchar("one".into()), Value::Varchar("two".into())],
409 )
410 .expect("a dictionary");
411 let piece = Vector::dictionary(vec![1, 0, 1], dictionary).expect("a dictionary vector");
412 let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1, 2], piece)]);
413 assert_eq!(
414 values(&built),
415 vec![
416 Value::Varchar("two".into()),
417 Value::Varchar("one".into()),
418 Value::Varchar("two".into())
419 ]
420 );
421 }
422
423 #[test]
424 fn a_piece_placed_at_the_wrong_number_of_positions_is_an_error() {
425 let piece =
426 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
427 let mut assembly = Assembly::new(LogicalType::BigInt, 4).expect("an assembly");
428 assert!(assembly.place(&[0, 1], &piece).is_err(), "two positions for one row");
429 }
430
431 #[test]
432 fn a_position_past_the_end_is_an_error_rather_than_a_lost_row() {
433 let piece =
434 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
435 let mut assembly = Assembly::new(LogicalType::BigInt, 2).expect("an assembly");
436 assert!(assembly.place(&[9], &piece).is_err(), "a row past the end of the assembly");
437 }
438
439 #[test]
440 fn a_piece_of_the_wrong_layout_is_an_error_rather_than_a_wrong_answer() {
441 let piece =
444 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("x".into())]).expect("text");
445 let mut assembly = Assembly::new(LogicalType::BigInt, 1).expect("an assembly");
446 assert!(assembly.place(&[0], &piece).is_err(), "text laid after integers");
447 }
448
449 #[test]
450 fn every_layout_assembles_the_way_it_scatters() {
451 let cases: Vec<(LogicalType, Vec<Value>)> = vec![
454 (LogicalType::Boolean, vec![Value::Boolean(true), Value::Boolean(false)]),
455 (LogicalType::TinyInt, vec![Value::TinyInt(1), Value::TinyInt(-2)]),
456 (LogicalType::SmallInt, vec![Value::SmallInt(3), Value::SmallInt(-4)]),
457 (LogicalType::Integer, vec![Value::Integer(5), Value::Integer(-6)]),
458 (LogicalType::BigInt, vec![Value::BigInt(7), Value::BigInt(-8)]),
459 (LogicalType::HugeInt, vec![Value::HugeInt(9), Value::HugeInt(-10)]),
460 (LogicalType::UTinyInt, vec![Value::UTinyInt(11), Value::UTinyInt(12)]),
461 (LogicalType::USmallInt, vec![Value::USmallInt(13), Value::USmallInt(14)]),
462 (LogicalType::UInteger, vec![Value::UInteger(15), Value::UInteger(16)]),
463 (LogicalType::UBigInt, vec![Value::UBigInt(17), Value::UBigInt(18)]),
464 (LogicalType::Float, vec![Value::Float(1.5), Value::Float(-2.5)]),
465 (LogicalType::Double, vec![Value::Double(3.5), Value::Double(-4.5)]),
466 (
467 LogicalType::Varchar,
468 vec![Value::Varchar("first".into()), Value::Varchar("second".into())],
469 ),
470 (LogicalType::Date, vec![Value::Date(19), Value::Date(20)]),
471 ];
472 for (ty, pair) in cases {
473 let left = Vector::from_values(ty.clone(), &pair[..1]).expect("a vector");
474 let right = Vector::from_values(ty.clone(), &pair[1..]).expect("a vector");
475 let built = agrees(&ty, 2, &[(vec![1], left), (vec![0], right)]);
476 assert_eq!(built.value_at(0), pair[1], "{ty:?} at row 0");
477 assert_eq!(built.value_at(1), pair[0], "{ty:?} at row 1");
478 }
479 }
480
481 #[test]
482 fn an_assembly_is_a_chunk_column_like_any_other() {
483 let piece = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(2)])
486 .expect("a vector");
487 let built = agrees(&LogicalType::BigInt, 2, &[(vec![1, 0], piece)]);
488 let chunk = Chunk::new(vec![built]).expect("a chunk of one column");
489 assert_eq!(chunk.len(), 2, "two rows");
490 }
491}