This is an automated email from the ASF dual-hosted git repository. github-bot pushed a commit to branch gh-readonly-queue/main/pr-2267-13b88a3fe86f4a64790b3ece3dcea675bd415cff in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit b6003eb98e721943c711672571d7cf252c42ae2b Author: Andriy Romanov <[email protected]> AuthorDate: Mon Mar 9 02:27:03 2026 -0700 Fixed COPY GRANTS clause parsing for snowflake (#2267) --- src/ast/ddl.rs | 6 ++++++ src/parser/mod.rs | 2 ++ tests/sqlparser_common.rs | 6 ++++++ tests/sqlparser_snowflake.rs | 11 +++++++++++ 4 files changed, 25 insertions(+) diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 6bea28cb..d6da8368 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -4293,6 +4293,9 @@ pub struct CreateView { pub if_not_exists: bool, /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html> pub temporary: bool, + /// Snowflake: `COPY GRANTS` clause + /// <https://docs.snowflake.com/en/sql-reference/sql/create-view> + pub copy_grants: bool, /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view> pub to: Option<ObjectName>, @@ -4336,6 +4339,9 @@ impl fmt::Display for CreateView { .map(|to| format!(" TO {to}")) .unwrap_or_default() )?; + if self.copy_grants { + write!(f, " COPY GRANTS")?; + } if !self.columns.is_empty() { write!(f, " ({})", display_comma_separated(&self.columns))?; } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index eaaa95ec..f9432f86 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -6375,6 +6375,7 @@ impl<'a> Parser<'a> { let name_before_not_exists = !if_not_exists_first && self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let if_not_exists = if_not_exists_first || name_before_not_exists; + let copy_grants = self.parse_keywords(&[Keyword::COPY, Keyword::GRANTS]); // Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet). // ANSI SQL and Postgres support RECURSIVE here, but we don't support it either. let columns = self.parse_view_columns()?; @@ -6442,6 +6443,7 @@ impl<'a> Parser<'a> { with_no_schema_binding, if_not_exists, temporary, + copy_grants, to, params: create_view_params, name_before_not_exists, diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index a59e3b96..08fb6107 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -8317,6 +8317,7 @@ fn parse_create_view() { params, name_before_not_exists: _, secure: _, + copy_grants: _, }) => { assert_eq!(or_alter, false); assert_eq!("myschema.myview", name.to_string()); @@ -8435,6 +8436,7 @@ fn parse_create_view_temporary() { params, name_before_not_exists: _, secure: _, + copy_grants: _, }) => { assert_eq!(or_alter, false); assert_eq!("myschema.myview", name.to_string()); @@ -8476,6 +8478,7 @@ fn parse_create_or_replace_view() { params, name_before_not_exists: _, secure: _, + copy_grants: _, }) => { assert_eq!(or_alter, false); assert_eq!("v", name.to_string()); @@ -8521,6 +8524,7 @@ fn parse_create_or_replace_materialized_view() { params, name_before_not_exists: _, secure: _, + copy_grants: _, }) => { assert_eq!(or_alter, false); assert_eq!("v", name.to_string()); @@ -8562,6 +8566,7 @@ fn parse_create_materialized_view() { params, name_before_not_exists: _, secure: _, + copy_grants: _, }) => { assert_eq!(or_alter, false); assert_eq!("myschema.myview", name.to_string()); @@ -8603,6 +8608,7 @@ fn parse_create_materialized_view_with_cluster_by() { params, name_before_not_exists: _, secure: _, + copy_grants: _, }) => { assert_eq!(or_alter, false); assert_eq!("myschema.myview", name.to_string()); diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 022c644a..265f8a9a 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4671,6 +4671,17 @@ fn test_snowflake_create_view_with_composite_policy_name() { snowflake().verified_stmt(create_view_with_tag); } +#[test] +fn test_snowflake_create_view_copy_grants() { + snowflake().verified_stmt("CREATE OR REPLACE VIEW bla COPY GRANTS AS (SELECT * FROM source)"); + snowflake() + .verified_stmt("CREATE OR REPLACE SECURE VIEW bla COPY GRANTS AS (SELECT * FROM source)"); + // COPY GRANTS with column list + snowflake().verified_stmt( + "CREATE OR REPLACE VIEW bla COPY GRANTS (a, b) AS (SELECT a, b FROM source)", + ); +} + #[test] fn test_snowflake_identifier_function() { // Using IDENTIFIER to reference a column --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
