Skip to content

Commit a13f8c6

Browse files
authored
Add support for ODBC functions (#1585)
1 parent 04271b0 commit a13f8c6

15 files changed

+142
-6
lines changed

src/ast/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -5523,6 +5523,15 @@ impl fmt::Display for CloseCursor {
55235523
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
55245524
pub struct Function {
55255525
pub name: ObjectName,
5526+
/// Flags whether this function call uses the [ODBC syntax].
5527+
///
5528+
/// Example:
5529+
/// ```sql
5530+
/// SELECT {fn CONCAT('foo', 'bar')}
5531+
/// ```
5532+
///
5533+
/// [ODBC syntax]: https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/scalar-function-calls?view=sql-server-2017
5534+
pub uses_odbc_syntax: bool,
55265535
/// The parameters to the function, including any options specified within the
55275536
/// delimiting parentheses.
55285537
///
@@ -5561,6 +5570,10 @@ pub struct Function {
55615570

55625571
impl fmt::Display for Function {
55635572
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5573+
if self.uses_odbc_syntax {
5574+
write!(f, "{{fn ")?;
5575+
}
5576+
55645577
write!(f, "{}{}{}", self.name, self.parameters, self.args)?;
55655578

55665579
if !self.within_group.is_empty() {
@@ -5583,6 +5596,10 @@ impl fmt::Display for Function {
55835596
write!(f, " OVER {o}")?;
55845597
}
55855598

5599+
if self.uses_odbc_syntax {
5600+
write!(f, "}}")?;
5601+
}
5602+
55865603
Ok(())
55875604
}
55885605
}

src/ast/spans.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,7 @@ impl Spanned for Function {
14781478
fn span(&self) -> Span {
14791479
let Function {
14801480
name,
1481+
uses_odbc_syntax: _,
14811482
parameters,
14821483
args,
14831484
filter,

src/ast/visitor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ where
530530
/// let old_expr = std::mem::replace(expr, Expr::Value(Value::Null));
531531
/// *expr = Expr::Function(Function {
532532
/// name: ObjectName(vec![Ident::new("f")]),
533+
/// uses_odbc_syntax: false,
533534
/// args: FunctionArguments::List(FunctionArgumentList {
534535
/// duplicate_treatment: None,
535536
/// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],

src/keywords.rs

+1
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ define_keywords!(
333333
FLOAT8,
334334
FLOOR,
335335
FLUSH,
336+
FN,
336337
FOLLOWING,
337338
FOR,
338339
FORCE,

src/parser/mod.rs

+59-6
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ impl<'a> Parser<'a> {
10531053
{
10541054
Ok(Some(Expr::Function(Function {
10551055
name: ObjectName(vec![w.to_ident(w_span)]),
1056+
uses_odbc_syntax: false,
10561057
parameters: FunctionArguments::None,
10571058
args: FunctionArguments::None,
10581059
null_treatment: None,
@@ -1111,6 +1112,7 @@ impl<'a> Parser<'a> {
11111112
self.expect_token(&Token::RParen)?;
11121113
Ok(Some(Expr::Function(Function {
11131114
name: ObjectName(vec![w.to_ident(w_span)]),
1115+
uses_odbc_syntax: false,
11141116
parameters: FunctionArguments::None,
11151117
args: FunctionArguments::Subquery(query),
11161118
filter: None,
@@ -1408,9 +1410,9 @@ impl<'a> Parser<'a> {
14081410
self.prev_token();
14091411
Ok(Expr::Value(self.parse_value()?))
14101412
}
1411-
Token::LBrace if self.dialect.supports_dictionary_syntax() => {
1413+
Token::LBrace => {
14121414
self.prev_token();
1413-
self.parse_duckdb_struct_literal()
1415+
self.parse_lbrace_expr()
14141416
}
14151417
_ => self.expected("an expression", next_token),
14161418
}?;
@@ -1509,23 +1511,46 @@ impl<'a> Parser<'a> {
15091511
}
15101512
}
15111513

1514+
/// Tries to parse the body of an [ODBC function] call.
1515+
/// i.e. without the enclosing braces
1516+
///
1517+
/// ```sql
1518+
/// fn myfunc(1,2,3)
1519+
/// ```
1520+
///
1521+
/// [ODBC function]: https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/scalar-function-calls?view=sql-server-2017
1522+
fn maybe_parse_odbc_fn_body(&mut self) -> Result<Option<Expr>, ParserError> {
1523+
self.maybe_parse(|p| {
1524+
p.expect_keyword(Keyword::FN)?;
1525+
let fn_name = p.parse_object_name(false)?;
1526+
let mut fn_call = p.parse_function_call(fn_name)?;
1527+
fn_call.uses_odbc_syntax = true;
1528+
Ok(Expr::Function(fn_call))
1529+
})
1530+
}
1531+
15121532
pub fn parse_function(&mut self, name: ObjectName) -> Result<Expr, ParserError> {
1533+
self.parse_function_call(name).map(Expr::Function)
1534+
}
1535+
1536+
fn parse_function_call(&mut self, name: ObjectName) -> Result<Function, ParserError> {
15131537
self.expect_token(&Token::LParen)?;
15141538

15151539
// Snowflake permits a subquery to be passed as an argument without
15161540
// an enclosing set of parens if it's the only argument.
15171541
if dialect_of!(self is SnowflakeDialect) && self.peek_sub_query() {
15181542
let subquery = self.parse_query()?;
15191543
self.expect_token(&Token::RParen)?;
1520-
return Ok(Expr::Function(Function {
1544+
return Ok(Function {
15211545
name,
1546+
uses_odbc_syntax: false,
15221547
parameters: FunctionArguments::None,
15231548
args: FunctionArguments::Subquery(subquery),
15241549
filter: None,
15251550
null_treatment: None,
15261551
over: None,
15271552
within_group: vec![],
1528-
}));
1553+
});
15291554
}
15301555

15311556
let mut args = self.parse_function_argument_list()?;
@@ -1584,15 +1609,16 @@ impl<'a> Parser<'a> {
15841609
None
15851610
};
15861611

1587-
Ok(Expr::Function(Function {
1612+
Ok(Function {
15881613
name,
1614+
uses_odbc_syntax: false,
15891615
parameters,
15901616
args: FunctionArguments::List(args),
15911617
null_treatment,
15921618
filter,
15931619
over,
15941620
within_group,
1595-
}))
1621+
})
15961622
}
15971623

15981624
/// Optionally parses a null treatment clause.
@@ -1619,6 +1645,7 @@ impl<'a> Parser<'a> {
16191645
};
16201646
Ok(Expr::Function(Function {
16211647
name,
1648+
uses_odbc_syntax: false,
16221649
parameters: FunctionArguments::None,
16231650
args,
16241651
filter: None,
@@ -2211,6 +2238,31 @@ impl<'a> Parser<'a> {
22112238
}
22122239
}
22132240

2241+
/// Parse expression types that start with a left brace '{'.
2242+
/// Examples:
2243+
/// ```sql
2244+
/// -- Dictionary expr.
2245+
/// {'key1': 'value1', 'key2': 'value2'}
2246+
///
2247+
/// -- Function call using the ODBC syntax.
2248+
/// { fn CONCAT('foo', 'bar') }
2249+
/// ```
2250+
fn parse_lbrace_expr(&mut self) -> Result<Expr, ParserError> {
2251+
let token = self.expect_token(&Token::LBrace)?;
2252+
2253+
if let Some(fn_expr) = self.maybe_parse_odbc_fn_body()? {
2254+
self.expect_token(&Token::RBrace)?;
2255+
return Ok(fn_expr);
2256+
}
2257+
2258+
if self.dialect.supports_dictionary_syntax() {
2259+
self.prev_token(); // Put back the '{'
2260+
return self.parse_duckdb_struct_literal();
2261+
}
2262+
2263+
self.expected("an expression", token)
2264+
}
2265+
22142266
/// Parses fulltext expressions [`sqlparser::ast::Expr::MatchAgainst`]
22152267
///
22162268
/// # Errors
@@ -7578,6 +7630,7 @@ impl<'a> Parser<'a> {
75787630
} else {
75797631
Ok(Statement::Call(Function {
75807632
name: object_name,
7633+
uses_odbc_syntax: false,
75817634
parameters: FunctionArguments::None,
75827635
args: FunctionArguments::None,
75837636
over: None,

src/test_utils.rs

+1
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ pub fn join(relation: TableFactor) -> Join {
376376
pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
377377
Expr::Function(Function {
378378
name: ObjectName(vec![Ident::new(function)]),
379+
uses_odbc_syntax: false,
379380
parameters: FunctionArguments::None,
380381
args: FunctionArguments::List(FunctionArgumentList {
381382
duplicate_treatment: None,

tests/sqlparser_clickhouse.rs

+4
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ fn parse_delimited_identifiers() {
199199
assert_eq!(
200200
&Expr::Function(Function {
201201
name: ObjectName(vec![Ident::with_quote('"', "myfun")]),
202+
uses_odbc_syntax: false,
202203
parameters: FunctionArguments::None,
203204
args: FunctionArguments::List(FunctionArgumentList {
204205
duplicate_treatment: None,
@@ -821,6 +822,7 @@ fn parse_create_table_with_variant_default_expressions() {
821822
name: None,
822823
option: ColumnOption::Materialized(Expr::Function(Function {
823824
name: ObjectName(vec![Ident::new("now")]),
825+
uses_odbc_syntax: false,
824826
args: FunctionArguments::List(FunctionArgumentList {
825827
args: vec![],
826828
duplicate_treatment: None,
@@ -842,6 +844,7 @@ fn parse_create_table_with_variant_default_expressions() {
842844
name: None,
843845
option: ColumnOption::Ephemeral(Some(Expr::Function(Function {
844846
name: ObjectName(vec![Ident::new("now")]),
847+
uses_odbc_syntax: false,
845848
args: FunctionArguments::List(FunctionArgumentList {
846849
args: vec![],
847850
duplicate_treatment: None,
@@ -872,6 +875,7 @@ fn parse_create_table_with_variant_default_expressions() {
872875
name: None,
873876
option: ColumnOption::Alias(Expr::Function(Function {
874877
name: ObjectName(vec![Ident::new("toString")]),
878+
uses_odbc_syntax: false,
875879
args: FunctionArguments::List(FunctionArgumentList {
876880
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
877881
Identifier(Ident::new("c"))

tests/sqlparser_common.rs

+43
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,7 @@ fn parse_select_count_wildcard() {
11081108
assert_eq!(
11091109
&Expr::Function(Function {
11101110
name: ObjectName(vec![Ident::new("COUNT")]),
1111+
uses_odbc_syntax: false,
11111112
parameters: FunctionArguments::None,
11121113
args: FunctionArguments::List(FunctionArgumentList {
11131114
duplicate_treatment: None,
@@ -1130,6 +1131,7 @@ fn parse_select_count_distinct() {
11301131
assert_eq!(
11311132
&Expr::Function(Function {
11321133
name: ObjectName(vec![Ident::new("COUNT")]),
1134+
uses_odbc_syntax: false,
11331135
parameters: FunctionArguments::None,
11341136
args: FunctionArguments::List(FunctionArgumentList {
11351137
duplicate_treatment: Some(DuplicateTreatment::Distinct),
@@ -2366,6 +2368,7 @@ fn parse_select_having() {
23662368
Some(Expr::BinaryOp {
23672369
left: Box::new(Expr::Function(Function {
23682370
name: ObjectName(vec![Ident::new("COUNT")]),
2371+
uses_odbc_syntax: false,
23692372
parameters: FunctionArguments::None,
23702373
args: FunctionArguments::List(FunctionArgumentList {
23712374
duplicate_treatment: None,
@@ -2396,6 +2399,7 @@ fn parse_select_qualify() {
23962399
Some(Expr::BinaryOp {
23972400
left: Box::new(Expr::Function(Function {
23982401
name: ObjectName(vec![Ident::new("ROW_NUMBER")]),
2402+
uses_odbc_syntax: false,
23992403
parameters: FunctionArguments::None,
24002404
args: FunctionArguments::List(FunctionArgumentList {
24012405
duplicate_treatment: None,
@@ -2802,6 +2806,7 @@ fn parse_listagg() {
28022806
assert_eq!(
28032807
&Expr::Function(Function {
28042808
name: ObjectName(vec![Ident::new("LISTAGG")]),
2809+
uses_odbc_syntax: false,
28052810
parameters: FunctionArguments::None,
28062811
args: FunctionArguments::List(FunctionArgumentList {
28072812
duplicate_treatment: Some(DuplicateTreatment::Distinct),
@@ -4603,6 +4608,7 @@ fn parse_named_argument_function() {
46034608
assert_eq!(
46044609
&Expr::Function(Function {
46054610
name: ObjectName(vec![Ident::new("FUN")]),
4611+
uses_odbc_syntax: false,
46064612
parameters: FunctionArguments::None,
46074613
args: FunctionArguments::List(FunctionArgumentList {
46084614
duplicate_treatment: None,
@@ -4642,6 +4648,7 @@ fn parse_named_argument_function_with_eq_operator() {
46424648
assert_eq!(
46434649
&Expr::Function(Function {
46444650
name: ObjectName(vec![Ident::new("FUN")]),
4651+
uses_odbc_syntax: false,
46454652
parameters: FunctionArguments::None,
46464653
args: FunctionArguments::List(FunctionArgumentList {
46474654
duplicate_treatment: None,
@@ -4716,6 +4723,7 @@ fn parse_window_functions() {
47164723
assert_eq!(
47174724
&Expr::Function(Function {
47184725
name: ObjectName(vec![Ident::new("row_number")]),
4726+
uses_odbc_syntax: false,
47194727
parameters: FunctionArguments::None,
47204728
args: FunctionArguments::List(FunctionArgumentList {
47214729
duplicate_treatment: None,
@@ -4846,6 +4854,7 @@ fn test_parse_named_window() {
48464854
quote_style: None,
48474855
span: Span::empty(),
48484856
}]),
4857+
uses_odbc_syntax: false,
48494858
parameters: FunctionArguments::None,
48504859
args: FunctionArguments::List(FunctionArgumentList {
48514860
duplicate_treatment: None,
@@ -4880,6 +4889,7 @@ fn test_parse_named_window() {
48804889
quote_style: None,
48814890
span: Span::empty(),
48824891
}]),
4892+
uses_odbc_syntax: false,
48834893
parameters: FunctionArguments::None,
48844894
args: FunctionArguments::List(FunctionArgumentList {
48854895
duplicate_treatment: None,
@@ -9008,6 +9018,7 @@ fn parse_time_functions() {
90089018
let select = verified_only_select(&sql);
90099019
let select_localtime_func_call_ast = Function {
90109020
name: ObjectName(vec![Ident::new(func_name)]),
9021+
uses_odbc_syntax: false,
90119022
parameters: FunctionArguments::None,
90129023
args: FunctionArguments::List(FunctionArgumentList {
90139024
duplicate_treatment: None,
@@ -10021,6 +10032,7 @@ fn parse_call() {
1002110032
assert_eq!(
1002210033
verified_stmt("CALL my_procedure('a')"),
1002310034
Statement::Call(Function {
10035+
uses_odbc_syntax: false,
1002410036
parameters: FunctionArguments::None,
1002510037
args: FunctionArguments::List(FunctionArgumentList {
1002610038
duplicate_treatment: None,
@@ -10511,6 +10523,7 @@ fn test_selective_aggregation() {
1051110523
vec![
1051210524
SelectItem::UnnamedExpr(Expr::Function(Function {
1051310525
name: ObjectName(vec![Ident::new("ARRAY_AGG")]),
10526+
uses_odbc_syntax: false,
1051410527
parameters: FunctionArguments::None,
1051510528
args: FunctionArguments::List(FunctionArgumentList {
1051610529
duplicate_treatment: None,
@@ -10529,6 +10542,7 @@ fn test_selective_aggregation() {
1052910542
SelectItem::ExprWithAlias {
1053010543
expr: Expr::Function(Function {
1053110544
name: ObjectName(vec![Ident::new("ARRAY_AGG")]),
10545+
uses_odbc_syntax: false,
1053210546
parameters: FunctionArguments::None,
1053310547
args: FunctionArguments::List(FunctionArgumentList {
1053410548
duplicate_treatment: None,
@@ -10968,6 +10982,35 @@ fn insert_into_with_parentheses() {
1096810982
dialects.verified_stmt(r#"INSERT INTO t1 ("select", name) (SELECT t2.name FROM t2)"#);
1096910983
}
1097010984

10985+
#[test]
10986+
fn parse_odbc_scalar_function() {
10987+
let select = verified_only_select("SELECT {fn my_func(1, 2)}");
10988+
let Expr::Function(Function {
10989+
name,
10990+
uses_odbc_syntax,
10991+
args,
10992+
..
10993+
}) = expr_from_projection(only(&select.projection))
10994+
else {
10995+
unreachable!("expected function")
10996+
};
10997+
assert_eq!(name, &ObjectName(vec![Ident::new("my_func")]));
10998+
assert!(uses_odbc_syntax);
10999+
matches!(args, FunctionArguments::List(l) if l.args.len() == 2);
11000+
11001+
verified_stmt("SELECT {fn fna()} AS foo, fnb(1)");
11002+
11003+
// Testing invalid SQL with any-one dialect is intentional.
11004+
// Depending on dialect flags the error message may be different.
11005+
let pg = TestedDialects::new(vec![Box::new(PostgreSqlDialect {})]);
11006+
assert_eq!(
11007+
pg.parse_sql_statements("SELECT {fn2 my_func()}")
11008+
.unwrap_err()
11009+
.to_string(),
11010+
"sql parser error: Expected: an expression, found: {"
11011+
);
11012+
}
11013+
1097111014
#[test]
1097211015
fn test_dictionary_syntax() {
1097311016
fn check(sql: &str, expect: Expr) {

0 commit comments

Comments
 (0)