Skip to content

Commit 5c2b7f7

Browse files
committed
Support CREATE FUNCTION for BigQuery
Adds support for the `CREATE FUNCTION` statement in BigQuery. Merges with the representation used in the hive/postgres dialects. https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1 parent a86c58b commit 5c2b7f7

File tree

6 files changed

+553
-170
lines changed

6 files changed

+553
-170
lines changed

src/ast/mod.rs

Lines changed: 154 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,14 +2399,64 @@ pub enum Statement {
23992399
/// Supported variants:
24002400
/// 1. [Hive](https://cwiki.apache.org/confluence/display/hive/languagemanual+ddl#LanguageManualDDL-Create/Drop/ReloadFunction)
24012401
/// 2. [Postgres](https://www.postgresql.org/docs/15/sql-createfunction.html)
2402+
/// 3. [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement)
24022403
CreateFunction {
24032404
or_replace: bool,
24042405
temporary: bool,
2406+
if_not_exists: bool,
24052407
name: ObjectName,
24062408
args: Option<Vec<OperateFunctionArg>>,
24072409
return_type: Option<DataType>,
2408-
/// Optional parameters.
2409-
params: CreateFunctionBody,
2410+
/// The expression that defines the function.
2411+
///
2412+
/// Examples:
2413+
/// ```sql
2414+
/// AS ((SELECT 1))
2415+
/// AS "console.log();"
2416+
/// ```
2417+
function_body: Option<CreateFunctionBody>,
2418+
/// Behavior attribute for the function
2419+
///
2420+
/// IMMUTABLE | STABLE | VOLATILE
2421+
///
2422+
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
2423+
behavior: Option<FunctionBehavior>,
2424+
/// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
2425+
///
2426+
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
2427+
called_on_null: Option<FunctionCalledOnNull>,
2428+
/// PARALLEL { UNSAFE | RESTRICTED | SAFE }
2429+
///
2430+
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
2431+
parallel: Option<FunctionParallel>,
2432+
/// USING ... (Hive only)
2433+
using: Option<CreateFunctionUsing>,
2434+
/// Language used in a UDF definition.
2435+
///
2436+
/// Example:
2437+
/// ```sql
2438+
/// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
2439+
/// ```
2440+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
2441+
language: Option<Ident>,
2442+
/// Determinism keyword used for non-sql UDF definitions.
2443+
///
2444+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2445+
determinism_specifier: Option<FunctionDeterminismSpecifier>,
2446+
/// List of options for creating the function.
2447+
///
2448+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2449+
options: Option<Vec<SqlOption>>,
2450+
/// Connection resource for a remote function.
2451+
///
2452+
/// Example:
2453+
/// ```sql
2454+
/// CREATE FUNCTION foo()
2455+
/// RETURNS FLOAT64
2456+
/// REMOTE WITH CONNECTION us.myconnection
2457+
/// ```
2458+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
2459+
remote_connection: Option<ObjectName>,
24102460
},
24112461
/// ```sql
24122462
/// CREATE PROCEDURE
@@ -3097,24 +3147,70 @@ impl fmt::Display for Statement {
30973147
Statement::CreateFunction {
30983148
or_replace,
30993149
temporary,
3150+
if_not_exists,
31003151
name,
31013152
args,
31023153
return_type,
3103-
params,
3154+
function_body,
3155+
language,
3156+
behavior,
3157+
called_on_null,
3158+
parallel,
3159+
using,
3160+
determinism_specifier,
3161+
options,
3162+
remote_connection,
31043163
} => {
31053164
write!(
31063165
f,
3107-
"CREATE {or_replace}{temp}FUNCTION {name}",
3166+
"CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
31083167
temp = if *temporary { "TEMPORARY " } else { "" },
31093168
or_replace = if *or_replace { "OR REPLACE " } else { "" },
3169+
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
31103170
)?;
31113171
if let Some(args) = args {
31123172
write!(f, "({})", display_comma_separated(args))?;
31133173
}
31143174
if let Some(return_type) = return_type {
31153175
write!(f, " RETURNS {return_type}")?;
31163176
}
3117-
write!(f, "{params}")?;
3177+
if let Some(determinism_specifier) = determinism_specifier {
3178+
write!(f, " {determinism_specifier}")?;
3179+
}
3180+
if let Some(language) = language {
3181+
write!(f, " LANGUAGE {language}")?;
3182+
}
3183+
if let Some(behavior) = behavior {
3184+
write!(f, " {behavior}")?;
3185+
}
3186+
if let Some(called_on_null) = called_on_null {
3187+
write!(f, " {called_on_null}")?;
3188+
}
3189+
if let Some(parallel) = parallel {
3190+
write!(f, " {parallel}")?;
3191+
}
3192+
if let Some(remote_connection) = remote_connection {
3193+
write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3194+
}
3195+
if let Some(CreateFunctionBody::AsBeforeOptions(function_body)) = function_body {
3196+
write!(f, " AS {function_body}")?;
3197+
}
3198+
if let Some(CreateFunctionBody::Return(function_body)) = function_body {
3199+
write!(f, " RETURN {function_body}")?;
3200+
}
3201+
if let Some(using) = using {
3202+
write!(f, " {using}")?;
3203+
}
3204+
if let Some(options) = options {
3205+
write!(
3206+
f,
3207+
" OPTIONS({})",
3208+
display_comma_separated(options.as_slice())
3209+
)?;
3210+
}
3211+
if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = function_body {
3212+
write!(f, " AS {function_body}")?;
3213+
}
31183214
Ok(())
31193215
}
31203216
Statement::CreateProcedure {
@@ -6041,75 +6137,74 @@ impl fmt::Display for FunctionParallel {
60416137
}
60426138
}
60436139

6140+
/// [BigQuery] Determinism specifier used in a UDF definition.
6141+
///
6142+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
60446143
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
60456144
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60466145
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6047-
pub enum FunctionDefinition {
6048-
SingleQuotedDef(String),
6049-
DoubleDollarDef(String),
6146+
pub enum FunctionDeterminismSpecifier {
6147+
Deterministic,
6148+
NotDeterministic,
60506149
}
60516150

6052-
impl fmt::Display for FunctionDefinition {
6151+
impl fmt::Display for FunctionDeterminismSpecifier {
60536152
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60546153
match self {
6055-
FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?,
6056-
FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?,
6154+
FunctionDeterminismSpecifier::Deterministic => {
6155+
write!(f, "DETERMINISTIC")
6156+
}
6157+
FunctionDeterminismSpecifier::NotDeterministic => {
6158+
write!(f, "NOT DETERMINISTIC")
6159+
}
60576160
}
6058-
Ok(())
60596161
}
60606162
}
60616163

6062-
/// Postgres specific feature.
6164+
/// Represent the expression body of a `CREATE FUNCTION` statement as well as
6165+
/// where within the statement, the body shows up.
60636166
///
6064-
/// See [Postgres docs](https://www.postgresql.org/docs/15/sql-createfunction.html)
6065-
/// for more details
6066-
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6167+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
6168+
/// [Postgres]: https://www.postgresql.org/docs/15/sql-createfunction.html
6169+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
60676170
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60686171
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6069-
pub struct CreateFunctionBody {
6070-
/// LANGUAGE lang_name
6071-
pub language: Option<Ident>,
6072-
/// IMMUTABLE | STABLE | VOLATILE
6073-
pub behavior: Option<FunctionBehavior>,
6074-
/// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
6075-
pub called_on_null: Option<FunctionCalledOnNull>,
6076-
/// PARALLEL { UNSAFE | RESTRICTED | SAFE }
6077-
pub parallel: Option<FunctionParallel>,
6078-
/// AS 'definition'
6172+
pub enum CreateFunctionBody {
6173+
/// A function body expression using the 'AS' keyword and shows up
6174+
/// before any `OPTIONS` clause.
60796175
///
6080-
/// Note that Hive's `AS class_name` is also parsed here.
6081-
pub as_: Option<FunctionDefinition>,
6082-
/// RETURN expression
6083-
pub return_: Option<Expr>,
6084-
/// USING ... (Hive only)
6085-
pub using: Option<CreateFunctionUsing>,
6086-
}
6087-
6088-
impl fmt::Display for CreateFunctionBody {
6089-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6090-
if let Some(language) = &self.language {
6091-
write!(f, " LANGUAGE {language}")?;
6092-
}
6093-
if let Some(behavior) = &self.behavior {
6094-
write!(f, " {behavior}")?;
6095-
}
6096-
if let Some(called_on_null) = &self.called_on_null {
6097-
write!(f, " {called_on_null}")?;
6098-
}
6099-
if let Some(parallel) = &self.parallel {
6100-
write!(f, " {parallel}")?;
6101-
}
6102-
if let Some(definition) = &self.as_ {
6103-
write!(f, " AS {definition}")?;
6104-
}
6105-
if let Some(expr) = &self.return_ {
6106-
write!(f, " RETURN {expr}")?;
6107-
}
6108-
if let Some(using) = &self.using {
6109-
write!(f, " {using}")?;
6110-
}
6111-
Ok(())
6112-
}
6176+
/// Example:
6177+
/// ```sql
6178+
/// CREATE FUNCTION myfunc(x FLOAT64, y FLOAT64) RETURNS FLOAT64
6179+
/// AS (x * y)
6180+
/// OPTIONS(description="desc");
6181+
/// ```
6182+
///
6183+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
6184+
AsBeforeOptions(Expr),
6185+
/// A function body expression using the 'AS' keyword and shows up
6186+
/// after any `OPTIONS` clause.
6187+
///
6188+
/// Example:
6189+
/// ```sql
6190+
/// CREATE FUNCTION myfunc(x FLOAT64, y FLOAT64) RETURNS FLOAT64
6191+
/// OPTIONS(description="desc")
6192+
/// AS (x * y);
6193+
/// ```
6194+
///
6195+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
6196+
AsAfterOptions(Expr),
6197+
/// Function body expression using the 'RETURN' keyword.
6198+
///
6199+
/// Example:
6200+
/// ```sql
6201+
/// CREATE FUNCTION myfunc(a INTEGER, IN b INTEGER = 1) RETURNS INTEGER
6202+
/// LANGUAGE SQL
6203+
/// RETURN a + b;
6204+
/// ```
6205+
///
6206+
/// [Postgres]: https://www.postgresql.org/docs/current/sql-createfunction.html
6207+
Return(Expr),
61136208
}
61146209

61156210
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ define_keywords!(
572572
RELATIVE,
573573
RELAY,
574574
RELEASE,
575+
REMOTE,
575576
RENAME,
576577
REORG,
577578
REPAIR,

0 commit comments

Comments
 (0)