Repository: apache/datafusion-sqlparser-rs (Rust)

Issue:
Nested alias doesn't work
from apache/arrow-datafusion#2867


while we have nested alias, the outer doesn't work

``` rust
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;

fn main() {

    let dialect = GenericDialect {}; // or AnsiDialect

    let sql = "SELECT __t404.__c394, __t404.__c395, __t404.__c396, __t404.__c397
                FROM ((
                    (SELECT test1.c0 AS __c394, test1.c1 AS __c395, test1.c2 AS __c396, test1.c3 AS __c397
                        FROM (test1)) __t398
                    INNER JOIN
                    (SELECT test1.c0 AS __c399, test1.c1 AS __c400, test1.c2 AS __c401, test1.c3 AS __c402
                        FROM (test1)) __t403
                    ON __t398.__c395 = __t403.__c401) __t404)
                WHERE __t404.__c395 != __t404.__c396; ";



    let ast = Parser::parse_sql(&dialect, sql).unwrap();

    println!("AST: {:?}", ast);
} 
```

``` bash
➜  sp git:(master) ✗ cargo run
   Compiling sp v0.1.0 (/Users/willy/willy/df-workspace/sp)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
     Running `target/debug/sp`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParserError("Expected ), found: __t404")', src/main.rs:26:48
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

while this works

```rust
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
                        
