From e4789fc4464caf50132dee759fd6db2f6106dc76 Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Wed, 23 Sep 2026 09:29:49 +0200 Subject: [PATCH 1/2] SQLite, DuckDB: Support aggregate `ORDER BY` without arguments --- src/dialect/duckdb.rs | 4 ++++ src/dialect/generic.rs | 4 ++++ src/dialect/mod.rs | 9 +++++++++ src/dialect/sqlite.rs | 4 ++++ src/parser/mod.rs | 9 ++++++++- tests/sqlparser_common.rs | 22 ++++++++++++++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/dialect/duckdb.rs b/src/dialect/duckdb.rs index 4e27d042b5..6f329ab2f8 100644 --- a/src/dialect/duckdb.rs +++ b/src/dialect/duckdb.rs @@ -69,6 +69,10 @@ impl Dialect for DuckDbDialect { true } + fn supports_aggregate_order_by_with_empty_args(&self) -> bool { + true + } + fn supports_named_fn_args_with_eq_operator(&self) -> bool { true } diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs index fb3f2c254f..6aae6acaea 100644 --- a/src/dialect/generic.rs +++ b/src/dialect/generic.rs @@ -189,6 +189,10 @@ impl Dialect for GenericDialect { true } + fn supports_aggregate_order_by_with_empty_args(&self) -> bool { + true + } + fn supports_comment_on(&self) -> bool { true } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 847d042418..094687af34 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -2138,6 +2138,15 @@ pub trait Dialect: Debug + Any { fn supports_cast_empty_data_type_to_unspecified(&self) -> bool { false } + + /// Returns true if the dialect allows an `ORDER BY` clause inside an aggregate function + /// call with no preceding arguments, e.g. `count(ORDER BY a)`. + /// + /// [SQLite](https://www.sqlite.org/lang_aggfunc.html#aggorderby), + /// [DuckDB](https://duckdb.org/docs/current/sql/functions/aggregates#order-by-clause-in-aggregate-functions) + fn supports_aggregate_order_by_with_empty_args(&self) -> bool { + false + } } /// Operators for which precedence must be defined. diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs index 16be3303bb..0224a0d834 100644 --- a/src/dialect/sqlite.rs +++ b/src/dialect/sqlite.rs @@ -226,4 +226,8 @@ impl Dialect for SQLiteDialect { fn supports_comma_join_constraint(&self) -> bool { true } + + fn supports_aggregate_order_by_with_empty_args(&self) -> bool { + true + } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 608e6c364f..2338a2d145 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -19437,7 +19437,14 @@ impl<'a> Parser<'a> { } let duplicate_treatment = self.parse_duplicate_treatment()?; - let args = self.parse_comma_separated(Parser::parse_function_args)?; + let args = if duplicate_treatment != Some(DuplicateTreatment::Distinct) + && self.dialect.supports_aggregate_order_by_with_empty_args() + && self.peek_keywords(&[Keyword::ORDER, Keyword::BY]) + { + vec![] + } else { + self.parse_comma_separated(Parser::parse_function_args)? + }; if self.parse_keyword(Keyword::WHERE) { clauses.push(FunctionArgumentClause::Where(self.parse_expr()?)); diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 6c047d17fb..1c6ff0f38e 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -21336,3 +21336,25 @@ fn parse_qualified_literal_prefix_requires_adjacent_period() { dialects.tokenizes_to(sql, vec![token]); } } + +#[test] +fn parse_aggregate_order_by_with_empty_args() { + let dialects = all_dialects_where(|d| d.supports_aggregate_order_by_with_empty_args()); + dialects.verified_stmt("SELECT count(ORDER BY a) FROM t"); + dialects.verified_stmt("SELECT count(ORDER BY a ASC, b DESC) FROM t"); + dialects.verified_stmt("SELECT count(ALL ORDER BY a) FROM t"); + assert_eq!( + dialects.parse_sql_statements("SELECT count(DISTINCT ORDER BY a) FROM t"), + Err(ParserError::ParserError( + "Expected: ), found: BY".to_string() + )) + ); + + assert_eq!( + all_dialects_where(|d| !d.supports_aggregate_order_by_with_empty_args()) + .parse_sql_statements("SELECT count(ORDER BY a) FROM t"), + Err(ParserError::ParserError( + "Expected: ), found: BY".to_string() + )) + ); +} From 1612cae1bb4dbefe2357faf5bc8afce3b9b6e1b6 Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Sat, 24 Oct 2026 00:11:18 +0200 Subject: [PATCH 2/2] Place regression tests beside related syntax cases --- tests/sqlparser_common.rs | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 1c6ff0f38e..f83a34be20 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -3937,6 +3937,28 @@ fn parse_agg_with_order_by() { } } +#[test] +fn parse_aggregate_order_by_with_empty_args() { + let dialects = all_dialects_where(|d| d.supports_aggregate_order_by_with_empty_args()); + dialects.verified_stmt("SELECT count(ORDER BY a) FROM t"); + dialects.verified_stmt("SELECT count(ORDER BY a ASC, b DESC) FROM t"); + dialects.verified_stmt("SELECT count(ALL ORDER BY a) FROM t"); + assert_eq!( + dialects.parse_sql_statements("SELECT count(DISTINCT ORDER BY a) FROM t"), + Err(ParserError::ParserError( + "Expected: ), found: BY".to_string() + )) + ); + + assert_eq!( + all_dialects_where(|d| !d.supports_aggregate_order_by_with_empty_args()) + .parse_sql_statements("SELECT count(ORDER BY a) FROM t"), + Err(ParserError::ParserError( + "Expected: ), found: BY".to_string() + )) + ); +} + #[test] fn parse_window_rank_function() { let supported_dialects = TestedDialects::new(vec![ @@ -21336,25 +21358,3 @@ fn parse_qualified_literal_prefix_requires_adjacent_period() { dialects.tokenizes_to(sql, vec![token]); } } - -#[test] -fn parse_aggregate_order_by_with_empty_args() { - let dialects = all_dialects_where(|d| d.supports_aggregate_order_by_with_empty_args()); - dialects.verified_stmt("SELECT count(ORDER BY a) FROM t"); - dialects.verified_stmt("SELECT count(ORDER BY a ASC, b DESC) FROM t"); - dialects.verified_stmt("SELECT count(ALL ORDER BY a) FROM t"); - assert_eq!( - dialects.parse_sql_statements("SELECT count(DISTINCT ORDER BY a) FROM t"), - Err(ParserError::ParserError( - "Expected: ), found: BY".to_string() - )) - ); - - assert_eq!( - all_dialects_where(|d| !d.supports_aggregate_order_by_with_empty_args()) - .parse_sql_statements("SELECT count(ORDER BY a) FROM t"), - Err(ParserError::ParserError( - "Expected: ), found: BY".to_string() - )) - ); -}