Add support of FREEZE|UNFREEZE PARTITION syntax for ClickHouse (#1380)

This commit is contained in:
hulk 2024-08-14 23:29:27 +08:00 committed by GitHub
parent c2f46ae07b
commit 6a11a67fcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 146 additions and 0 deletions

View file

@ -87,6 +87,20 @@ pub enum AlterTableOperation {
// See `AttachPartition` for more details
partition: Partition,
},
/// `FREEZE PARTITION <partition_expr>`
/// Note: this is a ClickHouse-specific operation, please refer to
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
FreezePartition {
partition: Partition,
with_name: Option<Ident>,
},
/// `UNFREEZE PARTITION <partition_expr>`
/// Note: this is a ClickHouse-specific operation, please refer to
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
UnfreezePartition {
partition: Partition,
with_name: Option<Ident>,
},
/// `DROP PRIMARY KEY`
///
/// Note: this is a MySQL-specific operation.
@ -379,6 +393,26 @@ impl fmt::Display for AlterTableOperation {
display_comma_separated(table_properties)
)
}
AlterTableOperation::FreezePartition {
partition,
with_name,
} => {
write!(f, "FREEZE {partition}")?;
if let Some(name) = with_name {
write!(f, " WITH NAME {name}")?;
}
Ok(())
}
AlterTableOperation::UnfreezePartition {
partition,
with_name,
} => {
write!(f, "UNFREEZE {partition}")?;
if let Some(name) = with_name {
write!(f, " WITH NAME {name}")?;
}
Ok(())
}
}
}
}

View file

@ -763,6 +763,7 @@ define_keywords!(
UNBOUNDED,
UNCACHE,
UNCOMMITTED,
UNFREEZE,
UNION,
UNIQUE,
UNKNOWN,

View file

@ -6684,6 +6684,34 @@ impl<'a> Parser<'a> {
AlterTableOperation::DetachPartition {
partition: self.parse_part_or_partition()?,
}
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
&& self.parse_keyword(Keyword::FREEZE)
{
let partition = self.parse_part_or_partition()?;
let with_name = if self.parse_keyword(Keyword::WITH) {
self.expect_keyword(Keyword::NAME)?;
Some(self.parse_identifier(false)?)
} else {
None
};
AlterTableOperation::FreezePartition {
partition,
with_name,
}
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
&& self.parse_keyword(Keyword::UNFREEZE)
{
let partition = self.parse_part_or_partition()?;
let with_name = if self.parse_keyword(Keyword::WITH) {
self.expect_keyword(Keyword::NAME)?;
Some(self.parse_identifier(false)?)
} else {
None
};
AlterTableOperation::UnfreezePartition {
partition,
with_name,
}
} else {
let options: Vec<SqlOption> =
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;

View file

@ -1216,6 +1216,89 @@ fn parse_create_table_on_commit_and_as_query() {
}
}
#[test]
fn parse_freeze_and_unfreeze_partition() {
// test cases without `WITH NAME`
for operation_name in &["FREEZE", "UNFREEZE"] {
let sql = format!("ALTER TABLE t {operation_name} PARTITION '2024-08-14'");
let expected_partition = Partition::Expr(Expr::Value(Value::SingleQuotedString(
"2024-08-14".to_string(),
)));
match clickhouse_and_generic().verified_stmt(&sql) {
Statement::AlterTable { operations, .. } => {
assert_eq!(operations.len(), 1);
let expected_operation = if operation_name == &"FREEZE" {
AlterTableOperation::FreezePartition {
partition: expected_partition,
with_name: None,
}
} else {
AlterTableOperation::UnfreezePartition {
partition: expected_partition,
with_name: None,
}
};
assert_eq!(operations[0], expected_operation);
}
_ => unreachable!(),
}
}
// test case with `WITH NAME`
for operation_name in &["FREEZE", "UNFREEZE"] {
let sql =
format!("ALTER TABLE t {operation_name} PARTITION '2024-08-14' WITH NAME 'hello'");
match clickhouse_and_generic().verified_stmt(&sql) {
Statement::AlterTable { operations, .. } => {
assert_eq!(operations.len(), 1);
let expected_partition = Partition::Expr(Expr::Value(Value::SingleQuotedString(
"2024-08-14".to_string(),
)));
let expected_operation = if operation_name == &"FREEZE" {
AlterTableOperation::FreezePartition {
partition: expected_partition,
with_name: Some(Ident::with_quote('\'', "hello")),
}
} else {
AlterTableOperation::UnfreezePartition {
partition: expected_partition,
with_name: Some(Ident::with_quote('\'', "hello")),
}
};
assert_eq!(operations[0], expected_operation);
}
_ => unreachable!(),
}
}
// negative cases
for operation_name in &["FREEZE", "UNFREEZE"] {
assert_eq!(
clickhouse_and_generic()
.parse_sql_statements(format!("ALTER TABLE t0 {operation_name} PARTITION").as_str())
.unwrap_err(),
ParserError("Expected: an expression:, found: EOF".to_string())
);
assert_eq!(
clickhouse_and_generic()
.parse_sql_statements(
format!("ALTER TABLE t0 {operation_name} PARTITION p0 WITH").as_str()
)
.unwrap_err(),
ParserError("Expected: NAME, found: EOF".to_string())
);
assert_eq!(
clickhouse_and_generic()
.parse_sql_statements(
format!("ALTER TABLE t0 {operation_name} PARTITION p0 WITH NAME").as_str()
)
.unwrap_err(),
ParserError("Expected: identifier, found: EOF".to_string())
);
}
}
#[test]
fn parse_select_table_function_settings() {
fn check_settings(sql: &str, expected: &TableFunctionArgs) {