1use std::collections::HashMap;
18use std::sync::Arc;
19
20use api::v1::SemanticType;
21use datatypes::arrow::array::{
22 Array, ArrayRef, BinaryArray, BinaryBuilder, DictionaryArray, UInt32Array, new_null_array,
23};
24use datatypes::arrow::compute::{TakeOptions, take};
25use datatypes::arrow::datatypes::{FieldRef, Schema, SchemaRef};
26use datatypes::arrow::record_batch::RecordBatch;
27use datatypes::data_type::ConcreteDataType;
28use datatypes::prelude::DataType;
29use datatypes::value::Value;
30use datatypes::vectors::{Helper, VectorRef};
31use mito_codec::row_converter::{
32 CompositeValues, PrimaryKeyCodec, SortField, build_primary_key_codec,
33 build_primary_key_codec_with_fields,
34};
35use snafu::{OptionExt, ResultExt, ensure};
36use store_api::codec::PrimaryKeyEncoding;
37use store_api::metadata::{RegionMetadata, RegionMetadataRef};
38use store_api::storage::ColumnId;
39
40use crate::error::{
41 CompatReaderSnafu, ComputeArrowSnafu, CreateDefaultSnafu, DecodeSnafu, EncodeSnafu,
42 NewRecordBatchSnafu, Result, UnexpectedSnafu, UnsupportedOperationSnafu,
43};
44use crate::read::flat_projection::{FlatProjectionMapper, flat_projected_columns};
45use crate::sst::internal_fields;
46use crate::sst::parquet::flat_format::{FlatReadFormat, primary_key_column_index};
47use crate::sst::parquet::format::{INTERNAL_COLUMN_NUM, PrimaryKeyArray};
48
49pub(crate) fn has_same_columns_and_pk_encoding(
52 projection_mapper: &FlatProjectionMapper,
53 read_format: &FlatReadFormat,
54 compaction: bool,
55) -> bool {
56 let left = projection_mapper.metadata();
57 let right = read_format.metadata();
58 if left.primary_key_encoding != right.primary_key_encoding {
59 return false;
60 }
61
62 if left.column_metadatas.len() != right.column_metadatas.len() {
63 return false;
64 }
65
66 for (left_col, right_col) in left.column_metadatas.iter().zip(&right.column_metadatas) {
67 if left_col.column_id != right_col.column_id {
68 return false;
69 }
70 debug_assert_eq!(left_col.semantic_type, right_col.semantic_type);
71 }
72
73 &projection_mapper.input_arrow_schema(compaction) == read_format.arrow_schema()
74}
75
76pub(crate) struct FlatCompatBatch {
78 index_or_defaults: Vec<IndexOrDefault>,
80 arrow_schema: SchemaRef,
82 compat_pk: FlatCompatPrimaryKey,
84}
85
86impl FlatCompatBatch {
87 pub(crate) fn try_new(
93 mapper: &FlatProjectionMapper,
94 read_format: &FlatReadFormat,
95 compaction: bool,
96 ) -> Result<Option<Self>> {
97 let actual = read_format.metadata();
98 let actual_schema = flat_projected_columns(
99 actual,
100 read_format.format_projection(),
101 read_format.json_target_types(),
102 );
103
104 let expect_schema = mapper.batch_schema();
105 if expect_schema == actual_schema
106 && actual.primary_key == mapper.metadata().primary_key
107 && actual.primary_key_encoding == mapper.metadata().primary_key_encoding
108 {
109 return Ok(None);
112 }
113
114 if actual.primary_key_encoding == PrimaryKeyEncoding::Sparse && compaction {
115 return FlatCompatBatch::try_new_compact_sparse(mapper, actual);
117 }
118
119 let (index_or_defaults, fields) = Self::compute_index_and_fields(
120 &actual_schema,
121 expect_schema,
122 mapper.metadata(),
123 mapper.input_arrow_schema(compaction).fields(),
124 )?;
125
126 let compat_pk = FlatCompatPrimaryKey::new(mapper.metadata(), actual)?;
127
128 Ok(Some(Self {
129 index_or_defaults,
130 arrow_schema: Arc::new(Schema::new(fields)),
131 compat_pk,
132 }))
133 }
134
135 fn compute_index_and_fields(
136 actual_schema: &[(ColumnId, ConcreteDataType)],
137 expect_schema: &[(ColumnId, ConcreteDataType)],
138 expect_metadata: &RegionMetadata,
139 target_fields: &[FieldRef],
140 ) -> Result<(Vec<IndexOrDefault>, Vec<FieldRef>)> {
141 let actual_schema_index: HashMap<_, _> = actual_schema
143 .iter()
144 .enumerate()
145 .map(|(idx, (column_id, data_type))| (*column_id, (idx, data_type)))
146 .collect();
147
148 let mut index_or_defaults = Vec::with_capacity(expect_schema.len());
149 let mut fields = Vec::with_capacity(expect_schema.len());
150 for (field_index, (column_id, expect_data_type)) in expect_schema.iter().enumerate() {
151 let column_index = expect_metadata.column_index_by_id(*column_id).unwrap();
153 let expect_column = &expect_metadata.column_metadatas[column_index];
154 let column_field = &target_fields[field_index];
160 debug_assert_eq!(column_field.name(), &expect_column.column_schema.name);
161 fields.push(column_field.clone());
162
163 if let Some((index, actual_data_type)) = actual_schema_index.get(column_id) {
164 let mut cast_type = None;
165
166 if expect_data_type != *actual_data_type {
168 ensure!(
169 !expect_data_type.is_json2() && !actual_data_type.is_json2(),
170 CompatReaderSnafu {
171 region_id: expect_metadata.region_id,
172 reason: format!(
173 "JSON2 column '{}' must be aligned before FlatCompatBatch, actual: {}, expected: {}",
174 expect_column.column_schema.name,
175 actual_data_type,
176 expect_data_type,
177 ),
178 }
179 );
180 cast_type = Some(expect_data_type.clone());
181 }
182 index_or_defaults.push(IndexOrDefault::Index {
184 pos: *index,
185 cast_type,
186 });
187 } else {
188 let default_vector = if expect_data_type.is_json2() {
190 Helper::try_into_vector(new_null_array(column_field.data_type(), 1)).context(
193 CreateDefaultSnafu {
194 region_id: expect_metadata.region_id,
195 column: &expect_column.column_schema.name,
196 },
197 )?
198 } else {
199 expect_column
200 .column_schema
201 .create_default_vector(1)
202 .context(CreateDefaultSnafu {
203 region_id: expect_metadata.region_id,
204 column: &expect_column.column_schema.name,
205 })?
206 .with_context(|| CompatReaderSnafu {
207 region_id: expect_metadata.region_id,
208 reason: format!(
209 "column {} does not have a default value to read",
210 expect_column.column_schema.name
211 ),
212 })?
213 };
214 index_or_defaults.push(IndexOrDefault::DefaultValue {
215 default_vector,
216 semantic_type: expect_column.semantic_type,
217 });
218 };
219 }
220 fields.extend_from_slice(&internal_fields());
221
222 Ok((index_or_defaults, fields))
223 }
224
225 fn try_new_compact_sparse(
226 mapper: &FlatProjectionMapper,
227 actual: &RegionMetadataRef,
228 ) -> Result<Option<Self>> {
229 ensure!(
232 mapper.metadata().primary_key_encoding == PrimaryKeyEncoding::Sparse,
233 UnsupportedOperationSnafu {
234 err_msg: "Flat format doesn't support converting sparse encoding back to dense encoding"
235 }
236 );
237
238 let actual_schema: Vec<_> = actual
241 .field_columns()
242 .chain([actual.time_index_column()])
243 .map(|col| (col.column_id, col.column_schema.data_type.clone()))
244 .collect();
245 let expect_schema: Vec<_> = mapper
246 .metadata()
247 .field_columns()
248 .chain([mapper.metadata().time_index_column()])
249 .map(|col| (col.column_id, col.column_schema.data_type.clone()))
250 .collect();
251
252 let (index_or_defaults, fields) = Self::compute_index_and_fields(
253 &actual_schema,
254 &expect_schema,
255 mapper.metadata(),
256 mapper.input_arrow_schema(true).fields(),
257 )?;
258
259 let compat_pk = FlatCompatPrimaryKey::default();
260
261 Ok(Some(Self {
262 index_or_defaults,
263 arrow_schema: Arc::new(Schema::new(fields)),
264 compat_pk,
265 }))
266 }
267
268 pub(crate) fn compat(&self, batch: RecordBatch) -> Result<RecordBatch> {
270 let len = batch.num_rows();
271 let columns = self
272 .index_or_defaults
273 .iter()
274 .map(|index_or_default| match index_or_default {
275 IndexOrDefault::Index { pos, cast_type } => {
276 let old_column = batch.column(*pos);
277
278 if let Some(ty) = cast_type {
279 let casted =
280 datatypes::arrow::compute::cast(old_column, &ty.as_arrow_type())
281 .context(ComputeArrowSnafu)?;
282 Ok(casted)
283 } else {
284 Ok(old_column.clone())
285 }
286 }
287 IndexOrDefault::DefaultValue {
288 default_vector,
289 semantic_type,
290 } => repeat_vector(default_vector, len, *semantic_type == SemanticType::Tag),
291 })
292 .chain(
293 batch.columns()[batch.num_columns() - INTERNAL_COLUMN_NUM..]
295 .iter()
296 .map(|col| Ok(col.clone())),
297 )
298 .collect::<Result<Vec<_>>>()?;
299
300 let mut columns = columns;
301 let primary_key_index = primary_key_column_index(columns.len());
302 columns[primary_key_index] = self.compat_primary_key(&columns[primary_key_index])?;
303
304 RecordBatch::try_new(self.arrow_schema.clone(), columns).context(NewRecordBatchSnafu)
305 }
306
307 pub(crate) fn compat_primary_key(&self, primary_key: &ArrayRef) -> Result<ArrayRef> {
309 self.compat_pk.compat(primary_key)
310 }
311}
312
313fn repeat_vector(vector: &VectorRef, to_len: usize, is_tag: bool) -> Result<ArrayRef> {
315 assert_eq!(1, vector.len());
316 let data_type = vector.data_type();
317 if is_tag && data_type.is_string() {
318 let values = vector.to_arrow_array();
319 if values.is_null(0) {
320 let keys = UInt32Array::new_null(to_len);
322 Ok(Arc::new(DictionaryArray::new(keys, values.slice(0, 0))))
323 } else {
324 let keys = UInt32Array::from_value(0, to_len);
325 Ok(Arc::new(DictionaryArray::new(keys, values)))
326 }
327 } else {
328 let keys = UInt32Array::from_value(0, to_len);
329 take(
330 &vector.to_arrow_array(),
331 &keys,
332 Some(TakeOptions {
333 check_bounds: false,
334 }),
335 )
336 .context(ComputeArrowSnafu)
337 }
338}
339
340fn is_primary_key_same(expect: &RegionMetadata, actual: &RegionMetadata) -> Result<bool> {
342 ensure!(
343 actual.primary_key.len() <= expect.primary_key.len(),
344 CompatReaderSnafu {
345 region_id: expect.region_id,
346 reason: format!(
347 "primary key has more columns {} than expect {}",
348 actual.primary_key.len(),
349 expect.primary_key.len()
350 ),
351 }
352 );
353 ensure!(
354 actual.primary_key == expect.primary_key[..actual.primary_key.len()],
355 CompatReaderSnafu {
356 region_id: expect.region_id,
357 reason: format!(
358 "primary key has different prefix, expect: {:?}, actual: {:?}",
359 expect.primary_key, actual.primary_key
360 ),
361 }
362 );
363
364 Ok(actual.primary_key.len() == expect.primary_key.len())
365}
366
367#[derive(Debug)]
369enum IndexOrDefault {
370 Index {
372 pos: usize,
373 cast_type: Option<ConcreteDataType>,
374 },
375 DefaultValue {
377 default_vector: VectorRef,
379 semantic_type: SemanticType,
381 },
382}
383
384struct FlatRewritePrimaryKey {
386 codec: Arc<dyn PrimaryKeyCodec>,
388 metadata: RegionMetadataRef,
390 old_codec: Arc<dyn PrimaryKeyCodec>,
393}
394
395impl FlatRewritePrimaryKey {
396 fn new(
397 expect: &RegionMetadataRef,
398 actual: &RegionMetadataRef,
399 ) -> Option<FlatRewritePrimaryKey> {
400 if expect.primary_key_encoding == actual.primary_key_encoding {
401 return None;
402 }
403 let codec = build_primary_key_codec(expect);
404 let old_codec = build_primary_key_codec(actual);
405
406 Some(FlatRewritePrimaryKey {
407 codec,
408 metadata: expect.clone(),
409 old_codec,
410 })
411 }
412
413 fn rewrite_key(
416 &self,
417 append_values: &[(ColumnId, Value)],
418 primary_key: &ArrayRef,
419 ) -> Result<ArrayRef> {
420 if let Some(old_pk_dict_array) = primary_key.as_any().downcast_ref::<PrimaryKeyArray>() {
421 let old_pk_values_array = old_pk_dict_array
422 .values()
423 .as_any()
424 .downcast_ref::<BinaryArray>()
425 .context(UnexpectedSnafu {
426 reason: "Primary-key dictionary values are not binary",
427 })?;
428 let new_pk_values_array =
429 Arc::new(self.rewrite_values(append_values, old_pk_values_array)?);
430 return Ok(Arc::new(PrimaryKeyArray::new(
431 old_pk_dict_array.keys().clone(),
432 new_pk_values_array,
433 )));
434 }
435
436 let old_pk_values_array =
437 primary_key
438 .as_any()
439 .downcast_ref::<BinaryArray>()
440 .context(UnexpectedSnafu {
441 reason: format!(
442 "Primary-key column is neither binary nor dictionary, got {:?}",
443 primary_key.data_type()
444 ),
445 })?;
446 Ok(Arc::new(
447 self.rewrite_values(append_values, old_pk_values_array)?,
448 ))
449 }
450
451 fn rewrite_values(
452 &self,
453 append_values: &[(ColumnId, Value)],
454 old_pk_values_array: &BinaryArray,
455 ) -> Result<BinaryArray> {
456 let mut builder = BinaryBuilder::with_capacity(
457 old_pk_values_array.len(),
458 old_pk_values_array.value_data().len(),
459 );
460
461 let mut buffer = Vec::with_capacity(
463 old_pk_values_array.value_data().len() / old_pk_values_array.len().max(1),
464 );
465 let mut column_id_values = Vec::new();
466 for value in old_pk_values_array.iter() {
468 let Some(old_pk) = value else {
469 builder.append_null();
470 continue;
471 };
472 let mut pk_values = self.old_codec.decode(old_pk).context(DecodeSnafu)?;
474 pk_values.extend(append_values);
475
476 buffer.clear();
477 column_id_values.clear();
478 match pk_values {
480 CompositeValues::Dense(dense_values) => {
481 self.codec
482 .encode_values(dense_values.as_slice(), &mut buffer)
483 .context(EncodeSnafu)?;
484 }
485 CompositeValues::Sparse(sparse_values) => {
486 for id in &self.metadata.primary_key {
487 let value = sparse_values.get_or_null(*id);
488 column_id_values.push((*id, value.clone()));
489 }
490 self.codec
491 .encode_values(&column_id_values, &mut buffer)
492 .context(EncodeSnafu)?;
493 }
494 }
495 builder.append_value(&buffer);
496 }
497 Ok(builder.finish())
498 }
499}
500
501#[derive(Default)]
503struct FlatCompatPrimaryKey {
504 rewriter: Option<FlatRewritePrimaryKey>,
506 converter: Option<Arc<dyn PrimaryKeyCodec>>,
508 values: Vec<(ColumnId, Value)>,
510}
511
512impl FlatCompatPrimaryKey {
513 fn new(expect: &RegionMetadataRef, actual: &RegionMetadataRef) -> Result<Self> {
514 let rewriter = FlatRewritePrimaryKey::new(expect, actual);
515
516 if is_primary_key_same(expect, actual)? {
517 return Ok(Self {
518 rewriter,
519 converter: None,
520 values: Vec::new(),
521 });
522 }
523
524 let to_add = &expect.primary_key[actual.primary_key.len()..];
526 let mut values = Vec::with_capacity(to_add.len());
527 let mut fields = Vec::with_capacity(to_add.len());
528 for column_id in to_add {
529 let column = expect.column_by_id(*column_id).unwrap();
531 fields.push((
532 *column_id,
533 SortField::new(column.column_schema.data_type.clone()),
534 ));
535 let default_value = column
536 .column_schema
537 .create_default()
538 .context(CreateDefaultSnafu {
539 region_id: expect.region_id,
540 column: &column.column_schema.name,
541 })?
542 .with_context(|| CompatReaderSnafu {
543 region_id: expect.region_id,
544 reason: format!(
545 "key column {} does not have a default value to read",
546 column.column_schema.name
547 ),
548 })?;
549 values.push((*column_id, default_value));
550 }
551 debug_assert!(!fields.is_empty());
553
554 let converter = Some(build_primary_key_codec_with_fields(
556 expect.primary_key_encoding,
557 fields.into_iter(),
558 ));
559
560 Ok(Self {
561 rewriter,
562 converter,
563 values,
564 })
565 }
566
567 fn compat(&self, primary_key: &ArrayRef) -> Result<ArrayRef> {
569 if let Some(rewriter) = &self.rewriter {
570 return rewriter.rewrite_key(&self.values, primary_key);
572 }
573
574 self.append_key(primary_key)
575 }
576
577 fn append_key(&self, primary_key: &ArrayRef) -> Result<ArrayRef> {
579 let Some(converter) = &self.converter else {
580 return Ok(primary_key.clone());
581 };
582
583 if let Some(old_pk_dict_array) = primary_key.as_any().downcast_ref::<PrimaryKeyArray>() {
584 let old_pk_values_array = old_pk_dict_array
585 .values()
586 .as_any()
587 .downcast_ref::<BinaryArray>()
588 .context(UnexpectedSnafu {
589 reason: "Primary-key dictionary values are not binary",
590 })?;
591 let new_pk_values_array =
592 Arc::new(self.append_values(old_pk_values_array, converter.as_ref())?);
593 return Ok(Arc::new(PrimaryKeyArray::new(
594 old_pk_dict_array.keys().clone(),
595 new_pk_values_array,
596 )));
597 }
598
599 let old_pk_values_array =
600 primary_key
601 .as_any()
602 .downcast_ref::<BinaryArray>()
603 .context(UnexpectedSnafu {
604 reason: format!(
605 "Primary-key column is neither binary nor dictionary, got {:?}",
606 primary_key.data_type()
607 ),
608 })?;
609 Ok(Arc::new(
610 self.append_values(old_pk_values_array, converter.as_ref())?,
611 ))
612 }
613
614 fn append_values(
615 &self,
616 old_pk_values_array: &BinaryArray,
617 converter: &dyn PrimaryKeyCodec,
618 ) -> Result<BinaryArray> {
619 let mut builder = BinaryBuilder::with_capacity(
620 old_pk_values_array.len(),
621 old_pk_values_array.value_data().len()
622 + converter.estimated_size().unwrap_or_default() * old_pk_values_array.len(),
623 );
624
625 let mut buffer = Vec::with_capacity(
627 old_pk_values_array.value_data().len() / old_pk_values_array.len().max(1)
628 + converter.estimated_size().unwrap_or_default(),
629 );
630
631 for value in old_pk_values_array.iter() {
633 let Some(old_pk) = value else {
634 builder.append_null();
635 continue;
636 };
637
638 buffer.clear();
639 buffer.extend_from_slice(old_pk);
640 converter
641 .encode_values(&self.values, &mut buffer)
642 .context(EncodeSnafu)?;
643
644 builder.append_value(&buffer);
645 }
646
647 Ok(builder.finish())
648 }
649}
650
651#[cfg(test)]
652mod tests {
653 use std::collections::BTreeMap;
654 use std::sync::Arc;
655
656 use api::v1::{OpType, SemanticType};
657 use datatypes::arrow::array::{
658 ArrayRef, BinaryArray, BinaryDictionaryBuilder, Int64Array, StringDictionaryBuilder,
659 TimestampMicrosecondArray, TimestampMillisecondArray, UInt8Array, UInt64Array,
660 };
661 use datatypes::arrow::datatypes::UInt32Type;
662 use datatypes::arrow::record_batch::RecordBatch;
663 use datatypes::extension::json::JsonMetadata;
664 use datatypes::json::JsonSettings;
665 use datatypes::prelude::ConcreteDataType;
666 use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema};
667 use datatypes::types::json_type::JsonNativeType;
668 use datatypes::types::parse_string_to_jsonb;
669 use datatypes::value::ValueRef;
670 use datatypes::vectors::json::array::JsonArray;
671 use datatypes::vectors::json::json2_physical_data_type;
672 use mito_codec::row_converter::{
673 DensePrimaryKeyCodec, PrimaryKeyCodecExt, SparsePrimaryKeyCodec,
674 };
675 use store_api::codec::PrimaryKeyEncoding;
676 use store_api::metadata::{ColumnMetadata, RegionMetadataBuilder};
677 use store_api::storage::RegionId;
678
679 use super::*;
680 use crate::read::flat_projection::FlatProjectionMapper;
681 use crate::read::read_columns::ReadColumns;
682 use crate::sst::parquet::flat_format::FlatReadFormat;
683 use crate::sst::parquet::{Json2RewriteTargets, Json2TargetLayout};
684 use crate::sst::{FlatSchemaOptions, to_flat_sst_arrow_schema};
685 use crate::test_util;
686
687 fn new_metadata(
689 semantic_types: &[(ColumnId, SemanticType, ConcreteDataType)],
690 primary_key: &[ColumnId],
691 ) -> RegionMetadata {
692 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
693 for (id, semantic_type, data_type) in semantic_types {
694 let column_schema = match semantic_type {
695 SemanticType::Tag => {
696 ColumnSchema::new(format!("tag_{id}"), data_type.clone(), true)
697 }
698 SemanticType::Field => {
699 ColumnSchema::new(format!("field_{id}"), data_type.clone(), true)
700 }
701 SemanticType::Timestamp => ColumnSchema::new("ts", data_type.clone(), false),
702 };
703
704 builder.push_column_metadata(ColumnMetadata {
705 column_schema,
706 semantic_type: *semantic_type,
707 column_id: *id,
708 });
709 }
710 builder.primary_key(primary_key.to_vec());
711 builder.build().unwrap()
712 }
713
714 fn encode_key(keys: &[Option<&str>]) -> Vec<u8> {
716 let fields = (0..keys.len())
717 .map(|_| (0, SortField::new(ConcreteDataType::string_datatype())))
718 .collect();
719 let converter = DensePrimaryKeyCodec::with_fields(fields);
720 let row = keys.iter().map(|str_opt| match str_opt {
721 Some(v) => ValueRef::String(v),
722 None => ValueRef::Null,
723 });
724
725 converter.encode(row).unwrap()
726 }
727
728 fn encode_sparse_key(keys: &[(ColumnId, Option<&str>)]) -> Vec<u8> {
730 let fields = (0..keys.len())
731 .map(|_| (1, SortField::new(ConcreteDataType::string_datatype())))
732 .collect();
733 let converter = SparsePrimaryKeyCodec::with_fields(fields);
734 let row = keys
735 .iter()
736 .map(|(id, str_opt)| match str_opt {
737 Some(v) => (*id, ValueRef::String(v)),
738 None => (*id, ValueRef::Null),
739 })
740 .collect::<Vec<_>>();
741 let mut buffer = vec![];
742 converter.encode_value_refs(&row, &mut buffer).unwrap();
743 buffer
744 }
745
746 fn build_flat_test_pk_array(primary_keys: &[&[u8]]) -> ArrayRef {
748 let mut builder = BinaryDictionaryBuilder::<UInt32Type>::new();
749 for &pk in primary_keys {
750 builder.append(pk).unwrap();
751 }
752 Arc::new(builder.finish())
753 }
754
755 #[test]
756 fn test_flat_compat_batch_with_missing_columns() {
757 let actual_metadata = Arc::new(new_metadata(
758 &[
759 (
760 0,
761 SemanticType::Timestamp,
762 ConcreteDataType::timestamp_millisecond_datatype(),
763 ),
764 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
765 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
766 ],
767 &[1],
768 ));
769
770 let expected_metadata = Arc::new(new_metadata(
771 &[
772 (
773 0,
774 SemanticType::Timestamp,
775 ConcreteDataType::timestamp_millisecond_datatype(),
776 ),
777 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
778 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
779 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
781 ],
782 &[1],
783 ));
784
785 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
786 let read_format = FlatReadFormat::new(
787 actual_metadata.clone(),
788 ReadColumns::new([0, 1, 2, 3]),
789 None,
790 "test",
791 false,
792 )
793 .unwrap();
794
795 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
796 .unwrap()
797 .unwrap();
798
799 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
800 tag_builder.append_value("tag1");
801 tag_builder.append_value("tag1");
802 let tag_dict_array = Arc::new(tag_builder.finish());
803
804 let k1 = encode_key(&[Some("tag1")]);
805 let input_columns: Vec<ArrayRef> = vec![
806 tag_dict_array.clone(),
807 Arc::new(Int64Array::from(vec![100, 200])),
808 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
809 build_flat_test_pk_array(&[&k1, &k1]),
810 Arc::new(UInt64Array::from_iter_values([1, 2])),
811 Arc::new(UInt8Array::from_iter_values([
812 OpType::Put as u8,
813 OpType::Put as u8,
814 ])),
815 ];
816 let input_schema =
817 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
818 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
819
820 let result = compat_batch.compat(input_batch).unwrap();
821
822 let expected_schema =
823 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
824
825 let expected_columns: Vec<ArrayRef> = vec![
826 tag_dict_array.clone(),
827 Arc::new(Int64Array::from(vec![100, 200])),
828 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
829 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
830 build_flat_test_pk_array(&[&k1, &k1]),
831 Arc::new(UInt64Array::from_iter_values([1, 2])),
832 Arc::new(UInt8Array::from_iter_values([
833 OpType::Put as u8,
834 OpType::Put as u8,
835 ])),
836 ];
837 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
838
839 assert_eq!(expected_batch, result);
840 }
841
842 #[test]
843 fn test_flat_compat_batch_uses_projected_json2_type() -> Result<()> {
844 let json2 = ConcreteDataType::json2(JsonNativeType::object());
845 let actual_metadata = Arc::new(new_metadata(
846 &[
847 (
848 0,
849 SemanticType::Timestamp,
850 ConcreteDataType::timestamp_millisecond_datatype(),
851 ),
852 (1, SemanticType::Field, json2.clone()),
853 ],
854 &[],
855 ));
856 let expected_metadata = Arc::new(new_metadata(
857 &[
858 (
859 0,
860 SemanticType::Timestamp,
861 ConcreteDataType::timestamp_millisecond_datatype(),
862 ),
863 (1, SemanticType::Field, json2),
864 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
865 ],
866 &[],
867 ));
868 let read_columns = ReadColumns::new([0, 1, 2])
869 .with_json_target_types(BTreeMap::from([(1, JsonNativeType::Variant)]));
870 let mapper = FlatProjectionMapper::new_with_read_columns(
871 &expected_metadata,
872 vec![0, 1, 2],
873 read_columns.clone(),
874 )?;
875 let read_format = FlatReadFormat::new(actual_metadata, read_columns, None, "test", false)?;
876
877 let compat = FlatCompatBatch::try_new(&mapper, &read_format, false)?.unwrap();
878 let json_index = mapper
879 .batch_schema()
880 .iter()
881 .position(|(id, _)| *id == 1)
882 .unwrap();
883 assert!(matches!(
884 &compat.index_or_defaults[json_index],
885 IndexOrDefault::Index {
886 cast_type: None,
887 ..
888 }
889 ));
890 Ok(())
891 }
892
893 #[test]
894 fn test_flat_compat_batch_with_read_projection_superset() {
895 let actual_metadata = Arc::new(new_metadata(
896 &[
897 (
898 0,
899 SemanticType::Timestamp,
900 ConcreteDataType::timestamp_millisecond_datatype(),
901 ),
902 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
903 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
904 ],
905 &[1],
906 ));
907
908 let expected_metadata = Arc::new(new_metadata(
909 &[
910 (
911 0,
912 SemanticType::Timestamp,
913 ConcreteDataType::timestamp_millisecond_datatype(),
914 ),
915 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
916 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
917 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
919 ],
920 &[1],
921 ));
922
923 let mapper = FlatProjectionMapper::new_with_read_columns(
924 &expected_metadata,
925 vec![1, 2],
926 ReadColumns::new([1, 2, 3]),
927 )
928 .unwrap();
929 let read_format = FlatReadFormat::new(
930 actual_metadata.clone(),
931 ReadColumns::new([1, 2, 3]),
932 None,
933 "test",
934 false,
935 )
936 .unwrap();
937
938 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
939 .unwrap()
940 .unwrap();
941
942 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
943 tag_builder.append_value("tag1");
944 tag_builder.append_value("tag1");
945 let tag_dict_array = Arc::new(tag_builder.finish());
946
947 let k1 = encode_key(&[Some("tag1")]);
948 let input_columns: Vec<ArrayRef> = vec![
949 tag_dict_array.clone(),
950 Arc::new(Int64Array::from(vec![100, 200])),
951 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
952 build_flat_test_pk_array(&[&k1, &k1]),
953 Arc::new(UInt64Array::from_iter_values([1, 2])),
954 Arc::new(UInt8Array::from_iter_values([
955 OpType::Put as u8,
956 OpType::Put as u8,
957 ])),
958 ];
959 let input_schema =
960 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
961 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
962
963 let result = compat_batch.compat(input_batch).unwrap();
964
965 let expected_schema =
966 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
967 let expected_columns: Vec<ArrayRef> = vec![
968 tag_dict_array.clone(),
969 Arc::new(Int64Array::from(vec![100, 200])),
970 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
971 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
972 build_flat_test_pk_array(&[&k1, &k1]),
973 Arc::new(UInt64Array::from_iter_values([1, 2])),
974 Arc::new(UInt8Array::from_iter_values([
975 OpType::Put as u8,
976 OpType::Put as u8,
977 ])),
978 ];
979 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
980
981 assert_eq!(expected_batch, result);
982 }
983
984 #[test]
985 fn test_flat_compat_batch_with_different_pk_encoding() {
986 let mut actual_metadata = new_metadata(
987 &[
988 (
989 0,
990 SemanticType::Timestamp,
991 ConcreteDataType::timestamp_millisecond_datatype(),
992 ),
993 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
994 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
995 ],
996 &[1],
997 );
998 actual_metadata.primary_key_encoding = PrimaryKeyEncoding::Dense;
999 let actual_metadata = Arc::new(actual_metadata);
1000
1001 let mut expected_metadata = new_metadata(
1002 &[
1003 (
1004 0,
1005 SemanticType::Timestamp,
1006 ConcreteDataType::timestamp_millisecond_datatype(),
1007 ),
1008 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1009 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1010 (3, SemanticType::Tag, ConcreteDataType::string_datatype()),
1011 ],
1012 &[1, 3],
1013 );
1014 expected_metadata.primary_key_encoding = PrimaryKeyEncoding::Sparse;
1015 let expected_metadata = Arc::new(expected_metadata);
1016
1017 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1018 let read_format = FlatReadFormat::new(
1019 actual_metadata.clone(),
1020 ReadColumns::new([0, 1, 2, 3]),
1021 None,
1022 "test",
1023 false,
1024 )
1025 .unwrap();
1026
1027 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
1028 .unwrap()
1029 .unwrap();
1030
1031 let mut tag1_builder = StringDictionaryBuilder::<UInt32Type>::new();
1033 tag1_builder.append_value("tag1");
1034 tag1_builder.append_value("tag1");
1035 let tag1_dict_array = Arc::new(tag1_builder.finish());
1036
1037 let k1 = encode_key(&[Some("tag1")]);
1038 let input_columns: Vec<ArrayRef> = vec![
1039 tag1_dict_array.clone(),
1040 Arc::new(Int64Array::from(vec![100, 200])),
1041 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1042 build_flat_test_pk_array(&[&k1, &k1]),
1043 Arc::new(UInt64Array::from_iter_values([1, 2])),
1044 Arc::new(UInt8Array::from_iter_values([
1045 OpType::Put as u8,
1046 OpType::Put as u8,
1047 ])),
1048 ];
1049 let input_schema =
1050 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1051 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1052
1053 let result = compat_batch.compat(input_batch).unwrap();
1054
1055 let sparse_k1 = encode_sparse_key(&[(1, Some("tag1")), (3, None)]);
1056 let mut null_tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
1057 null_tag_builder.append_nulls(2);
1058 let null_tag_dict_array = Arc::new(null_tag_builder.finish());
1059 let expected_columns: Vec<ArrayRef> = vec![
1060 tag1_dict_array.clone(),
1061 null_tag_dict_array,
1062 Arc::new(Int64Array::from(vec![100, 200])),
1063 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1064 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1065 Arc::new(UInt64Array::from_iter_values([1, 2])),
1066 Arc::new(UInt8Array::from_iter_values([
1067 OpType::Put as u8,
1068 OpType::Put as u8,
1069 ])),
1070 ];
1071 let output_schema =
1072 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1073 let expected_batch = RecordBatch::try_new(output_schema, expected_columns).unwrap();
1074
1075 assert_eq!(expected_batch, result);
1076 }
1077
1078 #[test]
1079 fn test_compat_primary_key_with_different_encoding_only() {
1080 let mut actual_metadata = new_metadata(
1081 &[
1082 (
1083 0,
1084 SemanticType::Timestamp,
1085 ConcreteDataType::timestamp_millisecond_datatype(),
1086 ),
1087 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1088 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1089 ],
1090 &[1],
1091 );
1092 actual_metadata.primary_key_encoding = PrimaryKeyEncoding::Dense;
1093 let actual_metadata = Arc::new(actual_metadata);
1094
1095 let mut expected_metadata = (*actual_metadata).clone();
1096 expected_metadata.primary_key_encoding = PrimaryKeyEncoding::Sparse;
1097 let expected_metadata = Arc::new(expected_metadata);
1098
1099 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1100 let read_format = FlatReadFormat::new(
1101 actual_metadata,
1102 ReadColumns::new([0, 1, 2]),
1103 None,
1104 "test",
1105 false,
1106 )
1107 .unwrap();
1108 let compat = FlatCompatBatch::try_new(&mapper, &read_format, false)
1109 .unwrap()
1110 .unwrap();
1111
1112 let dense_key = encode_key(&[Some("tag1")]);
1113 let sparse_key = encode_sparse_key(&[(1, Some("tag1"))]);
1114
1115 let dictionary_key = build_flat_test_pk_array(&[&dense_key, &dense_key]);
1116 let result = compat.compat_primary_key(&dictionary_key).unwrap();
1117 let result = result.as_any().downcast_ref::<PrimaryKeyArray>().unwrap();
1118 let values = result
1119 .values()
1120 .as_any()
1121 .downcast_ref::<BinaryArray>()
1122 .unwrap();
1123 assert_eq!(values.value(result.keys().value(0) as usize), sparse_key);
1124 assert_eq!(values.value(result.keys().value(1) as usize), sparse_key);
1125
1126 let binary_key: ArrayRef = Arc::new(BinaryArray::from(vec![
1127 Some(dense_key.as_slice()),
1128 Some(dense_key.as_slice()),
1129 ]));
1130 let result = compat.compat_primary_key(&binary_key).unwrap();
1131 let result = result.as_any().downcast_ref::<BinaryArray>().unwrap();
1132 assert_eq!(result.value(0), sparse_key);
1133 assert_eq!(result.value(1), sparse_key);
1134 }
1135
1136 #[test]
1139 fn test_flat_compat_batch_with_time_index_unit_change() {
1140 let actual_metadata = Arc::new(new_metadata(
1141 &[
1142 (
1143 0,
1144 SemanticType::Timestamp,
1145 ConcreteDataType::timestamp_millisecond_datatype(),
1146 ),
1147 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1148 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1149 ],
1150 &[1],
1151 ));
1152
1153 let mut expected_metadata = (*actual_metadata).clone();
1154 for column in expected_metadata.column_metadatas.iter_mut() {
1155 if column.semantic_type == SemanticType::Timestamp {
1156 column.column_schema.data_type = ConcreteDataType::timestamp_microsecond_datatype();
1157 }
1158 }
1159 let expected_metadata = Arc::new(
1161 RegionMetadataBuilder::from_existing(expected_metadata)
1162 .build()
1163 .unwrap(),
1164 );
1165
1166 let same_unit_metadata = Arc::new((*actual_metadata).clone());
1168 let mapper = FlatProjectionMapper::all(&same_unit_metadata).unwrap();
1169 let read_format = FlatReadFormat::new(
1170 actual_metadata.clone(),
1171 ReadColumns::new([0, 1, 2]),
1172 None,
1173 "test",
1174 false,
1175 )
1176 .unwrap();
1177 assert!(
1178 FlatCompatBatch::try_new(&mapper, &read_format, false)
1179 .unwrap()
1180 .is_none()
1181 );
1182
1183 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1185 let read_format = FlatReadFormat::new(
1186 actual_metadata.clone(),
1187 ReadColumns::new([0, 1, 2]),
1188 None,
1189 "test",
1190 false,
1191 )
1192 .unwrap();
1193 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
1194 .unwrap()
1195 .unwrap();
1196
1197 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
1198 tag_builder.append_value("tag1");
1199 tag_builder.append_value("tag1");
1200 let tag_dict_array = Arc::new(tag_builder.finish());
1201
1202 let k1 = encode_key(&[Some("tag1")]);
1203 let input_columns: Vec<ArrayRef> = vec![
1204 tag_dict_array.clone(),
1205 Arc::new(Int64Array::from(vec![100, 200])),
1206 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1207 build_flat_test_pk_array(&[&k1, &k1]),
1208 Arc::new(UInt64Array::from_iter_values([1, 2])),
1209 Arc::new(UInt8Array::from_iter_values([
1210 OpType::Put as u8,
1211 OpType::Put as u8,
1212 ])),
1213 ];
1214 let input_schema =
1215 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1216 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1217
1218 let result = compat_batch.compat(input_batch).unwrap();
1219
1220 let expected_columns: Vec<ArrayRef> = vec![
1221 tag_dict_array.clone(),
1222 Arc::new(Int64Array::from(vec![100, 200])),
1223 Arc::new(TimestampMicrosecondArray::from_iter_values([
1225 1_000_000, 2_000_000,
1226 ])),
1227 build_flat_test_pk_array(&[&k1, &k1]),
1228 Arc::new(UInt64Array::from_iter_values([1, 2])),
1229 Arc::new(UInt8Array::from_iter_values([
1230 OpType::Put as u8,
1231 OpType::Put as u8,
1232 ])),
1233 ];
1234 let expected_schema =
1235 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1236 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
1237
1238 assert_eq!(expected_batch, result);
1239 }
1240
1241 #[test]
1244 fn test_flat_compat_batch_time_index_unit_change_with_added_column() {
1245 let actual_metadata = Arc::new(new_metadata(
1246 &[
1247 (
1248 0,
1249 SemanticType::Timestamp,
1250 ConcreteDataType::timestamp_millisecond_datatype(),
1251 ),
1252 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1253 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1254 ],
1255 &[1],
1256 ));
1257
1258 let mut expected_metadata = new_metadata(
1259 &[
1260 (
1261 0,
1262 SemanticType::Timestamp,
1263 ConcreteDataType::timestamp_microsecond_datatype(),
1264 ),
1265 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1266 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1267 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
1268 ],
1269 &[1],
1270 );
1271 expected_metadata.primary_key_encoding = PrimaryKeyEncoding::Dense;
1272 let expected_metadata = Arc::new(expected_metadata);
1273
1274 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1275 let read_format = FlatReadFormat::new(
1276 actual_metadata.clone(),
1277 ReadColumns::new([0, 1, 2, 3]),
1278 None,
1279 "test",
1280 false,
1281 )
1282 .unwrap();
1283
1284 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
1285 .unwrap()
1286 .unwrap();
1287
1288 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
1289 tag_builder.append_value("tag1");
1290 tag_builder.append_value("tag1");
1291 let tag_dict_array = Arc::new(tag_builder.finish());
1292
1293 let k1 = encode_key(&[Some("tag1")]);
1294 let input_columns: Vec<ArrayRef> = vec![
1295 tag_dict_array.clone(),
1296 Arc::new(Int64Array::from(vec![100, 200])),
1297 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1298 build_flat_test_pk_array(&[&k1, &k1]),
1299 Arc::new(UInt64Array::from_iter_values([1, 2])),
1300 Arc::new(UInt8Array::from_iter_values([
1301 OpType::Put as u8,
1302 OpType::Put as u8,
1303 ])),
1304 ];
1305 let input_schema =
1306 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1307 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1308
1309 let result = compat_batch.compat(input_batch).unwrap();
1310
1311 let expected_columns: Vec<ArrayRef> = vec![
1312 tag_dict_array.clone(),
1313 Arc::new(Int64Array::from(vec![100, 200])),
1314 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
1315 Arc::new(TimestampMicrosecondArray::from_iter_values([
1316 1_000_000, 2_000_000,
1317 ])),
1318 build_flat_test_pk_array(&[&k1, &k1]),
1319 Arc::new(UInt64Array::from_iter_values([1, 2])),
1320 Arc::new(UInt8Array::from_iter_values([
1321 OpType::Put as u8,
1322 OpType::Put as u8,
1323 ])),
1324 ];
1325 let expected_schema =
1326 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1327 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
1328
1329 assert_eq!(expected_batch, result);
1330 }
1331
1332 #[test]
1335 fn test_flat_compat_batch_compact_sparse_time_index_unit_change() {
1336 let mut actual_metadata = new_metadata(
1337 &[
1338 (
1339 0,
1340 SemanticType::Timestamp,
1341 ConcreteDataType::timestamp_millisecond_datatype(),
1342 ),
1343 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1344 ],
1345 &[],
1346 );
1347 let reserved = crate::test_util::sst_util::sst_region_metadata_with_encoding(
1348 PrimaryKeyEncoding::Sparse,
1349 );
1350 actual_metadata.primary_key = reserved.primary_key.into_iter().take(2).collect();
1351 actual_metadata
1352 .column_metadatas
1353 .extend(reserved.column_metadatas.into_iter().take(2));
1354 actual_metadata.primary_key_encoding = PrimaryKeyEncoding::Sparse;
1355 let actual_metadata = Arc::new(
1356 RegionMetadataBuilder::from_existing(actual_metadata)
1357 .build()
1358 .unwrap(),
1359 );
1360
1361 let mut expected_metadata = (*actual_metadata).clone();
1362 for column in expected_metadata.column_metadatas.iter_mut() {
1363 if column.semantic_type == SemanticType::Timestamp {
1364 column.column_schema.data_type = ConcreteDataType::timestamp_microsecond_datatype();
1365 }
1366 }
1367 let expected_metadata = Arc::new(
1368 RegionMetadataBuilder::from_existing(expected_metadata)
1369 .build()
1370 .unwrap(),
1371 );
1372
1373 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1374 let read_format = FlatReadFormat::new(
1375 actual_metadata.clone(),
1376 ReadColumns::new([0, 2]),
1377 None,
1378 "test",
1379 true,
1380 )
1381 .unwrap();
1382
1383 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, true)
1384 .unwrap()
1385 .unwrap();
1386
1387 let mut sparse_k1 = Vec::new();
1388 SparsePrimaryKeyCodec::schemaless()
1389 .encode_internal(42, 7, &mut sparse_k1)
1390 .unwrap();
1391 let input_columns: Vec<ArrayRef> = vec![
1392 Arc::new(Int64Array::from(vec![100, 200])),
1393 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1394 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1395 Arc::new(UInt64Array::from_iter_values([1, 2])),
1396 Arc::new(UInt8Array::from_iter_values([
1397 OpType::Put as u8,
1398 OpType::Put as u8,
1399 ])),
1400 ];
1401 let input_schema = to_flat_sst_arrow_schema(
1402 &actual_metadata,
1403 &FlatSchemaOptions::from_encoding(PrimaryKeyEncoding::Sparse),
1404 );
1405 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1406
1407 let result = compat_batch.compat(input_batch).unwrap();
1408
1409 let expected_columns: Vec<ArrayRef> = vec![
1410 Arc::new(Int64Array::from(vec![100, 200])),
1411 Arc::new(TimestampMicrosecondArray::from_iter_values([
1412 1_000_000, 2_000_000,
1413 ])),
1414 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1415 Arc::new(UInt64Array::from_iter_values([1, 2])),
1416 Arc::new(UInt8Array::from_iter_values([
1417 OpType::Put as u8,
1418 OpType::Put as u8,
1419 ])),
1420 ];
1421 let output_schema = to_flat_sst_arrow_schema(
1422 &expected_metadata,
1423 &FlatSchemaOptions::from_encoding(PrimaryKeyEncoding::Sparse),
1424 );
1425 let expected_batch = RecordBatch::try_new(output_schema, expected_columns).unwrap();
1426
1427 assert_eq!(expected_batch, result);
1428 }
1429
1430 #[test]
1431 fn test_flat_compat_batch_compact_sparse() {
1432 let mut actual_metadata = new_metadata(
1433 &[
1434 (
1435 0,
1436 SemanticType::Timestamp,
1437 ConcreteDataType::timestamp_millisecond_datatype(),
1438 ),
1439 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1440 ],
1441 &[],
1442 );
1443 actual_metadata.primary_key_encoding = PrimaryKeyEncoding::Sparse;
1444 let actual_metadata = Arc::new(actual_metadata);
1445
1446 let mut expected_metadata = new_metadata(
1447 &[
1448 (
1449 0,
1450 SemanticType::Timestamp,
1451 ConcreteDataType::timestamp_millisecond_datatype(),
1452 ),
1453 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1454 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
1455 ],
1456 &[],
1457 );
1458 expected_metadata.primary_key_encoding = PrimaryKeyEncoding::Sparse;
1459 let expected_metadata = Arc::new(expected_metadata);
1460
1461 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1462 let read_format = FlatReadFormat::new(
1463 actual_metadata.clone(),
1464 ReadColumns::new([0, 2, 3]),
1465 None,
1466 "test",
1467 true,
1468 )
1469 .unwrap();
1470
1471 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, true)
1472 .unwrap()
1473 .unwrap();
1474
1475 let sparse_k1 = encode_sparse_key(&[]);
1476 let input_columns: Vec<ArrayRef> = vec![
1477 Arc::new(Int64Array::from(vec![100, 200])),
1478 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1479 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1480 Arc::new(UInt64Array::from_iter_values([1, 2])),
1481 Arc::new(UInt8Array::from_iter_values([
1482 OpType::Put as u8,
1483 OpType::Put as u8,
1484 ])),
1485 ];
1486 let input_schema =
1487 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1488 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1489
1490 let result = compat_batch.compat(input_batch).unwrap();
1491
1492 let expected_columns: Vec<ArrayRef> = vec![
1493 Arc::new(Int64Array::from(vec![100, 200])),
1494 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
1495 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1496 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1497 Arc::new(UInt64Array::from_iter_values([1, 2])),
1498 Arc::new(UInt8Array::from_iter_values([
1499 OpType::Put as u8,
1500 OpType::Put as u8,
1501 ])),
1502 ];
1503 let output_schema =
1504 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1505 let expected_batch = RecordBatch::try_new(output_schema, expected_columns).unwrap();
1506
1507 assert_eq!(expected_batch, result);
1508 }
1509 #[test]
1510 fn test_compaction_json2_uses_target_fields()
1511 -> std::result::Result<(), Box<dyn std::error::Error>> {
1512 let (metadata, batch) = test_util::sst_util::new_json2_record_batch()?;
1513 let logical_settings = JsonSettings::default();
1514 let layout = JsonSettings::try_new(vec![], Some(0))?;
1515 let targets: Json2RewriteTargets = Arc::new(BTreeMap::from([(
1516 0,
1517 Json2TargetLayout {
1518 extension_metadata: serde_json::to_string(&JsonMetadata::new(
1519 logical_settings.clone(),
1520 ))?,
1521 target_layout: layout.clone(),
1522 },
1523 )]));
1524 let json = JsonArray::from(batch.column(0)).rewrite_to_v2(
1526 batch.schema_ref().field(0),
1527 &logical_settings,
1528 &layout,
1529 )?;
1530 let mut fields = batch.schema_ref().fields().to_vec();
1531 fields[0] = Arc::new(
1532 fields[0]
1533 .as_ref()
1534 .clone()
1535 .with_data_type(json.data_type().clone()),
1536 );
1537 let mut columns = batch.columns().to_vec();
1538 columns[0] = json;
1539 let batch = RecordBatch::try_new(Arc::new(Schema::new(fields)), columns)?;
1540 for encoding in [PrimaryKeyEncoding::Dense, PrimaryKeyEncoding::Sparse] {
1541 let batch = if encoding == PrimaryKeyEncoding::Sparse {
1542 let mut key = Vec::new();
1543 SparsePrimaryKeyCodec::schemaless().encode_internal(42, 7, &mut key)?;
1544 let mut columns = batch.columns().to_vec();
1545 columns[primary_key_column_index(batch.num_columns())] =
1546 build_flat_test_pk_array(&[&key, &key]);
1547 RecordBatch::try_new(batch.schema(), columns)?
1548 } else {
1549 batch.clone()
1550 };
1551 for missing_json in [false, true] {
1552 let source = if missing_json {
1553 new_metadata(
1554 &[(
1555 1,
1556 SemanticType::Timestamp,
1557 ConcreteDataType::timestamp_millisecond_datatype(),
1558 )],
1559 &[],
1560 )
1561 } else {
1562 metadata.as_ref().clone()
1563 };
1564 let mut actual_builder = RegionMetadataBuilder::from_existing(source);
1565 actual_builder.primary_key_encoding(encoding);
1566 let mut expected_builder =
1567 RegionMetadataBuilder::from_existing(metadata.as_ref().clone());
1568 expected_builder.primary_key_encoding(encoding);
1569 expected_builder.push_column_metadata(ColumnMetadata {
1570 column_schema: ColumnSchema::new(
1571 "added",
1572 ConcreteDataType::int64_datatype(),
1573 true,
1574 )
1575 .with_default_constraint(Some(
1576 ColumnDefaultConstraint::Value(Value::Int64(42)),
1577 ))?,
1578 semantic_type: SemanticType::Field,
1579 column_id: 2,
1580 });
1581 if encoding == PrimaryKeyEncoding::Sparse {
1582 let reserved = test_util::sst_util::sst_region_metadata_with_encoding(encoding);
1583 for builder in [&mut actual_builder, &mut expected_builder] {
1584 builder.primary_key(reserved.primary_key[..2].to_vec());
1585 for column in reserved.column_metadatas.iter().take(2) {
1586 builder.push_column_metadata(column.clone());
1587 }
1588 }
1589 }
1590 let actual = Arc::new(actual_builder.build()?);
1591 let expected = Arc::new(expected_builder.build()?);
1592 let read_columns = ReadColumns::new([0, 1, 2]);
1593 let mapper = FlatProjectionMapper::new_with_json2_rewrite_targets(
1594 &expected,
1595 vec![0, 1, 2],
1596 read_columns.clone(),
1597 &targets,
1598 )?;
1599 let read_format = FlatReadFormat::new(actual, read_columns, None, "test", true)?;
1600 let compat = FlatCompatBatch::try_new(&mapper, &read_format, true)?
1601 .ok_or("missing columns require compatibility")?;
1602 let input = if missing_json {
1603 batch.project(&[1, 2, 3, 4])?
1604 } else {
1605 batch.clone()
1606 };
1607 let output = compat.compat(input)?;
1608 assert_eq!(
1609 output.column(0).data_type(),
1610 &json2_physical_data_type(&layout)
1611 );
1612 assert_eq!(
1613 output.column(0).null_count(),
1614 if missing_json { 2 } else { 0 }
1615 );
1616 let defaults = output
1617 .column(1)
1618 .as_any()
1619 .downcast_ref::<Int64Array>()
1620 .ok_or("expected int64 defaults")?;
1621 assert_eq!(defaults.values().as_ref(), &[42, 42]);
1622 if !missing_json {
1623 let jsonb = JsonArray::from(output.column(0)).project_to_v2(
1624 output.schema_ref().field(0),
1625 &datatypes::arrow::datatypes::DataType::Binary,
1626 )?;
1627 let jsonb = jsonb
1628 .as_any()
1629 .downcast_ref::<BinaryArray>()
1630 .ok_or("expected JSONB")?;
1631 assert_eq!(jsonb.value(0), parse_string_to_jsonb(r#"{"a":1}"#)?);
1632 assert_eq!(jsonb.value(1), parse_string_to_jsonb(r#"{"a":2}"#)?);
1633 }
1634 }
1635 }
1636 Ok(())
1637 }
1638}