From 913cf0e79b31d494eef15b44068f88d786e6fe8d Mon Sep 17 00:00:00 2001 From: Minjun Kim <48622976+funcpp@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:11:54 +0900 Subject: [PATCH 1/7] Enable `!` as NOT operator for Databricks dialect (#2287) --- src/dialect/databricks.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dialect/databricks.rs b/src/dialect/databricks.rs index 55e4f56cc..876eef22f 100644 --- a/src/dialect/databricks.rs +++ b/src/dialect/databricks.rs @@ -90,4 +90,9 @@ impl Dialect for DatabricksDialect { fn supports_optimize_table(&self) -> bool { true } + + /// See + fn supports_bang_not_operator(&self) -> bool { + true + } } From ab33d329d45296d29ecd0f0781891a6c30b6b55a Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 5 Apr 2026 15:25:46 +0200 Subject: [PATCH 2/7] Fix Snowflake TEXT(n) cast parsing --- src/parser/mod.rs | 10 +++++++++- tests/sqlparser_snowflake.rs | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6282ed3d7..88b5a7713 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -11909,6 +11909,7 @@ impl<'a> Parser<'a> { self.advance_token(); let next_token = self.get_current_token(); let next_token_index = self.get_current_index(); + let next_token_span = next_token.span; let mut trailing_bracket: MatchedTrailingBracket = false.into(); let mut data = match &next_token.token { @@ -12170,7 +12171,14 @@ impl<'a> Parser<'a> { self.expect_token(&Token::RParen)?; Ok(DataType::FixedString(character_length)) } - Keyword::TEXT => Ok(DataType::Text), + Keyword::TEXT => { + let type_name = w.to_ident(next_token_span); + if let Some(modifiers) = self.parse_optional_type_modifiers()? { + Ok(DataType::Custom(type_name.into(), modifiers)) + } else { + Ok(DataType::Text) + } + } Keyword::TINYTEXT => Ok(DataType::TinyText), Keyword::MEDIUMTEXT => Ok(DataType::MediumText), Keyword::LONGTEXT => Ok(DataType::LongText), diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 790bf1515..63daf2f3f 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5010,3 +5010,40 @@ fn test_select_dollar_column_from_stage() { // With table function args, without alias snowflake().verified_stmt("SELECT $1, $2 FROM @mystage1(file_format => 'myformat')"); } + +#[test] +fn test_text_cast_with_length_modifier() { + let select = snowflake().verified_only_select("SELECT col::TEXT(16777216) AS col FROM t"); + + match &select.projection[0] { + SelectItem::ExprWithAlias { + expr: Expr::Cast { data_type, .. }, + alias, + } => { + assert_eq!(alias, &Ident::new("col")); + assert_eq!( + data_type, + &DataType::Custom( + ObjectName::from(vec![Ident::new("TEXT")]), + vec!["16777216".to_string()], + ) + ); + } + _ => unreachable!(), + } + + snowflake().one_statement_parses_to( + "SELECT col::TEXT(16777216) AS col FROM t", + "SELECT col::TEXT(16777216) AS col FROM t", + ); +} + +#[test] +fn test_plain_text_data_type_still_parses_as_text() { + match snowflake().verified_stmt("CREATE TABLE t (c TEXT)") { + Statement::CreateTable(CreateTable { columns, .. }) => { + assert_eq!(columns[0].data_type, DataType::Text); + } + _ => unreachable!(), + } +} From 0d3415270166b7db7a79d43438ac3edb237d3b57 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 5 Apr 2026 15:34:57 +0200 Subject: [PATCH 3/7] Use verified_statement in Snowflake TEXT tests --- src/test_utils.rs | 7 ++++++- tests/sqlparser_snowflake.rs | 7 ++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index 9ba5960e8..0bee63e54 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -199,10 +199,15 @@ impl TestedDialects { /// Ensures that `sql` parses as a single [Statement], and that /// re-serializing the parse result produces the same `sql` /// string (is not modified after a serialization round-trip). - pub fn verified_stmt(&self, sql: &str) -> Statement { + pub fn verified_statement(&self, sql: &str) -> Statement { self.one_statement_parses_to(sql, sql) } + /// Shorthand for [`TestedDialects::verified_statement`]. + pub fn verified_stmt(&self, sql: &str) -> Statement { + self.verified_statement(sql) + } + /// Ensures that `sql` parses as a single [Query], and that /// re-serializing the parse result produces the same `sql` /// string (is not modified after a serialization round-trip). diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 63daf2f3f..0aaa88d02 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5032,15 +5032,12 @@ fn test_text_cast_with_length_modifier() { _ => unreachable!(), } - snowflake().one_statement_parses_to( - "SELECT col::TEXT(16777216) AS col FROM t", - "SELECT col::TEXT(16777216) AS col FROM t", - ); + snowflake().verified_statement("SELECT col::TEXT(16777216) AS col FROM t"); } #[test] fn test_plain_text_data_type_still_parses_as_text() { - match snowflake().verified_stmt("CREATE TABLE t (c TEXT)") { + match snowflake().verified_statement("CREATE TABLE t (c TEXT)") { Statement::CreateTable(CreateTable { columns, .. }) => { assert_eq!(columns[0].data_type, DataType::Text); } From 21e9b289f891be8582d515974247a3b61119d138 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 5 Apr 2026 15:56:06 +0200 Subject: [PATCH 4/7] Revert Snowflake test helper rename --- src/test_utils.rs | 9 ++------- tests/sqlparser_snowflake.rs | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index 0bee63e54..db57140e5 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -140,7 +140,7 @@ impl TestedDialects { /// /// In general, the canonical SQL should be the same (see crate /// documentation for rationale) and you should prefer the `verified_` - /// variants in testing, such as [`verified_statement`] or + /// variants in testing, such as [`verified_stmt`] or /// [`verified_query`]. /// /// If `canonical` is non empty,this function additionally asserts @@ -199,13 +199,8 @@ impl TestedDialects { /// Ensures that `sql` parses as a single [Statement], and that /// re-serializing the parse result produces the same `sql` /// string (is not modified after a serialization round-trip). - pub fn verified_statement(&self, sql: &str) -> Statement { - self.one_statement_parses_to(sql, sql) - } - - /// Shorthand for [`TestedDialects::verified_statement`]. pub fn verified_stmt(&self, sql: &str) -> Statement { - self.verified_statement(sql) + self.one_statement_parses_to(sql, sql) } /// Ensures that `sql` parses as a single [Query], and that diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 0aaa88d02..a58ad8a7b 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5032,12 +5032,12 @@ fn test_text_cast_with_length_modifier() { _ => unreachable!(), } - snowflake().verified_statement("SELECT col::TEXT(16777216) AS col FROM t"); + snowflake().verified_stmt("SELECT col::TEXT(16777216) AS col FROM t"); } #[test] fn test_plain_text_data_type_still_parses_as_text() { - match snowflake().verified_statement("CREATE TABLE t (c TEXT)") { + match snowflake().verified_stmt("CREATE TABLE t (c TEXT)") { Statement::CreateTable(CreateTable { columns, .. }) => { assert_eq!(columns[0].data_type, DataType::Text); } From d1dca11bbbee8ca9de5789b32d25892970d23914 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 5 Apr 2026 16:03:38 +0200 Subject: [PATCH 5/7] Revert unrelated test_utils doc change --- src/test_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index db57140e5..9ba5960e8 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -140,7 +140,7 @@ impl TestedDialects { /// /// In general, the canonical SQL should be the same (see crate /// documentation for rationale) and you should prefer the `verified_` - /// variants in testing, such as [`verified_stmt`] or + /// variants in testing, such as [`verified_statement`] or /// [`verified_query`]. /// /// If `canonical` is non empty,this function additionally asserts From 180f2944f09376041d1fa9506894d990d1146c29 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 5 Apr 2026 16:14:49 +0200 Subject: [PATCH 6/7] Revert unrelated Snowflake TEXT test --- tests/sqlparser_snowflake.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index a58ad8a7b..9af8fffbe 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -5034,13 +5034,3 @@ fn test_text_cast_with_length_modifier() { snowflake().verified_stmt("SELECT col::TEXT(16777216) AS col FROM t"); } - -#[test] -fn test_plain_text_data_type_still_parses_as_text() { - match snowflake().verified_stmt("CREATE TABLE t (c TEXT)") { - Statement::CreateTable(CreateTable { columns, .. }) => { - assert_eq!(columns[0].data_type, DataType::Text); - } - _ => unreachable!(), - } -} From 8b7bdb368667a05c61fc279c074e66c0ce355e4d Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 5 Apr 2026 16:44:14 +0200 Subject: [PATCH 7/7] Limit TEXT(n) parsing fix to Snowflake --- src/parser/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 88b5a7713..5e7e00705 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -11909,7 +11909,6 @@ impl<'a> Parser<'a> { self.advance_token(); let next_token = self.get_current_token(); let next_token_index = self.get_current_index(); - let next_token_span = next_token.span; let mut trailing_bracket: MatchedTrailingBracket = false.into(); let mut data = match &next_token.token { @@ -12172,9 +12171,13 @@ impl<'a> Parser<'a> { Ok(DataType::FixedString(character_length)) } Keyword::TEXT => { - let type_name = w.to_ident(next_token_span); - if let Some(modifiers) = self.parse_optional_type_modifiers()? { - Ok(DataType::Custom(type_name.into(), modifiers)) + if dialect_of!(self is SnowflakeDialect) { + let type_name = w.to_ident(next_token.span); + if let Some(modifiers) = self.parse_optional_type_modifiers()? { + Ok(DataType::Custom(type_name.into(), modifiers)) + } else { + Ok(DataType::Text) + } } else { Ok(DataType::Text) }