Skip to content

Commit 0193bf5

Browse files
committed
Add SECURE keyword for views in Snowflake (apache#2004)
1 parent 4a91f2f commit 0193bf5

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
@@ -2564,6 +2564,9 @@ pub enum Statement {
25642564
CreateView {
25652565
or_replace: bool,
25662566
materialized: bool,
2567+
/// Snowflake: SECURE view modifier
2568+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
2569+
secure: bool,
25672570
/// View name
25682571
name: ObjectName,
25692572
columns: Vec<ViewColumnDef>,
@@ -4268,6 +4271,7 @@ impl fmt::Display for Statement {
42684271
columns,
42694272
query,
42704273
materialized,
4274+
secure,
42714275
options,
42724276
cluster_by,
42734277
comment,
@@ -4287,11 +4291,15 @@ impl fmt::Display for Statement {
42874291
}
42884292
write!(
42894293
f,
4290-
"{materialized}{temporary}VIEW {if_not_exists}{name}{to}",
4294+
"{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
4295+
if_not_and_name = if *if_not_exists {
4296+
format!("IF NOT EXISTS {name}")
4297+
} else {
4298+
format!("{name}")
4299+
},
4300+
secure = if *secure { "SECURE " } else { "" },
42914301
materialized = if *materialized { "MATERIALIZED " } else { "" },
4292-
name = name,
42934302
temporary = if *temporary { "TEMPORARY " } else { "" },
4294-
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
42954303
to = to
42964304
.as_ref()
42974305
.map(|to| format!(" TO {to}"))

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ impl Spanned for Statement {
369369
Statement::CreateView {
370370
or_replace: _,
371371
materialized: _,
372+
secure: _,
372373
name,
373374
columns,
374375
query,

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ define_keywords!(
778778
SECONDARY,
779779
SECONDS,
780780
SECRET,
781+
SECURE,
781782
SECURITY,
782783
SEED,
783784
SELECT,

src/parser/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4380,8 +4380,11 @@ impl<'a> Parser<'a> {
43804380
let create_view_params = self.parse_create_view_params()?;
43814381
if self.parse_keyword(Keyword::TABLE) {
43824382
self.parse_create_table(or_replace, temporary, global, transient)
4383-
} else if self.parse_keyword(Keyword::MATERIALIZED) || self.parse_keyword(Keyword::VIEW) {
4384-
self.prev_token();
4383+
} else if self.peek_keyword(Keyword::MATERIALIZED)
4384+
|| self.peek_keyword(Keyword::VIEW)
4385+
|| self.peek_keywords(&[Keyword::SECURE, Keyword::MATERIALIZED, Keyword::VIEW])
4386+
|| self.peek_keywords(&[Keyword::SECURE, Keyword::VIEW])
4387+
{
43854388
self.parse_create_view(or_replace, temporary, create_view_params)
43864389
} else if self.parse_keyword(Keyword::POLICY) {
43874390
self.parse_create_policy()
@@ -5293,6 +5296,7 @@ impl<'a> Parser<'a> {
52935296
temporary: bool,
52945297
create_view_params: Option<CreateViewParams>,
52955298
) -> Result<Statement, ParserError> {
5299+
let secure = self.parse_keyword(Keyword::SECURE);
52965300
let materialized = self.parse_keyword(Keyword::MATERIALIZED);
52975301
self.expect_keyword_is(Keyword::VIEW)?;
52985302
let if_not_exists = dialect_of!(self is BigQueryDialect|SQLiteDialect|GenericDialect)
@@ -5361,6 +5365,7 @@ impl<'a> Parser<'a> {
53615365
columns,
53625366
query,
53635367
materialized,
5368+
secure,
53645369
or_replace,
53655370
options,
53665371
cluster_by,

tests/sqlparser_common.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7806,6 +7806,7 @@ fn parse_create_view() {
78067806
temporary,
78077807
to,
78087808
params,
7809+
secure: _,
78097810
} => {
78107811
assert_eq!("myschema.myview", name.to_string());
78117812
assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -7870,6 +7871,7 @@ fn parse_create_view_with_columns() {
78707871
temporary,
78717872
to,
78727873
params,
7874+
secure: _,
78737875
} => {
78747876
assert_eq!("v", name.to_string());
78757877
assert_eq!(
@@ -7917,6 +7919,7 @@ fn parse_create_view_temporary() {
79177919
temporary,
79187920
to,
79197921
params,
7922+
secure: _,
79207923
} => {
79217924
assert_eq!("myschema.myview", name.to_string());
79227925
assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -7954,6 +7957,7 @@ fn parse_create_or_replace_view() {
79547957
temporary,
79557958
to,
79567959
params,
7960+
secure: _,
79577961
} => {
79587962
assert_eq!("v", name.to_string());
79597963
assert_eq!(columns, vec![]);
@@ -7995,6 +7999,7 @@ fn parse_create_or_replace_materialized_view() {
79957999
temporary,
79968000
to,
79978001
params,
8002+
secure: _,
79988003
} => {
79998004
assert_eq!("v", name.to_string());
80008005
assert_eq!(columns, vec![]);
@@ -8032,6 +8037,7 @@ fn parse_create_materialized_view() {
80328037
temporary,
80338038
to,
80348039
params,
8040+
secure: _,
80358041
} => {
80368042
assert_eq!("myschema.myview", name.to_string());
80378043
assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -8069,6 +8075,7 @@ fn parse_create_materialized_view_with_cluster_by() {
80698075
temporary,
80708076
to,
80718077
params,
8078+
secure: _,
80728079
} => {
80738080
assert_eq!("myschema.myview", name.to_string());
80748081
assert_eq!(Vec::<ViewColumnDef>::new(), columns);

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)