Skip to content

Commit 004a8dc

Browse files
bitemyappChris Aalamb
authored
Support multiple PARTITION statements in ALTER TABLE ADD statement (#1011)
Co-authored-by: Chris A <chrisa@indeed.com> Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
1 parent 9832adb commit 004a8dc

File tree

5 files changed

+51
-10
lines changed

5 files changed

+51
-10
lines changed

src/ast/ddl.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub enum AlterTableOperation {
6969
/// Add Partitions
7070
AddPartitions {
7171
if_not_exists: bool,
72-
new_partitions: Vec<Expr>,
72+
new_partitions: Vec<Partition>,
7373
},
7474
DropPartitions {
7575
partitions: Vec<Expr>,
@@ -119,8 +119,8 @@ impl fmt::Display for AlterTableOperation {
119119
new_partitions,
120120
} => write!(
121121
f,
122-
"ADD{ine} PARTITION ({})",
123-
display_comma_separated(new_partitions),
122+
"ADD{ine} {}",
123+
display_separated(new_partitions, " "),
124124
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
125125
),
126126
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
@@ -771,3 +771,21 @@ impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
771771
Ok(())
772772
}
773773
}
774+
775+
/// PARTITION statement used in ALTER TABLE et al. such as in Hive SQL
776+
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
777+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
778+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
779+
pub struct Partition {
780+
pub partitions: Vec<Expr>,
781+
}
782+
783+
impl fmt::Display for Partition {
784+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
785+
write!(
786+
f,
787+
"PARTITION ({})",
788+
display_comma_separated(&self.partitions)
789+
)
790+
}
791+
}

src/ast/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ pub use self::data_type::{
3131
pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue};
3232
pub use self::ddl::{
3333
AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ColumnDef, ColumnOption,
34-
ColumnOptionDef, GeneratedAs, IndexType, KeyOrIndexDisplay, ProcedureParam, ReferentialAction,
35-
TableConstraint, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
34+
ColumnOptionDef, GeneratedAs, IndexType, KeyOrIndexDisplay, Partition, ProcedureParam,
35+
ReferentialAction, TableConstraint, UserDefinedTypeCompositeAttributeDef,
36+
UserDefinedTypeRepresentation,
3637
};
3738
pub use self::operator::{BinaryOperator, UnaryOperator};
3839
pub use self::query::{

src/dialect/generic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ use crate::dialect::Dialect;
1818
pub struct GenericDialect;
1919

2020
impl Dialect for GenericDialect {
21+
fn is_delimited_identifier_start(&self, ch: char) -> bool {
22+
ch == '"' || ch == '`'
23+
}
24+
2125
fn is_identifier_start(&self, ch: char) -> bool {
2226
ch.is_alphabetic() || ch == '_' || ch == '#' || ch == '@'
2327
}

src/parser/mod.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4195,20 +4195,32 @@ impl<'a> Parser<'a> {
41954195
Ok(SqlOption { name, value })
41964196
}
41974197

4198+
pub fn parse_partition(&mut self) -> Result<Partition, ParserError> {
4199+
self.expect_token(&Token::LParen)?;
4200+
let partitions = self.parse_comma_separated(Parser::parse_expr)?;
4201+
self.expect_token(&Token::RParen)?;
4202+
Ok(Partition { partitions })
4203+
}
4204+
41984205
pub fn parse_alter_table_operation(&mut self) -> Result<AlterTableOperation, ParserError> {
41994206
let operation = if self.parse_keyword(Keyword::ADD) {
42004207
if let Some(constraint) = self.parse_optional_table_constraint()? {
42014208
AlterTableOperation::AddConstraint(constraint)
42024209
} else {
42034210
let if_not_exists =
42044211
self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
4205-
if self.parse_keyword(Keyword::PARTITION) {
4206-
self.expect_token(&Token::LParen)?;
4207-
let partitions = self.parse_comma_separated(Parser::parse_expr)?;
4208-
self.expect_token(&Token::RParen)?;
4212+
let mut new_partitions = vec![];
4213+
loop {
4214+
if self.parse_keyword(Keyword::PARTITION) {
4215+
new_partitions.push(self.parse_partition()?);
4216+
} else {
4217+
break;
4218+
}
4219+
}
4220+
if !new_partitions.is_empty() {
42094221
AlterTableOperation::AddPartitions {
42104222
if_not_exists,
4211-
new_partitions: partitions,
4223+
new_partitions,
42124224
}
42134225
} else {
42144226
let column_keyword = self.parse_keyword(Keyword::COLUMN);

tests/sqlparser_hive.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ fn test_add_partition() {
128128
hive().verified_stmt(add);
129129
}
130130

131+
#[test]
132+
fn test_add_multiple_partitions() {
133+
let add = "ALTER TABLE db.table ADD IF NOT EXISTS PARTITION (`a` = 'asdf', `b` = 2) PARTITION (`a` = 'asdh', `b` = 3)";
134+
hive().verified_stmt(add);
135+
}
136+
131137
#[test]
132138
fn test_drop_partition() {
133139
let drop = "ALTER TABLE db.table DROP PARTITION (a = 1)";

0 commit comments

Comments
 (0)