File tree Expand file tree Collapse file tree 5 files changed +64
-1
lines changed
Expand file tree Collapse file tree 5 files changed +64
-1
lines changed Original file line number Diff line number Diff line change @@ -52,6 +52,10 @@ impl Dialect for GenericDialect {
5252 true
5353 }
5454
55+ fn supports_left_associative_joins_without_parens ( & self ) -> bool {
56+ true
57+ }
58+
5559 fn supports_connect_by ( & self ) -> bool {
5660 true
5761 }
Original file line number Diff line number Diff line change @@ -278,6 +278,34 @@ pub trait Dialect: Debug + Any {
278278 false
279279 }
280280
281+ /// Indicates whether the dialect supports left-associative join parsing
282+ /// by default when parentheses are omitted in nested joins.
283+ ///
284+ /// Most dialects (like MySQL or Postgres) assume **left-associative** precedence,
285+ /// so a query like:
286+ ///
287+ /// ```sql
288+ /// SELECT * FROM t1 NATURAL JOIN t5 INNER JOIN t0 ON ...
289+ /// ```
290+ /// is interpreted as:
291+ /// ```sql
292+ /// ((t1 NATURAL JOIN t5) INNER JOIN t0 ON ...)
293+ /// ```
294+ /// and internally represented as a **flat list** of joins.
295+ ///
296+ /// In contrast, some dialects (e.g. **Snowflake**) assume **right-associative**
297+ /// precedence and interpret the same query as:
298+ /// ```sql
299+ /// (t1 NATURAL JOIN (t5 INNER JOIN t0 ON ...))
300+ /// ```
301+ /// which results in a **nested join** structure in the AST.
302+ ///
303+ /// If this method returns `false`, the parser must build nested join trees
304+ /// even in the absence of parentheses to reflect the correct associativity
305+ fn supports_left_associative_joins_without_parens ( & self ) -> bool {
306+ true
307+ }
308+
281309 /// Returns true if the dialect supports the `(+)` syntax for OUTER JOIN.
282310 fn supports_outer_join_operator ( & self ) -> bool {
283311 false
Original file line number Diff line number Diff line change @@ -279,6 +279,10 @@ impl Dialect for SnowflakeDialect {
279279 true
280280 }
281281
282+ fn supports_left_associative_joins_without_parens ( & self ) -> bool {
283+ false
284+ }
285+
282286 fn is_reserved_for_identifier ( & self , kw : Keyword ) -> bool {
283287 // Unreserve some keywords that Snowflake accepts as identifiers
284288 // See: https://docs.snowflake.com/en/sql-reference/reserved-keywords
Original file line number Diff line number Diff line change @@ -11922,7 +11922,11 @@ impl<'a> Parser<'a> {
1192211922 };
1192311923 let mut relation = self.parse_table_factor()?;
1192411924
11925- if self.peek_parens_less_nested_join() {
11925+ if !self
11926+ .dialect
11927+ .supports_left_associative_joins_without_parens()
11928+ && self.peek_parens_less_nested_join()
11929+ {
1192611930 let joins = self.parse_joins()?;
1192711931 relation = TableFactor::NestedJoin {
1192811932 table_with_joins: Box::new(TableWithJoins { relation, joins }),
Original file line number Diff line number Diff line change @@ -15110,3 +15110,26 @@ fn parse_return() {
1511015110fn parse_subquery_limit() {
1511115111 let _ = all_dialects().verified_stmt("SELECT t1_id, t1_name FROM t1 WHERE t1_id IN (SELECT t2_id FROM t2 WHERE t1_name = t2_name LIMIT 10)");
1511215112}
15113+
15114+ #[test]
15115+ fn join_precedence() {
15116+ all_dialects_except(|d| !d.supports_left_associative_joins_without_parens())
15117+ .verified_query_with_canonical(
15118+ "SELECT *
15119+ FROM t1
15120+ NATURAL JOIN t5
15121+ INNER JOIN t0 ON (t0.v1 + t5.v0) > 0
15122+ WHERE t0.v1 = t1.v0",
15123+ // canonical string without parentheses
15124+ "SELECT * FROM t1 NATURAL JOIN t5 INNER JOIN t0 ON (t0.v1 + t5.v0) > 0 WHERE t0.v1 = t1.v0",
15125+ );
15126+ all_dialects_except(|d| d.supports_left_associative_joins_without_parens()).verified_query_with_canonical(
15127+ "SELECT *
15128+ FROM t1
15129+ NATURAL JOIN t5
15130+ INNER JOIN t0 ON (t0.v1 + t5.v0) > 0
15131+ WHERE t0.v1 = t1.v0",
15132+ // canonical string with parentheses
15133+ "SELECT * FROM t1 NATURAL JOIN (t5 INNER JOIN t0 ON (t0.v1 + t5.v0) > 0) WHERE t0.v1 = t1.v0",
15134+ );
15135+ }
You can’t perform that action at this time.
0 commit comments