Skip to content

Commit 3b1076c

Browse files
authored
Support DISTINCT ON (...) (#852)
* Support "DISTINCT ON (...)" * a test * fix the merge
1 parent f72e2ec commit 3b1076c

7 files changed

+96
-31
lines changed

src/ast/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ pub use self::ddl::{
3434
};
3535
pub use self::operator::{BinaryOperator, UnaryOperator};
3636
pub use self::query::{
37-
Cte, ExceptSelectItem, ExcludeSelectItem, Fetch, IdentWithAlias, Join, JoinConstraint,
38-
JoinOperator, LateralView, LockClause, LockType, NonBlock, Offset, OffsetRows, OrderByExpr,
39-
Query, RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto,
40-
SelectItem, SetExpr, SetOperator, SetQuantifier, Table, TableAlias, TableFactor,
37+
Cte, Distinct, ExceptSelectItem, ExcludeSelectItem, Fetch, IdentWithAlias, Join,
38+
JoinConstraint, JoinOperator, LateralView, LockClause, LockType, NonBlock, Offset, OffsetRows,
39+
OrderByExpr, Query, RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select,
40+
SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Table, TableAlias, TableFactor,
4141
TableWithJoins, Top, Values, WildcardAdditionalOptions, With,
4242
};
4343
pub use self::value::{

src/ast/query.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl fmt::Display for Table {
193193
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
194194
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
195195
pub struct Select {
196-
pub distinct: bool,
196+
pub distinct: Option<Distinct>,
197197
/// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
198198
pub top: Option<Top>,
199199
/// projection expressions
@@ -222,7 +222,10 @@ pub struct Select {
222222

223223
impl fmt::Display for Select {
224224
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225-
write!(f, "SELECT{}", if self.distinct { " DISTINCT" } else { "" })?;
225+
write!(f, "SELECT")?;
226+
if let Some(ref distinct) = self.distinct {
227+
write!(f, " {distinct}")?;
228+
}
226229
if let Some(ref top) = self.top {
227230
write!(f, " {top}")?;
228231
}
@@ -1079,6 +1082,29 @@ impl fmt::Display for NonBlock {
10791082
}
10801083
}
10811084

1085+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1086+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1087+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1088+
pub enum Distinct {
1089+
/// DISTINCT
1090+
Distinct,
1091+
1092+
/// DISTINCT ON({column names})
1093+
On(Vec<Expr>),
1094+
}
1095+
1096+
impl fmt::Display for Distinct {
1097+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1098+
match self {
1099+
Distinct::Distinct => write!(f, "DISTINCT"),
1100+
Distinct::On(col_names) => {
1101+
let col_names = display_comma_separated(col_names);
1102+
write!(f, "DISTINCT ON ({col_names})")
1103+
}
1104+
}
1105+
}
1106+
}
1107+
10821108
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
10831109
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10841110
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -1105,7 +1131,7 @@ impl fmt::Display for Top {
11051131
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11061132
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
11071133
pub struct Values {
1108-
/// Was there an explict ROWs keyword (MySQL)?
1134+
/// Was there an explicit ROWs keyword (MySQL)?
11091135
/// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
11101136
pub explicit_row: bool,
11111137
pub rows: Vec<Vec<Expr>>,

src/parser.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ impl<'a> Parser<'a> {
879879

880880
pub fn parse_function(&mut self, name: ObjectName) -> Result<Expr, ParserError> {
881881
self.expect_token(&Token::LParen)?;
882-
let distinct = self.parse_all_or_distinct()?;
882+
let distinct = self.parse_all_or_distinct()?.is_some();
883883
let args = self.parse_optional_args()?;
884884
let over = if self.parse_keyword(Keyword::OVER) {
885885
// TBD: support window names (`OVER mywin`) in place of inline specification
@@ -1302,7 +1302,7 @@ impl<'a> Parser<'a> {
13021302
/// Parse a SQL LISTAGG expression, e.g. `LISTAGG(...) WITHIN GROUP (ORDER BY ...)`.
13031303
pub fn parse_listagg_expr(&mut self) -> Result<Expr, ParserError> {
13041304
self.expect_token(&Token::LParen)?;
1305-
let distinct = self.parse_all_or_distinct()?;
1305+
let distinct = self.parse_all_or_distinct()?.is_some();
13061306
let expr = Box::new(self.parse_expr()?);
13071307
// While ANSI SQL would would require the separator, Redshift makes this optional. Here we
13081308
// choose to make the separator optional as this provides the more general implementation.
@@ -2300,16 +2300,31 @@ impl<'a> Parser<'a> {
23002300
}
23012301
}
23022302

2303-
/// Parse either `ALL` or `DISTINCT`. Returns `true` if `DISTINCT` is parsed and results in a
2304-
/// `ParserError` if both `ALL` and `DISTINCT` are fround.
2305-
pub fn parse_all_or_distinct(&mut self) -> Result<bool, ParserError> {
2303+
/// Parse either `ALL`, `DISTINCT` or `DISTINCT ON (...)`. Returns `None` if `ALL` is parsed
2304+
/// and results in a `ParserError` if both `ALL` and `DISTINCT` are found.
2305+
pub fn parse_all_or_distinct(&mut self) -> Result<Option<Distinct>, ParserError> {
23062306
let all = self.parse_keyword(Keyword::ALL);
23072307
let distinct = self.parse_keyword(Keyword::DISTINCT);
2308-
if all && distinct {
2309-
parser_err!("Cannot specify both ALL and DISTINCT".to_string())
2310-
} else {
2311-
Ok(distinct)
2308+
if !distinct {
2309+
return Ok(None);
23122310
}
2311+
if all {
2312+
return parser_err!("Cannot specify both ALL and DISTINCT".to_string());
2313+
}
2314+
let on = self.parse_keyword(Keyword::ON);
2315+
if !on {
2316+
return Ok(Some(Distinct::Distinct));
2317+
}
2318+
2319+
self.expect_token(&Token::LParen)?;
2320+
let col_names = if self.consume_token(&Token::RParen) {
2321+
self.prev_token();
2322+
Vec::new()
2323+
} else {
2324+
self.parse_comma_separated(Parser::parse_expr)?
2325+
};
2326+
self.expect_token(&Token::RParen)?;
2327+
Ok(Some(Distinct::On(col_names)))
23132328
}
23142329

23152330
/// Parse a SQL CREATE statement

tests/sqlparser_clickhouse.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn parse_map_access_expr() {
3232
let select = clickhouse().verified_only_select(sql);
3333
assert_eq!(
3434
Select {
35-
distinct: false,
35+
distinct: None,
3636
top: None,
3737
projection: vec![UnnamedExpr(MapAccess {
3838
column: Box::new(Identifier(Ident {

tests/sqlparser_common.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ fn parse_update_set_from() {
225225
subquery: Box::new(Query {
226226
with: None,
227227
body: Box::new(SetExpr::Select(Box::new(Select {
228-
distinct: false,
228+
distinct: None,
229229
top: None,
230230
projection: vec![
231231
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
@@ -597,7 +597,7 @@ fn parse_top_level() {
597597
fn parse_simple_select() {
598598
let sql = "SELECT id, fname, lname FROM customer WHERE id = 1 LIMIT 5";
599599
let select = verified_only_select(sql);
600-
assert!(!select.distinct);
600+
assert!(select.distinct.is_none());
601601
assert_eq!(3, select.projection.len());
602602
let select = verified_query(sql);
603603
assert_eq!(Some(Expr::Value(number("5"))), select.limit);
@@ -622,7 +622,7 @@ fn parse_limit_is_not_an_alias() {
622622
fn parse_select_distinct() {
623623
let sql = "SELECT DISTINCT name FROM customer";
624624
let select = verified_only_select(sql);
625-
assert!(select.distinct);
625+
assert!(select.distinct.is_some());
626626
assert_eq!(
627627
&SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
628628
only(&select.projection)
@@ -633,7 +633,7 @@ fn parse_select_distinct() {
633633
fn parse_select_distinct_two_fields() {
634634
let sql = "SELECT DISTINCT name, id FROM customer";
635635
let select = verified_only_select(sql);
636-
assert!(select.distinct);
636+
assert!(select.distinct.is_some());
637637
assert_eq!(
638638
&SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
639639
&select.projection[0]
@@ -657,6 +657,30 @@ fn parse_select_distinct_tuple() {
657657
);
658658
}
659659

660+
#[test]
661+
fn parse_select_distinct_on() {
662+
let sql = "SELECT DISTINCT ON (album_id) name FROM track ORDER BY album_id, milliseconds";
663+
let select = verified_only_select(sql);
664+
assert_eq!(
665+
&Some(Distinct::On(vec![Expr::Identifier(Ident::new("album_id"))])),
666+
&select.distinct
667+
);
668+
669+
let sql = "SELECT DISTINCT ON () name FROM track ORDER BY milliseconds";
670+
let select = verified_only_select(sql);
671+
assert_eq!(&Some(Distinct::On(vec![])), &select.distinct);
672+
673+
let sql = "SELECT DISTINCT ON (album_id, milliseconds) name FROM track";
674+
let select = verified_only_select(sql);
675+
assert_eq!(
676+
&Some(Distinct::On(vec![
677+
Expr::Identifier(Ident::new("album_id")),
678+
Expr::Identifier(Ident::new("milliseconds")),
679+
])),
680+
&select.distinct
681+
);
682+
}
683+
660684
#[test]
661685
fn parse_select_distinct_missing_paren() {
662686
let result = parse_sql_statements("SELECT DISTINCT (name, id FROM customer");
@@ -3517,7 +3541,7 @@ fn parse_interval_and_or_xor() {
35173541
let expected_ast = vec![Statement::Query(Box::new(Query {
35183542
with: None,
35193543
body: Box::new(SetExpr::Select(Box::new(Select {
3520-
distinct: false,
3544+
distinct: None,
35213545
top: None,
35223546
projection: vec![UnnamedExpr(Expr::Identifier(Ident {
35233547
value: "col".to_string(),
@@ -5834,7 +5858,7 @@ fn parse_merge() {
58345858
subquery: Box::new(Query {
58355859
with: None,
58365860
body: Box::new(SetExpr::Select(Box::new(Select {
5837-
distinct: false,
5861+
distinct: None,
58385862
top: None,
58395863
projection: vec![SelectItem::Wildcard(
58405864
WildcardAdditionalOptions::default()

tests/sqlparser_mysql.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ fn parse_quote_identifiers_2() {
445445
Statement::Query(Box::new(Query {
446446
with: None,
447447
body: Box::new(SetExpr::Select(Box::new(Select {
448-
distinct: false,
448+
distinct: None,
449449
top: None,
450450
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident {
451451
value: "quoted ` identifier".into(),
@@ -479,7 +479,7 @@ fn parse_quote_identifiers_3() {
479479
Statement::Query(Box::new(Query {
480480
with: None,
481481
body: Box::new(SetExpr::Select(Box::new(Select {
482-
distinct: false,
482+
distinct: None,
483483
top: None,
484484
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident {
485485
value: "`quoted identifier`".into(),
@@ -857,7 +857,7 @@ fn parse_select_with_numeric_prefix_column_name() {
857857
assert_eq!(
858858
q.body,
859859
Box::new(SetExpr::Select(Box::new(Select {
860-
distinct: false,
860+
distinct: None,
861861
top: None,
862862
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident::new(
863863
"123col_$@123abc"
@@ -896,7 +896,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
896896
assert_eq!(
897897
q.body,
898898
Box::new(SetExpr::Select(Box::new(Select {
899-
distinct: false,
899+
distinct: None,
900900
top: None,
901901
projection: vec![
902902
SelectItem::UnnamedExpr(Expr::Value(Value::Number(
@@ -1075,7 +1075,7 @@ fn parse_substring_in_select() {
10751075
Box::new(Query {
10761076
with: None,
10771077
body: Box::new(SetExpr::Select(Box::new(Select {
1078-
distinct: true,
1078+
distinct: Some(Distinct::Distinct),
10791079
top: None,
10801080
projection: vec![SelectItem::UnnamedExpr(Expr::Substring {
10811081
expr: Box::new(Expr::Identifier(Ident {
@@ -1372,7 +1372,7 @@ fn parse_hex_string_introducer() {
13721372
Statement::Query(Box::new(Query {
13731373
with: None,
13741374
body: Box::new(SetExpr::Select(Box::new(Select {
1375-
distinct: false,
1375+
distinct: None,
13761376
top: None,
13771377
projection: vec![SelectItem::UnnamedExpr(Expr::IntroducedString {
13781378
introducer: "_latin1".to_string(),

tests/sqlparser_postgres.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ fn parse_array_subquery_expr() {
16941694
op: SetOperator::Union,
16951695
set_quantifier: SetQuantifier::None,
16961696
left: Box::new(SetExpr::Select(Box::new(Select {
1697-
distinct: false,
1697+
distinct: None,
16981698
top: None,
16991699
projection: vec![SelectItem::UnnamedExpr(Expr::Value(Value::Number(
17001700
#[cfg(not(feature = "bigdecimal"))]
@@ -1715,7 +1715,7 @@ fn parse_array_subquery_expr() {
17151715
qualify: None,
17161716
}))),
17171717
right: Box::new(SetExpr::Select(Box::new(Select {
1718-
distinct: false,
1718+
distinct: None,
17191719
top: None,
17201720
projection: vec![SelectItem::UnnamedExpr(Expr::Value(Value::Number(
17211721
#[cfg(not(feature = "bigdecimal"))]

0 commit comments

Comments
 (0)