Skip to content

Commit 5f9f17d

Browse files
authored
Merge pull request #100 from benesch/nested-joins
Support nested joins
2 parents fc5e662 + 8fbf82d commit 5f9f17d

File tree

3 files changed

+82
-8
lines changed

3 files changed

+82
-8
lines changed

src/sqlast/query.rs

+11
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ pub enum TableFactor {
215215
subquery: Box<SQLQuery>,
216216
alias: Option<TableAlias>,
217217
},
218+
NestedJoin {
219+
base: Box<TableFactor>,
220+
joins: Vec<Join>,
221+
},
218222
}
219223

220224
impl ToString for TableFactor {
@@ -253,6 +257,13 @@ impl ToString for TableFactor {
253257
}
254258
s
255259
}
260+
TableFactor::NestedJoin { base, joins } => {
261+
let mut s = base.to_string();
262+
for join in joins {
263+
s += &join.to_string();
264+
}
265+
format!("({})", s)
266+
}
256267
}
257268
}
258269
}

src/sqlparser.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -1538,14 +1538,27 @@ impl Parser {
15381538
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
15391539
let lateral = self.parse_keyword("LATERAL");
15401540
if self.consume_token(&Token::LParen) {
1541-
let subquery = Box::new(self.parse_query()?);
1542-
self.expect_token(&Token::RParen)?;
1543-
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1544-
Ok(TableFactor::Derived {
1545-
lateral,
1546-
subquery,
1547-
alias,
1548-
})
1541+
if self.parse_keyword("SELECT")
1542+
|| self.parse_keyword("WITH")
1543+
|| self.parse_keyword("VALUES")
1544+
{
1545+
self.prev_token();
1546+
let subquery = Box::new(self.parse_query()?);
1547+
self.expect_token(&Token::RParen)?;
1548+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1549+
Ok(TableFactor::Derived {
1550+
lateral,
1551+
subquery,
1552+
alias,
1553+
})
1554+
} else if lateral {
1555+
parser_err!("Expected subquery after LATERAL, found nested join".to_string())
1556+
} else {
1557+
let base = Box::new(self.parse_table_factor()?);
1558+
let joins = self.parse_joins()?;
1559+
self.expect_token(&Token::RParen)?;
1560+
Ok(TableFactor::NestedJoin { base, joins })
1561+
}
15491562
} else if lateral {
15501563
self.expected("subquery after LATERAL", self.peek_token())
15511564
} else {

tests/sqlparser_common.rs

+50
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,49 @@ fn parse_complex_join() {
14471447
verified_only_select(sql);
14481448
}
14491449

1450+
#[test]
1451+
fn parse_join_nesting() {
1452+
fn table(name: impl Into<String>) -> TableFactor {
1453+
TableFactor::Table {
1454+
name: SQLObjectName(vec![name.into()]),
1455+
alias: None,
1456+
args: vec![],
1457+
with_hints: vec![],
1458+
}
1459+
}
1460+
1461+
fn join(relation: TableFactor) -> Join {
1462+
Join {
1463+
relation,
1464+
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
1465+
}
1466+
}
1467+
1468+
macro_rules! nest {
1469+
($base:expr, $($join:expr),*) => {
1470+
TableFactor::NestedJoin {
1471+
base: Box::new($base),
1472+
joins: vec![$(join($join)),*]
1473+
}
1474+
};
1475+
}
1476+
1477+
let sql = "SELECT * FROM a NATURAL JOIN (b NATURAL JOIN (c NATURAL JOIN d NATURAL JOIN e)) \
1478+
NATURAL JOIN (f NATURAL JOIN (g NATURAL JOIN h))";
1479+
assert_eq!(
1480+
verified_only_select(sql).joins,
1481+
vec![
1482+
join(nest!(table("b"), nest!(table("c"), table("d"), table("e")))),
1483+
join(nest!(table("f"), nest!(table("g"), table("h"))))
1484+
],
1485+
);
1486+
1487+
let sql = "SELECT * FROM (a NATURAL JOIN b) NATURAL JOIN c";
1488+
let select = verified_only_select(sql);
1489+
assert_eq!(select.relation.unwrap(), nest!(table("a"), table("b")),);
1490+
assert_eq!(select.joins, vec![join(table("c"))],)
1491+
}
1492+
14501493
#[test]
14511494
fn parse_join_syntax_variants() {
14521495
one_statement_parses_to(
@@ -2049,6 +2092,13 @@ fn lateral_derived() {
20492092
),
20502093
res.unwrap_err()
20512094
);
2095+
2096+
let sql = "SELECT * FROM a LEFT JOIN LATERAL (b CROSS JOIN c)";
2097+
let res = parse_sql_statements(sql);
2098+
assert_eq!(
2099+
ParserError::ParserError("Expected subquery after LATERAL, found nested join".to_string()),
2100+
res.unwrap_err()
2101+
);
20522102
}
20532103

20542104
#[test]

0 commit comments

Comments
 (0)