diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e26cb0dfc..2d13f2ea7 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3362,6 +3362,8 @@ pub struct Function { // Some functions must be called without trailing parentheses, for example Postgres // do it for current_catalog, current_schema, etc. This flags is used for formatting. pub special: bool, + // Required ordering for the function (if empty, there is no requirement). + pub order_by: Vec, } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] @@ -3388,12 +3390,18 @@ impl fmt::Display for Function { if self.special { write!(f, "{}", self.name)?; } else { + let order_by = if !self.order_by.is_empty() { + " ORDER BY " + } else { + "" + }; write!( f, - "{}({}{})", + "{}({}{}{order_by}{})", self.name, if self.distinct { "DISTINCT " } else { "" }, display_comma_separated(&self.args), + display_comma_separated(&self.order_by), )?; if let Some(o) = &self.over { diff --git a/src/ast/visitor.rs b/src/ast/visitor.rs index 6787bfd68..81343220a 100644 --- a/src/ast/visitor.rs +++ b/src/ast/visitor.rs @@ -480,7 +480,7 @@ where /// *expr = Expr::Function(Function { /// name: ObjectName(vec![Ident::new("f")]), /// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))], -/// over: None, distinct: false, special: false, +/// over: None, distinct: false, special: false, order_by: vec![], /// }); /// } /// ControlFlow::<()>::Continue(()) diff --git a/src/parser.rs b/src/parser.rs index af577ce5d..c53f07fce 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -705,6 +705,7 @@ impl<'a> Parser<'a> { over: None, distinct: false, special: true, + order_by: vec![], })) } Keyword::CURRENT_TIMESTAMP @@ -880,7 +881,7 @@ impl<'a> Parser<'a> { pub fn parse_function(&mut self, name: ObjectName) -> Result { self.expect_token(&Token::LParen)?; let distinct = self.parse_all_or_distinct()?.is_some(); - let args = self.parse_optional_args()?; + let (args, order_by) = self.parse_optional_args_with_orderby()?; let over = if self.parse_keyword(Keyword::OVER) { // TBD: support window names (`OVER mywin`) in place of inline specification self.expect_token(&Token::LParen)?; @@ -917,14 +918,15 @@ impl<'a> Parser<'a> { over, distinct, special: false, + order_by, })) } pub fn parse_time_functions(&mut self, name: ObjectName) -> Result { - let args = if self.consume_token(&Token::LParen) { - self.parse_optional_args()? + let (args, order_by) = if self.consume_token(&Token::LParen) { + self.parse_optional_args_with_orderby()? } else { - vec![] + (vec![], vec![]) }; Ok(Expr::Function(Function { name, @@ -932,6 +934,7 @@ impl<'a> Parser<'a> { over: None, distinct: false, special: false, + order_by, })) } @@ -6370,6 +6373,23 @@ impl<'a> Parser<'a> { } } + pub fn parse_optional_args_with_orderby( + &mut self, + ) -> Result<(Vec, Vec), ParserError> { + if self.consume_token(&Token::RParen) { + Ok((vec![], vec![])) + } else { + let args = self.parse_comma_separated(Parser::parse_function_args)?; + let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) { + self.parse_comma_separated(Parser::parse_order_by_expr)? + } else { + vec![] + }; + self.expect_token(&Token::RParen)?; + Ok((args, order_by)) + } + } + /// Parse a comma-delimited list of projections after SELECT pub fn parse_select_item(&mut self) -> Result { match self.parse_wildcard_expr()? { diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 0850bd4bf..11998ae6d 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -437,6 +437,7 @@ fn parse_map_access_offset() { over: None, distinct: false, special: false, + order_by: vec![], })], }) ); diff --git a/tests/sqlparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs index bb0ec48fa..23a399608 100644 --- a/tests/sqlparser_clickhouse.rs +++ b/tests/sqlparser_clickhouse.rs @@ -52,6 +52,7 @@ fn parse_map_access_expr() { over: None, distinct: false, special: false, + order_by: vec![], })], })], into: None, @@ -88,6 +89,7 @@ fn parse_map_access_expr() { over: None, distinct: false, special: false, + order_by: vec![], })] }), op: BinaryOperator::NotEq, @@ -135,6 +137,7 @@ fn parse_array_fn() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(only(&select.projection)) ); @@ -189,6 +192,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[1]), ); diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index ac5c18c0e..380547cc1 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -838,6 +838,7 @@ fn parse_select_count_wildcard() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(only(&select.projection)) ); @@ -857,6 +858,7 @@ fn parse_select_count_distinct() { over: None, distinct: true, special: false, + order_by: vec![], }), expr_from_projection(only(&select.projection)) ); @@ -1693,6 +1695,7 @@ fn parse_select_having() { over: None, distinct: false, special: false, + order_by: vec![], })), op: BinaryOperator::Gt, right: Box::new(Expr::Value(number("1"))), @@ -1726,6 +1729,7 @@ fn parse_select_qualify() { }), distinct: false, special: false, + order_by: vec![], })), op: BinaryOperator::Eq, right: Box::new(Expr::Value(number("1"))), @@ -2072,6 +2076,29 @@ fn parse_array_agg_func() { } } +#[test] +fn parse_agg_with_order_by() { + let supported_dialects = TestedDialects { + dialects: vec![ + Box::new(GenericDialect {}), + Box::new(PostgreSqlDialect {}), + Box::new(MsSqlDialect {}), + Box::new(AnsiDialect {}), + Box::new(HiveDialect {}), + ], + options: None, + }; + + for sql in [ + "SELECT FIRST_VALUE(x ORDER BY x) AS a FROM T", + "SELECT FIRST_VALUE(x ORDER BY x) FROM tbl", + "SELECT LAST_VALUE(x ORDER BY x, y) AS a FROM T", + "SELECT LAST_VALUE(x ORDER BY x ASC, y DESC) AS a FROM T", + ] { + supported_dialects.verified_stmt(sql); + } +} + #[test] fn parse_create_table() { let sql = "CREATE TABLE uk_cities (\ @@ -3116,6 +3143,7 @@ fn parse_scalar_function_in_projection() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(only(&select.projection)) ); @@ -3234,6 +3262,7 @@ fn parse_named_argument_function() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(only(&select.projection)) ); @@ -3272,6 +3301,7 @@ fn parse_window_functions() { }), distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -3670,6 +3700,7 @@ fn parse_at_timezone() { over: None, distinct: false, special: false, + order_by: vec![], })), time_zone: "UTC-06:00".to_string(), }, @@ -3696,6 +3727,7 @@ fn parse_at_timezone() { over: None, distinct: false, special: false, + order_by: vec![], },)), time_zone: "UTC-06:00".to_string(), },),), @@ -3706,6 +3738,7 @@ fn parse_at_timezone() { over: None, distinct: false, special: false, + order_by: vec![], },), alias: Ident { value: "hour".to_string(), @@ -3863,6 +3896,7 @@ fn parse_table_function() { over: None, distinct: false, special: false, + order_by: vec![], }); assert_eq!(expr, expected_expr); assert_eq!(alias, table_alias("a")) @@ -6286,6 +6320,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -6302,6 +6337,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -6318,6 +6354,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -6334,6 +6371,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -6350,6 +6388,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -6814,6 +6853,7 @@ fn parse_pivot_table() { over: None, distinct: false, special: false, + order_by: vec![], }), value_column: vec![Ident::new("a"), Ident::new("MONTH")], pivot_values: vec![ diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index 87c2660a8..ddc5a8ccf 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -346,6 +346,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[1]), ); diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 1f708b5e7..53db33230 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -177,6 +177,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[1]), ); diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index c70f2cb95..ba6f2b5f7 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -791,6 +791,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + order_by: vec![], }) }, Assignment { @@ -803,6 +804,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + order_by: vec![], }) }, Assignment { @@ -815,6 +817,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + order_by: vec![], }) }, Assignment { @@ -827,6 +830,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + order_by: vec![], }) }, Assignment { @@ -839,6 +843,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + order_by: vec![], }) }, ])), @@ -1182,6 +1187,7 @@ fn parse_table_colum_option_on_update() { over: None, distinct: false, special: false, + order_by: vec![], })), },], }], diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 9de8e0eb4..51e15f260 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -2057,7 +2057,8 @@ fn test_composite_value() { )))], over: None, distinct: false, - special: false + special: false, + order_by: vec![], })))) }), select.projection[0] @@ -2219,6 +2220,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + order_by: vec![], }), expr_from_projection(&select.projection[0]) ); @@ -2229,6 +2231,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + order_by: vec![], }), expr_from_projection(&select.projection[1]) ); @@ -2239,6 +2242,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + order_by: vec![], }), expr_from_projection(&select.projection[2]) ); @@ -2249,6 +2253,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + order_by: vec![], }), expr_from_projection(&select.projection[3]) ); @@ -2503,6 +2508,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[1]), ); diff --git a/tests/sqlparser_redshift.rs b/tests/sqlparser_redshift.rs index d3a676939..c44f6dee4 100644 --- a/tests/sqlparser_redshift.rs +++ b/tests/sqlparser_redshift.rs @@ -132,6 +132,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[1]), ); diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index d1a63dc86..9a54c89cf 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -249,6 +249,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + order_by: vec![], }), expr_from_projection(&select.projection[1]), );