Skip to content

Commit 87c4979

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 d5faf3c commit 87c4979

File tree

6 files changed

+554
-170
lines changed

6 files changed

+554
-170
lines changed

src/ast/mod.rs

Lines changed: 154 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2454,14 +2454,64 @@ pub enum Statement {
24542454
/// Supported variants:
24552455
/// 1. [Hive](https://cwiki.apache.org/confluence/display/hive/languagemanual+ddl#LanguageManualDDL-Create/Drop/ReloadFunction)
24562456
/// 2. [Postgres](https://www.postgresql.org/docs/15/sql-createfunction.html)
2457+
/// 3. [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement)
24572458
CreateFunction {
24582459
or_replace: bool,
24592460
temporary: bool,
2461+
if_not_exists: bool,
24602462
name: ObjectName,
24612463
args: Option<Vec<OperateFunctionArg>>,
24622464
return_type: Option<DataType>,
2463-
/// Optional parameters.
2464-
params: CreateFunctionBody,
2465+
/// The expression that defines the function.
2466+
///
2467+
/// Examples:
2468+
/// ```sql
2469+
/// AS ((SELECT 1))
2470+
/// AS "console.log();"
2471+
/// ```
2472+
function_body: Option<CreateFunctionBody>,
2473+
/// Behavior attribute for the function
2474+
///
2475+
/// IMMUTABLE | STABLE | VOLATILE
2476+
///
2477+
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
2478+
behavior: Option<FunctionBehavior>,
2479+
/// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
2480+
///
2481+
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
2482+
called_on_null: Option<FunctionCalledOnNull>,
2483+
/// PARALLEL { UNSAFE | RESTRICTED | SAFE }
2484+
///
2485+
/// [Postgres](https://www.postgresql.org/docs/current/sql-createfunction.html)
2486+
parallel: Option<FunctionParallel>,
2487+
/// USING ... (Hive only)
2488+
using: Option<CreateFunctionUsing>,
2489+
/// Language used in a UDF definition.
2490+
///
2491+
/// Example:
2492+
/// ```sql
2493+
/// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
2494+
/// ```
2495+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
2496+
language: Option<Ident>,
2497+
/// Determinism keyword used for non-sql UDF definitions.
2498+
///
2499+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2500+
determinism_specifier: Option<FunctionDeterminismSpecifier>,
2501+
/// List of options for creating the function.
2502+
///
2503+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2504+
options: Option<Vec<SqlOption>>,
2505+
/// Connection resource for a remote function.
2506+
///
2507+
/// Example:
2508+
/// ```sql
2509+
/// CREATE FUNCTION foo()
2510+
/// RETURNS FLOAT64
2511+
/// REMOTE WITH CONNECTION us.myconnection
2512+
/// ```
2513+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
2514+
remote_connection: Option<ObjectName>,
24652515
},
24662516
/// ```sql
24672517
/// CREATE PROCEDURE
@@ -3152,24 +3202,70 @@ impl fmt::Display for Statement {
31523202
Statement::CreateFunction {
31533203
or_replace,
31543204
temporary,
3205+
if_not_exists,
31553206
name,
31563207
args,
31573208
return_type,
3158-
params,
3209+
function_body,
3210+
language,
3211+
behavior,
3212+
called_on_null,
3213+
parallel,
3214+
using,
3215+
determinism_specifier,
3216+
options,
3217+
remote_connection,
31593218
} => {
31603219
write!(
31613220
f,
3162-
"CREATE {or_replace}{temp}FUNCTION {name}",
3221+
"CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
31633222
temp = if *temporary { "TEMPORARY " } else { "" },
31643223
or_replace = if *or_replace { "OR REPLACE " } else { "" },
3224+
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
31653225
)?;
31663226
if let Some(args) = args {
31673227
write!(f, "({})", display_comma_separated(args))?;
31683228
}
31693229
if let Some(return_type) = return_type {
31703230
write!(f, " RETURNS {return_type}")?;
31713231
}
3172-
write!(f, "{params}")?;
3232+
if let Some(determinism_specifier) = determinism_specifier {
3233+
write!(f, " {determinism_specifier}")?;
3234+
}
3235+
if let Some(language) = language {
3236+
write!(f, " LANGUAGE {language}")?;
3237+
}
3238+
if let Some(behavior) = behavior {
3239+
write!(f, " {behavior}")?;
3240+
}
3241+
if let Some(called_on_null) = called_on_null {
3242+
write!(f, " {called_on_null}")?;
3243+
}
3244+
if let Some(parallel) = parallel {
3245+
write!(f, " {parallel}")?;
3246+
}
3247+
if let Some(remote_connection) = remote_connection {
3248+
write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3249+
}
3250+
if let Some(CreateFunctionBody::AsBeforeOptions(function_body)) = function_body {
3251+
write!(f, " AS {function_body}")?;
3252+
}
3253+
if let Some(CreateFunctionBody::Return(function_body)) = function_body {
3254+
write!(f, " RETURN {function_body}")?;
3255+
}
3256+
if let Some(using) = using {
3257+
write!(f, " {using}")?;
3258+
}
3259+
if let Some(options) = options {
3260+
write!(
3261+
f,
3262+
" OPTIONS({})",
3263+
display_comma_separated(options.as_slice())
3264+
)?;
3265+
}
3266+
if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = function_body {
3267+
write!(f, " AS {function_body}")?;
3268+
}
31733269
Ok(())
31743270
}
31753271
Statement::CreateProcedure {
@@ -6143,75 +6239,74 @@ impl fmt::Display for FunctionParallel {
61436239
}
61446240
}
61456241

6242+
/// [BigQuery] Determinism specifier used in a UDF definition.
6243+
///
6244+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
61466245
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
61476246
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61486247
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6149-
pub enum FunctionDefinition {
6150-
SingleQuotedDef(String),
6151-
DoubleDollarDef(String),
6248+
pub enum FunctionDeterminismSpecifier {
6249+
Deterministic,
6250+
NotDeterministic,
61526251
}
61536252

6154-
impl fmt::Display for FunctionDefinition {
6253+
impl fmt::Display for FunctionDeterminismSpecifier {
61556254
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61566255
match self {
6157-
FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?,
6158-
FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?,
6256+
FunctionDeterminismSpecifier::Deterministic => {
6257+
write!(f, "DETERMINISTIC")
6258+
}
6259+
FunctionDeterminismSpecifier::NotDeterministic => {
6260+
write!(f, "NOT DETERMINISTIC")
6261+
}
61596262
}
6160-
Ok(())
61616263
}
61626264
}
61636265

6164-
/// Postgres specific feature.
6266+
/// Represent the expression body of a `CREATE FUNCTION` statement as well as
6267+
/// where within the statement, the body shows up.
61656268
///
6166-
/// See [Postgres docs](https://www.postgresql.org/docs/15/sql-createfunction.html)
6167-
/// for more details
6168-
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6269+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
6270+
/// [Postgres]: https://www.postgresql.org/docs/15/sql-createfunction.html
6271+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
61696272
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61706273
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6171-
pub struct CreateFunctionBody {
6172-
/// LANGUAGE lang_name
6173-
pub language: Option<Ident>,
6174-
/// IMMUTABLE | STABLE | VOLATILE
6175-
pub behavior: Option<FunctionBehavior>,
6176-
/// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
6177-
pub called_on_null: Option<FunctionCalledOnNull>,
6178-
/// PARALLEL { UNSAFE | RESTRICTED | SAFE }
6179-
pub parallel: Option<FunctionParallel>,
6180-
/// AS 'definition'
6274+
pub enum CreateFunctionBody {
6275+
/// A function body expression using the 'AS' keyword and shows up
6276+
/// before any `OPTIONS` clause.
61816277
///
6182-
/// Note that Hive's `AS class_name` is also parsed here.
6183-
pub as_: Option<FunctionDefinition>,
6184-
/// RETURN expression
6185-
pub return_: Option<Expr>,
6186-
/// USING ... (Hive only)
6187-
pub using: Option<CreateFunctionUsing>,
6188-
}
6189-
6190-
impl fmt::Display for CreateFunctionBody {
6191-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6192-
if let Some(language) = &self.language {
6193-
write!(f, " LANGUAGE {language}")?;
6194-
}
6195-
if let Some(behavior) = &self.behavior {
6196-
write!(f, " {behavior}")?;
6197-
}
6198-
if let Some(called_on_null) = &self.called_on_null {
6199-
write!(f, " {called_on_null}")?;
6200-
}
6201-
if let Some(parallel) = &self.parallel {
6202-
write!(f, " {parallel}")?;
6203-
}
6204-
if let Some(definition) = &self.as_ {
6205-
write!(f, " AS {definition}")?;
6206-
}
6207-
if let Some(expr) = &self.return_ {
6208-
write!(f, " RETURN {expr}")?;
6209-
}
6210-
if let Some(using) = &self.using {
6211-
write!(f, " {using}")?;
6212-
}
6213-
Ok(())
6214-
}
6278+
/// Example:
6279+
/// ```sql
6280+
/// CREATE FUNCTION myfunc(x FLOAT64, y FLOAT64) RETURNS FLOAT64
6281+
/// AS (x * y)
6282+
/// OPTIONS(description="desc");
6283+
/// ```
6284+
///
6285+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
6286+
AsBeforeOptions(Expr),
6287+
/// A function body expression using the 'AS' keyword and shows up
6288+
/// after any `OPTIONS` clause.
6289+
///
6290+
/// Example:
6291+
/// ```sql
6292+
/// CREATE FUNCTION myfunc(x FLOAT64, y FLOAT64) RETURNS FLOAT64
6293+
/// OPTIONS(description="desc")
6294+
/// AS (x * y);
6295+
/// ```
6296+
///
6297+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11
6298+
AsAfterOptions(Expr),
6299+
/// Function body expression using the 'RETURN' keyword.
6300+
///
6301+
/// Example:
6302+
/// ```sql
6303+
/// CREATE FUNCTION myfunc(a INTEGER, IN b INTEGER = 1) RETURNS INTEGER
6304+
/// LANGUAGE SQL
6305+
/// RETURN a + b;
6306+
/// ```
6307+
///
6308+
/// [Postgres]: https://www.postgresql.org/docs/current/sql-createfunction.html
6309+
Return(Expr),
62156310
}
62166311

62176312
#[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)