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