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 if column_metadata.semantic_type == SemanticType::Timestamp {
553 ensure!(
554 column_metadata.column_schema.data_type.is_timestamp(),
555 InvalidMetaSnafu {
556 reason: format!(
557 "column `{}` is not timestamp type",
558 column_metadata.column_schema.name
559 ),
560 }
561 );
562 }
563
564 ensure!(
565 !is_internal_column(&column_metadata.column_schema.name),
566 InvalidMetaSnafu {
567 reason: format!(
568 "{} is internal column name that can not be used",
569 column_metadata.column_schema.name
570 ),
571 }
572 );
573
574 Ok(())
575 }
576}
577
578pub struct RegionMetadataBuilder {
580 region_id: RegionId,
581 column_metadatas: Vec<ColumnMetadata>,
582 primary_key: Vec<ColumnId>,
583 schema_version: u64,
584 primary_key_encoding: PrimaryKeyEncoding,
585 partition_expr: Option<String>,
586}
587
588impl RegionMetadataBuilder {
589 pub fn new(id: RegionId) -> Self {
591 Self {
592 region_id: id,
593 column_metadatas: vec![],
594 primary_key: vec![],
595 schema_version: 0,
596 primary_key_encoding: PrimaryKeyEncoding::Dense,
597 partition_expr: None,
598 }
599 }
600
601 pub fn from_existing(existing: RegionMetadata) -> Self {
603 Self {
604 column_metadatas: existing.column_metadatas,
605 primary_key: existing.primary_key,
606 region_id: existing.region_id,
607 schema_version: existing.schema_version,
608 primary_key_encoding: existing.primary_key_encoding,
609 partition_expr: existing.partition_expr,
610 }
611 }
612
613 pub fn primary_key_encoding(&mut self, encoding: PrimaryKeyEncoding) -> &mut Self {
615 self.primary_key_encoding = encoding;
616 self
617 }
618
619 pub fn partition_expr_json(&mut self, expr_json: Option<String>) -> &mut Self {
621 self.partition_expr = expr_json;
622 self
623 }
624
625 pub fn push_column_metadata(&mut self, column_metadata: ColumnMetadata) -> &mut Self {
627 self.column_metadatas.push(column_metadata);
628 self
629 }
630
631 pub fn primary_key(&mut self, key: Vec<ColumnId>) -> &mut Self {
633 self.primary_key = key;
634 self
635 }
636
637 pub fn bump_version(&mut self) -> &mut Self {
639 self.schema_version += 1;
640 self
641 }
642
643 pub fn alter(&mut self, kind: AlterKind) -> Result<&mut Self> {
647 match kind {
648 AlterKind::AddColumns { columns } => self.add_columns(columns)?,
649 AlterKind::DropColumns { names } => self.drop_columns(&names),
650 AlterKind::ModifyColumnTypes { columns } => self.modify_column_types(columns)?,
651 AlterKind::SetJsonSettings {
652 column_name,
653 settings,
654 } => self.set_json_settings(column_name, settings)?,
655 AlterKind::SetIndexes { options } => self.set_indexes(options)?,
656 AlterKind::UnsetIndexes { options } => self.unset_indexes(options)?,
657 AlterKind::SetRegionOptions { options: _ } => {
658 }
660 AlterKind::UnsetRegionOptions { keys: _ } => {
661 }
663 AlterKind::DropDefaults { names } => {
664 self.drop_defaults(names)?;
665 }
666 AlterKind::SetDefaults { columns } => self.set_defaults(&columns)?,
667 AlterKind::SyncColumns { column_metadatas } => {
668 self.primary_key = column_metadatas
669 .iter()
670 .filter_map(|column_metadata| {
671 if column_metadata.semantic_type == SemanticType::Tag {
672 Some(column_metadata.column_id)
673 } else {
674 None
675 }
676 })
677 .collect::<Vec<_>>();
678 self.column_metadatas = column_metadatas;
679 }
680 }
681 Ok(self)
682 }
683
684 pub fn build(self) -> Result<RegionMetadata> {
686 self.build_with_options(true)
687 }
688
689 pub fn build_without_validation(self) -> Result<RegionMetadata> {
694 self.build_with_options(false)
695 }
696
697 fn build_with_options(self, validate: bool) -> Result<RegionMetadata> {
698 let skipped = SkippedFields::new(&self.column_metadatas)?;
699
700 let partition_expr_version = partition_expr_version(self.partition_expr.as_deref());
701 let meta = RegionMetadata {
702 schema: skipped.schema,
703 time_index: skipped.time_index,
704 id_to_index: skipped.id_to_index,
705 column_metadatas: self.column_metadatas,
706 primary_key: self.primary_key,
707 region_id: self.region_id,
708 schema_version: self.schema_version,
709 primary_key_encoding: self.primary_key_encoding,
710 partition_expr: self.partition_expr,
711 partition_expr_version,
712 };
713
714 if validate {
715 meta.validate()?;
716 }
717
718 Ok(meta)
719 }
720
721 fn add_columns(&mut self, columns: Vec<AddColumn>) -> Result<()> {
723 let mut names: HashSet<_> = self
724 .column_metadatas
725 .iter()
726 .map(|col| col.column_schema.name.clone())
727 .collect();
728
729 for add_column in columns {
730 if names.contains(&add_column.column_metadata.column_schema.name) {
731 continue;
733 }
734
735 let column_id = add_column.column_metadata.column_id;
736 let semantic_type = add_column.column_metadata.semantic_type;
737 let column_name = add_column.column_metadata.column_schema.name.clone();
738 match add_column.location {
739 None => {
740 self.column_metadatas.push(add_column.column_metadata);
741 }
742 Some(AddColumnLocation::First) => {
743 self.column_metadatas.insert(0, add_column.column_metadata);
744 }
745 Some(AddColumnLocation::After { column_name }) => {
746 let pos = self
747 .column_metadatas
748 .iter()
749 .position(|col| col.column_schema.name == column_name)
750 .context(InvalidRegionRequestSnafu {
751 region_id: self.region_id,
752 err: format!(
753 "column {} not found, failed to add column {} after it",
754 column_name, add_column.column_metadata.column_schema.name
755 ),
756 })?;
757 self.column_metadatas
759 .insert(pos + 1, add_column.column_metadata);
760 }
761 }
762 names.insert(column_name);
763 if semantic_type == SemanticType::Tag {
764 self.primary_key.push(column_id);
766 }
767 }
768
769 Ok(())
770 }
771
772 fn drop_columns(&mut self, names: &[String]) {
774 let name_set: HashSet<_> = names.iter().collect();
775 self.column_metadatas
776 .retain(|col| !name_set.contains(&col.column_schema.name));
777 }
778
779 fn modify_column_types(&mut self, columns: Vec<ModifyColumnType>) -> Result<()> {
781 let mut change_type_map: HashMap<_, _> = columns
782 .into_iter()
783 .map(
784 |ModifyColumnType {
785 column_name,
786 target_type,
787 }| (column_name, target_type),
788 )
789 .collect();
790
791 for column_meta in self.column_metadatas.iter_mut() {
792 if let Some(target_type) = change_type_map.remove(&column_meta.column_schema.name) {
793 column_meta.column_schema.data_type = target_type.clone();
794 let new_default =
796 if let Some(default_value) = column_meta.column_schema.default_constraint() {
797 Some(
798 default_value
799 .cast_to_datatype(&target_type)
800 .with_context(|_| CastDefaultValueSnafu {
801 reason: format!(
802 "Failed to cast default value from {:?} to type {:?}",
803 default_value, target_type
804 ),
805 })?,
806 )
807 } else {
808 None
809 };
810 column_meta.column_schema = column_meta
811 .column_schema
812 .clone()
813 .with_default_constraint(new_default.clone())
814 .with_context(|_| CastDefaultValueSnafu {
815 reason: format!("Failed to set new default: {:?}", new_default),
816 })?;
817 }
818 }
819
820 Ok(())
821 }
822
823 fn set_json_settings(
824 &mut self,
825 col_name: String,
826 settings: datatypes::json::JsonSettings,
827 ) -> Result<()> {
828 let Some(col_meta) = self
829 .column_metadatas
830 .iter_mut()
831 .find(|col| col.column_schema.name == col_name)
832 else {
833 return InvalidRegionRequestSnafu {
834 region_id: self.region_id,
835 err: format!("column {col_name} not found"),
836 }
837 .fail();
838 };
839
840 let old_metadata = col_meta.column_schema.metadata();
841 let new_metadata =
842 json2_metadata_with_updated_settings(old_metadata, settings).map_err(|err| {
843 InvalidRegionRequestSnafu {
844 region_id: self.region_id,
845 err: err.to_string(),
846 }
847 .build()
848 })?;
849
850 *col_meta.column_schema.mut_metadata() = new_metadata;
851 Ok(())
852 }
853
854 fn set_indexes(&mut self, options: Vec<SetIndexOption>) -> Result<()> {
855 let mut set_index_map: HashMap<_, Vec<_>> = HashMap::new();
856 for option in &options {
857 set_index_map
858 .entry(option.column_name())
859 .or_default()
860 .push(option);
861 }
862
863 for column_metadata in self.column_metadatas.iter_mut() {
864 if let Some(options) = set_index_map.remove(&column_metadata.column_schema.name) {
865 for option in options {
866 Self::set_index(column_metadata, option)?;
867 }
868 }
869 }
870
871 Ok(())
872 }
873
874 fn unset_indexes(&mut self, options: Vec<UnsetIndexOption>) -> Result<()> {
875 let mut unset_index_map: HashMap<_, Vec<_>> = HashMap::new();
876 for option in &options {
877 unset_index_map
878 .entry(option.column_name())
879 .or_default()
880 .push(option);
881 }
882
883 for column_metadata in self.column_metadatas.iter_mut() {
884 if let Some(options) = unset_index_map.remove(&column_metadata.column_schema.name) {
885 for option in options {
886 Self::unset_index(column_metadata, option)?;
887 }
888 }
889 }
890
891 Ok(())
892 }
893
894 fn set_index(column_metadata: &mut ColumnMetadata, options: &SetIndexOption) -> Result<()> {
895 match options {
896 SetIndexOption::Fulltext {
897 column_name,
898 options,
899 } => {
900 ensure!(
901 column_metadata.column_schema.data_type.is_string(),
902 InvalidColumnOptionSnafu {
903 column_name,
904 msg: "FULLTEXT index only supports string type".to_string(),
905 }
906 );
907 let current_fulltext_options = column_metadata
908 .column_schema
909 .fulltext_options()
910 .with_context(|_| GetFulltextOptionsSnafu {
911 column_name: column_name.clone(),
912 })?;
913 set_column_fulltext_options(
914 column_metadata,
915 column_name,
916 options,
917 current_fulltext_options,
918 )?;
919 }
920 SetIndexOption::Inverted { .. } => {
921 column_metadata.column_schema.set_inverted_index(true)
922 }
923 SetIndexOption::Skipping {
924 column_name,
925 options,
926 } => {
927 column_metadata
928 .column_schema
929 .set_skipping_options(options)
930 .context(UnsetSkippingIndexOptionsSnafu { column_name })?;
931 }
932 }
933
934 Ok(())
935 }
936
937 fn unset_index(column_metadata: &mut ColumnMetadata, options: &UnsetIndexOption) -> Result<()> {
938 match options {
939 UnsetIndexOption::Fulltext { column_name } => {
940 ensure!(
941 column_metadata.column_schema.data_type.is_string(),
942 InvalidColumnOptionSnafu {
943 column_name,
944 msg: "FULLTEXT index only supports string type".to_string(),
945 }
946 );
947
948 let current_fulltext_options = column_metadata
949 .column_schema
950 .fulltext_options()
951 .with_context(|_| GetFulltextOptionsSnafu {
952 column_name: column_name.clone(),
953 })?;
954
955 unset_column_fulltext_options(
956 column_metadata,
957 column_name,
958 current_fulltext_options,
959 )?;
960 }
961 UnsetIndexOption::Inverted { .. } => {
962 column_metadata.column_schema.set_inverted_index(false)
963 }
964 UnsetIndexOption::Skipping { column_name } => {
965 column_metadata
966 .column_schema
967 .unset_skipping_options()
968 .context(UnsetSkippingIndexOptionsSnafu { column_name })?;
969 }
970 }
971
972 Ok(())
973 }
974
975 fn drop_defaults(&mut self, column_names: Vec<String>) -> Result<()> {
976 for name in column_names.iter() {
977 let meta = self
978 .column_metadatas
979 .iter_mut()
980 .find(|col| col.column_schema.name == *name);
981 if let Some(meta) = meta {
982 if !meta.column_schema.is_nullable() {
983 return InvalidRegionRequestSnafu {
984 region_id: self.region_id,
985 err: format!(
986 "column {name} is not nullable and `default` cannot be dropped",
987 ),
988 }
989 .fail();
990 }
991 meta.column_schema = meta
992 .column_schema
993 .clone()
994 .with_default_constraint(None)
995 .with_context(|_| CastDefaultValueSnafu {
996 reason: format!("Failed to drop default : {name:?}"),
997 })?;
998 } else {
999 return InvalidRegionRequestSnafu {
1000 region_id: self.region_id,
1001 err: format!("column {name} not found",),
1002 }
1003 .fail();
1004 }
1005 }
1006 Ok(())
1007 }
1008
1009 fn set_defaults(&mut self, set_defaults: &[crate::region_request::SetDefault]) -> Result<()> {
1010 for set_default in set_defaults.iter() {
1011 let meta = self
1012 .column_metadatas
1013 .iter_mut()
1014 .find(|col| col.column_schema.name == set_default.name);
1015 if let Some(meta) = meta {
1016 let default_constraint = common_sql::convert::deserialize_default_constraint(
1017 set_default.default_constraint.as_slice(),
1018 &meta.column_schema.name,
1019 &meta.column_schema.data_type,
1020 )
1021 .context(SqlCommonSnafu)?;
1022
1023 meta.column_schema = meta
1024 .column_schema
1025 .clone()
1026 .with_default_constraint(default_constraint)
1027 .with_context(|_| CastDefaultValueSnafu {
1028 reason: format!("Failed to set default : {set_default:?}"),
1029 })?;
1030 } else {
1031 return InvalidRegionRequestSnafu {
1032 region_id: self.region_id,
1033 err: format!("column {} not found", set_default.name),
1034 }
1035 .fail();
1036 }
1037 }
1038 Ok(())
1039 }
1040}
1041
1042struct SkippedFields {
1044 schema: SchemaRef,
1046 time_index: ColumnId,
1048 id_to_index: HashMap<ColumnId, usize>,
1050}
1051
1052impl SkippedFields {
1053 fn new(column_metadatas: &[ColumnMetadata]) -> Result<SkippedFields> {
1055 let column_schemas = column_metadatas
1056 .iter()
1057 .map(|column_metadata| column_metadata.column_schema.clone())
1058 .collect();
1059 let schema = Arc::new(Schema::try_new(column_schemas).context(InvalidSchemaSnafu)?);
1060 let time_index = column_metadatas
1061 .iter()
1062 .find_map(|col| {
1063 if col.semantic_type == SemanticType::Timestamp {
1064 Some(col.column_id)
1065 } else {
1066 None
1067 }
1068 })
1069 .context(InvalidMetaSnafu {
1070 reason: "time index not found",
1071 })?;
1072 let id_to_index = column_metadatas
1073 .iter()
1074 .enumerate()
1075 .map(|(idx, col)| (col.column_id, idx))
1076 .collect();
1077
1078 Ok(SkippedFields {
1079 schema,
1080 time_index,
1081 id_to_index,
1082 })
1083 }
1084}
1085
1086#[derive(Snafu)]
1087#[snafu(visibility(pub))]
1088#[stack_trace_debug]
1089pub enum MetadataError {
1090 #[snafu(display("Invalid schema"))]
1091 InvalidSchema {
1092 source: datatypes::error::Error,
1093 #[snafu(implicit)]
1094 location: Location,
1095 },
1096
1097 #[snafu(display("Invalid metadata, {}", reason))]
1098 InvalidMeta {
1099 reason: String,
1100 #[snafu(implicit)]
1101 location: Location,
1102 },
1103
1104 #[snafu(display("Failed to ser/de json object"))]
1105 SerdeJson {
1106 #[snafu(implicit)]
1107 location: Location,
1108 #[snafu(source)]
1109 error: serde_json::Error,
1110 },
1111
1112 #[snafu(display("Invalid raw region request, err: {}", err))]
1113 InvalidRawRegionRequest {
1114 err: String,
1115 #[snafu(implicit)]
1116 location: Location,
1117 },
1118
1119 #[snafu(display("Invalid region request, region_id: {}, err: {}", region_id, err))]
1120 InvalidRegionRequest {
1121 region_id: RegionId,
1122 err: String,
1123 #[snafu(implicit)]
1124 location: Location,
1125 },
1126
1127 #[snafu(display("Unexpected schema error during project"))]
1128 SchemaProject {
1129 origin_schema: SchemaRef,
1130 projection: Vec<ColumnId>,
1131 #[snafu(implicit)]
1132 location: Location,
1133 source: datatypes::Error,
1134 },
1135
1136 #[snafu(display("Time index column not found"))]
1137 TimeIndexNotFound {
1138 #[snafu(implicit)]
1139 location: Location,
1140 },
1141
1142 #[snafu(display("Change column {} not exists in region: {}", column_name, region_id))]
1143 ChangeColumnNotFound {
1144 column_name: String,
1145 region_id: RegionId,
1146 #[snafu(implicit)]
1147 location: Location,
1148 },
1149
1150 #[snafu(display("Failed to convert column schema"))]
1151 ConvertColumnSchema {
1152 source: api::error::Error,
1153 #[snafu(implicit)]
1154 location: Location,
1155 },
1156
1157 #[snafu(display("Failed to convert TimeRanges"))]
1158 ConvertTimeRanges {
1159 source: api::error::Error,
1160 #[snafu(implicit)]
1161 location: Location,
1162 },
1163
1164 #[snafu(display("Invalid set region option request, key: {}, value: {}", key, value))]
1165 InvalidSetRegionOptionRequest {
1166 key: String,
1167 value: String,
1168 #[snafu(implicit)]
1169 location: Location,
1170 },
1171
1172 #[snafu(display("Invalid set region option request, key: {}", key))]
1173 InvalidUnsetRegionOptionRequest {
1174 key: String,
1175 #[snafu(implicit)]
1176 location: Location,
1177 },
1178
1179 #[snafu(display("Failed to decode protobuf"))]
1180 DecodeProto {
1181 #[snafu(source)]
1182 error: prost::UnknownEnumValue,
1183 #[snafu(implicit)]
1184 location: Location,
1185 },
1186
1187 #[snafu(display("Invalid column option, column name: {}, error: {}", column_name, msg))]
1188 InvalidColumnOption {
1189 column_name: String,
1190 msg: String,
1191 #[snafu(implicit)]
1192 location: Location,
1193 },
1194
1195 #[snafu(display("Failed to set fulltext options for column {}", column_name))]
1196 SetFulltextOptions {
1197 column_name: String,
1198 source: datatypes::Error,
1199 #[snafu(implicit)]
1200 location: Location,
1201 },
1202
1203 #[snafu(display("Failed to get fulltext options for column {}", column_name))]
1204 GetFulltextOptions {
1205 column_name: String,
1206 source: datatypes::Error,
1207 #[snafu(implicit)]
1208 location: Location,
1209 },
1210
1211 #[snafu(display("Failed to set skipping index options for column {}", column_name))]
1212 SetSkippingIndexOptions {
1213 column_name: String,
1214 source: datatypes::Error,
1215 #[snafu(implicit)]
1216 location: Location,
1217 },
1218
1219 #[snafu(display("Failed to unset skipping index options for column {}", column_name))]
1220 UnsetSkippingIndexOptions {
1221 column_name: String,
1222 source: datatypes::Error,
1223 #[snafu(implicit)]
1224 location: Location,
1225 },
1226
1227 #[snafu(display("Failed to decode arrow ipc record batches"))]
1228 DecodeArrowIpc {
1229 #[snafu(source)]
1230 error: arrow::error::ArrowError,
1231 #[snafu(implicit)]
1232 location: Location,
1233 },
1234
1235 #[snafu(display("Failed to cast default value, reason: {}", reason))]
1236 CastDefaultValue {
1237 reason: String,
1238 source: datatypes::Error,
1239 #[snafu(implicit)]
1240 location: Location,
1241 },
1242
1243 #[snafu(display("Unexpected: {}", reason))]
1244 Unexpected {
1245 reason: String,
1246 #[snafu(implicit)]
1247 location: Location,
1248 },
1249
1250 #[snafu(display("Failed to encode/decode flight message"))]
1251 FlightCodec {
1252 source: common_grpc::Error,
1253 #[snafu(implicit)]
1254 location: Location,
1255 },
1256
1257 #[snafu(display("Invalid index option"))]
1258 InvalidIndexOption {
1259 #[snafu(implicit)]
1260 location: Location,
1261 #[snafu(source)]
1262 error: datatypes::error::Error,
1263 },
1264
1265 #[snafu(display("Sql common error"))]
1266 SqlCommon {
1267 source: common_sql::error::Error,
1268 #[snafu(implicit)]
1269 location: Location,
1270 },
1271}
1272
1273impl ErrorExt for MetadataError {
1274 fn status_code(&self) -> StatusCode {
1275 match self {
1276 Self::SqlCommon { source, .. } => source.status_code(),
1277 _ => StatusCode::InvalidArguments,
1278 }
1279 }
1280
1281 fn as_any(&self) -> &dyn Any {
1282 self
1283 }
1284}
1285
1286fn set_column_fulltext_options(
1295 column_meta: &mut ColumnMetadata,
1296 column_name: &str,
1297 options: &FulltextOptions,
1298 current_options: Option<FulltextOptions>,
1299) -> Result<()> {
1300 if let Some(current_options) = current_options {
1301 ensure!(
1302 current_options.analyzer == options.analyzer
1303 && current_options.case_sensitive == options.case_sensitive,
1304 InvalidColumnOptionSnafu {
1305 column_name,
1306 msg: format!(
1307 "Cannot change analyzer or case_sensitive if FULLTEXT index is set before. Previous analyzer: {}, previous case_sensitive: {}",
1308 current_options.analyzer, current_options.case_sensitive
1309 ),
1310 }
1311 );
1312 }
1313
1314 column_meta
1315 .column_schema
1316 .set_fulltext_options(options)
1317 .context(SetFulltextOptionsSnafu { column_name })?;
1318
1319 Ok(())
1320}
1321
1322fn unset_column_fulltext_options(
1323 column_meta: &mut ColumnMetadata,
1324 column_name: &str,
1325 current_options: Option<FulltextOptions>,
1326) -> Result<()> {
1327 if let Some(mut current_options) = current_options
1328 && current_options.enable
1329 {
1330 current_options.enable = false;
1331 column_meta
1332 .column_schema
1333 .set_fulltext_options(¤t_options)
1334 .context(SetFulltextOptionsSnafu { column_name })?;
1335 } else {
1336 return InvalidColumnOptionSnafu {
1337 column_name,
1338 msg: "FULLTEXT index already disabled",
1339 }
1340 .fail();
1341 }
1342
1343 Ok(())
1344}
1345
1346#[cfg(test)]
1347mod test {
1348 use datatypes::prelude::ConcreteDataType;
1349 use datatypes::schema::{
1350 ColumnDefaultConstraint, ColumnSchema, FulltextAnalyzer, FulltextBackend,
1351 };
1352 use datatypes::value::Value;
1353
1354 use super::*;
1355
1356 fn create_builder() -> RegionMetadataBuilder {
1357 RegionMetadataBuilder::new(RegionId::new(1234, 5678))
1358 }
1359
1360 fn build_test_region_metadata() -> RegionMetadata {
1361 let mut builder = create_builder();
1362 builder
1363 .push_column_metadata(ColumnMetadata {
1364 column_schema: ColumnSchema::new("a", ConcreteDataType::int64_datatype(), false),
1365 semantic_type: SemanticType::Tag,
1366 column_id: 1,
1367 })
1368 .push_column_metadata(ColumnMetadata {
1369 column_schema: ColumnSchema::new("b", ConcreteDataType::float64_datatype(), false),
1370 semantic_type: SemanticType::Field,
1371 column_id: 2,
1372 })
1373 .push_column_metadata(ColumnMetadata {
1374 column_schema: ColumnSchema::new(
1375 "c",
1376 ConcreteDataType::timestamp_millisecond_datatype(),
1377 false,
1378 ),
1379 semantic_type: SemanticType::Timestamp,
1380 column_id: 3,
1381 })
1382 .primary_key(vec![1])
1383 .partition_expr_json(Some("".to_string()));
1384 builder.build().unwrap()
1385 }
1386
1387 #[test]
1388 fn test_region_metadata() {
1389 let region_metadata = build_test_region_metadata();
1390 assert_eq!("c", region_metadata.time_index_column().column_schema.name);
1391 assert_eq!(
1392 "a",
1393 region_metadata.column_by_id(1).unwrap().column_schema.name
1394 );
1395 assert_eq!(None, region_metadata.column_by_id(10));
1396 }
1397
1398 #[test]
1399 fn test_region_metadata_serde() {
1400 let region_metadata = build_test_region_metadata();
1401 let serialized = serde_json::to_string(®ion_metadata).unwrap();
1402 let deserialized: RegionMetadata = serde_json::from_str(&serialized).unwrap();
1403 assert_eq!(region_metadata, deserialized);
1404 }
1405
1406 #[test]
1407 fn test_column_metadata_validate() {
1408 let mut builder = create_builder();
1409 let col = ColumnMetadata {
1410 column_schema: ColumnSchema::new("ts", ConcreteDataType::string_datatype(), false),
1411 semantic_type: SemanticType::Timestamp,
1412 column_id: 1,
1413 };
1414
1415 builder.push_column_metadata(col);
1416 let err = builder.build().unwrap_err();
1417 assert!(
1418 err.to_string()
1419 .contains("column `ts` is not timestamp type"),
1420 "unexpected err: {err}",
1421 );
1422 }
1423
1424 #[test]
1425 fn test_empty_region_metadata() {
1426 let builder = create_builder();
1427 let err = builder.build().unwrap_err();
1428 assert!(
1430 err.to_string().contains("time index not found"),
1431 "unexpected err: {err}",
1432 );
1433 }
1434
1435 #[test]
1436 fn test_same_column_id() {
1437 let mut builder = create_builder();
1438 builder
1439 .push_column_metadata(ColumnMetadata {
1440 column_schema: ColumnSchema::new("a", ConcreteDataType::int64_datatype(), false),
1441 semantic_type: SemanticType::Tag,
1442 column_id: 1,
1443 })
1444 .push_column_metadata(ColumnMetadata {
1445 column_schema: ColumnSchema::new(
1446 "b",
1447 ConcreteDataType::timestamp_millisecond_datatype(),
1448 false,
1449 ),
1450 semantic_type: SemanticType::Timestamp,
1451 column_id: 1,
1452 });
1453 let err = builder.build().unwrap_err();
1454 assert!(
1455 err.to_string()
1456 .contains("column a and b have the same column id"),
1457 "unexpected err: {err}",
1458 );
1459 }
1460
1461 #[test]
1462 fn test_duplicate_time_index() {
1463 let mut builder = create_builder();
1464 builder
1465 .push_column_metadata(ColumnMetadata {
1466 column_schema: ColumnSchema::new(
1467 "a",
1468 ConcreteDataType::timestamp_millisecond_datatype(),
1469 false,
1470 ),
1471 semantic_type: SemanticType::Timestamp,
1472 column_id: 1,
1473 })
1474 .push_column_metadata(ColumnMetadata {
1475 column_schema: ColumnSchema::new(
1476 "b",
1477 ConcreteDataType::timestamp_millisecond_datatype(),
1478 false,
1479 ),
1480 semantic_type: SemanticType::Timestamp,
1481 column_id: 2,
1482 });
1483 let err = builder.build().unwrap_err();
1484 assert!(
1485 err.to_string().contains("expect only one time index"),
1486 "unexpected err: {err}",
1487 );
1488 }
1489
1490 #[test]
1491 fn test_unknown_primary_key() {
1492 let mut builder = create_builder();
1493 builder
1494 .push_column_metadata(ColumnMetadata {
1495 column_schema: ColumnSchema::new("a", ConcreteDataType::string_datatype(), false),
1496 semantic_type: SemanticType::Tag,
1497 column_id: 1,
1498 })
1499 .push_column_metadata(ColumnMetadata {
1500 column_schema: ColumnSchema::new(
1501 "b",
1502 ConcreteDataType::timestamp_millisecond_datatype(),
1503 false,
1504 ),
1505 semantic_type: SemanticType::Timestamp,
1506 column_id: 2,
1507 })
1508 .primary_key(vec![3]);
1509 let err = builder.build().unwrap_err();
1510 assert!(
1511 err.to_string().contains("unknown column id 3"),
1512 "unexpected err: {err}",
1513 );
1514 }
1515
1516 #[test]
1517 fn test_same_primary_key() {
1518 let mut builder = create_builder();
1519 builder
1520 .push_column_metadata(ColumnMetadata {
1521 column_schema: ColumnSchema::new("a", ConcreteDataType::string_datatype(), false),
1522 semantic_type: SemanticType::Tag,
1523 column_id: 1,
1524 })
1525 .push_column_metadata(ColumnMetadata {
1526 column_schema: ColumnSchema::new(
1527 "b",
1528 ConcreteDataType::timestamp_millisecond_datatype(),
1529 false,
1530 ),
1531 semantic_type: SemanticType::Timestamp,
1532 column_id: 2,
1533 })
1534 .primary_key(vec![1, 1]);
1535 let err = builder.build().unwrap_err();
1536 assert!(
1537 err.to_string()
1538 .contains("duplicate column a in primary key"),
1539 "unexpected err: {err}",
1540 );
1541 }
1542
1543 #[test]
1544 fn test_in_time_index() {
1545 let mut builder = create_builder();
1546 builder
1547 .push_column_metadata(ColumnMetadata {
1548 column_schema: ColumnSchema::new(
1549 "ts",
1550 ConcreteDataType::timestamp_millisecond_datatype(),
1551 false,
1552 ),
1553 semantic_type: SemanticType::Timestamp,
1554 column_id: 1,
1555 })
1556 .primary_key(vec![1]);
1557 let err = builder.build().unwrap_err();
1558 assert!(
1559 err.to_string()
1560 .contains("column ts is already a time index column"),
1561 "unexpected err: {err}",
1562 );
1563 }
1564
1565 #[test]
1566 fn test_nullable_time_index() {
1567 let mut builder = create_builder();
1568 builder.push_column_metadata(ColumnMetadata {
1569 column_schema: ColumnSchema::new(
1570 "ts",
1571 ConcreteDataType::timestamp_millisecond_datatype(),
1572 true,
1573 ),
1574 semantic_type: SemanticType::Timestamp,
1575 column_id: 1,
1576 });
1577 let err = builder.build().unwrap_err();
1578 assert!(
1579 err.to_string()
1580 .contains("time index column ts must be NOT NULL"),
1581 "unexpected err: {err}",
1582 );
1583 }
1584
1585 #[test]
1586 fn test_primary_key_semantic_type() {
1587 let mut builder = create_builder();
1588 builder
1589 .push_column_metadata(ColumnMetadata {
1590 column_schema: ColumnSchema::new(
1591 "ts",
1592 ConcreteDataType::timestamp_millisecond_datatype(),
1593 false,
1594 ),
1595 semantic_type: SemanticType::Timestamp,
1596 column_id: 1,
1597 })
1598 .push_column_metadata(ColumnMetadata {
1599 column_schema: ColumnSchema::new("a", ConcreteDataType::float64_datatype(), true),
1600 semantic_type: SemanticType::Field,
1601 column_id: 2,
1602 })
1603 .primary_key(vec![2]);
1604 let err = builder.build().unwrap_err();
1605 assert!(
1606 err.to_string()
1607 .contains("semantic type of column a should be Tag, not Field"),
1608 "unexpected err: {err}",
1609 );
1610 }
1611
1612 #[test]
1613 fn test_primary_key_tag_num() {
1614 let mut builder = create_builder();
1615 builder
1616 .push_column_metadata(ColumnMetadata {
1617 column_schema: ColumnSchema::new(
1618 "ts",
1619 ConcreteDataType::timestamp_millisecond_datatype(),
1620 false,
1621 ),
1622 semantic_type: SemanticType::Timestamp,
1623 column_id: 1,
1624 })
1625 .push_column_metadata(ColumnMetadata {
1626 column_schema: ColumnSchema::new("a", ConcreteDataType::string_datatype(), true),
1627 semantic_type: SemanticType::Tag,
1628 column_id: 2,
1629 })
1630 .push_column_metadata(ColumnMetadata {
1631 column_schema: ColumnSchema::new("b", ConcreteDataType::string_datatype(), true),
1632 semantic_type: SemanticType::Tag,
1633 column_id: 3,
1634 })
1635 .primary_key(vec![2]);
1636 let err = builder.build().unwrap_err();
1637 assert!(
1638 err.to_string()
1639 .contains("number of primary key columns 1 not equal to tag columns 2"),
1640 "unexpected err: {err}",
1641 );
1642 }
1643
1644 #[test]
1645 fn test_bump_version() {
1646 let mut region_metadata = build_test_region_metadata();
1647 let mut builder = RegionMetadataBuilder::from_existing(region_metadata.clone());
1648 builder.bump_version();
1649 let new_meta = builder.build().unwrap();
1650 region_metadata.schema_version += 1;
1651 assert_eq!(region_metadata, new_meta);
1652 }
1653
1654 fn new_column_metadata(name: &str, is_tag: bool, column_id: ColumnId) -> ColumnMetadata {
1655 let semantic_type = if is_tag {
1656 SemanticType::Tag
1657 } else {
1658 SemanticType::Field
1659 };
1660 ColumnMetadata {
1661 column_schema: ColumnSchema::new(name, ConcreteDataType::string_datatype(), true),
1662 semantic_type,
1663 column_id,
1664 }
1665 }
1666
1667 fn check_columns(metadata: &RegionMetadata, names: &[&str]) {
1668 let actual: Vec<_> = metadata
1669 .column_metadatas
1670 .iter()
1671 .map(|col| &col.column_schema.name)
1672 .collect();
1673 assert_eq!(names, actual);
1674 }
1675
1676 fn get_columns_default_constraint(
1677 metadata: &RegionMetadata,
1678 name: String,
1679 ) -> Option<Option<&ColumnDefaultConstraint>> {
1680 metadata.column_metadatas.iter().find_map(|col| {
1681 if col.column_schema.name == name {
1682 Some(col.column_schema.default_constraint())
1683 } else {
1684 None
1685 }
1686 })
1687 }
1688
1689 #[test]
1690 fn test_alter() {
1691 let metadata = build_test_region_metadata();
1693 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1694 builder
1696 .alter(AlterKind::AddColumns {
1697 columns: vec![AddColumn {
1698 column_metadata: new_column_metadata("d", true, 4),
1699 location: None,
1700 }],
1701 })
1702 .unwrap();
1703 let metadata = builder.build().unwrap();
1704 check_columns(&metadata, &["a", "b", "c", "d"]);
1705 assert_eq!([1, 4], &metadata.primary_key[..]);
1706
1707 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1708 builder
1709 .alter(AlterKind::AddColumns {
1710 columns: vec![AddColumn {
1711 column_metadata: new_column_metadata("e", false, 5),
1712 location: Some(AddColumnLocation::First),
1713 }],
1714 })
1715 .unwrap();
1716 let metadata = builder.build().unwrap();
1717 check_columns(&metadata, &["e", "a", "b", "c", "d"]);
1718
1719 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1720 builder
1721 .alter(AlterKind::AddColumns {
1722 columns: vec![AddColumn {
1723 column_metadata: new_column_metadata("f", false, 6),
1724 location: Some(AddColumnLocation::After {
1725 column_name: "b".to_string(),
1726 }),
1727 }],
1728 })
1729 .unwrap();
1730 let metadata = builder.build().unwrap();
1731 check_columns(&metadata, &["e", "a", "b", "f", "c", "d"]);
1732
1733 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1734 builder
1735 .alter(AlterKind::AddColumns {
1736 columns: vec![AddColumn {
1737 column_metadata: new_column_metadata("g", false, 7),
1738 location: Some(AddColumnLocation::After {
1739 column_name: "d".to_string(),
1740 }),
1741 }],
1742 })
1743 .unwrap();
1744 let metadata = builder.build().unwrap();
1745 check_columns(&metadata, &["e", "a", "b", "f", "c", "d", "g"]);
1746
1747 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1748 builder
1749 .alter(AlterKind::DropColumns {
1750 names: vec!["g".to_string(), "e".to_string()],
1751 })
1752 .unwrap();
1753 let metadata = builder.build().unwrap();
1754 check_columns(&metadata, &["a", "b", "f", "c", "d"]);
1755
1756 let mut builder = RegionMetadataBuilder::from_existing(metadata.clone());
1757 builder
1758 .alter(AlterKind::DropColumns {
1759 names: vec!["a".to_string()],
1760 })
1761 .unwrap();
1762 let err = builder.build().unwrap_err();
1764 assert_eq!(StatusCode::InvalidArguments, err.status_code());
1765
1766 let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
1767 let mut column_metadata = new_column_metadata("g", false, 8);
1768 let default_constraint = Some(ColumnDefaultConstraint::Value(Value::from("g")));
1769 column_metadata.column_schema = column_metadata
1770 .column_schema
1771 .with_default_constraint(default_constraint.clone())
1772 .unwrap();
1773 builder
1774 .alter(AlterKind::AddColumns {
1775 columns: vec![AddColumn {
1776 column_metadata,
1777 location: None,
1778 }],
1779 })
1780 .unwrap();
1781 let metadata = builder.build().unwrap();
1782 assert_eq!(
1783 get_columns_default_constraint(&metadata, "g".to_string()).unwrap(),
1784 default_constraint.as_ref()
1785 );
1786 check_columns(&metadata, &["a", "b", "f", "c", "d", "g"]);
1787
1788 let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
1789 builder
1790 .alter(AlterKind::DropDefaults {
1791 names: vec!["g".to_string()],
1792 })
1793 .unwrap();
1794 let metadata = builder.build().unwrap();
1795 assert_eq!(
1796 get_columns_default_constraint(&metadata, "g".to_string()).unwrap(),
1797 None
1798 );
1799 check_columns(&metadata, &["a", "b", "f", "c", "d", "g"]);
1800
1801 let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
1802 builder
1803 .alter(AlterKind::DropColumns {
1804 names: vec!["g".to_string()],
1805 })
1806 .unwrap();
1807 let metadata = builder.build().unwrap();
1808 check_columns(&metadata, &["a", "b", "f", "c", "d"]);
1809
1810 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1811 builder
1812 .alter(AlterKind::ModifyColumnTypes {
1813 columns: vec![ModifyColumnType {
1814 column_name: "b".to_string(),
1815 target_type: ConcreteDataType::string_datatype(),
1816 }],
1817 })
1818 .unwrap();
1819 let metadata = builder.build().unwrap();
1820 check_columns(&metadata, &["a", "b", "f", "c", "d"]);
1821 let b_type = &metadata
1822 .column_by_name("b")
1823 .unwrap()
1824 .column_schema
1825 .data_type;
1826 assert_eq!(ConcreteDataType::string_datatype(), *b_type);
1827
1828 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1829 builder
1830 .alter(AlterKind::SetIndexes {
1831 options: vec![SetIndexOption::Fulltext {
1832 column_name: "b".to_string(),
1833 options: FulltextOptions::new_unchecked(
1834 true,
1835 FulltextAnalyzer::Chinese,
1836 true,
1837 FulltextBackend::Bloom,
1838 1000,
1839 0.01,
1840 ),
1841 }],
1842 })
1843 .unwrap();
1844 let metadata = builder.build().unwrap();
1845 let a_fulltext_options = metadata
1846 .column_by_name("b")
1847 .unwrap()
1848 .column_schema
1849 .fulltext_options()
1850 .unwrap()
1851 .unwrap();
1852 assert!(a_fulltext_options.enable);
1853 assert_eq!(
1854 datatypes::schema::FulltextAnalyzer::Chinese,
1855 a_fulltext_options.analyzer
1856 );
1857 assert!(a_fulltext_options.case_sensitive);
1858
1859 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1860 builder
1861 .alter(AlterKind::UnsetIndexes {
1862 options: vec![UnsetIndexOption::Fulltext {
1863 column_name: "b".to_string(),
1864 }],
1865 })
1866 .unwrap();
1867 let metadata = builder.build().unwrap();
1868 let a_fulltext_options = metadata
1869 .column_by_name("b")
1870 .unwrap()
1871 .column_schema
1872 .fulltext_options()
1873 .unwrap()
1874 .unwrap();
1875 assert!(!a_fulltext_options.enable);
1876 assert_eq!(
1877 datatypes::schema::FulltextAnalyzer::Chinese,
1878 a_fulltext_options.analyzer
1879 );
1880 assert!(a_fulltext_options.case_sensitive);
1881 }
1882
1883 #[test]
1884 fn test_add_if_not_exists() {
1885 let metadata = build_test_region_metadata();
1887 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1888 builder
1890 .alter(AlterKind::AddColumns {
1891 columns: vec![
1892 AddColumn {
1893 column_metadata: new_column_metadata("d", true, 4),
1894 location: None,
1895 },
1896 AddColumn {
1897 column_metadata: new_column_metadata("d", true, 4),
1898 location: None,
1899 },
1900 ],
1901 })
1902 .unwrap();
1903 let metadata = builder.build().unwrap();
1904 check_columns(&metadata, &["a", "b", "c", "d"]);
1905 assert_eq!([1, 4], &metadata.primary_key[..]);
1906
1907 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1908 builder
1910 .alter(AlterKind::AddColumns {
1911 columns: vec![AddColumn {
1912 column_metadata: new_column_metadata("b", false, 2),
1913 location: None,
1914 }],
1915 })
1916 .unwrap();
1917 let metadata = builder.build().unwrap();
1918 check_columns(&metadata, &["a", "b", "c", "d"]);
1919 }
1920
1921 #[test]
1922 fn test_add_column_with_inverted_index() {
1923 let metadata = build_test_region_metadata();
1927 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1928 let mut col = new_column_metadata("d", true, 4);
1930 col.column_schema.set_inverted_index(true);
1931 builder
1932 .alter(AlterKind::AddColumns {
1933 columns: vec![
1934 AddColumn {
1935 column_metadata: col,
1936 location: None,
1937 },
1938 AddColumn {
1939 column_metadata: new_column_metadata("e", true, 5),
1940 location: None,
1941 },
1942 ],
1943 })
1944 .unwrap();
1945 let metadata = builder.build().unwrap();
1946 check_columns(&metadata, &["a", "b", "c", "d", "e"]);
1947 assert_eq!([1, 4, 5], &metadata.primary_key[..]);
1948 let column_metadata = metadata.column_by_name("a").unwrap();
1949 assert!(!column_metadata.column_schema.is_inverted_indexed());
1950 let column_metadata = metadata.column_by_name("b").unwrap();
1951 assert!(!column_metadata.column_schema.is_inverted_indexed());
1952 let column_metadata = metadata.column_by_name("c").unwrap();
1953 assert!(!column_metadata.column_schema.is_inverted_indexed());
1954 let column_metadata = metadata.column_by_name("d").unwrap();
1955 assert!(column_metadata.column_schema.is_inverted_indexed());
1956 let column_metadata = metadata.column_by_name("e").unwrap();
1957 assert!(!column_metadata.column_schema.is_inverted_indexed());
1958 }
1959
1960 #[test]
1961 fn test_drop_if_exists() {
1962 let metadata = build_test_region_metadata();
1964 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1965 builder
1967 .alter(AlterKind::AddColumns {
1968 columns: vec![
1969 AddColumn {
1970 column_metadata: new_column_metadata("d", false, 4),
1971 location: None,
1972 },
1973 AddColumn {
1974 column_metadata: new_column_metadata("e", false, 5),
1975 location: None,
1976 },
1977 ],
1978 })
1979 .unwrap();
1980 let metadata = builder.build().unwrap();
1981 check_columns(&metadata, &["a", "b", "c", "d", "e"]);
1982
1983 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1984 builder
1985 .alter(AlterKind::DropColumns {
1986 names: vec!["b".to_string(), "b".to_string()],
1987 })
1988 .unwrap();
1989 let metadata = builder.build().unwrap();
1990 check_columns(&metadata, &["a", "c", "d", "e"]);
1991
1992 let mut builder = RegionMetadataBuilder::from_existing(metadata);
1993 builder
1994 .alter(AlterKind::DropColumns {
1995 names: vec!["b".to_string(), "e".to_string()],
1996 })
1997 .unwrap();
1998 let metadata = builder.build().unwrap();
1999 check_columns(&metadata, &["a", "c", "d"]);
2000 }
2001
2002 #[test]
2003 fn test_invalid_column_name() {
2004 let mut builder = create_builder();
2005 builder.push_column_metadata(ColumnMetadata {
2006 column_schema: ColumnSchema::new(
2007 "__sequence",
2008 ConcreteDataType::timestamp_millisecond_datatype(),
2009 false,
2010 ),
2011 semantic_type: SemanticType::Timestamp,
2012 column_id: 1,
2013 });
2014 let err = builder.build().unwrap_err();
2015 assert!(
2016 err.to_string()
2017 .contains("internal column name that can not be used"),
2018 "unexpected err: {err}",
2019 );
2020 }
2021
2022 #[test]
2023 fn test_allow_internal_column_name() {
2024 let mut builder = create_builder();
2025 builder
2026 .push_column_metadata(ColumnMetadata {
2027 column_schema: ColumnSchema::new(
2028 "__primary_key",
2029 ConcreteDataType::string_datatype(),
2030 false,
2031 ),
2032 semantic_type: SemanticType::Tag,
2033 column_id: 1,
2034 })
2035 .push_column_metadata(ColumnMetadata {
2036 column_schema: ColumnSchema::new(
2037 "ts",
2038 ConcreteDataType::timestamp_millisecond_datatype(),
2039 false,
2040 ),
2041 semantic_type: SemanticType::Timestamp,
2042 column_id: 2,
2043 })
2044 .primary_key(vec![1]);
2045
2046 let metadata = builder.build_without_validation().unwrap();
2047 assert_eq!(
2048 "__primary_key",
2049 metadata.column_metadatas[0].column_schema.name
2050 );
2051 }
2052
2053 #[test]
2054 fn test_build_without_validation() {
2055 let mut builder = create_builder();
2057 builder
2058 .push_column_metadata(ColumnMetadata {
2059 column_schema: ColumnSchema::new(
2060 "ts",
2061 ConcreteDataType::timestamp_millisecond_datatype(),
2062 false,
2063 ),
2064 semantic_type: SemanticType::Timestamp,
2065 column_id: 1,
2066 })
2067 .push_column_metadata(ColumnMetadata {
2068 column_schema: ColumnSchema::new(
2069 "field",
2070 ConcreteDataType::string_datatype(),
2071 true,
2072 ),
2073 semantic_type: SemanticType::Field,
2074 column_id: 2,
2075 })
2076 .primary_key(vec![2]);
2077
2078 let metadata = builder.build_without_validation().unwrap();
2080 assert_eq!(vec![2], metadata.primary_key);
2081
2082 let mut builder = create_builder();
2084 builder
2085 .push_column_metadata(ColumnMetadata {
2086 column_schema: ColumnSchema::new(
2087 "ts",
2088 ConcreteDataType::timestamp_millisecond_datatype(),
2089 false,
2090 ),
2091 semantic_type: SemanticType::Timestamp,
2092 column_id: 1,
2093 })
2094 .push_column_metadata(ColumnMetadata {
2095 column_schema: ColumnSchema::new(
2096 "field",
2097 ConcreteDataType::string_datatype(),
2098 true,
2099 ),
2100 semantic_type: SemanticType::Field,
2101 column_id: 2,
2102 })
2103 .primary_key(vec![2]);
2104 let err = builder.build().unwrap_err();
2105 assert!(
2106 err.to_string()
2107 .contains("semantic type of column field should be Tag"),
2108 "unexpected err: {err}"
2109 );
2110 }
2111
2112 #[test]
2113 fn test_debug_for_column_metadata() {
2114 let region_metadata = build_test_region_metadata();
2115 let formatted = format!("{:?}", region_metadata);
2116 assert_eq!(
2117 formatted,
2118 "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(\"\") }"
2119 );
2120 }
2121
2122 #[test]
2123 fn test_region_metadata_deserialize_default_primary_key_encoding() {
2124 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}"#;
2125 let deserialized: RegionMetadata = serde_json::from_str(serialize).unwrap();
2126 assert_eq!(deserialized.primary_key_encoding, PrimaryKeyEncoding::Dense);
2127
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,"primary_key_encoding":"sparse"}"#;
2129 let deserialized: RegionMetadata = serde_json::from_str(serialize).unwrap();
2130 assert_eq!(
2131 deserialized.primary_key_encoding,
2132 PrimaryKeyEncoding::Sparse
2133 );
2134 }
2135}