Support UNION (ALL) BY NAME syntax (#915)

This commit is contained in:
parkma99 2023-07-19 05:15:05 +08:00 committed by GitHub
parent c45451850c
commit eb288487a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 164 additions and 3 deletions

View file

@ -110,7 +110,10 @@ impl fmt::Display for SetExpr {
} => { } => {
write!(f, "{left} {op}")?; write!(f, "{left} {op}")?;
match set_quantifier { match set_quantifier {
SetQuantifier::All | SetQuantifier::Distinct => write!(f, " {set_quantifier}")?, SetQuantifier::All
| SetQuantifier::Distinct
| SetQuantifier::ByName
| SetQuantifier::AllByName => write!(f, " {set_quantifier}")?,
SetQuantifier::None => write!(f, "{set_quantifier}")?, SetQuantifier::None => write!(f, "{set_quantifier}")?,
} }
write!(f, " {right}")?; write!(f, " {right}")?;
@ -148,6 +151,8 @@ impl fmt::Display for SetOperator {
pub enum SetQuantifier { pub enum SetQuantifier {
All, All,
Distinct, Distinct,
ByName,
AllByName,
None, None,
} }
@ -156,6 +161,8 @@ impl fmt::Display for SetQuantifier {
match self { match self {
SetQuantifier::All => write!(f, "ALL"), SetQuantifier::All => write!(f, "ALL"),
SetQuantifier::Distinct => write!(f, "DISTINCT"), SetQuantifier::Distinct => write!(f, "DISTINCT"),
SetQuantifier::ByName => write!(f, "BY NAME"),
SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
SetQuantifier::None => write!(f, ""), SetQuantifier::None => write!(f, ""),
} }
} }

View file

@ -384,6 +384,7 @@ define_keywords!(
MSCK, MSCK,
MULTISET, MULTISET,
MUTATION, MUTATION,
NAME,
NANOSECOND, NANOSECOND,
NANOSECONDS, NANOSECONDS,
NATIONAL, NATIONAL,

View file

@ -5331,8 +5331,14 @@ 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_keyword(Keyword::ALL) { if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) {
SetQuantifier::All SetQuantifier::ByName
} else if self.parse_keyword(Keyword::ALL) {
if self.parse_keywords(&[Keyword::BY, Keyword::NAME]) {
SetQuantifier::AllByName
} else {
SetQuantifier::All
}
} else if self.parse_keyword(Keyword::DISTINCT) { } else if self.parse_keyword(Keyword::DISTINCT) {
SetQuantifier::Distinct SetQuantifier::Distinct
} else { } else {

View file

@ -129,3 +129,150 @@ fn test_create_table_macro() {
}; };
assert_eq!(expected, macro_); assert_eq!(expected, macro_);
} }
#[test]
fn test_select_union_by_name() {
let ast = duckdb().verified_query("SELECT * FROM capitals UNION BY NAME SELECT * FROM weather");
let expected = Box::<SetExpr>::new(SetExpr::SetOperation {
op: SetOperator::Union,
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![],
},
joins: vec![],
}],
lateral_views: vec![],
selection: None,
group_by: 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![],
},
joins: vec![],
}],
lateral_views: vec![],
selection: None,
group_by: vec![],
cluster_by: vec![],
distribute_by: vec![],
sort_by: vec![],
having: None,
named_window: vec![],
qualify: None,
}))),
});
assert_eq!(ast.body, expected);
let ast =
duckdb().verified_query("SELECT * FROM capitals UNION ALL BY NAME SELECT * FROM weather");
let expected = Box::<SetExpr>::new(SetExpr::SetOperation {
op: SetOperator::Union,
set_quantifier: SetQuantifier::AllByName,
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![],
},
joins: vec![],
}],
lateral_views: vec![],
selection: None,
group_by: 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![],
},
joins: vec![],
}],
lateral_views: vec![],
selection: None,
group_by: vec![],
cluster_by: vec![],
distribute_by: vec![],
sort_by: vec![],
having: None,
named_window: vec![],
qualify: None,
}))),
});
assert_eq!(ast.body, expected);
}