This is an automated email from the ASF dual-hosted git repository.

iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new cffff309 Add SECURE keyword for views in Snowflake (#2004)
cffff309 is described below

commit cffff309610247dc278e5c1ef6ec7e643e87ab08
Author: Denys Tsomenko <denist...@gmail.com>
AuthorDate: Tue Aug 26 22:20:13 2025 +0300

    Add SECURE keyword for views in Snowflake (#2004)
---
 src/ast/mod.rs               |  7 ++++++-
 src/ast/spans.rs             |  1 +
 src/keywords.rs              |  1 +
 src/parser/mod.rs            |  9 +++++++--
 tests/sqlparser_common.rs    |  7 +++++++
 tests/sqlparser_snowflake.rs | 27 +++++++++++++++++++++++++++
 6 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 71cb6c5e..a4371566 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -3256,6 +3256,9 @@ pub enum Statement {
         or_alter: bool,
         or_replace: bool,
         materialized: bool,
+        /// Snowflake: SECURE view modifier
+        /// 
<https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
+        secure: bool,
         /// View name
         name: ObjectName,
         /// If `if_not_exists` is true, this flag is set to true if the view 
name comes before the `IF NOT EXISTS` clause.
@@ -5118,6 +5121,7 @@ impl fmt::Display for Statement {
                 columns,
                 query,
                 materialized,
+                secure,
                 options,
                 cluster_by,
                 comment,
@@ -5139,7 +5143,7 @@ impl fmt::Display for Statement {
                 }
                 write!(
                     f,
-                    "{materialized}{temporary}VIEW {if_not_and_name}{to}",
+                    "{secure}{materialized}{temporary}VIEW 
{if_not_and_name}{to}",
                     if_not_and_name = if *if_not_exists {
                         if *name_before_not_exists {
                             format!("{name} IF NOT EXISTS")
@@ -5149,6 +5153,7 @@ impl fmt::Display for Statement {
                     } else {
                         format!("{name}")
                     },
+                    secure = if *secure { "SECURE " } else { "" },
                     materialized = if *materialized { "MATERIALIZED " } else { 
"" },
                     temporary = if *temporary { "TEMPORARY " } else { "" },
                     to = to
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 39761751..6978b627 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -395,6 +395,7 @@ impl Spanned for Statement {
                 or_alter: _,
                 or_replace: _,
                 materialized: _,
+                secure: _,
                 name,
                 columns,
                 query,
diff --git a/src/keywords.rs b/src/keywords.rs
index d78a6c17..eb27d1c4 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -833,6 +833,7 @@ define_keywords!(
     SECONDARY_ENGINE_ATTRIBUTE,
     SECONDS,
     SECRET,
+    SECURE,
     SECURITY,
     SEED,
     SELECT,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 6c559eed..486664e2 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -4732,8 +4732,11 @@ impl<'a> Parser<'a> {
         let create_view_params = self.parse_create_view_params()?;
         if self.parse_keyword(Keyword::TABLE) {
             self.parse_create_table(or_replace, temporary, global, transient)
-        } else if self.parse_keyword(Keyword::MATERIALIZED) || 
self.parse_keyword(Keyword::VIEW) {
-            self.prev_token();
+        } else if self.peek_keyword(Keyword::MATERIALIZED)
+            || self.peek_keyword(Keyword::VIEW)
+            || self.peek_keywords(&[Keyword::SECURE, Keyword::MATERIALIZED, 
Keyword::VIEW])
+            || self.peek_keywords(&[Keyword::SECURE, Keyword::VIEW])
+        {
             self.parse_create_view(or_alter, or_replace, temporary, 
create_view_params)
         } else if self.parse_keyword(Keyword::POLICY) {
             self.parse_create_policy()
@@ -5853,6 +5856,7 @@ impl<'a> Parser<'a> {
         temporary: bool,
         create_view_params: Option<CreateViewParams>,
     ) -> Result<Statement, ParserError> {
+        let secure = self.parse_keyword(Keyword::SECURE);
         let materialized = self.parse_keyword(Keyword::MATERIALIZED);
         self.expect_keyword_is(Keyword::VIEW)?;
         let allow_unquoted_hyphen = dialect_of!(self is BigQueryDialect);
@@ -5923,6 +5927,7 @@ impl<'a> Parser<'a> {
             columns,
             query,
             materialized,
+            secure,
             or_replace,
             options,
             cluster_by,
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 8b99bb1d..2e2d9bfd 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -8078,6 +8078,7 @@ fn parse_create_view() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
@@ -8147,6 +8148,7 @@ fn parse_create_view_with_columns() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             assert_eq!(or_alter, false);
             assert_eq!("v", name.to_string());
@@ -8197,6 +8199,7 @@ fn parse_create_view_temporary() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
@@ -8237,6 +8240,7 @@ fn parse_create_or_replace_view() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             assert_eq!(or_alter, false);
             assert_eq!("v", name.to_string());
@@ -8281,6 +8285,7 @@ fn parse_create_or_replace_materialized_view() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             assert_eq!(or_alter, false);
             assert_eq!("v", name.to_string());
@@ -8321,6 +8326,7 @@ fn parse_create_materialized_view() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
@@ -8361,6 +8367,7 @@ fn parse_create_materialized_view_with_cluster_by() {
             to,
             params,
             name_before_not_exists: _,
+            secure: _,
         } => {
             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 0448e0c4..75e649fe 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -44,6 +44,33 @@ fn test_snowflake_create_table() {
     }
 }
 
+#[test]
+fn parse_sf_create_secure_view_and_materialized_view() {
+    for sql in [
+        "CREATE SECURE VIEW v AS SELECT 1",
+        "CREATE SECURE MATERIALIZED VIEW v AS SELECT 1",
+        "CREATE OR REPLACE SECURE VIEW v AS SELECT 1",
+        "CREATE OR REPLACE SECURE MATERIALIZED VIEW v AS SELECT 1",
+    ] {
+        match snowflake().verified_stmt(sql) {
+            Statement::CreateView {
+                secure,
+                materialized,
+                ..
+            } => {
+                assert!(secure);
+                if sql.contains("MATERIALIZED") {
+                    assert!(materialized);
+                } else {
+                    assert!(!materialized);
+                }
+            }
+            _ => unreachable!(),
+        }
+        assert_eq!(snowflake().verified_stmt(sql).to_string(), sql);
+    }
+}
+
 #[test]
 fn test_snowflake_create_or_replace_table() {
     let sql = "CREATE OR REPLACE TABLE my_table (a number)";


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@datafusion.apache.org
For additional commands, e-mail: commits-h...@datafusion.apache.org

Reply via email to