This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-2377-86a61436587f2ffdfd916f4966a5dba463266d5f in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit ed98c40011ea0966392e85bb81f815955f2a7de1 Author: Mosha Pasumansky <[email protected]> AuthorDate: Tue Jul 14 00:47:28 2026 -0700 PostgreSQL: support right-deep join chains (deferred ON clauses) (#2377) Co-authored-by: Claude Sonnet 4.6 <[email protected]> --- src/dialect/postgresql.rs | 6 ++++++ tests/sqlparser_postgres.rs | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index e980fc64..d342276e 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -299,6 +299,12 @@ impl Dialect for PostgreSqlDialect { true } + /// PostgreSQL supports right-deep join chains: `t0 JOIN t1 JOIN t2 ON c1 ON c2` + /// See: <https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-JOIN> + fn supports_left_associative_joins_without_parens(&self) -> bool { + false + } + /// Postgres supports `NOTNULL` as an alias for `IS NOT NULL` /// See: <https://www.postgresql.org/docs/17/functions-comparison.html> fn supports_notnull_operator(&self) -> bool { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 9ee6ab3d..9efa1dac 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -9582,3 +9582,20 @@ fn parse_limit_after_locking_clause() { // The pre-existing ordering keeps round-tripping unchanged. pg().verified_stmt("SELECT * FROM t ORDER BY id LIMIT 5 FOR UPDATE SKIP LOCKED"); } + +#[test] +fn parse_right_deep_join_chain() { + // PostgreSQL supports right-deep join syntax where ON clauses follow all JOIN keywords: + // t0 JOIN t1 JOIN t2 ON c1 ON c2 + // which is equivalent to (and serialized as) t0 JOIN (t1 JOIN t2 ON c1) ON c2. + pg().one_statement_parses_to( + "SELECT * FROM t0 INNER JOIN t1 INNER JOIN t2 ON true ON true", + "SELECT * FROM t0 INNER JOIN (t1 INNER JOIN t2 ON true) ON true", + ); + pg().one_statement_parses_to( + "SELECT * FROM t0 INNER JOIN t1 INNER JOIN t2 INNER JOIN t3 ON true ON true ON true", + "SELECT * FROM t0 INNER JOIN (t1 INNER JOIN (t2 INNER JOIN t3 ON true) ON true) ON true", + ); + // NATURAL JOIN followed by a constrained join must stay left-associative. + pg().verified_stmt("SELECT * FROM t0 NATURAL JOIN t1 INNER JOIN t2 ON true"); +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
