mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-26 15:39:12 +00:00
Add Expr::tuple + parsing (#414)
This commit is contained in:
parent
8a3544abae
commit
ff558eeb61
3 changed files with 68 additions and 13 deletions
|
@ -284,6 +284,8 @@ pub enum Expr {
|
||||||
Cube(Vec<Vec<Expr>>),
|
Cube(Vec<Vec<Expr>>),
|
||||||
/// The `ROLLUP` expr.
|
/// The `ROLLUP` expr.
|
||||||
Rollup(Vec<Vec<Expr>>),
|
Rollup(Vec<Vec<Expr>>),
|
||||||
|
/// ROW / TUPLE a single value, such as `SELECT (1, 2)`
|
||||||
|
Tuple(Vec<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Expr {
|
impl fmt::Display for Expr {
|
||||||
|
@ -445,6 +447,9 @@ impl fmt::Display for Expr {
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
|
Expr::Tuple(exprs) => {
|
||||||
|
write!(f, "({})", display_comma_separated(exprs))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,7 +494,12 @@ impl<'a> Parser<'a> {
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
Expr::Subquery(Box::new(self.parse_query()?))
|
Expr::Subquery(Box::new(self.parse_query()?))
|
||||||
} else {
|
} else {
|
||||||
Expr::Nested(Box::new(self.parse_expr()?))
|
let exprs = self.parse_comma_separated(Parser::parse_expr)?;
|
||||||
|
match exprs.len() {
|
||||||
|
0 => unreachable!(), // parse_comma_separated ensures 1 or more
|
||||||
|
1 => Expr::Nested(Box::new(exprs.into_iter().next().unwrap())),
|
||||||
|
_ => Expr::Tuple(exprs),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
|
@ -2739,19 +2744,8 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not Sure if Top should be cheked here as well. Trino doesn't support TOP.
|
|
||||||
let is_l_paren = if distinct {
|
|
||||||
self.consume_token(&Token::LParen)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let projection = self.parse_comma_separated(Parser::parse_select_item)?;
|
let projection = self.parse_comma_separated(Parser::parse_select_item)?;
|
||||||
|
|
||||||
if is_l_paren && !self.consume_token(&Token::RParen) {
|
|
||||||
return self.expected(")", self.peek_token());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that for keywords to be properly handled here, they need to be
|
// Note that for keywords to be properly handled here, they need to be
|
||||||
// added to `RESERVED_FOR_COLUMN_ALIAS` / `RESERVED_FOR_TABLE_ALIAS`,
|
// added to `RESERVED_FOR_COLUMN_ALIAS` / `RESERVED_FOR_TABLE_ALIAS`,
|
||||||
// otherwise they may be parsed as an alias as part of the `projection`
|
// otherwise they may be parsed as an alias as part of the `projection`
|
||||||
|
|
|
@ -332,7 +332,6 @@ fn parse_select_distinct_two_fields() {
|
||||||
let sql = "SELECT DISTINCT name, id FROM customer";
|
let sql = "SELECT DISTINCT name, id FROM customer";
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert!(select.distinct);
|
assert!(select.distinct);
|
||||||
one_statement_parses_to("SELECT DISTINCT (name, id) FROM customer", sql);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
|
&SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
|
||||||
&select.projection[0]
|
&select.projection[0]
|
||||||
|
@ -343,6 +342,19 @@ fn parse_select_distinct_two_fields() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_select_distinct_tuple() {
|
||||||
|
let sql = "SELECT DISTINCT (name, id) FROM customer";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(
|
||||||
|
&vec![SelectItem::UnnamedExpr(Expr::Tuple(vec![
|
||||||
|
Expr::Identifier(Ident::new("name")),
|
||||||
|
Expr::Identifier(Ident::new("id")),
|
||||||
|
]))],
|
||||||
|
&select.projection
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_select_distinct_missing_paren() {
|
fn parse_select_distinct_missing_paren() {
|
||||||
let result = parse_sql_statements("SELECT DISTINCT (name, id FROM customer");
|
let result = parse_sql_statements("SELECT DISTINCT (name, id FROM customer");
|
||||||
|
@ -1033,6 +1045,44 @@ fn parse_between_with_expr() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_tuples() {
|
||||||
|
let sql = "SELECT (1, 2), (1), ('foo', 3, baz)";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
SelectItem::UnnamedExpr(Expr::Tuple(vec![
|
||||||
|
Expr::Value(number("1")),
|
||||||
|
Expr::Value(number("2"))
|
||||||
|
])),
|
||||||
|
SelectItem::UnnamedExpr(Expr::Nested(Box::new(Expr::Value(number("1"))))),
|
||||||
|
SelectItem::UnnamedExpr(Expr::Tuple(vec![
|
||||||
|
Expr::Value(Value::SingleQuotedString("foo".into())),
|
||||||
|
Expr::Value(number("3")),
|
||||||
|
Expr::Identifier(Ident::new("baz"))
|
||||||
|
]))
|
||||||
|
],
|
||||||
|
select.projection
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_tuple_invalid() {
|
||||||
|
let sql = "select (1";
|
||||||
|
let res = parse_sql_statements(sql);
|
||||||
|
assert_eq!(
|
||||||
|
ParserError::ParserError("Expected ), found: EOF".to_string()),
|
||||||
|
res.unwrap_err()
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "select (), 2";
|
||||||
|
let res = parse_sql_statements(sql);
|
||||||
|
assert_eq!(
|
||||||
|
ParserError::ParserError("Expected an expression:, found: )".to_string()),
|
||||||
|
res.unwrap_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_select_order_by() {
|
fn parse_select_order_by() {
|
||||||
fn chk(sql: &str) {
|
fn chk(sql: &str) {
|
||||||
|
@ -1121,6 +1171,12 @@ fn parse_select_group_by() {
|
||||||
],
|
],
|
||||||
select.group_by
|
select.group_by
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Tuples can also be in the set
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT id, fname, lname FROM customer GROUP BY (lname, fname)",
|
||||||
|
"SELECT id, fname, lname FROM customer GROUP BY (lname, fname)",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue