mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-26 15:39:12 +00:00
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:
parent
4c121a92a6
commit
823635d2fc
4 changed files with 120 additions and 61 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue