mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-09 13:40:22 +00:00
Fix parsing of equality binop in function argument (#1182)
This commit is contained in:
parent
e976a2ee43
commit
3bf40485c5
5 changed files with 64 additions and 18 deletions
|
@ -33,4 +33,8 @@ impl Dialect for DuckDbDialect {
|
|||
fn supports_group_by_expr(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,6 +143,10 @@ pub trait Dialect: Debug + Any {
|
|||
fn supports_start_transaction_modifier(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// Returns true if the dialect supports named arguments of the form FUN(a = '1', b = '2').
|
||||
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// Returns true if the dialect has a CONVERT function which accepts a type first
|
||||
/// and an expression second, e.g. `CONVERT(varchar, 1)`
|
||||
fn convert_type_before_value(&self) -> bool {
|
||||
|
|
|
@ -8631,7 +8631,9 @@ impl<'a> Parser<'a> {
|
|||
arg,
|
||||
operator: FunctionArgOperator::RightArrow,
|
||||
})
|
||||
} else if self.peek_nth_token(1) == Token::Eq {
|
||||
} else if self.dialect.supports_named_fn_args_with_eq_operator()
|
||||
&& self.peek_nth_token(1) == Token::Eq
|
||||
{
|
||||
let name = self.parse_identifier(false)?;
|
||||
|
||||
self.expect_token(&Token::Eq)?;
|
||||
|
|
|
@ -68,7 +68,7 @@ impl TestedDialects {
|
|||
}
|
||||
Some((dialect, parsed))
|
||||
})
|
||||
.unwrap()
|
||||
.expect("tested dialects cannot be empty")
|
||||
.1
|
||||
}
|
||||
|
||||
|
@ -195,15 +195,6 @@ impl TestedDialects {
|
|||
|
||||
/// Returns all available dialects.
|
||||
pub fn all_dialects() -> TestedDialects {
|
||||
all_dialects_except(|_| false)
|
||||
}
|
||||
|
||||
/// Returns available dialects. The `except` predicate is used
|
||||
/// to filter out specific dialects.
|
||||
pub fn all_dialects_except<F>(except: F) -> TestedDialects
|
||||
where
|
||||
F: Fn(&dyn Dialect) -> bool,
|
||||
{
|
||||
let all_dialects = vec![
|
||||
Box::new(GenericDialect {}) as Box<dyn Dialect>,
|
||||
Box::new(PostgreSqlDialect {}) as Box<dyn Dialect>,
|
||||
|
@ -218,14 +209,30 @@ where
|
|||
Box::new(DuckDbDialect {}) as Box<dyn Dialect>,
|
||||
];
|
||||
TestedDialects {
|
||||
dialects: all_dialects
|
||||
.into_iter()
|
||||
.filter(|d| !except(d.as_ref()))
|
||||
.collect(),
|
||||
dialects: all_dialects,
|
||||
options: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all dialects matching the given predicate.
|
||||
pub fn all_dialects_where<F>(predicate: F) -> TestedDialects
|
||||
where
|
||||
F: Fn(&dyn Dialect) -> bool,
|
||||
{
|
||||
let mut dialects = all_dialects();
|
||||
dialects.dialects.retain(|d| predicate(&**d));
|
||||
dialects
|
||||
}
|
||||
|
||||
/// Returns available dialects. The `except` predicate is used
|
||||
/// to filter out specific dialects.
|
||||
pub fn all_dialects_except<F>(except: F) -> TestedDialects
|
||||
where
|
||||
F: Fn(&dyn Dialect) -> bool,
|
||||
{
|
||||
all_dialects_where(|d| !except(d))
|
||||
}
|
||||
|
||||
pub fn assert_eq_vec<T: ToString>(expected: &[&str], actual: &[T]) {
|
||||
assert_eq!(
|
||||
expected,
|
||||
|
|
|
@ -33,8 +33,8 @@ use sqlparser::keywords::ALL_KEYWORDS;
|
|||
use sqlparser::parser::{Parser, ParserError, ParserOptions};
|
||||
use sqlparser::tokenizer::Tokenizer;
|
||||
use test_utils::{
|
||||
all_dialects, alter_table_op, assert_eq_vec, expr_from_projection, join, number, only, table,
|
||||
table_alias, TestedDialects,
|
||||
all_dialects, all_dialects_where, alter_table_op, assert_eq_vec, expr_from_projection, join,
|
||||
number, only, table, table_alias, TestedDialects,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
|
@ -4045,7 +4045,9 @@ fn parse_named_argument_function() {
|
|||
#[test]
|
||||
fn parse_named_argument_function_with_eq_operator() {
|
||||
let sql = "SELECT FUN(a = '1', b = '2') FROM foo";
|
||||
let select = verified_only_select(sql);
|
||||
|
||||
let select = all_dialects_where(|d| d.supports_named_fn_args_with_eq_operator())
|
||||
.verified_only_select(sql);
|
||||
assert_eq!(
|
||||
&Expr::Function(Function {
|
||||
name: ObjectName(vec![Ident::new("FUN")]),
|
||||
|
@ -4074,6 +4076,33 @@ fn parse_named_argument_function_with_eq_operator() {
|
|||
}),
|
||||
expr_from_projection(only(&select.projection))
|
||||
);
|
||||
|
||||
// Ensure that bar = 42 in a function argument parses as an equality binop
|
||||
// rather than a named function argument.
|
||||
assert_eq!(
|
||||
all_dialects_except(|d| d.supports_named_fn_args_with_eq_operator())
|
||||
.verified_expr("foo(bar = 42)"),
|
||||
Expr::Function(Function {
|
||||
name: ObjectName(vec![Ident::new("foo")]),
|
||||
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
|
||||
Expr::BinaryOp {
|
||||
left: Box::new(Expr::Identifier(Ident::new("bar"))),
|
||||
op: BinaryOperator::Eq,
|
||||
right: Box::new(Expr::Value(number("42"))),
|
||||
},
|
||||
))],
|
||||
filter: None,
|
||||
null_treatment: None,
|
||||
over: None,
|
||||
distinct: false,
|
||||
special: false,
|
||||
order_by: vec![],
|
||||
})
|
||||
);
|
||||
|
||||
// TODO: should this parse for all dialects?
|
||||
all_dialects_except(|d| d.supports_named_fn_args_with_eq_operator())
|
||||
.verified_expr("iff(1 = 1, 1, 0)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue