Skip to content

Commit

Permalink
Encapsulate CreateFunction (#1573)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipcristiano authored Dec 2, 2024
1 parent bd750df commit e16b246
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 148 deletions.
129 changes: 127 additions & 2 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ use sqlparser_derive::{Visit, VisitMut};

use crate::ast::value::escape_single_quote_string;
use crate::ast::{
display_comma_separated, display_separated, DataType, Expr, Ident, MySQLColumnPosition,
ObjectName, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
display_comma_separated, display_separated, CreateFunctionBody, CreateFunctionUsing, DataType,
Expr, FunctionBehavior, FunctionCalledOnNull, FunctionDeterminismSpecifier, FunctionParallel,
Ident, MySQLColumnPosition, ObjectName, OperateFunctionArg, OrderByExpr, ProjectionSelect,
SequenceOptions, SqlOption, Tag, Value,
};
use crate::keywords::Keyword;
use crate::tokenizer::Token;
Expand Down Expand Up @@ -1819,3 +1821,126 @@ impl fmt::Display for ClusteredBy {
write!(f, " INTO {} BUCKETS", self.num_buckets)
}
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateFunction {
pub or_replace: bool,
pub temporary: bool,
pub if_not_exists: bool,
pub name: ObjectName,
pub args: Option<Vec<OperateFunctionArg>>,
pub return_type: Option<DataType>,
/// The expression that defines the function.
///
/// Examples:
/// ```sql
/// AS ((SELECT 1))
/// AS "console.log();"
/// ```
pub function_body: Option<CreateFunctionBody>,
/// Behavior attribute for the function
///
/// IMMUTABLE | STABLE | VOLATILE
///
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
pub behavior: Option<FunctionBehavior>,
/// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
///
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
pub called_on_null: Option<FunctionCalledOnNull>,
/// PARALLEL { UNSAFE | RESTRICTED | SAFE }
///
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
pub parallel: Option<FunctionParallel>,
/// USING ... (Hive only)
pub using: Option<CreateFunctionUsing>,
/// Language used in a UDF definition.
///
/// Example:
/// ```sql
/// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
/// ```
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
pub language: Option<Ident>,
/// Determinism keyword used for non-sql UDF definitions.
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
/// List of options for creating the function.
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
pub options: Option<Vec<SqlOption>>,
/// Connection resource for a remote function.
///
/// Example:
/// ```sql
/// CREATE FUNCTION foo()
/// RETURNS FLOAT64
/// REMOTE WITH CONNECTION us.myconnection
/// ```
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
pub remote_connection: Option<ObjectName>,
}

impl fmt::Display for CreateFunction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
name = self.name,
temp = if self.temporary { "TEMPORARY " } else { "" },
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
if_not_exists = if self.if_not_exists {
"IF NOT EXISTS "
} else {
""
},
)?;
if let Some(args) = &self.args {
write!(f, "({})", display_comma_separated(args))?;
}
if let Some(return_type) = &self.return_type {
write!(f, " RETURNS {return_type}")?;
}
if let Some(determinism_specifier) = &self.determinism_specifier {
write!(f, " {determinism_specifier}")?;
}
if let Some(language) = &self.language {
write!(f, " LANGUAGE {language}")?;
}
if let Some(behavior) = &self.behavior {
write!(f, " {behavior}")?;
}
if let Some(called_on_null) = &self.called_on_null {
write!(f, " {called_on_null}")?;
}
if let Some(parallel) = &self.parallel {
write!(f, " {parallel}")?;
}
if let Some(remote_connection) = &self.remote_connection {
write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
}
if let Some(CreateFunctionBody::AsBeforeOptions(function_body)) = &self.function_body {
write!(f, " AS {function_body}")?;
}
if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
write!(f, " RETURN {function_body}")?;
}
if let Some(using) = &self.using {
write!(f, " {using}")?;
}
if let Some(options) = &self.options {
write!(
f,
" OPTIONS({})",
display_comma_separated(options.as_slice())
)?;
}
if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
write!(f, " AS {function_body}")?;
}
Ok(())
}
}
133 changes: 4 additions & 129 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue,
pub use self::ddl::{
AlterColumnOperation, AlterIndexOperation, AlterPolicyOperation, AlterTableOperation,
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
ConstraintCharacteristics, Deduplicate, DeferrableInitial, GeneratedAs,
ConstraintCharacteristics, CreateFunction, Deduplicate, DeferrableInitial, GeneratedAs,
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
IdentityPropertyKind, IdentityPropertyOrder, IndexOption, IndexType, KeyOrIndexDisplay, Owner,
Partition, ProcedureParam, ReferentialAction, TableConstraint, TagsColumnOption,
Expand Down Expand Up @@ -897,7 +897,7 @@ pub enum Expr {
/// Example:
///
/// ```sql
/// SELECT (SELECT ',' + name FROM sys.objects FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
/// SELECT (SELECT ',' + name FROM sys.objects FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
/// SELECT CONVERT(XML,'<Book>abc</Book>').value('.','NVARCHAR(MAX)').value('.','NVARCHAR(MAX)')
/// ```
///
Expand Down Expand Up @@ -3003,64 +3003,7 @@ pub enum Statement {
/// 1. [Hive](https://cwiki.apache.org/confluence/display/hive/languagemanual+ddl#LanguageManualDDL-Create/Drop/ReloadFunction)
/// 2. [Postgres](https://www.postgresql.org/docs/15/sql-createfunction.html)
/// 3. [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement)
CreateFunction {
or_replace: bool,
temporary: bool,
if_not_exists: bool,
name: ObjectName,
args: Option<Vec<OperateFunctionArg>>,
return_type: Option<DataType>,
/// The expression that defines the function.
///
/// Examples:
/// ```sql
/// AS ((SELECT 1))
/// AS "console.log();"
/// ```
function_body: Option<CreateFunctionBody>,
/// Behavior attribute for the function
///
/// IMMUTABLE | STABLE | VOLATILE
///
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
behavior: Option<FunctionBehavior>,
/// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
///
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
called_on_null: Option<FunctionCalledOnNull>,
/// PARALLEL { UNSAFE | RESTRICTED | SAFE }
///
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
parallel: Option<FunctionParallel>,
/// USING ... (Hive only)
using: Option<CreateFunctionUsing>,
/// Language used in a UDF definition.
///
/// Example:
/// ```sql
/// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
/// ```
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
language: Option<Ident>,
/// Determinism keyword used for non-sql UDF definitions.
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
determinism_specifier: Option<FunctionDeterminismSpecifier>,
/// List of options for creating the function.
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
options: Option<Vec<SqlOption>>,
/// Connection resource for a remote function.
///
/// Example:
/// ```sql
/// CREATE FUNCTION foo()
/// RETURNS FLOAT64
/// REMOTE WITH CONNECTION us.myconnection
/// ```
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
remote_connection: Option<ObjectName>,
},
CreateFunction(CreateFunction),
/// CREATE TRIGGER
///
/// Examples:
Expand Down Expand Up @@ -3826,75 +3769,7 @@ impl fmt::Display for Statement {
}
Ok(())
}
Statement::CreateFunction {
or_replace,
temporary,
if_not_exists,
name,
args,
return_type,
function_body,
language,
behavior,
called_on_null,
parallel,
using,
determinism_specifier,
options,
remote_connection,
} => {
write!(
f,
"CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
temp = if *temporary { "TEMPORARY " } else { "" },
or_replace = if *or_replace { "OR REPLACE " } else { "" },
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
)?;
if let Some(args) = args {
write!(f, "({})", display_comma_separated(args))?;
}
if let Some(return_type) = return_type {
write!(f, " RETURNS {return_type}")?;
}
if let Some(determinism_specifier) = determinism_specifier {
write!(f, " {determinism_specifier}")?;
}
if let Some(language) = language {
write!(f, " LANGUAGE {language}")?;
}
if let Some(behavior) = behavior {
write!(f, " {behavior}")?;
}
if let Some(called_on_null) = called_on_null {
write!(f, " {called_on_null}")?;
}
if let Some(parallel) = parallel {
write!(f, " {parallel}")?;
}
if let Some(remote_connection) = remote_connection {
write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
}
if let Some(CreateFunctionBody::AsBeforeOptions(function_body)) = function_body {
write!(f, " AS {function_body}")?;
}
if let Some(CreateFunctionBody::Return(function_body)) = function_body {
write!(f, " RETURN {function_body}")?;
}
if let Some(using) = using {
write!(f, " {using}")?;
}
if let Some(options) = options {
write!(
f,
" OPTIONS({})",
display_comma_separated(options.as_slice())
)?;
}
if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = function_body {
write!(f, " AS {function_body}")?;
}
Ok(())
}
Statement::CreateFunction(create_function) => create_function.fmt(f),
Statement::CreateTrigger {
or_replace,
is_constraint,
Expand Down
12 changes: 6 additions & 6 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4240,7 +4240,7 @@ impl<'a> Parser<'a> {
}
}

Ok(Statement::CreateFunction {
Ok(Statement::CreateFunction(CreateFunction {
or_replace,
temporary,
name,
Expand All @@ -4256,7 +4256,7 @@ impl<'a> Parser<'a> {
determinism_specifier: None,
options: None,
remote_connection: None,
})
}))
}

/// Parse `CREATE FUNCTION` for [Hive]
Expand All @@ -4273,7 +4273,7 @@ impl<'a> Parser<'a> {
let as_ = self.parse_create_function_body_string()?;
let using = self.parse_optional_create_function_using()?;

Ok(Statement::CreateFunction {
Ok(Statement::CreateFunction(CreateFunction {
or_replace,
temporary,
name,
Expand All @@ -4289,7 +4289,7 @@ impl<'a> Parser<'a> {
determinism_specifier: None,
options: None,
remote_connection: None,
})
}))
}

/// Parse `CREATE FUNCTION` for [BigQuery]
Expand Down Expand Up @@ -4362,7 +4362,7 @@ impl<'a> Parser<'a> {
None
};

Ok(Statement::CreateFunction {
Ok(Statement::CreateFunction(CreateFunction {
or_replace,
temporary,
if_not_exists,
Expand All @@ -4378,7 +4378,7 @@ impl<'a> Parser<'a> {
behavior: None,
called_on_null: None,
parallel: None,
})
}))
}

fn parse_function_arg(&mut self) -> Result<OperateFunctionArg, ParserError> {
Expand Down
4 changes: 2 additions & 2 deletions tests/sqlparser_bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2011,7 +2011,7 @@ fn test_bigquery_create_function() {
let stmt = bigquery().verified_stmt(sql);
assert_eq!(
stmt,
Statement::CreateFunction {
Statement::CreateFunction(CreateFunction {
or_replace: true,
temporary: true,
if_not_exists: false,
Expand All @@ -2036,7 +2036,7 @@ fn test_bigquery_create_function() {
remote_connection: None,
called_on_null: None,
parallel: None,
}
})
);

let sqls = [
Expand Down
Loading

0 comments on commit e16b246

Please sign in to comment.