mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-09 21:42:05 +00:00
Add support of ATTACH/DETACH PARTITION for ClickHouse (#1362)
This commit is contained in:
parent
da484c57c4
commit
dfb8b81630
4 changed files with 114 additions and 1 deletions
|
@ -72,6 +72,21 @@ pub enum AlterTableOperation {
|
||||||
if_exists: bool,
|
if_exists: bool,
|
||||||
cascade: bool,
|
cascade: bool,
|
||||||
},
|
},
|
||||||
|
/// `ATTACH PART|PARTITION <partition_expr>`
|
||||||
|
/// Note: this is a ClickHouse-specific operation, please refer to
|
||||||
|
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/pakrtition#attach-partitionpart)
|
||||||
|
AttachPartition {
|
||||||
|
// PART is not a short form of PARTITION, it's a separate keyword
|
||||||
|
// which represents a physical file on disk and partition is a logical entity.
|
||||||
|
partition: Partition,
|
||||||
|
},
|
||||||
|
/// `DETACH PART|PARTITION <partition_expr>`
|
||||||
|
/// Note: this is a ClickHouse-specific operation, please refer to
|
||||||
|
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
|
||||||
|
DetachPartition {
|
||||||
|
// See `AttachPartition` for more details
|
||||||
|
partition: Partition,
|
||||||
|
},
|
||||||
/// `DROP PRIMARY KEY`
|
/// `DROP PRIMARY KEY`
|
||||||
///
|
///
|
||||||
/// Note: this is a MySQL-specific operation.
|
/// Note: this is a MySQL-specific operation.
|
||||||
|
@ -272,6 +287,12 @@ impl fmt::Display for AlterTableOperation {
|
||||||
column_name,
|
column_name,
|
||||||
if *cascade { " CASCADE" } else { "" }
|
if *cascade { " CASCADE" } else { "" }
|
||||||
),
|
),
|
||||||
|
AlterTableOperation::AttachPartition { partition } => {
|
||||||
|
write!(f, "ATTACH {partition}")
|
||||||
|
}
|
||||||
|
AlterTableOperation::DetachPartition { partition } => {
|
||||||
|
write!(f, "DETACH {partition}")
|
||||||
|
}
|
||||||
AlterTableOperation::EnableAlwaysRule { name } => {
|
AlterTableOperation::EnableAlwaysRule { name } => {
|
||||||
write!(f, "ENABLE ALWAYS RULE {name}")
|
write!(f, "ENABLE ALWAYS RULE {name}")
|
||||||
}
|
}
|
||||||
|
@ -1305,6 +1326,9 @@ impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
|
||||||
pub enum Partition {
|
pub enum Partition {
|
||||||
Identifier(Ident),
|
Identifier(Ident),
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
|
/// ClickHouse supports PART expr which represents physical partition in disk.
|
||||||
|
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
|
||||||
|
Part(Expr),
|
||||||
Partitions(Vec<Expr>),
|
Partitions(Vec<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1313,6 +1337,7 @@ impl fmt::Display for Partition {
|
||||||
match self {
|
match self {
|
||||||
Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
|
Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
|
||||||
Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
|
Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
|
||||||
|
Partition::Part(expr) => write!(f, "PART {expr}"),
|
||||||
Partition::Partitions(partitions) => {
|
Partition::Partitions(partitions) => {
|
||||||
write!(f, "PARTITION ({})", display_comma_separated(partitions))
|
write!(f, "PARTITION ({})", display_comma_separated(partitions))
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,6 +539,7 @@ define_keywords!(
|
||||||
PARALLEL,
|
PARALLEL,
|
||||||
PARAMETER,
|
PARAMETER,
|
||||||
PARQUET,
|
PARQUET,
|
||||||
|
PART,
|
||||||
PARTITION,
|
PARTITION,
|
||||||
PARTITIONED,
|
PARTITIONED,
|
||||||
PARTITIONS,
|
PARTITIONS,
|
||||||
|
|
|
@ -6432,7 +6432,7 @@ impl<'a> Parser<'a> {
|
||||||
} else if dialect_of!(self is PostgreSqlDialect | GenericDialect)
|
} else if dialect_of!(self is PostgreSqlDialect | GenericDialect)
|
||||||
&& self.parse_keywords(&[Keyword::OWNER, Keyword::TO])
|
&& self.parse_keywords(&[Keyword::OWNER, Keyword::TO])
|
||||||
{
|
{
|
||||||
let new_owner = match self.parse_one_of_keywords( &[Keyword::CURRENT_USER, Keyword::CURRENT_ROLE, Keyword::SESSION_USER]) {
|
let new_owner = match self.parse_one_of_keywords(&[Keyword::CURRENT_USER, Keyword::CURRENT_ROLE, Keyword::SESSION_USER]) {
|
||||||
Some(Keyword::CURRENT_USER) => Owner::CurrentUser,
|
Some(Keyword::CURRENT_USER) => Owner::CurrentUser,
|
||||||
Some(Keyword::CURRENT_ROLE) => Owner::CurrentRole,
|
Some(Keyword::CURRENT_ROLE) => Owner::CurrentRole,
|
||||||
Some(Keyword::SESSION_USER) => Owner::SessionUser,
|
Some(Keyword::SESSION_USER) => Owner::SessionUser,
|
||||||
|
@ -6448,6 +6448,18 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
AlterTableOperation::OwnerTo { new_owner }
|
AlterTableOperation::OwnerTo { new_owner }
|
||||||
|
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
|
||||||
|
&& self.parse_keyword(Keyword::ATTACH)
|
||||||
|
{
|
||||||
|
AlterTableOperation::AttachPartition {
|
||||||
|
partition: self.parse_part_or_partition()?,
|
||||||
|
}
|
||||||
|
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
|
||||||
|
&& self.parse_keyword(Keyword::DETACH)
|
||||||
|
{
|
||||||
|
AlterTableOperation::DetachPartition {
|
||||||
|
partition: self.parse_part_or_partition()?,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let options: Vec<SqlOption> =
|
let options: Vec<SqlOption> =
|
||||||
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;
|
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;
|
||||||
|
@ -6465,6 +6477,16 @@ impl<'a> Parser<'a> {
|
||||||
Ok(operation)
|
Ok(operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_part_or_partition(&mut self) -> Result<Partition, ParserError> {
|
||||||
|
let keyword = self.expect_one_of_keywords(&[Keyword::PART, Keyword::PARTITION])?;
|
||||||
|
match keyword {
|
||||||
|
Keyword::PART => Ok(Partition::Part(self.parse_expr()?)),
|
||||||
|
Keyword::PARTITION => Ok(Partition::Expr(self.parse_expr()?)),
|
||||||
|
// unreachable because expect_one_of_keywords used above
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_alter(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_alter(&mut self) -> Result<Statement, ParserError> {
|
||||||
let object_type = self.expect_one_of_keywords(&[
|
let object_type = self.expect_one_of_keywords(&[
|
||||||
Keyword::VIEW,
|
Keyword::VIEW,
|
||||||
|
|
|
@ -222,6 +222,71 @@ fn parse_create_table() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_attach_and_detach_partition() {
|
||||||
|
for operation in &["ATTACH", "DETACH"] {
|
||||||
|
match clickhouse_and_generic()
|
||||||
|
.verified_stmt(format!("ALTER TABLE t0 {operation} PARTITION part").as_str())
|
||||||
|
{
|
||||||
|
Statement::AlterTable {
|
||||||
|
name, operations, ..
|
||||||
|
} => {
|
||||||
|
pretty_assertions::assert_eq!("t0", name.to_string());
|
||||||
|
pretty_assertions::assert_eq!(
|
||||||
|
operations[0],
|
||||||
|
if operation == &"ATTACH" {
|
||||||
|
AlterTableOperation::AttachPartition {
|
||||||
|
partition: Partition::Expr(Identifier(Ident::new("part"))),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AlterTableOperation::DetachPartition {
|
||||||
|
partition: Partition::Expr(Identifier(Ident::new("part"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
match clickhouse_and_generic()
|
||||||
|
.verified_stmt(format!("ALTER TABLE t1 {operation} PART part").as_str())
|
||||||
|
{
|
||||||
|
Statement::AlterTable {
|
||||||
|
name, operations, ..
|
||||||
|
} => {
|
||||||
|
pretty_assertions::assert_eq!("t1", name.to_string());
|
||||||
|
pretty_assertions::assert_eq!(
|
||||||
|
operations[0],
|
||||||
|
if operation == &"ATTACH" {
|
||||||
|
AlterTableOperation::AttachPartition {
|
||||||
|
partition: Partition::Part(Identifier(Ident::new("part"))),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AlterTableOperation::DetachPartition {
|
||||||
|
partition: Partition::Part(Identifier(Ident::new("part"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// negative cases
|
||||||
|
assert_eq!(
|
||||||
|
clickhouse_and_generic()
|
||||||
|
.parse_sql_statements(format!("ALTER TABLE t0 {operation} 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} PART").as_str())
|
||||||
|
.unwrap_err(),
|
||||||
|
ParserError("Expected: an expression:, found: EOF".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_optimize_table() {
|
fn parse_optimize_table() {
|
||||||
clickhouse_and_generic().verified_stmt("OPTIMIZE TABLE t0");
|
clickhouse_and_generic().verified_stmt("OPTIMIZE TABLE t0");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue