Skip to content

Commit 618eb4d

Browse files
committed
Add OR ALTER support for CREATE FUNCTION
1 parent a26087a commit 618eb4d

File tree

5 files changed

+105
-3
lines changed

5 files changed

+105
-3
lines changed

src/ast/ddl.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -2157,6 +2157,10 @@ impl fmt::Display for ClusteredBy {
21572157
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21582158
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
21592159
pub struct CreateFunction {
2160+
/// True if this is a `CREATE OR ALTER FUNCTION` statement
2161+
///
2162+
/// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
2163+
pub or_alter: bool,
21602164
pub or_replace: bool,
21612165
pub temporary: bool,
21622166
pub if_not_exists: bool,
@@ -2219,9 +2223,10 @@ impl fmt::Display for CreateFunction {
22192223
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22202224
write!(
22212225
f,
2222-
"CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
2226+
"CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
22232227
name = self.name,
22242228
temp = if self.temporary { "TEMPORARY " } else { "" },
2229+
or_alter = if self.or_alter { "OR ALTER " } else { "" },
22252230
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
22262231
if_not_exists = if self.if_not_exists {
22272232
"IF NOT EXISTS "

src/parser/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -4556,7 +4556,7 @@ impl<'a> Parser<'a> {
45564556
} else if self.parse_keyword(Keyword::EXTERNAL) {
45574557
self.parse_create_external_table(or_replace)
45584558
} else if self.parse_keyword(Keyword::FUNCTION) {
4559-
self.parse_create_function(or_replace, temporary)
4559+
self.parse_create_function(or_alter, or_replace, temporary)
45604560
} else if self.parse_keyword(Keyword::TRIGGER) {
45614561
self.parse_create_trigger(or_replace, false)
45624562
} else if self.parse_keywords(&[Keyword::CONSTRAINT, Keyword::TRIGGER]) {
@@ -4865,6 +4865,7 @@ impl<'a> Parser<'a> {
48654865

48664866
pub fn parse_create_function(
48674867
&mut self,
4868+
or_alter: bool,
48684869
or_replace: bool,
48694870
temporary: bool,
48704871
) -> Result<Statement, ParserError> {
@@ -4877,7 +4878,7 @@ impl<'a> Parser<'a> {
48774878
} else if dialect_of!(self is BigQueryDialect) {
48784879
self.parse_bigquery_create_function(or_replace, temporary)
48794880
} else if dialect_of!(self is MsSqlDialect) {
4880-
self.parse_mssql_create_function(or_replace, temporary)
4881+
self.parse_mssql_create_function(or_alter, or_replace, temporary)
48814882
} else {
48824883
self.prev_token();
48834884
self.expected("an object type after CREATE", self.peek_token())
@@ -4992,6 +4993,7 @@ impl<'a> Parser<'a> {
49924993
}
49934994

49944995
Ok(Statement::CreateFunction(CreateFunction {
4996+
or_alter: false,
49954997
or_replace,
49964998
temporary,
49974999
name,
@@ -5025,6 +5027,7 @@ impl<'a> Parser<'a> {
50255027
let using = self.parse_optional_create_function_using()?;
50265028

50275029
Ok(Statement::CreateFunction(CreateFunction {
5030+
or_alter: false,
50285031
or_replace,
50295032
temporary,
50305033
name,
@@ -5114,6 +5117,7 @@ impl<'a> Parser<'a> {
51145117
};
51155118

51165119
Ok(Statement::CreateFunction(CreateFunction {
5120+
or_alter: false,
51175121
or_replace,
51185122
temporary,
51195123
if_not_exists,
@@ -5137,6 +5141,7 @@ impl<'a> Parser<'a> {
51375141
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql
51385142
fn parse_mssql_create_function(
51395143
&mut self,
5144+
or_alter: bool,
51405145
or_replace: bool,
51415146
temporary: bool,
51425147
) -> Result<Statement, ParserError> {
@@ -5169,6 +5174,7 @@ impl<'a> Parser<'a> {
51695174
self.expect_keyword_is(Keyword::END)?;
51705175

51715176
Ok(Statement::CreateFunction(CreateFunction {
5177+
or_alter,
51725178
or_replace,
51735179
temporary,
51745180
if_not_exists: false,

tests/sqlparser_bigquery.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,7 @@ fn test_bigquery_create_function() {
21342134
assert_eq!(
21352135
stmt,
21362136
Statement::CreateFunction(CreateFunction {
2137+
or_alter: false,
21372138
or_replace: true,
21382139
temporary: true,
21392140
if_not_exists: false,

tests/sqlparser_mssql.rs

+88
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ fn parse_create_function() {
193193
assert_eq!(
194194
ms().verified_stmt(return_expression_function),
195195
sqlparser::ast::Statement::CreateFunction(CreateFunction {
196+
or_alter: false,
196197
or_replace: false,
197198
temporary: false,
198199
if_not_exists: false,
@@ -255,6 +256,93 @@ fn parse_create_function() {
255256
assert_eq!(
256257
ms().verified_stmt(multi_statement_function),
257258
sqlparser::ast::Statement::CreateFunction(CreateFunction {
259+
or_alter: false,
260+
or_replace: false,
261+
temporary: false,
262+
if_not_exists: false,
263+
name: ObjectName::from(vec![Ident {
264+
value: "some_scalar_udf".into(),
265+
quote_style: None,
266+
span: Span::empty(),
267+
}]),
268+
args: Some(vec![
269+
OperateFunctionArg {
270+
mode: None,
271+
name: Some(Ident {
272+
value: "@foo".into(),
273+
quote_style: None,
274+
span: Span::empty(),
275+
}),
276+
data_type: DataType::Int(None),
277+
default_expr: None,
278+
},
279+
OperateFunctionArg {
280+
mode: None,
281+
name: Some(Ident {
282+
value: "@bar".into(),
283+
quote_style: None,
284+
span: Span::empty(),
285+
}),
286+
data_type: DataType::Varchar(Some(CharacterLength::IntegerLength {
287+
length: 256,
288+
unit: None
289+
})),
290+
default_expr: None,
291+
},
292+
]),
293+
return_type: Some(DataType::Int(None)),
294+
function_body: Some(CreateFunctionBody::MultiStatement(vec![
295+
Statement::Set(Set::SingleAssignment {
296+
scope: None,
297+
hivevar: false,
298+
variable: ObjectName::from(vec!["@foo".into()]),
299+
values: vec![sqlparser::ast::Expr::BinaryOp {
300+
left: Box::new(sqlparser::ast::Expr::Identifier(Ident {
301+
value: "@foo".to_string(),
302+
quote_style: None,
303+
span: Span::empty(),
304+
})),
305+
op: sqlparser::ast::BinaryOperator::Plus,
306+
right: Box::new(Expr::Value(
307+
(Value::Number("1".into(), false)).with_empty_span()
308+
)),
309+
}],
310+
}),
311+
Statement::Return(ReturnStatement {
312+
value: Some(ReturnStatementValue::Expr(Expr::Identifier(Ident {
313+
value: "@foo".into(),
314+
quote_style: None,
315+
span: Span::empty(),
316+
}))),
317+
}),
318+
])),
319+
behavior: None,
320+
called_on_null: None,
321+
parallel: None,
322+
using: None,
323+
language: None,
324+
determinism_specifier: None,
325+
options: None,
326+
remote_connection: None,
327+
}),
328+
);
329+
}
330+
331+
#[test]
332+
fn parse_mssql_create_function() {
333+
let create_or_alter_function = "\
334+
CREATE OR ALTER FUNCTION some_scalar_udf(@foo INT, @bar VARCHAR(256)) \
335+
RETURNS INT \
336+
AS \
337+
BEGIN \
338+
SET @foo = @foo + 1; \
339+
RETURN @foo \
340+
END\
341+
";
342+
assert_eq!(
343+
ms().verified_stmt(create_or_alter_function),
344+
sqlparser::ast::Statement::CreateFunction(CreateFunction {
345+
or_alter: true,
258346
or_replace: false,
259347
temporary: false,
260348
if_not_exists: false,

tests/sqlparser_postgres.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4069,6 +4069,7 @@ fn parse_create_function() {
40694069
assert_eq!(
40704070
pg_and_generic().verified_stmt(sql),
40714071
Statement::CreateFunction(CreateFunction {
4072+
or_alter: false,
40724073
or_replace: false,
40734074
temporary: false,
40744075
name: ObjectName::from(vec![Ident::new("add")]),
@@ -5449,6 +5450,7 @@ fn parse_trigger_related_functions() {
54495450
assert_eq!(
54505451
create_function,
54515452
Statement::CreateFunction(CreateFunction {
5453+
or_alter: false,
54525454
or_replace: false,
54535455
temporary: false,
54545456
if_not_exists: false,

0 commit comments

Comments
 (0)