Merge pull request #100 from benesch/nested-joins

Support nested joins
This commit is contained in:
Nikhil Benesch 2019-06-07 22:37:53 -04:00 committed by GitHub
commit 5f9f17de8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 8 deletions

View file

@ -215,6 +215,10 @@ pub enum TableFactor {
subquery: Box<SQLQuery>,
alias: Option<TableAlias>,
},
NestedJoin {
base: Box<TableFactor>,
joins: Vec<Join>,
},
}
impl ToString for TableFactor {
@ -253,6 +257,13 @@ impl ToString for TableFactor {
}
s
}
TableFactor::NestedJoin { base, joins } => {
let mut s = base.to_string();
for join in joins {
s += &join.to_string();
}
format!("({})", s)
}
}
}
}

View file

@ -1538,6 +1538,11 @@ impl Parser {
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
let lateral = self.parse_keyword("LATERAL");
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()?);
self.expect_token(&Token::RParen)?;
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
@ -1546,6 +1551,14 @@ impl Parser {
subquery,
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 {
self.expected("subquery after LATERAL", self.peek_token())
} else {

View file

@ -1447,6 +1447,49 @@ fn parse_complex_join() {
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]
fn parse_join_syntax_variants() {
one_statement_parses_to(
@ -2049,6 +2092,13 @@ fn lateral_derived() {
),
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]