Skip to content

Commit f692d90

Browse files
committed
Merge support-multi-column-alias
2 parents 3828bca + 156b6ff commit f692d90

File tree

7 files changed

+69
-2
lines changed

7 files changed

+69
-2
lines changed

src/ast/query.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,15 @@ pub enum SelectItem {
872872
/// The alias for the expression.
873873
alias: Ident,
874874
},
875+
/// An expression, followed by `[ AS ] (alias1, alias2, ...)`
876+
///
877+
/// [Spark SQL](https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select.html)
878+
ExprWithAliases {
879+
/// The expression being projected.
880+
expr: Expr,
881+
/// The list of aliases for the expression.
882+
aliases: Vec<Ident>,
883+
},
875884
/// An expression, followed by a wildcard expansion.
876885
/// e.g. `alias.*`, `STRUCT<STRING>('foo').*`
877886
QualifiedWildcard(SelectItemQualifiedWildcardKind, WildcardAdditionalOptions),
@@ -1175,6 +1184,12 @@ impl fmt::Display for SelectItem {
11751184
f.write_str(" AS ")?;
11761185
alias.fmt(f)
11771186
}
1187+
SelectItem::ExprWithAliases { expr, aliases } => {
1188+
expr.fmt(f)?;
1189+
f.write_str(" AS (")?;
1190+
display_comma_separated(aliases).fmt(f)?;
1191+
f.write_str(")")
1192+
}
11781193
SelectItem::QualifiedWildcard(kind, additional_options) => {
11791194
kind.fmt(f)?;
11801195
additional_options.fmt(f)

src/ast/spans.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,6 +1821,9 @@ impl Spanned for SelectItem {
18211821
match self {
18221822
SelectItem::UnnamedExpr(expr) => expr.span(),
18231823
SelectItem::ExprWithAlias { expr, alias } => expr.span().union(&alias.span),
1824+
SelectItem::ExprWithAliases { expr, aliases } => {
1825+
union_spans(iter::once(expr.span()).chain(aliases.iter().map(|i| i.span)))
1826+
}
18241827
SelectItem::QualifiedWildcard(kind, wildcard_additional_options) => union_spans(
18251828
[kind.span()]
18261829
.into_iter()

src/dialect/databricks.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::dialect::Dialect;
1919

2020
/// A [`Dialect`] for [Databricks SQL](https://www.databricks.com/)
2121
///
22-
/// See <https://docs.databricks.com/en/sql/language-manual/index.html>.
22+
/// See <https://docs.databricks.com/en/sql/language-manual/index.html>.
2323
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
2424
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2525
pub struct DatabricksDialect;
@@ -95,7 +95,7 @@ impl Dialect for DatabricksDialect {
9595
true
9696
}
9797

98-
/// See <https://docs.databricks.com/aws/en/sql/language-manual/functions/bangsign>
98+
/// See <https://docs.databricks.com/aws/en/sql/language-manual/functions/bangsign>
9999
fn supports_bang_not_operator(&self) -> bool {
100100
true
101101
}
@@ -104,4 +104,9 @@ impl Dialect for DatabricksDialect {
104104
fn supports_cte_without_as(&self) -> bool {
105105
true
106106
}
107+
108+
109+
fn supports_select_item_multi_column_alias(&self) -> bool {
110+
true
111+
}
107112
}

src/dialect/generic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,8 @@ impl Dialect for GenericDialect {
292292
fn supports_cte_without_as(&self) -> bool {
293293
true
294294
}
295+
296+
fn supports_select_item_multi_column_alias(&self) -> bool {
297+
true
298+
}
295299
}

src/dialect/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,18 @@ pub trait Dialect: Debug + Any {
16751675
fn supports_cte_without_as(&self) -> bool {
16761676
false
16771677
}
1678+
1679+
1680+
/// Returns true if the dialect supports parenthesized multi-column
1681+
/// aliases in SELECT items. For example:
1682+
/// ```sql
1683+
/// SELECT stack(2, 'a', 'b') AS (col1, col2)
1684+
/// ```
1685+
///
1686+
/// [Spark SQL](https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select.html)
1687+
fn supports_select_item_multi_column_alias(&self) -> bool {
1688+
false
1689+
}
16781690
}
16791691

16801692
/// Operators for which precedence must be defined.

src/parser/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18107,6 +18107,19 @@ impl<'a> Parser<'a> {
1810718107
self.parse_wildcard_additional_options(wildcard_token)?,
1810818108
))
1810918109
}
18110+
expr if self.dialect.supports_select_item_multi_column_alias()
18111+
&& self.peek_keyword(Keyword::AS)
18112+
&& self.peek_nth_token(1).token == Token::LParen =>
18113+
{
18114+
self.expect_keyword(Keyword::AS)?;
18115+
self.expect_token(&Token::LParen)?;
18116+
let aliases = self.parse_comma_separated(|p| p.parse_identifier())?;
18117+
self.expect_token(&Token::RParen)?;
18118+
Ok(SelectItem::ExprWithAliases {
18119+
expr: maybe_prefixed_expr(expr, prefix),
18120+
aliases,
18121+
})
18122+
}
1811018123
expr => self
1811118124
.maybe_parse_select_item_alias()
1811218125
.map(|alias| match alias {

tests/sqlparser_databricks.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,4 +677,19 @@ fn parse_cte_without_as() {
677677
assert!(all_dialects_where(|d| !d.supports_cte_without_as())
678678
.parse_sql_statements("WITH cte (SELECT 1) SELECT * FROM cte")
679679
.is_err());
680+
681+
}
682+
683+
#[test]
684+
fn parse_select_item_multi_column_alias() {
685+
databricks_and_generic().verified_stmt("SELECT stack(2, 'a', 'b', 'c', 'd') AS (col1, col2)");
686+
687+
databricks_and_generic()
688+
.verified_stmt("SELECT stack(2, 'a', 'b', 'c', 'd') AS (col1, col2) FROM t");
689+
690+
assert!(
691+
all_dialects_where(|d| !d.supports_select_item_multi_column_alias())
692+
.parse_sql_statements("SELECT stack(2, 'a', 'b') AS (col1, col2)")
693+
.is_err()
694+
);
680695
}

0 commit comments

Comments
 (0)