mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Handle optional datatypes properly in CREATE FUNCTION
statements (#1826)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
parent
3f4d5f96ee
commit
05d7ffb1d5
2 changed files with 225 additions and 5 deletions
|
@ -21,6 +21,7 @@
|
|||
|
||||
#[macro_use]
|
||||
mod test_utils;
|
||||
|
||||
use helpers::attached_token::AttachedToken;
|
||||
use sqlparser::tokenizer::Span;
|
||||
use test_utils::*;
|
||||
|
@ -4105,6 +4106,216 @@ fn parse_update_in_with_subquery() {
|
|||
pg_and_generic().verified_stmt(r#"WITH "result" AS (UPDATE "Hero" SET "name" = 'Captain America', "number_of_movies" = "number_of_movies" + 1 WHERE "secret_identity" = 'Sam Wilson' RETURNING "id", "name", "secret_identity", "number_of_movies") SELECT * FROM "result""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parser_create_function_with_args() {
|
||||
let sql1 = r#"CREATE OR REPLACE FUNCTION check_strings_different(str1 VARCHAR, str2 VARCHAR) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF str1 <> str2 THEN
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END;
|
||||
$$"#;
|
||||
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql1),
|
||||
Statement::CreateFunction(CreateFunction {
|
||||
or_alter: false,
|
||||
or_replace: true,
|
||||
temporary: false,
|
||||
name: ObjectName::from(vec![Ident::new("check_strings_different")]),
|
||||
args: Some(vec![
|
||||
OperateFunctionArg::with_name(
|
||||
"str1",
|
||||
DataType::Varchar(None),
|
||||
),
|
||||
OperateFunctionArg::with_name(
|
||||
"str2",
|
||||
DataType::Varchar(None),
|
||||
),
|
||||
]),
|
||||
return_type: Some(DataType::Boolean),
|
||||
language: Some("plpgsql".into()),
|
||||
behavior: None,
|
||||
called_on_null: None,
|
||||
parallel: None,
|
||||
function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value(
|
||||
(Value::DollarQuotedString(DollarQuotedString {value: "\nBEGIN\n IF str1 <> str2 THEN\n RETURN TRUE;\n ELSE\n RETURN FALSE;\n END IF;\nEND;\n".to_owned(), tag: None})).with_empty_span()
|
||||
))),
|
||||
if_not_exists: false,
|
||||
using: None,
|
||||
determinism_specifier: None,
|
||||
options: None,
|
||||
remote_connection: None,
|
||||
})
|
||||
);
|
||||
|
||||
let sql2 = r#"CREATE OR REPLACE FUNCTION check_not_zero(int1 INT) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF int1 <> 0 THEN
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END;
|
||||
$$"#;
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql2),
|
||||
Statement::CreateFunction(CreateFunction {
|
||||
or_alter: false,
|
||||
or_replace: true,
|
||||
temporary: false,
|
||||
name: ObjectName::from(vec![Ident::new("check_not_zero")]),
|
||||
args: Some(vec![
|
||||
OperateFunctionArg::with_name(
|
||||
"int1",
|
||||
DataType::Int(None)
|
||||
)
|
||||
]),
|
||||
return_type: Some(DataType::Boolean),
|
||||
language: Some("plpgsql".into()),
|
||||
behavior: None,
|
||||
called_on_null: None,
|
||||
parallel: None,
|
||||
function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value(
|
||||
(Value::DollarQuotedString(DollarQuotedString {value: "\nBEGIN\n IF int1 <> 0 THEN\n RETURN TRUE;\n ELSE\n RETURN FALSE;\n END IF;\nEND;\n".to_owned(), tag: None})).with_empty_span()
|
||||
))),
|
||||
if_not_exists: false,
|
||||
using: None,
|
||||
determinism_specifier: None,
|
||||
options: None,
|
||||
remote_connection: None,
|
||||
})
|
||||
);
|
||||
|
||||
let sql3 = r#"CREATE OR REPLACE FUNCTION check_values_different(a INT, b INT) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF a <> b THEN
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END;
|
||||
$$"#;
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql3),
|
||||
Statement::CreateFunction(CreateFunction {
|
||||
or_alter: false,
|
||||
or_replace: true,
|
||||
temporary: false,
|
||||
name: ObjectName::from(vec![Ident::new("check_values_different")]),
|
||||
args: Some(vec![
|
||||
OperateFunctionArg::with_name(
|
||||
"a",
|
||||
DataType::Int(None)
|
||||
),
|
||||
OperateFunctionArg::with_name(
|
||||
"b",
|
||||
DataType::Int(None)
|
||||
),
|
||||
]),
|
||||
return_type: Some(DataType::Boolean),
|
||||
language: Some("plpgsql".into()),
|
||||
behavior: None,
|
||||
called_on_null: None,
|
||||
parallel: None,
|
||||
function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value(
|
||||
(Value::DollarQuotedString(DollarQuotedString {value: "\nBEGIN\n IF a <> b THEN\n RETURN TRUE;\n ELSE\n RETURN FALSE;\n END IF;\nEND;\n".to_owned(), tag: None})).with_empty_span()
|
||||
))),
|
||||
if_not_exists: false,
|
||||
using: None,
|
||||
determinism_specifier: None,
|
||||
options: None,
|
||||
remote_connection: None,
|
||||
})
|
||||
);
|
||||
|
||||
let sql4 = r#"CREATE OR REPLACE FUNCTION check_values_different(int1 INT, int2 INT) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF int1 <> int2 THEN
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END;
|
||||
$$"#;
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql4),
|
||||
Statement::CreateFunction(CreateFunction {
|
||||
or_alter: false,
|
||||
or_replace: true,
|
||||
temporary: false,
|
||||
name: ObjectName::from(vec![Ident::new("check_values_different")]),
|
||||
args: Some(vec![
|
||||
OperateFunctionArg::with_name(
|
||||
"int1",
|
||||
DataType::Int(None)
|
||||
),
|
||||
OperateFunctionArg::with_name(
|
||||
"int2",
|
||||
DataType::Int(None)
|
||||
),
|
||||
]),
|
||||
return_type: Some(DataType::Boolean),
|
||||
language: Some("plpgsql".into()),
|
||||
behavior: None,
|
||||
called_on_null: None,
|
||||
parallel: None,
|
||||
function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value(
|
||||
(Value::DollarQuotedString(DollarQuotedString {value: "\nBEGIN\n IF int1 <> int2 THEN\n RETURN TRUE;\n ELSE\n RETURN FALSE;\n END IF;\nEND;\n".to_owned(), tag: None})).with_empty_span()
|
||||
))),
|
||||
if_not_exists: false,
|
||||
using: None,
|
||||
determinism_specifier: None,
|
||||
options: None,
|
||||
remote_connection: None,
|
||||
})
|
||||
);
|
||||
|
||||
let sql5 = r#"CREATE OR REPLACE FUNCTION foo(a TIMESTAMP WITH TIME ZONE, b VARCHAR) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RETURN TRUE;
|
||||
END;
|
||||
$$"#;
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql5),
|
||||
Statement::CreateFunction(CreateFunction {
|
||||
or_alter: false,
|
||||
or_replace: true,
|
||||
temporary: false,
|
||||
name: ObjectName::from(vec![Ident::new("foo")]),
|
||||
args: Some(vec![
|
||||
OperateFunctionArg::with_name(
|
||||
"a",
|
||||
DataType::Timestamp(None, TimezoneInfo::WithTimeZone)
|
||||
),
|
||||
OperateFunctionArg::with_name("b", DataType::Varchar(None)),
|
||||
]),
|
||||
return_type: Some(DataType::Boolean),
|
||||
language: Some("plpgsql".into()),
|
||||
behavior: None,
|
||||
called_on_null: None,
|
||||
parallel: None,
|
||||
function_body: Some(CreateFunctionBody::AsBeforeOptions(Expr::Value(
|
||||
(Value::DollarQuotedString(DollarQuotedString {
|
||||
value: "\n BEGIN\n RETURN TRUE;\n END;\n ".to_owned(),
|
||||
tag: None
|
||||
}))
|
||||
.with_empty_span()
|
||||
))),
|
||||
if_not_exists: false,
|
||||
using: None,
|
||||
determinism_specifier: None,
|
||||
options: None,
|
||||
remote_connection: None,
|
||||
})
|
||||
);
|
||||
|
||||
let incorrect_sql = "CREATE FUNCTION add(function(struct<a,b> int64), b INTEGER) RETURNS INTEGER LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE AS 'select $1 + $2;'";
|
||||
assert!(pg().parse_sql_statements(incorrect_sql).is_err(),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_function() {
|
||||
let sql = "CREATE FUNCTION add(INTEGER, INTEGER) RETURNS INTEGER LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE AS 'select $1 + $2;'";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue