Skip to content

Commit 4ee461b

Browse files
committed
Require that nested joins always have one join
The SQL specification prohibits constructions like SELECT * FROM a NATURAL JOIN (b) where b sits alone inside parentheses. Parentheses in a FROM entry always introduce either a derived table or a join.
1 parent 8bee742 commit 4ee461b

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

src/sqlast/query.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ pub enum TableFactor {
238238
subquery: Box<SQLQuery>,
239239
alias: Option<TableAlias>,
240240
},
241+
/// Represents a parenthesized join expression, such as
242+
/// `(foo <JOIN> bar [ <JOIN> baz ... ])`.
243+
/// The inner `TableWithJoins` can have no joins only if its
244+
/// `relation` is itself a `TableFactor::NestedJoin`.
241245
NestedJoin(Box<TableWithJoins>),
242246
}
243247

src/sqlparser.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,16 @@ impl Parser {
17191719
// we won't, and we'll return that error instead.
17201720
self.index = index;
17211721
let table_and_joins = self.parse_table_and_joins()?;
1722+
match table_and_joins.relation {
1723+
TableFactor::NestedJoin { .. } => (),
1724+
_ => {
1725+
if table_and_joins.joins.is_empty() {
1726+
// The SQL spec prohibits derived tables and bare
1727+
// tables from appearing alone in parentheses.
1728+
self.expected("joined table", self.peek_token())?
1729+
}
1730+
}
1731+
}
17221732
self.expect_token(&Token::RParen)?;
17231733
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
17241734
}

tests/sqlparser_common.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,12 @@ fn parse_join_nesting() {
17421742
from.joins,
17431743
vec![join(nest!(nest!(nest!(table("b"), table("c")))))]
17441744
);
1745+
1746+
let res = parse_sql_statements("SELECT * FROM (a NATURAL JOIN (b))");
1747+
assert_eq!(
1748+
ParserError::ParserError("Expected joined table, found: )".to_string()),
1749+
res.unwrap_err()
1750+
);
17451751
}
17461752

17471753
#[test]
@@ -1873,7 +1879,13 @@ fn parse_derived_tables() {
18731879
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
18741880
}],
18751881
}))
1876-
)
1882+
);
1883+
1884+
let res = parse_sql_statements("SELECT * FROM ((SELECT 1) AS t)");
1885+
assert_eq!(
1886+
ParserError::ParserError("Expected joined table, found: )".to_string()),
1887+
res.unwrap_err()
1888+
);
18771889
}
18781890

18791891
#[test]

0 commit comments

Comments
 (0)