mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
Support MySQL ROWS
syntax for VALUES
(#737)
* Adapt VALUES to MySQL dialect * Update src/ast/query.rs Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org> * remove *requirement* for ROW Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
faf75b7161
commit
8e1c90c0d8
5 changed files with 72 additions and 35 deletions
|
@ -797,16 +797,22 @@ impl fmt::Display for Top {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Values(pub Vec<Vec<Expr>>);
|
||||
pub struct Values {
|
||||
/// Was there an explict ROWs keyword (MySQL)?
|
||||
/// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
|
||||
pub explicit_row: bool,
|
||||
pub rows: Vec<Vec<Expr>>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Values {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "VALUES ")?;
|
||||
let prefix = if self.explicit_row { "ROW" } else { "" };
|
||||
let mut delim = "";
|
||||
for row in &self.0 {
|
||||
for row in &self.rows {
|
||||
write!(f, "{}", delim)?;
|
||||
delim = ", ";
|
||||
write!(f, "({})", display_comma_separated(row))?;
|
||||
write!(f, "{prefix}({})", display_comma_separated(row))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -5642,13 +5642,19 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
pub fn parse_values(&mut self) -> Result<Values, ParserError> {
|
||||
let values = self.parse_comma_separated(|parser| {
|
||||
let mut explicit_row = false;
|
||||
|
||||
let rows = self.parse_comma_separated(|parser| {
|
||||
if parser.parse_keyword(Keyword::ROW) {
|
||||
explicit_row = true;
|
||||
}
|
||||
|
||||
parser.expect_token(&Token::LParen)?;
|
||||
let exprs = parser.parse_comma_separated(Parser::parse_expr)?;
|
||||
parser.expect_token(&Token::RParen)?;
|
||||
Ok(exprs)
|
||||
})?;
|
||||
Ok(Values(values))
|
||||
Ok(Values { explicit_row, rows })
|
||||
}
|
||||
|
||||
pub fn parse_start_transaction(&mut self) -> Result<Statement, ParserError> {
|
||||
|
|
|
@ -88,7 +88,9 @@ fn parse_insert_values() {
|
|||
assert_eq!(column, &Ident::new(expected_columns[index].clone()));
|
||||
}
|
||||
match &*source.body {
|
||||
SetExpr::Values(Values(values)) => assert_eq!(values.as_slice(), expected_rows),
|
||||
SetExpr::Values(Values { rows, .. }) => {
|
||||
assert_eq!(rows.as_slice(), expected_rows)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -460,6 +462,7 @@ fn parse_top_level() {
|
|||
verified_stmt("(SELECT 1)");
|
||||
verified_stmt("((SELECT 1))");
|
||||
verified_stmt("VALUES (1)");
|
||||
verified_stmt("VALUES ROW(1, true, 'a'), ROW(2, false, 'b')");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -4268,6 +4271,7 @@ fn parse_values() {
|
|||
verified_stmt("SELECT * FROM (VALUES (1), (2), (3))");
|
||||
verified_stmt("SELECT * FROM (VALUES (1), (2), (3)), (VALUES (1, 2, 3))");
|
||||
verified_stmt("SELECT * FROM (VALUES (1)) UNION VALUES (1)");
|
||||
verified_stmt("SELECT * FROM (VALUES ROW(1, true, 'a'), ROW(2, false, 'b')) AS t (a, b, c)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -5608,11 +5612,14 @@ fn parse_merge() {
|
|||
MergeClause::NotMatched {
|
||||
predicate: None,
|
||||
columns: vec![Ident::new("A"), Ident::new("B"), Ident::new("C")],
|
||||
values: Values(vec![vec![
|
||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("A")]),
|
||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("B")]),
|
||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("C")]),
|
||||
]]),
|
||||
values: Values {
|
||||
explicit_row: false,
|
||||
rows: vec![vec![
|
||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("A")]),
|
||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("B")]),
|
||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("C")]),
|
||||
]]
|
||||
},
|
||||
},
|
||||
MergeClause::MatchedUpdate {
|
||||
predicate: Some(Expr::BinaryOp {
|
||||
|
|
|
@ -660,20 +660,25 @@ fn parse_simple_insert() {
|
|||
assert_eq!(
|
||||
Box::new(Query {
|
||||
with: None,
|
||||
body: Box::new(SetExpr::Values(Values(vec![
|
||||
vec![
|
||||
Expr::Value(Value::SingleQuotedString("Test Some Inserts".to_string())),
|
||||
Expr::Value(Value::Number("1".to_string(), false))
|
||||
],
|
||||
vec![
|
||||
Expr::Value(Value::SingleQuotedString("Test Entry 2".to_string())),
|
||||
Expr::Value(Value::Number("2".to_string(), false))
|
||||
],
|
||||
vec![
|
||||
Expr::Value(Value::SingleQuotedString("Test Entry 3".to_string())),
|
||||
Expr::Value(Value::Number("3".to_string(), false))
|
||||
body: Box::new(SetExpr::Values(Values {
|
||||
explicit_row: false,
|
||||
rows: vec![
|
||||
vec![
|
||||
Expr::Value(Value::SingleQuotedString(
|
||||
"Test Some Inserts".to_string()
|
||||
)),
|
||||
Expr::Value(Value::Number("1".to_string(), false))
|
||||
],
|
||||
vec![
|
||||
Expr::Value(Value::SingleQuotedString("Test Entry 2".to_string())),
|
||||
Expr::Value(Value::Number("2".to_string(), false))
|
||||
],
|
||||
vec![
|
||||
Expr::Value(Value::SingleQuotedString("Test Entry 3".to_string())),
|
||||
Expr::Value(Value::Number("3".to_string(), false))
|
||||
]
|
||||
]
|
||||
]))),
|
||||
})),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
offset: None,
|
||||
|
@ -717,16 +722,21 @@ fn parse_insert_with_on_duplicate_update() {
|
|||
assert_eq!(
|
||||
Box::new(Query {
|
||||
with: None,
|
||||
body: Box::new(SetExpr::Values(Values(vec![vec![
|
||||
Expr::Value(Value::SingleQuotedString("accounting_manager".to_string())),
|
||||
Expr::Value(Value::SingleQuotedString(
|
||||
"Some description about the group".to_string()
|
||||
)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
]]))),
|
||||
body: Box::new(SetExpr::Values(Values {
|
||||
explicit_row: false,
|
||||
rows: vec![vec![
|
||||
Expr::Value(Value::SingleQuotedString(
|
||||
"accounting_manager".to_string()
|
||||
)),
|
||||
Expr::Value(Value::SingleQuotedString(
|
||||
"Some description about the group".to_string()
|
||||
)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
Expr::Value(Value::Boolean(true)),
|
||||
]]
|
||||
})),
|
||||
order_by: vec![],
|
||||
limit: None,
|
||||
offset: None,
|
||||
|
@ -1209,3 +1219,9 @@ fn mysql_and_generic() -> TestedDialects {
|
|||
dialects: vec![Box::new(MySqlDialect {}), Box::new(GenericDialect {})],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_values() {
|
||||
mysql().verified_stmt("VALUES ROW(1, true, 'a')");
|
||||
mysql().verified_stmt("SELECT a, c FROM (VALUES ROW(1, true, 'a'), ROW(2, false, 'b'), ROW(3, false, 'c')) AS t (a, b, c)");
|
||||
}
|
||||
|
|
|
@ -1067,7 +1067,9 @@ fn parse_prepare() {
|
|||
Expr::Identifier("a3".into()),
|
||||
]];
|
||||
match &*source.body {
|
||||
SetExpr::Values(Values(values)) => assert_eq!(values.as_slice(), &expected_values),
|
||||
SetExpr::Values(Values { rows, .. }) => {
|
||||
assert_eq!(rows.as_slice(), &expected_values)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue