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 {
/// Identifier e.g. table name or column name
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`
CompoundIdentifier(Vec<Ident>),
/// `IS NULL` operator
@ -301,8 +291,6 @@ impl fmt::Display for Expr {
}
Ok(())
}
Expr::Wildcard => f.write_str("*"),
Expr::QualifiedWildcard(q) => write!(f, "{}.*", display_separated(q, ".")),
Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
Expr::IsNull(ast) => write!(f, "{} IS 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)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum FunctionArg {
Named { name: Ident, arg: Expr },
Unnamed(Expr),
Named { name: Ident, arg: FunctionArgExpr },
Unnamed(FunctionArgExpr),
}
impl fmt::Display for FunctionArg {

View file

@ -66,6 +66,22 @@ pub enum 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 {
fn from(e: TokenizerError) -> Self {
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
pub fn parse_expr(&mut self) -> Result<Expr, ParserError> {
self.parse_subexpr(0)
@ -377,23 +423,17 @@ impl<'a> Parser<'a> {
_ => match self.peek_token() {
Token::LParen | Token::Period => {
let mut id_parts: Vec<Ident> = vec![w.to_ident()];
let mut ends_with_wildcard = false;
while self.consume_token(&Token::Period) {
match self.next_token() {
Token::Word(w) => id_parts.push(w.to_ident()),
Token::Mul => {
ends_with_wildcard = true;
break;
}
unexpected => {
return self
.expected("an identifier or a '*' after '.'", unexpected);
}
}
}
if ends_with_wildcard {
Ok(Expr::QualifiedWildcard(id_parts))
} else if self.consume_token(&Token::LParen) {
if self.consume_token(&Token::LParen) {
self.prev_token();
self.parse_function(ObjectName(id_parts))
} else {
@ -403,7 +443,6 @@ impl<'a> Parser<'a> {
_ => Ok(Expr::Identifier(w.to_ident())),
},
}, // End of Token::Word
Token::Mul => Ok(Expr::Wildcard),
tok @ Token::Minus | tok @ Token::Plus => {
let op = if tok == Token::Plus {
UnaryOperator::Plus
@ -3259,11 +3298,11 @@ impl<'a> Parser<'a> {
let name = self.parse_identifier()?;
self.expect_token(&Token::RArrow)?;
let arg = self.parse_expr()?;
let arg = self.parse_wildcard_expr()?.into();
Ok(FunctionArg::Named { name, arg })
} 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
pub fn parse_select_item(&mut self) -> Result<SelectItem, ParserError> {
let expr = self.parse_expr()?;
if let Expr::Wildcard = expr {
Ok(SelectItem::Wildcard)
} else if let Expr::QualifiedWildcard(prefix) = expr {
Ok(SelectItem::QualifiedWildcard(ObjectName(prefix)))
} else {
// `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)? {
Ok(SelectItem::ExprWithAlias { expr, alias })
} else {
Ok(SelectItem::UnnamedExpr(expr))
}
match self.parse_wildcard_expr()? {
WildcardExpr::Expr(expr) => self
.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)
.map(|alias| match alias {
Some(alias) => SelectItem::ExprWithAlias { expr, alias },
None => SelectItem::UnnamedExpr(expr),
}),
WildcardExpr::QualifiedWildcard(prefix) => Ok(SelectItem::QualifiedWildcard(prefix)),
WildcardExpr::Wildcard => Ok(SelectItem::Wildcard),
}
}

View file

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

View file

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