diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 9d500203..7e46a59f 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -1709,7 +1709,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/ast/mod.rs b/src/ast/mod.rs index cffd3292..7db4af11 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -9372,12 +9372,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/dialect/snowflake.rs b/src/dialect/snowflake.rs index ba28a8ec..ee770b0f 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -1189,7 +1189,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/src/parser/mod.rs b/src/parser/mod.rs index 289dd6b3..612144a6 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7884,7 +7884,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 3ffd3339..8a1558b2 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 ); @@ -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, } )) @@ -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() + ), ] }), }], @@ -846,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()]), } )), @@ -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() + ), ] }), } @@ -878,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, } )), @@ -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); } @@ -4172,3 +4190,17 @@ fn test_snowflake_create_view_with_multiple_column_options() { r#"CREATE VIEW X (COL WITH TAG (pii='email') COMMENT 'foobar') AS SELECT * FROM Y"#; snowflake().verified_stmt(create_view_with_tag); } + +#[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); +}