fn main() {                                                              
      
    let dialect = GenericDialect {}; // or AnsiDialect

    /* 
    let sql = "SELECT a, b, 123, myfunc(b) \
               FROM table_1 \
               WHERE a > b AND b < 100 \
               ORDER BY a DESC, b";
               */
    let sql = "SELECT __c394, __c395, __c396, __c397
                FROM ((
                    (SELECT test1.c0 AS __c394, test1.c1 AS __c395, test1.c2 AS __c396, test1.c3 AS __c397
                        FROM (test1)) __t398
                    INNER JOIN
                    (SELECT test1.c0 AS __c399, test1.c1 AS __c400, test1.c2 AS __c401, test1.c3 AS __c402
                        FROM (test1)) __t403
                    ON __t398.__c395 = __t403.__c401) )
                WHERE __c395 != __c396; ";

    

    let ast = Parser::parse_sql(&dialect, sql).unwrap();

    println!("AST: {:?}", ast);
}
```


Discussion:

Patch:
diff --git a/src/ast/query.rs b/src/ast/query.rs
index ed9d5781a..bc5af9e5f 100644
--- a/src/ast/query.rs
+++ b/src/ast/query.rs
@@ -375,7 +375,10 @@ pub enum TableFactor {
     ///
     /// The parser may also accept non-standard nesting of bare tables for some
     /// dialects, but the information about such nesting is stripped from AST.
-    NestedJoin(Box<TableWithJoins>),
+    NestedJoin {
+        table_with_joins: Box<TableWithJoins>,
+        alias: Option<TableAlias>,
+    },
 }
 
 impl fmt::Display for TableFactor {
@@ -438,7 +441,16 @@ impl fmt::Display for TableFactor {
                 }
                 Ok(())
             }
-            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
+            TableFactor::NestedJoin {
+                table_with_joins,
+                alias,
+            } => {
+                write!(f, "({})", table_with_joins)?;
+                if let Some(alias) = alias {
+                    write!(f, " AS {}", alias)?;
+                }
+                Ok(())
+            }
         }
     }
 }
diff --git a/src/parser.rs b/src/parser.rs
index 1fd74e716..a8181e3fe 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -3869,12 +3869,24 @@ impl<'a> Parser<'a> {
             #[allow(clippy::if_same_then_else)]
             if !table_and_joins.joins.is_empty() {
                 self.expect_token(&Token::RParen)?;
-                Ok(TableFactor::NestedJoin(Box::new(table_and_joins))) // (A)
-            } else if let TableFactor::NestedJoin(_) = &table_and_joins.relation {
+                let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
+                Ok(TableFactor::NestedJoin {
+                    table_with_joins: Box::new(table_and_joins),
+                    alias,
+                }) // (A)
+            } else if let TableFactor::NestedJoin {
+                table_with_joins: _,
+                alias: _,
+            } = &table_and_joins.relation
+            {
                 // (B): `table_and_joins` (what we found inside the parentheses)
                 // is a nested join `(foo JOIN bar)`, not followed by other joins.
                 self.expect_token(&Token::RParen)?;
-                Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
+                let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
+                Ok(TableFactor::NestedJoin {
+                    table_with_joins: Box::new(table_and_joins),
+                    alias,
+                })
             } else if dialect_of!(self is SnowflakeDialect | GenericDialect) {
                 // Dialect-specific behavior: Snowflake diverges from the
                 // standard and from most of the other implementations by
@@ -3893,7 +3905,8 @@ impl<'a> Parser<'a> {
                         TableFactor::Derived { alias, .. }
                         | TableFactor::Table { alias, .. }
                         | TableFactor::UNNEST { alias, .. }
-                        | TableFactor::TableFunction { alias, .. } => {
+                        | TableFactor::TableFunction { alias, .. }
+                        | TableFactor::NestedJoin { alias, .. } => {
                             // but not `FROM (mytable AS alias1) AS alias2`.
                             if let Some(inner_alias) = alias {
                                 return Err(ParserError::ParserError(format!(
@@ -3906,7 +3919,6 @@ impl<'a> Parser<'a> {
                             // `(mytable AS alias)`
                             alias.replace(outer_alias);
                         }
-                        TableFactor::NestedJoin(_) => unreachable!(),
                     };
                 }
                 // Do not store the extra set of parens in the AST


Test patch:
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 18641a947..c191f9200 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -3446,32 +3446,45 @@ fn parse_joins_using() {
 
 #[test]
 fn parse_natural_join() {
-    fn natural_join(f: impl Fn(JoinConstraint) -> JoinOperator) -> Join {
+    fn natural_join(f: impl Fn(JoinConstraint) -> JoinOperator, alias: Option<TableAlias>) -> Join {
         Join {
             relation: TableFactor::Table {
                 name: ObjectName(vec![Ident::new("t2")]),
-                alias: None,
+                alias,
                 args: None,
                 with_hints: vec![],
             },
             join_operator: f(JoinConstraint::Natural),
         }
     }
+
+    // if not specified, inner join as default
     assert_eq!(
         only(&verified_only_select("SELECT * FROM t1 NATURAL JOIN t2").from).joins,
-        vec![natural_join(JoinOperator::Inner)]
+        vec![natural_join(JoinOperator::Inner, None)]
     );
+    // left join explicitly
     assert_eq!(
         only(&verified_only_select("SELECT * FROM t1 NATURAL LEFT JOIN t2").from).joins,
-        vec![natural_join(JoinOperator::LeftOuter)]
+        vec![natural_join(JoinOperator::LeftOuter, None)]
     );
+
+    // right join explicitly
     assert_eq!(
         only(&verified_only_select("SELECT * FROM t1 NATURAL RIGHT JOIN t2").from).joins,
-        vec![natural_join(JoinOperator::RightOuter)]
+        vec![natural_join(JoinOperator::RightOuter, None)]
     );
+
+    // full join explicitly
     assert_eq!(
         only(&verified_only_select("SELECT * FROM t1 NATURAL FULL JOIN t2").from).joins,
-        vec![natural_join(JoinOperator::FullOuter)]
+        vec![natural_join(JoinOperator::FullOuter, None)]
+    );
+
+    // natural join another table with alias
+    assert_eq!(
+        only(&verified_only_select("SELECT * FROM t1 NATURAL JOIN t2 AS t3").from).joins,
+        vec![natural_join(JoinOperator::Inner, table_alias("t3"))]
     );
 
     let sql = "SELECT * FROM t1 natural";
@@ -3519,6 +3532,21 @@ fn parse_join_nesting() {
         from.joins,
         vec![join(nest!(nest!(nest!(table("b"), table("c")))))]
     );
+
+    let sql = "SELECT * FROM (a NATURAL JOIN b) AS c";
+    let select = verified_only_select(sql);
+    let from = only(select.from);
+    assert_eq!(
+        from.relation,
+        TableFactor::NestedJoin {
+            table_with_joins: Box::new(TableWithJoins {
+                relation: table("a"),
+                joins: vec![join(table("b"))],
+            }),
+            alias: table_alias("c")
+        }
+    );
+    assert_eq!(from.joins, vec![]);
 }
 
 #[test]
@@ -3676,25 +3704,28 @@ fn parse_derived_tables() {
     let from = only(select.from);
     assert_eq!(
         from.relation,
-        TableFactor::NestedJoin(Box::new(TableWithJoins {
-            relation: TableFactor::Derived {
-                lateral: false,
-                subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
-                alias: Some(TableAlias {
-                    name: "t1".into(),
-                    columns: vec![],
-                })
-            },
-            joins: vec![Join {
-                relation: TableFactor::Table {
-                    name: ObjectName(vec!["t2".into()]),
-                    alias: None,
-                    args: None,
-                    with_hints: vec![],
+        TableFactor::NestedJoin {
+            table_with_joins: Box::new(TableWithJoins {
+                relation: TableFactor::Derived {
+                    lateral: false,
+                    subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
+                    alias: Some(TableAlias {
+                        name: "t1".into(),
+                        columns: vec![],
+                    })
                 },
-                join_operator: JoinOperator::Inner(JoinConstraint::Natural),
-            }],
-        }))
+                joins: vec![Join {
+                    relation: TableFactor::Table {
+                        name: ObjectName(vec!["t2".into()]),
+                        alias: None,
+                        args: None,
+                        with_hints: vec![],
+                    },
+                    join_operator: JoinOperator::Inner(JoinConstraint::Natural),
+                }],
+            }),
+            alias: None
+        }
     );
 }
 
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index c08632a15..7c089a935 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -131,10 +131,9 @@ fn test_single_table_in_parenthesis_with_alias() {
         "SELECT * FROM (a AS alias1 NATURAL JOIN b AS c)",
     );
 
-    let res = snowflake_and_generic().parse_sql_statements("SELECT * FROM (a NATURAL JOIN b) c");
-    assert_eq!(
-        ParserError::ParserError("Expected end of statement, found: c".to_string()),
-        res.unwrap_err()
+    snowflake_and_generic().one_statement_parses_to(
+        "SELECT * FROM (a NATURAL JOIN b) c",
+        "SELECT * FROM (a NATURAL JOIN b) AS c",
     );
 
     let res = snowflake().parse_sql_statements("SELECT * FROM (a b) c");
diff --git a/tests/test_utils/mod.rs b/tests/test_utils/mod.rs
index f224314b9..d3a56ce46 100644
--- a/tests/test_utils/mod.rs
+++ b/tests/test_utils/mod.rs
@@ -26,9 +26,9 @@ pub use sqlparser::test_utils::*;
 #[macro_export]
 macro_rules! nest {
     ($base:expr $(, $join:expr)*) => {
-        TableFactor::NestedJoin(Box::new(TableWithJoins {
+        TableFactor::NestedJoin { table_with_joins: Box::new(TableWithJoins {
             relation: $base,
             joins: vec![$(join($join)),*]
-        }))
+        }), alias: None}
     };
 }