From 2e5532cc5ad2b54f562fc056435a8d28c78edaa7 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Tue, 3 Feb 2026 19:31:08 -0500 Subject: [PATCH 1/3] Snowflake: Add support for Lambda functions --- src/ast/mod.rs | 22 ++++++++++++++++++- src/dialect/snowflake.rs | 5 +++++ src/parser/mod.rs | 41 +++++++++++++++++++++++++++++++---- tests/sqlparser_common.rs | 11 +++++++++- tests/sqlparser_databricks.rs | 16 ++++++++++++-- tests/sqlparser_snowflake.rs | 6 +++++ 6 files changed, 93 insertions(+), 8 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 010a8189b0..8eed3d5dc9 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1421,7 +1421,7 @@ impl fmt::Display for AccessExpr { #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct LambdaFunction { /// The parameters to the lambda function. - pub params: OneOrManyWithParens, + pub params: OneOrManyWithParens, /// The body of the lambda function. pub body: Box, /// The syntax style used to write the lambda function. @@ -1446,6 +1446,26 @@ impl fmt::Display for LambdaFunction { } } +/// A parameter to a lambda function, optionally with a data type. +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct LambdaFunctionParameter { + /// The name of the parameter + pub name: Ident, + /// The optional data type of the parameter + pub data_type: Option, +} + +impl fmt::Display for LambdaFunctionParameter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.data_type { + Some(dt) => write!(f, "{} {}", self.name, dt), + None => write!(f, "{}", self.name), + } + } +} + /// The syntax style for a lambda function. #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index 3b6fa1c296..bc09f1e617 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -632,6 +632,11 @@ impl Dialect for SnowflakeDialect { fn supports_select_wildcard_rename(&self) -> bool { true } + + /// See + fn supports_lambda_functions(&self) -> bool { + true + } } // Peeks ahead to identify tokens that are expected after diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 585242a8ab..28d91a8242 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1606,7 +1606,25 @@ impl<'a> Parser<'a> { Token::Arrow if self.dialect.supports_lambda_functions() => { self.expect_token(&Token::Arrow)?; Ok(Expr::Lambda(LambdaFunction { - params: OneOrManyWithParens::One(w.to_ident(w_span)), + params: OneOrManyWithParens::One(LambdaFunctionParameter { + name: w.to_ident(w_span), + data_type: None, + }), + body: Box::new(self.parse_expr()?), + syntax: LambdaSyntax::Arrow, + })) + } + Token::Word(_) + if self.peek_nth_token(1).token == Token::Arrow + && self.dialect.supports_lambda_functions() => + { + let first_param = LambdaFunctionParameter { + name: w.to_ident(self.peek_nth_token_ref(1).span), + data_type: self.maybe_parse(|parser| parser.parse_data_type())?, + }; + self.expect_token(&Token::Arrow)?; + Ok(Expr::Lambda(LambdaFunction { + params: OneOrManyWithParens::One(first_param), body: Box::new(self.parse_expr()?), syntax: LambdaSyntax::Arrow, })) @@ -2192,7 +2210,12 @@ impl<'a> Parser<'a> { return Ok(None); } self.maybe_parse(|p| { - let params = p.parse_comma_separated(|p| p.parse_identifier())?; + let params = p.parse_comma_separated(|p| { + Ok(LambdaFunctionParameter { + name: p.parse_identifier()?, + data_type: None, + }) + })?; p.expect_token(&Token::RParen)?; p.expect_token(&Token::Arrow)?; let expr = p.parse_expr()?; @@ -2217,12 +2240,22 @@ impl<'a> Parser<'a> { // Parse the parameters: either a single identifier or comma-separated identifiers let params = if self.consume_token(&Token::LParen) { // Parenthesized parameters: (x, y) - let params = self.parse_comma_separated(|p| p.parse_identifier())?; + let params = self.parse_comma_separated(|p| { + Ok(LambdaFunctionParameter { + name: p.parse_identifier()?, + data_type: None, + }) + })?; self.expect_token(&Token::RParen)?; OneOrManyWithParens::Many(params) } else { // Unparenthesized parameters: x or x, y - let params = self.parse_comma_separated(|p| p.parse_identifier())?; + let params = self.parse_comma_separated(|p| { + Ok(LambdaFunctionParameter { + name: p.parse_identifier()?, + data_type: None, + }) + })?; if params.len() == 1 { OneOrManyWithParens::One(params.into_iter().next().unwrap()) } else { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index b6b867049e..474001c73d 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -15872,7 +15872,16 @@ fn test_lambdas() { ] ), Expr::Lambda(LambdaFunction { - params: OneOrManyWithParens::Many(vec![Ident::new("p1"), Ident::new("p2")]), + params: OneOrManyWithParens::Many(vec![ + LambdaFunctionParameter { + name: Ident::new("p1"), + data_type: None + }, + LambdaFunctionParameter { + name: Ident::new("p2"), + data_type: None + } + ]), body: Box::new(Expr::Case { case_token: AttachedToken::empty(), end_token: AttachedToken::empty(), diff --git a/tests/sqlparser_databricks.rs b/tests/sqlparser_databricks.rs index b088afd78b..899592c98e 100644 --- a/tests/sqlparser_databricks.rs +++ b/tests/sqlparser_databricks.rs @@ -72,7 +72,10 @@ fn test_databricks_exists() { ] ), Expr::Lambda(LambdaFunction { - params: OneOrManyWithParens::One(Ident::new("x")), + params: OneOrManyWithParens::One(LambdaFunctionParameter { + name: Ident::new("x"), + data_type: None + }), body: Box::new(Expr::IsNull(Box::new(Expr::Identifier(Ident::new("x"))))), syntax: LambdaSyntax::Arrow, }) @@ -109,7 +112,16 @@ fn test_databricks_lambdas() { ] ), Expr::Lambda(LambdaFunction { - params: OneOrManyWithParens::Many(vec![Ident::new("p1"), Ident::new("p2")]), + params: OneOrManyWithParens::Many(vec![ + LambdaFunctionParameter { + name: Ident::new("p1"), + data_type: None + }, + LambdaFunctionParameter { + name: Ident::new("p2"), + data_type: None + } + ]), body: Box::new(Expr::Case { case_token: AttachedToken::empty(), end_token: AttachedToken::empty(), diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 014a241fac..765f469011 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4557,3 +4557,9 @@ fn test_truncate_table_if_exists() { snowflake().verified_stmt("TRUNCATE TABLE my_table"); snowflake().verified_stmt("TRUNCATE IF EXISTS my_table"); } + +#[test] +fn test_snowflake_lambda() { + snowflake().verified_expr("TRANSFORM([1, 2, 3], a -> a * 2)"); + snowflake().verified_expr("TRANSFORM([1, 2, 3], a INT -> a * 2)"); +} From 3267aec843152729c9fdb1f0ba94bc5c780f910f Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Tue, 3 Feb 2026 21:42:16 -0500 Subject: [PATCH 2/3] Snowflake: Add support for Lambda functions --- src/keywords.rs | 2 + src/parser/mod.rs | 128 +++++++++++++++++++++++------------ tests/sqlparser_snowflake.rs | 2 + 3 files changed, 90 insertions(+), 42 deletions(-) diff --git a/src/keywords.rs b/src/keywords.rs index f84f4d213a..7db7de8506 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -827,6 +827,7 @@ define_keywords!( RECEIVE, RECLUSTER, RECURSIVE, + REDUCE, REF, REFERENCES, REFERENCING, @@ -1051,6 +1052,7 @@ define_keywords!( TRACE, TRAILING, TRANSACTION, + TRANSFORM, TRANSIENT, TRANSLATE, TRANSLATE_REGEX, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 28d91a8242..06a9b0f3ba 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1556,6 +1556,43 @@ impl<'a> Parser<'a> { Keyword::LAMBDA if self.dialect.supports_lambda_functions() => { Ok(Some(self.parse_lambda_expr()?)) } + Keyword::FILTER + | Keyword::TRANSFORM + | Keyword::REDUCE if self.dialect.supports_lambda_functions() => { + self.expect_token(&Token::LParen)?; + let array = self.parse_expr()?; + self.expect_token(&Token::Comma)?; + let initial_value = if w.keyword == Keyword::REDUCE { + let initial_value = self.parse_expr()?; + self.expect_token(&Token::Comma)?; + Some(initial_value) + } else { + None + }; + let lambda = self.parse_lambda_expr_with_typed_args()?; + let mut args = vec![ + FunctionArg::Unnamed(FunctionArgExpr::Expr(array)), + FunctionArg::Unnamed(FunctionArgExpr::Expr(lambda)), + ]; + if let Some(initial_value) = initial_value { + args.insert(1, FunctionArg::Unnamed(FunctionArgExpr::Expr(initial_value))); + } + self.expect_token(&Token::RParen)?; + Ok(Some(Expr::Function(Function { + name: ObjectName::from(vec![w.to_ident(w_span)]), + uses_odbc_syntax: false, + parameters: FunctionArguments::None, + args: FunctionArguments::List(FunctionArgumentList { + duplicate_treatment: None, + clauses: vec![], + args, + }), + filter: None, + null_treatment: None, + over: None, + within_group: vec![], + }))) + } _ if self.dialect.supports_geometric_types() => match w.keyword { Keyword::CIRCLE => Ok(Some(self.parse_geometric_type(GeometricTypeKind::Circle)?)), Keyword::BOX => Ok(Some(self.parse_geometric_type(GeometricTypeKind::GeometricBox)?)), @@ -1614,21 +1651,6 @@ impl<'a> Parser<'a> { syntax: LambdaSyntax::Arrow, })) } - Token::Word(_) - if self.peek_nth_token(1).token == Token::Arrow - && self.dialect.supports_lambda_functions() => - { - let first_param = LambdaFunctionParameter { - name: w.to_ident(self.peek_nth_token_ref(1).span), - data_type: self.maybe_parse(|parser| parser.parse_data_type())?, - }; - self.expect_token(&Token::Arrow)?; - Ok(Expr::Lambda(LambdaFunction { - params: OneOrManyWithParens::One(first_param), - body: Box::new(self.parse_expr()?), - syntax: LambdaSyntax::Arrow, - })) - } _ => Ok(Expr::Identifier(w.to_ident(w_span))), } } @@ -2210,12 +2232,7 @@ impl<'a> Parser<'a> { return Ok(None); } self.maybe_parse(|p| { - let params = p.parse_comma_separated(|p| { - Ok(LambdaFunctionParameter { - name: p.parse_identifier()?, - data_type: None, - }) - })?; + let params = p.parse_comma_separated(|p| p.parse_lambda_function_parameter(false))?; p.expect_token(&Token::RParen)?; p.expect_token(&Token::Arrow)?; let expr = p.parse_expr()?; @@ -2227,6 +2244,18 @@ impl<'a> Parser<'a> { }) } + /// Parses a lambda expression using the arrow syntax with optionally typed arguments. + fn parse_lambda_expr_with_typed_args(&mut self) -> Result { + let params = self.parse_lambda_function_parameters(true)?; + self.expect_token(&Token::Arrow)?; + let body = self.parse_expr()?; + Ok(Expr::Lambda(LambdaFunction { + params, + body: Box::new(body), + syntax: LambdaSyntax::Arrow, + })) + } + /// Parses a lambda expression using the `LAMBDA` keyword syntax. /// /// Syntax: `LAMBDA : ` @@ -2237,40 +2266,55 @@ impl<'a> Parser<'a> { /// /// See fn parse_lambda_expr(&mut self) -> Result { + // Parse the parameters: either a single identifier or comma-separated identifiers + let params = self.parse_lambda_function_parameters(false)?; + // Expect the colon separator + self.expect_token(&Token::Colon)?; + // Parse the body expression + let body = self.parse_expr()?; + Ok(Expr::Lambda(LambdaFunction { + params, + body: Box::new(body), + syntax: LambdaSyntax::LambdaKeyword, + })) + } + + /// Parses the parameters of a lambda function with optional typing. + fn parse_lambda_function_parameters( + &mut self, + typed: bool, + ) -> Result, ParserError> { // Parse the parameters: either a single identifier or comma-separated identifiers let params = if self.consume_token(&Token::LParen) { // Parenthesized parameters: (x, y) - let params = self.parse_comma_separated(|p| { - Ok(LambdaFunctionParameter { - name: p.parse_identifier()?, - data_type: None, - }) - })?; + let params = + self.parse_comma_separated(|p| p.parse_lambda_function_parameter(typed))?; self.expect_token(&Token::RParen)?; OneOrManyWithParens::Many(params) } else { // Unparenthesized parameters: x or x, y - let params = self.parse_comma_separated(|p| { - Ok(LambdaFunctionParameter { - name: p.parse_identifier()?, - data_type: None, - }) - })?; + let params = + self.parse_comma_separated(|p| p.parse_lambda_function_parameter(typed))?; if params.len() == 1 { OneOrManyWithParens::One(params.into_iter().next().unwrap()) } else { OneOrManyWithParens::Many(params) } }; - // Expect the colon separator - self.expect_token(&Token::Colon)?; - // Parse the body expression - let body = self.parse_expr()?; - Ok(Expr::Lambda(LambdaFunction { - params, - body: Box::new(body), - syntax: LambdaSyntax::LambdaKeyword, - })) + Ok(params) + } + + /// Parses a single parameter of a lambda function, with optional typing. + fn parse_lambda_function_parameter( + &mut self, + typed: bool, + ) -> Result { + let name = self.parse_identifier()?; + let data_type = match self.peek_token().token { + Token::Word(_) if typed => self.maybe_parse(|p| p.parse_data_type())?, + _ => None, + }; + Ok(LambdaFunctionParameter { name, data_type }) } /// Tries to parse the body of an [ODBC escaping sequence] diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 765f469011..bca7ceb03b 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4562,4 +4562,6 @@ fn test_truncate_table_if_exists() { fn test_snowflake_lambda() { snowflake().verified_expr("TRANSFORM([1, 2, 3], a -> a * 2)"); snowflake().verified_expr("TRANSFORM([1, 2, 3], a INT -> a * 2)"); + snowflake().verified_expr("TRANSFORM([1, 2, 3], (x INT, y INT) -> (x + y))"); + snowflake().verified_expr("REDUCE([1, 2, 3], 0, (acc, val) -> acc + val)"); } From 516a09d3f9227e20e904d56a51e737784cfb4cb4 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Fri, 6 Feb 2026 17:42:58 +0100 Subject: [PATCH 3/3] Simplify lambda exp parsing --- src/ast/mod.rs | 1 + src/parser/mod.rs | 90 +++++++++++------------------------- tests/sqlparser_common.rs | 6 +++ tests/sqlparser_snowflake.rs | 8 ---- 4 files changed, 35 insertions(+), 70 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 8eed3d5dc9..39b65c2efe 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1454,6 +1454,7 @@ pub struct LambdaFunctionParameter { /// The name of the parameter pub name: Ident, /// The optional data type of the parameter + /// [Snowflake Syntax](https://docs.snowflake.com/en/sql-reference/functions/filter#arguments) pub data_type: Option, } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 06a9b0f3ba..57404a75ef 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1556,43 +1556,6 @@ impl<'a> Parser<'a> { Keyword::LAMBDA if self.dialect.supports_lambda_functions() => { Ok(Some(self.parse_lambda_expr()?)) } - Keyword::FILTER - | Keyword::TRANSFORM - | Keyword::REDUCE if self.dialect.supports_lambda_functions() => { - self.expect_token(&Token::LParen)?; - let array = self.parse_expr()?; - self.expect_token(&Token::Comma)?; - let initial_value = if w.keyword == Keyword::REDUCE { - let initial_value = self.parse_expr()?; - self.expect_token(&Token::Comma)?; - Some(initial_value) - } else { - None - }; - let lambda = self.parse_lambda_expr_with_typed_args()?; - let mut args = vec![ - FunctionArg::Unnamed(FunctionArgExpr::Expr(array)), - FunctionArg::Unnamed(FunctionArgExpr::Expr(lambda)), - ]; - if let Some(initial_value) = initial_value { - args.insert(1, FunctionArg::Unnamed(FunctionArgExpr::Expr(initial_value))); - } - self.expect_token(&Token::RParen)?; - Ok(Some(Expr::Function(Function { - name: ObjectName::from(vec![w.to_ident(w_span)]), - uses_odbc_syntax: false, - parameters: FunctionArguments::None, - args: FunctionArguments::List(FunctionArgumentList { - duplicate_treatment: None, - clauses: vec![], - args, - }), - filter: None, - null_treatment: None, - over: None, - within_group: vec![], - }))) - } _ if self.dialect.supports_geometric_types() => match w.keyword { Keyword::CIRCLE => Ok(Some(self.parse_geometric_type(GeometricTypeKind::Circle)?)), Keyword::BOX => Ok(Some(self.parse_geometric_type(GeometricTypeKind::GeometricBox)?)), @@ -1640,6 +1603,9 @@ impl<'a> Parser<'a> { value: self.parse_introduced_string_expr()?.into(), }) } + // An unreserved word (likely an identifier) is followed by an arrow, + // which indicates a lambda function with a single, untyped parameter. + // For example: `a -> a * 2`. Token::Arrow if self.dialect.supports_lambda_functions() => { self.expect_token(&Token::Arrow)?; Ok(Expr::Lambda(LambdaFunction { @@ -1651,6 +1617,24 @@ impl<'a> Parser<'a> { syntax: LambdaSyntax::Arrow, })) } + // An unreserved word (likely an identifier) that is followed by another word (likley a data type) + // which is then followed by an arrow, which indicates a lambda function with a single, typed parameter. + // For example: `a INT -> a * 2`. + Token::Word(_) + if self.peek_nth_token_ref(1).token == Token::Arrow + && self.dialect.supports_lambda_functions() => + { + let data_type = self.parse_data_type()?; + self.expect_token(&Token::Arrow)?; + Ok(Expr::Lambda(LambdaFunction { + params: OneOrManyWithParens::One(LambdaFunctionParameter { + name: w.to_ident(w_span), + data_type: Some(data_type), + }), + body: Box::new(self.parse_expr()?), + syntax: LambdaSyntax::Arrow, + })) + } _ => Ok(Expr::Identifier(w.to_ident(w_span))), } } @@ -2232,7 +2216,7 @@ impl<'a> Parser<'a> { return Ok(None); } self.maybe_parse(|p| { - let params = p.parse_comma_separated(|p| p.parse_lambda_function_parameter(false))?; + let params = p.parse_comma_separated(|p| p.parse_lambda_function_parameter())?; p.expect_token(&Token::RParen)?; p.expect_token(&Token::Arrow)?; let expr = p.parse_expr()?; @@ -2244,19 +2228,7 @@ impl<'a> Parser<'a> { }) } - /// Parses a lambda expression using the arrow syntax with optionally typed arguments. - fn parse_lambda_expr_with_typed_args(&mut self) -> Result { - let params = self.parse_lambda_function_parameters(true)?; - self.expect_token(&Token::Arrow)?; - let body = self.parse_expr()?; - Ok(Expr::Lambda(LambdaFunction { - params, - body: Box::new(body), - syntax: LambdaSyntax::Arrow, - })) - } - - /// Parses a lambda expression using the `LAMBDA` keyword syntax. + /// Parses a lambda expression following the `LAMBDA` keyword syntax. /// /// Syntax: `LAMBDA : ` /// @@ -2267,7 +2239,7 @@ impl<'a> Parser<'a> { /// See fn parse_lambda_expr(&mut self) -> Result { // Parse the parameters: either a single identifier or comma-separated identifiers - let params = self.parse_lambda_function_parameters(false)?; + let params = self.parse_lambda_function_parameters()?; // Expect the colon separator self.expect_token(&Token::Colon)?; // Parse the body expression @@ -2282,19 +2254,16 @@ impl<'a> Parser<'a> { /// Parses the parameters of a lambda function with optional typing. fn parse_lambda_function_parameters( &mut self, - typed: bool, ) -> Result, ParserError> { // Parse the parameters: either a single identifier or comma-separated identifiers let params = if self.consume_token(&Token::LParen) { // Parenthesized parameters: (x, y) - let params = - self.parse_comma_separated(|p| p.parse_lambda_function_parameter(typed))?; + let params = self.parse_comma_separated(|p| p.parse_lambda_function_parameter())?; self.expect_token(&Token::RParen)?; OneOrManyWithParens::Many(params) } else { // Unparenthesized parameters: x or x, y - let params = - self.parse_comma_separated(|p| p.parse_lambda_function_parameter(typed))?; + let params = self.parse_comma_separated(|p| p.parse_lambda_function_parameter())?; if params.len() == 1 { OneOrManyWithParens::One(params.into_iter().next().unwrap()) } else { @@ -2305,13 +2274,10 @@ impl<'a> Parser<'a> { } /// Parses a single parameter of a lambda function, with optional typing. - fn parse_lambda_function_parameter( - &mut self, - typed: bool, - ) -> Result { + fn parse_lambda_function_parameter(&mut self) -> Result { let name = self.parse_identifier()?; let data_type = match self.peek_token().token { - Token::Word(_) if typed => self.maybe_parse(|p| p.parse_data_type())?, + Token::Word(_) => self.maybe_parse(|p| p.parse_data_type())?, _ => None, }; Ok(LambdaFunctionParameter { name, data_type }) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 474001c73d..aafbfb756f 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -15926,6 +15926,12 @@ fn test_lambdas() { "map_zip_with(map(1, 'a', 2, 'b'), map(1, 'x', 2, 'y'), (k, v1, v2) -> concat(v1, v2))", ); dialects.verified_expr("transform(array(1, 2, 3), x -> x + 1)"); + + // Ensure all lambda variants are parsed correctly + dialects.verified_expr("a -> a * 2"); // Single parameter without type + dialects.verified_expr("a INT -> a * 2"); // Single parameter with type + dialects.verified_expr("(a, b) -> a * b"); // Multiple parameters without types + dialects.verified_expr("(a INT, b FLOAT) -> a * b"); // Multiple parameters with types } #[test] diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index bca7ceb03b..014a241fac 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4557,11 +4557,3 @@ fn test_truncate_table_if_exists() { snowflake().verified_stmt("TRUNCATE TABLE my_table"); snowflake().verified_stmt("TRUNCATE IF EXISTS my_table"); } - -#[test] -fn test_snowflake_lambda() { - snowflake().verified_expr("TRANSFORM([1, 2, 3], a -> a * 2)"); - snowflake().verified_expr("TRANSFORM([1, 2, 3], a INT -> a * 2)"); - snowflake().verified_expr("TRANSFORM([1, 2, 3], (x INT, y INT) -> (x + y))"); - snowflake().verified_expr("REDUCE([1, 2, 3], 0, (acc, val) -> acc + val)"); -}