Skip to content

Commit f6e4be4

Browse files
chunshao90alamb
andauthored
Support mysql partition to table selection (#959)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
1 parent a16791d commit f6e4be4

14 files changed

+108
-7
lines changed

src/ast/query.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ pub enum TableFactor {
670670
/// Optional version qualifier to facilitate table time-travel, as
671671
/// supported by BigQuery and MSSQL.
672672
version: Option<TableVersion>,
673+
/// [Partition selection](https://dev.mysql.com/doc/refman/8.0/en/partitioning-selection.html), supported by MySQL.
674+
partitions: Vec<Ident>,
673675
},
674676
Derived {
675677
lateral: bool,
@@ -730,8 +732,12 @@ impl fmt::Display for TableFactor {
730732
args,
731733
with_hints,
732734
version,
735+
partitions,
733736
} => {
734737
write!(f, "{name}")?;
738+
if !partitions.is_empty() {
739+
write!(f, "PARTITION ({})", display_comma_separated(partitions))?;
740+
}
735741
if let Some(args) = args {
736742
write!(f, "({})", display_comma_separated(args))?;
737743
}

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,8 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
716716
Keyword::QUALIFY,
717717
Keyword::WINDOW,
718718
Keyword::END,
719+
// for MYSQL PARTITION SELECTION
720+
Keyword::PARTITION,
719721
];
720722

721723
/// Can't be used as a column alias, so that `SELECT <expr> alias`

src/parser/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6277,6 +6277,14 @@ impl<'a> Parser<'a> {
62776277
} else {
62786278
let name = self.parse_object_name()?;
62796279

6280+
let partitions: Vec<Ident> = if dialect_of!(self is MySqlDialect | GenericDialect)
6281+
&& self.parse_keyword(Keyword::PARTITION)
6282+
{
6283+
self.parse_partitions()?
6284+
} else {
6285+
vec![]
6286+
};
6287+
62806288
// Parse potential version qualifier
62816289
let version = self.parse_table_version()?;
62826290

@@ -6311,6 +6319,7 @@ impl<'a> Parser<'a> {
63116319
args,
63126320
with_hints,
63136321
version,
6322+
partitions,
63146323
})
63156324
}
63166325
}
@@ -7483,6 +7492,13 @@ impl<'a> Parser<'a> {
74837492
representation: UserDefinedTypeRepresentation::Composite { attributes },
74847493
})
74857494
}
7495+
7496+
fn parse_partitions(&mut self) -> Result<Vec<Ident>, ParserError> {
7497+
self.expect_token(&Token::LParen)?;
7498+
let partitions = self.parse_comma_separated(Parser::parse_identifier)?;
7499+
self.expect_token(&Token::RParen)?;
7500+
Ok(partitions)
7501+
}
74867502
}
74877503

74887504
impl Word {
@@ -8100,4 +8116,29 @@ mod tests {
81008116
"sql parser error: Unexpected token following period in identifier: *",
81018117
);
81028118
}
8119+
8120+
#[test]
8121+
fn test_mysql_partition_selection() {
8122+
let sql = "SELECT * FROM employees PARTITION (p0, p2)";
8123+
let expected = vec!["p0", "p2"];
8124+
8125+
let ast: Vec<Statement> = Parser::parse_sql(&MySqlDialect {}, sql).unwrap();
8126+
assert_eq!(ast.len(), 1);
8127+
if let Statement::Query(v) = &ast[0] {
8128+
if let SetExpr::Select(select) = &*v.body {
8129+
assert_eq!(select.from.len(), 1);
8130+
let from: &TableWithJoins = &select.from[0];
8131+
let table_factor = &from.relation;
8132+
if let TableFactor::Table { partitions, .. } = table_factor {
8133+
let actual: Vec<&str> = partitions
8134+
.iter()
8135+
.map(|ident| ident.value.as_str())
8136+
.collect();
8137+
assert_eq!(expected, actual);
8138+
}
8139+
}
8140+
} else {
8141+
panic!("fail to parse mysql partition selection");
8142+
}
8143+
}
81038144
}

src/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub fn table(name: impl Into<String>) -> TableFactor {
248248
args: None,
249249
with_hints: vec![],
250250
version: None,
251+
partitions: vec![],
251252
}
252253
}
253254

tests/sqlparser_bigquery.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ fn parse_table_identifiers() {
9696
args: None,
9797
with_hints: vec![],
9898
version: None,
99+
partitions: vec![],
99100
},
100101
joins: vec![]
101102
},]
@@ -160,6 +161,7 @@ fn parse_table_time_travel() {
160161
version: Some(TableVersion::ForSystemTimeAsOf(Expr::Value(
161162
Value::SingleQuotedString(version)
162163
))),
164+
partitions: vec![],
163165
},
164166
joins: vec![]
165167
},]

tests/sqlparser_clickhouse.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,16 @@ fn parse_map_access_expr() {
6363
args: None,
6464
with_hints: vec![],
6565
version: None,
66+
partitions: vec![],
6667
},
67-
joins: vec![]
68+
joins: vec![],
6869
}],
6970
lateral_views: vec![],
7071
selection: Some(BinaryOp {
7172
left: Box::new(BinaryOp {
7273
left: Box::new(Identifier(Ident::new("id"))),
7374
op: BinaryOperator::Eq,
74-
right: Box::new(Expr::Value(Value::SingleQuotedString("test".to_string())))
75+
right: Box::new(Expr::Value(Value::SingleQuotedString("test".to_string()))),
7576
}),
7677
op: BinaryOperator::And,
7778
right: Box::new(BinaryOp {
@@ -91,19 +92,19 @@ fn parse_map_access_expr() {
9192
distinct: false,
9293
special: false,
9394
order_by: vec![],
94-
})]
95+
})],
9596
}),
9697
op: BinaryOperator::NotEq,
97-
right: Box::new(Expr::Value(Value::SingleQuotedString("foo".to_string())))
98-
})
98+
right: Box::new(Expr::Value(Value::SingleQuotedString("foo".to_string()))),
99+
}),
99100
}),
100101
group_by: GroupByExpr::Expressions(vec![]),
101102
cluster_by: vec![],
102103
distribute_by: vec![],
103104
sort_by: vec![],
104105
having: None,
105106
named_window: vec![],
106-
qualify: None
107+
qualify: None,
107108
},
108109
select
109110
);
@@ -117,7 +118,7 @@ fn parse_array_expr() {
117118
&Expr::Array(Array {
118119
elem: vec![
119120
Expr::Value(Value::SingleQuotedString("1".to_string())),
120-
Expr::Value(Value::SingleQuotedString("2".to_string()))
121+
Expr::Value(Value::SingleQuotedString("2".to_string())),
121122
],
122123
named: false,
123124
}),
@@ -171,6 +172,7 @@ fn parse_delimited_identifiers() {
171172
args,
172173
with_hints,
173174
version,
175+
partitions: _,
174176
} => {
175177
assert_eq!(vec![Ident::with_quote('"', "a table")], name.0);
176178
assert_eq!(Ident::with_quote('"', "alias"), alias.unwrap().name);

0 commit comments

Comments
 (0)