mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 23:14:07 +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)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[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 {
|
impl fmt::Display for Values {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "VALUES ")?;
|
write!(f, "VALUES ")?;
|
||||||
|
let prefix = if self.explicit_row { "ROW" } else { "" };
|
||||||
let mut delim = "";
|
let mut delim = "";
|
||||||
for row in &self.0 {
|
for row in &self.rows {
|
||||||
write!(f, "{}", delim)?;
|
write!(f, "{}", delim)?;
|
||||||
delim = ", ";
|
delim = ", ";
|
||||||
write!(f, "({})", display_comma_separated(row))?;
|
write!(f, "{prefix}({})", display_comma_separated(row))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5642,13 +5642,19 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_values(&mut self) -> Result<Values, ParserError> {
|
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)?;
|
parser.expect_token(&Token::LParen)?;
|
||||||
let exprs = parser.parse_comma_separated(Parser::parse_expr)?;
|
let exprs = parser.parse_comma_separated(Parser::parse_expr)?;
|
||||||
parser.expect_token(&Token::RParen)?;
|
parser.expect_token(&Token::RParen)?;
|
||||||
Ok(exprs)
|
Ok(exprs)
|
||||||
})?;
|
})?;
|
||||||
Ok(Values(values))
|
Ok(Values { explicit_row, rows })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_start_transaction(&mut self) -> Result<Statement, ParserError> {
|
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()));
|
assert_eq!(column, &Ident::new(expected_columns[index].clone()));
|
||||||
}
|
}
|
||||||
match &*source.body {
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,6 +462,7 @@ fn parse_top_level() {
|
||||||
verified_stmt("(SELECT 1)");
|
verified_stmt("(SELECT 1)");
|
||||||
verified_stmt("((SELECT 1))");
|
verified_stmt("((SELECT 1))");
|
||||||
verified_stmt("VALUES (1)");
|
verified_stmt("VALUES (1)");
|
||||||
|
verified_stmt("VALUES ROW(1, true, 'a'), ROW(2, false, 'b')");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -4268,6 +4271,7 @@ fn parse_values() {
|
||||||
verified_stmt("SELECT * FROM (VALUES (1), (2), (3))");
|
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), (2), (3)), (VALUES (1, 2, 3))");
|
||||||
verified_stmt("SELECT * FROM (VALUES (1)) UNION VALUES (1)");
|
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]
|
#[test]
|
||||||
|
@ -5608,11 +5612,14 @@ fn parse_merge() {
|
||||||
MergeClause::NotMatched {
|
MergeClause::NotMatched {
|
||||||
predicate: None,
|
predicate: None,
|
||||||
columns: vec![Ident::new("A"), Ident::new("B"), Ident::new("C")],
|
columns: vec![Ident::new("A"), Ident::new("B"), Ident::new("C")],
|
||||||
values: Values(vec![vec![
|
values: Values {
|
||||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("A")]),
|
explicit_row: false,
|
||||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("B")]),
|
rows: vec![vec![
|
||||||
Expr::CompoundIdentifier(vec![Ident::new("stg"), Ident::new("C")]),
|
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 {
|
MergeClause::MatchedUpdate {
|
||||||
predicate: Some(Expr::BinaryOp {
|
predicate: Some(Expr::BinaryOp {
|
||||||
|
|
|
@ -660,20 +660,25 @@ fn parse_simple_insert() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Box::new(Query {
|
Box::new(Query {
|
||||||
with: None,
|
with: None,
|
||||||
body: Box::new(SetExpr::Values(Values(vec![
|
body: Box::new(SetExpr::Values(Values {
|
||||||
vec![
|
explicit_row: false,
|
||||||
Expr::Value(Value::SingleQuotedString("Test Some Inserts".to_string())),
|
rows: vec![
|
||||||
Expr::Value(Value::Number("1".to_string(), false))
|
vec![
|
||||||
],
|
Expr::Value(Value::SingleQuotedString(
|
||||||
vec![
|
"Test Some Inserts".to_string()
|
||||||
Expr::Value(Value::SingleQuotedString("Test Entry 2".to_string())),
|
)),
|
||||||
Expr::Value(Value::Number("2".to_string(), false))
|
Expr::Value(Value::Number("1".to_string(), false))
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Expr::Value(Value::SingleQuotedString("Test Entry 3".to_string())),
|
Expr::Value(Value::SingleQuotedString("Test Entry 2".to_string())),
|
||||||
Expr::Value(Value::Number("3".to_string(), false))
|
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![],
|
order_by: vec![],
|
||||||
limit: None,
|
limit: None,
|
||||||
offset: None,
|
offset: None,
|
||||||
|
@ -717,16 +722,21 @@ fn parse_insert_with_on_duplicate_update() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Box::new(Query {
|
Box::new(Query {
|
||||||
with: None,
|
with: None,
|
||||||
body: Box::new(SetExpr::Values(Values(vec![vec![
|
body: Box::new(SetExpr::Values(Values {
|
||||||
Expr::Value(Value::SingleQuotedString("accounting_manager".to_string())),
|
explicit_row: false,
|
||||||
Expr::Value(Value::SingleQuotedString(
|
rows: vec![vec![
|
||||||
"Some description about the group".to_string()
|
Expr::Value(Value::SingleQuotedString(
|
||||||
)),
|
"accounting_manager".to_string()
|
||||||
Expr::Value(Value::Boolean(true)),
|
)),
|
||||||
Expr::Value(Value::Boolean(true)),
|
Expr::Value(Value::SingleQuotedString(
|
||||||
Expr::Value(Value::Boolean(true)),
|
"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)),
|
||||||
|
Expr::Value(Value::Boolean(true)),
|
||||||
|
]]
|
||||||
|
})),
|
||||||
order_by: vec![],
|
order_by: vec![],
|
||||||
limit: None,
|
limit: None,
|
||||||
offset: None,
|
offset: None,
|
||||||
|
@ -1209,3 +1219,9 @@ fn mysql_and_generic() -> TestedDialects {
|
||||||
dialects: vec![Box::new(MySqlDialect {}), Box::new(GenericDialect {})],
|
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()),
|
Expr::Identifier("a3".into()),
|
||||||
]];
|
]];
|
||||||
match &*source.body {
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue