mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-04 05:00:34 +00:00
Add support for UNION DISTINCT BY NAME syntax (#997)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
c03586b727
commit
5c10668dbb
3 changed files with 89 additions and 152 deletions
|
@ -120,7 +120,8 @@ impl fmt::Display for SetExpr {
|
||||||
SetQuantifier::All
|
SetQuantifier::All
|
||||||
| SetQuantifier::Distinct
|
| SetQuantifier::Distinct
|
||||||
| SetQuantifier::ByName
|
| SetQuantifier::ByName
|
||||||
| SetQuantifier::AllByName => write!(f, " {set_quantifier}")?,
|
| SetQuantifier::AllByName
|
||||||
|
| SetQuantifier::DistinctByName => write!(f, " {set_quantifier}")?,
|
||||||
SetQuantifier::None => write!(f, "{set_quantifier}")?,
|
SetQuantifier::None => write!(f, "{set_quantifier}")?,
|
||||||
}
|
}
|
||||||
write!(f, " {right}")?;
|
write!(f, " {right}")?;
|
||||||
|
@ -160,6 +161,7 @@ pub enum SetQuantifier {
|
||||||
Distinct,
|
Distinct,
|
||||||
ByName,
|
ByName,
|
||||||
AllByName,
|
AllByName,
|
||||||
|
DistinctByName,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +172,7 @@ impl fmt::Display for SetQuantifier {
|
||||||
SetQuantifier::Distinct => write!(f, "DISTINCT"),
|
SetQuantifier::Distinct => write!(f, "DISTINCT"),
|
||||||
SetQuantifier::ByName => write!(f, "BY NAME"),
|
SetQuantifier::ByName => write!(f, "BY NAME"),
|
||||||
SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
|
SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
|
||||||
|
SetQuantifier::DistinctByName => write!(f, "DISTINCT BY NAME"),
|
||||||
SetQuantifier::None => write!(f, ""),
|
SetQuantifier::None => write!(f, ""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5696,7 +5696,9 @@ impl<'a> Parser<'a> {
|
||||||
pub fn parse_set_quantifier(&mut self, op: &Option<SetOperator>) -> SetQuantifier {
|
pub fn parse_set_quantifier(&mut self, op: &Option<SetOperator>) -> SetQuantifier {
|
||||||
match op {
|
match op {
|
||||||
Some(SetOperator::Union) => {
|
Some(SetOperator::Union) => {
|
||||||
if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) {
|
if self.parse_keywords(&[Keyword::DISTINCT, Keyword::BY, Keyword::NAME]) {
|
||||||
|
SetQuantifier::DistinctByName
|
||||||
|
} else if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) {
|
||||||
SetQuantifier::ByName
|
SetQuantifier::ByName
|
||||||
} else if self.parse_keyword(Keyword::ALL) {
|
} else if self.parse_keyword(Keyword::ALL) {
|
||||||
if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) {
|
if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) {
|
||||||
|
|
|
@ -132,155 +132,87 @@ fn test_create_table_macro() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_select_union_by_name() {
|
fn test_select_union_by_name() {
|
||||||
let ast = duckdb().verified_query("SELECT * FROM capitals UNION BY NAME SELECT * FROM weather");
|
let q1 = "SELECT * FROM capitals UNION BY NAME SELECT * FROM weather";
|
||||||
let expected = Box::<SetExpr>::new(SetExpr::SetOperation {
|
let q2 = "SELECT * FROM capitals UNION ALL BY NAME SELECT * FROM weather";
|
||||||
op: SetOperator::Union,
|
let q3 = "SELECT * FROM capitals UNION DISTINCT BY NAME SELECT * FROM weather";
|
||||||
set_quantifier: SetQuantifier::ByName,
|
|
||||||
left: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
|
||||||
distinct: None,
|
|
||||||
top: None,
|
|
||||||
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions {
|
|
||||||
opt_exclude: None,
|
|
||||||
opt_except: None,
|
|
||||||
opt_rename: None,
|
|
||||||
opt_replace: None,
|
|
||||||
})],
|
|
||||||
into: None,
|
|
||||||
from: vec![TableWithJoins {
|
|
||||||
relation: TableFactor::Table {
|
|
||||||
name: ObjectName(vec![Ident {
|
|
||||||
value: "capitals".to_string(),
|
|
||||||
quote_style: None,
|
|
||||||
}]),
|
|
||||||
alias: None,
|
|
||||||
args: None,
|
|
||||||
with_hints: vec![],
|
|
||||||
version: None,
|
|
||||||
partitions: vec![],
|
|
||||||
},
|
|
||||||
joins: vec![],
|
|
||||||
}],
|
|
||||||
lateral_views: vec![],
|
|
||||||
selection: None,
|
|
||||||
group_by: GroupByExpr::Expressions(vec![]),
|
|
||||||
cluster_by: vec![],
|
|
||||||
distribute_by: vec![],
|
|
||||||
sort_by: vec![],
|
|
||||||
having: None,
|
|
||||||
named_window: vec![],
|
|
||||||
qualify: None,
|
|
||||||
}))),
|
|
||||||
right: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
|
||||||
distinct: None,
|
|
||||||
top: None,
|
|
||||||
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions {
|
|
||||||
opt_exclude: None,
|
|
||||||
opt_except: None,
|
|
||||||
opt_rename: None,
|
|
||||||
opt_replace: None,
|
|
||||||
})],
|
|
||||||
into: None,
|
|
||||||
from: vec![TableWithJoins {
|
|
||||||
relation: TableFactor::Table {
|
|
||||||
name: ObjectName(vec![Ident {
|
|
||||||
value: "weather".to_string(),
|
|
||||||
quote_style: None,
|
|
||||||
}]),
|
|
||||||
alias: None,
|
|
||||||
args: None,
|
|
||||||
with_hints: vec![],
|
|
||||||
version: None,
|
|
||||||
partitions: vec![],
|
|
||||||
},
|
|
||||||
joins: vec![],
|
|
||||||
}],
|
|
||||||
lateral_views: vec![],
|
|
||||||
selection: None,
|
|
||||||
group_by: GroupByExpr::Expressions(vec![]),
|
|
||||||
cluster_by: vec![],
|
|
||||||
distribute_by: vec![],
|
|
||||||
sort_by: vec![],
|
|
||||||
having: None,
|
|
||||||
named_window: vec![],
|
|
||||||
qualify: None,
|
|
||||||
}))),
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(ast.body, expected);
|
for (ast, expected_quantifier) in &[
|
||||||
|
(duckdb().verified_query(q1), SetQuantifier::ByName),
|
||||||
let ast =
|
(duckdb().verified_query(q2), SetQuantifier::AllByName),
|
||||||
duckdb().verified_query("SELECT * FROM capitals UNION ALL BY NAME SELECT * FROM weather");
|
(duckdb().verified_query(q3), SetQuantifier::DistinctByName),
|
||||||
let expected = Box::<SetExpr>::new(SetExpr::SetOperation {
|
] {
|
||||||
op: SetOperator::Union,
|
let expected = Box::<SetExpr>::new(SetExpr::SetOperation {
|
||||||
set_quantifier: SetQuantifier::AllByName,
|
op: SetOperator::Union,
|
||||||
left: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
set_quantifier: *expected_quantifier,
|
||||||
distinct: None,
|
left: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
||||||
top: None,
|
distinct: None,
|
||||||
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions {
|
top: None,
|
||||||
opt_exclude: None,
|
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions {
|
||||||
opt_except: None,
|
opt_exclude: None,
|
||||||
opt_rename: None,
|
opt_except: None,
|
||||||
opt_replace: None,
|
opt_rename: None,
|
||||||
})],
|
opt_replace: None,
|
||||||
into: None,
|
})],
|
||||||
from: vec![TableWithJoins {
|
into: None,
|
||||||
relation: TableFactor::Table {
|
from: vec![TableWithJoins {
|
||||||
name: ObjectName(vec![Ident {
|
relation: TableFactor::Table {
|
||||||
value: "capitals".to_string(),
|
name: ObjectName(vec![Ident {
|
||||||
quote_style: None,
|
value: "capitals".to_string(),
|
||||||
}]),
|
quote_style: None,
|
||||||
alias: None,
|
}]),
|
||||||
args: None,
|
alias: None,
|
||||||
with_hints: vec![],
|
args: None,
|
||||||
version: None,
|
with_hints: vec![],
|
||||||
partitions: vec![],
|
version: None,
|
||||||
},
|
partitions: vec![],
|
||||||
joins: vec![],
|
},
|
||||||
}],
|
joins: vec![],
|
||||||
lateral_views: vec![],
|
}],
|
||||||
selection: None,
|
lateral_views: vec![],
|
||||||
group_by: GroupByExpr::Expressions(vec![]),
|
selection: None,
|
||||||
cluster_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
distribute_by: vec![],
|
cluster_by: vec![],
|
||||||
sort_by: vec![],
|
distribute_by: vec![],
|
||||||
having: None,
|
sort_by: vec![],
|
||||||
named_window: vec![],
|
having: None,
|
||||||
qualify: None,
|
named_window: vec![],
|
||||||
}))),
|
qualify: None,
|
||||||
right: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
}))),
|
||||||
distinct: None,
|
right: Box::<SetExpr>::new(SetExpr::Select(Box::new(Select {
|
||||||
top: None,
|
distinct: None,
|
||||||
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions {
|
top: None,
|
||||||
opt_exclude: None,
|
projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions {
|
||||||
opt_except: None,
|
opt_exclude: None,
|
||||||
opt_rename: None,
|
opt_except: None,
|
||||||
opt_replace: None,
|
opt_rename: None,
|
||||||
})],
|
opt_replace: None,
|
||||||
into: None,
|
})],
|
||||||
from: vec![TableWithJoins {
|
into: None,
|
||||||
relation: TableFactor::Table {
|
from: vec![TableWithJoins {
|
||||||
name: ObjectName(vec![Ident {
|
relation: TableFactor::Table {
|
||||||
value: "weather".to_string(),
|
name: ObjectName(vec![Ident {
|
||||||
quote_style: None,
|
value: "weather".to_string(),
|
||||||
}]),
|
quote_style: None,
|
||||||
alias: None,
|
}]),
|
||||||
args: None,
|
alias: None,
|
||||||
with_hints: vec![],
|
args: None,
|
||||||
version: None,
|
with_hints: vec![],
|
||||||
partitions: vec![],
|
version: None,
|
||||||
},
|
partitions: vec![],
|
||||||
joins: vec![],
|
},
|
||||||
}],
|
joins: vec![],
|
||||||
lateral_views: vec![],
|
}],
|
||||||
selection: None,
|
lateral_views: vec![],
|
||||||
group_by: GroupByExpr::Expressions(vec![]),
|
selection: None,
|
||||||
cluster_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
distribute_by: vec![],
|
cluster_by: vec![],
|
||||||
sort_by: vec![],
|
distribute_by: vec![],
|
||||||
having: None,
|
sort_by: vec![],
|
||||||
named_window: vec![],
|
having: None,
|
||||||
qualify: None,
|
named_window: vec![],
|
||||||
}))),
|
qualify: None,
|
||||||
});
|
}))),
|
||||||
assert_eq!(ast.body, expected);
|
});
|
||||||
|
assert_eq!(ast.body, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue