This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 63eeaa0d [PIVOT] Optional AS keyword for aliases (#2209)
63eeaa0d is described below
commit 63eeaa0d7e4bdec852b34b6f125dfb90c1d7f3e9
Author: xitep <[email protected]>
AuthorDate: Wed Feb 18 10:24:01 2026 +0100
[PIVOT] Optional AS keyword for aliases (#2209)
---
src/ast/query.rs | 7 +++++--
src/parser/mod.rs | 49 +++++++++++++++++++++++++++++++----------------
tests/sqlparser_common.rs | 12 ++++++++++++
3 files changed, 49 insertions(+), 19 deletions(-)
diff --git a/src/ast/query.rs b/src/ast/query.rs
index b8f605be..6d95216d 100644
--- a/src/ast/query.rs
+++ b/src/ast/query.rs
@@ -1589,6 +1589,7 @@ pub enum TableFactor {
///
///
[BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator)
///
[Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/pivot)
+ ///
[Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-68257B27-1C4C-4C47-8140-5C60E0E65D35)
Pivot {
/// The input table to pivot.
table: Box<TableFactor>,
@@ -1610,8 +1611,10 @@ pub enum TableFactor {
/// table UNPIVOT [ { INCLUDE | EXCLUDE } NULLS ] (value FOR name IN
(column1, [ column2, ... ])) [ alias ]
/// ```
///
- /// See <https://docs.snowflake.com/en/sql-reference/constructs/unpivot>.
- /// See
<https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot>.
+ ///
[Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/unpivot)
+ ///
[Databricks](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot)
+ ///
[BigQuery](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#unpivot_operator)
+ ///
[Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-9B4E0389-413C-4014-94A1-0A0571BDF7E1)
Unpivot {
/// The input table to unpivot.
table: Box<TableFactor>,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index e708217d..eba9b32d 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -13617,7 +13617,7 @@ impl<'a> Parser<'a> {
Keyword::PIVOT => {
self.expect_token(&Token::LParen)?;
let aggregate_functions =
-
self.parse_comma_separated(Self::parse_aliased_function_call)?;
+
self.parse_comma_separated(Self::parse_pivot_aggregate_function)?;
self.expect_keyword_is(Keyword::FOR)?;
let value_column = self.parse_period_separated(|p|
p.parse_identifier())?;
self.expect_keyword_is(Keyword::IN)?;
@@ -16242,20 +16242,6 @@ impl<'a> Parser<'a> {
})
}
- fn parse_aliased_function_call(&mut self) -> Result<ExprWithAlias,
ParserError> {
- let function_name = match self.next_token().token {
- Token::Word(w) => Ok(w.value),
- _ => self.expected("a function identifier", self.peek_token()),
- }?;
- let expr =
self.parse_function(ObjectName::from(vec![Ident::new(function_name)]))?;
- let alias = if self.parse_keyword(Keyword::AS) {
- Some(self.parse_identifier()?)
- } else {
- None
- };
-
- Ok(ExprWithAlias { expr, alias })
- }
/// Parses an expression with an optional alias
///
/// Examples:
@@ -16289,13 +16275,40 @@ impl<'a> Parser<'a> {
Ok(ExprWithAlias { expr, alias })
}
+ /// Parse an expression followed by an optional alias; Unlike
+ /// [Self::parse_expr_with_alias] the "AS" keyword between the expression
+ /// and the alias is optional.
+ fn parse_expr_with_alias_optional_as_keyword(&mut self) ->
Result<ExprWithAlias, ParserError> {
+ let expr = self.parse_expr()?;
+ let alias = self.parse_identifier_optional_alias()?;
+ Ok(ExprWithAlias { expr, alias })
+ }
+
+ /// Parses a plain function call with an optional alias for the `PIVOT`
clause
+ fn parse_pivot_aggregate_function(&mut self) -> Result<ExprWithAlias,
ParserError> {
+ let function_name = match self.next_token().token {
+ Token::Word(w) => Ok(w.value),
+ _ => self.expected("a function identifier", self.peek_token()),
+ }?;
+ let expr =
self.parse_function(ObjectName::from(vec![Ident::new(function_name)]))?;
+ let alias = {
+ fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) ->
bool {
+ // ~ for a PIVOT aggregate function the alias must not be a
"FOR"; in any dialect
+ kw != &Keyword::FOR &&
parser.dialect.is_select_item_alias(explicit, kw, parser)
+ }
+ self.parse_optional_alias_inner(None, validator)?
+ };
+ Ok(ExprWithAlias { expr, alias })
+ }
+
/// Parse a PIVOT table factor (ClickHouse/Oracle style pivot), returning
a TableFactor.
pub fn parse_pivot_table_factor(
&mut self,
table: TableFactor,
) -> Result<TableFactor, ParserError> {
self.expect_token(&Token::LParen)?;
- let aggregate_functions =
self.parse_comma_separated(Self::parse_aliased_function_call)?;
+ let aggregate_functions =
+ self.parse_comma_separated(Self::parse_pivot_aggregate_function)?;
self.expect_keyword_is(Keyword::FOR)?;
let value_column = if self.peek_token_ref().token == Token::LParen {
self.parse_parenthesized_column_list_inner(Mandatory, false, |p| {
@@ -16317,7 +16330,9 @@ impl<'a> Parser<'a> {
} else if self.peek_sub_query() {
PivotValueSource::Subquery(self.parse_query()?)
} else {
-
PivotValueSource::List(self.parse_comma_separated(Self::parse_expr_with_alias)?)
+ PivotValueSource::List(
+
self.parse_comma_separated(Self::parse_expr_with_alias_optional_as_keyword)?,
+ )
};
self.expect_token(&Token::RParen)?;
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 5822153a..182854d1 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -11357,6 +11357,18 @@ fn parse_pivot_table() {
verified_stmt(multiple_value_columns_sql).to_string(),
multiple_value_columns_sql
);
+
+ // assert optional "AS" keyword for aliases for pivot values
+ one_statement_parses_to(
+ "SELECT * FROM t PIVOT(SUM(1) FOR a.abc IN (1 x, 'two' y, three z))",
+ "SELECT * FROM t PIVOT(SUM(1) FOR a.abc IN (1 AS x, 'two' AS y, three
AS z))",
+ );
+
+ // assert optional "AS" keyword for aliases for pivot aggregate function
+ one_statement_parses_to(
+ "SELECT * FROM t PIVOT(SUM(1) x, COUNT(42) y FOR a.abc IN (1))",
+ "SELECT * FROM t PIVOT(SUM(1) AS x, COUNT(42) AS y FOR a.abc IN (1))",
+ );
}
#[test]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]