1use std::any::Any;
20use std::collections::{HashMap, HashSet};
21use std::sync::Arc;
22use std::{fmt, mem};
23
24use api::v1::SemanticType;
25use api::v1::column_def::try_as_column_schema;
26use api::v1::region::RegionColumnDef;
27use common_base::hash::partition_expr_version;
28use common_error::ext::ErrorExt;
29use common_error::status_code::StatusCode;
30use common_macro::stack_trace_debug;
31use datatypes::arrow;
32use datatypes::arrow::datatypes::FieldRef;
33use datatypes::extension::json::json2_metadata_with_updated_settings;
34use datatypes::schema::{ColumnSchema, FulltextOptions, Schema, SchemaRef};
35use datatypes::types::TimestampType;
36use itertools::Itertools;
37use serde::de::Error;
38use serde::{Deserialize, Deserializer, Serialize};
39use snafu::{Location, OptionExt, ResultExt, Snafu, ensure};
40
41use crate::codec::PrimaryKeyEncoding;
42use crate::region_request::{
43 AddColumn, AddColumnLocation, AlterKind, ModifyColumnType, SetIndexOption, UnsetIndexOption,
44};
45use crate::storage::consts::is_internal_column;
46use crate::storage::{ColumnId, RegionId};
47
48pub type Result<T> = std::result::Result<T, MetadataError>;
49
50#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
52pub struct ColumnMetadata {
53 pub column_schema: ColumnSchema,
55 pub semantic_type: SemanticType,
57 pub column_id: ColumnId,
59}
60
61impl fmt::Debug for ColumnMetadata {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 write!(
64 f,
65 "[{:?} {:?} {:?}]",
66 self.column_schema, self.semantic_type, self.column_id,
67 )
68 }
69}
70
71impl ColumnMetadata {
72 pub fn try_from_column_def(column_def: RegionColumnDef) -> Result<Self> {
74 let column_id = column_def.column_id;
75 let column_def = column_def
76 .column_def
77 .context(InvalidRawRegionRequestSnafu {
78 err: "column_def is absent",
79 })?;
80 let semantic_type = column_def.semantic_type();
81 let column_schema = try_as_column_schema(&column_def).context(ConvertColumnSchemaSnafu)?;
82
83 Ok(Self {
84 column_schema,
85 semantic_type,
86 column_id,
87 })
88 }
89
90 pub fn encode_list(columns: &[Self]) -> serde_json::Result<Vec<u8>> {
92 serde_json::to_vec(columns)
93 }
94
95 pub fn decode_list(bytes: &[u8]) -> serde_json::Result<Vec<Self>> {
97 serde_json::from_slice(bytes)
98 }
99
100 pub fn is_same_datatype(&self, other: &Self) -> bool {
101 self.column_schema.data_type == other.column_schema.data_type
102 }
103
104 pub fn estimated_size(&self) -> usize {
106 mem::size_of_val(self) - mem::size_of_val(&self.column_schema)
107 + self.column_schema.estimated_size()
108 }
109}
110
111#[cfg_attr(doc, aquamarine::aquamarine)]
112#[derive(Clone, PartialEq, Eq, Serialize)]
136pub struct RegionMetadata {
137 #[serde(skip)]
139 pub schema: SchemaRef,
140
141 #[serde(skip)]
145 time_index: ColumnId,
146 #[serde(skip)]
148 id_to_index: HashMap<ColumnId, usize>,
149
150 pub column_metadatas: Vec<ColumnMetadata>,
153 pub primary_key: Vec<ColumnId>,
155
156 pub region_id: RegionId,
158 pub schema_version: u64,
162
163 pub primary_key_encoding: PrimaryKeyEncoding,
165
166 pub partition_expr: Option<String>,
171 #[serde(skip)]
172 pub partition_expr_version: u64,
173}
174
175impl fmt::Debug for RegionMetadata {
176 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177 f.debug_struct("RegionMetadata")
178 .field("column_metadatas", &self.column_metadatas)
179 .field("time_index", &self.time_index)
180 .field("primary_key", &self.primary_key)
181 .field("region_id", &self.region_id)
182 .field("schema_version", &self.schema_version)
183 .field("partition_expr", &self.partition_expr)
184 .finish()
185 }
186}
187
188pub type RegionMetadataRef = Arc<RegionMetadata>;
189
190impl<'de> Deserialize<'de> for RegionMetadata {
191 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
192 where
193 D: Deserializer<'de>,
194 {
195 #[derive(Deserialize)]
197 struct RegionMetadataWithoutSchema {
198 column_metadatas: Vec<ColumnMetadata>,
199 primary_key: Vec<ColumnId>,
200 region_id: RegionId,
201 schema_version: u64,
202 #[serde(default)]
203 primary_key_encoding: PrimaryKeyEncoding,
204 #[serde(default)]
205 partition_expr: Option<String>,
206 }
207
208 let without_schema = RegionMetadataWithoutSchema::deserialize(deserializer)?;
209 let skipped =
210 SkippedFields::new(&without_schema.column_metadatas).map_err(D::Error::custom)?;
211
212 let partition_expr_version =
213 partition_expr_version(without_schema.partition_expr.as_deref());
214
215 Ok(Self {
216 schema: skipped.schema,
217 time_index: skipped.time_index,
218 id_to_index: skipped.id_to_index,
219 column_metadatas: without_schema.column_metadatas,
220 primary_key: without_schema.primary_key,
221 region_id: without_schema.region_id,
222 schema_version: without_schema.schema_version,
223 primary_key_encoding: without_schema.primary_key_encoding,
224 partition_expr: without_schema.partition_expr,
225 partition_expr_version,
226 })
227 }
228}
229
230impl RegionMetadata {
231 pub fn from_json(s: &str) -> Result<Self> {
233 serde_json::from_str(s).context(SerdeJsonSnafu)
234 }
235
236 pub fn estimated_size(&self) -> usize {
238 mem::size_of_val(self)
239 + mem::size_of::<ColumnMetadata>() * self.column_metadatas.capacity()
240 + self
241 .column_metadatas
242 .iter()
243 .map(|column| column.estimated_size() - mem::size_of::<ColumnMetadata>())
244 .sum::<usize>()
245 + mem::size_of::<ColumnId>() * self.primary_key.capacity()
246 + mem::size_of::<(ColumnId, usize)>() * self.id_to_index.capacity()
247 + self.schema.estimated_size()
248 + self
249 .partition_expr
250 .as_ref()
251 .map(|expr| expr.capacity())
252 .unwrap_or_default()
253 }
254
255 pub fn to_json(&self) -> Result<String> {
257 serde_json::to_string(&self).context(SerdeJsonSnafu)
258 }
259
260 pub fn set_partition_expr(&mut self, expr: Option<String>) {
261 self.partition_expr_version = partition_expr_version(expr.as_deref());
262 self.partition_expr = expr;
263 }
264
265 pub fn column_by_id(&self, column_id: ColumnId) -> Option<&ColumnMetadata> {
267 self.id_to_index
268 .get(&column_id)
269 .map(|index| &self.column_metadatas[*index])
270 }
271
272 pub fn column_index_by_id(&self, column_id: ColumnId) -> Option<usize> {
274 self.id_to_index.get(&column_id).copied()
275 }
276
277 pub fn column_index_by_name(&self, column_name: &str) -> Option<usize> {
279 self.column_metadatas
280 .iter()
281 .position(|col| col.column_schema.name == column_name)
282 }
283
284 pub fn time_index_column(&self) -> &ColumnMetadata {
289 let index = self.id_to_index[&self.time_index];
290 &self.column_metadatas[index]
291 }
292
293 pub fn time_index_type(&self) -> TimestampType {
298 let index = self.id_to_index[&self.time_index];
299 self.column_metadatas[index]
300 .column_schema
301 .data_type
302 .as_timestamp()
303 .unwrap()
304 }
305
306 pub fn time_index_column_pos(&self) -> usize {
308 self.id_to_index[&self.time_index]
309 }
310
311 pub fn time_index_field(&self) -> FieldRef {
313 let index = self.id_to_index[&self.time_index];
314 self.schema.arrow_schema().fields[index].clone()
315 }
316
317 pub fn column_by_name(&self, name: &str) -> Option<&ColumnMetadata> {
319 self.schema
320 .column_index_by_name(name)
321 .map(|index| &self.column_metadatas[index])
322 }
323
324 pub fn primary_key_columns(&self) -> impl Iterator<Item = &ColumnMetadata> {
326 self.primary_key
328 .iter()
329 .map(|id| self.column_by_id(*id).unwrap())
330 }
331
332 pub fn field_columns(&self) -> impl Iterator<Item = &ColumnMetadata> {
337 self.column_metadatas
338 .iter()
339 .filter(|column| column.semantic_type == SemanticType::Field)
340 }
341
342 pub fn primary_key_index(&self, column_id: ColumnId) -> Option<usize> {
346 self.primary_key.iter().position(|id| *id == column_id)
347 }
348
349 pub fn project(&self, projection: &[ColumnId]) -> Result<RegionMetadata> {
353 ensure!(
355 projection.contains(&self.time_index),
356 TimeIndexNotFoundSnafu
357 );
358
359 let indices_to_preserve = projection
361 .iter()
362 .map(|id| {
363 self.column_index_by_id(*id)
364 .with_context(|| InvalidRegionRequestSnafu {
365 region_id: self.region_id,
366 err: format!("column id {} not found", id),
367 })
368 })
369 .collect::<Result<Vec<_>>>()?;
370
371 let projected_schema =
373 self.schema
374 .try_project(&indices_to_preserve)
375 .with_context(|_| SchemaProjectSnafu {
376 origin_schema: self.schema.clone(),
377 projection: projection.to_vec(),
378 })?;
379
380 let mut projected_column_metadatas = Vec::with_capacity(indices_to_preserve.len());
382 let mut projected_primary_key = vec![];
383 let mut projected_id_to_index = HashMap::with_capacity(indices_to_preserve.len());
384 for index in indices_to_preserve {
385 let col = self.column_metadatas[index].clone();
386 if col.semantic_type == SemanticType::Tag {
387 projected_primary_key.push(col.column_id);
388 }
389 projected_id_to_index.insert(col.column_id, projected_column_metadatas.len());
390 projected_column_metadatas.push(col);
391 }
392
393 Ok(RegionMetadata {
394 schema: Arc::new(projected_schema),
395 time_index: self.time_index,
396 id_to_index: projected_id_to_index,
397 column_metadatas: projected_column_metadatas,
398 primary_key: projected_primary_key,
399 region_id: self.region_id,
400 schema_version: self.schema_version,
401 primary_key_encoding: self.primary_key_encoding,
402 partition_expr: self.partition_expr.clone(),
403 partition_expr_version: partition_expr_version(self.partition_expr.as_deref()),
404 })
405 }
406
407 pub fn inverted_indexed_column_ids<'a>(
409 &self,
410 ignore_column_ids: impl Iterator<Item = &'a ColumnId>,
411 ) -> HashSet<ColumnId> {
412 let mut inverted_index = self
413 .column_metadatas
414 .iter()
415 .filter(|column| column.column_schema.is_inverted_indexed())
416 .map(|column| column.column_id)
417 .collect::<HashSet<_>>();
418
419 for ignored in ignore_column_ids {
420 inverted_index.remove(ignored);
421 }
422
423 inverted_index
424 }
425
426 fn validate(&self) -> Result<()> {
428 let mut id_names = HashMap::with_capacity(self.column_metadatas.len());
430 for col in &self.column_metadatas {
431 Self::validate_column_metadata(col)?;
433
434 ensure!(
437 !id_names.contains_key(&col.column_id),
438 InvalidMetaSnafu {
439 reason: format!(
440 "column {} and {} have the same column id {}",
441 id_names[&col.column_id], col.column_schema.name, col.column_id,
442 ),
443 }
444 );
445 id_names.insert(col.column_id, &col.column_schema.name);
446 }
447
448 let time_indexes = self
450 .column_metadatas
451 .iter()
452 .filter(|col| col.semantic_type == SemanticType::Timestamp)
453 .collect::<Vec<_>>();
454 ensure!(
455 time_indexes.len() == 1,
456 InvalidMetaSnafu {
457 reason: format!(
458 "expect only one time index, found {}: {}",
459 time_indexes.len(),
460 time_indexes
461 .iter()
462 .map(|c| &c.column_schema.name)
463 .join(", ")
464 ),
465 }
466 );
467
468 ensure!(
470 !self.time_index_column().column_schema.is_nullable(),
471 InvalidMetaSnafu {
472 reason: format!(
473 "time index column {} must be NOT NULL",
474 self.time_index_column().column_schema.name
475 ),
476 }
477 );
478
479 if !self.primary_key.is_empty() {
480 let mut pk_ids = HashSet::with_capacity(self.primary_key.len());
481 for column_id in &self.primary_key {
483 ensure!(
485 id_names.contains_key(column_id),
486 InvalidMetaSnafu {
487 reason: format!("unknown column id {}", column_id),
488 }
489 );
490
491 let column = self.column_by_id(*column_id).unwrap();
493 ensure!(
495 !pk_ids.contains(&column_id),
496 InvalidMetaSnafu {
497 reason: format!(
498 "duplicate column {} in primary key",
499 column.column_schema.name
500 ),
501 }
502 );
503
504 ensure!(
506 *column_id != self.time_index,
507 InvalidMetaSnafu {
508 reason: format!(
509 "column {} is already a time index column",
510 column.column_schema.name,
511 ),
512 }
513 );
514
515 ensure!(
517 column.semantic_type == SemanticType::Tag,
518 InvalidMetaSnafu {
519 reason: format!(
520 "semantic type of column {} should be Tag, not {:?}",
521 column.column_schema.name, column.semantic_type
522 ),
523 }
524 );
525
526 pk_ids.insert(column_id);
527 }
528 }
529
530 let num_tag = self
532 .column_metadatas
533 .iter()
534 .filter(|col| col.semantic_type == SemanticType::Tag)
535 .count();
536 ensure!(
537 num_tag == self.primary_key.len(),
538 InvalidMetaSnafu {
539 reason: format!(
540 "number of primary key columns {} not equal to tag columns {}",
541 self.primary_key.len(),
542 num_tag
543 ),
544 }
545 );
546
547 Ok(())
548 }
549
550 fn validate_column_metadata(column_metadata: &ColumnMetadata) -> Result<()> {
552 column_metadata
553 .column_schema
554 .compression_options()
555 .context(InvalidSchemaSnafu)?;
556 if column_metadata.semantic_type == SemanticType::Timestamp {
557 ensure!(
558 column_metadata.column_schema.data_type.is_timestamp(),
559 InvalidMetaSnafu {
560 reason: format!(
561 "column `{}` is not timestamp type",
562 column_metadata.column_schema.name
563 ),
564 }
565 );
566 }
567
568 ensure!(
569 !is_internal_column(&column_metadata.column_schema.name),
570 InvalidMetaSnafu {
571 reason: format!(
572 "{} is internal column name that can not be used",
573 column_metadata.column_schema.name
574 ),
575 }
576 );
577
578 Ok(())
579 }
580}
581
582pub struct RegionMetadataBuilder {
584 region_id: RegionId,
585 column_metadatas: Vec<ColumnMetadata>,
586 primary_key: Vec<ColumnId>,
587 schema_version: u64,
588 primary_key_encoding: PrimaryKeyEncoding,
589 partition_expr: Option<String>,
590}
591
592impl RegionMetadataBuilder {
593 pub fn new(id: RegionId) -> Self {
595 Self {
596 region_id: id,
597 column_metadatas: vec![],
598 primary_key: vec![],
599 schema_version: 0,
600 primary_key_encoding: PrimaryKeyEncoding::Dense,
601 partition_expr: None,
602 }
603 }
604
605 pub fn from_existing(existing: RegionMetadata) -> Self {
607 Self {
608 column_metadatas: existing.column_metadatas,
609 primary_key: existing.primary_key,
610 region_id: existing.region_id,
611 schema_version: existing.schema_version,
612 primary_key_encoding: existing.primary_key_encoding,
613 partition_expr: existing.partition_expr,
614 }
615 }
616
617 pub fn primary_key_encoding(&mut self, encoding: PrimaryKeyEncoding) -> &mut Self {
619 self.primary_key_encoding = encoding;
620 self
621 }
622
623 pub fn partition_expr_json(&mut self, expr_json: Option<String>) -> &mut Self {
625 self.partition_expr = expr_json;
626 self
627 }
628
629 pub fn push_column_metadata(&mut self, column_metadata: ColumnMetadata) -> &mut Self {
631 self.column_metadatas.push(column_metadata);
632 self
633 }
634
635 pub fn primary_key(&mut self, key: Vec<ColumnId>) -> &mut Self {
637 self.primary_key = key;
638 self
639 }
640
641 pub fn bump_version(&mut self) -> &mut Self {
643 self.schema_version += 1;
644 self
645 }
646
647 pub fn alter(&mut self, kind: AlterKind) -> Result<&mut Self> {
651 match kind {
652 AlterKind::AddColumns { columns } => self.add_columns(columns)?,
653 AlterKind::DropColumns { names } => self.drop_columns(&names),
654 AlterKind::ModifyColumnTypes { columns } => self.modify_column_types(columns)?,
655 AlterKind::SetJsonSettings {
656 column_name,
657 settings,
658 } => self.set_json_settings(column_name, settings)?,
659 AlterKind::SetIndexes { options } => self.set_indexes(options)?,
660 AlterKind::UnsetIndexes { options } => self.unset_indexes(options)?,
661 AlterKind::SetRegionOptions { options: _ } => {
662 }
664 AlterKind::UnsetRegionOptions { keys: _ } => {
665 }
667 AlterKind::DropDefaults { names } => {
668 self.drop_defaults(names)?;
669 }
670 AlterKind::SetDefaults { columns } => self.set_defaults(&columns)?,
671 AlterKind::SyncColumns { column_metadatas } => {
672 self.primary_key = column_metadatas
673 .iter()
674 .filter_map(|column_metadata| {
675 if column_metadata.semantic_type == SemanticType::Tag {
676 Some(column_metadata.column_id)
677 } else {
678 None
679 }
680 })
681 .collect::<Vec<_>>();
682 self.column_metadatas = column_metadatas;
683 }
684 }
685 Ok(self)
686 }
687
688 pub fn build(self) -> Result<RegionMetadata> {
690 self.build_with_options(true)
691 }
692
693 pub fn build_without_validation(self) -> Result<RegionMetadata> {
698 self.build_with_options(false)
699 }
700
701 fn build_with_options(self, validate: bool) -> Result<RegionMetadata> {
702 let skipped = SkippedFields::new(&self.column_metadatas)?;
703
704 let partition_expr_version = partition_expr_version(self.partition_expr.as_deref());
705 let meta = RegionMetadata {
706 schema: skipped.schema,
707 time_index: skipped.time_index,
708 id_to_index: skipped.id_to_index,
709 column_metadatas: self.column_metadatas,
710 primary_key: self.primary_key,
711 region_id: self.region_id,
712 schema_version: self.schema_version,
713 primary_key_encoding: self.primary_key_encoding,
714 partition_expr: self.partition_expr,
715 partition_expr_version,
716 };
717
718 if validate {
719 meta.validate()?;
720 }
721
722 Ok(meta)
723 }
724
725 fn add_columns(&mut self, columns: Vec<AddColumn>) -> Result<()> {
727 let mut names: HashSet<_> = self
728 .column_metadatas
729 .iter()
730 .map(|col| col.column_schema.name.clone())
731 .collect();
732
733 for add_column in columns {
734 if names.contains(&add_column.column_metadata.column_schema.name) {
735 continue;
737 }
738
739 let column_id = add_column.column_metadata.column_id;
740 let semantic_type = add_column.column_metadata.semantic_type;
741 let column_name = add_column.column_metadata.column_schema.name.clone();
742 match add_column.location {
743 None => {
744 self.column_metadatas.push(add_column.column_metadata);
745 }
746 Some(AddColumnLocation::First) => {
747 self.column_metadatas.insert(0, add_column.column_metadata);
748 }
749 Some(AddColumnLocation::After { column_name }) => {
750 let pos = self
751 .column_metadatas
752 .iter()
753 .position(|col| col.column_schema.name == column_name)
754 .context(InvalidRegionRequestSnafu {
755 region_id: self.region_id,
756 err: format!(
757 "column {} not found, failed to add column {} after it",
758 column_name, add_column.column_metadata.column_schema.name
759 ),
760 })?;
761 self.column_metadatas
763 .insert(pos + 1, add_column.column_metadata);
764 }
765 }
766 names.insert(column_name);
767 if semantic_type == SemanticType::Tag {
768 self.primary_key.push(column_id);
770 }
771 }
772
773 Ok(())
774 }
775
776 fn drop_columns(&mut self, names: &[String]) {
778 let name_set: HashSet<_> = names.iter().collect();
779 self.column_metadatas
780 .retain(|col| !name_set.contains(&col.column_schema.name));
781 }
782
783 fn modify_column_types(&mut self, columns: Vec<ModifyColumnType>) -> Result<()> {
785 let mut change_type_map: HashMap<_, _> = columns
786 .into_iter()
787 .map(
788 |ModifyColumnType {
789 column_name,
790 target_type,
791 }| (column_name, target_type),
792 )
793 .collect();
794
795 for column_meta in self.column_metadatas.iter_mut() {
796 if let Some(target_type) = change_type_map.remove(&column_meta.column_schema.name) {
797 column_meta.column_schema.data_type = target_type.clone();
798 let new_default =
800 if let Some(default_value) = column_meta.column_schema.default_constraint() {
801 Some(
802 default_value
803 .cast_to_datatype(&target_type)
804 .with_context(|_| CastDefaultValueSnafu {
805 reason: format!(
806 "Failed to cast default value from {:?} to type {:?}",
807 default_value, target_type
808 ),
809 })?,
810 )
811 } else {
812 None
813 };
814 column_meta.column_schema = column_meta
815 .column_schema
816 .clone()
817 .with_default_constraint(new_default.clone())
818 .with_context(|_| CastDefaultValueSnafu {
819 reason: format!("Failed to set new default: {:?}", new_default),
820 })?;
821 }
822 }
823
824 Ok(())
825 }
826
827 fn set_json_settings(
828 &mut self,
829 col_name: String,
830 settings: datatypes::json::JsonSettings,
831 ) -> Result<()> {
832 let Some(col_meta) = self
833 .column_metadatas
834 .iter_mut()
835 .find(|col| col.column_schema.name == col_name)
836 else {
837 return InvalidRegionRequestSnafu {
838 region_id: self.region_id,
839 err: format!("column {col_name} not found"),
840 }
841 .fail();
842 };
843
844 let old_metadata = col_meta.column_schema.metadata();
845 let new_metadata =
846 json2_metadata_with_updated_settings(old_metadata, settings).map_err(|err| {
847 InvalidRegionRequestSnafu {
848 region_id: self.region_id,
849 err: err.to_string(),
850 }
851 .build()
852 })?;
853
854 *col_meta.column_schema.mut_metadata() = new_metadata;
855 Ok(())
856 }
857
858 fn set_indexes(&mut self, options: Vec<SetIndexOption>) -> Result<()> {
859 let mut set_index_map: HashMap<_, Vec<_>> = HashMap::new();
860 for option in &options {
861 set_index_map
862 .entry(option.column_name())
863 .or_default()
864 .push(option);
865 }
866
867 for column_metadata in self.column_metadatas.iter_mut() {
868 if let Some(options) = set_index_map.remove(&column_metadata.column_schema.name) {
869 for option in options {
870 Self::set_index(column_metadata, option)?;
871 }
872 }
873 }
874
875 Ok(())
876 }
877
878 fn unset_indexes(&mut self, options: Vec<UnsetIndexOption>) -> Result<()> {
879 let mut unset_index_map: HashMap<_, Vec<_>> = HashMap::new();
880 for option in &options {
881 unset_index_map
882 .entry(option.column_name())
883 .or_default()
884 .push(option);
885 }
886
887 for column_metadata in self.column_metadatas.iter_mut() {
888 if let Some(options) = unset_index_map.remove(&column_metadata.column_schema.name) {
889 for option in options {
890 Self::unset_index(column_metadata, option)?;
891 }
892 }
893 }
894
895 Ok(())
896 }
897
898 fn set_index(column_metadata: &mut ColumnMetadata, options: &SetIndexOption) -> Result<()> {
899 match options {
900 SetIndexOption::Fulltext {
901 column_name,
902 options,
903 } => {
904 ensure!(
905 column_metadata.column_schema.data_type.is_string(),
906 InvalidColumnOptionSnafu {
907 column_name,
908 msg: "FULLTEXT index only supports string type".to_string(),
909 }
910 );
911 let current_fulltext_options = column_metadata
912 .column_schema
913 .fulltext_options()
914 .with_context(|_| GetFulltextOptionsSnafu {
915 column_name: column_name.clone(),
916 })?;
917 set_column_fulltext_options(
918 column_metadata,
919 column_name,
920 options,
921 current_fulltext_options,
922 )?;
923 }
924 SetIndexOption::Inverted { .. } => {
925 column_metadata.column_schema.set_inverted_index(true)
926 }
927 SetIndexOption::Skipping {
928 column_name,
929 options,
930 } => {
931 column_metadata
932 .column_schema
933 .set_skipping_options(options)
934 .context(UnsetSkippingIndexOptionsSnafu { column_name })?;
935 }
936 }
937
938 Ok(())
939 }
940
941 fn unset_index(column_metadata: &mut ColumnMetadata, options: &UnsetIndexOption) -> Result<()> {
942 match options {
943 UnsetIndexOption::Fulltext { column_name } => {
944 ensure!(
945 column_metadata.column_schema.data_type.is_string(),
946 InvalidColumnOptionSnafu {
947 column_name,
948 msg: "FULLTEXT index only supports string type".to_string(),
949 }
950 );
951
952 let current_fulltext_options = column_metadata
953 .column_schema
954 .fulltext_options()
955 .with_context(|_| GetFulltextOptionsSnafu {
956 column_name: column_name.clone(),
957 })?;
958
959 unset_column_fulltext_options(
960 column_metadata,
961 column_name,
962 current_fulltext_options,
963 )?;
964 }
965 UnsetIndexOption::Inverted { .. } => {
966 column_metadata.column_schema.set_inverted_index(false)
967 }
968 UnsetIndexOption::Skipping { column_name } => {
969 column_metadata
970 .column_schema
971 .unset_skipping_options()
972 .context(UnsetSkippingIndexOptionsSnafu { column_name })?;
973 }
974 }
975
976 Ok(())
977 }
978
979 fn drop_defaults(&mut self, column_names: Vec<String>) -> Result<()> {
980 for name in column_names.iter() {
981 let meta = self
982 .column_metadatas
983 .iter_mut()
984 .find(|col| col.column_schema.name == *name);
985 if let Some(meta) = meta {
986 if !meta.column_schema.is_nullable() {
987 return InvalidRegionRequestSnafu {
988 region_id: self.region_id,
989 err: format!(
990 "column {name} is not nullable and `default` cannot be dropped",
991 ),
992 }
993 .fail();
994 }
995 meta.column_schema = meta
996 .column_schema
997 .clone()
998 .with_default_constraint(None)
999 .with_context(|_| CastDefaultValueSnafu {
1000 reason: format!("Failed to drop default : {name:?}"),
1001 })?;
1002 } else {
1003 return InvalidRegionRequestSnafu {
1004 region_id: self.region_id,
1005 err: format!("column {name} not found",),
1006 }
1007 .fail();
1008 }
1009 }
1010 Ok(())
1011 }
1012
1013 fn set_defaults(&mut self, set_defaults: &[crate::region_request::SetDefault]) -> Result<()> {
1014 for set_default in set_defaults.iter() {
1015 let meta = self
1016 .column_metadatas
1017 .iter_mut()
1018 .find(|col| col.column_schema.name == set_default.name);
1019 if let Some(meta) = meta {
1020 let default_constraint = common_sql::convert::deserialize_default_constraint(
1021 set_default.default_constraint.as_slice(),
1022 &meta.column_schema.name,
1023 &meta.column_schema.data_type,
1024 )
1025 .context(SqlCommonSnafu)?;
1026
1027 meta.column_schema = meta
1028 .column_schema
1029 .clone()
1030 .with_default_constraint(default_constraint)
1031 .with_context(|_| CastDefaultValueSnafu {
1032 reason: format!("Failed to set default : {set_default:?}"),
1033 })?;
1034 } else {
1035 return InvalidRegionRequestSnafu {
1036 region_id: self.region_id,
1037 err: format!("column {} not found", set_default.name),
1038 }
1039 .fail();
1040 }
1041 }
1042 Ok(())
1043 }
1044}
1045
1046struct SkippedFields {
1048 schema: SchemaRef,
1050 time_index: ColumnId,
1052 id_to_index: HashMap<ColumnId, usize>,
1054}
1055
1056impl SkippedFields {
1057 fn new(column_metadatas: &[ColumnMetadata]) -> Result<SkippedFields> {
1059 let column_schemas = column_metadatas
1060 .iter()
1061 .map(|column_metadata| column_metadata.column_schema.clone())
1062 .collect();
1063 let schema = Arc::new(Schema::try_new(column_schemas).context(InvalidSchemaSnafu)?);
1064 let time_index = column_metadatas
1065 .iter()
1066 .find_map(|col| {
1067 if col.semantic_type == SemanticType::Timestamp {
1068 Some(col.column_id)
1069 } else {
1070 None
1071 }
1072 })
1073 .context(InvalidMetaSnafu {
1074 reason: "time index not found",
1075 })?;
1076 let id_to_index = column_metadatas
1077 .iter()
1078 .enumerate()
1079 .map(|(idx, col)| (col.column_id, idx))
1080 .collect();
1081
1082 Ok(SkippedFields {
1083 schema,
1084 time_index,
1085 id_to_index,
1086 })
1087 }
1088}
1089
1090#[derive(Snafu)]
1091#[snafu(visibility(pub))]
1092#[stack_trace_debug]
1093pub enum MetadataError {
1094 #[snafu(display("Invalid schema"))]
1095 InvalidSchema {
1096 source: datatypes::error::Error,
1097 #[snafu(implicit)]
1098 location: Location,
1099 },
1100
1101 #[snafu(display("Invalid metadata, {}", reason))]
1102 InvalidMeta {
1103 reason: String,
1104 #[snafu(implicit)]
1105 location: Location,
1106 },
1107
1108 #[snafu(display("Failed to ser/de json object"))]
1109 SerdeJson {
1110 #[snafu(implicit)]
1111 location: Location,
1112 #[snafu(source)]
1113 error: serde_json::Error,
1114 },
1115
1116 #[snafu(display("Invalid raw region request, err: {}", err))]
1117 InvalidRawRegionRequest {
1118 err: String,
1119 #[snafu(implicit)]
1120 location: Location,
1121 },
1122
1123 #[snafu(display("Invalid region request, region_id: {}, err: {}", region_id, err))]
1124 InvalidRegionRequest {
1125 region_id: RegionId,
1126 err: String,
1127 #[snafu(implicit)]
1128 location: Location,
1129 },
1130
1131 #[snafu(display("Unexpected schema error during project"))]
1132 SchemaProject {
1133 origin_schema: SchemaRef,
1134 projection: Vec<ColumnId>,
1135 #[snafu(implicit)]
1136 location: Location,
1137 source: datatypes::Error,
1138 },
1139
1140 #[snafu(display("Time index column not found"))]
1141 TimeIndexNotFound {
1142 #[snafu(implicit)]
1143 location: Location,
1144 },
1145
1146 #[snafu(display("Change column {} not exists in region: {}", column_name, region_id))]
1147 ChangeColumnNotFound {
1148 column_name: String,
1149 region_id: RegionId,
1150 #[snafu(implicit)]
1151 location: Location,
1152 },
1153
1154 #[snafu(display("Failed to convert column schema"))]
1155 ConvertColumnSchema {
1156 source: api::error::Error,
1157 #[snafu(implicit)]
1158 location: Location,
1159 },
1160
1161 #[snafu(display("Failed to convert TimeRanges"))]
1162 ConvertTimeRanges {
1163 source: api::error::Error,
1164 #[snafu(implicit)]
1165 location: Location,
1166 },
1167
1168 #[snafu(display("Invalid set region option request, key: {}, value: {}", key, value))]
1169 InvalidSetRegionOptionRequest {
1170 key: String,
1171 value: String,
1172 #[snafu(implicit)]
1173 location: Location,
1174 },
1175
1176 #[snafu(display("Invalid set region option request, key: {}", key))]
1177 InvalidUnsetRegionOptionRequest {
1178 key: String,
1179 #[snafu(implicit)]
1180 location: Location,
1181 },
1182
1183 #[snafu(display("Failed to decode protobuf"))]
1184 DecodeProto {
1185 #[snafu(source)]
1186 error: prost::UnknownEnumValue,
1187 #[snafu(implicit)]
1188 location: Location,
1189 },
1190
1191 #[snafu(display("Invalid column option, column name: {}, error: {}", column_name, msg))]
1192 InvalidColumnOption {
1193 column_name: String,
1194 msg: String,
1195 #[snafu(implicit)]
1196 location: Location,
1197 },
1198
1199 #[snafu(display("Failed to set fulltext options for column {}", column_name))]
1200 SetFulltextOptions {
1201 column_name: String,
1202 source: datatypes::Error,
1203 #[snafu(implicit)]
1204 location: Location,
1205 },
1206
1207 #[snafu(display("Failed to get fulltext options for column {}", column_name))]
1208 GetFulltextOptions {
1209 column_name: String,
1210 source: datatypes::Error,
1211 #[snafu(implicit)]
1212 location: Location,
1213 },
1214
1215 #[snafu(display("Failed to set skipping index options for column {}", column_name))]
1216 SetSkippingIndexOptions {
1217 column_name: String,
1218 source: datatypes::Error,
1219 #[snafu(implicit)]
1220 location: Location,
1221 },
1222
1223 #[snafu(display("Failed to unset skipping index options for column {}", column_name))]
1224 UnsetSkippingIndexOptions {
1225 column_name: String,
1226 source: datatypes::Error,
1227 #[snafu(implicit)]
1228 location: Location,
1229 },
1230
1231 #[snafu(display("Failed to decode arrow ipc record batches"))]
1232 DecodeArrowIpc {
1233 #[snafu(source)]
1234 error: arrow::error::ArrowError,
1235 #[snafu(implicit)]
1236 location: Location,
1237 },
1238
1239 #[snafu(display("Failed to cast default value, reason: {}", reason))]
1240 CastDefaultValue {
1241 reason: String,
1242 source: datatypes::Error,
1243 #[snafu(implicit)]
1244 location: Location,
1245 },
1246
1247 #[snafu(display("Unexpected: {}", reason))]
1248 Unexpected {
1249 reason: String,
1250 #[snafu(implicit)]
1251 location: Location,
1252 },
1253
1254 #[snafu(display("Failed to encode/decode flight message"))]
1255 FlightCodec {
1256 source: common_grpc::Error,
1257 #[snafu(implicit)]
1258 location: Location,
1259 },
1260
1261 #[snafu(display("Invalid index option"))]
1262 InvalidIndexOption {
1263 #[snafu(implicit)]
1264 location: Location,
1265 #[snafu(source)]
1266 error: datatypes::error::Error,
1267 },
1268
1269 #[snafu(display("Sql common error"))]
1270 SqlCommon {
1271 source: common_sql::error::Error,
1272 #[snafu(implicit)]
1273 location: Location,
1274 },
1275}
1276
1277impl ErrorExt for MetadataError {
1278 fn status_code(&self) -> StatusCode {
1279 match self {
1280 Self::SqlCommon { source, .. } => source.status_code(),
1281 _ => StatusCode::InvalidArguments,
1282 }
1283 }
1284
1285 fn as_any(&self) -> &dyn Any {
1286 self
1287 }
1288}
1289
1290fn set_column_fulltext_options(
1299 column_meta: &mut ColumnMetadata,
1300 column_name: &str,
1301 options: &FulltextOptions,
1302 current_options: Option<FulltextOptions>,
1303) -> Result<()> {
1304 if let Some(current_options) = current_options {
1305 ensure!(
1306 current_options.analyzer == options.analyzer
1307 && current_options.case_sensitive == options.case_sensitive,
1308 InvalidColumnOptionSnafu {
1309 column_name,
1310 msg: format!(
1311 "Cannot change analyzer or case_sensitive if FULLTEXT index is set before. Previous analyzer: {}, previous case_sensitive: {}",
1312 current_options.analyzer, current_options.case_sensitive
1313 ),
1314 }
1315 );
1316 }
1317
1318 column_meta
1319 .column_schema
1320 .set_fulltext_options(options)
1321 .context(SetFulltextOptionsSnafu { column_name })?;
1322
1323 Ok(())
1324}
1325
1326fn unset_column_fulltext_options(
1327 column_meta: &mut ColumnMetadata,
1328 column_name: &str,
1329 current_options: Option<FulltextOptions>,
1330) -> Result<()> {
1331 if let Some(mut current_options) = current_options
1332 && current_options.enable
1333 {
1334 current_options.enable = false;
1335 column_meta
1336 .column_schema
1337 .set_fulltext_options(¤t_options)
1338 .context(SetFulltextOptionsSnafu { column_name })?;
1339 } else {
1340 return InvalidColumnOptionSnafu {
1341 column_name,
1342 msg: "FULLTEXT index already disabled",
1343 }
1344 .fail();
1345 }
1346
1347 Ok(())
1348}
1349
1350#[cfg(test)]
1351mod test {
1352 use datatypes::prelude::ConcreteDataType;
1353 use datatypes::schema::{
1354 ColumnDefaultConstraint, ColumnSchema, FulltextAnalyzer, FulltextBackend,
1355 };
1356 use datatypes::value::Value;
1357
1358 use super::*;
1359
1360 fn create_builder() -> RegionMetadataBuilder {
1361 RegionMetadataBuilder::new(RegionId::new(1234, 5678))
1362 }
1363
1364 fn build_test_region_metadata() -> RegionMetadata {
1365 let mut builder = create_builder();
1366 builder
1367 .push_column_metadata(ColumnMetadata {
1368 column_schema: ColumnSchema::new("a", ConcreteDataType::int64_datatype(), false),
1369 semantic_type: SemanticType::Tag,
1370 column_id: 1,
1371 })
1372 .push_column_metadata(ColumnMetadata {
1373 column_schema: ColumnSchema::new("b", ConcreteDataType::float64_datatype(), false),
1374 semantic_type: SemanticType::Field,
1375 column_id: 2,
1376 })
1377 .push_column_metadata(ColumnMetadata {
1378 column_schema: ColumnSchema::new(
1379 "c",
1380 ConcreteDataType::timestamp_millisecond_datatype(),
1381 false,
1382 ),
1383 semantic_type: SemanticType::Timestamp,
1384 column_id: 3,
1385 })
1386 .primary_key(vec![1])
1387 .partition_expr_json(Some("".to_string()));
1388 builder.build().unwrap()
1389 }
1390
1391 #[test]
1392 fn test_region_metadata() {
1393 let region_metadata = build_test_region_metadata();
1394 assert_eq!("c", region_metadata.time_index_column().column_schema.name);
1395 assert_eq!(
1396 "a",
1397 region_metadata.column_by_id(1).unwrap().column_schema.name
1398 );
1399 assert_eq!(None, region_metadata.column_by_id(10));
1400 }
1401
1402 #[test]
1403 fn test_region_metadata_serde() {
1404 let region_metadata = build_test_region_metadata();
1405 let serialized = serde_json::to_string(®ion_metadata).unwrap();
1406 let deserialized: RegionMetadata = serde_json::from_str(&serialized).unwrap();
1407 assert_eq!(region_metadata, deserialized);
1408 }
1409
1410 #[test]
1411 fn test_column_metadata_validate() {
1412 let mut builder = create_builder();
1413 let col = ColumnMetadata {
1414 column_schema: ColumnSchema::new("ts", ConcreteDataType::string_datatype(), false),
1415 semantic_type: SemanticType::Timestamp,
1416 column_id: 1,
1417 };
1418
1419 builder.push_column_metadata(col);
1420 let err = builder.build().unwrap_err();
1421 assert!(
1422 err.to_string()
1423 .contains("column `ts` is not timestamp type"),
1424 "unexpected err: {err}",
1425 );
1426 }
1427
1428 #[test]
1429 fn test_empty_region_metadata() {
1430 let builder = create_builder();
1431 let err = builder.build().unwrap_err();
1432 assert!(
1434 err.to_string().contains("time index not found"),
1435 "unexpected err: {err}",
1436 );
1437 }
1438
1439 #[test]
1440 fn test_same_column_id() {
1441 let mut builder = create_builder();
1442 builder
1443 .push_column_metadata(ColumnMetadata {
1444 column_schema: ColumnSchema::new("a", ConcreteDataType::int64_datatype(), false),
1445 semantic_type: SemanticType::Tag,
1446 column_id: 1,
1447 })
1448 .push_column_metadata(ColumnMetadata {
1449 column_schema: ColumnSchema::new(
1450 "b",
1451 ConcreteDataType::timestamp_millisecond_datatype(),
1452 false,
1453 ),
1454 semantic_type: SemanticType::Timestamp,
1455 column_id: 1,
1456 });
1457 let err = builder.build().unwrap_err();
1458 assert!(
1459 err.to_string()
1460 .contains("column a and b have the same column id"),
1461 "unexpected err: {err}",
1462 );
1463 }
1464
1465 #[test]
1466 fn test_duplicate_time_index() {
1467 let mut builder = create_builder();
1468 builder
1469 .push_column_metadata(ColumnMetadata {
1470 column_schema: ColumnSchema::new(
1471 "a",
1472 ConcreteDataType::timestamp_millisecond_datatype(),
1473 false,
1474 ),
1475 semantic_type: SemanticType::Timestamp,
1476 column_id: 1,
1477 })
1478 .push_column_metadata(ColumnMetadata {
1479 column_schema: ColumnSchema::new(
1480 "b",
1481 ConcreteDataType::timestamp_millisecond_datatype(),
1482 false,
1483 ),
1484 semantic_type: SemanticType::Timestamp,
1485 column_id: 2,
1486 });
1487 let err = builder.build().unwrap_err();
1488 assert!(
1489 err.to_string().contains("expect only one time index"),
1490 "unexpected err: {err}",
1491 );
1492 }
1493
1494 #[test]
1495 fn test_unknown_primary_key() {
1496 let mut builder = create_builder();
1497 builder
1498 .push_column_metadata(ColumnMetadata {
1499 column_schema: ColumnSchema::new("a", ConcreteDataType::string_datatype(), false),
1500 semantic_type: SemanticType::Tag,
1501 column_id: 1,
1502 })
1503 .push_column_metadata(ColumnMetadata {
1504 column_schema: ColumnSchema::new(
1505 "b",
1506 ConcreteDataType::timestamp_millisecond_datatype(),
1507 false,
1508 ),
1509 semantic_type: SemanticType::Timestamp,
1510 column_id: 2,
1511 })
1512 .primary_key(vec![3]);
1513 let err = builder.build().unwrap_err();
1514 assert!(
1515 err.to_string().contains("unknown column id 3"),
1516 "unexpected err: {err}",
1517 );
1518 }
1519
1520 #[test]
1521 fn test_same_primary_key() {
1522 let mut builder = create_builder();
1523 builder
1524 .push_column_metadata(ColumnMetadata {
1525 column_schema: ColumnSchema::new("a", ConcreteDataType::string_datatype(), false),
1526 semantic_type: SemanticType::Tag,
1527 column_id: 1,
1528 })
1529 .push_column_metadata(ColumnMetadata {
1530 column_schema: ColumnSchema::new(
1531 "b",
1532 ConcreteDataType::timestamp_millisecond_datatype(),
1533 false,
1534 ),
1535 semantic_type: SemanticType::Timestamp,
1536 column_id: 2,
1537 })
1538 .primary_key(vec![1, 1]);
1539 let err = builder.build().unwrap_err();
1540 assert!(
1541 err.to_string()
1542 .contains("duplicate column a in primary key"),
1543 "unexpected err: {err}",
1544 );
1545 }
1546
1547 #[test]
1548 fn test_in_time_index() {
1549 let mut builder = create_builder();
1550 builder
1551 .push_column_metadata(ColumnMetadata {
1552 column_schema: ColumnSchema::new(
1553 "ts",
1554 ConcreteDataType::timestamp_millisecond_datatype(),
1555 false,
1556 ),
1557 semantic_type: SemanticType::Timestamp,
1558 column_id: 1,
1559 })
1560 .primary_key(vec![1]);
1561 let err = builder.build().unwrap_err();
1562 assert!(
1563 err.to_string()
1564 .contains("column ts is already a time index column"),
1565 "unexpected err: {err}",
1566 );
1567 }
1568
1569 #[test]
1570 fn test_nullable_time_index() {
1571 let mut builder = create_builder();
1572 builder.push_column_metadata(ColumnMetadata {
1573 column_schema: ColumnSchema::new(
1574 "ts",
1575 ConcreteDataType::timestamp_millisecond_datatype(),
1576 true,
1577 ),
1578 semantic_type: SemanticType::Timestamp,
1579 column_id: 1,
1580 });
1581 let err = builder.build().unwrap_err();
1582 assert!(
1583 err.to_string()
1584 .contains("time index column ts must be NOT NULL"),
1585 "unexpected err: {err}",
1586 );
1587 }
1588
1589 #[test]
1590 fn test_primary_key_semantic_type() {
1591 let mut builder = create_builder();
1592 builder
1593 .push_column_metadata(ColumnMetadata {
1594 column_schema: ColumnSchema::new(
1595 "ts",
1596 ConcreteDataType::timestamp_millisecond_datatype(),
1597 false,
1598 ),
1599 semantic_type: SemanticType::Timestamp,
1600 column_id: 1,
1601 })
1602 .push_column_metadata(ColumnMetadata {
1603 column_schema: ColumnSchema::new("a", ConcreteDataType::float64_datatype(), true),
1604 semantic_type: SemanticType::Field,
1605 column_id: 2,
1606 })
1607 .primary_key(vec![2]);
1608 let err = builder.build().unwrap_err();
1609 assert!(
1610 err.to_string()
1611 .contains("semantic type of column a should be Tag, not Field"),
1612 "unexpected err: {err}",
1613 );
1614 }
1615
1616 #[test]
1617 fn test_primary_key_tag_num() {
1618 let mut builder = create_builder();
1619 builder
1620 .push_column_metadata(ColumnMetadata {
1621 column_schema: ColumnSchema::new(
1622 "ts",
1623 ConcreteDataType::timestamp_millisecond_datatype(),
1624 false,
1625 ),
1626 semantic_type: SemanticType::Timestamp,
1627 column_id: 1,
1628 })
1629 .push_column_metadata(ColumnMetadata {
1630 column_schema: ColumnSchema::new("a", ConcreteDataType::string_datatype(), true),
1631 semantic_type: SemanticType::Tag,
1632 column_id: 2,
1633 })
1634 .push_column_metadata(ColumnMetadata {
1635 column_schema: ColumnSchema::new("b", ConcreteDataType::string_datatype(), true),
1636 semantic_type: SemanticType::Tag,
1637 column_id: 3,
1638 })
1639 .primary_key(vec![2]);
1640 let err = builder.build().unwrap_err();
1641 assert!(
1642 err.to_string()
1643 .contains("number of primary key columns 1 not equal to tag columns 2"),
1644 "unexpected err: {err}",
1645 );
1646 }
1647
1648 #[test]
1649 fn test_bump_version() {
1650 let mut region_metadata = build_test_region_metadata();
1651 let mut builder = RegionMetadataBuilder::from_existing(region_metadata.clone());
1652 builder.bump_version();
1653 let new_meta = builder.build().unwrap();
1654 region_metadata.schema_version += 1;
1655 assert_eq!(region_metadata, new_meta);
1656 }
1657
1658 fn new_column_metadata(name: &str, is_tag: bool, column_id: ColumnId) -> ColumnMetadata {
1659 let semantic_type = if is_tag {
1660 SemanticType::Tag
1661 } else {
1662 SemanticType::Field
1663 };
1664 ColumnMetadata {
1665 column_schema: ColumnSchema::new(name, ConcreteDataType::string_datatype(), true),
1666 semantic_type,
1667 column_id,
1668 }
1669 }
1670
1671 fn check_columns(metadata: &RegionMetadata, names: &[&str]) {
1672 let actual: Vec<_> = metadata
1673 .column_metadatas
1674 .iter()
1675 .map(|col| &col.column_schema.name)
1676 .collect();
1677 assert_eq!(names, actual);
1678 }
1679
1680 fn get_columns_default_constraint(
1681 metadata: &RegionMetadata,
1682 name: String,
1683 ) -> Option<Option<&ColumnDefaultConstraint>> {
1684 metadata.column_metadatas.iter().find_map(|col| {
1685 if col.column_schema.name == name {
1686 Some(col.column_schema.default_constraint())
1687 } else {
1688 None
1689 }
1690 })
1691 }
1692
1693 #[test]
1694 fn test_alter() {
1695 let metadata = build_test_region_metadata();
1697 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1698 builder
1700 .alter(AlterKind::AddColumns {
1701 columns: vec![AddColumn {
1702 column_metadata: new_column_metadata("d", true, 4),
1703 location: None,
1704 }],
1705 })
1706 .unwrap();
1707 let metadata = builder.build().unwrap();
1708 check_columns(&metadata, &["a", "b", "c", "d"]);
1709 assert_eq!([1, 4], &metadata.primary_key[..]);
1710
1711 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1712 builder
1713 .alter(AlterKind::AddColumns {
1714 columns: vec![AddColumn {
1715 column_metadata: new_column_metadata("e", false, 5),
1716 location: Some(AddColumnLocation::First),
1717 }],
1718 })
1719 .unwrap();
1720 let metadata = builder.build().unwrap();
1721 check_columns(&metadata, &["e", "a", "b", "c", "d"]);
1722
1723 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1724 builder
1725 .alter(AlterKind::AddColumns {
1726 columns: vec![AddColumn {
1727 column_metadata: new_column_metadata("f", false, 6),
1728 location: Some(AddColumnLocation::After {
1729 column_name: "b".to_string(),
1730 }),
1731 }],
1732 })
1733 .unwrap();
1734 let metadata = builder.build().unwrap();
1735 check_columns(&metadata, &["e", "a", "b", "f", "c", "d"]);
1736
1737 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1738 builder
1739 .alter(AlterKind::AddColumns {
1740 columns: vec![AddColumn {
1741 column_metadata: new_column_metadata("g", false, 7),
1742 location: Some(AddColumnLocation::After {
1743 column_name: "d".to_string(),
1744 }),
1745 }],
1746 })
1747 .unwrap();
1748 let metadata = builder.build().unwrap();
1749 check_columns(&metadata, &["e", "a", "b", "f", "c", "d", "g"]);
1750
1751 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1752 builder
1753 .alter(AlterKind::DropColumns {
1754 names: vec!["g".to_string(), "e".to_string()],
1755 })
1756 .unwrap();
1757 let metadata = builder.build().unwrap();
1758 check_columns(&metadata, &["a", "b", "f", "c", "d"]);
1759
1760 let mut builder = RegionMetadataBuilder::from_existing(metadata.clone());
1761 builder
1762 .alter(AlterKind::DropColumns {
1763 names: vec!["a".to_string()],
1764 })
1765 .unwrap();
1766 let err = builder.build().unwrap_err();
1768 assert_eq!(StatusCode::InvalidArguments, err.status_code());
1769
1770 let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
1771 let mut column_metadata = new_column_metadata("g", false, 8);
1772 let default_constraint = Some(ColumnDefaultConstraint::Value(Value::from("g")));
1773 column_metadata.column_schema = column_metadata
1774 .column_schema
1775 .with_default_constraint(default_constraint.clone())
1776 .unwrap();
1777 builder
1778 .alter(AlterKind::AddColumns {
1779 columns: vec![AddColumn {
1780 column_metadata,
1781 location: None,
1782 }],
1783 })
1784 .unwrap();
1785 let metadata = builder.build().unwrap();
1786 assert_eq!(
1787 get_columns_default_constraint(&metadata, "g".to_string()).unwrap(),
1788 default_constraint.as_ref()
1789 );
1790 check_columns(&metadata, &["a", "b", "f", "c", "d", "g"]);
1791
1792 let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
1793 builder
1794 .alter(AlterKind::DropDefaults {
1795 names: vec!["g".to_string()],
1796 })
1797 .unwrap();
1798 let metadata = builder.build().unwrap();
1799 assert_eq!(
1800 get_columns_default_constraint(&metadata, "g".to_string()).unwrap(),
1801 None
1802 );
1803 check_columns(&metadata, &["a", "b", "f", "c", "d", "g"]);
1804
1805 let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
1806 builder
1807 .alter(AlterKind::DropColumns {
1808 names: vec!["g".to_string()],
1809 })
1810 .unwrap();
1811 let metadata = builder.build().unwrap();
1812 check_columns(&metadata, &["a", "b", "f", "c", "d"]);
1813
1814 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1815 builder
1816 .alter(AlterKind::ModifyColumnTypes {
1817 columns: vec![ModifyColumnType {
1818 column_name: "b".to_string(),
1819 target_type: ConcreteDataType::string_datatype(),
1820 }],
1821 })
1822 .unwrap();
1823 let metadata = builder.build().unwrap();
1824 check_columns(&metadata, &["a", "b", "f", "c", "d"]);
1825 let b_type = &metadata
1826 .column_by_name("b")
1827 .unwrap()
1828 .column_schema
1829 .data_type;
1830 assert_eq!(ConcreteDataType::string_datatype(), *b_type);
1831
1832 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1833 builder
1834 .alter(AlterKind::SetIndexes {
1835 options: vec![SetIndexOption::Fulltext {
1836 column_name: "b".to_string(),
1837 options: FulltextOptions::new_unchecked(
1838 true,
1839 FulltextAnalyzer::Chinese,
1840 true,
1841 FulltextBackend::Bloom,
1842 1000,
1843 0.01,
1844 ),
1845 }],
1846 })
1847 .unwrap();
1848 let metadata = builder.build().unwrap();
1849 let a_fulltext_options = metadata
1850 .column_by_name("b")
1851 .unwrap()
1852 .column_schema
1853 .fulltext_options()
1854 .unwrap()
1855 .unwrap();
1856 assert!(a_fulltext_options.enable);
1857 assert_eq!(
1858 datatypes::schema::FulltextAnalyzer::Chinese,
1859 a_fulltext_options.analyzer
1860 );
1861 assert!(a_fulltext_options.case_sensitive);
1862
1863 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1864 builder
1865 .alter(AlterKind::UnsetIndexes {
1866 options: vec![UnsetIndexOption::Fulltext {
1867 column_name: "b".to_string(),
1868 }],
1869 })
1870 .unwrap();
1871 let metadata = builder.build().unwrap();
1872 let a_fulltext_options = metadata
1873 .column_by_name("b")
1874 .unwrap()
1875 .column_schema
1876 .fulltext_options()
1877 .unwrap()
1878 .unwrap();
1879 assert!(!a_fulltext_options.enable);
1880 assert_eq!(
1881 datatypes::schema::FulltextAnalyzer::Chinese,
1882 a_fulltext_options.analyzer
1883 );
1884 assert!(a_fulltext_options.case_sensitive);
1885 }
1886
1887 #[test]
1888 fn test_add_if_not_exists() {
1889 let metadata = build_test_region_metadata();
1891 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1892 builder
1894 .alter(AlterKind::AddColumns {
1895 columns: vec![
1896 AddColumn {
1897 column_metadata: new_column_metadata("d", true, 4),
1898 location: None,
1899 },
1900 AddColumn {
1901 column_metadata: new_column_metadata("d", true, 4),
1902 location: None,
1903 },
1904 ],
1905 })
1906 .unwrap();
1907 let metadata = builder.build().unwrap();
1908 check_columns(&metadata, &["a", "b", "c", "d"]);
1909 assert_eq!([1, 4], &metadata.primary_key[..]);
1910
1911 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1912 builder
1914 .alter(AlterKind::AddColumns {
1915 columns: vec![AddColumn {
1916 column_metadata: new_column_metadata("b", false, 2),
1917 location: None,
1918 }],
1919 })
1920 .unwrap();
1921 let metadata = builder.build().unwrap();
1922 check_columns(&metadata, &["a", "b", "c", "d"]);
1923 }
1924
1925 #[test]
1926 fn test_add_column_with_inverted_index() {
1927 let metadata = build_test_region_metadata();
1931 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1932 let mut col = new_column_metadata("d", true, 4);
1934 col.column_schema.set_inverted_index(true);
1935 builder
1936 .alter(AlterKind::AddColumns {
1937 columns: vec![
1938 AddColumn {
1939 column_metadata: col,
1940 location: None,
1941 },
1942 AddColumn {
1943 column_metadata: new_column_metadata("e", true, 5),
1944 location: None,
1945 },
1946 ],
1947 })
1948 .unwrap();
1949 let metadata = builder.build().unwrap();
1950 check_columns(&metadata, &["a", "b", "c", "d", "e"]);
1951 assert_eq!([1, 4, 5], &metadata.primary_key[..]);
1952 let column_metadata = metadata.column_by_name("a").unwrap();
1953 assert!(!column_metadata.column_schema.is_inverted_indexed());
1954 let column_metadata = metadata.column_by_name("b").unwrap();
1955 assert!(!column_metadata.column_schema.is_inverted_indexed());
1956 let column_metadata = metadata.column_by_name("c").unwrap();
1957 assert!(!column_metadata.column_schema.is_inverted_indexed());
1958 let column_metadata = metadata.column_by_name("d").unwrap();
1959 assert!(column_metadata.column_schema.is_inverted_indexed());
1960 let column_metadata = metadata.column_by_name("e").unwrap();
1961 assert!(!column_metadata.column_schema.is_inverted_indexed());
1962 }
1963
1964 #[test]
1965 fn test_drop_if_exists() {
1966 let metadata = build_test_region_metadata();
1968 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1969 builder
1971 .alter(AlterKind::AddColumns {
1972 columns: vec![
1973 AddColumn {
1974 column_metadata: new_column_metadata("d", false, 4),
1975 location: None,
1976 },
1977 AddColumn {
1978 column_metadata: new_column_metadata("e", false, 5),
1979 location: None,
1980 },
1981 ],
1982 })
1983 .unwrap();
1984 let metadata = builder.build().unwrap();
1985 check_columns(&metadata, &["a", "b", "c", "d", "e"]);
1986
1987 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1988 builder
1989 .alter(AlterKind::DropColumns {
1990 names: vec!["b".to_string(), "b".to_string()],
1991 })
1992 .unwrap();
1993 let metadata = builder.build().unwrap();
1994 check_columns(&metadata, &["a", "c", "d", "e"]);
1995
1996 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1997 builder
1998 .alter(AlterKind::DropColumns {
1999 names: vec!["b".to_string(), "e".to_string()],
2000 })
2001 .unwrap();
2002 let metadata = builder.build().unwrap();
2003 check_columns(&metadata, &["a", "c", "d"]);
2004 }
2005
2006 #[test]
2007 fn test_invalid_column_name() {
2008 let mut builder = create_builder();
2009 builder.push_column_metadata(ColumnMetadata {
2010 column_schema: ColumnSchema::new(
2011 "__sequence",
2012 ConcreteDataType::timestamp_millisecond_datatype(),
2013 false,
2014 ),
2015 semantic_type: SemanticType::Timestamp,
2016 column_id: 1,
2017 });
2018 let err = builder.build().unwrap_err();
2019 assert!(
2020 err.to_string()
2021 .contains("internal column name that can not be used"),
2022 "unexpected err: {err}",
2023 );
2024 }
2025
2026 #[test]
2027 fn test_allow_internal_column_name() {
2028 let mut builder = create_builder();
2029 builder
2030 .push_column_metadata(ColumnMetadata {
2031 column_schema: ColumnSchema::new(
2032 "__primary_key",
2033 ConcreteDataType::string_datatype(),
2034 false,
2035 ),
2036 semantic_type: SemanticType::Tag,
2037 column_id: 1,
2038 })
2039 .push_column_metadata(ColumnMetadata {
2040 column_schema: ColumnSchema::new(
2041 "ts",
2042 ConcreteDataType::timestamp_millisecond_datatype(),
2043 false,
2044 ),
2045 semantic_type: SemanticType::Timestamp,
2046 column_id: 2,
2047 })
2048 .primary_key(vec![1]);
2049
2050 let metadata = builder.build_without_validation().unwrap();
2051 assert_eq!(
2052 "__primary_key",
2053 metadata.column_metadatas[0].column_schema.name
2054 );
2055 }
2056
2057 #[test]
2058 fn test_build_without_validation() {
2059 let mut builder = create_builder();
2061 builder
2062 .push_column_metadata(ColumnMetadata {
2063 column_schema: ColumnSchema::new(
2064 "ts",
2065 ConcreteDataType::timestamp_millisecond_datatype(),
2066 false,
2067 ),
2068 semantic_type: SemanticType::Timestamp,
2069 column_id: 1,
2070 })
2071 .push_column_metadata(ColumnMetadata {
2072 column_schema: ColumnSchema::new(
2073 "field",
2074 ConcreteDataType::string_datatype(),
2075 true,
2076 ),
2077 semantic_type: SemanticType::Field,
2078 column_id: 2,
2079 })
2080 .primary_key(vec![2]);
2081
2082 let metadata = builder.build_without_validation().unwrap();
2084 assert_eq!(vec![2], metadata.primary_key);
2085
2086 let mut builder = create_builder();
2088 builder
2089 .push_column_metadata(ColumnMetadata {
2090 column_schema: ColumnSchema::new(
2091 "ts",
2092 ConcreteDataType::timestamp_millisecond_datatype(),
2093 false,
2094 ),
2095 semantic_type: SemanticType::Timestamp,
2096 column_id: 1,
2097 })
2098 .push_column_metadata(ColumnMetadata {
2099 column_schema: ColumnSchema::new(
2100 "field",
2101 ConcreteDataType::string_datatype(),
2102 true,
2103 ),
2104 semantic_type: SemanticType::Field,
2105 column_id: 2,
2106 })
2107 .primary_key(vec![2]);
2108 let err = builder.build().unwrap_err();
2109 assert!(
2110 err.to_string()
2111 .contains("semantic type of column field should be Tag"),
2112 "unexpected err: {err}"
2113 );
2114 }
2115
2116 #[test]
2117 fn test_debug_for_column_metadata() {
2118 let region_metadata = build_test_region_metadata();
2119 let formatted = format!("{:?}", region_metadata);
2120 assert_eq!(
2121 formatted,
2122 "RegionMetadata { column_metadatas: [[a Int64 not null Tag 1], [b Float64 not null Field 2], [c TimestampMillisecond not null Timestamp 3]], time_index: 3, primary_key: [1], region_id: 5299989648942(1234, 5678), schema_version: 0, partition_expr: Some(\"\") }"
2123 );
2124 }
2125
2126 #[test]
2127 fn test_region_metadata_deserialize_default_primary_key_encoding() {
2128 let serialize = r#"{"column_metadatas":[{"column_schema":{"name":"a","data_type":{"Int64":{}},"is_nullable":false,"is_time_index":false,"default_constraint":null,"metadata":{}},"semantic_type":"Tag","column_id":1},{"column_schema":{"name":"b","data_type":{"Float64":{}},"is_nullable":false,"is_time_index":false,"default_constraint":null,"metadata":{}},"semantic_type":"Field","column_id":2},{"column_schema":{"name":"c","data_type":{"Timestamp":{"Millisecond":null}},"is_nullable":false,"is_time_index":false,"default_constraint":null,"metadata":{}},"semantic_type":"Timestamp","column_id":3}],"primary_key":[1],"region_id":5299989648942,"schema_version":0}"#;
2129 let deserialized: RegionMetadata = serde_json::from_str(serialize).unwrap();
2130 assert_eq!(deserialized.primary_key_encoding, PrimaryKeyEncoding::Dense);
2131
2132 let serialize = r#"{"column_metadatas":[{"column_schema":{"name":"a","data_type":{"Int64":{}},"is_nullable":false,"is_time_index":false,"default_constraint":null,"metadata":{}},"semantic_type":"Tag","column_id":1},{"column_schema":{"name":"b","data_type":{"Float64":{}},"is_nullable":false,"is_time_index":false,"default_constraint":null,"metadata":{}},"semantic_type":"Field","column_id":2},{"column_schema":{"name":"c","data_type":{"Timestamp":{"Millisecond":null}},"is_nullable":false,"is_time_index":false,"default_constraint":null,"metadata":{}},"semantic_type":"Timestamp","column_id":3}],"primary_key":[1],"region_id":5299989648942,"schema_version":0,"primary_key_encoding":"sparse"}"#;
2133 let deserialized: RegionMetadata = serde_json::from_str(serialize).unwrap();
2134 assert_eq!(
2135 deserialized.primary_key_encoding,
2136 PrimaryKeyEncoding::Sparse
2137 );
2138 }
2139}