From 7a9172607462821d691491a51457fd75b3542479 Mon Sep 17 00:00:00 2001 From: Elia Perantoni Date: Wed, 11 Jun 2025 12:56:55 +0200 Subject: [PATCH 1/3] feat: change `Tag.key` to `ObjectName` --- src/ast/mod.rs | 4 ++-- src/parser/mod.rs | 2 +- tests/sqlparser_snowflake.rs | 42 +++++++++++++++++++++++++----------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 04401a48b..ff295e649 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -9206,12 +9206,12 @@ impl Display for RowAccessPolicy { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Tag { - pub key: Ident, + pub key: ObjectName, pub value: String, } impl Tag { - pub fn new(key: Ident, value: String) -> Self { + pub fn new(key: ObjectName, value: String) -> Self { Self { key, value } } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 19c11d296..a088a69ba 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7866,7 +7866,7 @@ impl<'a> Parser<'a> { } pub(crate) fn parse_tag(&mut self) -> Result { - let name = self.parse_identifier()?; + let name = self.parse_object_name(false)?; self.expect_token(&Token::Eq)?; let value = self.parse_literal_string()?; diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 7d734ca26..5b7a360f6 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -270,8 +270,8 @@ fn test_snowflake_create_table_with_tag() { assert_eq!("my_table", name.to_string()); assert_eq!( Some(vec![ - Tag::new("A".into(), "TAG A".to_string()), - Tag::new("B".into(), "TAG B".to_string()) + Tag::new(ObjectName::from(vec![Ident::new("A")]), "TAG A".to_string()), + Tag::new(ObjectName::from(vec![Ident::new("B")]), "TAG B".to_string()) ]), with_tags ); @@ -291,8 +291,8 @@ fn test_snowflake_create_table_with_tag() { assert_eq!("my_table", name.to_string()); assert_eq!( Some(vec![ - Tag::new("A".into(), "TAG A".to_string()), - Tag::new("B".into(), "TAG B".to_string()) + Tag::new(ObjectName::from(vec![Ident::new("A")]), "TAG A".to_string()), + Tag::new(ObjectName::from(vec![Ident::new("B")]), "TAG B".to_string()) ]), with_tags ); @@ -802,8 +802,14 @@ fn test_snowflake_create_table_with_columns_tags() { option: ColumnOption::Tags(TagsColumnOption { with, tags: vec![ - Tag::new("A".into(), "TAG A".into()), - Tag::new("B".into(), "TAG B".into()), + Tag::new( + ObjectName::from(vec![Ident::new("A")]), + "TAG A".into() + ), + Tag::new( + ObjectName::from(vec![Ident::new("B")]), + "TAG B".into() + ), ] }), }], @@ -856,8 +862,14 @@ fn test_snowflake_create_table_with_several_column_options() { option: ColumnOption::Tags(TagsColumnOption { with: true, tags: vec![ - Tag::new("A".into(), "TAG A".into()), - Tag::new("B".into(), "TAG B".into()), + Tag::new( + ObjectName::from(vec![Ident::new("A")]), + "TAG A".into() + ), + Tag::new( + ObjectName::from(vec![Ident::new("B")]), + "TAG B".into() + ), ] }), } @@ -888,8 +900,14 @@ fn test_snowflake_create_table_with_several_column_options() { option: ColumnOption::Tags(TagsColumnOption { with: false, tags: vec![ - Tag::new("C".into(), "TAG C".into()), - Tag::new("D".into(), "TAG D".into()), + Tag::new( + ObjectName::from(vec![Ident::new("C")]), + "TAG C".into() + ), + Tag::new( + ObjectName::from(vec![Ident::new("D")]), + "TAG D".into() + ), ] }), } @@ -942,8 +960,8 @@ fn test_snowflake_create_iceberg_table_all_options() { with_aggregation_policy.map(|name| name.to_string()) ); assert_eq!(Some(vec![ - Tag::new("A".into(), "TAG A".into()), - Tag::new("B".into(), "TAG B".into()), + Tag::new(ObjectName::from(vec![Ident::new("A")]), "TAG A".into()), + Tag::new(ObjectName::from(vec![Ident::new("B")]), "TAG B".into()), ]), with_tags); } From c111c21cea2fc3dc59fc0bf3b61f3179f77ef430 Mon Sep 17 00:00:00 2001 From: Elia Perantoni Date: Thu, 12 Jun 2025 12:56:57 +0200 Subject: [PATCH 2/3] feat: column masking policy is an `ObjectName` --- src/ast/ddl.rs | 2 +- src/dialect/snowflake.rs | 2 +- tests/sqlparser_snowflake.rs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 059c61967..946ac9975 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -1651,7 +1651,7 @@ pub struct ColumnPolicyProperty { /// ``` /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table pub with: bool, - pub policy_name: Ident, + pub policy_name: ObjectName, pub using_columns: Option>, } diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index ea0b94a63..43fce8f30 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -1177,7 +1177,7 @@ fn parse_column_policy_property( parser: &mut Parser, with: bool, ) -> Result { - let policy_name = parser.parse_identifier()?; + let policy_name = parser.parse_object_name(false)?; let using_columns = if parser.parse_keyword(Keyword::USING) { parser.expect_token(&Token::LParen)?; let columns = parser.parse_comma_separated(|p| p.parse_identifier())?; diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 5b7a360f6..c3a09746d 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -731,7 +731,7 @@ fn test_snowflake_create_table_with_columns_masking_policy() { option: ColumnOption::Policy(ColumnPolicy::MaskingPolicy( ColumnPolicyProperty { with, - policy_name: "p".into(), + policy_name: ObjectName::from(vec![Ident::new("p")]), using_columns, } )) @@ -765,7 +765,7 @@ fn test_snowflake_create_table_with_columns_projection_policy() { option: ColumnOption::Policy(ColumnPolicy::ProjectionPolicy( ColumnPolicyProperty { with, - policy_name: "p".into(), + policy_name: ObjectName::from(vec![Ident::new("p")]), using_columns: None, } )) @@ -852,7 +852,7 @@ fn test_snowflake_create_table_with_several_column_options() { option: ColumnOption::Policy(ColumnPolicy::MaskingPolicy( ColumnPolicyProperty { with: true, - policy_name: "p1".into(), + policy_name: ObjectName::from(vec![Ident::new("p1")]), using_columns: Some(vec!["a".into(), "b".into()]), } )), @@ -890,7 +890,7 @@ fn test_snowflake_create_table_with_several_column_options() { option: ColumnOption::Policy(ColumnPolicy::ProjectionPolicy( ColumnPolicyProperty { with: false, - policy_name: "p2".into(), + policy_name: ObjectName::from(vec![Ident::new("p2")]), using_columns: None, } )), From 1bf16505257c0db4e26c2e0f5043a1943a8801a6 Mon Sep 17 00:00:00 2001 From: Elia Perantoni Date: Fri, 4 Jul 2025 12:17:42 +0200 Subject: [PATCH 3/3] test: add tests --- tests/sqlparser_snowflake.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index c3a09746d..71429fc38 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4100,3 +4100,17 @@ fn parse_connect_by_root_operator() { "sql parser error: Expected an expression, found: FROM" ); } + +#[test] +fn test_snowflake_create_view_with_composite_tag() { + let create_view_with_tag = + r#"CREATE VIEW X (COL WITH TAG (foo.bar.baz.pii='email')) AS SELECT * FROM Y"#; + snowflake().verified_stmt(create_view_with_tag); +} + +#[test] +fn test_snowflake_create_view_with_composite_policy_name() { + let create_view_with_tag = + r#"CREATE VIEW X (COL WITH MASKING POLICY foo.bar.baz) AS SELECT * FROM Y"#; + snowflake().verified_stmt(create_view_with_tag); +}