mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2025-12-22 22:20:02 +00:00
fix: alter table modify type should also modify default value (#6049)
* fix: select after alter * fix: insert a proper row&catch a bug * fix: alter table modify type modify default value type too * refactor: per review * chore: per review * refactor: per review * refactor: per review
This commit is contained in:
@@ -20,6 +20,7 @@ use snafu::{ensure, ResultExt};
|
|||||||
|
|
||||||
use crate::data_type::{ConcreteDataType, DataType};
|
use crate::data_type::{ConcreteDataType, DataType};
|
||||||
use crate::error::{self, Result};
|
use crate::error::{self, Result};
|
||||||
|
use crate::types::cast;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vectors::operations::VectorOp;
|
use crate::vectors::operations::VectorOp;
|
||||||
use crate::vectors::{TimestampMillisecondVector, VectorRef};
|
use crate::vectors::{TimestampMillisecondVector, VectorRef};
|
||||||
@@ -178,6 +179,18 @@ impl ColumnDefaultConstraint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cast default value to given type
|
||||||
|
pub fn cast_to_datatype(&self, data_type: &ConcreteDataType) -> Result<Self> {
|
||||||
|
match self {
|
||||||
|
ColumnDefaultConstraint::Value(v) => Ok(Self::Value(cast(v.clone(), data_type)?)),
|
||||||
|
ColumnDefaultConstraint::Function(expr) => match &expr[..] {
|
||||||
|
// no need to cast, since function always require a data_type when need to create default value
|
||||||
|
CURRENT_TIMESTAMP | CURRENT_TIMESTAMP_FN | NOW_FN => Ok(self.clone()),
|
||||||
|
_ => error::UnsupportedDefaultExprSnafu { expr }.fail(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Only create default vector if it's impure, i.e., it's a function.
|
/// Only create default vector if it's impure, i.e., it's a function.
|
||||||
///
|
///
|
||||||
/// This helps to delay creating constant default values to mito engine while also keeps impure default have consistent values
|
/// This helps to delay creating constant default values to mito engine while also keeps impure default have consistent values
|
||||||
|
|||||||
@@ -243,6 +243,8 @@ pub enum Error {
|
|||||||
region_id: RegionId,
|
region_id: RegionId,
|
||||||
column: String,
|
column: String,
|
||||||
source: datatypes::Error,
|
source: datatypes::Error,
|
||||||
|
#[snafu(implicit)]
|
||||||
|
location: Location,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[snafu(display("Failed to build entry, region_id: {}", region_id))]
|
#[snafu(display("Failed to build entry, region_id: {}", region_id))]
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ impl RegionMetadataBuilder {
|
|||||||
match kind {
|
match kind {
|
||||||
AlterKind::AddColumns { columns } => self.add_columns(columns)?,
|
AlterKind::AddColumns { columns } => self.add_columns(columns)?,
|
||||||
AlterKind::DropColumns { names } => self.drop_columns(&names),
|
AlterKind::DropColumns { names } => self.drop_columns(&names),
|
||||||
AlterKind::ModifyColumnTypes { columns } => self.modify_column_types(columns),
|
AlterKind::ModifyColumnTypes { columns } => self.modify_column_types(columns)?,
|
||||||
AlterKind::SetIndex { options } => match options {
|
AlterKind::SetIndex { options } => match options {
|
||||||
ApiSetIndexOptions::Fulltext {
|
ApiSetIndexOptions::Fulltext {
|
||||||
column_name,
|
column_name,
|
||||||
@@ -681,7 +681,7 @@ impl RegionMetadataBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Changes columns type to the metadata if exist.
|
/// Changes columns type to the metadata if exist.
|
||||||
fn modify_column_types(&mut self, columns: Vec<ModifyColumnType>) {
|
fn modify_column_types(&mut self, columns: Vec<ModifyColumnType>) -> Result<()> {
|
||||||
let mut change_type_map: HashMap<_, _> = columns
|
let mut change_type_map: HashMap<_, _> = columns
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(
|
.map(
|
||||||
@@ -694,9 +694,34 @@ impl RegionMetadataBuilder {
|
|||||||
|
|
||||||
for column_meta in self.column_metadatas.iter_mut() {
|
for column_meta in self.column_metadatas.iter_mut() {
|
||||||
if let Some(target_type) = change_type_map.remove(&column_meta.column_schema.name) {
|
if let Some(target_type) = change_type_map.remove(&column_meta.column_schema.name) {
|
||||||
column_meta.column_schema.data_type = target_type;
|
column_meta.column_schema.data_type = target_type.clone();
|
||||||
|
// also cast default value to target_type if default value exist
|
||||||
|
let new_default =
|
||||||
|
if let Some(default_value) = column_meta.column_schema.default_constraint() {
|
||||||
|
Some(
|
||||||
|
default_value
|
||||||
|
.cast_to_datatype(&target_type)
|
||||||
|
.with_context(|_| CastDefaultValueSnafu {
|
||||||
|
reason: format!(
|
||||||
|
"Failed to cast default value from {:?} to type {:?}",
|
||||||
|
default_value, target_type
|
||||||
|
),
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
column_meta.column_schema = column_meta
|
||||||
|
.column_schema
|
||||||
|
.clone()
|
||||||
|
.with_default_constraint(new_default.clone())
|
||||||
|
.with_context(|_| CastDefaultValueSnafu {
|
||||||
|
reason: format!("Failed to set new default: {:?}", new_default),
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_column_inverted_index_options(
|
fn change_column_inverted_index_options(
|
||||||
@@ -967,6 +992,14 @@ pub enum MetadataError {
|
|||||||
location: Location,
|
location: Location,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[snafu(display("Failed to cast default value, reason: {}", reason))]
|
||||||
|
CastDefaultValue {
|
||||||
|
reason: String,
|
||||||
|
source: datatypes::Error,
|
||||||
|
#[snafu(implicit)]
|
||||||
|
location: Location,
|
||||||
|
},
|
||||||
|
|
||||||
#[snafu(display("Unexpected: {}", reason))]
|
#[snafu(display("Unexpected: {}", reason))]
|
||||||
Unexpected {
|
Unexpected {
|
||||||
reason: String,
|
reason: String,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use datatypes::data_type::DataType;
|
|||||||
use snafu::{ensure, ResultExt};
|
use snafu::{ensure, ResultExt};
|
||||||
use sqlx::MySqlPool;
|
use sqlx::MySqlPool;
|
||||||
|
|
||||||
use crate::error::{self, Result};
|
use crate::error::{self, Result, UnexpectedSnafu};
|
||||||
use crate::ir::create_expr::ColumnOption;
|
use crate::ir::create_expr::ColumnOption;
|
||||||
use crate::ir::{Column, Ident};
|
use crate::ir::{Column, Ident};
|
||||||
|
|
||||||
@@ -211,6 +211,35 @@ pub async fn fetch_columns(
|
|||||||
.context(error::ExecuteQuerySnafu { sql })
|
.context(error::ExecuteQuerySnafu { sql })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// validate that apart from marker column(if it still exists, every thing else is just default value)
|
||||||
|
#[allow(unused)]
|
||||||
|
pub async fn valid_marker_value(
|
||||||
|
db: &MySqlPool,
|
||||||
|
_schema_name: Ident,
|
||||||
|
table_name: Ident,
|
||||||
|
) -> Result<bool> {
|
||||||
|
let sql = format!("SELECT * FROM {table_name}");
|
||||||
|
// cache is useless and buggy anyway since alter happens all the time
|
||||||
|
// TODO(discord9): invalid prepared sql after alter
|
||||||
|
let res = sqlx::query(&sql)
|
||||||
|
.persistent(false)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.context(error::ExecuteQuerySnafu { sql })?;
|
||||||
|
if res.len() != 1 {
|
||||||
|
UnexpectedSnafu {
|
||||||
|
violated: format!(
|
||||||
|
"Expected one row after alter table, found {}:{:?}",
|
||||||
|
res.len(),
|
||||||
|
res
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.fail()?
|
||||||
|
}
|
||||||
|
// TODO(discord9): make sure marker value is set
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use datatypes::data_type::{ConcreteDataType, DataType};
|
use datatypes::data_type::{ConcreteDataType, DataType};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use arbitrary::{Arbitrary, Unstructured};
|
use arbitrary::{Arbitrary, Unstructured};
|
||||||
use common_telemetry::info;
|
use common_telemetry::info;
|
||||||
|
use datatypes::prelude::{ConcreteDataType, DataType};
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_chacha::ChaChaRng;
|
use rand_chacha::ChaChaRng;
|
||||||
@@ -26,7 +27,7 @@ use snafu::ResultExt;
|
|||||||
use sqlx::{MySql, Pool};
|
use sqlx::{MySql, Pool};
|
||||||
use strum::{EnumIter, IntoEnumIterator};
|
use strum::{EnumIter, IntoEnumIterator};
|
||||||
use tests_fuzz::context::{TableContext, TableContextRef};
|
use tests_fuzz::context::{TableContext, TableContextRef};
|
||||||
use tests_fuzz::error::{self, Result};
|
use tests_fuzz::error::{self, Result, UnexpectedSnafu};
|
||||||
use tests_fuzz::fake::{
|
use tests_fuzz::fake::{
|
||||||
merge_two_word_map_fn, random_capitalize_map, uppercase_and_keyword_backtick_map,
|
merge_two_word_map_fn, random_capitalize_map, uppercase_and_keyword_backtick_map,
|
||||||
MappedGenerator, WordGenerator,
|
MappedGenerator, WordGenerator,
|
||||||
@@ -94,6 +95,63 @@ fn generate_create_table_expr<R: Rng + 'static>(rng: &mut R) -> Result<CreateTab
|
|||||||
create_table_generator.generate(rng)
|
create_table_generator.generate(rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the insert sql that insert one row of non-default value in table
|
||||||
|
#[allow(unused)]
|
||||||
|
fn generate_insert_table_sql<R: Rng + 'static>(
|
||||||
|
rng: &mut R,
|
||||||
|
create_table_expr: &CreateTableExpr,
|
||||||
|
) -> Result<String> {
|
||||||
|
use datatypes::value::Value;
|
||||||
|
let mut column_names = vec![];
|
||||||
|
let mut column_values = vec![];
|
||||||
|
for column in &create_table_expr.columns {
|
||||||
|
if column.is_time_index() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let marker_name = &column.name;
|
||||||
|
let marker_value = match column.column_type {
|
||||||
|
ConcreteDataType::Boolean(_) => Value::Boolean(true),
|
||||||
|
ConcreteDataType::Int16(_) => Value::Int16(42),
|
||||||
|
ConcreteDataType::Int32(_) => Value::Int32(42),
|
||||||
|
ConcreteDataType::Int64(_) => Value::Int64(42),
|
||||||
|
ConcreteDataType::Float32(_) => Value::from(42.0f32),
|
||||||
|
ConcreteDataType::Float64(_) => Value::from(42.0f64),
|
||||||
|
ConcreteDataType::String(_) => Value::from("How many roads must a man walk down?"),
|
||||||
|
_ => UnexpectedSnafu {
|
||||||
|
violated: format!(
|
||||||
|
"Unexpected datatype, found {} in create-table={:?}",
|
||||||
|
column.column_type, create_table_expr
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.fail()?,
|
||||||
|
};
|
||||||
|
column_names.push(marker_name.to_string());
|
||||||
|
column_values.push(marker_value.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let table_name = &create_table_expr.table_name;
|
||||||
|
|
||||||
|
let ts_column = create_table_expr
|
||||||
|
.columns
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.is_time_index())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let ts_column_name = &ts_column.name;
|
||||||
|
let ts_column_value = ts_column.column_type.default_value();
|
||||||
|
|
||||||
|
let concat_column_names = column_names.join(",");
|
||||||
|
|
||||||
|
let concat_column_values = column_values.join(",");
|
||||||
|
|
||||||
|
let sql = format!(
|
||||||
|
"INSERT INTO {table_name} ({concat_column_names}, {ts_column_name}) VALUES ({concat_column_values}, \"{ts_column_value}\");"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(sql)
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_alter_table_expr<R: Rng + 'static>(
|
fn generate_alter_table_expr<R: Rng + 'static>(
|
||||||
table_ctx: TableContextRef,
|
table_ctx: TableContextRef,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
@@ -173,6 +231,13 @@ async fn execute_alter_table(ctx: FuzzContext, input: FuzzInput) -> Result<()> {
|
|||||||
.context(error::ExecuteQuerySnafu { sql: &sql })?;
|
.context(error::ExecuteQuerySnafu { sql: &sql })?;
|
||||||
info!("Create table: {sql}, result: {result:?}");
|
info!("Create table: {sql}, result: {result:?}");
|
||||||
|
|
||||||
|
let insert = generate_insert_table_sql(&mut rng, &expr)?;
|
||||||
|
let result = sqlx::query(&insert)
|
||||||
|
.execute(&ctx.greptime)
|
||||||
|
.await
|
||||||
|
.context(error::ExecuteQuerySnafu { sql: &insert })?;
|
||||||
|
info!("Insert Into table: {insert}, result: {result:?}");
|
||||||
|
|
||||||
// Alter table actions
|
// Alter table actions
|
||||||
let mut table_ctx = Arc::new(TableContext::from(&expr));
|
let mut table_ctx = Arc::new(TableContext::from(&expr));
|
||||||
for _ in 0..input.actions {
|
for _ in 0..input.actions {
|
||||||
@@ -187,6 +252,14 @@ async fn execute_alter_table(ctx: FuzzContext, input: FuzzInput) -> Result<()> {
|
|||||||
// Applies changes
|
// Applies changes
|
||||||
table_ctx = Arc::new(Arc::unwrap_or_clone(table_ctx).alter(expr).unwrap());
|
table_ctx = Arc::new(Arc::unwrap_or_clone(table_ctx).alter(expr).unwrap());
|
||||||
|
|
||||||
|
// validate value
|
||||||
|
validator::column::valid_marker_value(
|
||||||
|
&ctx.greptime,
|
||||||
|
"public".into(),
|
||||||
|
table_ctx.name.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Validates columns
|
// Validates columns
|
||||||
let mut column_entries = validator::column::fetch_columns(
|
let mut column_entries = validator::column::fetch_columns(
|
||||||
&ctx.greptime,
|
&ctx.greptime,
|
||||||
|
|||||||
@@ -69,6 +69,52 @@ ALTER TABLE test_alt_table MODIFY COLUMN m interval;
|
|||||||
|
|
||||||
Error: 1001(Unsupported), Not supported: Modify column type to interval type
|
Error: 1001(Unsupported), Not supported: Modify column type to interval type
|
||||||
|
|
||||||
|
INSERT INTO test_alt_table (h, i, j, m, dt) VALUES (42, 42, 0, 11, 0);
|
||||||
|
|
||||||
|
Affected Rows: 1
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table MODIFY COLUMN m Float64;
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table;
|
||||||
|
|
||||||
|
+----+----+-------------------------+---+------+---------------------+
|
||||||
|
| h | i | j | k | m | dt |
|
||||||
|
+----+----+-------------------------+---+------+---------------------+
|
||||||
|
| 1 | 1 | 1970-01-01T00:00:00 | | | |
|
||||||
|
| 2 | 2 | 1970-01-01T00:00:00.001 | | | |
|
||||||
|
| 42 | 42 | 1970-01-01T00:00:00 | | 11.0 | 1970-01-01T00:00:00 |
|
||||||
|
+----+----+-------------------------+---+------+---------------------+
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table MODIFY COLUMN m INTEGER;
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table;
|
||||||
|
|
||||||
|
+----+----+-------------------------+---+----+---------------------+
|
||||||
|
| h | i | j | k | m | dt |
|
||||||
|
+----+----+-------------------------+---+----+---------------------+
|
||||||
|
| 1 | 1 | 1970-01-01T00:00:00 | | | |
|
||||||
|
| 2 | 2 | 1970-01-01T00:00:00.001 | | | |
|
||||||
|
| 42 | 42 | 1970-01-01T00:00:00 | | 11 | 1970-01-01T00:00:00 |
|
||||||
|
+----+----+-------------------------+---+----+---------------------+
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table MODIFY COLUMN m BOOLEAN;
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table;
|
||||||
|
|
||||||
|
+----+----+-------------------------+---+------+---------------------+
|
||||||
|
| h | i | j | k | m | dt |
|
||||||
|
+----+----+-------------------------+---+------+---------------------+
|
||||||
|
| 1 | 1 | 1970-01-01T00:00:00 | | | |
|
||||||
|
| 2 | 2 | 1970-01-01T00:00:00.001 | | | |
|
||||||
|
| 42 | 42 | 1970-01-01T00:00:00 | | true | 1970-01-01T00:00:00 |
|
||||||
|
+----+----+-------------------------+---+------+---------------------+
|
||||||
|
|
||||||
DESC TABLE test_alt_table;
|
DESC TABLE test_alt_table;
|
||||||
|
|
||||||
+--------+----------------------+-----+------+---------+---------------+
|
+--------+----------------------+-----+------+---------+---------------+
|
||||||
@@ -78,7 +124,7 @@ DESC TABLE test_alt_table;
|
|||||||
| i | Int32 | PRI | YES | | TAG |
|
| i | Int32 | PRI | YES | | TAG |
|
||||||
| j | TimestampMillisecond | PRI | NO | | TIMESTAMP |
|
| j | TimestampMillisecond | PRI | NO | | TIMESTAMP |
|
||||||
| k | String | PRI | YES | | TAG |
|
| k | String | PRI | YES | | TAG |
|
||||||
| m | Int32 | | YES | | FIELD |
|
| m | Boolean | | YES | | FIELD |
|
||||||
| dt | TimestampMicrosecond | | YES | | FIELD |
|
| dt | TimestampMicrosecond | | YES | | FIELD |
|
||||||
+--------+----------------------+-----+------+---------+---------------+
|
+--------+----------------------+-----+------+---------+---------------+
|
||||||
|
|
||||||
@@ -86,6 +132,86 @@ DROP TABLE test_alt_table;
|
|||||||
|
|
||||||
Affected Rows: 0
|
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));
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Affected Rows: 2
|
||||||
|
|
||||||
|
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 |
|
||||||
|
+---+-------+-------------------------+
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table_default MODIFY COLUMN i INTEGER;
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
|
DESC TABLE test_alt_table_default;
|
||||||
|
|
||||||
|
+--------+----------------------+-----+------+---------+---------------+
|
||||||
|
| Column | Type | Key | Null | Default | Semantic Type |
|
||||||
|
+--------+----------------------+-----+------+---------+---------------+
|
||||||
|
| h | Int32 | PRI | YES | | TAG |
|
||||||
|
| i | Int32 | | YES | 0 | FIELD |
|
||||||
|
| j | TimestampMillisecond | PRI | NO | | TIMESTAMP |
|
||||||
|
+--------+----------------------+-----+------+---------+---------------+
|
||||||
|
|
||||||
|
INSERT INTO test_alt_table_default (h, j) VALUES (3, 0), (4, 1);
|
||||||
|
|
||||||
|
Affected Rows: 2
|
||||||
|
|
||||||
|
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 |
|
||||||
|
+---+---+-------------------------+
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table_default MODIFY COLUMN i STRING;
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
|
INSERT INTO test_alt_table_default (h, j) VALUES (5, 0);
|
||||||
|
|
||||||
|
Affected Rows: 1
|
||||||
|
|
||||||
|
INSERT INTO test_alt_table_default (h, i, j) VALUES (6, "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 |
|
||||||
|
+---+------+-------------------------+
|
||||||
|
|
||||||
|
DROP TABLE test_alt_table_default;
|
||||||
|
|
||||||
|
Affected Rows: 0
|
||||||
|
|
||||||
-- to test if same name column can be added
|
-- to test if same name column can be added
|
||||||
CREATE TABLE phy (ts timestamp time index, val double) engine = metric with ("physical_metric_table" = "");
|
CREATE TABLE phy (ts timestamp time index, val double) engine = metric with ("physical_metric_table" = "");
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,51 @@ ALTER TABLE test_alt_table ADD COLUMN n interval;
|
|||||||
-- Should fail issue #5422
|
-- Should fail issue #5422
|
||||||
ALTER TABLE test_alt_table MODIFY COLUMN m interval;
|
ALTER TABLE test_alt_table MODIFY COLUMN m interval;
|
||||||
|
|
||||||
|
INSERT INTO test_alt_table (h, i, j, m, dt) VALUES (42, 42, 0, 11, 0);
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table MODIFY COLUMN m Float64;
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table;
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table MODIFY COLUMN m INTEGER;
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table;
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table MODIFY COLUMN m BOOLEAN;
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table;
|
||||||
|
|
||||||
DESC TABLE test_alt_table;
|
DESC TABLE test_alt_table;
|
||||||
|
|
||||||
DROP 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));
|
||||||
|
|
||||||
|
ALTER TABLE test_alt_table_default MODIFY COLUMN i BOOLEAN;
|
||||||
|
|
||||||
|
INSERT INTO test_alt_table_default (h, j) VALUES (1, 0), (2, 1);
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table_default ORDER BY h;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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, i, j) VALUES (6, "word" ,1);
|
||||||
|
|
||||||
|
SELECT * FROM test_alt_table_default ORDER BY h;
|
||||||
|
|
||||||
|
DROP TABLE test_alt_table_default;
|
||||||
|
|
||||||
-- to test if same name column can be added
|
-- to test if same name column can be added
|
||||||
CREATE TABLE phy (ts timestamp time index, val double) engine = metric with ("physical_metric_table" = "");
|
CREATE TABLE phy (ts timestamp time index, val double) engine = metric with ("physical_metric_table" = "");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user