mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-04 04:12:55 +00:00
feat: Add DROP DEFAULT (#6290)
* feat: Add `DROP DEFAULT` Signed-off-by: Yihai Lin <yihai-lin@foxmail.com> * chore: use `next_token` Signed-off-by: Yihai Lin <yihai-lin@foxmail.com> --------- Signed-off-by: Yihai Lin <yihai-lin@foxmail.com>
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -5143,7 +5143,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "greptime-proto"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/GreptimeTeam/greptime-proto.git?rev=fdcbe5f1c7c467634c90a1fd1a00a784b92a4e80#fdcbe5f1c7c467634c90a1fd1a00a784b92a4e80"
|
||||
source = "git+https://github.com/firefantasy/greptime-proto.git?rev=abaee5144a833a025f5bc0e41642ef733d9c5c98#abaee5144a833a025f5bc0e41642ef733d9c5c98"
|
||||
dependencies = [
|
||||
"prost 0.13.5",
|
||||
"serde",
|
||||
|
||||
@@ -134,7 +134,7 @@ etcd-client = "0.14"
|
||||
fst = "0.4.7"
|
||||
futures = "0.3"
|
||||
futures-util = "0.3"
|
||||
greptime-proto = { git = "https://github.com/GreptimeTeam/greptime-proto.git", rev = "fdcbe5f1c7c467634c90a1fd1a00a784b92a4e80" }
|
||||
greptime-proto = { git = "https://github.com/firefantasy/greptime-proto.git", rev = "abaee5144a833a025f5bc0e41642ef733d9c5c98" }
|
||||
hex = "0.4"
|
||||
http = "1"
|
||||
humantime = "2.1"
|
||||
|
||||
@@ -180,6 +180,22 @@ pub fn alter_expr_to_request(table_id: TableId, expr: AlterTableExpr) -> Result<
|
||||
},
|
||||
None => return MissingAlterIndexOptionSnafu.fail(),
|
||||
},
|
||||
Kind::DropDefaults(o) => {
|
||||
let names = o
|
||||
.drop_defaults
|
||||
.into_iter()
|
||||
.map(|col| {
|
||||
ensure!(
|
||||
!col.column_name.is_empty(),
|
||||
MissingFieldSnafu {
|
||||
field: "column_name"
|
||||
}
|
||||
);
|
||||
Ok(col.column_name)
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
AlterKind::DropDefaults { names }
|
||||
}
|
||||
};
|
||||
|
||||
let request = AlterTableRequest {
|
||||
|
||||
@@ -135,6 +135,7 @@ fn create_proto_alter_kind(
|
||||
Kind::UnsetTableOptions(v) => Ok(Some(alter_request::Kind::UnsetTableOptions(v.clone()))),
|
||||
Kind::SetIndex(v) => Ok(Some(alter_request::Kind::SetIndex(v.clone()))),
|
||||
Kind::UnsetIndex(v) => Ok(Some(alter_request::Kind::UnsetIndex(v.clone()))),
|
||||
Kind::DropDefaults(v) => Ok(Some(alter_request::Kind::DropDefaults(v.clone()))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ impl AlterTableProcedure {
|
||||
| AlterKind::SetTableOptions { .. }
|
||||
| AlterKind::UnsetTableOptions { .. }
|
||||
| AlterKind::SetIndex { .. }
|
||||
| AlterKind::UnsetIndex { .. } => {}
|
||||
| AlterKind::UnsetIndex { .. }
|
||||
| AlterKind::DropDefaults { .. } => {}
|
||||
}
|
||||
|
||||
Ok(new_info)
|
||||
|
||||
@@ -24,11 +24,11 @@ use api::v1::column_def::options_from_column_schema;
|
||||
use api::v1::{
|
||||
set_index, unset_index, AddColumn, AddColumns, AlterDatabaseExpr, AlterTableExpr, Analyzer,
|
||||
ColumnDataType, ColumnDataTypeExtension, CreateFlowExpr, CreateTableExpr, CreateViewExpr,
|
||||
DropColumn, DropColumns, ExpireAfter, FulltextBackend as PbFulltextBackend, ModifyColumnType,
|
||||
ModifyColumnTypes, RenameTable, SemanticType, SetDatabaseOptions, SetFulltext, SetIndex,
|
||||
SetInverted, SetSkipping, SetTableOptions, SkippingIndexType as PbSkippingIndexType, TableName,
|
||||
UnsetDatabaseOptions, UnsetFulltext, UnsetIndex, UnsetInverted, UnsetSkipping,
|
||||
UnsetTableOptions,
|
||||
DropColumn, DropColumns, DropDefaults, ExpireAfter, FulltextBackend as PbFulltextBackend,
|
||||
ModifyColumnType, ModifyColumnTypes, RenameTable, SemanticType, SetDatabaseOptions,
|
||||
SetFulltext, SetIndex, SetInverted, SetSkipping, SetTableOptions,
|
||||
SkippingIndexType as PbSkippingIndexType, TableName, UnsetDatabaseOptions, UnsetFulltext,
|
||||
UnsetIndex, UnsetInverted, UnsetSkipping, UnsetTableOptions,
|
||||
};
|
||||
use common_error::ext::BoxedError;
|
||||
use common_grpc_expr::util::ColumnExpr;
|
||||
@@ -631,6 +631,17 @@ pub(crate) fn to_alter_table_expr(
|
||||
})),
|
||||
},
|
||||
}),
|
||||
AlterTableOperation::DropDefaults { columns } => {
|
||||
AlterTableKind::DropDefaults(DropDefaults {
|
||||
drop_defaults: columns
|
||||
.into_iter()
|
||||
.map(|col| {
|
||||
let column_name = col.0.to_string();
|
||||
Ok(api::v1::DropDefault { column_name })
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(AlterTableExpr {
|
||||
|
||||
@@ -30,7 +30,7 @@ use crate::parsers::utils::{
|
||||
};
|
||||
use crate::statements::alter::{
|
||||
AddColumn, AlterDatabase, AlterDatabaseOperation, AlterTable, AlterTableOperation,
|
||||
KeyValueOption, SetIndexOperation, UnsetIndexOperation,
|
||||
DropDefaultsOperation, KeyValueOption, SetIndexOperation, UnsetIndexOperation,
|
||||
};
|
||||
use crate::statements::statement::Statement;
|
||||
use crate::util::parse_option_string;
|
||||
@@ -156,6 +156,7 @@ impl ParserContext<'_> {
|
||||
.collect();
|
||||
AlterTableOperation::SetTableOptions { options }
|
||||
}
|
||||
Keyword::ALTER => self.parse_alter_columns()?,
|
||||
_ => self.expected(
|
||||
"ADD or DROP or MODIFY or RENAME or SET after ALTER TABLE",
|
||||
self.parser.peek_token(),
|
||||
@@ -168,6 +169,29 @@ impl ParserContext<'_> {
|
||||
Ok(AlterTable::new(table_name, alter_operation))
|
||||
}
|
||||
|
||||
// Parse the following: ALTER TABLE table_name ALTER ...
|
||||
fn parse_alter_columns(&mut self) -> Result<AlterTableOperation> {
|
||||
let _ = self.parser.next_token();
|
||||
let _ = self.parser.next_token();
|
||||
let ts = self.parser.next_token();
|
||||
match ts.token {
|
||||
// Parse `DROP DEFAULT`: ALTER TABLE `table_name` ALTER `a` DROP DEFAULT, ALTER `b` DROP DEFAULT, ...
|
||||
Token::Word(w) if w.keyword == Keyword::DROP => {
|
||||
let ts = self.parser.peek_token();
|
||||
match ts.token {
|
||||
Token::Word(w) if w.keyword == Keyword::DEFAULT => {
|
||||
self.parser.prev_token();
|
||||
self.parser.prev_token();
|
||||
self.parser.prev_token();
|
||||
self.parse_alter_table_drop_default()
|
||||
}
|
||||
_ => self.expected("DEFAULT is expecting after DROP", ts),
|
||||
}
|
||||
}
|
||||
_ => self.expected("DROP after ALTER COLUMN", ts),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_alter_table_unset(&mut self) -> Result<AlterTableOperation> {
|
||||
let _ = self.parser.next_token();
|
||||
let keys = self
|
||||
@@ -198,6 +222,14 @@ impl ParserContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_alter_table_drop_default(&mut self) -> Result<AlterTableOperation> {
|
||||
let columns = self
|
||||
.parser
|
||||
.parse_comma_separated(parse_alter_column_drop_default)
|
||||
.context(error::SyntaxSnafu)?;
|
||||
Ok(AlterTableOperation::DropDefaults { columns })
|
||||
}
|
||||
|
||||
fn parse_alter_table_modify(&mut self) -> Result<AlterTableOperation> {
|
||||
let _ = self.parser.next_token();
|
||||
self.parser
|
||||
@@ -385,6 +417,23 @@ impl ParserContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_alter_column_drop_default(
|
||||
parser: &mut Parser,
|
||||
) -> std::result::Result<DropDefaultsOperation, ParserError> {
|
||||
parser.next_token();
|
||||
let column_name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
|
||||
if parser.parse_keywords(&[Keyword::DROP, Keyword::DEFAULT]) {
|
||||
Ok(DropDefaultsOperation(column_name))
|
||||
} else {
|
||||
let not_drop = parser.peek_token();
|
||||
parser.next_token();
|
||||
let not_default = parser.peek_token();
|
||||
Err(ParserError::ParserError(format!(
|
||||
"Unexpected keyword, expect DROP DEFAULT, got: `{not_drop} {not_default}`"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a string literal and an optional string literal value.
|
||||
fn parse_string_options(parser: &mut Parser) -> std::result::Result<(String, String), ParserError> {
|
||||
let name = parser.parse_literal_string()?;
|
||||
@@ -1125,4 +1174,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_alter_drop_default() {
|
||||
let columns = vec![vec!["a"], vec!["a", "b", "c"]];
|
||||
for col in columns {
|
||||
let sql = col
|
||||
.iter()
|
||||
.map(|x| format!("ALTER {x} DROP DEFAULT"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(",");
|
||||
let sql = format!("ALTER TABLE test_table {sql}");
|
||||
let mut result = ParserContext::create_with_dialect(
|
||||
&sql,
|
||||
&GreptimeDbDialect {},
|
||||
ParseOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(1, result.len());
|
||||
let statement = result.remove(0);
|
||||
assert_matches!(statement, Statement::AlterTable { .. });
|
||||
match statement {
|
||||
Statement::AlterTable(alter_table) => {
|
||||
assert_eq!("test_table", alter_table.table_name().0[0].value);
|
||||
let alter_operation = alter_table.alter_operation();
|
||||
match alter_operation {
|
||||
AlterTableOperation::DropDefaults { columns } => {
|
||||
assert_eq!(col.len(), columns.len());
|
||||
for i in 0..columns.len() {
|
||||
assert_eq!(col[i], columns[i].0.value);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +92,15 @@ pub enum AlterTableOperation {
|
||||
UnsetIndex {
|
||||
options: UnsetIndexOperation,
|
||||
},
|
||||
DropDefaults {
|
||||
columns: Vec<DropDefaultsOperation>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
/// `ALTER <column_name> DROP DEFAULT`
|
||||
pub struct DropDefaultsOperation(pub Ident);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
pub enum SetIndexOperation {
|
||||
/// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
|
||||
@@ -204,6 +211,13 @@ impl Display for AlterTableOperation {
|
||||
write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
|
||||
}
|
||||
},
|
||||
AlterTableOperation::DropDefaults { columns } => {
|
||||
let columns = columns
|
||||
.iter()
|
||||
.map(|column| format!("ALTER {} DROP DEFAULT", column.0))
|
||||
.join(", ");
|
||||
write!(f, "{columns}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,5 +501,26 @@ ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX"#,
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
let sql = "ALTER TABLE monitor ALTER a DROP DEFAULT";
|
||||
let stmts =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
assert_eq!(1, stmts.len());
|
||||
assert_matches!(&stmts[0], Statement::AlterTable { .. });
|
||||
|
||||
match &stmts[0] {
|
||||
Statement::AlterTable(set) => {
|
||||
let new_sql = format!("\n{}", set);
|
||||
assert_eq!(
|
||||
r#"
|
||||
ALTER TABLE monitor ALTER a DROP DEFAULT"#,
|
||||
&new_sql
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,6 +612,9 @@ impl RegionMetadataBuilder {
|
||||
AlterKind::UnsetRegionOptions { keys: _ } => {
|
||||
// nothing to be done with RegionMetadata
|
||||
}
|
||||
AlterKind::DropDefaults { names } => {
|
||||
self.drop_defaults(names)?;
|
||||
}
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
@@ -826,6 +829,40 @@ impl RegionMetadataBuilder {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn drop_defaults(&mut self, column_names: Vec<String>) -> Result<()> {
|
||||
for name in column_names.iter() {
|
||||
let meta = self
|
||||
.column_metadatas
|
||||
.iter_mut()
|
||||
.find(|col| col.column_schema.name == *name);
|
||||
if let Some(meta) = meta {
|
||||
if !meta.column_schema.is_nullable() {
|
||||
return InvalidRegionRequestSnafu {
|
||||
region_id: self.region_id,
|
||||
err: format!(
|
||||
"column {name} is not nullable and `default` cannot be dropped",
|
||||
),
|
||||
}
|
||||
.fail();
|
||||
}
|
||||
meta.column_schema = meta
|
||||
.column_schema
|
||||
.clone()
|
||||
.with_default_constraint(None)
|
||||
.with_context(|_| CastDefaultValueSnafu {
|
||||
reason: format!("Failed to drop default : {name:?}"),
|
||||
})?;
|
||||
} else {
|
||||
return InvalidRegionRequestSnafu {
|
||||
region_id: self.region_id,
|
||||
err: format!("column {name} not found",),
|
||||
}
|
||||
.fail();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Fields skipped in serialization.
|
||||
@@ -1100,7 +1137,10 @@ fn unset_column_fulltext_options(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use datatypes::prelude::ConcreteDataType;
|
||||
use datatypes::schema::{ColumnSchema, FulltextAnalyzer, FulltextBackend};
|
||||
use datatypes::schema::{
|
||||
ColumnDefaultConstraint, ColumnSchema, FulltextAnalyzer, FulltextBackend,
|
||||
};
|
||||
use datatypes::value::Value;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1423,6 +1463,19 @@ mod test {
|
||||
assert_eq!(names, actual);
|
||||
}
|
||||
|
||||
fn get_columns_default_constraint(
|
||||
metadata: &RegionMetadata,
|
||||
name: String,
|
||||
) -> Option<Option<&ColumnDefaultConstraint>> {
|
||||
metadata.column_metadatas.iter().find_map(|col| {
|
||||
if col.column_schema.name == name {
|
||||
Some(col.column_schema.default_constraint())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alter() {
|
||||
// a (tag), b (field), c (ts)
|
||||
@@ -1500,6 +1553,50 @@ mod test {
|
||||
let err = builder.build().unwrap_err();
|
||||
assert_eq!(StatusCode::InvalidArguments, err.status_code());
|
||||
|
||||
let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
|
||||
let mut column_metadata = new_column_metadata("g", false, 8);
|
||||
let default_constraint = Some(ColumnDefaultConstraint::Value(Value::from("g")));
|
||||
column_metadata.column_schema = column_metadata
|
||||
.column_schema
|
||||
.with_default_constraint(default_constraint.clone())
|
||||
.unwrap();
|
||||
builder
|
||||
.alter(AlterKind::AddColumns {
|
||||
columns: vec![AddColumn {
|
||||
column_metadata,
|
||||
location: None,
|
||||
}],
|
||||
})
|
||||
.unwrap();
|
||||
let metadata = builder.build().unwrap();
|
||||
assert_eq!(
|
||||
get_columns_default_constraint(&metadata, "g".to_string()).unwrap(),
|
||||
default_constraint.as_ref()
|
||||
);
|
||||
check_columns(&metadata, &["a", "b", "f", "c", "d", "g"]);
|
||||
|
||||
let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
|
||||
builder
|
||||
.alter(AlterKind::DropDefaults {
|
||||
names: vec!["g".to_string()],
|
||||
})
|
||||
.unwrap();
|
||||
let metadata = builder.build().unwrap();
|
||||
assert_eq!(
|
||||
get_columns_default_constraint(&metadata, "g".to_string()).unwrap(),
|
||||
None
|
||||
);
|
||||
check_columns(&metadata, &["a", "b", "f", "c", "d", "g"]);
|
||||
|
||||
let mut builder: RegionMetadataBuilder = RegionMetadataBuilder::from_existing(metadata);
|
||||
builder
|
||||
.alter(AlterKind::DropColumns {
|
||||
names: vec!["g".to_string()],
|
||||
})
|
||||
.unwrap();
|
||||
let metadata = builder.build().unwrap();
|
||||
check_columns(&metadata, &["a", "b", "f", "c", "d"]);
|
||||
|
||||
let mut builder = RegionMetadataBuilder::from_existing(metadata);
|
||||
builder
|
||||
.alter(AlterKind::ModifyColumnTypes {
|
||||
|
||||
@@ -530,6 +530,11 @@ pub enum AlterKind {
|
||||
SetIndex { options: ApiSetIndexOptions },
|
||||
/// Unset index options.
|
||||
UnsetIndex { options: ApiUnsetIndexOptions },
|
||||
/// Drop column default value.
|
||||
DropDefaults {
|
||||
/// Name of columns to drop.
|
||||
names: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
@@ -627,6 +632,11 @@ impl AlterKind {
|
||||
options.is_fulltext(),
|
||||
)?;
|
||||
}
|
||||
AlterKind::DropDefaults { names } => {
|
||||
names
|
||||
.iter()
|
||||
.try_for_each(|name| Self::validate_column_to_drop(name, metadata))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -656,6 +666,9 @@ impl AlterKind {
|
||||
AlterKind::UnsetIndex { options } => {
|
||||
metadata.column_by_name(options.column_name()).is_some()
|
||||
}
|
||||
AlterKind::DropDefaults { names } => names
|
||||
.iter()
|
||||
.any(|name| metadata.column_by_name(name).is_some()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,6 +807,9 @@ impl TryFrom<alter_request::Kind> for AlterKind {
|
||||
},
|
||||
},
|
||||
},
|
||||
alter_request::Kind::DropDefaults(x) => AlterKind::DropDefaults {
|
||||
names: x.drop_defaults.into_iter().map(|x| x.column_name).collect(),
|
||||
},
|
||||
};
|
||||
|
||||
Ok(alter_kind)
|
||||
|
||||
@@ -264,6 +264,7 @@ impl TableMeta {
|
||||
self.change_column_skipping_index_options(table_name, column_name, None)
|
||||
}
|
||||
},
|
||||
AlterKind::DropDefaults { names } => self.drop_defaults(table_name, names),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,8 +927,60 @@ impl TableMeta {
|
||||
column_names,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_defaults(&self, table_name: &str, column_names: &[String]) -> Result<TableMetaBuilder> {
|
||||
let table_schema = &self.schema;
|
||||
let mut meta_builder = self.new_meta_builder();
|
||||
let mut columns = Vec::with_capacity(table_schema.num_columns());
|
||||
for column_schema in table_schema.column_schemas() {
|
||||
if let Some(name) = column_names.iter().find(|s| **s == column_schema.name) {
|
||||
// Drop default constraint.
|
||||
ensure!(
|
||||
column_schema.default_constraint().is_some(),
|
||||
error::InvalidAlterRequestSnafu {
|
||||
table: table_name,
|
||||
err: format!("column {name} does not have a default value"),
|
||||
}
|
||||
);
|
||||
if !column_schema.is_nullable() {
|
||||
return error::InvalidAlterRequestSnafu {
|
||||
table: table_name,
|
||||
err: format!(
|
||||
"column {name} is not nullable and `default` cannot be dropped",
|
||||
),
|
||||
}
|
||||
.fail();
|
||||
}
|
||||
let new_column_schema = column_schema.clone();
|
||||
let new_column_schema = new_column_schema
|
||||
.with_default_constraint(None)
|
||||
.with_context(|_| error::SchemaBuildSnafu {
|
||||
msg: format!("Table {table_name} cannot drop default values"),
|
||||
})?;
|
||||
columns.push(new_column_schema);
|
||||
} else {
|
||||
columns.push(column_schema.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let mut builder = SchemaBuilder::try_from_columns(columns)
|
||||
.with_context(|_| error::SchemaBuildSnafu {
|
||||
msg: format!("Failed to convert column schemas into schema for table {table_name}"),
|
||||
})?
|
||||
// Also bump the schema version.
|
||||
.version(table_schema.version() + 1);
|
||||
for (k, v) in table_schema.metadata().iter() {
|
||||
builder = builder.add_metadata(k, v);
|
||||
}
|
||||
let new_schema = builder.build().with_context(|_| error::SchemaBuildSnafu {
|
||||
msg: format!("Table {table_name} cannot drop default values"),
|
||||
})?;
|
||||
|
||||
let _ = meta_builder.schema(Arc::new(new_schema));
|
||||
|
||||
Ok(meta_builder)
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Builder)]
|
||||
#[builder(pattern = "owned")]
|
||||
pub struct TableInfo {
|
||||
|
||||
@@ -257,6 +257,9 @@ pub enum AlterKind {
|
||||
UnsetIndex {
|
||||
options: UnsetIndexOptions,
|
||||
},
|
||||
DropDefaults {
|
||||
names: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
--- alter table to add new column with default timestamp values aware of session timezone test ---
|
||||
CREATE TABLE test1 (i INTEGER, j TIMESTAMP time index, PRIMARY KEY(i));
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN k INTEGER DEFAULT 100;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN l INTEGER DEFAULT 200;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN m TIMESTAMP DEFAULT '2024-01-30 00:00:00';
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN n INTEGER DEFAULT 300;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
SHOW CREATE TABLE test1;
|
||||
|
||||
+-------+-------------------------------------------------------------+
|
||||
| Table | Create Table |
|
||||
+-------+-------------------------------------------------------------+
|
||||
| test1 | CREATE TABLE IF NOT EXISTS "test1" ( |
|
||||
| | "i" INT NULL, |
|
||||
| | "j" TIMESTAMP(3) NOT NULL, |
|
||||
| | "k" INT NULL DEFAULT 100, |
|
||||
| | "l" INT NULL DEFAULT 200, |
|
||||
| | "m" TIMESTAMP(3) NULL DEFAULT '2024-01-30 00:00:00+0000', |
|
||||
| | "n" INT NULL DEFAULT 300, |
|
||||
| | TIME INDEX ("j"), |
|
||||
| | PRIMARY KEY ("i") |
|
||||
| | ) |
|
||||
| | |
|
||||
| | ENGINE=mito |
|
||||
| | |
|
||||
+-------+-------------------------------------------------------------+
|
||||
|
||||
INSERT INTO test1 VALUES (1, '2024-01-30 12:00:00', DEFAULT, DEFAULT, DEFAULT, DEFAULT);
|
||||
|
||||
Affected Rows: 1
|
||||
|
||||
SELECT * FROM test1;
|
||||
|
||||
+---+---------------------+-----+-----+---------------------+-----+
|
||||
| i | j | k | l | m | n |
|
||||
+---+---------------------+-----+-----+---------------------+-----+
|
||||
| 1 | 2024-01-30T12:00:00 | 100 | 200 | 2024-01-30T00:00:00 | 300 |
|
||||
+---+---------------------+-----+-----+---------------------+-----+
|
||||
|
||||
ALTER TABLE test1 ALTER k DROP DEFAULT;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
ALTER TABLE test1 ALTER l DROP DEFAULT, ALTER m DROP DEFAULT, ALTER n DROP DEFAULT;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
SHOW CREATE TABLE test1;
|
||||
|
||||
+-------+--------------------------------------+
|
||||
| Table | Create Table |
|
||||
+-------+--------------------------------------+
|
||||
| test1 | CREATE TABLE IF NOT EXISTS "test1" ( |
|
||||
| | "i" INT NULL, |
|
||||
| | "j" TIMESTAMP(3) NOT NULL, |
|
||||
| | "k" INT NULL, |
|
||||
| | "l" INT NULL, |
|
||||
| | "m" TIMESTAMP(3) NULL, |
|
||||
| | "n" INT NULL, |
|
||||
| | TIME INDEX ("j"), |
|
||||
| | PRIMARY KEY ("i") |
|
||||
| | ) |
|
||||
| | |
|
||||
| | ENGINE=mito |
|
||||
| | |
|
||||
+-------+--------------------------------------+
|
||||
|
||||
INSERT INTO test1 VALUES (1, '2024-01-30 12:00:00', DEFAULT, DEFAULT, DEFAULT, DEFAULT);
|
||||
|
||||
Affected Rows: 1
|
||||
|
||||
SELECT * FROM test1;
|
||||
|
||||
+---+---------------------+---+---+---+---+
|
||||
| i | j | k | l | m | n |
|
||||
+---+---------------------+---+---+---+---+
|
||||
| 1 | 2024-01-30T12:00:00 | | | | |
|
||||
+---+---------------------+---+---+---+---+
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN o INTEGER NOT NULL DEFAULT 400;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
SELECT * FROM test1;
|
||||
|
||||
+---+---------------------+---+---+---+---+-----+
|
||||
| i | j | k | l | m | n | o |
|
||||
+---+---------------------+---+---+---+---+-----+
|
||||
| 1 | 2024-01-30T12:00:00 | | | | | 400 |
|
||||
+---+---------------------+---+---+---+---+-----+
|
||||
|
||||
ALTER TABLE test1 ALTER o DROP DEFAULT;
|
||||
|
||||
Error: 1004(InvalidArguments), Invalid alter table(test1) request: column o is not nullable and `default` cannot be dropped
|
||||
|
||||
DROP TABLE test1;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
--- alter table to add new column with default timestamp values aware of session timezone test ---
|
||||
|
||||
CREATE TABLE test1 (i INTEGER, j TIMESTAMP time index, PRIMARY KEY(i));
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN k INTEGER DEFAULT 100;
|
||||
ALTER TABLE test1 ADD COLUMN l INTEGER DEFAULT 200;
|
||||
ALTER TABLE test1 ADD COLUMN m TIMESTAMP DEFAULT '2024-01-30 00:00:00';
|
||||
ALTER TABLE test1 ADD COLUMN n INTEGER DEFAULT 300;
|
||||
|
||||
SHOW CREATE TABLE test1;
|
||||
|
||||
INSERT INTO test1 VALUES (1, '2024-01-30 12:00:00', DEFAULT, DEFAULT, DEFAULT, DEFAULT);
|
||||
|
||||
SELECT * FROM test1;
|
||||
|
||||
ALTER TABLE test1 ALTER k DROP DEFAULT;
|
||||
ALTER TABLE test1 ALTER l DROP DEFAULT, ALTER m DROP DEFAULT, ALTER n DROP DEFAULT;
|
||||
|
||||
SHOW CREATE TABLE test1;
|
||||
|
||||
INSERT INTO test1 VALUES (1, '2024-01-30 12:00:00', DEFAULT, DEFAULT, DEFAULT, DEFAULT);
|
||||
|
||||
SELECT * FROM test1;
|
||||
|
||||
ALTER TABLE test1 ADD COLUMN o INTEGER NOT NULL DEFAULT 400;
|
||||
SELECT * FROM test1;
|
||||
|
||||
ALTER TABLE test1 ALTER o DROP DEFAULT;
|
||||
|
||||
DROP TABLE test1;
|
||||
Reference in New Issue
Block a user