diff --git a/src/common/meta/src/key/flow/flow_name.rs b/src/common/meta/src/key/flow/flow_name.rs index 4c465c7070..d368ca7c3a 100644 --- a/src/common/meta/src/key/flow/flow_name.rs +++ b/src/common/meta/src/key/flow/flow_name.rs @@ -205,7 +205,7 @@ impl FlowNameManager { catalog: &str, ) -> BoxStream<'static, Result<(String, FlowNameValue)>> { let start_key = FlowNameKey::range_start_key(catalog); - common_telemetry::debug!("flow_names: start_key: {:?}", start_key); + common_telemetry::trace!("flow_names: start_key: {:?}", start_key); let req = RangeRequest::new().with_prefix(start_key); let stream = PaginationStream::new( diff --git a/src/table/src/error.rs b/src/table/src/error.rs index 6cd79fd61c..e48e47d2c1 100644 --- a/src/table/src/error.rs +++ b/src/table/src/error.rs @@ -175,6 +175,14 @@ pub enum Error { #[snafu(display("Invalid table name: '{s}'"))] InvalidTableName { s: String }, + + #[snafu(display("Failed to cast default value, reason: {}", reason))] + CastDefaultValue { + reason: String, + source: datatypes::Error, + #[snafu(implicit)] + location: Location, + }, } impl ErrorExt for Error { @@ -187,6 +195,7 @@ impl ErrorExt for Error { Error::RemoveColumnInIndex { .. } | Error::BuildColumnDescriptor { .. } | Error::InvalidAlterRequest { .. } => StatusCode::InvalidArguments, + Error::CastDefaultValue { source, .. } => source.status_code(), Error::TablesRecordBatch { .. } => StatusCode::Unexpected, Error::ColumnExists { .. } => StatusCode::TableColumnExists, Error::SchemaBuild { source, .. } | Error::SetFulltextOptions { source, .. } => { diff --git a/src/table/src/metadata.rs b/src/table/src/metadata.rs index 4235588ff0..14f734afd4 100644 --- a/src/table/src/metadata.rs +++ b/src/table/src/metadata.rs @@ -817,17 +817,34 @@ impl TableMeta { ); } // Collect columns after changed. - let columns: Vec<_> = table_schema - .column_schemas() - .iter() - .cloned() - .map(|mut column| { - if let Some(change_column) = modify_column_types.get(&column.name) { - column.data_type = change_column.target_type.clone(); - } - column - }) - .collect(); + + let mut columns: Vec<_> = Vec::with_capacity(table_schema.column_schemas().len()); + for mut column in table_schema.column_schemas().iter().cloned() { + if let Some(change_column) = modify_column_types.get(&column.name) { + column.data_type = change_column.target_type.clone(); + let new_default = if let Some(default_value) = column.default_constraint() { + Some( + default_value + .cast_to_datatype(&change_column.target_type) + .with_context(|_| error::CastDefaultValueSnafu { + reason: format!( + "Failed to cast default value from {:?} to type {:?}", + default_value, &change_column.target_type + ), + })?, + ) + } else { + None + }; + column = column + .clone() + .with_default_constraint(new_default.clone()) + .with_context(|_| error::CastDefaultValueSnafu { + reason: format!("Failed to set new default: {:?}", new_default), + })?; + } + columns.push(column) + } let mut builder = SchemaBuilder::try_from_columns(columns) .with_context(|_| error::SchemaBuildSnafu { diff --git a/tests-fuzz/src/context.rs b/tests-fuzz/src/context.rs index d0d5dee72d..5678399f8b 100644 --- a/tests-fuzz/src/context.rs +++ b/tests-fuzz/src/context.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use common_query::AddColumnLocation; +use datatypes::types::cast; use partition::partition::PartitionDef; use rand::Rng; use snafu::{ensure, OptionExt}; @@ -22,6 +23,7 @@ use snafu::{ensure, OptionExt}; use crate::error::{self, Result}; use crate::generator::Random; use crate::ir::alter_expr::{AlterTableOperation, AlterTableOption}; +use crate::ir::create_expr::ColumnOption; use crate::ir::{AlterTableExpr, Column, CreateTableExpr, Ident}; pub type TableContextRef = Arc; @@ -138,7 +140,12 @@ impl TableContext { } AlterTableOperation::ModifyDataType { column } => { if let Some(idx) = self.columns.iter().position(|col| col.name == column.name) { - self.columns[idx].column_type = column.column_type; + self.columns[idx].column_type = column.column_type.clone(); + for opt in self.columns[idx].options.iter_mut() { + if let ColumnOption::DefaultValue(value) = opt { + *value = cast(value.clone(), &column.column_type).unwrap(); + } + } } Ok(self) } diff --git a/tests/cases/standalone/common/alter/alter_table.result b/tests/cases/standalone/common/alter/alter_table.result index e441b59c22..b1969bbaf7 100644 --- a/tests/cases/standalone/common/alter/alter_table.result +++ b/tests/cases/standalone/common/alter/alter_table.result @@ -133,26 +133,49 @@ DROP TABLE test_alt_table; Affected Rows: 0 -- test if column with default value can change type properly -CREATE TABLE test_alt_table_default(h INTEGER, i INTEGER DEFAULT 0, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); +CREATE TABLE test_alt_table_default(h INTEGER, i Float64 DEFAULT 0.0, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); Affected Rows: 0 +INSERT INTO test_alt_table_default (h, j) VALUES (0, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_default (h, i, j) VALUES (1, 0.1, 0); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_default ORDER BY h; + ++---+-----+---------------------+ +| h | i | j | ++---+-----+---------------------+ +| 0 | 0.0 | 1970-01-01T00:00:00 | +| 1 | 0.1 | 1970-01-01T00:00:00 | ++---+-----+---------------------+ + ALTER TABLE test_alt_table_default MODIFY COLUMN i BOOLEAN; Affected Rows: 0 -INSERT INTO test_alt_table_default (h, j) VALUES (1, 0), (2, 1); +INSERT INTO test_alt_table_default (h, j) VALUES (2, 0); -Affected Rows: 2 +Affected Rows: 1 + +INSERT INTO test_alt_table_default (h, i, j) VALUES (3, TRUE, 0); + +Affected Rows: 1 SELECT * FROM test_alt_table_default ORDER BY h; -+---+-------+-------------------------+ -| h | i | j | -+---+-------+-------------------------+ -| 1 | false | 1970-01-01T00:00:00 | -| 2 | false | 1970-01-01T00:00:00.001 | -+---+-------+-------------------------+ ++---+-------+---------------------+ +| h | i | j | ++---+-------+---------------------+ +| 0 | false | 1970-01-01T00:00:00 | +| 1 | true | 1970-01-01T00:00:00 | +| 2 | false | 1970-01-01T00:00:00 | +| 3 | true | 1970-01-01T00:00:00 | ++---+-------+---------------------+ ALTER TABLE test_alt_table_default MODIFY COLUMN i INTEGER; @@ -168,50 +191,279 @@ DESC TABLE test_alt_table_default; | j | TimestampMillisecond | PRI | NO | | TIMESTAMP | +--------+----------------------+-----+------+---------+---------------+ -INSERT INTO test_alt_table_default (h, j) VALUES (3, 0), (4, 1); +INSERT INTO test_alt_table_default (h, j) VALUES (4, 0); -Affected Rows: 2 +Affected Rows: 1 + +INSERT INTO test_alt_table_default (h, i, j) VALUES (5, 42, 0); + +Affected Rows: 1 SELECT * FROM test_alt_table_default ORDER BY h; -+---+---+-------------------------+ -| h | i | j | -+---+---+-------------------------+ -| 1 | 0 | 1970-01-01T00:00:00 | -| 2 | 0 | 1970-01-01T00:00:00.001 | -| 3 | 0 | 1970-01-01T00:00:00 | -| 4 | 0 | 1970-01-01T00:00:00.001 | -+---+---+-------------------------+ ++---+----+---------------------+ +| h | i | j | ++---+----+---------------------+ +| 0 | 0 | 1970-01-01T00:00:00 | +| 1 | 0 | 1970-01-01T00:00:00 | +| 2 | 0 | 1970-01-01T00:00:00 | +| 3 | 1 | 1970-01-01T00:00:00 | +| 4 | 0 | 1970-01-01T00:00:00 | +| 5 | 42 | 1970-01-01T00:00:00 | ++---+----+---------------------+ ALTER TABLE test_alt_table_default MODIFY COLUMN i STRING; Affected Rows: 0 -INSERT INTO test_alt_table_default (h, j) VALUES (5, 0); +INSERT INTO test_alt_table_default (h, j) VALUES (6, 0); Affected Rows: 1 -INSERT INTO test_alt_table_default (h, i, j) VALUES (6, "word" ,1); +INSERT INTO test_alt_table_default (h, i, j) VALUES (7, "word" ,1); Affected Rows: 1 SELECT * FROM test_alt_table_default ORDER BY h; -+---+------+-------------------------+ -| h | i | j | -+---+------+-------------------------+ -| 1 | 0 | 1970-01-01T00:00:00 | -| 2 | 0 | 1970-01-01T00:00:00.001 | -| 3 | 0 | 1970-01-01T00:00:00 | -| 4 | 0 | 1970-01-01T00:00:00.001 | -| 5 | 0 | 1970-01-01T00:00:00 | -| 6 | word | 1970-01-01T00:00:00.001 | -+---+------+-------------------------+ ++---+-------+-------------------------+ +| h | i | j | ++---+-------+-------------------------+ +| 0 | 0.0 | 1970-01-01T00:00:00 | +| 1 | 0.1 | 1970-01-01T00:00:00 | +| 2 | false | 1970-01-01T00:00:00 | +| 3 | true | 1970-01-01T00:00:00 | +| 4 | 0 | 1970-01-01T00:00:00 | +| 5 | 42 | 1970-01-01T00:00:00 | +| 6 | 0 | 1970-01-01T00:00:00 | +| 7 | word | 1970-01-01T00:00:00.001 | ++---+-------+-------------------------+ DROP TABLE test_alt_table_default; Affected Rows: 0 +-- test with non-zero default value +CREATE TABLE test_alt_table_default_nz(h INTEGER, i Float64 DEFAULT 0.1, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); + +Affected Rows: 0 + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (0, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (1, 0.0, 0); + +Affected Rows: 1 + +ADMIN FLUSH_TABLE('test_alt_table_default_nz'); + ++------------------------------------------------+ +| ADMIN FLUSH_TABLE('test_alt_table_default_nz') | ++------------------------------------------------+ +| 0 | ++------------------------------------------------+ + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + ++---+-----+---------------------+ +| h | i | j | ++---+-----+---------------------+ +| 0 | 0.1 | 1970-01-01T00:00:00 | +| 1 | 0.0 | 1970-01-01T00:00:00 | ++---+-----+---------------------+ + +ALTER TABLE test_alt_table_default_nz MODIFY COLUMN i BOOLEAN; + +Affected Rows: 0 + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (2, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (3, FALSE, 0); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + ++---+-------+---------------------+ +| h | i | j | ++---+-------+---------------------+ +| 0 | true | 1970-01-01T00:00:00 | +| 1 | false | 1970-01-01T00:00:00 | +| 2 | true | 1970-01-01T00:00:00 | +| 3 | false | 1970-01-01T00:00:00 | ++---+-------+---------------------+ + +ALTER TABLE test_alt_table_default_nz MODIFY COLUMN i INTEGER; + +Affected Rows: 0 + +DESC TABLE test_alt_table_default_nz; + ++--------+----------------------+-----+------+---------+---------------+ +| Column | Type | Key | Null | Default | Semantic Type | ++--------+----------------------+-----+------+---------+---------------+ +| h | Int32 | PRI | YES | | TAG | +| i | Int32 | | YES | 1 | FIELD | +| j | TimestampMillisecond | PRI | NO | | TIMESTAMP | ++--------+----------------------+-----+------+---------+---------------+ + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (4, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (5, 42, 0); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + ++---+----+---------------------+ +| h | i | j | ++---+----+---------------------+ +| 0 | 0 | 1970-01-01T00:00:00 | +| 1 | 0 | 1970-01-01T00:00:00 | +| 2 | 1 | 1970-01-01T00:00:00 | +| 3 | 0 | 1970-01-01T00:00:00 | +| 4 | 1 | 1970-01-01T00:00:00 | +| 5 | 42 | 1970-01-01T00:00:00 | ++---+----+---------------------+ + +ALTER TABLE test_alt_table_default_nz MODIFY COLUMN i STRING; + +Affected Rows: 0 + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (6, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (7, "word" ,1); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + ++---+-------+-------------------------+ +| h | i | j | ++---+-------+-------------------------+ +| 0 | 0.1 | 1970-01-01T00:00:00 | +| 1 | 0.0 | 1970-01-01T00:00:00 | +| 2 | true | 1970-01-01T00:00:00 | +| 3 | false | 1970-01-01T00:00:00 | +| 4 | 1 | 1970-01-01T00:00:00 | +| 5 | 42 | 1970-01-01T00:00:00 | +| 6 | 1 | 1970-01-01T00:00:00 | +| 7 | word | 1970-01-01T00:00:00.001 | ++---+-------+-------------------------+ + +DROP TABLE test_alt_table_default_nz; + +Affected Rows: 0 + +-- test alter table type will cause wired behavior due to underlying column data is unchanged +CREATE TABLE test_alt_table_col_ty(h INTEGER, i Float64 DEFAULT 0.1, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); + +Affected Rows: 0 + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (0, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (1, 0.2, 0); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_col_ty ORDER BY h; + ++---+-----+---------------------+ +| h | i | j | ++---+-----+---------------------+ +| 0 | 0.1 | 1970-01-01T00:00:00 | +| 1 | 0.2 | 1970-01-01T00:00:00 | ++---+-----+---------------------+ + +ALTER TABLE test_alt_table_col_ty MODIFY COLUMN i BOOLEAN; + +Affected Rows: 0 + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (2, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (3, TRUE, 0); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_col_ty ORDER BY h; + ++---+------+---------------------+ +| h | i | j | ++---+------+---------------------+ +| 0 | true | 1970-01-01T00:00:00 | +| 1 | true | 1970-01-01T00:00:00 | +| 2 | true | 1970-01-01T00:00:00 | +| 3 | true | 1970-01-01T00:00:00 | ++---+------+---------------------+ + +ALTER TABLE test_alt_table_col_ty MODIFY COLUMN i INTEGER; + +Affected Rows: 0 + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (4, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (5, 42, 0); + +Affected Rows: 1 + +SELECT * FROM test_alt_table_col_ty ORDER BY h; + ++---+----+---------------------+ +| h | i | j | ++---+----+---------------------+ +| 0 | 0 | 1970-01-01T00:00:00 | +| 1 | 0 | 1970-01-01T00:00:00 | +| 2 | 1 | 1970-01-01T00:00:00 | +| 3 | 1 | 1970-01-01T00:00:00 | +| 4 | 1 | 1970-01-01T00:00:00 | +| 5 | 42 | 1970-01-01T00:00:00 | ++---+----+---------------------+ + +ALTER TABLE test_alt_table_col_ty MODIFY COLUMN i STRING; + +Affected Rows: 0 + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (6, 0); + +Affected Rows: 1 + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (7, "how many roads must a man walk down before they call him a man", 0); + +Affected Rows: 1 + +-- here see 0.1 is converted to "0.1" since underlying column data is unchanged +SELECT * FROM test_alt_table_col_ty ORDER BY h; + ++---+----------------------------------------------------------------+---------------------+ +| h | i | j | ++---+----------------------------------------------------------------+---------------------+ +| 0 | 0.1 | 1970-01-01T00:00:00 | +| 1 | 0.2 | 1970-01-01T00:00:00 | +| 2 | true | 1970-01-01T00:00:00 | +| 3 | true | 1970-01-01T00:00:00 | +| 4 | 1 | 1970-01-01T00:00:00 | +| 5 | 42 | 1970-01-01T00:00:00 | +| 6 | 1 | 1970-01-01T00:00:00 | +| 7 | how many roads must a man walk down before they call him a man | 1970-01-01T00:00:00 | ++---+----------------------------------------------------------------+---------------------+ + +DROP TABLE test_alt_table_col_ty; + +Affected Rows: 0 + -- to test if same name column can be added CREATE TABLE phy (ts timestamp time index, val double) engine = metric with ("physical_metric_table" = ""); diff --git a/tests/cases/standalone/common/alter/alter_table.sql b/tests/cases/standalone/common/alter/alter_table.sql index 56db60f062..6088ea3bd2 100644 --- a/tests/cases/standalone/common/alter/alter_table.sql +++ b/tests/cases/standalone/common/alter/alter_table.sql @@ -44,11 +44,19 @@ DESC TABLE test_alt_table; DROP TABLE test_alt_table; -- test if column with default value can change type properly -CREATE TABLE test_alt_table_default(h INTEGER, i INTEGER DEFAULT 0, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); +CREATE TABLE test_alt_table_default(h INTEGER, i Float64 DEFAULT 0.0, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); + +INSERT INTO test_alt_table_default (h, j) VALUES (0, 0); + +INSERT INTO test_alt_table_default (h, i, j) VALUES (1, 0.1, 0); + +SELECT * FROM test_alt_table_default ORDER BY h; ALTER TABLE test_alt_table_default MODIFY COLUMN i BOOLEAN; -INSERT INTO test_alt_table_default (h, j) VALUES (1, 0), (2, 1); +INSERT INTO test_alt_table_default (h, j) VALUES (2, 0); + +INSERT INTO test_alt_table_default (h, i, j) VALUES (3, TRUE, 0); SELECT * FROM test_alt_table_default ORDER BY h; @@ -56,20 +64,97 @@ ALTER TABLE test_alt_table_default MODIFY COLUMN i INTEGER; DESC TABLE test_alt_table_default; -INSERT INTO test_alt_table_default (h, j) VALUES (3, 0), (4, 1); +INSERT INTO test_alt_table_default (h, j) VALUES (4, 0); + +INSERT INTO test_alt_table_default (h, i, j) VALUES (5, 42, 0); SELECT * FROM test_alt_table_default ORDER BY h; ALTER TABLE test_alt_table_default MODIFY COLUMN i STRING; -INSERT INTO test_alt_table_default (h, j) VALUES (5, 0); +INSERT INTO test_alt_table_default (h, j) VALUES (6, 0); -INSERT INTO test_alt_table_default (h, i, j) VALUES (6, "word" ,1); +INSERT INTO test_alt_table_default (h, i, j) VALUES (7, "word" ,1); SELECT * FROM test_alt_table_default ORDER BY h; DROP TABLE test_alt_table_default; +-- test with non-zero default value +CREATE TABLE test_alt_table_default_nz(h INTEGER, i Float64 DEFAULT 0.1, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (0, 0); + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (1, 0.0, 0); + +ADMIN FLUSH_TABLE('test_alt_table_default_nz'); + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + +ALTER TABLE test_alt_table_default_nz MODIFY COLUMN i BOOLEAN; + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (2, 0); + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (3, FALSE, 0); + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + +ALTER TABLE test_alt_table_default_nz MODIFY COLUMN i INTEGER; + +DESC TABLE test_alt_table_default_nz; + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (4, 0); + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (5, 42, 0); + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + +ALTER TABLE test_alt_table_default_nz MODIFY COLUMN i STRING; + +INSERT INTO test_alt_table_default_nz (h, j) VALUES (6, 0); + +INSERT INTO test_alt_table_default_nz (h, i, j) VALUES (7, "word" ,1); + +SELECT * FROM test_alt_table_default_nz ORDER BY h; + +DROP TABLE test_alt_table_default_nz; + +-- test alter table type will cause wired behavior due to underlying column data is unchanged +CREATE TABLE test_alt_table_col_ty(h INTEGER, i Float64 DEFAULT 0.1, j TIMESTAMP TIME INDEX, PRIMARY KEY (h)); + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (0, 0); + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (1, 0.2, 0); + +SELECT * FROM test_alt_table_col_ty ORDER BY h; + +ALTER TABLE test_alt_table_col_ty MODIFY COLUMN i BOOLEAN; + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (2, 0); + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (3, TRUE, 0); + +SELECT * FROM test_alt_table_col_ty ORDER BY h; + +ALTER TABLE test_alt_table_col_ty MODIFY COLUMN i INTEGER; + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (4, 0); + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (5, 42, 0); + +SELECT * FROM test_alt_table_col_ty ORDER BY h; + +ALTER TABLE test_alt_table_col_ty MODIFY COLUMN i STRING; + +INSERT INTO test_alt_table_col_ty (h, j) VALUES (6, 0); + +INSERT INTO test_alt_table_col_ty (h, i, j) VALUES (7, "how many roads must a man walk down before they call him a man", 0); + +-- here see 0.1 is converted to "0.1" since underlying column data is unchanged +SELECT * FROM test_alt_table_col_ty ORDER BY h; + +DROP TABLE test_alt_table_col_ty; + -- to test if same name column can be added CREATE TABLE phy (ts timestamp time index, val double) engine = metric with ("physical_metric_table" = "");