Add FunctionArgExpr and remove Expr::[Qualified]Wildcard, (#378)

* Add FunctionArgExpr and remove Expr::[Qualified]Wildcard,

There is no use case of `Expr::Wildcard` and `Expr::QualifiedWildcard` only except for function argments.
Add `FunctionArgExpr` to have `Wildcard` and `QualifiedWildcard`, and remove wildcards in `Expr`.

* Apply `FunctionArgExpr` to sqlparser_mysql tests
This commit is contained in:
Taehoon Moon 2021-12-15 20:35:37 +09:00 committed by GitHub
parent 4c121a92a6
commit 823635d2fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 61 deletions

View file

@ -157,16 +157,6 @@ impl fmt::Display for ObjectName {
pub enum Expr { pub enum Expr {
/// Identifier e.g. table name or column name /// Identifier e.g. table name or column name
Identifier(Ident), Identifier(Ident),
/// Unqualified wildcard (`*`). SQL allows this in limited contexts, such as:
/// - right after `SELECT` (which is represented as a [SelectItem::Wildcard] instead)
/// - or as part of an aggregate function, e.g. `COUNT(*)`,
///
/// ...but we currently also accept it in contexts where it doesn't make
/// sense, such as `* + *`
Wildcard,
/// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
/// (Same caveats apply to `QualifiedWildcard` as to `Wildcard`.)
QualifiedWildcard(Vec<Ident>),
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col` /// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
CompoundIdentifier(Vec<Ident>), CompoundIdentifier(Vec<Ident>),
/// `IS NULL` operator /// `IS NULL` operator
@ -301,8 +291,6 @@ impl fmt::Display for Expr {
} }
Ok(()) Ok(())
} }
Expr::Wildcard => f.write_str("*"),
Expr::QualifiedWildcard(q) => write!(f, "{}.*", display_separated(q, ".")),
Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")), Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
Expr::IsNull(ast) => write!(f, "{} IS NULL", ast), Expr::IsNull(ast) => write!(f, "{} IS NULL", ast),
Expr::IsNotNull(ast) => write!(f, "{} IS NOT NULL", ast), Expr::IsNotNull(ast) => write!(f, "{} IS NOT NULL", ast),
@ -1640,11 +1628,31 @@ impl fmt::Display for Assignment {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum FunctionArgExpr {
Expr(Expr),
/// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
QualifiedWildcard(ObjectName),
/// An unqualified `*`
Wildcard,
}
impl fmt::Display for FunctionArgExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FunctionArgExpr::Expr(expr) => write!(f, "{}", expr),
FunctionArgExpr::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix),
FunctionArgExpr::Wildcard => f.write_str("*"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum FunctionArg { pub enum FunctionArg {
Named { name: Ident, arg: Expr }, Named { name: Ident, arg: FunctionArgExpr },
Unnamed(Expr), Unnamed(FunctionArgExpr),
} }
impl fmt::Display for FunctionArg { impl fmt::Display for FunctionArg {

View file

@ -66,6 +66,22 @@ pub enum IsLateral {
use IsLateral::*; use IsLateral::*;
pub enum WildcardExpr {
Expr(Expr),
QualifiedWildcard(ObjectName),
Wildcard,
}
impl From<WildcardExpr> for FunctionArgExpr {
fn from(wildcard_expr: WildcardExpr) -> Self {
match wildcard_expr {
WildcardExpr::Expr(expr) => Self::Expr(expr),
WildcardExpr::QualifiedWildcard(prefix) => Self::QualifiedWildcard(prefix),
WildcardExpr::Wildcard => Self::Wildcard,
}
}
}
impl From<TokenizerError> for ParserError { impl From<TokenizerError> for ParserError {
fn from(e: TokenizerError) -> Self { fn from(e: TokenizerError) -> Self {
ParserError::TokenizerError(e.to_string()) ParserError::TokenizerError(e.to_string())
@ -283,6 +299,36 @@ impl<'a> Parser<'a> {
}) })
} }
/// Parse a new expression including wildcard & qualified wildcard
pub fn parse_wildcard_expr(&mut self) -> Result<WildcardExpr, ParserError> {
let index = self.index;
match self.next_token() {
Token::Word(w) if self.peek_token() == Token::Period => {
let mut id_parts: Vec<Ident> = vec![w.to_ident()];
while self.consume_token(&Token::Period) {
match self.next_token() {
Token::Word(w) => id_parts.push(w.to_ident()),
Token::Mul => {
return Ok(WildcardExpr::QualifiedWildcard(ObjectName(id_parts)));
}
unexpected => {
return self.expected("an identifier or a '*' after '.'", unexpected);
}
}
}
}
Token::Mul => {
return Ok(WildcardExpr::Wildcard);
}
_ => (),
};
self.index = index;
self.parse_expr().map(WildcardExpr::Expr)
}
/// Parse a new expression /// Parse a new expression
pub fn parse_expr(&mut self) -> Result<Expr, ParserError> { pub fn parse_expr(&mut self) -> Result<Expr, ParserError> {
self.parse_subexpr(0) self.parse_subexpr(0)
@ -377,23 +423,17 @@ impl<'a> Parser<'a> {
_ => match self.peek_token() { _ => match self.peek_token() {
Token::LParen | Token::Period => { Token::LParen | Token::Period => {
let mut id_parts: Vec<Ident> = vec![w.to_ident()]; let mut id_parts: Vec<Ident> = vec![w.to_ident()];
let mut ends_with_wildcard = false;
while self.consume_token(&Token::Period) { while self.consume_token(&Token::Period) {
match self.next_token() { match self.next_token() {
Token::Word(w) => id_parts.push(w.to_ident()), Token::Word(w) => id_parts.push(w.to_ident()),
Token::Mul => {
ends_with_wildcard = true;
break;
}
unexpected => { unexpected => {
return self return self
.expected("an identifier or a '*' after '.'", unexpected); .expected("an identifier or a '*' after '.'", unexpected);
} }
} }
} }
if ends_with_wildcard {
Ok(Expr::QualifiedWildcard(id_parts)) if self.consume_token(&Token::LParen) {
} else if self.consume_token(&Token::LParen) {
self.prev_token(); self.prev_token();
self.parse_function(ObjectName(id_parts)) self.parse_function(ObjectName(id_parts))
} else { } else {
@ -403,7 +443,6 @@ impl<'a> Parser<'a> {
_ => Ok(Expr::Identifier(w.to_ident())), _ => Ok(Expr::Identifier(w.to_ident())),
}, },
}, // End of Token::Word }, // End of Token::Word
Token::Mul => Ok(Expr::Wildcard),
tok @ Token::Minus | tok @ Token::Plus => { tok @ Token::Minus | tok @ Token::Plus => {
let op = if tok == Token::Plus { let op = if tok == Token::Plus {
UnaryOperator::Plus UnaryOperator::Plus
@ -3259,11 +3298,11 @@ impl<'a> Parser<'a> {
let name = self.parse_identifier()?; let name = self.parse_identifier()?;
self.expect_token(&Token::RArrow)?; self.expect_token(&Token::RArrow)?;
let arg = self.parse_expr()?; let arg = self.parse_wildcard_expr()?.into();
Ok(FunctionArg::Named { name, arg }) Ok(FunctionArg::Named { name, arg })
} else { } else {
Ok(FunctionArg::Unnamed(self.parse_expr()?)) Ok(FunctionArg::Unnamed(self.parse_wildcard_expr()?.into()))
} }
} }
@ -3279,18 +3318,15 @@ impl<'a> Parser<'a> {
/// Parse a comma-delimited list of projections after SELECT /// Parse a comma-delimited list of projections after SELECT
pub fn parse_select_item(&mut self) -> Result<SelectItem, ParserError> { pub fn parse_select_item(&mut self) -> Result<SelectItem, ParserError> {
let expr = self.parse_expr()?; match self.parse_wildcard_expr()? {
if let Expr::Wildcard = expr { WildcardExpr::Expr(expr) => self
Ok(SelectItem::Wildcard) .parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)
} else if let Expr::QualifiedWildcard(prefix) = expr { .map(|alias| match alias {
Ok(SelectItem::QualifiedWildcard(ObjectName(prefix))) Some(alias) => SelectItem::ExprWithAlias { expr, alias },
} else { None => SelectItem::UnnamedExpr(expr),
// `expr` is a regular SQL expression and can be followed by an alias }),
if let Some(alias) = self.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)? { WildcardExpr::QualifiedWildcard(prefix) => Ok(SelectItem::QualifiedWildcard(prefix)),
Ok(SelectItem::ExprWithAlias { expr, alias }) WildcardExpr::Wildcard => Ok(SelectItem::Wildcard),
} else {
Ok(SelectItem::UnnamedExpr(expr))
}
} }
} }

View file

@ -363,10 +363,19 @@ fn parse_select_wildcard() {
])), ])),
only(&select.projection) only(&select.projection)
); );
let sql = "SELECT * + * FROM foo;";
let result = parse_sql_statements(sql);
assert_eq!(
ParserError::ParserError("Expected end of statement, found: +".to_string()),
result.unwrap_err(),
);
} }
#[test] #[test]
fn parse_count_wildcard() { fn parse_count_wildcard() {
verified_only_select("SELECT COUNT(*) FROM Order WHERE id = 10");
verified_only_select( verified_only_select(
"SELECT COUNT(Employee.*) FROM Order JOIN Employee ON Order.employee = Employee.id", "SELECT COUNT(Employee.*) FROM Order JOIN Employee ON Order.employee = Employee.id",
); );
@ -425,7 +434,7 @@ fn parse_select_count_wildcard() {
assert_eq!( assert_eq!(
&Expr::Function(Function { &Expr::Function(Function {
name: ObjectName(vec![Ident::new("COUNT")]), name: ObjectName(vec![Ident::new("COUNT")]),
args: vec![FunctionArg::Unnamed(Expr::Wildcard)], args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)],
over: None, over: None,
distinct: false, distinct: false,
}), }),
@ -440,10 +449,10 @@ fn parse_select_count_distinct() {
assert_eq!( assert_eq!(
&Expr::Function(Function { &Expr::Function(Function {
name: ObjectName(vec![Ident::new("COUNT")]), name: ObjectName(vec![Ident::new("COUNT")]),
args: vec![FunctionArg::Unnamed(Expr::UnaryOp { args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::UnaryOp {
op: UnaryOperator::Plus, op: UnaryOperator::Plus,
expr: Box::new(Expr::Identifier(Ident::new("x"))), expr: Box::new(Expr::Identifier(Ident::new("x"))),
})], }))],
over: None, over: None,
distinct: true, distinct: true,
}), }),
@ -1156,7 +1165,7 @@ fn parse_select_having() {
Some(Expr::BinaryOp { Some(Expr::BinaryOp {
left: Box::new(Expr::Function(Function { left: Box::new(Expr::Function(Function {
name: ObjectName(vec![Ident::new("COUNT")]), name: ObjectName(vec![Ident::new("COUNT")]),
args: vec![FunctionArg::Unnamed(Expr::Wildcard)], args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)],
over: None, over: None,
distinct: false, distinct: false,
})), })),
@ -1965,7 +1974,9 @@ fn parse_scalar_function_in_projection() {
assert_eq!( assert_eq!(
&Expr::Function(Function { &Expr::Function(Function {
name: ObjectName(vec![Ident::new("sqrt")]), name: ObjectName(vec![Ident::new("sqrt")]),
args: vec![FunctionArg::Unnamed(Expr::Identifier(Ident::new("id")))], args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("id"))
))],
over: None, over: None,
distinct: false, distinct: false,
}), }),
@ -2032,11 +2043,15 @@ fn parse_named_argument_function() {
args: vec![ args: vec![
FunctionArg::Named { FunctionArg::Named {
name: Ident::new("a"), name: Ident::new("a"),
arg: Expr::Value(Value::SingleQuotedString("1".to_owned())) arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"1".to_owned()
))),
}, },
FunctionArg::Named { FunctionArg::Named {
name: Ident::new("b"), name: Ident::new("b"),
arg: Expr::Value(Value::SingleQuotedString("2".to_owned())) arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"2".to_owned()
))),
}, },
], ],
over: None, over: None,
@ -2296,9 +2311,9 @@ fn parse_table_function() {
TableFactor::TableFunction { expr, alias } => { TableFactor::TableFunction { expr, alias } => {
let expected_expr = Expr::Function(Function { let expected_expr = Expr::Function(Function {
name: ObjectName(vec![Ident::new("FUN")]), name: ObjectName(vec![Ident::new("FUN")]),
args: vec![FunctionArg::Unnamed(Expr::Value( args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("1".to_owned()), Value::SingleQuotedString("1".to_owned()),
))], )))],
over: None, over: None,
distinct: false, distinct: false,
}); });

View file

@ -314,9 +314,9 @@ fn parse_insert_with_on_duplicate_update() {
id: vec![Ident::new("description".to_string())], id: vec![Ident::new("description".to_string())],
value: Expr::Function(Function { value: Expr::Function(Function {
name: ObjectName(vec![Ident::new("VALUES".to_string()),]), name: ObjectName(vec![Ident::new("VALUES".to_string()),]),
args: vec![FunctionArg::Unnamed(Expr::Identifier(Ident::new( args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
"description" Expr::Identifier(Ident::new("description"))
)))], ))],
over: None, over: None,
distinct: false distinct: false
}) })
@ -325,9 +325,9 @@ fn parse_insert_with_on_duplicate_update() {
id: vec![Ident::new("perm_create".to_string())], id: vec![Ident::new("perm_create".to_string())],
value: Expr::Function(Function { value: Expr::Function(Function {
name: ObjectName(vec![Ident::new("VALUES".to_string()),]), name: ObjectName(vec![Ident::new("VALUES".to_string()),]),
args: vec![FunctionArg::Unnamed(Expr::Identifier(Ident::new( args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
"perm_create" Expr::Identifier(Ident::new("perm_create"))
)))], ))],
over: None, over: None,
distinct: false distinct: false
}) })
@ -336,9 +336,9 @@ fn parse_insert_with_on_duplicate_update() {
id: vec![Ident::new("perm_read".to_string())], id: vec![Ident::new("perm_read".to_string())],
value: Expr::Function(Function { value: Expr::Function(Function {
name: ObjectName(vec![Ident::new("VALUES".to_string()),]), name: ObjectName(vec![Ident::new("VALUES".to_string()),]),
args: vec![FunctionArg::Unnamed(Expr::Identifier(Ident::new( args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
"perm_read" Expr::Identifier(Ident::new("perm_read"))
)))], ))],
over: None, over: None,
distinct: false distinct: false
}) })
@ -347,9 +347,9 @@ fn parse_insert_with_on_duplicate_update() {
id: vec![Ident::new("perm_update".to_string())], id: vec![Ident::new("perm_update".to_string())],
value: Expr::Function(Function { value: Expr::Function(Function {
name: ObjectName(vec![Ident::new("VALUES".to_string()),]), name: ObjectName(vec![Ident::new("VALUES".to_string()),]),
args: vec![FunctionArg::Unnamed(Expr::Identifier(Ident::new( args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
"perm_update" Expr::Identifier(Ident::new("perm_update"))
)))], ))],
over: None, over: None,
distinct: false distinct: false
}) })
@ -358,9 +358,9 @@ fn parse_insert_with_on_duplicate_update() {
id: vec![Ident::new("perm_delete".to_string())], id: vec![Ident::new("perm_delete".to_string())],
value: Expr::Function(Function { value: Expr::Function(Function {
name: ObjectName(vec![Ident::new("VALUES".to_string()),]), name: ObjectName(vec![Ident::new("VALUES".to_string()),]),
args: vec![FunctionArg::Unnamed(Expr::Identifier(Ident::new( args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
"perm_delete" Expr::Identifier(Ident::new("perm_delete"))
)))], ))],
over: None, over: None,
distinct: false distinct: false
}) })