Skip to content

Commit 75ce913

Browse files
committed
Add SECURE keyword for views in Snowflake (apache#2004) (#16)
1 parent 890fe6b commit 75ce913

File tree

6 files changed

+54
-5
lines changed

6 files changed

+54
-5
lines changed

src/ast/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,6 +3261,9 @@ pub enum Statement {
32613261
or_alter: bool,
32623262
or_replace: bool,
32633263
materialized: bool,
3264+
/// Snowflake: SECURE view modifier
3265+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3266+
secure: bool,
32643267
/// View name
32653268
name: ObjectName,
32663269
columns: Vec<ViewColumnDef>,
@@ -5102,6 +5105,7 @@ impl fmt::Display for Statement {
51025105
columns,
51035106
query,
51045107
materialized,
5108+
secure,
51055109
options,
51065110
cluster_by,
51075111
comment,
@@ -5122,11 +5126,15 @@ impl fmt::Display for Statement {
51225126
}
51235127
write!(
51245128
f,
5125-
"{materialized}{temporary}VIEW {if_not_exists}{name}{to}",
5129+
"{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
5130+
if_not_and_name = if *if_not_exists {
5131+
format!("IF NOT EXISTS {name}")
5132+
} else {
5133+
format!("{name}")
5134+
},
5135+
secure = if *secure { "SECURE " } else { "" },
51265136
materialized = if *materialized { "MATERIALIZED " } else { "" },
5127-
name = name,
51285137
temporary = if *temporary { "TEMPORARY " } else { "" },
5129-
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
51305138
to = to
51315139
.as_ref()
51325140
.map(|to| format!(" TO {to}"))

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ impl Spanned for Statement {
391391
or_alter: _,
392392
or_replace: _,
393393
materialized: _,
394+
secure: _,
394395
name,
395396
columns,
396397
query,

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ define_keywords!(
812812
SECONDARY_ENGINE_ATTRIBUTE,
813813
SECONDS,
814814
SECRET,
815+
SECURE,
815816
SECURITY,
816817
SEED,
817818
SELECT,

src/parser/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4644,8 +4644,11 @@ impl<'a> Parser<'a> {
46444644
let create_view_params = self.parse_create_view_params()?;
46454645
if self.parse_keyword(Keyword::TABLE) {
46464646
self.parse_create_table(or_replace, temporary, global, transient)
4647-
} else if self.parse_keyword(Keyword::MATERIALIZED) || self.parse_keyword(Keyword::VIEW) {
4648-
self.prev_token();
4647+
} else if self.peek_keyword(Keyword::MATERIALIZED)
4648+
|| self.peek_keyword(Keyword::VIEW)
4649+
|| self.peek_keywords(&[Keyword::SECURE, Keyword::MATERIALIZED, Keyword::VIEW])
4650+
|| self.peek_keywords(&[Keyword::SECURE, Keyword::VIEW])
4651+
{
46494652
self.parse_create_view(or_alter, or_replace, temporary, create_view_params)
46504653
} else if self.parse_keyword(Keyword::POLICY) {
46514654
self.parse_create_policy()
@@ -5722,6 +5725,7 @@ impl<'a> Parser<'a> {
57225725
temporary: bool,
57235726
create_view_params: Option<CreateViewParams>,
57245727
) -> Result<Statement, ParserError> {
5728+
let secure = self.parse_keyword(Keyword::SECURE);
57255729
let materialized = self.parse_keyword(Keyword::MATERIALIZED);
57265730
self.expect_keyword_is(Keyword::VIEW)?;
57275731
let if_not_exists = dialect_of!(self is BigQueryDialect|SQLiteDialect|GenericDialect)
@@ -5787,6 +5791,7 @@ impl<'a> Parser<'a> {
57875791
columns,
57885792
query,
57895793
materialized,
5794+
secure,
57905795
or_replace,
57915796
options,
57925797
cluster_by,

tests/sqlparser_common.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8004,6 +8004,7 @@ fn parse_create_view() {
80048004
temporary,
80058005
to,
80068006
params,
8007+
secure: _,
80078008
} => {
80088009
assert_eq!(or_alter, false);
80098010
assert_eq!("myschema.myview", name.to_string());
@@ -8072,6 +8073,7 @@ fn parse_create_view_with_columns() {
80728073
temporary,
80738074
to,
80748075
params,
8076+
secure: _,
80758077
} => {
80768078
assert_eq!(or_alter, false);
80778079
assert_eq!("v", name.to_string());
@@ -8121,6 +8123,7 @@ fn parse_create_view_temporary() {
81218123
temporary,
81228124
to,
81238125
params,
8126+
secure: _,
81248127
} => {
81258128
assert_eq!(or_alter, false);
81268129
assert_eq!("myschema.myview", name.to_string());
@@ -8160,6 +8163,7 @@ fn parse_create_or_replace_view() {
81608163
temporary,
81618164
to,
81628165
params,
8166+
secure: _,
81638167
} => {
81648168
assert_eq!(or_alter, false);
81658169
assert_eq!("v", name.to_string());
@@ -8203,6 +8207,7 @@ fn parse_create_or_replace_materialized_view() {
82038207
temporary,
82048208
to,
82058209
params,
8210+
secure: _,
82068211
} => {
82078212
assert_eq!(or_alter, false);
82088213
assert_eq!("v", name.to_string());
@@ -8242,6 +8247,7 @@ fn parse_create_materialized_view() {
82428247
temporary,
82438248
to,
82448249
params,
8250+
secure: _,
82458251
} => {
82468252
assert_eq!(or_alter, false);
82478253
assert_eq!("myschema.myview", name.to_string());
@@ -8281,6 +8287,7 @@ fn parse_create_materialized_view_with_cluster_by() {
82818287
temporary,
82828288
to,
82838289
params,
8290+
secure: _,
82848291
} => {
82858292
assert_eq!(or_alter, false);
82868293
assert_eq!("myschema.myview", name.to_string());

tests/sqlparser_snowflake.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,33 @@ fn test_snowflake_create_table() {
4444
}
4545
}
4646

47+
#[test]
48+
fn parse_sf_create_secure_view_and_materialized_view() {
49+
for sql in [
50+
"CREATE SECURE VIEW v AS SELECT 1",
51+
"CREATE SECURE MATERIALIZED VIEW v AS SELECT 1",
52+
"CREATE OR REPLACE SECURE VIEW v AS SELECT 1",
53+
"CREATE OR REPLACE SECURE MATERIALIZED VIEW v AS SELECT 1",
54+
] {
55+
match snowflake().verified_stmt(sql) {
56+
Statement::CreateView {
57+
secure,
58+
materialized,
59+
..
60+
} => {
61+
assert!(secure);
62+
if sql.contains("MATERIALIZED") {
63+
assert!(materialized);
64+
} else {
65+
assert!(!materialized);
66+
}
67+
}
68+
_ => unreachable!(),
69+
}
70+
assert_eq!(snowflake().verified_stmt(sql).to_string(), sql);
71+
}
72+
}
73+
4774
#[test]
4875
fn test_snowflake_create_or_replace_table() {
4976
let sql = "CREATE OR REPLACE TABLE my_table (a number)";

0 commit comments

Comments
 (0)