diff --git a/src/ast/query.rs b/src/ast/query.rs index 296e4e8ca..ebb8f4998 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -2701,6 +2701,9 @@ impl fmt::Display for Join { JoinConstraint::Using(attrs) => { write!(f, " USING({})", display_comma_separated(attrs)) } + JoinConstraint::UsingAlias(columns, alias) => { + write!(f, " USING({}) AS {alias}", display_comma_separated(columns)) + } _ => Ok(()), } } @@ -2890,6 +2893,8 @@ pub enum JoinConstraint { On(Expr), /// `USING(...)` list of column names. Using(Vec), + /// `USING(...) AS alias` list of column names with an alias for the joined columns. + UsingAlias(Vec, Ident), /// `NATURAL` join (columns matched automatically). Natural, /// No constraint specified (e.g. `CROSS JOIN`). diff --git a/src/ast/spans.rs b/src/ast/spans.rs index cb06b7899..e94765293 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -2304,6 +2304,12 @@ impl Spanned for JoinConstraint { match self { JoinConstraint::On(expr) => expr.span(), JoinConstraint::Using(vec) => union_spans(vec.iter().map(|i| i.span())), + JoinConstraint::UsingAlias(columns, alias) => union_spans( + columns + .iter() + .map(|i| i.span()) + .chain(iter::once(alias.span)), + ), JoinConstraint::Natural => Span::empty(), JoinConstraint::None => Span::empty(), } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c23b27053..16619a864 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -17745,7 +17745,14 @@ impl<'a> Parser<'a> { Ok(JoinConstraint::On(constraint)) } else if self.parse_keyword(Keyword::USING) { let columns = self.parse_parenthesized_qualified_column_list(Mandatory, false)?; - Ok(JoinConstraint::Using(columns)) + if self.parse_keyword(Keyword::AS) { + Ok(JoinConstraint::UsingAlias( + columns, + self.parse_identifier()?, + )) + } else { + Ok(JoinConstraint::Using(columns)) + } } else { Ok(JoinConstraint::None) //self.expected_ref("ON, or USING after JOIN", self.peek_token_ref()) diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 8f390b5ea..64dab4ae8 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -9931,3 +9931,11 @@ fn parse_non_reserved_keywords_as_table_alias() { )); } } + +#[test] +fn parse_join_using_alias() { + pg().one_statement_parses_to( + "SELECT * FROM t1 JOIN t2 USING (id) AS joined_cols", + "SELECT * FROM t1 JOIN t2 USING(id) AS joined_cols", + ); +}