mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-22 15:55:00 +00:00
commit
5f9f17de8a
3 changed files with 82 additions and 8 deletions
|
@ -215,6 +215,10 @@ pub enum TableFactor {
|
||||||
subquery: Box<SQLQuery>,
|
subquery: Box<SQLQuery>,
|
||||||
alias: Option<TableAlias>,
|
alias: Option<TableAlias>,
|
||||||
},
|
},
|
||||||
|
NestedJoin {
|
||||||
|
base: Box<TableFactor>,
|
||||||
|
joins: Vec<Join>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for TableFactor {
|
impl ToString for TableFactor {
|
||||||
|
@ -253,6 +257,13 @@ impl ToString for TableFactor {
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
TableFactor::NestedJoin { base, joins } => {
|
||||||
|
let mut s = base.to_string();
|
||||||
|
for join in joins {
|
||||||
|
s += &join.to_string();
|
||||||
|
}
|
||||||
|
format!("({})", s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1538,6 +1538,11 @@ impl Parser {
|
||||||
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
|
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
|
||||||
let lateral = self.parse_keyword("LATERAL");
|
let lateral = self.parse_keyword("LATERAL");
|
||||||
if self.consume_token(&Token::LParen) {
|
if self.consume_token(&Token::LParen) {
|
||||||
|
if self.parse_keyword("SELECT")
|
||||||
|
|| self.parse_keyword("WITH")
|
||||||
|
|| self.parse_keyword("VALUES")
|
||||||
|
{
|
||||||
|
self.prev_token();
|
||||||
let subquery = Box::new(self.parse_query()?);
|
let subquery = Box::new(self.parse_query()?);
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
|
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
|
||||||
|
@ -1546,6 +1551,14 @@ impl Parser {
|
||||||
subquery,
|
subquery,
|
||||||
alias,
|
alias,
|
||||||
})
|
})
|
||||||
|
} else if lateral {
|
||||||
|
parser_err!("Expected subquery after LATERAL, found nested join".to_string())
|
||||||
|
} else {
|
||||||
|
let base = Box::new(self.parse_table_factor()?);
|
||||||
|
let joins = self.parse_joins()?;
|
||||||
|
self.expect_token(&Token::RParen)?;
|
||||||
|
Ok(TableFactor::NestedJoin { base, joins })
|
||||||
|
}
|
||||||
} else if lateral {
|
} else if lateral {
|
||||||
self.expected("subquery after LATERAL", self.peek_token())
|
self.expected("subquery after LATERAL", self.peek_token())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1447,6 +1447,49 @@ fn parse_complex_join() {
|
||||||
verified_only_select(sql);
|
verified_only_select(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_join_nesting() {
|
||||||
|
fn table(name: impl Into<String>) -> TableFactor {
|
||||||
|
TableFactor::Table {
|
||||||
|
name: SQLObjectName(vec![name.into()]),
|
||||||
|
alias: None,
|
||||||
|
args: vec![],
|
||||||
|
with_hints: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn join(relation: TableFactor) -> Join {
|
||||||
|
Join {
|
||||||
|
relation,
|
||||||
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! nest {
|
||||||
|
($base:expr, $($join:expr),*) => {
|
||||||
|
TableFactor::NestedJoin {
|
||||||
|
base: Box::new($base),
|
||||||
|
joins: vec![$(join($join)),*]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let sql = "SELECT * FROM a NATURAL JOIN (b NATURAL JOIN (c NATURAL JOIN d NATURAL JOIN e)) \
|
||||||
|
NATURAL JOIN (f NATURAL JOIN (g NATURAL JOIN h))";
|
||||||
|
assert_eq!(
|
||||||
|
verified_only_select(sql).joins,
|
||||||
|
vec![
|
||||||
|
join(nest!(table("b"), nest!(table("c"), table("d"), table("e")))),
|
||||||
|
join(nest!(table("f"), nest!(table("g"), table("h"))))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "SELECT * FROM (a NATURAL JOIN b) NATURAL JOIN c";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(select.relation.unwrap(), nest!(table("a"), table("b")),);
|
||||||
|
assert_eq!(select.joins, vec![join(table("c"))],)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_join_syntax_variants() {
|
fn parse_join_syntax_variants() {
|
||||||
one_statement_parses_to(
|
one_statement_parses_to(
|
||||||
|
@ -2049,6 +2092,13 @@ fn lateral_derived() {
|
||||||
),
|
),
|
||||||
res.unwrap_err()
|
res.unwrap_err()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let sql = "SELECT * FROM a LEFT JOIN LATERAL (b CROSS JOIN c)";
|
||||||
|
let res = parse_sql_statements(sql);
|
||||||
|
assert_eq!(
|
||||||
|
ParserError::ParserError("Expected subquery after LATERAL, found nested join".to_string()),
|
||||||
|
res.unwrap_err()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue