1use std::fmt;
16use std::fmt::Display;
17use std::hash::BuildHasher;
18use std::sync::Arc;
19
20use bytes::Bytes;
21use either::Either;
22use itertools::Itertools;
23use rand::rngs::SmallRng;
24use rand::{Rng, SeedableRng};
25use risingwave_common_estimate_size::EstimateSize;
26use risingwave_pb::data::PbDataChunk;
27
28use super::{Array, ArrayImpl, ArrayRef, ArrayResult, StructArray};
29use crate::array::ArrayBuilderImpl;
30use crate::array::data_chunk_iter::RowRef;
31use crate::bitmap::{Bitmap, BitmapBuilder};
32use crate::field_generator::{FieldGeneratorImpl, VarcharProperty};
33use crate::hash::HashCode;
34use crate::row::Row;
35use crate::types::{DataType, DatumRef, MapType, StructType, ToOwnedDatum, ToText};
36use crate::util::chunk_coalesce::DataChunkBuilder;
37use crate::util::hash_util::finalize_hashers;
38use crate::util::iter_util::ZipEqFast;
39use crate::util::value_encoding::{
40 ValueRowSerializer, estimate_serialize_datum_size, serialize_datum_into,
41 try_get_exact_serialize_datum_size,
42};
43
44#[derive(Clone, PartialEq)]
64#[must_use]
65pub struct DataChunk {
66 columns: Arc<[ArrayRef]>,
67 visibility: Bitmap,
68}
69
70impl DataChunk {
71 pub(crate) const PRETTY_TABLE_PRESET: &'static str = "||--+-++| ++++++";
72
73 pub fn new(columns: Vec<ArrayRef>, visibility: impl Into<Bitmap>) -> Self {
77 let visibility = visibility.into();
78 let capacity = visibility.len();
79 for column in &columns {
80 assert_eq!(capacity, column.len());
81 }
82
83 DataChunk {
84 columns: columns.into(),
85 visibility,
86 }
87 }
88
89 pub fn new_dummy(cardinality: usize) -> Self {
91 DataChunk {
92 columns: Arc::new([]),
93 visibility: Bitmap::ones(cardinality),
94 }
95 }
96
97 pub fn from_rows(rows: &[impl Row], data_types: &[DataType]) -> Self {
104 let mut builder = DataChunkBuilder::new(data_types.to_vec(), rows.len() + 1);
109
110 for row in rows {
111 let none = builder.append_one_row(row);
112 debug_assert!(none.is_none());
113 }
114
115 builder.consume_all().expect("chunk should not be empty")
116 }
117
118 pub fn next_visible_row_idx(&self, row_idx: usize) -> Option<usize> {
120 self.visibility.next_set_bit(row_idx)
121 }
122
123 pub fn into_parts(self) -> (Vec<ArrayRef>, Bitmap) {
124 (self.columns.to_vec(), self.visibility)
125 }
126
127 pub fn into_parts_v2(self) -> (Arc<[ArrayRef]>, Bitmap) {
128 (self.columns, self.visibility)
129 }
130
131 pub fn from_parts(columns: Arc<[ArrayRef]>, visibilities: Bitmap) -> Self {
132 Self {
133 columns,
134 visibility: visibilities,
135 }
136 }
137
138 pub fn dimension(&self) -> usize {
139 self.columns.len()
140 }
141
142 pub fn cardinality(&self) -> usize {
145 self.visibility.count_ones()
146 }
147
148 pub fn has_visible_rows(&self) -> bool {
150 self.visibility.any()
151 }
152
153 pub fn rate_limit_permits(&self) -> u64 {
155 self.cardinality() as _
156 }
157
158 pub fn capacity(&self) -> usize {
161 self.visibility.len()
162 }
163
164 pub fn selectivity(&self) -> f64 {
165 if self.visibility.is_empty() {
166 0.0
167 } else if self.visibility.all() {
168 1.0
169 } else {
170 self.visibility.count_ones() as f64 / self.visibility.len() as f64
171 }
172 }
173
174 pub fn with_visibility(&self, visibility: impl Into<Bitmap>) -> Self {
175 DataChunk {
176 columns: self.columns.clone(),
177 visibility: visibility.into(),
178 }
179 }
180
181 pub fn visibility(&self) -> &Bitmap {
182 &self.visibility
183 }
184
185 pub fn set_visibility(&mut self, visibility: Bitmap) {
186 assert_eq!(visibility.len(), self.capacity());
187 self.visibility = visibility;
188 }
189
190 pub fn is_vis_compacted(&self) -> bool {
193 self.visibility.all()
194 }
195
196 pub fn column_at(&self, idx: usize) -> &ArrayRef {
197 &self.columns[idx]
198 }
199
200 pub fn columns(&self) -> &[ArrayRef] {
201 &self.columns
202 }
203
204 pub fn data_types(&self) -> Vec<DataType> {
206 self.columns.iter().map(|col| col.data_type()).collect()
207 }
208
209 pub fn split_column_at(&self, idx: usize) -> (Self, Self) {
215 let (left, right) = self.columns.split_at(idx);
216 let left = DataChunk::new(left.to_vec(), self.visibility.clone());
217 let right = DataChunk::new(right.to_vec(), self.visibility.clone());
218 (left, right)
219 }
220
221 pub fn to_protobuf(&self) -> PbDataChunk {
222 assert!(self.visibility.all(), "must be compacted before transfer");
223 let mut proto = PbDataChunk {
224 cardinality: self.cardinality() as u32,
225 columns: Default::default(),
226 };
227 let column_ref = &mut proto.columns;
228 for array in &*self.columns {
229 column_ref.push(array.to_protobuf());
230 }
231 proto
232 }
233
234 pub fn compact_vis(self) -> Self {
247 if self.visibility.all() {
248 return self;
249 }
250 let cardinality = self.visibility.count_ones();
251 let columns = self
252 .columns
253 .iter()
254 .map(|col| {
255 let array = col;
256 array.compact_vis(&self.visibility, cardinality).into()
257 })
258 .collect::<Vec<_>>();
259 Self::new(columns, Bitmap::ones(cardinality))
260 }
261
262 pub fn expand_vis(self, vis: Bitmap) -> Self {
264 let mut uncompact_builders: Vec<_> = self
265 .columns
266 .iter()
267 .map(|c| c.create_builder(vis.len()))
268 .collect();
269 let mut last_u = None;
270
271 for (idx, u) in vis.iter_ones().enumerate() {
272 let zeros = if let Some(last_u) = last_u {
274 u - last_u - 1
275 } else {
276 u
277 };
278 for _ in 0..zeros {
279 uncompact_builders
280 .iter_mut()
281 .for_each(|builder| builder.append_null());
282 }
283 uncompact_builders
284 .iter_mut()
285 .zip_eq_fast(self.columns.iter())
286 .for_each(|(builder, c)| builder.append(c.datum_at(idx)));
287 last_u = Some(u);
288 }
289 let zeros = if let Some(last_u) = last_u {
290 vis.len() - last_u - 1
291 } else {
292 vis.len()
293 };
294 for _ in 0..zeros {
295 uncompact_builders
296 .iter_mut()
297 .for_each(|builder| builder.append_null());
298 }
299 let array: Vec<_> = uncompact_builders
300 .into_iter()
301 .map(|builder| Arc::new(builder.finish()))
302 .collect();
303
304 Self::new(array, vis)
305 }
306
307 pub fn from_protobuf(proto: &PbDataChunk) -> ArrayResult<Self> {
308 let mut columns = vec![];
309 for any_col in proto.get_columns() {
310 let cardinality = proto.get_cardinality() as usize;
311 columns.push(ArrayImpl::from_protobuf(any_col, cardinality)?.into());
312 }
313
314 let chunk = DataChunk::new(columns, proto.cardinality as usize);
315 Ok(chunk)
316 }
317
318 pub fn rechunk(chunks: &[DataChunk], each_size_limit: usize) -> ArrayResult<Vec<DataChunk>> {
322 let Some(data_types) = chunks.first().map(|c| c.data_types()) else {
323 return Ok(Vec::new());
324 };
325
326 let mut builder = DataChunkBuilder::new(data_types, each_size_limit);
327 let mut outputs = Vec::new();
328
329 for chunk in chunks {
330 for output in builder.append_chunk(chunk.clone()) {
331 outputs.push(output);
332 }
333 }
334 if let Some(output) = builder.consume_all() {
335 outputs.push(output);
336 }
337
338 Ok(outputs)
339 }
340
341 pub fn get_hash_values<H: BuildHasher>(
344 &self,
345 column_idxes: &[usize],
346 hasher_builder: H,
347 ) -> Vec<HashCode<H>> {
348 let len = self.capacity();
349 let mut states = Vec::with_capacity(len);
350 states.resize_with(len, || hasher_builder.build_hasher());
351 for column_idx in column_idxes {
353 let array = self.column_at(*column_idx);
354 array.hash_vec(&mut states[..], self.visibility());
355 }
356 finalize_hashers(&states[..])
357 .into_iter()
358 .map(|hash_code| hash_code.into())
359 .collect_vec()
360 }
361
362 pub fn row_at(&self, pos: usize) -> (RowRef<'_>, bool) {
368 let row = self.row_at_unchecked_vis(pos);
369 let vis = self.visibility.is_set(pos);
370 (row, vis)
371 }
372
373 pub fn row_at_unchecked_vis(&self, pos: usize) -> RowRef<'_> {
378 RowRef::new(self, pos)
379 }
380
381 pub fn to_pretty(&self) -> impl Display + use<> {
383 use comfy_table::Table;
384
385 if self.cardinality() == 0 {
386 return Either::Left("(empty)");
387 }
388
389 let mut table = Table::new();
390 table.load_preset(Self::PRETTY_TABLE_PRESET);
391
392 for row in self.rows() {
393 let cells: Vec<_> = row
394 .iter()
395 .map(|v| {
396 match v {
397 None => "".to_owned(), Some(scalar) => scalar.to_text(),
399 }
400 })
401 .collect();
402 table.add_row(cells);
403 }
404
405 Either::Right(table)
406 }
407
408 pub fn keep_columns(&self, column_indices: &[usize]) -> Self {
418 let capacity: usize = self.capacity();
419 let columns = (self.columns.iter().enumerate())
420 .map(|(i, column)| {
421 if column_indices.contains(&i) {
422 column.clone()
423 } else {
424 let mut builder = column.create_builder(capacity);
425 builder.append_n(capacity, None as DatumRef<'_>);
426 builder.finish().into()
427 }
428 })
429 .collect();
430 DataChunk {
431 columns,
432 visibility: self.visibility.clone(),
433 }
434 }
435
436 pub fn project(&self, indices: &[usize]) -> Self {
442 Self {
443 columns: indices.iter().map(|i| self.columns[*i].clone()).collect(),
444 visibility: self.visibility.clone(),
445 }
446 }
447
448 pub fn project_with_vis(&self, indices: &[usize], visibility: Bitmap) -> Self {
450 assert_eq!(visibility.len(), self.capacity());
451 Self {
452 columns: indices.iter().map(|i| self.columns[*i].clone()).collect(),
453 visibility,
454 }
455 }
456
457 pub fn reorder_rows(&self, indexes: &[usize]) -> Self {
459 let mut array_builders: Vec<ArrayBuilderImpl> = self
460 .columns
461 .iter()
462 .map(|col| col.create_builder(indexes.len()))
463 .collect();
464 for &i in indexes {
465 for (builder, col) in array_builders.iter_mut().zip_eq_fast(self.columns.iter()) {
466 builder.append(col.value_at(i));
467 }
468 }
469 let columns = array_builders
470 .into_iter()
471 .map(|builder| builder.finish().into())
472 .collect();
473 DataChunk::new(columns, indexes.len())
474 }
475
476 fn partition_sizes(&self) -> (usize, Vec<&ArrayRef>) {
485 let mut col_variable: Vec<&ArrayRef> = vec![];
486 let mut row_len_fixed: usize = 0;
487 for c in &*self.columns {
488 if let Some(field_len) = try_get_exact_serialize_datum_size(c) {
489 row_len_fixed += field_len;
490 } else {
491 col_variable.push(c);
492 }
493 }
494 (row_len_fixed, col_variable)
495 }
496
497 unsafe fn compute_size_of_variable_cols_in_row(
498 variable_cols: &[&ArrayRef],
499 row_idx: usize,
500 ) -> usize {
501 unsafe {
502 variable_cols
503 .iter()
504 .map(|col| estimate_serialize_datum_size(col.value_at_unchecked(row_idx)))
505 .sum::<usize>()
506 }
507 }
508
509 unsafe fn init_buffer(
510 row_len_fixed: usize,
511 variable_cols: &[&ArrayRef],
512 row_idx: usize,
513 ) -> Vec<u8> {
514 unsafe {
515 Vec::with_capacity(
516 row_len_fixed + Self::compute_size_of_variable_cols_in_row(variable_cols, row_idx),
517 )
518 }
519 }
520
521 pub fn serialize(&self) -> Vec<Bytes> {
528 let buffers = if !self.visibility.all() {
529 let rows_num = self.visibility.len();
530 let mut buffers: Vec<Vec<u8>> = vec![];
531 let (row_len_fixed, col_variable) = self.partition_sizes();
532
533 for i in 0..rows_num {
535 unsafe {
537 if self.visibility.is_set_unchecked(i) {
538 buffers.push(Self::init_buffer(row_len_fixed, &col_variable, i));
539 } else {
540 buffers.push(vec![]);
541 }
542 }
543 }
544
545 for c in &*self.columns {
547 assert_eq!(c.len(), rows_num);
548 for (i, buffer) in buffers.iter_mut().enumerate() {
549 unsafe {
551 if self.visibility.is_set_unchecked(i) {
552 serialize_datum_into(c.value_at_unchecked(i), buffer);
553 }
554 }
555 }
556 }
557 buffers
558 } else {
559 let mut buffers: Vec<Vec<u8>> = vec![];
560 let (row_len_fixed, col_variable) = self.partition_sizes();
561 for i in 0..self.visibility.len() {
562 unsafe {
563 buffers.push(Self::init_buffer(row_len_fixed, &col_variable, i));
564 }
565 }
566 for c in &*self.columns {
567 assert_eq!(c.len(), self.visibility.len());
568 for (i, buffer) in buffers.iter_mut().enumerate() {
569 unsafe {
571 serialize_datum_into(c.value_at_unchecked(i), buffer);
572 }
573 }
574 }
575 buffers
576 };
577
578 buffers.into_iter().map(|item| item.into()).collect_vec()
579 }
580
581 pub fn serialize_with(&self, serializer: &impl ValueRowSerializer) -> Vec<Bytes> {
586 let mut results = Vec::with_capacity(self.capacity());
587 for row in self.rows_with_holes() {
588 results.push(if let Some(row) = row {
589 serializer.serialize(row).into()
590 } else {
591 Bytes::new()
592 });
593 }
594 results
595 }
596
597 pub fn estimate_value_encoding_size(&self, column_indices: &[usize]) -> usize {
600 if self.capacity() == 0 {
601 0
602 } else {
603 column_indices
604 .iter()
605 .map(|idx| {
606 let datum = self.column_at(*idx).datum_at(0);
607 estimate_serialize_datum_size(datum)
608 })
609 .sum()
610 }
611 }
612}
613
614impl fmt::Debug for DataChunk {
615 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616 write!(
617 f,
618 "DataChunk {{ cardinality = {}, capacity = {}, data = \n{} }}",
619 self.cardinality(),
620 self.capacity(),
621 self.to_pretty()
622 )
623 }
624}
625
626impl<'a> From<&'a StructArray> for DataChunk {
627 fn from(array: &'a StructArray) -> Self {
628 Self {
629 columns: array.fields().cloned().collect(),
630 visibility: Bitmap::ones(array.len()),
631 }
632 }
633}
634
635impl EstimateSize for DataChunk {
636 fn estimated_heap_size(&self) -> usize {
637 self.columns
638 .iter()
639 .map(|a| a.estimated_heap_size())
640 .sum::<usize>()
641 + self.visibility.estimated_heap_size()
642 }
643}
644
645pub trait DataChunkTestExt {
647 const SEED: u64 = 0xFF67FEABBAEF76FF;
649
650 fn from_pretty(s: &str) -> Self;
682
683 fn with_invisible_holes(self) -> Self
685 where
686 Self: Sized;
687
688 fn assert_valid(&self);
690
691 fn gen_data_chunk(
693 chunk_offset: usize,
694 chunk_size: usize,
695 data_types: &[DataType],
696 string_properties: &VarcharProperty,
697 visibility_ratio: f64,
698 ) -> Self;
699
700 fn gen_data_chunks(
702 num_of_chunks: usize,
703 chunk_size: usize,
704 data_types: &[DataType],
705 string_properties: &VarcharProperty,
706 visibility_ratio: f64,
707 ) -> Vec<Self>
708 where
709 Self: Sized;
710}
711
712impl DataChunkTestExt for DataChunk {
713 fn from_pretty(s: &str) -> Self {
714 use crate::types::ScalarImpl;
715 fn parse_type(s: &str) -> DataType {
716 if let Some(s) = s.strip_suffix("[]") {
717 return DataType::list(parse_type(s));
718 }
719
720 if let Some(inner) = s.strip_prefix("map<").and_then(|s| s.strip_suffix('>')) {
723 let mut parts = inner.split(',');
724 let key_type = parts.next().expect("Key type expected");
725 let value_type = parts.next().expect("Value type expected");
726 return DataType::Map(MapType::from_kv(
727 parse_type(key_type),
728 parse_type(value_type),
729 ));
730 }
731
732 match s {
733 "B" => DataType::Boolean,
734 "I" => DataType::Int64,
735 "i" => DataType::Int32,
736 "F" => DataType::Float64,
737 "f" => DataType::Float32,
738 "TS" => DataType::Timestamp,
739 "TZ" => DataType::Timestamptz,
740 "T" => DataType::Varchar,
741 "SRL" => DataType::Serial,
742 "D" => DataType::Date,
743 array if array.starts_with('<') && array.ends_with('>') => DataType::Struct(
744 StructType::unnamed(array[1..array.len() - 1].split(',').map(parse_type)),
745 ),
746 _ => todo!("unsupported type: {s:?}"),
747 }
748 }
749
750 let mut lines = s.split('\n').filter(|l| !l.trim().is_empty());
751 let header = lines.next().unwrap().trim();
753 let datatypes = header
754 .split_ascii_whitespace()
755 .take_while(|c| *c != "//")
756 .map(parse_type)
757 .collect::<Vec<_>>();
758 let mut array_builders = datatypes
759 .iter()
760 .map(|ty| ty.create_array_builder(1))
761 .collect::<Vec<_>>();
762 let mut visibility = vec![];
763 for line in lines {
764 let mut token = line.trim().split_ascii_whitespace();
765 #[expect(clippy::disallowed_methods)]
767 for ((builder, ty), val_str) in
768 array_builders.iter_mut().zip(&datatypes).zip(&mut token)
769 {
770 let datum = match val_str {
771 "." => None,
772 "(empty)" => Some("".into()),
773 _ => Some(ScalarImpl::from_text_for_test(val_str, ty).unwrap()),
775 };
776 builder.append(datum);
777 }
778 let visible = match token.next() {
779 None | Some("//") => true,
780 Some("D") => false,
781 Some(t) => panic!("invalid token: {t:?}"),
782 };
783 visibility.push(visible);
784 }
785 let columns = array_builders
786 .into_iter()
787 .map(|builder| builder.finish().into())
788 .collect();
789 let vis = Bitmap::from_iter(visibility);
790 let chunk = DataChunk::new(columns, vis);
791 chunk.assert_valid();
792 chunk
793 }
794
795 fn with_invisible_holes(self) -> Self
796 where
797 Self: Sized,
798 {
799 let (cols, vis) = self.into_parts();
800 let n = vis.len();
801 let mut new_vis = BitmapBuilder::with_capacity(n * 2);
802 for b in vis.iter() {
803 new_vis.append(b);
804 new_vis.append(false);
805 }
806 let new_cols = cols
807 .into_iter()
808 .map(|col| {
809 let arr = col;
810 let mut builder = arr.create_builder(n * 2);
811 for v in arr.iter() {
812 builder.append(v.to_owned_datum());
813 builder.append_null();
814 }
815
816 builder.finish().into()
817 })
818 .collect();
819 let chunk = DataChunk::new(new_cols, new_vis.finish());
820 chunk.assert_valid();
821 chunk
822 }
823
824 fn assert_valid(&self) {
825 let cols = self.columns();
826 let vis = &self.visibility;
827 let n = vis.len();
828 for col in cols {
829 assert_eq!(col.len(), n);
830 }
831 }
832
833 fn gen_data_chunk(
834 chunk_offset: usize,
835 chunk_size: usize,
836 data_types: &[DataType],
837 varchar_properties: &VarcharProperty,
838 visibility_percent: f64,
839 ) -> Self {
840 let vis = if visibility_percent == 0.0 {
841 Bitmap::zeros(chunk_size)
842 } else if visibility_percent == 1.0 {
843 Bitmap::ones(chunk_size)
844 } else {
845 let mut rng = SmallRng::from_seed([0; 32]);
846 let mut vis_builder = BitmapBuilder::with_capacity(chunk_size);
847 for _i in 0..chunk_size {
848 vis_builder.append(rng.random_bool(visibility_percent));
849 }
850 vis_builder.finish()
851 };
852
853 let mut columns = Vec::new();
854 for data_type in data_types {
856 let mut array_builder = data_type.create_array_builder(chunk_size);
857 for j in 0..chunk_size {
858 let offset = ((chunk_offset + 1) * (j + 1)) as u64;
859 match data_type {
860 DataType::Varchar => {
861 let datum =
862 FieldGeneratorImpl::with_varchar(varchar_properties, Self::SEED)
863 .generate_datum(offset);
864 array_builder.append(&datum);
865 }
866 DataType::Timestamp => {
867 let datum =
868 FieldGeneratorImpl::with_timestamp(None, None, None, Self::SEED)
869 .expect("create timestamp generator should succeed")
870 .generate_datum(offset);
871 array_builder.append(datum);
872 }
873 DataType::Timestamptz => {
874 let datum =
875 FieldGeneratorImpl::with_timestamptz(None, None, None, Self::SEED)
876 .expect("create timestamptz generator should succeed")
877 .generate_datum(offset);
878 array_builder.append(datum);
879 }
880 _ if data_type.is_numeric() => {
881 let mut data_gen = FieldGeneratorImpl::with_number_random(
882 data_type.clone(),
883 None,
884 None,
885 Self::SEED,
886 )
887 .unwrap();
888 let datum = data_gen.generate_datum(offset);
889 array_builder.append(datum);
890 }
891 _ => todo!("unsupported type: {data_type:?}"),
892 }
893 }
894 columns.push(array_builder.finish().into());
895 }
896 DataChunk::new(columns, vis)
897 }
898
899 fn gen_data_chunks(
900 num_of_chunks: usize,
901 chunk_size: usize,
902 data_types: &[DataType],
903 varchar_properties: &VarcharProperty,
904 visibility_percent: f64,
905 ) -> Vec<Self> {
906 (0..num_of_chunks)
907 .map(|i| {
908 Self::gen_data_chunk(
909 i,
910 chunk_size,
911 data_types,
912 varchar_properties,
913 visibility_percent,
914 )
915 })
916 .collect()
917 }
918}
919
920#[cfg(test)]
921mod tests {
922 use crate::array::*;
923 use crate::row::Row;
924
925 #[test]
926 fn test_rechunk() {
927 let test_case = |num_chunks: usize, chunk_size: usize, new_chunk_size: usize| {
928 let mut chunks = vec![];
929 for chunk_idx in 0..num_chunks {
930 let mut builder = PrimitiveArrayBuilder::<i32>::new(0);
931 for i in chunk_size * chunk_idx..chunk_size * (chunk_idx + 1) {
932 builder.append(Some(i as i32));
933 }
934 let chunk = DataChunk::new(vec![Arc::new(builder.finish().into())], chunk_size);
935 chunks.push(chunk);
936 }
937
938 let total_size = num_chunks * chunk_size;
939 let num_full_new_chunk = total_size / new_chunk_size;
940 let mut chunk_sizes = vec![new_chunk_size; num_full_new_chunk];
941 let remainder = total_size % new_chunk_size;
942 if remainder != 0 {
943 chunk_sizes.push(remainder);
944 }
945
946 let new_chunks = DataChunk::rechunk(&chunks, new_chunk_size).unwrap();
947 assert_eq!(new_chunks.len(), chunk_sizes.len());
948 for (idx, chunk_size) in chunk_sizes.iter().enumerate() {
950 assert_eq!(*chunk_size, new_chunks[idx].capacity());
951 }
952
953 let mut chunk_idx = 0;
954 let mut cur_idx = 0;
955 for val in 0..total_size {
956 if cur_idx >= chunk_sizes[chunk_idx] {
957 cur_idx = 0;
958 chunk_idx += 1;
959 }
960 assert_eq!(
961 new_chunks[chunk_idx]
962 .column_at(0)
963 .as_int32()
964 .value_at(cur_idx)
965 .unwrap(),
966 val as i32
967 );
968 cur_idx += 1;
969 }
970 };
971
972 test_case(0, 0, 1);
973 test_case(0, 10, 1);
974 test_case(10, 0, 1);
975 test_case(1, 1, 6);
976 test_case(1, 10, 11);
977 test_case(2, 3, 6);
978 test_case(5, 5, 6);
979 test_case(10, 10, 7);
980 }
981
982 #[test]
983 fn test_chunk_iter() {
984 let num_of_columns: usize = 2;
985 let length = 5;
986 let mut columns = vec![];
987 for i in 0..num_of_columns {
988 let mut builder = PrimitiveArrayBuilder::<i32>::new(length);
989 for _ in 0..length {
990 builder.append(Some(i as i32));
991 }
992 let arr = builder.finish();
993 columns.push(Arc::new(arr.into()))
994 }
995 let chunk: DataChunk = DataChunk::new(columns, length);
996 for row in chunk.rows() {
997 for i in 0..num_of_columns {
998 let val = row.datum_at(i).unwrap();
999 assert_eq!(val.into_int32(), i as i32);
1000 }
1001 }
1002 }
1003
1004 #[test]
1005 fn test_to_pretty_string() {
1006 let chunk = DataChunk::new(
1007 vec![
1008 Arc::new(I64Array::from_iter([1, 2, 3, 4]).into()),
1009 Arc::new(I64Array::from_iter([Some(6), None, Some(7), None]).into()),
1010 ],
1011 4,
1012 );
1013 assert_eq!(
1014 chunk.to_pretty().to_string(),
1015 "\
1016+---+---+
1017| 1 | 6 |
1018| 2 | |
1019| 3 | 7 |
1020| 4 | |
1021+---+---+"
1022 );
1023 }
1024
1025 #[test]
1026 fn test_no_column_chunk() {
1027 let chunk = DataChunk::new_dummy(10);
1028 assert_eq!(chunk.rows().count(), 10);
1029
1030 let chunk_after_serde = DataChunk::from_protobuf(&chunk.to_protobuf()).unwrap();
1031 assert_eq!(chunk_after_serde.rows().count(), 10);
1032 assert_eq!(chunk_after_serde.cardinality(), 10);
1033 }
1034
1035 #[test]
1036 fn reorder_columns() {
1037 let chunk = DataChunk::from_pretty(
1038 "I I I
1039 2 5 1
1040 4 9 2
1041 6 9 3",
1042 );
1043 assert_eq!(
1044 chunk.project(&[2, 1, 0]),
1045 DataChunk::from_pretty(
1046 "I I I
1047 1 5 2
1048 2 9 4
1049 3 9 6",
1050 )
1051 );
1052 assert_eq!(
1053 chunk.project(&[2, 0]),
1054 DataChunk::from_pretty(
1055 "I I
1056 1 2
1057 2 4
1058 3 6",
1059 )
1060 );
1061 assert_eq!(chunk.project(&[0, 1, 2]), chunk);
1062 assert_eq!(chunk.project(&[]).cardinality(), 3);
1063 }
1064
1065 #[test]
1066 fn test_chunk_estimated_size() {
1067 assert_eq!(
1068 72,
1069 DataChunk::from_pretty(
1070 "I I I
1071 1 5 2
1072 2 9 4
1073 3 9 6",
1074 )
1075 .estimated_heap_size()
1076 );
1077 assert_eq!(
1078 48,
1079 DataChunk::from_pretty(
1080 "I I
1081 1 2
1082 2 4
1083 3 6",
1084 )
1085 .estimated_heap_size()
1086 );
1087 }
1088}