1use rudb_common::{Error, LogicalType, Result, Value};
36
37use crate::string::StringView;
38use crate::validity::Validity;
39use crate::vector::{Data, NOWHERE, Vector, copy_of, empty_data_for, layout_of};
40
41#[derive(Debug)]
46pub struct Assembly {
47 ty: LogicalType,
48 rows: usize,
49 data: Data,
51 at: Vec<usize>,
53 live: Vec<bool>,
55 values: Option<Vec<Value>>,
63}
64
65impl Assembly {
66 pub fn new(ty: LogicalType, rows: usize) -> Result<Self> {
72 let nested =
73 matches!(ty, LogicalType::List(_) | LogicalType::Struct(_) | LogicalType::Map(_, _));
74 let values = if nested { Some(vec![Value::Null; rows]) } else { None };
75 let data = if nested { Data::Empty } else { empty_data_for(&ty)? };
76 Ok(Self { ty, rows, data, at: vec![NOWHERE; rows], live: vec![false; rows], values })
77 }
78
79 #[must_use]
81 pub fn rows(&self) -> usize {
82 self.rows
83 }
84
85 pub fn place(&mut self, positions: &[u32], piece: &Vector) -> Result<()> {
98 if positions.len() != piece.len() {
99 return Err(Error::internal(format!(
100 "a piece of {} rows placed at {} positions",
101 piece.len(),
102 positions.len()
103 )));
104 }
105 for &row in positions {
106 if row as usize >= self.rows {
107 return Err(Error::internal(format!(
108 "row {row} placed in an assembly of {} rows",
109 self.rows
110 )));
111 }
112 }
113 if let Some(values) = &mut self.values {
114 for (slot, &row) in positions.iter().enumerate() {
118 values[row as usize] = piece.value_at(slot);
119 }
120 return Ok(());
121 }
122 let flat = piece.flatten()?;
127 let Some(from) = flat.data() else {
128 return Err(Error::internal("a flattened vector with no run of data in it"));
129 };
130 let start = self.data.len();
131 let appended = extend(&mut self.data, from)?;
132 for (slot, &row) in positions.iter().enumerate() {
133 let row = row as usize;
134 if slot < appended {
137 self.at[row] = start + slot;
138 self.live[row] = !piece.is_null_at(slot);
139 } else {
140 self.at[row] = NOWHERE;
141 self.live[row] = false;
142 }
143 }
144 Ok(())
145 }
146
147 pub fn finish(self) -> Result<Vector> {
153 if let Some(values) = self.values {
154 return Vector::from_values(self.ty, &values);
155 }
156 if matches!(self.data, Data::Empty) {
159 return Ok(Vector::constant(self.ty, Value::Null, self.rows));
160 }
161 let gathered = copy_of(&self.data, &self.at);
162 Ok(Vector::flat(self.ty, gathered)?.with_validity(Validity::from_run(&self.live)))
163 }
164}
165
166fn extend(into: &mut Data, from: &Data) -> Result<usize> {
172 macro_rules! extended {
173 ($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
174 match (&mut *into, from) {
175 (_, Data::Empty) => Ok(0),
178 $((Data::$variant(out), Data::$variant(values)) => {
179 out.extend_from_slice(values.as_slice());
180 Ok(values.len())
181 })+
182 (Data::Varlen(out), Data::Varlen(values)) => {
186 out.reserve_views(values.len());
187 out.reserve_bytes(
188 values
189 .views()
190 .iter()
191 .filter(|view| !view.is_inline())
192 .map(StringView::len)
193 .sum(),
194 );
195 for index in 0..values.len() {
196 out.push_from(values, index);
197 }
198 Ok(values.len())
199 }
200 (out, from) => Err(Error::internal(format!(
201 "a run of {:?} values cannot be laid after a run of {:?} ones",
202 layout_of(from),
203 layout_of(out)
204 ))),
205 }
206 };
207 }
208 crate::for_each_layout!(fixed, extended)
209}
210
211#[cfg(test)]
219mod tests {
220 use super::*;
221 use crate::Chunk;
222
223 fn values(vector: &Vector) -> Vec<Value> {
225 (0..vector.len()).map(|row| vector.value_at(row)).collect()
226 }
227
228 fn scattered(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
233 let mut answers = vec![Value::Null; rows];
234 for (positions, piece) in pieces {
235 for (slot, &row) in positions.iter().enumerate() {
236 answers[row as usize] = piece.value_at(slot);
237 }
238 }
239 Vector::from_values(ty.clone(), &answers).expect("the reference builds")
240 }
241
242 fn agrees(ty: &LogicalType, rows: usize, pieces: &[(Vec<u32>, Vector)]) -> Vector {
244 let mut assembly = Assembly::new(ty.clone(), rows).expect("an assembly of this type");
245 for (positions, piece) in pieces {
246 assembly.place(positions, piece).expect("the piece is placed");
247 }
248 let built = assembly.finish().expect("the assembly finishes");
249 assert_eq!(built.len(), rows, "an assembly of {rows} rows");
250 assert_eq!(values(&built), values(&scattered(ty, rows, pieces)), "against the slow way");
251 built
252 }
253
254 #[test]
255 fn two_pieces_interleave_back_into_the_order_the_rows_came_in() {
256 let evens = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(0), Value::BigInt(2)])
257 .expect("a vector");
258 let odds = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(3)])
259 .expect("a vector");
260 let built = agrees(&LogicalType::BigInt, 4, &[(vec![0, 2], evens), (vec![1, 3], odds)]);
261 assert_eq!(
262 values(&built),
263 vec![Value::BigInt(0), Value::BigInt(1), Value::BigInt(2), Value::BigInt(3)]
264 );
265 }
266
267 #[test]
268 fn a_row_no_piece_claims_is_null() {
269 let piece =
272 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(7)]).expect("a vector");
273 let built = agrees(&LogicalType::BigInt, 3, &[(vec![1], piece)]);
274 assert_eq!(values(&built), vec![Value::Null, Value::BigInt(7), Value::Null]);
275 }
276
277 #[test]
278 fn no_pieces_at_all_is_a_column_of_nulls_of_the_right_length() {
279 let built = agrees(&LogicalType::Integer, 5, &[]);
280 assert!(built.is_null_at(4), "every row of it is null");
281 }
282
283 #[test]
284 fn a_null_inside_a_piece_stays_null_where_the_piece_put_it() {
285 let piece = Vector::from_values(
288 LogicalType::BigInt,
289 &[Value::BigInt(1), Value::Null, Value::BigInt(3)],
290 )
291 .expect("a vector");
292 let built = agrees(&LogicalType::BigInt, 3, &[(vec![2, 0, 1], piece)]);
293 assert!(built.is_null_at(0), "the null landed where the piece put it");
294 assert_eq!(built.value_at(2), Value::BigInt(1));
295 }
296
297 #[test]
298 fn strings_are_assembled_without_going_through_a_value_each() {
299 let left = Vector::from_values(
300 LogicalType::Varchar,
301 &[Value::Varchar("a short one".into()), Value::Varchar("another".into())],
302 )
303 .expect("a vector");
304 let right = Vector::from_values(
305 LogicalType::Varchar,
306 &[Value::Varchar("a string that is far too long to live inline in a view".into())],
307 )
308 .expect("a vector");
309 let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 2], left), (vec![1], right)]);
310 assert_eq!(built.value_at(0), Value::Varchar("a short one".into()));
311 assert_eq!(
312 built.value_at(1),
313 Value::Varchar("a string that is far too long to live inline in a view".into())
314 );
315 assert_eq!(built.value_at(2), Value::Varchar("another".into()));
316 }
317
318 #[test]
319 fn a_constant_piece_is_written_out_rather_than_read_a_row_at_a_time() {
320 let arm = Vector::from_values(LogicalType::Varchar, &[Value::Varchar("kept".into())])
323 .expect("a vector");
324 let otherwise = Vector::constant(LogicalType::Varchar, Value::Varchar("".into()), 3);
325 let built = agrees(&LogicalType::Varchar, 4, &[(vec![2], arm), (vec![0, 1, 3], otherwise)]);
326 assert_eq!(built.value_at(0), Value::Varchar("".into()));
327 assert_eq!(built.value_at(2), Value::Varchar("kept".into()));
328 }
329
330 #[test]
331 fn a_dictionary_piece_is_walked_to_its_values() {
332 let dictionary = Vector::from_values(
335 LogicalType::Varchar,
336 &[Value::Varchar("one".into()), Value::Varchar("two".into())],
337 )
338 .expect("a dictionary");
339 let piece = Vector::dictionary(vec![1, 0, 1], dictionary).expect("a dictionary vector");
340 let built = agrees(&LogicalType::Varchar, 3, &[(vec![0, 1, 2], piece)]);
341 assert_eq!(
342 values(&built),
343 vec![
344 Value::Varchar("two".into()),
345 Value::Varchar("one".into()),
346 Value::Varchar("two".into())
347 ]
348 );
349 }
350
351 #[test]
352 fn a_piece_placed_at_the_wrong_number_of_positions_is_an_error() {
353 let piece =
354 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
355 let mut assembly = Assembly::new(LogicalType::BigInt, 4).expect("an assembly");
356 assert!(assembly.place(&[0, 1], &piece).is_err(), "two positions for one row");
357 }
358
359 #[test]
360 fn a_position_past_the_end_is_an_error_rather_than_a_lost_row() {
361 let piece =
362 Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1)]).expect("a vector");
363 let mut assembly = Assembly::new(LogicalType::BigInt, 2).expect("an assembly");
364 assert!(assembly.place(&[9], &piece).is_err(), "a row past the end of the assembly");
365 }
366
367 #[test]
368 fn a_piece_of_the_wrong_layout_is_an_error_rather_than_a_wrong_answer() {
369 let piece =
372 Vector::from_values(LogicalType::Varchar, &[Value::Varchar("x".into())]).expect("text");
373 let mut assembly = Assembly::new(LogicalType::BigInt, 1).expect("an assembly");
374 assert!(assembly.place(&[0], &piece).is_err(), "text laid after integers");
375 }
376
377 #[test]
378 fn every_layout_assembles_the_way_it_scatters() {
379 let cases: Vec<(LogicalType, Vec<Value>)> = vec![
382 (LogicalType::Boolean, vec![Value::Boolean(true), Value::Boolean(false)]),
383 (LogicalType::TinyInt, vec![Value::TinyInt(1), Value::TinyInt(-2)]),
384 (LogicalType::SmallInt, vec![Value::SmallInt(3), Value::SmallInt(-4)]),
385 (LogicalType::Integer, vec![Value::Integer(5), Value::Integer(-6)]),
386 (LogicalType::BigInt, vec![Value::BigInt(7), Value::BigInt(-8)]),
387 (LogicalType::HugeInt, vec![Value::HugeInt(9), Value::HugeInt(-10)]),
388 (LogicalType::UTinyInt, vec![Value::UTinyInt(11), Value::UTinyInt(12)]),
389 (LogicalType::USmallInt, vec![Value::USmallInt(13), Value::USmallInt(14)]),
390 (LogicalType::UInteger, vec![Value::UInteger(15), Value::UInteger(16)]),
391 (LogicalType::UBigInt, vec![Value::UBigInt(17), Value::UBigInt(18)]),
392 (LogicalType::Float, vec![Value::Float(1.5), Value::Float(-2.5)]),
393 (LogicalType::Double, vec![Value::Double(3.5), Value::Double(-4.5)]),
394 (
395 LogicalType::Varchar,
396 vec![Value::Varchar("first".into()), Value::Varchar("second".into())],
397 ),
398 (LogicalType::Date, vec![Value::Date(19), Value::Date(20)]),
399 ];
400 for (ty, pair) in cases {
401 let left = Vector::from_values(ty.clone(), &pair[..1]).expect("a vector");
402 let right = Vector::from_values(ty.clone(), &pair[1..]).expect("a vector");
403 let built = agrees(&ty, 2, &[(vec![1], left), (vec![0], right)]);
404 assert_eq!(built.value_at(0), pair[1], "{ty:?} at row 0");
405 assert_eq!(built.value_at(1), pair[0], "{ty:?} at row 1");
406 }
407 }
408
409 #[test]
410 fn an_assembly_is_a_chunk_column_like_any_other() {
411 let piece = Vector::from_values(LogicalType::BigInt, &[Value::BigInt(1), Value::BigInt(2)])
414 .expect("a vector");
415 let built = agrees(&LogicalType::BigInt, 2, &[(vec![1, 0], piece)]);
416 let chunk = Chunk::new(vec![built]).expect("a chunk of one column");
417 assert_eq!(chunk.len(), 2, "two rows");
418 }
419}