Skip to content

Commit 076b587

Browse files
authored
Support NestedJoin with an alias (#551)
* add alias for nestedjoin * fmt * add/modify test cases * inline nestedjoin instead of macro
1 parent e24951e commit 076b587

File tree

5 files changed

+91
-37
lines changed

5 files changed

+91
-37
lines changed

src/ast/query.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,10 @@ pub enum TableFactor {
375375
///
376376
/// The parser may also accept non-standard nesting of bare tables for some
377377
/// dialects, but the information about such nesting is stripped from AST.
378-
NestedJoin(Box<TableWithJoins>),
378+
NestedJoin {
379+
table_with_joins: Box<TableWithJoins>,
380+
alias: Option<TableAlias>,
381+
},
379382
}
380383

381384
impl fmt::Display for TableFactor {
@@ -438,7 +441,16 @@ impl fmt::Display for TableFactor {
438441
}
439442
Ok(())
440443
}
441-
TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
444+
TableFactor::NestedJoin {
445+
table_with_joins,
446+
alias,
447+
} => {
448+
write!(f, "({})", table_with_joins)?;
449+
if let Some(alias) = alias {
450+
write!(f, " AS {}", alias)?;
451+
}
452+
Ok(())
453+
}
442454
}
443455
}
444456
}

src/parser.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -3869,12 +3869,24 @@ impl<'a> Parser<'a> {
38693869
#[allow(clippy::if_same_then_else)]
38703870
if !table_and_joins.joins.is_empty() {
38713871
self.expect_token(&Token::RParen)?;
3872-
Ok(TableFactor::NestedJoin(Box::new(table_and_joins))) // (A)
3873-
} else if let TableFactor::NestedJoin(_) = &table_and_joins.relation {
3872+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
3873+
Ok(TableFactor::NestedJoin {
3874+
table_with_joins: Box::new(table_and_joins),
3875+
alias,
3876+
}) // (A)
3877+
} else if let TableFactor::NestedJoin {
3878+
table_with_joins: _,
3879+
alias: _,
3880+
} = &table_and_joins.relation
3881+
{
38743882
// (B): `table_and_joins` (what we found inside the parentheses)
38753883
// is a nested join `(foo JOIN bar)`, not followed by other joins.
38763884
self.expect_token(&Token::RParen)?;
3877-
Ok(TableFactor::NestedJoin(Box::new(table_and_joins)))
3885+
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
3886+
Ok(TableFactor::NestedJoin {
3887+
table_with_joins: Box::new(table_and_joins),
3888+
alias,
3889+
})
38783890
} else if dialect_of!(self is SnowflakeDialect | GenericDialect) {
38793891
// Dialect-specific behavior: Snowflake diverges from the
38803892
// standard and from most of the other implementations by
@@ -3893,7 +3905,8 @@ impl<'a> Parser<'a> {
38933905
TableFactor::Derived { alias, .. }
38943906
| TableFactor::Table { alias, .. }
38953907
| TableFactor::UNNEST { alias, .. }
3896-
| TableFactor::TableFunction { alias, .. } => {
3908+
| TableFactor::TableFunction { alias, .. }
3909+
| TableFactor::NestedJoin { alias, .. } => {
38973910
// but not `FROM (mytable AS alias1) AS alias2`.
38983911
if let Some(inner_alias) = alias {
38993912
return Err(ParserError::ParserError(format!(
@@ -3906,7 +3919,6 @@ impl<'a> Parser<'a> {
39063919
// `(mytable AS alias)`
39073920
alias.replace(outer_alias);
39083921
}
3909-
TableFactor::NestedJoin(_) => unreachable!(),
39103922
};
39113923
}
39123924
// Do not store the extra set of parens in the AST

tests/sqlparser_common.rs

+55-24
Original file line numberDiff line numberDiff line change
@@ -3446,32 +3446,45 @@ fn parse_joins_using() {
34463446

34473447
#[test]
34483448
fn parse_natural_join() {
3449-
fn natural_join(f: impl Fn(JoinConstraint) -> JoinOperator) -> Join {
3449+
fn natural_join(f: impl Fn(JoinConstraint) -> JoinOperator, alias: Option<TableAlias>) -> Join {
34503450
Join {
34513451
relation: TableFactor::Table {
34523452
name: ObjectName(vec![Ident::new("t2")]),
3453-
alias: None,
3453+
alias,
34543454
args: None,
34553455
with_hints: vec![],
34563456
},
34573457
join_operator: f(JoinConstraint::Natural),
34583458
}
34593459
}
3460+
3461+
// if not specified, inner join as default
34603462
assert_eq!(
34613463
only(&verified_only_select("SELECT * FROM t1 NATURAL JOIN t2").from).joins,
3462-
vec![natural_join(JoinOperator::Inner)]
3464+
vec![natural_join(JoinOperator::Inner, None)]
34633465
);
3466+
// left join explicitly
34643467
assert_eq!(
34653468
only(&verified_only_select("SELECT * FROM t1 NATURAL LEFT JOIN t2").from).joins,
3466-
vec![natural_join(JoinOperator::LeftOuter)]
3469+
vec![natural_join(JoinOperator::LeftOuter, None)]
34673470
);
3471+
3472+
// right join explicitly
34683473
assert_eq!(
34693474
only(&verified_only_select("SELECT * FROM t1 NATURAL RIGHT JOIN t2").from).joins,
3470-
vec![natural_join(JoinOperator::RightOuter)]
3475+
vec![natural_join(JoinOperator::RightOuter, None)]
34713476
);
3477+
3478+
// full join explicitly
34723479
assert_eq!(
34733480
only(&verified_only_select("SELECT * FROM t1 NATURAL FULL JOIN t2").from).joins,
3474-
vec![natural_join(JoinOperator::FullOuter)]
3481+
vec![natural_join(JoinOperator::FullOuter, None)]
3482+
);
3483+
3484+
// natural join another table with alias
3485+
assert_eq!(
3486+
only(&verified_only_select("SELECT * FROM t1 NATURAL JOIN t2 AS t3").from).joins,
3487+
vec![natural_join(JoinOperator::Inner, table_alias("t3"))]
34753488
);
34763489

34773490
let sql = "SELECT * FROM t1 natural";
@@ -3519,6 +3532,21 @@ fn parse_join_nesting() {
35193532
from.joins,
35203533
vec![join(nest!(nest!(nest!(table("b"), table("c")))))]
35213534
);
3535+
3536+
let sql = "SELECT * FROM (a NATURAL JOIN b) AS c";
3537+
let select = verified_only_select(sql);
3538+
let from = only(select.from);
3539+
assert_eq!(
3540+
from.relation,
3541+
TableFactor::NestedJoin {
3542+
table_with_joins: Box::new(TableWithJoins {
3543+
relation: table("a"),
3544+
joins: vec![join(table("b"))],
3545+
}),
3546+
alias: table_alias("c")
3547+
}
3548+
);
3549+
assert_eq!(from.joins, vec![]);
35223550
}
35233551

35243552
#[test]
@@ -3676,25 +3704,28 @@ fn parse_derived_tables() {
36763704
let from = only(select.from);
36773705
assert_eq!(
36783706
from.relation,
3679-
TableFactor::NestedJoin(Box::new(TableWithJoins {
3680-
relation: TableFactor::Derived {
3681-
lateral: false,
3682-
subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
3683-
alias: Some(TableAlias {
3684-
name: "t1".into(),
3685-
columns: vec![],
3686-
})
3687-
},
3688-
joins: vec![Join {
3689-
relation: TableFactor::Table {
3690-
name: ObjectName(vec!["t2".into()]),
3691-
alias: None,
3692-
args: None,
3693-
with_hints: vec![],
3707+
TableFactor::NestedJoin {
3708+
table_with_joins: Box::new(TableWithJoins {
3709+
relation: TableFactor::Derived {
3710+
lateral: false,
3711+
subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
3712+
alias: Some(TableAlias {
3713+
name: "t1".into(),
3714+
columns: vec![],
3715+
})
36943716
},
3695-
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
3696-
}],
3697-
}))
3717+
joins: vec![Join {
3718+
relation: TableFactor::Table {
3719+
name: ObjectName(vec!["t2".into()]),
3720+
alias: None,
3721+
args: None,
3722+
with_hints: vec![],
3723+
},
3724+
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
3725+
}],
3726+
}),
3727+
alias: None
3728+
}
36983729
);
36993730
}
37003731

tests/sqlparser_snowflake.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,9 @@ fn test_single_table_in_parenthesis_with_alias() {
131131
"SELECT * FROM (a AS alias1 NATURAL JOIN b AS c)",
132132
);
133133

134-
let res = snowflake_and_generic().parse_sql_statements("SELECT * FROM (a NATURAL JOIN b) c");
135-
assert_eq!(
136-
ParserError::ParserError("Expected end of statement, found: c".to_string()),
137-
res.unwrap_err()
134+
snowflake_and_generic().one_statement_parses_to(
135+
"SELECT * FROM (a NATURAL JOIN b) c",
136+
"SELECT * FROM (a NATURAL JOIN b) AS c",
138137
);
139138

140139
let res = snowflake().parse_sql_statements("SELECT * FROM (a b) c");

tests/test_utils/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ pub use sqlparser::test_utils::*;
2626
#[macro_export]
2727
macro_rules! nest {
2828
($base:expr $(, $join:expr)*) => {
29-
TableFactor::NestedJoin(Box::new(TableWithJoins {
29+
TableFactor::NestedJoin { table_with_joins: Box::new(TableWithJoins {
3030
relation: $base,
3131
joins: vec![$(join($join)),*]
32-
}))
32+
}), alias: None}
3333
};
3434
}

0 commit comments

Comments
 (0)