mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-19 21:50:19 +00:00
Support NestedJoin
with an alias (#551)
* add alias for nestedjoin * fmt * add/modify test cases * inline nestedjoin instead of macro
This commit is contained in:
parent
e24951e080
commit
076b587bb2
5 changed files with 91 additions and 37 deletions
|
@ -375,7 +375,10 @@ pub enum TableFactor {
|
||||||
///
|
///
|
||||||
/// The parser may also accept non-standard nesting of bare tables for some
|
/// The parser may also accept non-standard nesting of bare tables for some
|
||||||
/// dialects, but the information about such nesting is stripped from AST.
|
/// 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 {
|
impl fmt::Display for TableFactor {
|
||||||
|
@ -438,7 +441,16 @@ impl fmt::Display for TableFactor {
|
||||||
}
|
}
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3869,12 +3869,24 @@ impl<'a> Parser<'a> {
|
||||||
#[allow(clippy::if_same_then_else)]
|
#[allow(clippy::if_same_then_else)]
|
||||||
if !table_and_joins.joins.is_empty() {
|
if !table_and_joins.joins.is_empty() {
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(TableFactor::NestedJoin(Box::new(table_and_joins))) // (A)
|
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
|
||||||
} else if let TableFactor::NestedJoin(_) = &table_and_joins.relation {
|
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)
|
// (B): `table_and_joins` (what we found inside the parentheses)
|
||||||
// is a nested join `(foo JOIN bar)`, not followed by other joins.
|
// is a nested join `(foo JOIN bar)`, not followed by other joins.
|
||||||
self.expect_token(&Token::RParen)?;
|
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) {
|
} else if dialect_of!(self is SnowflakeDialect | GenericDialect) {
|
||||||
// Dialect-specific behavior: Snowflake diverges from the
|
// Dialect-specific behavior: Snowflake diverges from the
|
||||||
// standard and from most of the other implementations by
|
// standard and from most of the other implementations by
|
||||||
|
@ -3893,7 +3905,8 @@ impl<'a> Parser<'a> {
|
||||||
TableFactor::Derived { alias, .. }
|
TableFactor::Derived { alias, .. }
|
||||||
| TableFactor::Table { alias, .. }
|
| TableFactor::Table { alias, .. }
|
||||||
| TableFactor::UNNEST { alias, .. }
|
| TableFactor::UNNEST { alias, .. }
|
||||||
| TableFactor::TableFunction { alias, .. } => {
|
| TableFactor::TableFunction { alias, .. }
|
||||||
|
| TableFactor::NestedJoin { alias, .. } => {
|
||||||
// but not `FROM (mytable AS alias1) AS alias2`.
|
// but not `FROM (mytable AS alias1) AS alias2`.
|
||||||
if let Some(inner_alias) = alias {
|
if let Some(inner_alias) = alias {
|
||||||
return Err(ParserError::ParserError(format!(
|
return Err(ParserError::ParserError(format!(
|
||||||
|
@ -3906,7 +3919,6 @@ impl<'a> Parser<'a> {
|
||||||
// `(mytable AS alias)`
|
// `(mytable AS alias)`
|
||||||
alias.replace(outer_alias);
|
alias.replace(outer_alias);
|
||||||
}
|
}
|
||||||
TableFactor::NestedJoin(_) => unreachable!(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Do not store the extra set of parens in the AST
|
// Do not store the extra set of parens in the AST
|
||||||
|
|
|
@ -3446,32 +3446,45 @@ fn parse_joins_using() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_natural_join() {
|
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 {
|
Join {
|
||||||
relation: TableFactor::Table {
|
relation: TableFactor::Table {
|
||||||
name: ObjectName(vec![Ident::new("t2")]),
|
name: ObjectName(vec![Ident::new("t2")]),
|
||||||
alias: None,
|
alias,
|
||||||
args: None,
|
args: None,
|
||||||
with_hints: vec![],
|
with_hints: vec![],
|
||||||
},
|
},
|
||||||
join_operator: f(JoinConstraint::Natural),
|
join_operator: f(JoinConstraint::Natural),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if not specified, inner join as default
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 NATURAL JOIN t2").from).joins,
|
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!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 NATURAL LEFT JOIN t2").from).joins,
|
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!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 NATURAL RIGHT JOIN t2").from).joins,
|
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!(
|
assert_eq!(
|
||||||
only(&verified_only_select("SELECT * FROM t1 NATURAL FULL JOIN t2").from).joins,
|
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";
|
let sql = "SELECT * FROM t1 natural";
|
||||||
|
@ -3519,6 +3532,21 @@ fn parse_join_nesting() {
|
||||||
from.joins,
|
from.joins,
|
||||||
vec![join(nest!(nest!(nest!(table("b"), table("c")))))]
|
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]
|
#[test]
|
||||||
|
@ -3676,7 +3704,8 @@ fn parse_derived_tables() {
|
||||||
let from = only(select.from);
|
let from = only(select.from);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from.relation,
|
from.relation,
|
||||||
TableFactor::NestedJoin(Box::new(TableWithJoins {
|
TableFactor::NestedJoin {
|
||||||
|
table_with_joins: Box::new(TableWithJoins {
|
||||||
relation: TableFactor::Derived {
|
relation: TableFactor::Derived {
|
||||||
lateral: false,
|
lateral: false,
|
||||||
subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
|
subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
|
||||||
|
@ -3694,7 +3723,9 @@ fn parse_derived_tables() {
|
||||||
},
|
},
|
||||||
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
|
||||||
}],
|
}],
|
||||||
}))
|
}),
|
||||||
|
alias: None
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,10 +131,9 @@ fn test_single_table_in_parenthesis_with_alias() {
|
||||||
"SELECT * FROM (a AS alias1 NATURAL JOIN b AS c)",
|
"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");
|
snowflake_and_generic().one_statement_parses_to(
|
||||||
assert_eq!(
|
"SELECT * FROM (a NATURAL JOIN b) c",
|
||||||
ParserError::ParserError("Expected end of statement, found: c".to_string()),
|
"SELECT * FROM (a NATURAL JOIN b) AS c",
|
||||||
res.unwrap_err()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let res = snowflake().parse_sql_statements("SELECT * FROM (a b) c");
|
let res = snowflake().parse_sql_statements("SELECT * FROM (a b) c");
|
||||||
|
|
|
@ -26,9 +26,9 @@ pub use sqlparser::test_utils::*;
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! nest {
|
macro_rules! nest {
|
||||||
($base:expr $(, $join:expr)*) => {
|
($base:expr $(, $join:expr)*) => {
|
||||||
TableFactor::NestedJoin(Box::new(TableWithJoins {
|
TableFactor::NestedJoin { table_with_joins: Box::new(TableWithJoins {
|
||||||
relation: $base,
|
relation: $base,
|
||||||
joins: vec![$(join($join)),*]
|
joins: vec![$(join($join)),*]
|
||||||
}))
|
}), alias: None}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue