Skip to content

Commit 6a11a67

Browse files
authored
Add support of FREEZE|UNFREEZE PARTITION syntax for ClickHouse (#1380)
1 parent c2f46ae commit 6a11a67

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

src/ast/ddl.rs

+34
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ pub enum AlterTableOperation {
8787
// See `AttachPartition` for more details
8888
partition: Partition,
8989
},
90+
/// `FREEZE PARTITION <partition_expr>`
91+
/// Note: this is a ClickHouse-specific operation, please refer to
92+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
93+
FreezePartition {
94+
partition: Partition,
95+
with_name: Option<Ident>,
96+
},
97+
/// `UNFREEZE PARTITION <partition_expr>`
98+
/// Note: this is a ClickHouse-specific operation, please refer to
99+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
100+
UnfreezePartition {
101+
partition: Partition,
102+
with_name: Option<Ident>,
103+
},
90104
/// `DROP PRIMARY KEY`
91105
///
92106
/// Note: this is a MySQL-specific operation.
@@ -379,6 +393,26 @@ impl fmt::Display for AlterTableOperation {
379393
display_comma_separated(table_properties)
380394
)
381395
}
396+
AlterTableOperation::FreezePartition {
397+
partition,
398+
with_name,
399+
} => {
400+
write!(f, "FREEZE {partition}")?;
401+
if let Some(name) = with_name {
402+
write!(f, " WITH NAME {name}")?;
403+
}
404+
Ok(())
405+
}
406+
AlterTableOperation::UnfreezePartition {
407+
partition,
408+
with_name,
409+
} => {
410+
write!(f, "UNFREEZE {partition}")?;
411+
if let Some(name) = with_name {
412+
write!(f, " WITH NAME {name}")?;
413+
}
414+
Ok(())
415+
}
382416
}
383417
}
384418
}

src/keywords.rs

+1
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,7 @@ define_keywords!(
763763
UNBOUNDED,
764764
UNCACHE,
765765
UNCOMMITTED,
766+
UNFREEZE,
766767
UNION,
767768
UNIQUE,
768769
UNKNOWN,

src/parser/mod.rs

+28
Original file line numberDiff line numberDiff line change
@@ -6684,6 +6684,34 @@ impl<'a> Parser<'a> {
66846684
AlterTableOperation::DetachPartition {
66856685
partition: self.parse_part_or_partition()?,
66866686
}
6687+
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
6688+
&& self.parse_keyword(Keyword::FREEZE)
6689+
{
6690+
let partition = self.parse_part_or_partition()?;
6691+
let with_name = if self.parse_keyword(Keyword::WITH) {
6692+
self.expect_keyword(Keyword::NAME)?;
6693+
Some(self.parse_identifier(false)?)
6694+
} else {
6695+
None
6696+
};
6697+
AlterTableOperation::FreezePartition {
6698+
partition,
6699+
with_name,
6700+
}
6701+
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
6702+
&& self.parse_keyword(Keyword::UNFREEZE)
6703+
{
6704+
let partition = self.parse_part_or_partition()?;
6705+
let with_name = if self.parse_keyword(Keyword::WITH) {
6706+
self.expect_keyword(Keyword::NAME)?;
6707+
Some(self.parse_identifier(false)?)
6708+
} else {
6709+
None
6710+
};
6711+
AlterTableOperation::UnfreezePartition {
6712+
partition,
6713+
with_name,
6714+
}
66876715
} else {
66886716
let options: Vec<SqlOption> =
66896717
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;

tests/sqlparser_clickhouse.rs

+83
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,89 @@ fn parse_create_table_on_commit_and_as_query() {
12161216
}
12171217
}
12181218

1219+
#[test]
1220+
fn parse_freeze_and_unfreeze_partition() {
1221+
// test cases without `WITH NAME`
1222+
for operation_name in &["FREEZE", "UNFREEZE"] {
1223+
let sql = format!("ALTER TABLE t {operation_name} PARTITION '2024-08-14'");
1224+
1225+
let expected_partition = Partition::Expr(Expr::Value(Value::SingleQuotedString(
1226+
"2024-08-14".to_string(),
1227+
)));
1228+
match clickhouse_and_generic().verified_stmt(&sql) {
1229+
Statement::AlterTable { operations, .. } => {
1230+
assert_eq!(operations.len(), 1);
1231+
let expected_operation = if operation_name == &"FREEZE" {
1232+
AlterTableOperation::FreezePartition {
1233+
partition: expected_partition,
1234+
with_name: None,
1235+
}
1236+
} else {
1237+
AlterTableOperation::UnfreezePartition {
1238+
partition: expected_partition,
1239+
with_name: None,
1240+
}
1241+
};
1242+
assert_eq!(operations[0], expected_operation);
1243+
}
1244+
_ => unreachable!(),
1245+
}
1246+
}
1247+
1248+
// test case with `WITH NAME`
1249+
for operation_name in &["FREEZE", "UNFREEZE"] {
1250+
let sql =
1251+
format!("ALTER TABLE t {operation_name} PARTITION '2024-08-14' WITH NAME 'hello'");
1252+
match clickhouse_and_generic().verified_stmt(&sql) {
1253+
Statement::AlterTable { operations, .. } => {
1254+
assert_eq!(operations.len(), 1);
1255+
let expected_partition = Partition::Expr(Expr::Value(Value::SingleQuotedString(
1256+
"2024-08-14".to_string(),
1257+
)));
1258+
let expected_operation = if operation_name == &"FREEZE" {
1259+
AlterTableOperation::FreezePartition {
1260+
partition: expected_partition,
1261+
with_name: Some(Ident::with_quote('\'', "hello")),
1262+
}
1263+
} else {
1264+
AlterTableOperation::UnfreezePartition {
1265+
partition: expected_partition,
1266+
with_name: Some(Ident::with_quote('\'', "hello")),
1267+
}
1268+
};
1269+
assert_eq!(operations[0], expected_operation);
1270+
}
1271+
_ => unreachable!(),
1272+
}
1273+
}
1274+
1275+
// negative cases
1276+
for operation_name in &["FREEZE", "UNFREEZE"] {
1277+
assert_eq!(
1278+
clickhouse_and_generic()
1279+
.parse_sql_statements(format!("ALTER TABLE t0 {operation_name} PARTITION").as_str())
1280+
.unwrap_err(),
1281+
ParserError("Expected: an expression:, found: EOF".to_string())
1282+
);
1283+
assert_eq!(
1284+
clickhouse_and_generic()
1285+
.parse_sql_statements(
1286+
format!("ALTER TABLE t0 {operation_name} PARTITION p0 WITH").as_str()
1287+
)
1288+
.unwrap_err(),
1289+
ParserError("Expected: NAME, found: EOF".to_string())
1290+
);
1291+
assert_eq!(
1292+
clickhouse_and_generic()
1293+
.parse_sql_statements(
1294+
format!("ALTER TABLE t0 {operation_name} PARTITION p0 WITH NAME").as_str()
1295+
)
1296+
.unwrap_err(),
1297+
ParserError("Expected: identifier, found: EOF".to_string())
1298+
);
1299+
}
1300+
}
1301+
12191302
#[test]
12201303
fn parse_select_table_function_settings() {
12211304
fn check_settings(sql: &str, expected: &TableFunctionArgs) {

0 commit comments

Comments
 (0)