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, &actual_schema);
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 actual_schema: &[(ColumnId, ConcreteDataType)],
229 ) -> Result<Option<Self>> {
230 ensure!(
233 mapper.metadata().primary_key_encoding == actual.primary_key_encoding,
234 UnsupportedOperationSnafu {
235 err_msg: "Flat format doesn't support converting sparse encoding back to dense encoding"
236 }
237 );
238
239 let mut actual_fields = Vec::with_capacity(actual_schema.len());
242 for (id, data_type) in actual_schema {
243 let column = actual
244 .column_by_id(*id)
245 .with_context(|| CompatReaderSnafu {
246 region_id: actual.region_id,
247 reason: format!("column {id} is absent from region metadata"),
248 })?;
249 if column.semantic_type != SemanticType::Tag {
250 actual_fields.push((*id, data_type.clone()));
251 }
252 }
253 let mut expect_fields = Vec::with_capacity(mapper.batch_schema().len());
254 for (id, data_type) in mapper.batch_schema() {
255 let column =
256 mapper
257 .metadata()
258 .column_by_id(*id)
259 .with_context(|| CompatReaderSnafu {
260 region_id: mapper.metadata().region_id,
261 reason: format!("column {id} is absent from region metadata"),
262 })?;
263 if column.semantic_type != SemanticType::Tag {
264 expect_fields.push((*id, data_type.clone()));
265 }
266 }
267
268 let (index_or_defaults, fields) = Self::compute_index_and_fields(
269 &actual_fields,
270 &expect_fields,
271 mapper.metadata(),
272 mapper.input_arrow_schema(true).fields(),
273 )?;
274
275 let compat_pk = FlatCompatPrimaryKey::default();
276
277 Ok(Some(Self {
278 index_or_defaults,
279 arrow_schema: Arc::new(Schema::new(fields)),
280 compat_pk,
281 }))
282 }
283
284 pub(crate) fn compat(&self, batch: RecordBatch) -> Result<RecordBatch> {
286 let len = batch.num_rows();
287 let columns = self
288 .index_or_defaults
289 .iter()
290 .map(|index_or_default| match index_or_default {
291 IndexOrDefault::Index { pos, cast_type } => {
292 let old_column = batch.column(*pos);
293
294 if let Some(ty) = cast_type {
295 let casted =
296 datatypes::arrow::compute::cast(old_column, &ty.as_arrow_type())
297 .context(ComputeArrowSnafu)?;
298 Ok(casted)
299 } else {
300 Ok(old_column.clone())
301 }
302 }
303 IndexOrDefault::DefaultValue {
304 default_vector,
305 semantic_type,
306 } => repeat_vector(default_vector, len, *semantic_type == SemanticType::Tag),
307 })
308 .chain(
309 batch.columns()[batch.num_columns() - INTERNAL_COLUMN_NUM..]
311 .iter()
312 .map(|col| Ok(col.clone())),
313 )
314 .collect::<Result<Vec<_>>>()?;
315
316 let mut columns = columns;
317 let primary_key_index = primary_key_column_index(columns.len());
318 columns[primary_key_index] = self.compat_primary_key(&columns[primary_key_index])?;
319
320 RecordBatch::try_new(self.arrow_schema.clone(), columns).context(NewRecordBatchSnafu)
321 }
322
323 pub(crate) fn compat_primary_key(&self, primary_key: &ArrayRef) -> Result<ArrayRef> {
325 self.compat_pk.compat(primary_key)
326 }
327}
328
329fn repeat_vector(vector: &VectorRef, to_len: usize, is_tag: bool) -> Result<ArrayRef> {
331 assert_eq!(1, vector.len());
332 let data_type = vector.data_type();
333 if is_tag && data_type.is_string() {
334 let values = vector.to_arrow_array();
335 if values.is_null(0) {
336 let keys = UInt32Array::new_null(to_len);
338 Ok(Arc::new(DictionaryArray::new(keys, values.slice(0, 0))))
339 } else {
340 let keys = UInt32Array::from_value(0, to_len);
341 Ok(Arc::new(DictionaryArray::new(keys, values)))
342 }
343 } else {
344 let keys = UInt32Array::from_value(0, to_len);
345 take(
346 &vector.to_arrow_array(),
347 &keys,
348 Some(TakeOptions {
349 check_bounds: false,
350 }),
351 )
352 .context(ComputeArrowSnafu)
353 }
354}
355
356fn is_primary_key_same(expect: &RegionMetadata, actual: &RegionMetadata) -> Result<bool> {
358 ensure!(
359 actual.primary_key.len() <= expect.primary_key.len(),
360 CompatReaderSnafu {
361 region_id: expect.region_id,
362 reason: format!(
363 "primary key has more columns {} than expect {}",
364 actual.primary_key.len(),
365 expect.primary_key.len()
366 ),
367 }
368 );
369 ensure!(
370 actual.primary_key == expect.primary_key[..actual.primary_key.len()],
371 CompatReaderSnafu {
372 region_id: expect.region_id,
373 reason: format!(
374 "primary key has different prefix, expect: {:?}, actual: {:?}",
375 expect.primary_key, actual.primary_key
376 ),
377 }
378 );
379
380 Ok(actual.primary_key.len() == expect.primary_key.len())
381}
382
383#[derive(Debug)]
385enum IndexOrDefault {
386 Index {
388 pos: usize,
389 cast_type: Option<ConcreteDataType>,
390 },
391 DefaultValue {
393 default_vector: VectorRef,
395 semantic_type: SemanticType,
397 },
398}
399
400struct FlatRewritePrimaryKey {
402 codec: Arc<dyn PrimaryKeyCodec>,
404 metadata: RegionMetadataRef,
406 old_codec: Arc<dyn PrimaryKeyCodec>,
409}
410
411impl FlatRewritePrimaryKey {
412 fn new(
413 expect: &RegionMetadataRef,
414 actual: &RegionMetadataRef,
415 ) -> Option<FlatRewritePrimaryKey> {
416 if expect.primary_key_encoding == actual.primary_key_encoding {
417 return None;
418 }
419 let codec = build_primary_key_codec(expect);
420 let old_codec = build_primary_key_codec(actual);
421
422 Some(FlatRewritePrimaryKey {
423 codec,
424 metadata: expect.clone(),
425 old_codec,
426 })
427 }
428
429 fn rewrite_key(
432 &self,
433 append_values: &[(ColumnId, Value)],
434 primary_key: &ArrayRef,
435 ) -> Result<ArrayRef> {
436 if let Some(old_pk_dict_array) = primary_key.as_any().downcast_ref::<PrimaryKeyArray>() {
437 let old_pk_values_array = old_pk_dict_array
438 .values()
439 .as_any()
440 .downcast_ref::<BinaryArray>()
441 .context(UnexpectedSnafu {
442 reason: "Primary-key dictionary values are not binary",
443 })?;
444 let new_pk_values_array =
445 Arc::new(self.rewrite_values(append_values, old_pk_values_array)?);
446 return Ok(Arc::new(PrimaryKeyArray::new(
447 old_pk_dict_array.keys().clone(),
448 new_pk_values_array,
449 )));
450 }
451
452 let old_pk_values_array =
453 primary_key
454 .as_any()
455 .downcast_ref::<BinaryArray>()
456 .context(UnexpectedSnafu {
457 reason: format!(
458 "Primary-key column is neither binary nor dictionary, got {:?}",
459 primary_key.data_type()
460 ),
461 })?;
462 Ok(Arc::new(
463 self.rewrite_values(append_values, old_pk_values_array)?,
464 ))
465 }
466
467 fn rewrite_values(
468 &self,
469 append_values: &[(ColumnId, Value)],
470 old_pk_values_array: &BinaryArray,
471 ) -> Result<BinaryArray> {
472 let mut builder = BinaryBuilder::with_capacity(
473 old_pk_values_array.len(),
474 old_pk_values_array.value_data().len(),
475 );
476
477 let mut buffer = Vec::with_capacity(
479 old_pk_values_array.value_data().len() / old_pk_values_array.len().max(1),
480 );
481 let mut column_id_values = Vec::new();
482 for value in old_pk_values_array.iter() {
484 let Some(old_pk) = value else {
485 builder.append_null();
486 continue;
487 };
488 let mut pk_values = self.old_codec.decode(old_pk).context(DecodeSnafu)?;
490 pk_values.extend(append_values);
491
492 buffer.clear();
493 column_id_values.clear();
494 match pk_values {
496 CompositeValues::Dense(dense_values) => {
497 self.codec
498 .encode_values(dense_values.as_slice(), &mut buffer)
499 .context(EncodeSnafu)?;
500 }
501 CompositeValues::Sparse(sparse_values) => {
502 for id in &self.metadata.primary_key {
503 let value = sparse_values.get_or_null(*id);
504 column_id_values.push((*id, value.clone()));
505 }
506 self.codec
507 .encode_values(&column_id_values, &mut buffer)
508 .context(EncodeSnafu)?;
509 }
510 }
511 builder.append_value(&buffer);
512 }
513 Ok(builder.finish())
514 }
515}
516
517#[derive(Default)]
519struct FlatCompatPrimaryKey {
520 rewriter: Option<FlatRewritePrimaryKey>,
522 converter: Option<Arc<dyn PrimaryKeyCodec>>,
524 values: Vec<(ColumnId, Value)>,
526}
527
528impl FlatCompatPrimaryKey {
529 fn new(expect: &RegionMetadataRef, actual: &RegionMetadataRef) -> Result<Self> {
530 let rewriter = FlatRewritePrimaryKey::new(expect, actual);
531
532 if is_primary_key_same(expect, actual)? {
533 return Ok(Self {
534 rewriter,
535 converter: None,
536 values: Vec::new(),
537 });
538 }
539
540 let to_add = &expect.primary_key[actual.primary_key.len()..];
542 let mut values = Vec::with_capacity(to_add.len());
543 let mut fields = Vec::with_capacity(to_add.len());
544 for column_id in to_add {
545 let column = expect.column_by_id(*column_id).unwrap();
547 fields.push((
548 *column_id,
549 SortField::new(column.column_schema.data_type.clone()),
550 ));
551 let default_value = column
552 .column_schema
553 .create_default()
554 .context(CreateDefaultSnafu {
555 region_id: expect.region_id,
556 column: &column.column_schema.name,
557 })?
558 .with_context(|| CompatReaderSnafu {
559 region_id: expect.region_id,
560 reason: format!(
561 "key column {} does not have a default value to read",
562 column.column_schema.name
563 ),
564 })?;
565 values.push((*column_id, default_value));
566 }
567 debug_assert!(!fields.is_empty());
569
570 let converter =
572 build_primary_key_codec_with_fields(expect.primary_key_encoding, fields.into_iter());
573
574 Ok(Self {
575 rewriter,
576 converter: Some(converter),
577 values,
578 })
579 }
580
581 fn compat(&self, primary_key: &ArrayRef) -> Result<ArrayRef> {
583 if let Some(rewriter) = &self.rewriter {
584 return rewriter.rewrite_key(&self.values, primary_key);
586 }
587
588 self.append_key(primary_key)
589 }
590
591 fn append_key(&self, primary_key: &ArrayRef) -> Result<ArrayRef> {
593 let Some(converter) = &self.converter else {
594 return Ok(primary_key.clone());
595 };
596
597 if let Some(old_pk_dict_array) = primary_key.as_any().downcast_ref::<PrimaryKeyArray>() {
598 let old_pk_values_array = old_pk_dict_array
599 .values()
600 .as_any()
601 .downcast_ref::<BinaryArray>()
602 .context(UnexpectedSnafu {
603 reason: "Primary-key dictionary values are not binary",
604 })?;
605 let new_pk_values_array =
606 Arc::new(self.append_values(old_pk_values_array, converter.as_ref())?);
607 return Ok(Arc::new(PrimaryKeyArray::new(
608 old_pk_dict_array.keys().clone(),
609 new_pk_values_array,
610 )));
611 }
612
613 let old_pk_values_array =
614 primary_key
615 .as_any()
616 .downcast_ref::<BinaryArray>()
617 .context(UnexpectedSnafu {
618 reason: format!(
619 "Primary-key column is neither binary nor dictionary, got {:?}",
620 primary_key.data_type()
621 ),
622 })?;
623 Ok(Arc::new(
624 self.append_values(old_pk_values_array, converter.as_ref())?,
625 ))
626 }
627
628 fn append_values(
629 &self,
630 old_pk_values_array: &BinaryArray,
631 converter: &dyn PrimaryKeyCodec,
632 ) -> Result<BinaryArray> {
633 let mut builder = BinaryBuilder::with_capacity(
634 old_pk_values_array.len(),
635 old_pk_values_array.value_data().len()
636 + converter.estimated_size().unwrap_or_default() * old_pk_values_array.len(),
637 );
638
639 let mut buffer = Vec::with_capacity(
641 old_pk_values_array.value_data().len() / old_pk_values_array.len().max(1)
642 + converter.estimated_size().unwrap_or_default(),
643 );
644
645 for value in old_pk_values_array.iter() {
647 let Some(old_pk) = value else {
648 builder.append_null();
649 continue;
650 };
651
652 buffer.clear();
653 buffer.extend_from_slice(old_pk);
654 converter
655 .encode_values(&self.values, &mut buffer)
656 .context(EncodeSnafu)?;
657
658 builder.append_value(&buffer);
659 }
660
661 Ok(builder.finish())
662 }
663}
664
665#[cfg(test)]
666mod tests {
667 use std::collections::BTreeMap;
668 use std::sync::Arc;
669
670 use api::v1::{OpType, SemanticType};
671 use datatypes::arrow::array::{
672 ArrayRef, BinaryArray, BinaryDictionaryBuilder, Int64Array, StringDictionaryBuilder,
673 TimestampMicrosecondArray, TimestampMillisecondArray, UInt8Array, UInt64Array,
674 };
675 use datatypes::arrow::datatypes::UInt32Type;
676 use datatypes::arrow::record_batch::RecordBatch;
677 use datatypes::extension::json::JsonMetadata;
678 use datatypes::json::JsonSettings;
679 use datatypes::prelude::ConcreteDataType;
680 use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema};
681 use datatypes::types::json_type::JsonNativeType;
682 use datatypes::types::parse_string_to_jsonb;
683 use datatypes::value::ValueRef;
684 use datatypes::vectors::json::array::JsonArray;
685 use datatypes::vectors::json::json2_physical_data_type;
686 use mito_codec::row_converter::{
687 DensePrimaryKeyCodec, PrimaryKeyCodecExt, SparsePrimaryKeyCodec,
688 };
689 use store_api::codec::PrimaryKeyEncoding;
690 use store_api::metadata::{ColumnMetadata, RegionMetadataBuilder};
691 use store_api::storage::RegionId;
692 use store_api::storage::consts::ReservedColumnId;
693
694 use super::*;
695 use crate::read::flat_projection::FlatProjectionMapper;
696 use crate::read::read_columns::ReadColumns;
697 use crate::sst::parquet::flat_format::FlatReadFormat;
698 use crate::sst::parquet::{Json2RewriteTargets, Json2TargetLayout};
699 use crate::sst::{FlatSchemaOptions, to_flat_sst_arrow_schema};
700 use crate::test_util;
701 use crate::test_util::sst_util::sst_region_metadata_with_encoding;
702
703 fn new_metadata(
705 semantic_types: &[(ColumnId, SemanticType, ConcreteDataType)],
706 primary_key: &[ColumnId],
707 ) -> RegionMetadata {
708 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
709 for (id, semantic_type, data_type) in semantic_types {
710 let mut column_schema = match semantic_type {
711 SemanticType::Tag => {
712 ColumnSchema::new(format!("tag_{id}"), data_type.clone(), true)
713 }
714 SemanticType::Field => {
715 ColumnSchema::new(format!("field_{id}"), data_type.clone(), true)
716 }
717 SemanticType::Timestamp => ColumnSchema::new("ts", data_type.clone(), false),
718 };
719 if data_type.is_json2() {
720 column_schema.with_extension_type(
721 &datatypes::extension::json::Json2ExtensionType::default(),
722 );
723 }
724
725 builder.push_column_metadata(ColumnMetadata {
726 column_schema,
727 semantic_type: *semantic_type,
728 column_id: *id,
729 });
730 }
731 builder.primary_key(primary_key.to_vec());
732 builder.build().unwrap()
733 }
734
735 fn with_sparse_encoding(metadata: RegionMetadata) -> RegionMetadata {
736 let reserved = sst_region_metadata_with_encoding(PrimaryKeyEncoding::Sparse);
737 let primary_key = reserved
738 .primary_key
739 .into_iter()
740 .take(2)
741 .chain(metadata.primary_key.iter().copied())
742 .collect();
743 let mut builder = RegionMetadataBuilder::from_existing(metadata);
744 for column in reserved.column_metadatas.into_iter().take(2) {
745 builder.push_column_metadata(column);
746 }
747 builder
748 .primary_key(primary_key)
749 .primary_key_encoding(PrimaryKeyEncoding::Sparse);
750 builder.build().unwrap()
751 }
752
753 fn encode_key(keys: &[Option<&str>]) -> Vec<u8> {
755 let fields = (0..keys.len())
756 .map(|_| (0, SortField::new(ConcreteDataType::string_datatype())))
757 .collect();
758 let converter = DensePrimaryKeyCodec::with_fields(fields);
759 let row = keys.iter().map(|str_opt| match str_opt {
760 Some(v) => ValueRef::String(v),
761 None => ValueRef::Null,
762 });
763
764 converter.encode(row).unwrap()
765 }
766
767 fn encode_sparse_key(keys: &[(ColumnId, Option<&str>)]) -> Vec<u8> {
769 let converter = SparsePrimaryKeyCodec::schemaless();
770 let row = keys
771 .iter()
772 .map(|(id, str_opt)| match str_opt {
773 Some(v) => (*id, ValueRef::String(v)),
774 None => (*id, ValueRef::Null),
775 })
776 .collect::<Vec<_>>();
777 let mut buffer = vec![];
778 converter.encode_internal(42, 7, &mut buffer).unwrap();
779 converter.encode_value_refs(&row, &mut buffer).unwrap();
780 buffer
781 }
782
783 fn build_flat_test_pk_array(primary_keys: &[&[u8]]) -> ArrayRef {
785 let mut builder = BinaryDictionaryBuilder::<UInt32Type>::new();
786 for &pk in primary_keys {
787 builder.append(pk).unwrap();
788 }
789 Arc::new(builder.finish())
790 }
791
792 #[test]
793 fn test_flat_compat_batch_with_missing_columns() {
794 let actual_metadata = Arc::new(new_metadata(
795 &[
796 (
797 0,
798 SemanticType::Timestamp,
799 ConcreteDataType::timestamp_millisecond_datatype(),
800 ),
801 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
802 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
803 ],
804 &[1],
805 ));
806
807 let expected_metadata = Arc::new(new_metadata(
808 &[
809 (
810 0,
811 SemanticType::Timestamp,
812 ConcreteDataType::timestamp_millisecond_datatype(),
813 ),
814 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
815 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
816 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
818 ],
819 &[1],
820 ));
821
822 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
823 let read_format = FlatReadFormat::new(
824 actual_metadata.clone(),
825 ReadColumns::new([0, 1, 2, 3]),
826 None,
827 "test",
828 false,
829 )
830 .unwrap();
831
832 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
833 .unwrap()
834 .unwrap();
835
836 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
837 tag_builder.append_value("tag1");
838 tag_builder.append_value("tag1");
839 let tag_dict_array = Arc::new(tag_builder.finish());
840
841 let k1 = encode_key(&[Some("tag1")]);
842 let input_columns: Vec<ArrayRef> = vec![
843 tag_dict_array.clone(),
844 Arc::new(Int64Array::from(vec![100, 200])),
845 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
846 build_flat_test_pk_array(&[&k1, &k1]),
847 Arc::new(UInt64Array::from_iter_values([1, 2])),
848 Arc::new(UInt8Array::from_iter_values([
849 OpType::Put as u8,
850 OpType::Put as u8,
851 ])),
852 ];
853 let input_schema =
854 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
855 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
856
857 let result = compat_batch.compat(input_batch).unwrap();
858
859 let expected_schema =
860 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
861
862 let expected_columns: Vec<ArrayRef> = vec![
863 tag_dict_array.clone(),
864 Arc::new(Int64Array::from(vec![100, 200])),
865 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
866 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
867 build_flat_test_pk_array(&[&k1, &k1]),
868 Arc::new(UInt64Array::from_iter_values([1, 2])),
869 Arc::new(UInt8Array::from_iter_values([
870 OpType::Put as u8,
871 OpType::Put as u8,
872 ])),
873 ];
874 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
875
876 assert_eq!(expected_batch, result);
877 }
878
879 #[rstest::rstest]
880 #[case(PrimaryKeyEncoding::Dense, false)]
881 #[case(PrimaryKeyEncoding::Sparse, true)]
882 fn test_flat_compat_batch_uses_projected_json2_type(
883 #[case] encoding: PrimaryKeyEncoding,
884 #[case] compaction: bool,
885 ) -> Result<()> {
886 let json2 = ConcreteDataType::json2(JsonNativeType::object());
887 let mut actual_metadata = Arc::new(new_metadata(
888 &[
889 (
890 0,
891 SemanticType::Timestamp,
892 ConcreteDataType::timestamp_millisecond_datatype(),
893 ),
894 (1, SemanticType::Field, json2.clone()),
895 ],
896 &[],
897 ));
898 let mut expected_metadata = Arc::new(new_metadata(
899 &[
900 (
901 0,
902 SemanticType::Timestamp,
903 ConcreteDataType::timestamp_millisecond_datatype(),
904 ),
905 (1, SemanticType::Field, json2),
906 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
907 ],
908 &[],
909 ));
910 if encoding == PrimaryKeyEncoding::Sparse {
911 actual_metadata = Arc::new(with_sparse_encoding((*actual_metadata).clone()));
912 expected_metadata = Arc::new(with_sparse_encoding((*expected_metadata).clone()));
913 }
914 let read_columns = ReadColumns::new([0, 1, 2])
915 .with_json_target_types(BTreeMap::from([(1, JsonNativeType::Variant)]));
916 let mapper = FlatProjectionMapper::new_with_read_columns(
917 &expected_metadata,
918 vec![0, 1, 2],
919 read_columns.clone(),
920 )?;
921 let read_format = FlatReadFormat::new(actual_metadata, read_columns, None, "test", false)?;
922
923 let compat = FlatCompatBatch::try_new(&mapper, &read_format, compaction)?.unwrap();
924 let json_index = mapper
925 .batch_schema()
926 .iter()
927 .position(|(id, _)| *id == 1)
928 .unwrap();
929 assert!(matches!(
930 &compat.index_or_defaults[json_index],
931 IndexOrDefault::Index {
932 cast_type: None,
933 ..
934 }
935 ));
936 assert_eq!(
937 compat.arrow_schema.field(json_index).data_type(),
938 &datatypes::arrow::datatypes::DataType::Binary
939 );
940 Ok(())
941 }
942
943 #[test]
944 fn test_flat_compat_batch_with_read_projection_superset() {
945 let actual_metadata = Arc::new(new_metadata(
946 &[
947 (
948 0,
949 SemanticType::Timestamp,
950 ConcreteDataType::timestamp_millisecond_datatype(),
951 ),
952 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
953 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
954 ],
955 &[1],
956 ));
957
958 let expected_metadata = Arc::new(new_metadata(
959 &[
960 (
961 0,
962 SemanticType::Timestamp,
963 ConcreteDataType::timestamp_millisecond_datatype(),
964 ),
965 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
966 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
967 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
969 ],
970 &[1],
971 ));
972
973 let mapper = FlatProjectionMapper::new_with_read_columns(
974 &expected_metadata,
975 vec![1, 2],
976 ReadColumns::new([1, 2, 3]),
977 )
978 .unwrap();
979 let read_format = FlatReadFormat::new(
980 actual_metadata.clone(),
981 ReadColumns::new([1, 2, 3]),
982 None,
983 "test",
984 false,
985 )
986 .unwrap();
987
988 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
989 .unwrap()
990 .unwrap();
991
992 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
993 tag_builder.append_value("tag1");
994 tag_builder.append_value("tag1");
995 let tag_dict_array = Arc::new(tag_builder.finish());
996
997 let k1 = encode_key(&[Some("tag1")]);
998 let input_columns: Vec<ArrayRef> = vec![
999 tag_dict_array.clone(),
1000 Arc::new(Int64Array::from(vec![100, 200])),
1001 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1002 build_flat_test_pk_array(&[&k1, &k1]),
1003 Arc::new(UInt64Array::from_iter_values([1, 2])),
1004 Arc::new(UInt8Array::from_iter_values([
1005 OpType::Put as u8,
1006 OpType::Put as u8,
1007 ])),
1008 ];
1009 let input_schema =
1010 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1011 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1012
1013 let result = compat_batch.compat(input_batch).unwrap();
1014
1015 let expected_schema =
1016 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1017 let expected_columns: Vec<ArrayRef> = vec![
1018 tag_dict_array.clone(),
1019 Arc::new(Int64Array::from(vec![100, 200])),
1020 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
1021 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1022 build_flat_test_pk_array(&[&k1, &k1]),
1023 Arc::new(UInt64Array::from_iter_values([1, 2])),
1024 Arc::new(UInt8Array::from_iter_values([
1025 OpType::Put as u8,
1026 OpType::Put as u8,
1027 ])),
1028 ];
1029 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
1030
1031 assert_eq!(expected_batch, result);
1032 }
1033
1034 #[test]
1035 fn test_flat_compat_batch_with_different_pk_encoding() {
1036 let mut actual_metadata = new_metadata(
1037 &[
1038 (
1039 0,
1040 SemanticType::Timestamp,
1041 ConcreteDataType::timestamp_millisecond_datatype(),
1042 ),
1043 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1044 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1045 ],
1046 &[1],
1047 );
1048 actual_metadata = with_sparse_encoding(actual_metadata);
1049 actual_metadata.primary_key_encoding = PrimaryKeyEncoding::Dense;
1050 let actual_metadata = Arc::new(actual_metadata);
1051
1052 let mut expected_metadata = new_metadata(
1053 &[
1054 (
1055 0,
1056 SemanticType::Timestamp,
1057 ConcreteDataType::timestamp_millisecond_datatype(),
1058 ),
1059 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1060 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1061 (3, SemanticType::Tag, ConcreteDataType::string_datatype()),
1062 ],
1063 &[1, 3],
1064 );
1065 expected_metadata = with_sparse_encoding(expected_metadata);
1066 let expected_metadata = Arc::new(expected_metadata);
1067
1068 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1069 let read_format = FlatReadFormat::new(
1070 actual_metadata.clone(),
1071 ReadColumns::new([
1072 0,
1073 1,
1074 2,
1075 3,
1076 ReservedColumnId::table_id(),
1077 ReservedColumnId::tsid(),
1078 ]),
1079 None,
1080 "test",
1081 false,
1082 )
1083 .unwrap();
1084
1085 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
1086 .unwrap()
1087 .unwrap();
1088
1089 let mut tag1_builder = StringDictionaryBuilder::<UInt32Type>::new();
1091 tag1_builder.append_value("tag1");
1092 tag1_builder.append_value("tag1");
1093 let tag1_dict_array = Arc::new(tag1_builder.finish());
1094
1095 let mut k1 = Vec::new();
1096 build_primary_key_codec(&actual_metadata)
1097 .encode_values(
1098 &[
1099 (ReservedColumnId::table_id(), Value::UInt32(42)),
1100 (ReservedColumnId::tsid(), Value::UInt64(7)),
1101 (1, Value::from("tag1")),
1102 ],
1103 &mut k1,
1104 )
1105 .unwrap();
1106 let input_columns: Vec<ArrayRef> = vec![
1107 Arc::new(datatypes::arrow::array::UInt32Array::from(vec![42, 42])),
1108 Arc::new(UInt64Array::from(vec![7, 7])),
1109 tag1_dict_array.clone(),
1110 Arc::new(Int64Array::from(vec![100, 200])),
1111 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1112 build_flat_test_pk_array(&[&k1, &k1]),
1113 Arc::new(UInt64Array::from_iter_values([1, 2])),
1114 Arc::new(UInt8Array::from_iter_values([
1115 OpType::Put as u8,
1116 OpType::Put as u8,
1117 ])),
1118 ];
1119 let input_schema =
1120 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1121 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1122
1123 let result = compat_batch.compat(input_batch).unwrap();
1124
1125 let sparse_k1 = encode_sparse_key(&[(1, Some("tag1")), (3, None)]);
1126 let mut null_tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
1127 null_tag_builder.append_nulls(2);
1128 let null_tag_dict_array = Arc::new(null_tag_builder.finish());
1129 let expected_columns: Vec<ArrayRef> = vec![
1130 Arc::new(datatypes::arrow::array::UInt32Array::from(vec![42, 42])),
1131 Arc::new(UInt64Array::from(vec![7, 7])),
1132 tag1_dict_array.clone(),
1133 null_tag_dict_array,
1134 Arc::new(Int64Array::from(vec![100, 200])),
1135 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1136 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1137 Arc::new(UInt64Array::from_iter_values([1, 2])),
1138 Arc::new(UInt8Array::from_iter_values([
1139 OpType::Put as u8,
1140 OpType::Put as u8,
1141 ])),
1142 ];
1143 let output_schema =
1144 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1145 let expected_batch = RecordBatch::try_new(output_schema, expected_columns).unwrap();
1146
1147 assert_eq!(expected_batch, result);
1148 }
1149
1150 #[test]
1151 fn test_compat_sparse_primary_key_with_new_nullable_tag() {
1152 let actual = Arc::new(sst_region_metadata_with_encoding(
1153 PrimaryKeyEncoding::Sparse,
1154 ));
1155 let mut builder = RegionMetadataBuilder::from_existing((*actual).clone());
1156 let mut primary_key = actual.primary_key.clone();
1157 primary_key.push(4);
1158 builder
1159 .push_column_metadata(ColumnMetadata {
1160 column_schema: ColumnSchema::new(
1161 "new_tag",
1162 ConcreteDataType::string_datatype(),
1163 true,
1164 ),
1165 semantic_type: SemanticType::Tag,
1166 column_id: 4,
1167 })
1168 .primary_key(primary_key);
1169 let expected = Arc::new(builder.build().unwrap());
1170 let compat = FlatCompatPrimaryKey::new(&expected, &actual).unwrap();
1171
1172 let values = vec![
1173 (ReservedColumnId::table_id(), Value::UInt32(23)),
1174 (ReservedColumnId::tsid(), Value::UInt64(42)),
1175 (0, Value::from("api")),
1176 (1, Value::Null),
1177 ];
1178 let mut key = Vec::new();
1179 build_primary_key_codec(&actual)
1180 .encode_values(&values, &mut key)
1181 .unwrap();
1182
1183 let dictionary_key = build_flat_test_pk_array(&[&key, &key]);
1185 let binary_key: ArrayRef = Arc::new(BinaryArray::from(vec![
1186 Some(key.as_slice()),
1187 None,
1188 Some(key.as_slice()),
1189 ]));
1190 for input in [dictionary_key, binary_key] {
1191 let result = compat.compat(&input).unwrap();
1192 assert_eq!(result.as_ref(), input.as_ref());
1193 }
1194 }
1195
1196 #[test]
1197 fn test_compat_primary_key_with_different_encoding_only() {
1198 let mut actual_metadata = new_metadata(
1199 &[
1200 (
1201 0,
1202 SemanticType::Timestamp,
1203 ConcreteDataType::timestamp_millisecond_datatype(),
1204 ),
1205 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1206 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1207 ],
1208 &[1],
1209 );
1210 actual_metadata = with_sparse_encoding(actual_metadata);
1211 actual_metadata.primary_key_encoding = PrimaryKeyEncoding::Dense;
1212 let actual_metadata = Arc::new(actual_metadata);
1213
1214 let mut expected_metadata = (*actual_metadata).clone();
1215 expected_metadata.primary_key_encoding = PrimaryKeyEncoding::Sparse;
1216 let expected_metadata = Arc::new(expected_metadata);
1217
1218 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1219 let read_format = FlatReadFormat::new(
1220 actual_metadata.clone(),
1221 ReadColumns::new([
1222 0,
1223 1,
1224 2,
1225 ReservedColumnId::table_id(),
1226 ReservedColumnId::tsid(),
1227 ]),
1228 None,
1229 "test",
1230 false,
1231 )
1232 .unwrap();
1233 let compat = FlatCompatBatch::try_new(&mapper, &read_format, false)
1234 .unwrap()
1235 .unwrap();
1236
1237 let mut dense_key = Vec::new();
1238 build_primary_key_codec(&actual_metadata)
1239 .encode_values(
1240 &[
1241 (ReservedColumnId::table_id(), Value::UInt32(42)),
1242 (ReservedColumnId::tsid(), Value::UInt64(7)),
1243 (1, Value::from("tag1")),
1244 ],
1245 &mut dense_key,
1246 )
1247 .unwrap();
1248 let sparse_key = encode_sparse_key(&[(1, Some("tag1"))]);
1249
1250 let dictionary_key = build_flat_test_pk_array(&[&dense_key, &dense_key]);
1251 let result = compat.compat_primary_key(&dictionary_key).unwrap();
1252 let result = result.as_any().downcast_ref::<PrimaryKeyArray>().unwrap();
1253 let values = result
1254 .values()
1255 .as_any()
1256 .downcast_ref::<BinaryArray>()
1257 .unwrap();
1258 assert_eq!(values.value(result.keys().value(0) as usize), sparse_key);
1259 assert_eq!(values.value(result.keys().value(1) as usize), sparse_key);
1260
1261 let binary_key: ArrayRef = Arc::new(BinaryArray::from(vec![
1262 Some(dense_key.as_slice()),
1263 Some(dense_key.as_slice()),
1264 ]));
1265 let result = compat.compat_primary_key(&binary_key).unwrap();
1266 let result = result.as_any().downcast_ref::<BinaryArray>().unwrap();
1267 assert_eq!(result.value(0), sparse_key);
1268 assert_eq!(result.value(1), sparse_key);
1269 }
1270
1271 #[test]
1274 fn test_flat_compat_batch_with_time_index_unit_change() {
1275 let actual_metadata = Arc::new(new_metadata(
1276 &[
1277 (
1278 0,
1279 SemanticType::Timestamp,
1280 ConcreteDataType::timestamp_millisecond_datatype(),
1281 ),
1282 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1283 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1284 ],
1285 &[1],
1286 ));
1287
1288 let mut expected_metadata = (*actual_metadata).clone();
1289 for column in expected_metadata.column_metadatas.iter_mut() {
1290 if column.semantic_type == SemanticType::Timestamp {
1291 column.column_schema.data_type = ConcreteDataType::timestamp_microsecond_datatype();
1292 }
1293 }
1294 let expected_metadata = Arc::new(
1296 RegionMetadataBuilder::from_existing(expected_metadata)
1297 .build()
1298 .unwrap(),
1299 );
1300
1301 let same_unit_metadata = Arc::new((*actual_metadata).clone());
1303 let mapper = FlatProjectionMapper::all(&same_unit_metadata).unwrap();
1304 let read_format = FlatReadFormat::new(
1305 actual_metadata.clone(),
1306 ReadColumns::new([0, 1, 2]),
1307 None,
1308 "test",
1309 false,
1310 )
1311 .unwrap();
1312 assert!(
1313 FlatCompatBatch::try_new(&mapper, &read_format, false)
1314 .unwrap()
1315 .is_none()
1316 );
1317
1318 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1320 let read_format = FlatReadFormat::new(
1321 actual_metadata.clone(),
1322 ReadColumns::new([0, 1, 2]),
1323 None,
1324 "test",
1325 false,
1326 )
1327 .unwrap();
1328 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
1329 .unwrap()
1330 .unwrap();
1331
1332 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
1333 tag_builder.append_value("tag1");
1334 tag_builder.append_value("tag1");
1335 let tag_dict_array = Arc::new(tag_builder.finish());
1336
1337 let k1 = encode_key(&[Some("tag1")]);
1338 let input_columns: Vec<ArrayRef> = vec![
1339 tag_dict_array.clone(),
1340 Arc::new(Int64Array::from(vec![100, 200])),
1341 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1342 build_flat_test_pk_array(&[&k1, &k1]),
1343 Arc::new(UInt64Array::from_iter_values([1, 2])),
1344 Arc::new(UInt8Array::from_iter_values([
1345 OpType::Put as u8,
1346 OpType::Put as u8,
1347 ])),
1348 ];
1349 let input_schema =
1350 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1351 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1352
1353 let result = compat_batch.compat(input_batch).unwrap();
1354
1355 let expected_columns: Vec<ArrayRef> = vec![
1356 tag_dict_array.clone(),
1357 Arc::new(Int64Array::from(vec![100, 200])),
1358 Arc::new(TimestampMicrosecondArray::from_iter_values([
1360 1_000_000, 2_000_000,
1361 ])),
1362 build_flat_test_pk_array(&[&k1, &k1]),
1363 Arc::new(UInt64Array::from_iter_values([1, 2])),
1364 Arc::new(UInt8Array::from_iter_values([
1365 OpType::Put as u8,
1366 OpType::Put as u8,
1367 ])),
1368 ];
1369 let expected_schema =
1370 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1371 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
1372
1373 assert_eq!(expected_batch, result);
1374 }
1375
1376 #[test]
1379 fn test_flat_compat_batch_time_index_unit_change_with_added_column() {
1380 let actual_metadata = Arc::new(new_metadata(
1381 &[
1382 (
1383 0,
1384 SemanticType::Timestamp,
1385 ConcreteDataType::timestamp_millisecond_datatype(),
1386 ),
1387 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1388 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1389 ],
1390 &[1],
1391 ));
1392
1393 let mut expected_metadata = new_metadata(
1394 &[
1395 (
1396 0,
1397 SemanticType::Timestamp,
1398 ConcreteDataType::timestamp_microsecond_datatype(),
1399 ),
1400 (1, SemanticType::Tag, ConcreteDataType::string_datatype()),
1401 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1402 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
1403 ],
1404 &[1],
1405 );
1406 expected_metadata.primary_key_encoding = PrimaryKeyEncoding::Dense;
1407 let expected_metadata = Arc::new(expected_metadata);
1408
1409 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1410 let read_format = FlatReadFormat::new(
1411 actual_metadata.clone(),
1412 ReadColumns::new([0, 1, 2, 3]),
1413 None,
1414 "test",
1415 false,
1416 )
1417 .unwrap();
1418
1419 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, false)
1420 .unwrap()
1421 .unwrap();
1422
1423 let mut tag_builder = StringDictionaryBuilder::<UInt32Type>::new();
1424 tag_builder.append_value("tag1");
1425 tag_builder.append_value("tag1");
1426 let tag_dict_array = Arc::new(tag_builder.finish());
1427
1428 let k1 = encode_key(&[Some("tag1")]);
1429 let input_columns: Vec<ArrayRef> = vec![
1430 tag_dict_array.clone(),
1431 Arc::new(Int64Array::from(vec![100, 200])),
1432 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1433 build_flat_test_pk_array(&[&k1, &k1]),
1434 Arc::new(UInt64Array::from_iter_values([1, 2])),
1435 Arc::new(UInt8Array::from_iter_values([
1436 OpType::Put as u8,
1437 OpType::Put as u8,
1438 ])),
1439 ];
1440 let input_schema =
1441 to_flat_sst_arrow_schema(&actual_metadata, &FlatSchemaOptions::default());
1442 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1443
1444 let result = compat_batch.compat(input_batch).unwrap();
1445
1446 let expected_columns: Vec<ArrayRef> = vec![
1447 tag_dict_array.clone(),
1448 Arc::new(Int64Array::from(vec![100, 200])),
1449 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
1450 Arc::new(TimestampMicrosecondArray::from_iter_values([
1451 1_000_000, 2_000_000,
1452 ])),
1453 build_flat_test_pk_array(&[&k1, &k1]),
1454 Arc::new(UInt64Array::from_iter_values([1, 2])),
1455 Arc::new(UInt8Array::from_iter_values([
1456 OpType::Put as u8,
1457 OpType::Put as u8,
1458 ])),
1459 ];
1460 let expected_schema =
1461 to_flat_sst_arrow_schema(&expected_metadata, &FlatSchemaOptions::default());
1462 let expected_batch = RecordBatch::try_new(expected_schema, expected_columns).unwrap();
1463
1464 assert_eq!(expected_batch, result);
1465 }
1466
1467 #[test]
1470 fn test_flat_compat_batch_compact_sparse_time_index_unit_change() {
1471 let mut actual_metadata = new_metadata(
1472 &[
1473 (
1474 0,
1475 SemanticType::Timestamp,
1476 ConcreteDataType::timestamp_millisecond_datatype(),
1477 ),
1478 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1479 ],
1480 &[],
1481 );
1482 actual_metadata = with_sparse_encoding(actual_metadata);
1483 let actual_metadata = Arc::new(actual_metadata);
1484
1485 let mut expected_metadata = (*actual_metadata).clone();
1486 for column in expected_metadata.column_metadatas.iter_mut() {
1487 if column.semantic_type == SemanticType::Timestamp {
1488 column.column_schema.data_type = ConcreteDataType::timestamp_microsecond_datatype();
1489 }
1490 }
1491 let expected_metadata = Arc::new(
1492 RegionMetadataBuilder::from_existing(expected_metadata)
1493 .build()
1494 .unwrap(),
1495 );
1496
1497 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1498 let read_format = FlatReadFormat::new(
1499 actual_metadata.clone(),
1500 ReadColumns::new([0, 2]),
1501 None,
1502 "test",
1503 true,
1504 )
1505 .unwrap();
1506
1507 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, true)
1508 .unwrap()
1509 .unwrap();
1510
1511 let mut sparse_k1 = Vec::new();
1512 SparsePrimaryKeyCodec::schemaless()
1513 .encode_internal(42, 7, &mut sparse_k1)
1514 .unwrap();
1515 let input_columns: Vec<ArrayRef> = vec![
1516 Arc::new(Int64Array::from(vec![100, 200])),
1517 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1518 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1519 Arc::new(UInt64Array::from_iter_values([1, 2])),
1520 Arc::new(UInt8Array::from_iter_values([
1521 OpType::Put as u8,
1522 OpType::Put as u8,
1523 ])),
1524 ];
1525 let input_schema = to_flat_sst_arrow_schema(
1526 &actual_metadata,
1527 &FlatSchemaOptions::from_encoding(PrimaryKeyEncoding::Sparse),
1528 );
1529 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1530
1531 let result = compat_batch.compat(input_batch).unwrap();
1532
1533 let expected_columns: Vec<ArrayRef> = vec![
1534 Arc::new(Int64Array::from(vec![100, 200])),
1535 Arc::new(TimestampMicrosecondArray::from_iter_values([
1536 1_000_000, 2_000_000,
1537 ])),
1538 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1539 Arc::new(UInt64Array::from_iter_values([1, 2])),
1540 Arc::new(UInt8Array::from_iter_values([
1541 OpType::Put as u8,
1542 OpType::Put as u8,
1543 ])),
1544 ];
1545 let output_schema = to_flat_sst_arrow_schema(
1546 &expected_metadata,
1547 &FlatSchemaOptions::from_encoding(PrimaryKeyEncoding::Sparse),
1548 );
1549 let expected_batch = RecordBatch::try_new(output_schema, expected_columns).unwrap();
1550
1551 assert_eq!(expected_batch, result);
1552 }
1553
1554 #[test]
1555 fn test_flat_compat_batch_compact_sparse() {
1556 let mut actual_metadata = new_metadata(
1557 &[
1558 (
1559 0,
1560 SemanticType::Timestamp,
1561 ConcreteDataType::timestamp_millisecond_datatype(),
1562 ),
1563 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1564 ],
1565 &[],
1566 );
1567 actual_metadata = with_sparse_encoding(actual_metadata);
1568 let actual_metadata = Arc::new(actual_metadata);
1569
1570 let mut expected_metadata = new_metadata(
1571 &[
1572 (
1573 0,
1574 SemanticType::Timestamp,
1575 ConcreteDataType::timestamp_millisecond_datatype(),
1576 ),
1577 (2, SemanticType::Field, ConcreteDataType::int64_datatype()),
1578 (3, SemanticType::Field, ConcreteDataType::int64_datatype()),
1579 ],
1580 &[],
1581 );
1582 expected_metadata = with_sparse_encoding(expected_metadata);
1583 let expected_metadata = Arc::new(expected_metadata);
1584
1585 let mapper = FlatProjectionMapper::all(&expected_metadata).unwrap();
1586 let read_format = FlatReadFormat::new(
1587 actual_metadata.clone(),
1588 ReadColumns::new([0, 2, 3]),
1589 None,
1590 "test",
1591 true,
1592 )
1593 .unwrap();
1594
1595 let compat_batch = FlatCompatBatch::try_new(&mapper, &read_format, true)
1596 .unwrap()
1597 .unwrap();
1598
1599 let sparse_k1 = encode_sparse_key(&[]);
1600 let input_columns: Vec<ArrayRef> = vec![
1601 Arc::new(Int64Array::from(vec![100, 200])),
1602 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1603 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1604 Arc::new(UInt64Array::from_iter_values([1, 2])),
1605 Arc::new(UInt8Array::from_iter_values([
1606 OpType::Put as u8,
1607 OpType::Put as u8,
1608 ])),
1609 ];
1610 let input_schema = to_flat_sst_arrow_schema(
1611 &actual_metadata,
1612 &FlatSchemaOptions::from_encoding(PrimaryKeyEncoding::Sparse),
1613 );
1614 let input_batch = RecordBatch::try_new(input_schema, input_columns).unwrap();
1615
1616 let result = compat_batch.compat(input_batch).unwrap();
1617
1618 let expected_columns: Vec<ArrayRef> = vec![
1619 Arc::new(Int64Array::from(vec![100, 200])),
1620 Arc::new(Int64Array::from(vec![None::<i64>, None::<i64>])),
1621 Arc::new(TimestampMillisecondArray::from_iter_values([1000, 2000])),
1622 build_flat_test_pk_array(&[&sparse_k1, &sparse_k1]),
1623 Arc::new(UInt64Array::from_iter_values([1, 2])),
1624 Arc::new(UInt8Array::from_iter_values([
1625 OpType::Put as u8,
1626 OpType::Put as u8,
1627 ])),
1628 ];
1629 let output_schema = to_flat_sst_arrow_schema(
1630 &expected_metadata,
1631 &FlatSchemaOptions::from_encoding(PrimaryKeyEncoding::Sparse),
1632 );
1633 let expected_batch = RecordBatch::try_new(output_schema, expected_columns).unwrap();
1634
1635 assert_eq!(expected_batch, result);
1636 }
1637 #[test]
1638 fn test_compaction_json2_uses_target_fields()
1639 -> std::result::Result<(), Box<dyn std::error::Error>> {
1640 let (metadata, batch) = test_util::sst_util::new_json2_record_batch()?;
1641 let logical_settings = JsonSettings::default();
1642 let layout = JsonSettings::try_new(vec![], Some(0))?;
1643 let targets: Json2RewriteTargets = Arc::new(BTreeMap::from([(
1644 0,
1645 Json2TargetLayout {
1646 extension_metadata: serde_json::to_string(&JsonMetadata::new(
1647 logical_settings.clone(),
1648 ))?,
1649 target_layout: layout.clone(),
1650 },
1651 )]));
1652 let json = JsonArray::from(batch.column(0)).rewrite_to_v2(
1654 batch.schema_ref().field(0),
1655 &logical_settings,
1656 &layout,
1657 )?;
1658 let mut fields = batch.schema_ref().fields().to_vec();
1659 fields[0] = Arc::new(
1660 fields[0]
1661 .as_ref()
1662 .clone()
1663 .with_data_type(json.data_type().clone()),
1664 );
1665 let mut columns = batch.columns().to_vec();
1666 columns[0] = json;
1667 let batch = RecordBatch::try_new(Arc::new(Schema::new(fields)), columns)?;
1668 for encoding in [PrimaryKeyEncoding::Dense, PrimaryKeyEncoding::Sparse] {
1669 let batch = if encoding == PrimaryKeyEncoding::Sparse {
1670 let mut key = Vec::new();
1671 SparsePrimaryKeyCodec::schemaless().encode_internal(42, 7, &mut key)?;
1672 let mut columns = batch.columns().to_vec();
1673 columns[primary_key_column_index(batch.num_columns())] =
1674 build_flat_test_pk_array(&[&key, &key]);
1675 RecordBatch::try_new(batch.schema(), columns)?
1676 } else {
1677 batch.clone()
1678 };
1679 for missing_json in [false, true] {
1680 let source = if missing_json {
1681 new_metadata(
1682 &[(
1683 1,
1684 SemanticType::Timestamp,
1685 ConcreteDataType::timestamp_millisecond_datatype(),
1686 )],
1687 &[],
1688 )
1689 } else {
1690 metadata.as_ref().clone()
1691 };
1692 let actual = Arc::new(if encoding == PrimaryKeyEncoding::Sparse {
1693 with_sparse_encoding(source)
1694 } else {
1695 source
1696 });
1697 let expected = if encoding == PrimaryKeyEncoding::Sparse {
1698 with_sparse_encoding(metadata.as_ref().clone())
1699 } else {
1700 metadata.as_ref().clone()
1701 };
1702 let mut builder = RegionMetadataBuilder::from_existing(expected);
1703 builder.push_column_metadata(ColumnMetadata {
1704 column_schema: ColumnSchema::new(
1705 "added",
1706 ConcreteDataType::int64_datatype(),
1707 true,
1708 )
1709 .with_default_constraint(Some(
1710 ColumnDefaultConstraint::Value(Value::Int64(42)),
1711 ))?,
1712 semantic_type: SemanticType::Field,
1713 column_id: 2,
1714 });
1715 let expected = Arc::new(builder.build()?);
1716 let read_columns = ReadColumns::new([0, 1, 2]);
1717 let mapper = FlatProjectionMapper::new_with_json2_rewrite_targets(
1718 &expected,
1719 vec![0, 1, expected.column_index_by_id(2).unwrap()],
1720 read_columns.clone(),
1721 &targets,
1722 )?;
1723 let read_format = FlatReadFormat::new(actual, read_columns, None, "test", true)?;
1724 let compat = FlatCompatBatch::try_new(&mapper, &read_format, true)?
1725 .ok_or("missing columns require compatibility")?;
1726 let input = if missing_json {
1727 batch.project(&[1, 2, 3, 4])?
1728 } else {
1729 batch.clone()
1730 };
1731 let output = compat.compat(input)?;
1732 assert_eq!(
1733 output.column(0).data_type(),
1734 &json2_physical_data_type(&layout)
1735 );
1736 assert_eq!(
1737 output.column(0).null_count(),
1738 if missing_json { 2 } else { 0 }
1739 );
1740 let defaults = output
1741 .column(1)
1742 .as_any()
1743 .downcast_ref::<Int64Array>()
1744 .ok_or("expected int64 defaults")?;
1745 assert_eq!(defaults.values().as_ref(), &[42, 42]);
1746 if !missing_json {
1747 let jsonb = JsonArray::from(output.column(0)).project_to_v2(
1748 output.schema_ref().field(0),
1749 &datatypes::arrow::datatypes::DataType::Binary,
1750 )?;
1751 let jsonb = jsonb
1752 .as_any()
1753 .downcast_ref::<BinaryArray>()
1754 .ok_or("expected JSONB")?;
1755 assert_eq!(jsonb.value(0), parse_string_to_jsonb(r#"{"a":1}"#)?);
1756 assert_eq!(jsonb.value(1), parse_string_to_jsonb(r#"{"a":2}"#)?);
1757 }
1758 }
1759 }
1760 Ok(())
1761 }
1762}