Skip to content

Commit 265d617

Browse files
committed
Support nested joins
Fix #83.
1 parent 85ba953 commit 265d617

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
@@ -213,6 +213,10 @@ pub enum TableFactor {
213213
subquery: Box<SQLQuery>,
214214
alias: Option<SQLIdent>,
215215
},
216+
NestedJoin {
217+
base: Box<TableFactor>,
218+
joins: Vec<Join>,
219+
},
216220
}
217221

218222
impl ToString for TableFactor {
@@ -251,6 +255,13 @@ impl ToString for TableFactor {
251255
}
252256
s
253257
}
258+
TableFactor::NestedJoin { base, joins } => {
259+
let mut s = base.to_string();
260+
for join in joins {
261+
s += &join.to_string();
262+
}
263+
format!("({})", s)
264+
}
254265
}
255266
}
256267
}

src/sqlparser.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -1443,14 +1443,27 @@ impl Parser {
14431443
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
14441444
let lateral = self.parse_keyword("LATERAL");
14451445
if self.consume_token(&Token::LParen) {
1446-
let subquery = Box::new(self.parse_query()?);
1447-
self.expect_token(&Token::RParen)?;
1448-
let alias = self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1449-
Ok(TableFactor::Derived {
1450-
lateral,
1451-
subquery,
1452-
alias,
1453-
})
1446+
if self.parse_keyword("SELECT")
1447+
|| self.parse_keyword("WITH")
1448+
|| self.parse_keyword("VALUES")
1449+
{
1450+
self.prev_token();
1451+
let subquery = Box::new(self.parse_query()?);
1452+
self.expect_token(&Token::RParen)?;
1453+
let alias = self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1454+
Ok(TableFactor::Derived {
1455+
lateral,
1456+
subquery,
1457+
alias,
1458+
})
1459+
} else if lateral {
1460+
parser_err!("Expected subquery after LATERAL, found nested join".to_string())
1461+
} else {
1462+
let base = Box::new(self.parse_table_factor()?);
1463+
let joins = self.parse_joins()?;
1464+
self.expect_token(&Token::RParen)?;
1465+
Ok(TableFactor::NestedJoin { base, joins })
1466+
}
14541467
} else if lateral {
14551468
self.expected("subquery after LATERAL", self.peek_token())
14561469
} else {

tests/sqlparser_common.rs

+50
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,49 @@ fn parse_complex_join() {
12611261
verified_only_select(sql);
12621262
}
12631263

1264+
#[test]
1265+
fn parse_join_nesting() {
1266+
fn table(name: impl Into<String>) -> TableFactor {
1267+
TableFactor::Table {
1268+
name: SQLObjectName(vec![name.into()]),
1269+
alias: None,
1270+
args: vec![],
1271+
with_hints: vec![],
1272+
}
1273+
}
1274+
1275+
fn join(relation: TableFactor) -> Join {
1276+
Join {
1277+
relation,
1278+
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
1279+
}
1280+
}
1281+
1282+
macro_rules! nest {
1283+
($base:expr, $($join:expr),*) => {
1284+
TableFactor::NestedJoin {
1285+
base: Box::new($base),
1286+
joins: vec![$(join($join)),*]
1287+
}
1288+
};
1289+
}
1290+
1291+
let sql = "SELECT * FROM a NATURAL JOIN (b NATURAL JOIN (c NATURAL JOIN d NATURAL JOIN e)) \
1292+
NATURAL JOIN (f NATURAL JOIN (g NATURAL JOIN h))";
1293+
assert_eq!(
1294+
verified_only_select(sql).joins,
1295+
vec![
1296+
join(nest!(table("b"), nest!(table("c"), table("d"), table("e")))),
1297+
join(nest!(table("f"), nest!(table("g"), table("h"))))
1298+
],
1299+
);
1300+
1301+
let sql = "SELECT * FROM (a NATURAL JOIN b) NATURAL JOIN c";
1302+
let select = verified_only_select(sql);
1303+
assert_eq!(select.relation.unwrap(), nest!(table("a"), table("b")),);
1304+
assert_eq!(select.joins, vec![join(table("c"))],)
1305+
}
1306+
12641307
#[test]
12651308
fn parse_join_syntax_variants() {
12661309
one_statement_parses_to(
@@ -1758,6 +1801,13 @@ fn lateral_derived() {
17581801
),
17591802
res.unwrap_err()
17601803
);
1804+
1805+
let sql = "SELECT * FROM a LEFT JOIN LATERAL (b CROSS JOIN c)";
1806+
let res = parse_sql_statements(sql);
1807+
assert_eq!(
1808+
ParserError::ParserError("Expected subquery after LATERAL, found nested join".to_string()),
1809+
res.unwrap_err()
1810+
);
17611811
}
17621812

17631813
#[test]

0 commit comments

Comments
 (0)