mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-26 15:39:12 +00:00
Add support for qualified column names in JOIN ... USING (#1663)
This commit is contained in:
parent
e9498d538a
commit
44df6d6f92
4 changed files with 35 additions and 7 deletions
|
@ -2050,7 +2050,7 @@ pub enum JoinOperator {
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
pub enum JoinConstraint {
|
pub enum JoinConstraint {
|
||||||
On(Expr),
|
On(Expr),
|
||||||
Using(Vec<Ident>),
|
Using(Vec<ObjectName>),
|
||||||
Natural,
|
Natural,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2008,7 +2008,7 @@ impl Spanned for JoinConstraint {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
JoinConstraint::On(expr) => expr.span(),
|
JoinConstraint::On(expr) => expr.span(),
|
||||||
JoinConstraint::Using(vec) => union_spans(vec.iter().map(|i| i.span)),
|
JoinConstraint::Using(vec) => union_spans(vec.iter().map(|i| i.span())),
|
||||||
JoinConstraint::Natural => Span::empty(),
|
JoinConstraint::Natural => Span::empty(),
|
||||||
JoinConstraint::None => Span::empty(),
|
JoinConstraint::None => Span::empty(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -9336,18 +9336,45 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a parenthesized comma-separated list of unqualified, possibly quoted identifiers
|
/// Parses a parenthesized comma-separated list of unqualified, possibly quoted identifiers.
|
||||||
|
/// For example: `(col1, "col 2", ...)`
|
||||||
pub fn parse_parenthesized_column_list(
|
pub fn parse_parenthesized_column_list(
|
||||||
&mut self,
|
&mut self,
|
||||||
optional: IsOptional,
|
optional: IsOptional,
|
||||||
allow_empty: bool,
|
allow_empty: bool,
|
||||||
) -> Result<Vec<Ident>, ParserError> {
|
) -> Result<Vec<Ident>, ParserError> {
|
||||||
|
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| p.parse_identifier())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a parenthesized comma-separated list of qualified, possibly quoted identifiers.
|
||||||
|
/// For example: `(db1.sc1.tbl1.col1, db1.sc1.tbl1."col 2", ...)`
|
||||||
|
pub fn parse_parenthesized_qualified_column_list(
|
||||||
|
&mut self,
|
||||||
|
optional: IsOptional,
|
||||||
|
allow_empty: bool,
|
||||||
|
) -> Result<Vec<ObjectName>, ParserError> {
|
||||||
|
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| {
|
||||||
|
p.parse_object_name(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a parenthesized comma-separated list of columns using
|
||||||
|
/// the provided function to parse each element.
|
||||||
|
fn parse_parenthesized_column_list_inner<F, T>(
|
||||||
|
&mut self,
|
||||||
|
optional: IsOptional,
|
||||||
|
allow_empty: bool,
|
||||||
|
mut f: F,
|
||||||
|
) -> Result<Vec<T>, ParserError>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut Parser) -> Result<T, ParserError>,
|
||||||
|
{
|
||||||
if self.consume_token(&Token::LParen) {
|
if self.consume_token(&Token::LParen) {
|
||||||
if allow_empty && self.peek_token().token == Token::RParen {
|
if allow_empty && self.peek_token().token == Token::RParen {
|
||||||
self.next_token();
|
self.next_token();
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
} else {
|
} else {
|
||||||
let cols = self.parse_comma_separated(|p| p.parse_identifier())?;
|
let cols = self.parse_comma_separated(|p| f(p))?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(cols)
|
Ok(cols)
|
||||||
}
|
}
|
||||||
|
@ -9358,7 +9385,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a parenthesized comma-separated list of table alias column definitions.
|
/// Parses a parenthesized comma-separated list of table alias column definitions.
|
||||||
fn parse_table_alias_column_defs(&mut self) -> Result<Vec<TableAliasColumnDef>, ParserError> {
|
fn parse_table_alias_column_defs(&mut self) -> Result<Vec<TableAliasColumnDef>, ParserError> {
|
||||||
if self.consume_token(&Token::LParen) {
|
if self.consume_token(&Token::LParen) {
|
||||||
let cols = self.parse_comma_separated(|p| {
|
let cols = self.parse_comma_separated(|p| {
|
||||||
|
@ -11853,7 +11880,7 @@ impl<'a> Parser<'a> {
|
||||||
let constraint = self.parse_expr()?;
|
let constraint = self.parse_expr()?;
|
||||||
Ok(JoinConstraint::On(constraint))
|
Ok(JoinConstraint::On(constraint))
|
||||||
} else if self.parse_keyword(Keyword::USING) {
|
} else if self.parse_keyword(Keyword::USING) {
|
||||||
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
|
let columns = self.parse_parenthesized_qualified_column_list(Mandatory, false)?;
|
||||||
Ok(JoinConstraint::Using(columns))
|
Ok(JoinConstraint::Using(columns))
|
||||||
} else {
|
} else {
|
||||||
Ok(JoinConstraint::None)
|
Ok(JoinConstraint::None)
|
||||||
|
|
|
@ -6541,7 +6541,7 @@ fn parse_joins_using() {
|
||||||
sample: None,
|
sample: None,
|
||||||
},
|
},
|
||||||
global: false,
|
global: false,
|
||||||
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
|
join_operator: f(JoinConstraint::Using(vec![ObjectName(vec!["c1".into()])])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Test parsing of aliases
|
// Test parsing of aliases
|
||||||
|
@ -6598,6 +6598,7 @@ fn parse_joins_using() {
|
||||||
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 USING(c1)").from).joins,
|
only(&verified_only_select("SELECT * FROM t1 FULL JOIN t2 USING(c1)").from).joins,
|
||||||
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
|
vec![join_with_constraint("t2", None, JoinOperator::FullOuter)]
|
||||||
);
|
);
|
||||||
|
verified_stmt("SELECT * FROM tbl1 AS t1 JOIN tbl2 AS t2 USING(t2.col1)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue