Skip to content

Commit 640c460

Browse files
Task LAV-1995: parse external functions (apache#2446)
1 parent 687de65 commit 640c460

9 files changed

Lines changed: 561 additions & 12 deletions

File tree

src/ast/ddl.rs

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4102,6 +4102,101 @@ impl fmt::Display for FunctionReturnType {
41024102
}
41034103
}
41044104

4105+
/// A `HEADERS` entry in a Snowflake external function definition.
4106+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4107+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4108+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4109+
pub struct ExternalFunctionHeader {
4110+
/// Header-name string literal.
4111+
pub name: ValueWithSpan,
4112+
/// Header-value string literal.
4113+
pub value: ValueWithSpan,
4114+
}
4115+
4116+
impl fmt::Display for ExternalFunctionHeader {
4117+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4118+
write!(f, "{} = {}", self.name, self.value)
4119+
}
4120+
}
4121+
4122+
/// Compression mode for a Snowflake external function request.
4123+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4124+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4125+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4126+
pub enum ExternalFunctionCompression {
4127+
/// No compression.
4128+
None,
4129+
/// Gzip compression.
4130+
Gzip,
4131+
/// Deflate compression.
4132+
Deflate,
4133+
/// Compression selected automatically.
4134+
Auto,
4135+
}
4136+
4137+
impl fmt::Display for ExternalFunctionCompression {
4138+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4139+
match self {
4140+
Self::None => write!(f, "NONE"),
4141+
Self::Gzip => write!(f, "GZIP"),
4142+
Self::Deflate => write!(f, "DEFLATE"),
4143+
Self::Auto => write!(f, "AUTO"),
4144+
}
4145+
}
4146+
}
4147+
4148+
/// Snowflake-specific parameters for `CREATE EXTERNAL FUNCTION`.
4149+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4150+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4151+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4152+
pub struct ExternalFunctionParams {
4153+
/// Whether the return type has a `NOT NULL` annotation.
4154+
pub return_not_null: bool,
4155+
/// API integration used to invoke the remote endpoint.
4156+
pub api_integration: ObjectName,
4157+
/// Custom HTTP headers.
4158+
pub headers: Option<Vec<ExternalFunctionHeader>>,
4159+
/// Context function names forwarded as headers.
4160+
pub context_headers: Option<Vec<Ident>>,
4161+
/// Maximum rows per request batch.
4162+
pub max_batch_rows: Option<u64>,
4163+
/// Request compression mode.
4164+
pub compression: Option<ExternalFunctionCompression>,
4165+
/// Optional request translator function.
4166+
pub request_translator: Option<ObjectName>,
4167+
/// Optional response translator function.
4168+
pub response_translator: Option<ObjectName>,
4169+
}
4170+
4171+
impl fmt::Display for ExternalFunctionParams {
4172+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4173+
write!(f, "API_INTEGRATION = {}", self.api_integration)?;
4174+
if let Some(headers) = &self.headers {
4175+
write!(f, " HEADERS = ({})", display_comma_separated(headers))?;
4176+
}
4177+
if let Some(context_headers) = &self.context_headers {
4178+
write!(
4179+
f,
4180+
" CONTEXT_HEADERS = ({})",
4181+
display_comma_separated(context_headers)
4182+
)?;
4183+
}
4184+
if let Some(max_batch_rows) = self.max_batch_rows {
4185+
write!(f, " MAX_BATCH_ROWS = {max_batch_rows}")?;
4186+
}
4187+
if let Some(compression) = &self.compression {
4188+
write!(f, " COMPRESSION = {compression}")?;
4189+
}
4190+
if let Some(request_translator) = &self.request_translator {
4191+
write!(f, " REQUEST_TRANSLATOR = {request_translator}")?;
4192+
}
4193+
if let Some(response_translator) = &self.response_translator {
4194+
write!(f, " RESPONSE_TRANSLATOR = {response_translator}")?;
4195+
}
4196+
Ok(())
4197+
}
4198+
}
4199+
41054200
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
41064201
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41074202
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -4185,16 +4280,23 @@ pub struct CreateFunction {
41854280
/// ```
41864281
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
41874282
pub remote_connection: Option<ObjectName>,
4283+
/// Snowflake external-function parameters.
4284+
pub external_params: Option<ExternalFunctionParams>,
41884285
}
41894286

41904287
impl fmt::Display for CreateFunction {
41914288
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41924289
write!(
41934290
f,
4194-
"CREATE {or_alter}{or_replace}{temp}{secure}{data_metric}FUNCTION {if_not_exists}{name}",
4291+
"CREATE {or_alter}{or_replace}{temp}{secure}{external}{data_metric}FUNCTION {if_not_exists}{name}",
41954292
name = self.name,
41964293
temp = if self.temporary { "TEMPORARY " } else { "" },
41974294
secure = if self.secure { "SECURE " } else { "" },
4295+
external = if self.external_params.is_some() {
4296+
"EXTERNAL "
4297+
} else {
4298+
""
4299+
},
41984300
data_metric = if self.data_metric { "DATA METRIC " } else { "" },
41994301
or_alter = if self.or_alter { "OR ALTER " } else { "" },
42004302
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
@@ -4210,6 +4312,32 @@ impl fmt::Display for CreateFunction {
42104312
if let Some(return_type) = &self.return_type {
42114313
write!(f, " RETURNS {return_type}")?;
42124314
}
4315+
if let Some(external) = &self.external_params {
4316+
if external.return_not_null {
4317+
write!(f, " NOT NULL")?;
4318+
}
4319+
if let Some(called_on_null) = &self.called_on_null {
4320+
write!(f, " {called_on_null}")?;
4321+
}
4322+
if let Some(behavior) = &self.behavior {
4323+
write!(f, " {behavior}")?;
4324+
}
4325+
if let Some(options) = &self.options {
4326+
for option in options {
4327+
write!(f, " {option}")?;
4328+
}
4329+
}
4330+
write!(f, " {external}")?;
4331+
if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) =
4332+
&self.function_body
4333+
{
4334+
write!(f, " AS {body}")?;
4335+
if let Some(link_symbol) = link_symbol {
4336+
write!(f, ", {link_symbol}")?;
4337+
}
4338+
}
4339+
return Ok(());
4340+
}
42134341
if let Some(determinism_specifier) = &self.determinism_specifier {
42144342
write!(f, " {determinism_specifier}")?;
42154343
}

src/ast/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ pub use self::ddl::{
7777
CreateOperatorClass, CreateOperatorFamily, CreatePolicy, CreatePolicyCommand, CreatePolicyType,
7878
CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial, DistStyle,
7979
DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorClass, DropOperatorFamily,
80-
DropOperatorSignature, DropPolicy, DropTrigger, ExternalTablePartitionColumn, ForValues,
80+
DropOperatorSignature, DropPolicy, DropTrigger, ExternalFunctionCompression,
81+
ExternalFunctionHeader, ExternalFunctionParams, ExternalTablePartitionColumn, ForValues,
8182
FunctionReturnType, GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
8283
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
8384
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes,

src/ast/spans.rs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
use crate::{
1919
ast::{
2020
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
21-
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
22-
ExportData, Owner, TypedString,
21+
ColumnOptions, CreateFunction, CreateFunctionBody, CreateOperator, CreateOperatorClass,
22+
CreateOperatorFamily, CreateView, ExportData, ExternalFunctionHeader,
23+
ExternalFunctionParams, Owner, TypedString,
2324
},
2425
tokenizer::TokenWithSpan,
2526
};
@@ -469,7 +470,7 @@ impl Spanned for Statement {
469470
Statement::Rollback { .. } => Span::empty(),
470471
Statement::CreateSchema { .. } => Span::empty(),
471472
Statement::CreateDatabase { .. } => Span::empty(),
472-
Statement::CreateFunction { .. } => Span::empty(),
473+
Statement::CreateFunction(create_function) => create_function.span(),
473474
Statement::CreateDomain { .. } => Span::empty(),
474475
Statement::CreateTrigger { .. } => Span::empty(),
475476
Statement::DropTrigger { .. } => Span::empty(),
@@ -1233,6 +1234,81 @@ impl Spanned for SqlOption {
12331234
}
12341235
}
12351236

1237+
impl Spanned for ExternalFunctionHeader {
1238+
fn span(&self) -> Span {
1239+
self.name.span().union(&self.value.span())
1240+
}
1241+
}
1242+
1243+
impl Spanned for ExternalFunctionParams {
1244+
fn span(&self) -> Span {
1245+
union_spans(
1246+
iter::once(self.api_integration.span())
1247+
.chain(
1248+
self.headers
1249+
.iter()
1250+
.flatten()
1251+
.map(Spanned::span),
1252+
)
1253+
.chain(
1254+
self.context_headers
1255+
.iter()
1256+
.flatten()
1257+
.map(|header| header.span),
1258+
)
1259+
.chain(
1260+
self.request_translator
1261+
.iter()
1262+
.map(|translator| translator.span()),
1263+
)
1264+
.chain(
1265+
self.response_translator
1266+
.iter()
1267+
.map(|translator| translator.span()),
1268+
),
1269+
)
1270+
}
1271+
}
1272+
1273+
impl Spanned for CreateFunctionBody {
1274+
fn span(&self) -> Span {
1275+
match self {
1276+
CreateFunctionBody::AsBeforeOptions { body, link_symbol } => {
1277+
body.span().union_opt(&link_symbol.as_ref().map(Spanned::span))
1278+
}
1279+
CreateFunctionBody::AsAfterOptions(body)
1280+
| CreateFunctionBody::Return(body)
1281+
| CreateFunctionBody::AsReturnExpr(body) => body.span(),
1282+
CreateFunctionBody::AsBeginEnd(body) => body.span(),
1283+
CreateFunctionBody::AsReturnSelect(body) => body.span(),
1284+
}
1285+
}
1286+
}
1287+
1288+
impl Spanned for CreateFunction {
1289+
fn span(&self) -> Span {
1290+
union_spans(
1291+
iter::once(self.name.span())
1292+
.chain(
1293+
self.args
1294+
.iter()
1295+
.flatten()
1296+
.flat_map(|argument| {
1297+
[
1298+
argument.name.as_ref().map(|name| name.span),
1299+
argument.default_expr.as_ref().map(Spanned::span),
1300+
]
1301+
.into_iter()
1302+
.flatten()
1303+
}),
1304+
)
1305+
.chain(self.options.iter().flatten().map(Spanned::span))
1306+
.chain(self.function_body.iter().map(Spanned::span))
1307+
.chain(self.external_params.iter().map(Spanned::span)),
1308+
)
1309+
}
1310+
}
1311+
12361312
/// # partial span
12371313
///
12381314
/// Missing spans:

0 commit comments

Comments
 (0)