1use std::collections::{HashMap, HashSet};
16use std::sync::Arc;
17
18use chrono::{DateTime, Utc};
19use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME};
20use common_macro::ToMetaBuilder;
21use common_query::AddColumnLocation;
22use datafusion_expr::TableProviderFilterPushDown;
23pub use datatypes::error::{Error as ConvertError, Result as ConvertResult};
24use datatypes::schema::{
25 ColumnSchema, FulltextOptions, Schema, SchemaBuilder, SchemaRef, SkippingIndexOptions,
26};
27use derive_builder::Builder;
28use serde::{Deserialize, Deserializer, Serialize};
29use snafu::{OptionExt, ResultExt, ensure};
30use store_api::metric_engine_consts::PHYSICAL_TABLE_METADATA_KEY;
31use store_api::mito_engine_options::{
32 APPEND_MODE_KEY, COMPACTION_TYPE, COMPACTION_TYPE_TWCS, MERGE_MODE_KEY, SST_FORMAT_KEY,
33};
34use store_api::region_request::{SetRegionOption, UnsetRegionOption};
35use store_api::storage::{ColumnDescriptor, ColumnDescriptorBuilder, ColumnId};
36
37use crate::error::{self, Result};
38use crate::requests::{
39 AddColumnRequest, AlterKind, ModifyColumnTypeRequest, REPARTITION_COLUMN_HINT_KEY,
40 SetDefaultRequest, SetIndexOption, TableOptions, UnsetIndexOption,
41};
42use crate::table_reference::TableReference;
43
44pub type TableId = u32;
45pub type TableVersion = u64;
46
47#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
50pub enum FilterPushDownType {
51 Unsupported,
53 Inexact,
58 Exact,
62}
63
64impl From<TableProviderFilterPushDown> for FilterPushDownType {
65 fn from(value: TableProviderFilterPushDown) -> Self {
66 match value {
67 TableProviderFilterPushDown::Unsupported => FilterPushDownType::Unsupported,
68 TableProviderFilterPushDown::Inexact => FilterPushDownType::Inexact,
69 TableProviderFilterPushDown::Exact => FilterPushDownType::Exact,
70 }
71 }
72}
73
74impl From<FilterPushDownType> for TableProviderFilterPushDown {
75 fn from(value: FilterPushDownType) -> Self {
76 match value {
77 FilterPushDownType::Unsupported => TableProviderFilterPushDown::Unsupported,
78 FilterPushDownType::Inexact => TableProviderFilterPushDown::Inexact,
79 FilterPushDownType::Exact => TableProviderFilterPushDown::Exact,
80 }
81 }
82}
83
84#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
86pub enum TableType {
87 Base,
89 View,
91 Temporary,
93}
94
95impl std::fmt::Display for TableType {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 TableType::Base => f.write_str("BASE TABLE"),
99 TableType::Temporary => f.write_str("TEMPORARY"),
100 TableType::View => f.write_str("VIEW"),
101 }
102 }
103}
104
105impl From<TableType> for datafusion::datasource::TableType {
106 fn from(t: TableType) -> datafusion::datasource::TableType {
107 match t {
108 TableType::Base => datafusion::datasource::TableType::Base,
109 TableType::View => datafusion::datasource::TableType::View,
110 TableType::Temporary => datafusion::datasource::TableType::Temporary,
111 }
112 }
113}
114
115#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
117pub struct TableIdent {
118 pub table_id: TableId,
120 pub version: TableVersion,
123}
124
125#[derive(Clone, Debug, Builder, PartialEq, Eq, ToMetaBuilder, Serialize)]
129#[builder(pattern = "mutable", custom_constructor)]
130pub struct TableMeta {
131 pub schema: SchemaRef,
132 pub primary_key_indices: Vec<usize>,
135 #[builder(default = "self.default_value_indices()?")]
136 pub value_indices: Vec<usize>,
137 #[builder(default, setter(into))]
138 pub engine: String,
139 pub next_column_id: ColumnId,
140 #[builder(default)]
142 pub options: TableOptions,
143 #[builder(default = "Utc::now()")]
144 pub created_on: DateTime<Utc>,
145 #[builder(default = "self.default_updated_on()")]
146 pub updated_on: DateTime<Utc>,
147 #[builder(default = "Vec::new()")]
148 pub partition_key_indices: Vec<usize>,
149 #[builder(default = "Vec::new()")]
150 pub column_ids: Vec<ColumnId>,
151}
152
153impl TableMeta {
154 pub fn empty() -> Self {
155 Self {
156 schema: Arc::new(Schema::new(vec![])),
157 primary_key_indices: vec![],
158 value_indices: vec![],
159 engine: "".to_string(),
160 next_column_id: 0,
161 options: TableOptions::default(),
162 created_on: Utc::now(),
163 updated_on: Utc::now(),
164 partition_key_indices: vec![],
165 column_ids: vec![],
166 }
167 }
168}
169
170impl<'de> Deserialize<'de> for TableMeta {
171 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
172 where
173 D: Deserializer<'de>,
174 {
175 #[derive(Deserialize)]
176 struct RawTableMeta {
177 schema: SchemaRef,
178 primary_key_indices: Vec<usize>,
179 value_indices: Vec<usize>,
180 engine: String,
181 next_column_id: ColumnId,
182 options: TableOptions,
183 created_on: DateTime<Utc>,
184 updated_on: Option<DateTime<Utc>>,
185 #[serde(default)]
186 partition_key_indices: Vec<usize>,
187 #[serde(default)]
188 column_ids: Vec<ColumnId>,
189 }
190
191 let RawTableMeta {
192 schema,
193 primary_key_indices,
194 value_indices,
195 engine,
196 next_column_id,
197 options,
198 created_on,
199 updated_on,
200 partition_key_indices,
201 column_ids,
202 } = RawTableMeta::deserialize(deserializer)?;
203
204 Ok(Self {
205 schema,
206 primary_key_indices,
207 value_indices,
208 engine,
209 next_column_id,
210 options,
211 created_on,
212 updated_on: updated_on.unwrap_or(created_on),
213 partition_key_indices,
214 column_ids,
215 })
216 }
217}
218
219impl TableMetaBuilder {
220 #[cfg(any(test, feature = "testing"))]
222 pub fn empty() -> Self {
223 Self {
224 schema: None,
225 primary_key_indices: None,
226 value_indices: None,
227 engine: None,
228 next_column_id: None,
229 options: None,
230 created_on: None,
231 updated_on: None,
232 partition_key_indices: None,
233 column_ids: None,
234 }
235 }
236}
237
238impl TableMetaBuilder {
239 fn default_value_indices(&self) -> std::result::Result<Vec<usize>, String> {
240 match (&self.primary_key_indices, &self.schema) {
241 (Some(v), Some(schema)) => {
242 let column_schemas = schema.column_schemas();
243 Ok((0..column_schemas.len())
244 .filter(|idx| !v.contains(idx))
245 .collect())
246 }
247 _ => Err("Missing primary_key_indices or schema to create value_indices".to_string()),
248 }
249 }
250
251 fn default_updated_on(&self) -> DateTime<Utc> {
252 self.created_on.unwrap_or_default()
253 }
254
255 pub fn new_external_table() -> Self {
256 Self {
257 schema: None,
258 primary_key_indices: Some(Vec::new()),
259 value_indices: Some(Vec::new()),
260 engine: None,
261 next_column_id: Some(0),
262 options: None,
263 created_on: None,
264 updated_on: None,
265 partition_key_indices: None,
266 column_ids: None,
267 }
268 }
269}
270
271struct SplitResult<'a> {
273 columns_at_first: Vec<&'a AddColumnRequest>,
275 columns_at_after: HashMap<String, Vec<&'a AddColumnRequest>>,
277 columns_at_last: Vec<&'a AddColumnRequest>,
279 column_names: Vec<String>,
281}
282
283impl TableMeta {
284 pub fn row_key_column_names(&self) -> impl Iterator<Item = &String> {
285 let columns_schemas = &self.schema.column_schemas();
286 self.primary_key_indices
287 .iter()
288 .map(|idx| &columns_schemas[*idx].name)
289 }
290
291 pub fn field_column_names(&self) -> impl Iterator<Item = &String> {
292 let columns_schemas = self.schema.column_schemas();
294 let primary_key_indices = &self.primary_key_indices;
295 columns_schemas
296 .iter()
297 .enumerate()
298 .filter(|(i, cs)| !primary_key_indices.contains(i) && !cs.is_time_index())
299 .map(|(_, cs)| &cs.name)
300 }
301
302 pub fn partition_column_names(&self) -> impl Iterator<Item = &String> {
303 let columns_schemas = &self.schema.column_schemas();
304 self.partition_key_indices
305 .iter()
306 .map(|idx| &columns_schemas[*idx].name)
307 }
308
309 pub fn partition_columns(&self) -> impl Iterator<Item = &ColumnSchema> {
310 self.partition_key_indices
311 .iter()
312 .map(|idx| &self.schema.column_schemas()[*idx])
313 }
314
315 pub fn builder_with_alter_kind(
319 &self,
320 table_name: &str,
321 alter_kind: &AlterKind,
322 ) -> Result<TableMetaBuilder> {
323 let mut builder = match alter_kind {
324 AlterKind::AddColumns { columns } => self.add_columns(table_name, columns),
325 AlterKind::DropColumns { names } => self.remove_columns(table_name, names),
326 AlterKind::ModifyColumnTypes { columns } => {
327 self.modify_column_types(table_name, columns)
328 }
329 AlterKind::RenameTable { .. } => Ok(self.new_meta_builder()),
331 AlterKind::SetTableOptions { options } => self.set_table_options(options),
332 AlterKind::UnsetTableOptions { keys } => self.unset_table_options(keys),
333 AlterKind::SetRepartitionColumnHint { column_name } => {
334 self.set_repartition_column_hint(table_name, column_name)
335 }
336 AlterKind::UnsetRepartitionColumnHint => self.unset_repartition_column_hint(),
337 AlterKind::SetIndexes { options } => self.set_indexes(table_name, options),
338 AlterKind::UnsetIndexes { options } => self.unset_indexes(table_name, options),
339 AlterKind::DropDefaults { names } => self.drop_defaults(table_name, names),
340 AlterKind::SetDefaults { defaults } => self.set_defaults(table_name, defaults),
341 }?;
342 let _ = builder.updated_on(Utc::now());
343 Ok(builder)
344 }
345
346 fn set_table_options(&self, requests: &[SetRegionOption]) -> Result<TableMetaBuilder> {
348 let mut new_options = self.options.clone();
349
350 for request in requests {
351 match request {
352 SetRegionOption::Ttl(new_ttl) => {
353 new_options.ttl = *new_ttl;
354 }
355 SetRegionOption::Twsc(key, value) => {
356 if !value.is_empty() {
357 new_options.extra_options.insert(key.clone(), value.clone());
358 new_options.extra_options.insert(
360 COMPACTION_TYPE.to_string(),
361 COMPACTION_TYPE_TWCS.to_string(),
362 );
363 } else {
364 new_options.extra_options.remove(key.as_str());
366 }
367 }
368 SetRegionOption::Format(value) => {
369 new_options
370 .extra_options
371 .insert(SST_FORMAT_KEY.to_string(), value.clone());
372 }
373 SetRegionOption::AppendMode(value) => {
374 new_options
375 .extra_options
376 .insert(APPEND_MODE_KEY.to_string(), value.to_string());
377 if *value {
378 new_options.extra_options.remove(MERGE_MODE_KEY);
379 }
380 }
381 }
382 }
383 let mut builder = self.new_meta_builder();
384 builder.options(new_options);
385
386 Ok(builder)
387 }
388
389 fn unset_table_options(&self, requests: &[UnsetRegionOption]) -> Result<TableMetaBuilder> {
390 let requests = requests.iter().map(Into::into).collect::<Vec<_>>();
391 self.set_table_options(&requests)
392 }
393
394 fn set_repartition_column_hint(
395 &self,
396 table_name: &str,
397 column_name: &str,
398 ) -> Result<TableMetaBuilder> {
399 let column_name = column_name.trim();
400 ensure!(
401 !column_name.is_empty() && !column_name.contains(','),
402 error::InvalidAlterRequestSnafu {
403 table: table_name,
404 err: format!("{REPARTITION_COLUMN_HINT_KEY} expects exactly one column name"),
405 }
406 );
407
408 ensure!(
409 self.partition_key_indices.is_empty(),
410 error::InvalidAlterRequestSnafu {
411 table: table_name,
412 err: format!(
413 "cannot set {REPARTITION_COLUMN_HINT_KEY} on a table with partition metadata"
414 ),
415 }
416 );
417
418 let column_index = self
419 .schema
420 .column_index_by_name(column_name)
421 .with_context(|| error::ColumnNotExistsSnafu {
422 column_name,
423 table_name,
424 })?;
425
426 if let Some(time_index) = self.schema.timestamp_index() {
427 ensure!(
428 column_index != time_index,
429 error::InvalidAlterRequestSnafu {
430 table: table_name,
431 err: format!(
432 "cannot set {REPARTITION_COLUMN_HINT_KEY} to the time index column"
433 ),
434 }
435 );
436 }
437
438 let mut new_options = self.options.clone();
439 new_options.extra_options.insert(
440 REPARTITION_COLUMN_HINT_KEY.to_string(),
441 column_name.to_string(),
442 );
443
444 let mut builder = self.new_meta_builder();
445 builder.options(new_options);
446 Ok(builder)
447 }
448
449 fn unset_repartition_column_hint(&self) -> Result<TableMetaBuilder> {
450 let mut new_options = self.options.clone();
451 new_options
452 .extra_options
453 .remove(REPARTITION_COLUMN_HINT_KEY);
454
455 let mut builder = self.new_meta_builder();
456 builder.options(new_options);
457 Ok(builder)
458 }
459
460 fn set_indexes(
461 &self,
462 table_name: &str,
463 requests: &[SetIndexOption],
464 ) -> Result<TableMetaBuilder> {
465 let table_schema = &self.schema;
466 let mut set_index_options: HashMap<&str, Vec<_>> = HashMap::new();
467 for request in requests {
468 let column_name = request.column_name();
469 table_schema
470 .column_index_by_name(column_name)
471 .with_context(|| error::ColumnNotExistsSnafu {
472 column_name,
473 table_name,
474 })?;
475 set_index_options
476 .entry(column_name)
477 .or_default()
478 .push(request);
479 }
480
481 let mut meta_builder = self.new_meta_builder();
482 let mut columns: Vec<_> = Vec::with_capacity(table_schema.column_schemas().len());
483 for mut column in table_schema.column_schemas().iter().cloned() {
484 if let Some(request) = set_index_options.get(column.name.as_str()) {
485 for request in request {
486 self.set_index(&mut column, request)?;
487 }
488 }
489 columns.push(column);
490 }
491
492 let mut builder = SchemaBuilder::try_from_columns(columns)
493 .with_context(|_| error::SchemaBuildSnafu {
494 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
495 })?
496 .version(table_schema.version() + 1);
497
498 for (k, v) in table_schema.metadata().iter() {
499 builder = builder.add_metadata(k, v);
500 }
501
502 let new_schema = builder.build().with_context(|_| {
503 let column_names = requests
504 .iter()
505 .map(|request| request.column_name())
506 .collect::<Vec<_>>();
507 error::SchemaBuildSnafu {
508 msg: format!(
509 "Table {table_name} cannot set index options with columns {column_names:?}",
510 ),
511 }
512 })?;
513 let _ = meta_builder
514 .schema(Arc::new(new_schema))
515 .primary_key_indices(self.primary_key_indices.clone());
516
517 Ok(meta_builder)
518 }
519
520 fn unset_indexes(
521 &self,
522 table_name: &str,
523 requests: &[UnsetIndexOption],
524 ) -> Result<TableMetaBuilder> {
525 let table_schema = &self.schema;
526 let mut set_index_options: HashMap<&str, Vec<_>> = HashMap::new();
527 for request in requests {
528 let column_name = request.column_name();
529 table_schema
530 .column_index_by_name(column_name)
531 .with_context(|| error::ColumnNotExistsSnafu {
532 column_name,
533 table_name,
534 })?;
535 set_index_options
536 .entry(column_name)
537 .or_default()
538 .push(request);
539 }
540
541 let mut meta_builder = self.new_meta_builder();
542 let mut columns: Vec<_> = Vec::with_capacity(table_schema.column_schemas().len());
543 for mut column in table_schema.column_schemas().iter().cloned() {
544 if let Some(request) = set_index_options.get(column.name.as_str()) {
545 for request in request {
546 self.unset_index(&mut column, request)?;
547 }
548 }
549 columns.push(column);
550 }
551
552 let mut builder = SchemaBuilder::try_from_columns(columns)
553 .with_context(|_| error::SchemaBuildSnafu {
554 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
555 })?
556 .version(table_schema.version() + 1);
557
558 for (k, v) in table_schema.metadata().iter() {
559 builder = builder.add_metadata(k, v);
560 }
561
562 let new_schema = builder.build().with_context(|_| {
563 let column_names = requests
564 .iter()
565 .map(|request| request.column_name())
566 .collect::<Vec<_>>();
567 error::SchemaBuildSnafu {
568 msg: format!(
569 "Table {table_name} cannot set index options with columns {column_names:?}",
570 ),
571 }
572 })?;
573 let _ = meta_builder
574 .schema(Arc::new(new_schema))
575 .primary_key_indices(self.primary_key_indices.clone());
576
577 Ok(meta_builder)
578 }
579
580 fn set_index(&self, column_schema: &mut ColumnSchema, request: &SetIndexOption) -> Result<()> {
581 match request {
582 SetIndexOption::Fulltext {
583 column_name,
584 options,
585 } => {
586 ensure!(
587 column_schema.data_type.is_string(),
588 error::InvalidColumnOptionSnafu {
589 column_name,
590 msg: "FULLTEXT index only supports string type",
591 }
592 );
593
594 let current_fulltext_options = column_schema
595 .fulltext_options()
596 .context(error::SetFulltextOptionsSnafu { column_name })?;
597 set_column_fulltext_options(
598 column_schema,
599 column_name,
600 options,
601 current_fulltext_options,
602 )?;
603 }
604 SetIndexOption::Inverted { column_name } => {
605 debug_assert_eq!(column_schema.name, *column_name);
606 column_schema.set_inverted_index(true);
607 }
608 SetIndexOption::Skipping {
609 column_name,
610 options,
611 } => {
612 set_column_skipping_index_options(column_schema, column_name, options)?;
613 }
614 }
615
616 Ok(())
617 }
618
619 fn unset_index(
620 &self,
621 column_schema: &mut ColumnSchema,
622 request: &UnsetIndexOption,
623 ) -> Result<()> {
624 match request {
625 UnsetIndexOption::Fulltext { column_name } => {
626 let current_fulltext_options = column_schema
627 .fulltext_options()
628 .context(error::SetFulltextOptionsSnafu { column_name })?;
629 unset_column_fulltext_options(
630 column_schema,
631 column_name,
632 current_fulltext_options.clone(),
633 )?
634 }
635 UnsetIndexOption::Inverted { .. } => {
636 column_schema.set_inverted_index(false);
637 }
638 UnsetIndexOption::Skipping { column_name } => {
639 unset_column_skipping_index_options(column_schema, column_name)?;
640 }
641 }
642
643 Ok(())
644 }
645
646 pub fn alloc_new_column(
651 &mut self,
652 table_name: &str,
653 new_column: &ColumnSchema,
654 ) -> Result<ColumnDescriptor> {
655 let desc = ColumnDescriptorBuilder::new(
656 self.next_column_id as ColumnId,
657 &new_column.name,
658 new_column.data_type.clone(),
659 )
660 .is_nullable(new_column.is_nullable())
661 .default_constraint(new_column.default_constraint().cloned())
662 .build()
663 .context(error::BuildColumnDescriptorSnafu {
664 table_name,
665 column_name: &new_column.name,
666 })?;
667
668 self.next_column_id += 1;
670
671 Ok(desc)
672 }
673
674 fn new_meta_builder(&self) -> TableMetaBuilder {
676 let mut builder = TableMetaBuilder::from(self);
677 builder.value_indices = None;
679 builder
680 }
681
682 fn add_columns(
684 &self,
685 table_name: &str,
686 requests: &[AddColumnRequest],
687 ) -> Result<TableMetaBuilder> {
688 let table_schema = &self.schema;
689 let mut meta_builder = self.new_meta_builder();
690 let original_primary_key_indices: HashSet<&usize> =
691 self.primary_key_indices.iter().collect();
692
693 let mut names = HashSet::with_capacity(requests.len());
694 let mut new_columns = Vec::with_capacity(requests.len());
695 for col_to_add in requests {
696 if let Some(column_schema) =
697 table_schema.column_schema_by_name(&col_to_add.column_schema.name)
698 {
699 ensure!(
701 col_to_add.add_if_not_exists,
702 error::ColumnExistsSnafu {
703 table_name,
704 column_name: &col_to_add.column_schema.name
705 },
706 );
707
708 ensure!(
710 column_schema.data_type == col_to_add.column_schema.data_type,
711 error::InvalidAlterRequestSnafu {
712 table: table_name,
713 err: format!(
714 "column {} already exists with different type {:?}",
715 col_to_add.column_schema.name, column_schema.data_type,
716 ),
717 }
718 );
719 } else {
720 ensure!(
723 names.insert(&col_to_add.column_schema.name),
724 error::InvalidAlterRequestSnafu {
725 table: table_name,
726 err: format!(
727 "add column {} more than once",
728 col_to_add.column_schema.name
729 ),
730 }
731 );
732
733 ensure!(
734 col_to_add.column_schema.is_nullable()
735 || col_to_add.column_schema.default_constraint().is_some(),
736 error::InvalidAlterRequestSnafu {
737 table: table_name,
738 err: format!(
739 "no default value for column {}",
740 col_to_add.column_schema.name
741 ),
742 },
743 );
744
745 new_columns.push(col_to_add.clone());
746 }
747 }
748 let requests = &new_columns[..];
749
750 let SplitResult {
751 columns_at_first,
752 columns_at_after,
753 columns_at_last,
754 column_names,
755 } = self.split_requests_by_column_location(table_name, requests)?;
756 let mut primary_key_indices = Vec::with_capacity(self.primary_key_indices.len());
757 let mut columns = Vec::with_capacity(table_schema.num_columns() + requests.len());
758 columns_at_first.iter().rev().for_each(|request| {
760 if request.is_key {
761 primary_key_indices.push(columns.len());
763 }
764 columns.push(request.column_schema.clone());
765 });
766 for (index, column_schema) in table_schema.column_schemas().iter().enumerate() {
768 if original_primary_key_indices.contains(&index) {
769 primary_key_indices.push(columns.len());
770 }
771 columns.push(column_schema.clone());
772 if let Some(requests) = columns_at_after.get(&column_schema.name) {
773 requests.iter().rev().for_each(|request| {
774 if request.is_key {
775 primary_key_indices.push(columns.len());
777 }
778 columns.push(request.column_schema.clone());
779 });
780 }
781 }
782 columns_at_last.iter().for_each(|request| {
784 if request.is_key {
785 primary_key_indices.push(columns.len());
787 }
788 columns.push(request.column_schema.clone());
789 });
790
791 let mut builder = SchemaBuilder::try_from(columns)
792 .with_context(|_| error::SchemaBuildSnafu {
793 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
794 })?
795 .version(table_schema.version() + 1);
797 for (k, v) in table_schema.metadata().iter() {
798 builder = builder.add_metadata(k, v);
799 }
800 let new_schema = builder.build().with_context(|_| error::SchemaBuildSnafu {
801 msg: format!("Table {table_name} cannot add new columns {column_names:?}"),
802 })?;
803
804 let partition_key_indices = self
805 .partition_key_indices
806 .iter()
807 .map(|idx| table_schema.column_name_by_index(*idx))
808 .map(|name| new_schema.column_index_by_name(name).unwrap())
810 .collect();
811
812 let _ = meta_builder
814 .schema(Arc::new(new_schema))
815 .primary_key_indices(primary_key_indices)
816 .partition_key_indices(partition_key_indices);
817
818 Ok(meta_builder)
819 }
820
821 fn remove_columns(
822 &self,
823 table_name: &str,
824 column_names: &[String],
825 ) -> Result<TableMetaBuilder> {
826 let table_schema = &self.schema;
827 let column_names: HashSet<_> = column_names.iter().collect();
828 let mut meta_builder = self.new_meta_builder();
829
830 let timestamp_index = table_schema.timestamp_index();
831 for column_name in &column_names {
833 if let Some(index) = table_schema.column_index_by_name(column_name) {
834 ensure!(
837 !self.primary_key_indices.contains(&index),
838 error::RemoveColumnInIndexSnafu {
839 column_name: *column_name,
840 table_name,
841 }
842 );
843
844 ensure!(
845 !self.partition_key_indices.contains(&index),
846 error::RemovePartitionColumnSnafu {
847 column_name: *column_name,
848 table_name,
849 }
850 );
851
852 if let Some(ts_index) = timestamp_index {
853 ensure!(
855 index != ts_index,
856 error::RemoveColumnInIndexSnafu {
857 column_name: table_schema.column_name_by_index(ts_index),
858 table_name,
859 }
860 );
861 }
862 } else {
863 return error::ColumnNotExistsSnafu {
864 column_name: *column_name,
865 table_name,
866 }
867 .fail()?;
868 }
869 }
870
871 let columns: Vec<_> = table_schema
873 .column_schemas()
874 .iter()
875 .filter(|column_schema| !column_names.contains(&column_schema.name))
876 .cloned()
877 .collect();
878
879 let mut builder = SchemaBuilder::try_from_columns(columns)
880 .with_context(|_| error::SchemaBuildSnafu {
881 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
882 })?
883 .version(table_schema.version() + 1);
885 for (k, v) in table_schema.metadata().iter() {
886 builder = builder.add_metadata(k, v);
887 }
888 let new_schema = builder.build().with_context(|_| error::SchemaBuildSnafu {
889 msg: format!("Table {table_name} cannot add remove columns {column_names:?}"),
890 })?;
891
892 let primary_key_indices = self
894 .primary_key_indices
895 .iter()
896 .map(|idx| table_schema.column_name_by_index(*idx))
897 .map(|name| new_schema.column_index_by_name(name).unwrap())
899 .collect();
900
901 let partition_key_indices = self
902 .partition_key_indices
903 .iter()
904 .map(|idx| table_schema.column_name_by_index(*idx))
905 .map(|name| new_schema.column_index_by_name(name).unwrap())
907 .collect();
908
909 let _ = meta_builder
910 .schema(Arc::new(new_schema))
911 .primary_key_indices(primary_key_indices)
912 .partition_key_indices(partition_key_indices);
913
914 Ok(meta_builder)
915 }
916
917 fn modify_column_types(
918 &self,
919 table_name: &str,
920 requests: &[ModifyColumnTypeRequest],
921 ) -> Result<TableMetaBuilder> {
922 let table_schema = &self.schema;
923 let mut meta_builder = self.new_meta_builder();
924
925 let mut modify_column_types = HashMap::with_capacity(requests.len());
926 let timestamp_index = table_schema.timestamp_index();
927
928 for col_to_change in requests {
929 let change_column_name = &col_to_change.column_name;
930
931 let index = table_schema
932 .column_index_by_name(change_column_name)
933 .with_context(|| error::ColumnNotExistsSnafu {
934 column_name: change_column_name,
935 table_name,
936 })?;
937
938 let column = &table_schema.column_schemas()[index];
939
940 ensure!(
941 !self.primary_key_indices.contains(&index),
942 error::InvalidAlterRequestSnafu {
943 table: table_name,
944 err: format!(
945 "Not allowed to change primary key index column '{}'",
946 column.name
947 )
948 }
949 );
950
951 if let Some(ts_index) = timestamp_index {
952 ensure!(
954 index != ts_index,
955 error::InvalidAlterRequestSnafu {
956 table: table_name,
957 err: format!(
958 "Not allowed to change timestamp index column '{}' datatype",
959 column.name
960 )
961 }
962 );
963 }
964
965 ensure!(
966 modify_column_types
967 .insert(&col_to_change.column_name, col_to_change)
968 .is_none(),
969 error::InvalidAlterRequestSnafu {
970 table: table_name,
971 err: format!(
972 "change column datatype {} more than once",
973 col_to_change.column_name
974 ),
975 }
976 );
977
978 ensure!(
979 column
980 .data_type
981 .can_arrow_type_cast_to(&col_to_change.target_type),
982 error::InvalidAlterRequestSnafu {
983 table: table_name,
984 err: format!(
985 "column '{}' cannot be cast automatically to type '{}'",
986 col_to_change.column_name, col_to_change.target_type,
987 ),
988 }
989 );
990
991 ensure!(
992 column.is_nullable(),
993 error::InvalidAlterRequestSnafu {
994 table: table_name,
995 err: format!(
996 "column '{}' must be nullable to ensure safe conversion.",
997 col_to_change.column_name,
998 ),
999 }
1000 );
1001 }
1002 let mut columns: Vec<_> = Vec::with_capacity(table_schema.column_schemas().len());
1005 for mut column in table_schema.column_schemas().iter().cloned() {
1006 if let Some(change_column) = modify_column_types.get(&column.name) {
1007 column.data_type = change_column.target_type.clone();
1008 let new_default = if let Some(default_value) = column.default_constraint() {
1009 Some(
1010 default_value
1011 .cast_to_datatype(&change_column.target_type)
1012 .with_context(|_| error::CastDefaultValueSnafu {
1013 reason: format!(
1014 "Failed to cast default value from {:?} to type {:?}",
1015 default_value, &change_column.target_type
1016 ),
1017 })?,
1018 )
1019 } else {
1020 None
1021 };
1022 column = column
1023 .clone()
1024 .with_default_constraint(new_default.clone())
1025 .with_context(|_| error::CastDefaultValueSnafu {
1026 reason: format!("Failed to set new default: {:?}", new_default),
1027 })?;
1028 }
1029 columns.push(column)
1030 }
1031
1032 let mut builder = SchemaBuilder::try_from_columns(columns)
1033 .with_context(|_| error::SchemaBuildSnafu {
1034 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
1035 })?
1036 .version(table_schema.version() + 1);
1038 for (k, v) in table_schema.metadata().iter() {
1039 builder = builder.add_metadata(k, v);
1040 }
1041 let new_schema = builder.build().with_context(|_| {
1042 let column_names: Vec<_> = requests
1043 .iter()
1044 .map(|request| &request.column_name)
1045 .collect();
1046
1047 error::SchemaBuildSnafu {
1048 msg: format!(
1049 "Table {table_name} cannot change datatype with columns {column_names:?}"
1050 ),
1051 }
1052 })?;
1053
1054 let _ = meta_builder
1055 .schema(Arc::new(new_schema))
1056 .primary_key_indices(self.primary_key_indices.clone());
1057
1058 Ok(meta_builder)
1059 }
1060
1061 fn split_requests_by_column_location<'a>(
1063 &self,
1064 table_name: &str,
1065 requests: &'a [AddColumnRequest],
1066 ) -> Result<SplitResult<'a>> {
1067 let table_schema = &self.schema;
1068 let mut columns_at_first = Vec::new();
1069 let mut columns_at_after = HashMap::new();
1070 let mut columns_at_last = Vec::new();
1071 let mut column_names = Vec::with_capacity(requests.len());
1072 for request in requests {
1073 let column_name = &request.column_schema.name;
1075 column_names.push(column_name.clone());
1076 ensure!(
1077 table_schema.column_schema_by_name(column_name).is_none(),
1078 error::ColumnExistsSnafu {
1079 column_name,
1080 table_name,
1081 }
1082 );
1083 match request.location.as_ref() {
1084 Some(AddColumnLocation::First) => {
1085 columns_at_first.push(request);
1086 }
1087 Some(AddColumnLocation::After { column_name }) => {
1088 ensure!(
1089 table_schema.column_schema_by_name(column_name).is_some(),
1090 error::ColumnNotExistsSnafu {
1091 column_name,
1092 table_name,
1093 }
1094 );
1095 columns_at_after
1096 .entry(column_name.clone())
1097 .or_insert(Vec::new())
1098 .push(request);
1099 }
1100 None => {
1101 columns_at_last.push(request);
1102 }
1103 }
1104 }
1105 Ok(SplitResult {
1106 columns_at_first,
1107 columns_at_after,
1108 columns_at_last,
1109 column_names,
1110 })
1111 }
1112
1113 fn drop_defaults(&self, table_name: &str, column_names: &[String]) -> Result<TableMetaBuilder> {
1114 let table_schema = &self.schema;
1115 let mut meta_builder = self.new_meta_builder();
1116 let mut columns = Vec::with_capacity(table_schema.num_columns());
1117 for column_schema in table_schema.column_schemas() {
1118 if let Some(name) = column_names.iter().find(|s| **s == column_schema.name) {
1119 ensure!(
1121 column_schema.default_constraint().is_some(),
1122 error::InvalidAlterRequestSnafu {
1123 table: table_name,
1124 err: format!("column {name} does not have a default value"),
1125 }
1126 );
1127 if !column_schema.is_nullable() {
1128 return error::InvalidAlterRequestSnafu {
1129 table: table_name,
1130 err: format!(
1131 "column {name} is not nullable and `default` cannot be dropped",
1132 ),
1133 }
1134 .fail();
1135 }
1136 let new_column_schema = column_schema.clone();
1137 let new_column_schema = new_column_schema
1138 .with_default_constraint(None)
1139 .with_context(|_| error::SchemaBuildSnafu {
1140 msg: format!("Table {table_name} cannot drop default values"),
1141 })?;
1142 columns.push(new_column_schema);
1143 } else {
1144 columns.push(column_schema.clone());
1145 }
1146 }
1147
1148 let mut builder = SchemaBuilder::try_from_columns(columns)
1149 .with_context(|_| error::SchemaBuildSnafu {
1150 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
1151 })?
1152 .version(table_schema.version() + 1);
1154 for (k, v) in table_schema.metadata().iter() {
1155 builder = builder.add_metadata(k, v);
1156 }
1157 let new_schema = builder.build().with_context(|_| error::SchemaBuildSnafu {
1158 msg: format!("Table {table_name} cannot drop default values"),
1159 })?;
1160
1161 let _ = meta_builder.schema(Arc::new(new_schema));
1162
1163 Ok(meta_builder)
1164 }
1165
1166 fn set_defaults(
1167 &self,
1168 table_name: &str,
1169 set_defaults: &[SetDefaultRequest],
1170 ) -> Result<TableMetaBuilder> {
1171 let table_schema = &self.schema;
1172 let mut meta_builder = self.new_meta_builder();
1173 let mut columns = Vec::with_capacity(table_schema.num_columns());
1174 for column_schema in table_schema.column_schemas() {
1175 if let Some(set_default) = set_defaults
1176 .iter()
1177 .find(|s| s.column_name == column_schema.name)
1178 {
1179 let new_column_schema = column_schema.clone();
1180 let new_column_schema = new_column_schema
1181 .with_default_constraint(set_default.default_constraint.clone())
1182 .with_context(|_| error::SchemaBuildSnafu {
1183 msg: format!("Table {table_name} cannot set default values"),
1184 })?;
1185 columns.push(new_column_schema);
1186 } else {
1187 columns.push(column_schema.clone());
1188 }
1189 }
1190
1191 let mut builder = SchemaBuilder::try_from_columns(columns)
1192 .with_context(|_| error::SchemaBuildSnafu {
1193 msg: format!("Failed to convert column schemas into schema for table {table_name}"),
1194 })?
1195 .version(table_schema.version() + 1);
1197 for (k, v) in table_schema.metadata().iter() {
1198 builder = builder.add_metadata(k, v);
1199 }
1200 let new_schema = builder.build().with_context(|_| error::SchemaBuildSnafu {
1201 msg: format!("Table {table_name} cannot set default values"),
1202 })?;
1203
1204 let _ = meta_builder.schema(Arc::new(new_schema));
1205
1206 Ok(meta_builder)
1207 }
1208}
1209
1210#[derive(Clone, Debug, PartialEq, Eq, Builder, Serialize, Deserialize)]
1211#[builder(pattern = "owned")]
1212pub struct TableInfo {
1213 #[builder(default, setter(into))]
1215 pub ident: TableIdent,
1216 #[builder(setter(into))]
1218 pub name: String,
1219 #[builder(default, setter(into))]
1221 pub desc: Option<String>,
1222 #[builder(default = "DEFAULT_CATALOG_NAME.to_string()", setter(into))]
1223 pub catalog_name: String,
1224 #[builder(default = "DEFAULT_SCHEMA_NAME.to_string()", setter(into))]
1225 pub schema_name: String,
1226 pub meta: TableMeta,
1227 #[builder(default = "TableType::Base")]
1228 pub table_type: TableType,
1229}
1230
1231pub type TableInfoRef = Arc<TableInfo>;
1232
1233impl TableInfo {
1234 pub fn table_id(&self) -> TableId {
1235 self.ident.table_id
1236 }
1237
1238 pub fn full_table_name(&self) -> String {
1240 common_catalog::format_full_table_name(&self.catalog_name, &self.schema_name, &self.name)
1241 }
1242
1243 pub fn get_db_string(&self) -> String {
1244 common_catalog::build_db_string(&self.catalog_name, &self.schema_name)
1245 }
1246
1247 pub fn is_physical_table(&self) -> bool {
1249 self.meta
1250 .options
1251 .extra_options
1252 .contains_key(PHYSICAL_TABLE_METADATA_KEY)
1253 }
1254
1255 pub fn is_ttl_instant_table(&self) -> bool {
1257 self.meta
1258 .options
1259 .ttl
1260 .map(|t| t.is_instant())
1261 .unwrap_or(false)
1262 }
1263}
1264
1265impl TableInfoBuilder {
1266 pub fn new<S: Into<String>>(name: S, meta: TableMeta) -> Self {
1267 Self {
1268 name: Some(name.into()),
1269 meta: Some(meta),
1270 ..Default::default()
1271 }
1272 }
1273
1274 pub fn table_id(mut self, id: TableId) -> Self {
1275 let ident = self.ident.get_or_insert_with(TableIdent::default);
1276 ident.table_id = id;
1277 self
1278 }
1279
1280 pub fn table_version(mut self, version: TableVersion) -> Self {
1281 let ident = self.ident.get_or_insert_with(TableIdent::default);
1282 ident.version = version;
1283 self
1284 }
1285}
1286
1287impl TableIdent {
1288 pub fn new(table_id: TableId) -> Self {
1289 Self {
1290 table_id,
1291 version: 0,
1292 }
1293 }
1294}
1295
1296impl From<TableId> for TableIdent {
1297 fn from(table_id: TableId) -> Self {
1298 Self::new(table_id)
1299 }
1300}
1301
1302impl TableInfo {
1303 pub fn name_to_ids(&self) -> Option<HashMap<String, ColumnId>> {
1307 let column_schemas = self.meta.schema.column_schemas();
1308 if self.meta.column_ids.len() != column_schemas.len() {
1309 None
1310 } else {
1311 Some(
1312 self.meta
1313 .column_ids
1314 .iter()
1315 .enumerate()
1316 .map(|(index, id)| (column_schemas[index].name.clone(), *id))
1317 .collect(),
1318 )
1319 }
1320 }
1321
1322 pub fn sort_columns(&mut self) {
1324 let column_schemas = self.meta.schema.column_schemas();
1325 let primary_keys = self
1326 .meta
1327 .primary_key_indices
1328 .iter()
1329 .map(|index| column_schemas[*index].name.clone())
1330 .collect::<HashSet<_>>();
1331
1332 let name_to_ids = self.name_to_ids().unwrap_or_default();
1333 let mut column_schemas = column_schemas.to_vec();
1334 column_schemas.sort_unstable_by(|a, b| a.name.cmp(&b.name));
1335
1336 let mut primary_key_indices = Vec::with_capacity(primary_keys.len());
1338 let mut value_indices = Vec::with_capacity(column_schemas.len() - primary_keys.len());
1339 let mut column_ids = Vec::with_capacity(column_schemas.len());
1340 for (index, column_schema) in column_schemas.iter().enumerate() {
1341 if primary_keys.contains(&column_schema.name) {
1342 primary_key_indices.push(index);
1343 } else {
1344 value_indices.push(index);
1345 }
1346 if let Some(id) = name_to_ids.get(&column_schema.name) {
1347 column_ids.push(*id);
1348 }
1349 }
1350
1351 self.meta.schema = Arc::new(Schema::new_with_version(
1353 column_schemas,
1354 self.meta.schema.version(),
1355 ));
1356 self.meta.primary_key_indices = primary_key_indices;
1357 self.meta.value_indices = value_indices;
1358 self.meta.column_ids = column_ids;
1359 }
1360
1361 pub fn to_region_options(&self) -> HashMap<String, String> {
1365 let mut options = HashMap::from(&self.meta.options);
1366 options.remove(REPARTITION_COLUMN_HINT_KEY);
1367 options
1368 }
1369
1370 pub fn table_ref(&self) -> TableReference<'_> {
1372 TableReference::full(
1373 self.catalog_name.as_str(),
1374 self.schema_name.as_str(),
1375 self.name.as_str(),
1376 )
1377 }
1378}
1379
1380fn set_column_fulltext_options(
1389 column_schema: &mut ColumnSchema,
1390 column_name: &str,
1391 options: &FulltextOptions,
1392 current_options: Option<FulltextOptions>,
1393) -> Result<()> {
1394 if let Some(current_options) = current_options {
1395 ensure!(
1396 current_options.analyzer == options.analyzer
1397 && current_options.case_sensitive == options.case_sensitive,
1398 error::InvalidColumnOptionSnafu {
1399 column_name,
1400 msg: format!(
1401 "Cannot change analyzer or case_sensitive if FULLTEXT index is set before. Previous analyzer: {}, previous case_sensitive: {}",
1402 current_options.analyzer, current_options.case_sensitive
1403 ),
1404 }
1405 );
1406 }
1407
1408 column_schema
1409 .set_fulltext_options(options)
1410 .context(error::SetFulltextOptionsSnafu { column_name })?;
1411
1412 Ok(())
1413}
1414
1415fn unset_column_fulltext_options(
1416 column_schema: &mut ColumnSchema,
1417 column_name: &str,
1418 current_options: Option<FulltextOptions>,
1419) -> Result<()> {
1420 ensure!(
1421 current_options
1422 .as_ref()
1423 .is_some_and(|options| options.enable),
1424 error::InvalidColumnOptionSnafu {
1425 column_name,
1426 msg: "FULLTEXT index already disabled".to_string(),
1427 }
1428 );
1429
1430 let mut options = current_options.unwrap();
1431 options.enable = false;
1432 column_schema
1433 .set_fulltext_options(&options)
1434 .context(error::SetFulltextOptionsSnafu { column_name })?;
1435
1436 Ok(())
1437}
1438
1439fn set_column_skipping_index_options(
1440 column_schema: &mut ColumnSchema,
1441 column_name: &str,
1442 options: &SkippingIndexOptions,
1443) -> Result<()> {
1444 column_schema
1445 .set_skipping_options(options)
1446 .context(error::SetSkippingOptionsSnafu { column_name })?;
1447
1448 Ok(())
1449}
1450
1451fn unset_column_skipping_index_options(
1452 column_schema: &mut ColumnSchema,
1453 column_name: &str,
1454) -> Result<()> {
1455 column_schema
1456 .unset_skipping_options()
1457 .context(error::UnsetSkippingOptionsSnafu { column_name })?;
1458 Ok(())
1459}
1460
1461#[cfg(test)]
1462mod tests {
1463 use std::assert_matches;
1464
1465 use common_error::ext::ErrorExt;
1466 use common_error::status_code::StatusCode;
1467 use datatypes::data_type::ConcreteDataType;
1468 use datatypes::schema::{
1469 ColumnSchema, FulltextAnalyzer, FulltextBackend, Schema, SchemaBuilder,
1470 };
1471
1472 use super::*;
1473 use crate::Error;
1474
1475 fn new_test_schema() -> Schema {
1477 let column_schemas = vec![
1478 ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true),
1479 ColumnSchema::new(
1480 "ts",
1481 ConcreteDataType::timestamp_millisecond_datatype(),
1482 false,
1483 )
1484 .with_time_index(true),
1485 ColumnSchema::new("col2", ConcreteDataType::int32_datatype(), true),
1486 ];
1487 SchemaBuilder::try_from(column_schemas)
1488 .unwrap()
1489 .version(123)
1490 .build()
1491 .unwrap()
1492 }
1493
1494 fn add_columns_to_meta(meta: &TableMeta) -> TableMeta {
1495 let new_tag = ColumnSchema::new("my_tag", ConcreteDataType::string_datatype(), true);
1496 let new_field = ColumnSchema::new("my_field", ConcreteDataType::string_datatype(), true);
1497 let alter_kind = AlterKind::AddColumns {
1498 columns: vec![
1499 AddColumnRequest {
1500 column_schema: new_tag,
1501 is_key: true,
1502 location: None,
1503 add_if_not_exists: false,
1504 },
1505 AddColumnRequest {
1506 column_schema: new_field,
1507 is_key: false,
1508 location: None,
1509 add_if_not_exists: false,
1510 },
1511 ],
1512 };
1513
1514 let builder = meta
1515 .builder_with_alter_kind("my_table", &alter_kind)
1516 .unwrap();
1517 builder.build().unwrap()
1518 }
1519
1520 fn add_columns_to_meta_with_location(meta: &TableMeta) -> TableMeta {
1521 let new_tag = ColumnSchema::new("my_tag_first", ConcreteDataType::string_datatype(), true);
1522 let new_field = ColumnSchema::new(
1523 "my_field_after_ts",
1524 ConcreteDataType::string_datatype(),
1525 true,
1526 );
1527 let yet_another_field = ColumnSchema::new(
1528 "yet_another_field_after_ts",
1529 ConcreteDataType::int64_datatype(),
1530 true,
1531 );
1532 let alter_kind = AlterKind::AddColumns {
1533 columns: vec![
1534 AddColumnRequest {
1535 column_schema: new_tag,
1536 is_key: true,
1537 location: Some(AddColumnLocation::First),
1538 add_if_not_exists: false,
1539 },
1540 AddColumnRequest {
1541 column_schema: new_field,
1542 is_key: false,
1543 location: Some(AddColumnLocation::After {
1544 column_name: "ts".to_string(),
1545 }),
1546 add_if_not_exists: false,
1547 },
1548 AddColumnRequest {
1549 column_schema: yet_another_field,
1550 is_key: true,
1551 location: Some(AddColumnLocation::After {
1552 column_name: "ts".to_string(),
1553 }),
1554 add_if_not_exists: false,
1555 },
1556 ],
1557 };
1558
1559 let builder = meta
1560 .builder_with_alter_kind("my_table", &alter_kind)
1561 .unwrap();
1562 builder.build().unwrap()
1563 }
1564
1565 #[test]
1566 fn test_add_columns() {
1567 let schema = Arc::new(new_test_schema());
1568 let meta = TableMetaBuilder::empty()
1569 .schema(schema)
1570 .primary_key_indices(vec![0])
1571 .engine("engine")
1572 .next_column_id(3)
1573 .build()
1574 .unwrap();
1575
1576 let new_meta = add_columns_to_meta(&meta);
1577 let names: Vec<String> = new_meta
1578 .schema
1579 .column_schemas()
1580 .iter()
1581 .map(|column_schema| column_schema.name.clone())
1582 .collect();
1583 assert_eq!(&["col1", "ts", "col2", "my_tag", "my_field"], &names[..]);
1584 assert_eq!(&[0, 3], &new_meta.primary_key_indices[..]);
1585 assert_eq!(&[1, 2, 4], &new_meta.value_indices[..]);
1586 }
1587
1588 #[test]
1589 fn test_set_append_mode_true_clears_merge_mode_option() {
1590 let schema = Arc::new(new_test_schema());
1591 let mut table_options = TableOptions::default();
1592 table_options
1593 .extra_options
1594 .insert(MERGE_MODE_KEY.to_string(), "last_non_null".to_string());
1595 let meta = TableMetaBuilder::empty()
1596 .schema(schema)
1597 .primary_key_indices(vec![0])
1598 .engine("engine")
1599 .next_column_id(3)
1600 .options(table_options)
1601 .build()
1602 .unwrap();
1603
1604 let alter_kind = AlterKind::SetTableOptions {
1605 options: vec![SetRegionOption::AppendMode(true)],
1606 };
1607 let new_meta = meta
1608 .builder_with_alter_kind("my_table", &alter_kind)
1609 .unwrap()
1610 .build()
1611 .unwrap();
1612
1613 assert_eq!(
1614 Some("true"),
1615 new_meta
1616 .options
1617 .extra_options
1618 .get(APPEND_MODE_KEY)
1619 .map(String::as_str)
1620 );
1621 assert!(!new_meta.options.extra_options.contains_key(MERGE_MODE_KEY));
1622 }
1623
1624 #[test]
1625 fn test_set_append_mode_false_keeps_merge_mode_option() {
1626 let schema = Arc::new(new_test_schema());
1627 let mut table_options = TableOptions::default();
1628 table_options
1629 .extra_options
1630 .insert(MERGE_MODE_KEY.to_string(), "last_non_null".to_string());
1631 let meta = TableMetaBuilder::empty()
1632 .schema(schema)
1633 .primary_key_indices(vec![0])
1634 .engine("engine")
1635 .next_column_id(3)
1636 .options(table_options)
1637 .build()
1638 .unwrap();
1639
1640 let alter_kind = AlterKind::SetTableOptions {
1641 options: vec![SetRegionOption::AppendMode(false)],
1642 };
1643 let new_meta = meta
1644 .builder_with_alter_kind("my_table", &alter_kind)
1645 .unwrap()
1646 .build()
1647 .unwrap();
1648
1649 assert_eq!(
1650 Some("false"),
1651 new_meta
1652 .options
1653 .extra_options
1654 .get(APPEND_MODE_KEY)
1655 .map(String::as_str)
1656 );
1657 assert_eq!(
1658 Some("last_non_null"),
1659 new_meta
1660 .options
1661 .extra_options
1662 .get(MERGE_MODE_KEY)
1663 .map(String::as_str)
1664 );
1665 }
1666
1667 #[test]
1668 fn test_set_repartition_column_hint() {
1669 let meta = TableMetaBuilder::empty()
1670 .schema(Arc::new(new_test_schema()))
1671 .primary_key_indices(vec![0])
1672 .engine("engine")
1673 .next_column_id(3)
1674 .build()
1675 .unwrap();
1676
1677 let alter_kind = AlterKind::SetRepartitionColumnHint {
1678 column_name: " col1 ".to_string(),
1679 };
1680 let new_meta = meta
1681 .builder_with_alter_kind("my_table", &alter_kind)
1682 .unwrap()
1683 .build()
1684 .unwrap();
1685
1686 assert_eq!(
1687 Some("col1"),
1688 new_meta
1689 .options
1690 .extra_options
1691 .get(REPARTITION_COLUMN_HINT_KEY)
1692 .map(String::as_str)
1693 );
1694 }
1695
1696 #[test]
1697 fn test_set_repartition_column_hint_rejects_empty_column() {
1698 let meta = TableMetaBuilder::empty()
1699 .schema(Arc::new(new_test_schema()))
1700 .primary_key_indices(vec![0])
1701 .engine("engine")
1702 .next_column_id(3)
1703 .build()
1704 .unwrap();
1705
1706 let alter_kind = AlterKind::SetRepartitionColumnHint {
1707 column_name: " ".to_string(),
1708 };
1709 let err = meta
1710 .builder_with_alter_kind("my_table", &alter_kind)
1711 .err()
1712 .unwrap();
1713
1714 assert!(
1715 err.to_string()
1716 .contains("repartition.column.hint expects exactly one column name")
1717 );
1718 }
1719
1720 #[test]
1721 fn test_set_repartition_column_hint_rejects_multiple_columns() {
1722 let meta = TableMetaBuilder::empty()
1723 .schema(Arc::new(new_test_schema()))
1724 .primary_key_indices(vec![0])
1725 .engine("engine")
1726 .next_column_id(3)
1727 .build()
1728 .unwrap();
1729
1730 let alter_kind = AlterKind::SetRepartitionColumnHint {
1731 column_name: "col1,col2".to_string(),
1732 };
1733 let err = meta
1734 .builder_with_alter_kind("my_table", &alter_kind)
1735 .err()
1736 .unwrap();
1737
1738 assert!(
1739 err.to_string()
1740 .contains("repartition.column.hint expects exactly one column name")
1741 );
1742 }
1743
1744 #[test]
1745 fn test_set_repartition_column_hint_rejects_missing_column() {
1746 let meta = TableMetaBuilder::empty()
1747 .schema(Arc::new(new_test_schema()))
1748 .primary_key_indices(vec![0])
1749 .engine("engine")
1750 .next_column_id(3)
1751 .build()
1752 .unwrap();
1753
1754 let alter_kind = AlterKind::SetRepartitionColumnHint {
1755 column_name: "missing".to_string(),
1756 };
1757 let err = meta
1758 .builder_with_alter_kind("my_table", &alter_kind)
1759 .err()
1760 .unwrap();
1761
1762 assert!(err.to_string().contains("Column missing not exists"));
1763 }
1764
1765 #[test]
1766 fn test_set_repartition_column_hint_rejects_time_index_column() {
1767 let meta = TableMetaBuilder::empty()
1768 .schema(Arc::new(new_test_schema()))
1769 .primary_key_indices(vec![0])
1770 .engine("engine")
1771 .next_column_id(3)
1772 .build()
1773 .unwrap();
1774
1775 let alter_kind = AlterKind::SetRepartitionColumnHint {
1776 column_name: "ts".to_string(),
1777 };
1778 let err = meta
1779 .builder_with_alter_kind("my_table", &alter_kind)
1780 .err()
1781 .unwrap();
1782
1783 assert!(
1784 err.to_string()
1785 .contains("cannot set repartition.column.hint to the time index column")
1786 );
1787 }
1788
1789 #[test]
1790 fn test_set_repartition_column_hint_rejects_partitioned_table() {
1791 let meta = TableMetaBuilder::empty()
1792 .schema(Arc::new(new_test_schema()))
1793 .primary_key_indices(vec![0])
1794 .engine("engine")
1795 .next_column_id(3)
1796 .partition_key_indices(vec![0])
1797 .build()
1798 .unwrap();
1799
1800 let alter_kind = AlterKind::SetRepartitionColumnHint {
1801 column_name: "col1".to_string(),
1802 };
1803 let err = meta
1804 .builder_with_alter_kind("my_table", &alter_kind)
1805 .err()
1806 .unwrap();
1807
1808 assert!(
1809 err.to_string()
1810 .contains("cannot set repartition.column.hint on a table with partition metadata")
1811 );
1812 }
1813
1814 #[test]
1815 fn test_unset_repartition_column_hint() {
1816 let mut table_options = TableOptions::default();
1817 table_options
1818 .extra_options
1819 .insert(REPARTITION_COLUMN_HINT_KEY.to_string(), "col1".to_string());
1820 let meta = TableMetaBuilder::empty()
1821 .schema(Arc::new(new_test_schema()))
1822 .primary_key_indices(vec![0])
1823 .engine("engine")
1824 .next_column_id(3)
1825 .options(table_options)
1826 .build()
1827 .unwrap();
1828
1829 let new_meta = meta
1830 .builder_with_alter_kind("my_table", &AlterKind::UnsetRepartitionColumnHint)
1831 .unwrap()
1832 .build()
1833 .unwrap();
1834
1835 assert!(
1836 !new_meta
1837 .options
1838 .extra_options
1839 .contains_key(REPARTITION_COLUMN_HINT_KEY)
1840 );
1841 }
1842
1843 #[test]
1844 fn test_repartition_column_hint_is_not_region_option() {
1845 let mut table_options = TableOptions::default();
1846 table_options
1847 .extra_options
1848 .insert(REPARTITION_COLUMN_HINT_KEY.to_string(), "col1".to_string());
1849 let table_info = TableInfoBuilder::default()
1850 .table_id(1)
1851 .table_version(0)
1852 .name("my_table")
1853 .catalog_name(DEFAULT_CATALOG_NAME)
1854 .schema_name(DEFAULT_SCHEMA_NAME)
1855 .meta(
1856 TableMetaBuilder::empty()
1857 .schema(Arc::new(new_test_schema()))
1858 .primary_key_indices(vec![0])
1859 .engine("engine")
1860 .next_column_id(3)
1861 .options(table_options)
1862 .build()
1863 .unwrap(),
1864 )
1865 .build()
1866 .unwrap();
1867
1868 assert!(
1869 !table_info
1870 .to_region_options()
1871 .contains_key(REPARTITION_COLUMN_HINT_KEY)
1872 );
1873 }
1874
1875 #[test]
1876 fn test_add_columns_multiple_times() {
1877 let schema = Arc::new(new_test_schema());
1878 let meta = TableMetaBuilder::empty()
1879 .schema(schema)
1880 .primary_key_indices(vec![0])
1881 .engine("engine")
1882 .next_column_id(3)
1883 .build()
1884 .unwrap();
1885
1886 let alter_kind = AlterKind::AddColumns {
1887 columns: vec![
1888 AddColumnRequest {
1889 column_schema: ColumnSchema::new(
1890 "col3",
1891 ConcreteDataType::int32_datatype(),
1892 true,
1893 ),
1894 is_key: true,
1895 location: None,
1896 add_if_not_exists: true,
1897 },
1898 AddColumnRequest {
1899 column_schema: ColumnSchema::new(
1900 "col3",
1901 ConcreteDataType::int32_datatype(),
1902 true,
1903 ),
1904 is_key: true,
1905 location: None,
1906 add_if_not_exists: true,
1907 },
1908 ],
1909 };
1910 let err = meta
1911 .builder_with_alter_kind("my_table", &alter_kind)
1912 .err()
1913 .unwrap();
1914 assert_eq!(StatusCode::InvalidArguments, err.status_code());
1915 }
1916
1917 #[test]
1918 fn test_remove_columns() {
1919 let schema = Arc::new(new_test_schema());
1920 let meta = TableMetaBuilder::empty()
1921 .schema(schema.clone())
1922 .primary_key_indices(vec![0])
1923 .engine("engine")
1924 .next_column_id(3)
1925 .build()
1926 .unwrap();
1927 let meta = add_columns_to_meta(&meta);
1929
1930 let alter_kind = AlterKind::DropColumns {
1931 names: vec![String::from("col2"), String::from("my_field")],
1932 };
1933 let new_meta = meta
1934 .builder_with_alter_kind("my_table", &alter_kind)
1935 .unwrap()
1936 .build()
1937 .unwrap();
1938
1939 let names: Vec<String> = new_meta
1940 .schema
1941 .column_schemas()
1942 .iter()
1943 .map(|column_schema| column_schema.name.clone())
1944 .collect();
1945 assert_eq!(&["col1", "ts", "my_tag"], &names[..]);
1946 assert_eq!(&[0, 2], &new_meta.primary_key_indices[..]);
1947 assert_eq!(&[1], &new_meta.value_indices[..]);
1948 assert_eq!(
1949 schema.timestamp_column(),
1950 new_meta.schema.timestamp_column()
1951 );
1952 }
1953
1954 #[test]
1955 fn test_remove_multiple_columns_before_timestamp() {
1956 let column_schemas = vec![
1957 ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true),
1958 ColumnSchema::new("col2", ConcreteDataType::int32_datatype(), true),
1959 ColumnSchema::new("col3", ConcreteDataType::int32_datatype(), true),
1960 ColumnSchema::new(
1961 "ts",
1962 ConcreteDataType::timestamp_millisecond_datatype(),
1963 false,
1964 )
1965 .with_time_index(true),
1966 ];
1967 let schema = Arc::new(
1968 SchemaBuilder::try_from(column_schemas)
1969 .unwrap()
1970 .version(123)
1971 .build()
1972 .unwrap(),
1973 );
1974 let meta = TableMetaBuilder::empty()
1975 .schema(schema.clone())
1976 .primary_key_indices(vec![1])
1977 .engine("engine")
1978 .next_column_id(4)
1979 .build()
1980 .unwrap();
1981
1982 let alter_kind = AlterKind::DropColumns {
1984 names: vec![String::from("col3"), String::from("col1")],
1985 };
1986 let new_meta = meta
1987 .builder_with_alter_kind("my_table", &alter_kind)
1988 .unwrap()
1989 .build()
1990 .unwrap();
1991
1992 let names: Vec<String> = new_meta
1993 .schema
1994 .column_schemas()
1995 .iter()
1996 .map(|column_schema| column_schema.name.clone())
1997 .collect();
1998 assert_eq!(&["col2", "ts"], &names[..]);
1999 assert_eq!(&[0], &new_meta.primary_key_indices[..]);
2000 assert_eq!(&[1], &new_meta.value_indices[..]);
2001 assert_eq!(
2002 schema.timestamp_column(),
2003 new_meta.schema.timestamp_column()
2004 );
2005 }
2006
2007 #[test]
2008 fn test_add_existing_column() {
2009 let schema = Arc::new(new_test_schema());
2010 let meta = TableMetaBuilder::empty()
2011 .schema(schema)
2012 .primary_key_indices(vec![0])
2013 .engine("engine")
2014 .next_column_id(3)
2015 .build()
2016 .unwrap();
2017
2018 let alter_kind = AlterKind::AddColumns {
2019 columns: vec![AddColumnRequest {
2020 column_schema: ColumnSchema::new("col1", ConcreteDataType::string_datatype(), true),
2021 is_key: false,
2022 location: None,
2023 add_if_not_exists: false,
2024 }],
2025 };
2026
2027 let err = meta
2028 .builder_with_alter_kind("my_table", &alter_kind)
2029 .err()
2030 .unwrap();
2031 assert_eq!(StatusCode::TableColumnExists, err.status_code());
2032
2033 let alter_kind = AlterKind::AddColumns {
2035 columns: vec![AddColumnRequest {
2036 column_schema: ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true),
2037 is_key: true,
2038 location: None,
2039 add_if_not_exists: true,
2040 }],
2041 };
2042 let new_meta = meta
2043 .builder_with_alter_kind("my_table", &alter_kind)
2044 .unwrap()
2045 .build()
2046 .unwrap();
2047 assert_eq!(
2048 meta.schema.column_schemas(),
2049 new_meta.schema.column_schemas()
2050 );
2051 assert_eq!(meta.schema.version() + 1, new_meta.schema.version());
2052 }
2053
2054 #[test]
2055 fn test_add_different_type_column() {
2056 let schema = Arc::new(new_test_schema());
2057 let meta = TableMetaBuilder::empty()
2058 .schema(schema)
2059 .primary_key_indices(vec![0])
2060 .engine("engine")
2061 .next_column_id(3)
2062 .build()
2063 .unwrap();
2064
2065 let alter_kind = AlterKind::AddColumns {
2067 columns: vec![AddColumnRequest {
2068 column_schema: ColumnSchema::new("col1", ConcreteDataType::string_datatype(), true),
2069 is_key: false,
2070 location: None,
2071 add_if_not_exists: true,
2072 }],
2073 };
2074 let err = meta
2075 .builder_with_alter_kind("my_table", &alter_kind)
2076 .err()
2077 .unwrap();
2078 assert_eq!(StatusCode::InvalidArguments, err.status_code());
2079 }
2080
2081 #[test]
2082 fn test_add_invalid_column() {
2083 let schema = Arc::new(new_test_schema());
2084 let meta = TableMetaBuilder::empty()
2085 .schema(schema)
2086 .primary_key_indices(vec![0])
2087 .engine("engine")
2088 .next_column_id(3)
2089 .build()
2090 .unwrap();
2091
2092 let alter_kind = AlterKind::AddColumns {
2094 columns: vec![AddColumnRequest {
2095 column_schema: ColumnSchema::new(
2096 "weny",
2097 ConcreteDataType::string_datatype(),
2098 false,
2099 ),
2100 is_key: false,
2101 location: None,
2102 add_if_not_exists: false,
2103 }],
2104 };
2105
2106 let err = meta
2107 .builder_with_alter_kind("my_table", &alter_kind)
2108 .err()
2109 .unwrap();
2110 assert_eq!(StatusCode::InvalidArguments, err.status_code());
2111 }
2112
2113 #[test]
2114 fn test_remove_unknown_column() {
2115 let schema = Arc::new(new_test_schema());
2116 let meta = TableMetaBuilder::empty()
2117 .schema(schema)
2118 .primary_key_indices(vec![0])
2119 .engine("engine")
2120 .next_column_id(3)
2121 .build()
2122 .unwrap();
2123
2124 let alter_kind = AlterKind::DropColumns {
2125 names: vec![String::from("unknown")],
2126 };
2127
2128 let err = meta
2129 .builder_with_alter_kind("my_table", &alter_kind)
2130 .err()
2131 .unwrap();
2132 assert_eq!(StatusCode::TableColumnNotFound, err.status_code());
2133 }
2134
2135 #[test]
2136 fn test_change_unknown_column_data_type() {
2137 let schema = Arc::new(new_test_schema());
2138 let meta = TableMetaBuilder::empty()
2139 .schema(schema)
2140 .primary_key_indices(vec![0])
2141 .engine("engine")
2142 .next_column_id(3)
2143 .build()
2144 .unwrap();
2145
2146 let alter_kind = AlterKind::ModifyColumnTypes {
2147 columns: vec![ModifyColumnTypeRequest {
2148 column_name: "unknown".to_string(),
2149 target_type: ConcreteDataType::string_datatype(),
2150 }],
2151 };
2152
2153 let err = meta
2154 .builder_with_alter_kind("my_table", &alter_kind)
2155 .err()
2156 .unwrap();
2157 assert_eq!(StatusCode::TableColumnNotFound, err.status_code());
2158 }
2159
2160 #[test]
2161 fn test_remove_key_column() {
2162 let schema = Arc::new(new_test_schema());
2163 let meta = TableMetaBuilder::empty()
2164 .schema(schema)
2165 .primary_key_indices(vec![0])
2166 .engine("engine")
2167 .next_column_id(3)
2168 .build()
2169 .unwrap();
2170
2171 let alter_kind = AlterKind::DropColumns {
2173 names: vec![String::from("col1")],
2174 };
2175
2176 let err = meta
2177 .builder_with_alter_kind("my_table", &alter_kind)
2178 .err()
2179 .unwrap();
2180 assert_eq!(StatusCode::InvalidArguments, err.status_code());
2181
2182 let alter_kind = AlterKind::DropColumns {
2184 names: vec![String::from("ts")],
2185 };
2186
2187 let err = meta
2188 .builder_with_alter_kind("my_table", &alter_kind)
2189 .err()
2190 .unwrap();
2191 assert_eq!(StatusCode::InvalidArguments, err.status_code());
2192 }
2193
2194 #[test]
2195 fn test_remove_partition_column() {
2196 let schema = Arc::new(new_test_schema());
2197 let meta = TableMetaBuilder::empty()
2198 .schema(schema)
2199 .primary_key_indices(vec![])
2200 .partition_key_indices(vec![0])
2201 .engine("engine")
2202 .next_column_id(3)
2203 .build()
2204 .unwrap();
2205 let alter_kind = AlterKind::DropColumns {
2207 names: vec![String::from("col1")],
2208 };
2209
2210 let err = meta
2211 .builder_with_alter_kind("my_table", &alter_kind)
2212 .err()
2213 .unwrap();
2214 assert_matches!(err, Error::RemovePartitionColumn { .. });
2215 }
2216
2217 #[test]
2218 fn test_change_key_column_data_type() {
2219 let schema = Arc::new(new_test_schema());
2220 let meta = TableMetaBuilder::empty()
2221 .schema(schema)
2222 .primary_key_indices(vec![0])
2223 .engine("engine")
2224 .next_column_id(3)
2225 .build()
2226 .unwrap();
2227
2228 let alter_kind = AlterKind::ModifyColumnTypes {
2230 columns: vec![ModifyColumnTypeRequest {
2231 column_name: "col1".to_string(),
2232 target_type: ConcreteDataType::string_datatype(),
2233 }],
2234 };
2235
2236 let err = meta
2237 .builder_with_alter_kind("my_table", &alter_kind)
2238 .err()
2239 .unwrap();
2240 assert_eq!(StatusCode::InvalidArguments, err.status_code());
2241
2242 let alter_kind = AlterKind::ModifyColumnTypes {
2244 columns: vec![ModifyColumnTypeRequest {
2245 column_name: "ts".to_string(),
2246 target_type: ConcreteDataType::string_datatype(),
2247 }],
2248 };
2249
2250 let err = meta
2251 .builder_with_alter_kind("my_table", &alter_kind)
2252 .err()
2253 .unwrap();
2254 assert_eq!(StatusCode::InvalidArguments, err.status_code());
2255 }
2256
2257 #[test]
2258 fn test_alloc_new_column() {
2259 let schema = Arc::new(new_test_schema());
2260 let mut meta = TableMetaBuilder::empty()
2261 .schema(schema)
2262 .primary_key_indices(vec![0])
2263 .engine("engine")
2264 .next_column_id(3)
2265 .build()
2266 .unwrap();
2267 assert_eq!(3, meta.next_column_id);
2268
2269 let column_schema = ColumnSchema::new("col1", ConcreteDataType::int32_datatype(), true);
2270 let desc = meta.alloc_new_column("test_table", &column_schema).unwrap();
2271
2272 assert_eq!(4, meta.next_column_id);
2273 assert_eq!(column_schema.name, desc.name);
2274 }
2275
2276 #[test]
2277 fn test_add_columns_with_location() {
2278 let schema = Arc::new(new_test_schema());
2279 let meta = TableMetaBuilder::empty()
2280 .schema(schema)
2281 .primary_key_indices(vec![0])
2282 .partition_key_indices(vec![0, 2])
2284 .engine("engine")
2285 .next_column_id(3)
2286 .build()
2287 .unwrap();
2288
2289 let new_meta = add_columns_to_meta_with_location(&meta);
2290 let names: Vec<String> = new_meta
2291 .schema
2292 .column_schemas()
2293 .iter()
2294 .map(|column_schema| column_schema.name.clone())
2295 .collect();
2296 assert_eq!(
2297 &[
2298 "my_tag_first", "col1", "ts", "yet_another_field_after_ts", "my_field_after_ts", "col2", ],
2305 &names[..]
2306 );
2307 assert_eq!(&[0, 1, 3], &new_meta.primary_key_indices[..]);
2308 assert_eq!(&[2, 4, 5], &new_meta.value_indices[..]);
2309 assert_eq!(&[1, 5], &new_meta.partition_key_indices[..]);
2310 }
2311
2312 #[test]
2313 fn test_modify_column_fulltext_options() {
2314 let schema = Arc::new(new_test_schema());
2315 let meta = TableMetaBuilder::empty()
2316 .schema(schema)
2317 .primary_key_indices(vec![0])
2318 .engine("engine")
2319 .next_column_id(3)
2320 .build()
2321 .unwrap();
2322
2323 let alter_kind = AlterKind::SetIndexes {
2324 options: vec![SetIndexOption::Fulltext {
2325 column_name: "col1".to_string(),
2326 options: FulltextOptions::default(),
2327 }],
2328 };
2329 let err = meta
2330 .builder_with_alter_kind("my_table", &alter_kind)
2331 .err()
2332 .unwrap();
2333 assert_eq!(
2334 "Invalid column option, column name: col1, error: FULLTEXT index only supports string type",
2335 err.to_string()
2336 );
2337
2338 let new_meta = add_columns_to_meta_with_location(&meta);
2340 let alter_kind = AlterKind::SetIndexes {
2341 options: vec![SetIndexOption::Fulltext {
2342 column_name: "my_tag_first".to_string(),
2343 options: FulltextOptions::new_unchecked(
2344 true,
2345 FulltextAnalyzer::Chinese,
2346 true,
2347 FulltextBackend::Bloom,
2348 1000,
2349 0.01,
2350 ),
2351 }],
2352 };
2353 let new_meta = new_meta
2354 .builder_with_alter_kind("my_table", &alter_kind)
2355 .unwrap()
2356 .build()
2357 .unwrap();
2358 let column_schema = new_meta
2359 .schema
2360 .column_schema_by_name("my_tag_first")
2361 .unwrap();
2362 let fulltext_options = column_schema.fulltext_options().unwrap().unwrap();
2363 assert!(fulltext_options.enable);
2364 assert_eq!(
2365 datatypes::schema::FulltextAnalyzer::Chinese,
2366 fulltext_options.analyzer
2367 );
2368 assert!(fulltext_options.case_sensitive);
2369
2370 let alter_kind = AlterKind::UnsetIndexes {
2371 options: vec![UnsetIndexOption::Fulltext {
2372 column_name: "my_tag_first".to_string(),
2373 }],
2374 };
2375 let new_meta = new_meta
2376 .builder_with_alter_kind("my_table", &alter_kind)
2377 .unwrap()
2378 .build()
2379 .unwrap();
2380 let column_schema = new_meta
2381 .schema
2382 .column_schema_by_name("my_tag_first")
2383 .unwrap();
2384 let fulltext_options = column_schema.fulltext_options().unwrap().unwrap();
2385 assert!(!fulltext_options.enable);
2386 }
2387
2388 #[test]
2389 fn test_table_info_serde_compatibility() {
2390 let serialized = r#"{"ident":{"table_id":1024,"version":1},"name":"foo","desc":"my table","catalog_name":"greptime","schema_name":"public","meta":{"schema":{"column_schemas":[{"name":"col1","data_type":{"Int32":{}},"is_nullable":true,"is_time_index":false,"default_constraint":null,"metadata":{}},{"name":"ts","data_type":{"Timestamp":{"Millisecond":null}},"is_nullable":false,"is_time_index":true,"default_constraint":null,"metadata":{"greptime:time_index":"true"}},{"name":"col2","data_type":{"Int32":{}},"is_nullable":true,"is_time_index":false,"default_constraint":null,"metadata":{}}],"timestamp_index":1,"version":123},"primary_key_indices":[0],"value_indices":[1,2],"engine":"mito","next_column_id":3,"options":{"write_buffer_size":null,"ttl":"1h","skip_wal":false,"extra_options":{}},"created_on":"-262143-01-01T00:00:00Z","updated_on":"+262142-12-31T23:59:59.999999999Z","partition_key_indices":[2],"column_ids":[0,1,2]},"table_type":"Base"}"#;
2423
2424 let actual: TableInfo = serde_json::from_str(serialized).unwrap();
2425 let expected = TableInfo {
2426 ident: TableIdent {
2427 table_id: 1024,
2428 version: 1,
2429 },
2430 name: "foo".to_string(),
2431 desc: Some("my table".to_string()),
2432 catalog_name: "greptime".to_string(),
2433 schema_name: "public".to_string(),
2434 meta: TableMeta {
2435 schema: Arc::new(new_test_schema()),
2436 primary_key_indices: vec![0],
2437 value_indices: vec![1, 2],
2438 engine: "mito".to_string(),
2439 next_column_id: 3,
2440 options: TableOptions {
2441 ttl: Some(common_time::TimeToLive::Duration(
2442 std::time::Duration::from_secs(3600),
2443 )),
2444 ..Default::default()
2445 },
2446 created_on: DateTime::<Utc>::MIN_UTC,
2447 updated_on: DateTime::<Utc>::MAX_UTC,
2448 partition_key_indices: vec![2],
2449 column_ids: vec![0, 1, 2],
2450 },
2451 table_type: TableType::Base,
2452 };
2453 assert_eq!(actual, expected);
2454 }
2455}