Skip to content

Commit ecc0125

Browse files
committed
feat: Support explicit DISTINCT option with UNION
Signed-off-by: Alex Qyoun-ae <[email protected]>
1 parent 34f22de commit ecc0125

File tree

5 files changed

+39
-8
lines changed

5 files changed

+39
-8
lines changed

src/ast/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ pub use self::ddl::{
3737
pub use self::operator::{BinaryOperator, UnaryOperator};
3838
pub use self::query::{
3939
Cte, Fetch, Join, JoinConstraint, JoinOperator, LateralView, LockType, Offset, OffsetRows,
40-
OrderByExpr, Query, Select, SelectInto, SelectItem, SetExpr, SetOperator, TableAlias,
41-
TableFactor, TableWithJoins, Top, Values, With,
40+
OrderByExpr, Query, Select, SelectInto, SelectItem, SetExpr, SetOperator, SetOperatorOption,
41+
TableAlias, TableFactor, TableWithJoins, Top, Values, With,
4242
};
4343
pub use self::value::{escape_single_quote_string, DateTimeField, TrimWhereField, Value};
4444

src/ast/query.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub enum SetExpr {
7878
/// UNION/EXCEPT/INTERSECT of two queries
7979
SetOperation {
8080
op: SetOperator,
81-
all: bool,
81+
option: Option<SetOperatorOption>,
8282
left: Box<SetExpr>,
8383
right: Box<SetExpr>,
8484
},
@@ -98,10 +98,13 @@ impl fmt::Display for SetExpr {
9898
left,
9999
right,
100100
op,
101-
all,
101+
option,
102102
} => {
103-
let all_str = if *all { " ALL" } else { "" };
104-
write!(f, "{} {}{} {}", left, op, all_str, right)
103+
let option_str = option
104+
.as_ref()
105+
.map(|option| format!(" {}", option))
106+
.unwrap_or_else(|| "".to_string());
107+
write!(f, "{} {}{} {}", left, op, option_str, right)
105108
}
106109
}
107110
}
@@ -125,6 +128,22 @@ impl fmt::Display for SetOperator {
125128
}
126129
}
127130

131+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
132+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133+
pub enum SetOperatorOption {
134+
All,
135+
Distinct,
136+
}
137+
138+
impl fmt::Display for SetOperatorOption {
139+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140+
f.write_str(match self {
141+
SetOperatorOption::All => "ALL",
142+
SetOperatorOption::Distinct => "DISTINCT",
143+
})
144+
}
145+
}
146+
128147
/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
129148
/// appear either as the only body item of a `Query`, or as an operand
130149
/// to a set operation like `UNION`.

src/parser.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3473,10 +3473,11 @@ impl<'a> Parser<'a> {
34733473
break;
34743474
}
34753475
self.next_token(); // skip past the set operator
3476+
let option = self.parse_set_operator_option();
34763477
expr = SetExpr::SetOperation {
34773478
left: Box::new(expr),
34783479
op: op.unwrap(),
3479-
all: self.parse_keyword(Keyword::ALL),
3480+
option,
34803481
right: Box::new(self.parse_query_body(next_precedence)?),
34813482
};
34823483
}
@@ -3493,6 +3494,16 @@ impl<'a> Parser<'a> {
34933494
}
34943495
}
34953496

3497+
pub fn parse_set_operator_option(&mut self) -> Option<SetOperatorOption> {
3498+
if self.parse_keyword(Keyword::ALL) {
3499+
return Some(SetOperatorOption::All);
3500+
}
3501+
if self.parse_keyword(Keyword::DISTINCT) {
3502+
return Some(SetOperatorOption::Distinct);
3503+
}
3504+
None
3505+
}
3506+
34963507
/// Parse a restricted `SELECT` statement (no CTEs / `UNION` / `ORDER BY`),
34973508
/// assuming the initial `SELECT` was already consumed
34983509
pub fn parse_select(&mut self) -> Result<Select, ParserError> {

tests/sqlparser_common.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,6 +3658,7 @@ fn parse_union() {
36583658
// TODO: add assertions
36593659
verified_stmt("SELECT 1 UNION SELECT 2");
36603660
verified_stmt("SELECT 1 UNION ALL SELECT 2");
3661+
verified_stmt("SELECT 1 UNION DISTINCT SELECT 2");
36613662
verified_stmt("SELECT 1 EXCEPT SELECT 2");
36623663
verified_stmt("SELECT 1 EXCEPT ALL SELECT 2");
36633664
verified_stmt("SELECT 1 INTERSECT SELECT 2");

tests/sqlparser_postgres.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ fn parse_array_subquery_expr() {
12721272
with: None,
12731273
body: SetExpr::SetOperation {
12741274
op: SetOperator::Union,
1275-
all: false,
1275+
option: None,
12761276
left: Box::new(SetExpr::Select(Box::new(Select {
12771277
distinct: false,
12781278
top: None,

0 commit comments

Comments
 (0)