You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by lu...@apache.org on 2026/10/17 17:09:48 UTC

(datafusion-sqlparser-rs) branch sqlite-comma-join-constraints created (now 29d64ae7b)

This is an automated email from the ASF dual-hosted git repository.

LucaCappelletti94 pushed a change to branch sqlite-comma-join-constraints
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


      at 29d64ae7b SQLite: Support `ON` and `USING` after a comma join

This branch includes the following new commits:

     new 29d64ae7b SQLite: Support `ON` and `USING` after a comma join

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org


(datafusion-sqlparser-rs) 01/01: SQLite: Support `ON` and `USING` after a comma join

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

LucaCappelletti94 pushed a commit to branch sqlite-comma-join-constraints
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit 29d64ae7b776271288d19b19655163abe34d3ec9
Author: LucaCappelletti94 <ca...@gmail.com>
AuthorDate: Wed Sep 23 12:38:01 2026 +0200

    SQLite: Support `ON` and `USING` after a comma join
---
 src/dialect/generic.rs    |  4 ++++
 src/dialect/mod.rs        |  8 ++++++++
 src/dialect/sqlite.rs     |  4 ++++
 src/parser/mod.rs         | 32 ++++++++++++++++++++++++++++----
 tests/sqlparser_sqlite.rs | 38 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs
index 694eb8f19..9e6b2880b 100644
--- a/src/dialect/generic.rs
+++ b/src/dialect/generic.rs
@@ -173,6 +173,10 @@ impl Dialect for GenericDialect {
         true
     }
 
+    fn supports_comma_join_constraint(&self) -> bool {
+        true
+    }
+
     fn supports_comment_on(&self) -> bool {
         true
     }
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index f7c54a9b7..58b4b0908 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -445,6 +445,14 @@ pub trait Dialect: Debug + Any {
         false
     }
 
+    /// Returns true if the dialect supports `ON`/`USING` after a comma-joined table,
+    /// e.g. `SELECT * FROM t, u ON t.a = u.a`.
+    ///
+    /// [SQLite](https://www.sqlite.org/syntax/join-clause.html)
+    fn supports_comma_join_constraint(&self) -> bool {
+        false
+    }
+
     /// Returns true if the dialect supports CONNECT BY.
     fn supports_connect_by(&self) -> bool {
         false
diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs
index 497639556..081134f28 100644
--- a/src/dialect/sqlite.rs
+++ b/src/dialect/sqlite.rs
@@ -142,4 +142,8 @@ impl Dialect for SQLiteDialect {
     fn supports_national_string_literal(&self) -> bool {
         false
     }
+
+    fn supports_comma_join_constraint(&self) -> bool {
+        true
+    }
 }
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 340b2d077..519008f05 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -5086,13 +5086,37 @@ impl<'a> Parser<'a> {
 
     /// Parse a list of [TableWithJoins]
     fn parse_table_with_joins(&mut self) -> Result<Vec<TableWithJoins>, ParserError> {
-        let trailing_commas = self.dialect.supports_from_trailing_commas();
+        let dialect = self.dialect;
+        let trailing_commas = dialect.supports_from_trailing_commas();
+        let mut tables: Vec<TableWithJoins> = vec![];
 
         self.parse_comma_separated_with_trailing_commas(
-            Parser::parse_table_and_joins,
+            |parser| {
+                let table = parser.parse_table_and_joins()?;
+                match tables.last_mut() {
+                    Some(previous)
+                        if dialect.supports_comma_join_constraint()
+                            && table.joins.is_empty()
+                            && parser
+                                .peek_one_of_keywords(&[Keyword::ON, Keyword::USING])
+                                .is_some() =>
+                    {
+                        let constraint = parser.parse_join_constraint(false)?;
+                        previous.joins.push(Join {
+                            relation: table.relation,
+                            global: false,
+                            join_operator: JoinOperator::Join(constraint),
+                        });
+                        previous.joins.extend(parser.parse_joins()?);
+                    }
+                    _ => tables.push(table),
+                }
+                Ok(())
+            },
             trailing_commas,
-            |kw, parser| !self.dialect.is_table_factor(kw, parser),
-        )
+            |kw, parser| !dialect.is_table_factor(kw, parser),
+        )?;
+        Ok(tables)
     }
 
     /// Parse the comma of a comma-separated syntax element.
diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs
index ade2d9d82..a6a95d2e5 100644
--- a/tests/sqlparser_sqlite.rs
+++ b/tests/sqlparser_sqlite.rs
@@ -1117,6 +1117,44 @@ fn parse_create_table_options_list() {
     }
 }
 
+#[test]
+fn parse_comma_join_constraint() {
+    let dialects = all_dialects_where(|d| d.supports_comma_join_constraint());
+    for (sql, canonical) in [
+        (
+            "SELECT * FROM t, u ON t.a = u.a",
+            "SELECT * FROM t JOIN u ON t.a = u.a",
+        ),
+        (
+            "SELECT * FROM t, u USING (a)",
+            "SELECT * FROM t JOIN u USING(a)",
+        ),
+        (
+            "SELECT * FROM t, u ON t.a = u.a, v ON v.a = u.a",
+            "SELECT * FROM t JOIN u ON t.a = u.a JOIN v ON v.a = u.a",
+        ),
+        (
+            "SELECT * FROM t, u ON t.a = u.a JOIN v ON v.a = u.a",
+            "SELECT * FROM t JOIN u ON t.a = u.a JOIN v ON v.a = u.a",
+        ),
+        (
+            "UPDATE t SET a = 1 FROM u, v ON u.a = v.a",
+            "UPDATE t SET a = 1 FROM u JOIN v ON u.a = v.a",
+        ),
+    ] {
+        dialects.one_statement_parses_to(sql, canonical);
+    }
+    dialects.verified_stmt("SELECT * FROM t, u");
+
+    assert_eq!(
+        all_dialects_where(|d| !d.supports_comma_join_constraint())
+            .parse_sql_statements("SELECT * FROM t, u ON t.a = u.a"),
+        Err(ParserError::ParserError(
+            "Expected: end of statement, found: ON".to_string()
+        ))
+    );
+}
+
 fn sqlite() -> TestedDialects {
     TestedDialects::new(vec![Box::new(SQLiteDialect {})])
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org