@@ -9988,6 +9988,48 @@ impl<'a> Parser<'a> {
99889988        Ok(IdentWithAlias { ident, alias })
99899989    }
99909990
9991+     /// Parse `identifier [AS] identifier` where the AS keyword is optional
9992+     fn parse_identifier_with_optional_alias(&mut self) -> Result<IdentWithAlias, ParserError> {
9993+         let ident = self.parse_identifier()?;
9994+         let _after_as = self.parse_keyword(Keyword::AS);
9995+         let alias = self.parse_identifier()?;
9996+         Ok(IdentWithAlias { ident, alias })
9997+     }
9998+ 
9999+     /// Parse comma-separated list of parenthesized queries for pipe operators
10000+     fn parse_pipe_operator_queries(&mut self) -> Result<Vec<Query>, ParserError> {
10001+         self.parse_comma_separated(|parser| {
10002+             parser.expect_token(&Token::LParen)?;
10003+             let query = parser.parse_query()?;
10004+             parser.expect_token(&Token::RParen)?;
10005+             Ok(*query)
10006+         })
10007+     }
10008+ 
10009+     /// Parse set quantifier for pipe operators that require DISTINCT. E.g. INTERSECT and EXCEPT
10010+     fn parse_distinct_required_set_quantifier(
10011+         &mut self,
10012+         operator_name: &str,
10013+     ) -> Result<SetQuantifier, ParserError> {
10014+         let quantifier = self.parse_set_quantifier(&Some(SetOperator::Intersect));
10015+         match quantifier {
10016+             SetQuantifier::Distinct | SetQuantifier::DistinctByName => Ok(quantifier),
10017+             _ => Err(ParserError::ParserError(format!(
10018+                 "{operator_name} pipe operator requires DISTINCT modifier",
10019+             ))),
10020+         }
10021+     }
10022+ 
10023+     /// Parse optional identifier alias (with or without AS keyword)
10024+     fn parse_identifier_optional_alias(&mut self) -> Result<Option<Ident>, ParserError> {
10025+         if self.parse_keyword(Keyword::AS) {
10026+             Ok(Some(self.parse_identifier()?))
10027+         } else {
10028+             // Check if the next token is an identifier (implicit alias)
10029+             self.maybe_parse(|parser| parser.parse_identifier())
10030+         }
10031+     }
10032+ 
999110033    /// Optionally parses an alias for a select list item
999210034    fn maybe_parse_select_item_alias(&mut self) -> Result<Option<Ident>, ParserError> {
999310035        fn validator(explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
@@ -11134,6 +11176,19 @@ impl<'a> Parser<'a> {
1113411176                Keyword::AGGREGATE,
1113511177                Keyword::ORDER,
1113611178                Keyword::TABLESAMPLE,
11179+                 Keyword::RENAME,
11180+                 Keyword::UNION,
11181+                 Keyword::INTERSECT,
11182+                 Keyword::EXCEPT,
11183+                 Keyword::CALL,
11184+                 Keyword::PIVOT,
11185+                 Keyword::UNPIVOT,
11186+                 Keyword::JOIN,
11187+                 Keyword::INNER,
11188+                 Keyword::LEFT,
11189+                 Keyword::RIGHT,
11190+                 Keyword::FULL,
11191+                 Keyword::CROSS,
1113711192            ])?;
1113811193            match kw {
1113911194                Keyword::SELECT => {
@@ -11200,6 +11255,121 @@ impl<'a> Parser<'a> {
1120011255                    let sample = self.parse_table_sample(TableSampleModifier::TableSample)?;
1120111256                    pipe_operators.push(PipeOperator::TableSample { sample });
1120211257                }
11258+                 Keyword::RENAME => {
11259+                     let mappings =
11260+                         self.parse_comma_separated(Parser::parse_identifier_with_optional_alias)?;
11261+                     pipe_operators.push(PipeOperator::Rename { mappings });
11262+                 }
11263+                 Keyword::UNION => {
11264+                     let set_quantifier = self.parse_set_quantifier(&Some(SetOperator::Union));
11265+                     let queries = self.parse_pipe_operator_queries()?;
11266+                     pipe_operators.push(PipeOperator::Union {
11267+                         set_quantifier,
11268+                         queries,
11269+                     });
11270+                 }
11271+                 Keyword::INTERSECT => {
11272+                     let set_quantifier =
11273+                         self.parse_distinct_required_set_quantifier("INTERSECT")?;
11274+                     let queries = self.parse_pipe_operator_queries()?;
11275+                     pipe_operators.push(PipeOperator::Intersect {
11276+                         set_quantifier,
11277+                         queries,
11278+                     });
11279+                 }
11280+                 Keyword::EXCEPT => {
11281+                     let set_quantifier = self.parse_distinct_required_set_quantifier("EXCEPT")?;
11282+                     let queries = self.parse_pipe_operator_queries()?;
11283+                     pipe_operators.push(PipeOperator::Except {
11284+                         set_quantifier,
11285+                         queries,
11286+                     });
11287+                 }
11288+                 Keyword::CALL => {
11289+                     let function_name = self.parse_object_name(false)?;
11290+                     let function_expr = self.parse_function(function_name)?;
11291+                     if let Expr::Function(function) = function_expr {
11292+                         let alias = self.parse_identifier_optional_alias()?;
11293+                         pipe_operators.push(PipeOperator::Call { function, alias });
11294+                     } else {
11295+                         return Err(ParserError::ParserError(
11296+                             "Expected function call after CALL".to_string(),
11297+                         ));
11298+                     }
11299+                 }
11300+                 Keyword::PIVOT => {
11301+                     self.expect_token(&Token::LParen)?;
11302+                     let aggregate_functions =
11303+                         self.parse_comma_separated(Self::parse_aliased_function_call)?;
11304+                     self.expect_keyword_is(Keyword::FOR)?;
11305+                     let value_column = self.parse_period_separated(|p| p.parse_identifier())?;
11306+                     self.expect_keyword_is(Keyword::IN)?;
11307+ 
11308+                     self.expect_token(&Token::LParen)?;
11309+                     let value_source = if self.parse_keyword(Keyword::ANY) {
11310+                         let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
11311+                             self.parse_comma_separated(Parser::parse_order_by_expr)?
11312+                         } else {
11313+                             vec![]
11314+                         };
11315+                         PivotValueSource::Any(order_by)
11316+                     } else if self.peek_sub_query() {
11317+                         PivotValueSource::Subquery(self.parse_query()?)
11318+                     } else {
11319+                         PivotValueSource::List(
11320+                             self.parse_comma_separated(Self::parse_expr_with_alias)?,
11321+                         )
11322+                     };
11323+                     self.expect_token(&Token::RParen)?;
11324+                     self.expect_token(&Token::RParen)?;
11325+ 
11326+                     let alias = self.parse_identifier_optional_alias()?;
11327+ 
11328+                     pipe_operators.push(PipeOperator::Pivot {
11329+                         aggregate_functions,
11330+                         value_column,
11331+                         value_source,
11332+                         alias,
11333+                     });
11334+                 }
11335+                 Keyword::UNPIVOT => {
11336+                     self.expect_token(&Token::LParen)?;
11337+                     let value_column = self.parse_identifier()?;
11338+                     self.expect_keyword(Keyword::FOR)?;
11339+                     let name_column = self.parse_identifier()?;
11340+                     self.expect_keyword(Keyword::IN)?;
11341+ 
11342+                     self.expect_token(&Token::LParen)?;
11343+                     let unpivot_columns = self.parse_comma_separated(Parser::parse_identifier)?;
11344+                     self.expect_token(&Token::RParen)?;
11345+ 
11346+                     self.expect_token(&Token::RParen)?;
11347+ 
11348+                     let alias = self.parse_identifier_optional_alias()?;
11349+ 
11350+                     pipe_operators.push(PipeOperator::Unpivot {
11351+                         value_column,
11352+                         name_column,
11353+                         unpivot_columns,
11354+                         alias,
11355+                     });
11356+                 }
11357+                 Keyword::JOIN
11358+                 | Keyword::INNER
11359+                 | Keyword::LEFT
11360+                 | Keyword::RIGHT
11361+                 | Keyword::FULL
11362+                 | Keyword::CROSS => {
11363+                     self.prev_token();
11364+                     let mut joins = self.parse_joins()?;
11365+                     if joins.len() != 1 {
11366+                         return Err(ParserError::ParserError(
11367+                             "Join pipe operator must have a single join".to_string(),
11368+                         ));
11369+                     }
11370+                     let join = joins.swap_remove(0);
11371+                     pipe_operators.push(PipeOperator::Join(join))
11372+                 }
1120311373                unhandled => {
1120411374                    return Err(ParserError::ParserError(format!(
1120511375                    "`expect_one_of_keywords` further up allowed unhandled keyword: {unhandled:?}"
0 commit comments