Skip to content

Commit 5263da6

Browse files
authored
Handle CREATE [TEMPORARY|TEMP] VIEW [IF NOT EXISTS] (#993)
1 parent 02f3d78 commit 5263da6

File tree

4 files changed

+106
-4
lines changed

4 files changed

+106
-4
lines changed

src/ast/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,10 @@ pub enum Statement {
13181318
cluster_by: Vec<Ident>,
13191319
/// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
13201320
with_no_schema_binding: bool,
1321+
/// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
1322+
if_not_exists: bool,
1323+
/// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
1324+
temporary: bool,
13211325
},
13221326
/// CREATE TABLE
13231327
CreateTable {
@@ -2274,13 +2278,17 @@ impl fmt::Display for Statement {
22742278
with_options,
22752279
cluster_by,
22762280
with_no_schema_binding,
2281+
if_not_exists,
2282+
temporary,
22772283
} => {
22782284
write!(
22792285
f,
2280-
"CREATE {or_replace}{materialized}VIEW {name}",
2286+
"CREATE {or_replace}{materialized}{temporary}VIEW {if_not_exists}{name}",
22812287
or_replace = if *or_replace { "OR REPLACE " } else { "" },
22822288
materialized = if *materialized { "MATERIALIZED " } else { "" },
2283-
name = name
2289+
name = name,
2290+
temporary = if *temporary { "TEMPORARY " } else { "" },
2291+
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" }
22842292
)?;
22852293
if !with_options.is_empty() {
22862294
write!(f, " WITH ({})", display_comma_separated(with_options))?;

src/parser/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -2478,7 +2478,7 @@ impl<'a> Parser<'a> {
24782478
self.parse_create_table(or_replace, temporary, global, transient)
24792479
} else if self.parse_keyword(Keyword::MATERIALIZED) || self.parse_keyword(Keyword::VIEW) {
24802480
self.prev_token();
2481-
self.parse_create_view(or_replace)
2481+
self.parse_create_view(or_replace, temporary)
24822482
} else if self.parse_keyword(Keyword::EXTERNAL) {
24832483
self.parse_create_external_table(or_replace)
24842484
} else if self.parse_keyword(Keyword::FUNCTION) {
@@ -2955,9 +2955,15 @@ impl<'a> Parser<'a> {
29552955
}
29562956
}
29572957

2958-
pub fn parse_create_view(&mut self, or_replace: bool) -> Result<Statement, ParserError> {
2958+
pub fn parse_create_view(
2959+
&mut self,
2960+
or_replace: bool,
2961+
temporary: bool,
2962+
) -> Result<Statement, ParserError> {
29592963
let materialized = self.parse_keyword(Keyword::MATERIALIZED);
29602964
self.expect_keyword(Keyword::VIEW)?;
2965+
let if_not_exists = dialect_of!(self is SQLiteDialect|GenericDialect)
2966+
&& self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
29612967
// Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet).
29622968
// ANSI SQL and Postgres support RECURSIVE here, but we don't support it either.
29632969
let name = self.parse_object_name()?;
@@ -2992,6 +2998,8 @@ impl<'a> Parser<'a> {
29922998
with_options,
29932999
cluster_by,
29943000
with_no_schema_binding,
3001+
if_not_exists,
3002+
temporary,
29953003
})
29963004
}
29973005

tests/sqlparser_common.rs

+55
Original file line numberDiff line numberDiff line change
@@ -5321,6 +5321,8 @@ fn parse_create_view() {
53215321
with_options,
53225322
cluster_by,
53235323
with_no_schema_binding: late_binding,
5324+
if_not_exists,
5325+
temporary,
53245326
} => {
53255327
assert_eq!("myschema.myview", name.to_string());
53265328
assert_eq!(Vec::<Ident>::new(), columns);
@@ -5330,6 +5332,8 @@ fn parse_create_view() {
53305332
assert_eq!(with_options, vec![]);
53315333
assert_eq!(cluster_by, vec![]);
53325334
assert!(!late_binding);
5335+
assert!(!if_not_exists);
5336+
assert!(!temporary);
53335337
}
53345338
_ => unreachable!(),
53355339
}
@@ -5371,6 +5375,8 @@ fn parse_create_view_with_columns() {
53715375
materialized,
53725376
cluster_by,
53735377
with_no_schema_binding: late_binding,
5378+
if_not_exists,
5379+
temporary,
53745380
} => {
53755381
assert_eq!("v", name.to_string());
53765382
assert_eq!(columns, vec![Ident::new("has"), Ident::new("cols")]);
@@ -5380,6 +5386,39 @@ fn parse_create_view_with_columns() {
53805386
assert!(!or_replace);
53815387
assert_eq!(cluster_by, vec![]);
53825388
assert!(!late_binding);
5389+
assert!(!if_not_exists);
5390+
assert!(!temporary);
5391+
}
5392+
_ => unreachable!(),
5393+
}
5394+
}
5395+
5396+
#[test]
5397+
fn parse_create_view_temporary() {
5398+
let sql = "CREATE TEMPORARY VIEW myschema.myview AS SELECT foo FROM bar";
5399+
match verified_stmt(sql) {
5400+
Statement::CreateView {
5401+
name,
5402+
columns,
5403+
query,
5404+
or_replace,
5405+
materialized,
5406+
with_options,
5407+
cluster_by,
5408+
with_no_schema_binding: late_binding,
5409+
if_not_exists,
5410+
temporary,
5411+
} => {
5412+
assert_eq!("myschema.myview", name.to_string());
5413+
assert_eq!(Vec::<Ident>::new(), columns);
5414+
assert_eq!("SELECT foo FROM bar", query.to_string());
5415+
assert!(!materialized);
5416+
assert!(!or_replace);
5417+
assert_eq!(with_options, vec![]);
5418+
assert_eq!(cluster_by, vec![]);
5419+
assert!(!late_binding);
5420+
assert!(!if_not_exists);
5421+
assert!(temporary);
53835422
}
53845423
_ => unreachable!(),
53855424
}
@@ -5398,6 +5437,8 @@ fn parse_create_or_replace_view() {
53985437
materialized,
53995438
cluster_by,
54005439
with_no_schema_binding: late_binding,
5440+
if_not_exists,
5441+
temporary,
54015442
} => {
54025443
assert_eq!("v", name.to_string());
54035444
assert_eq!(columns, vec![]);
@@ -5407,6 +5448,8 @@ fn parse_create_or_replace_view() {
54075448
assert!(or_replace);
54085449
assert_eq!(cluster_by, vec![]);
54095450
assert!(!late_binding);
5451+
assert!(!if_not_exists);
5452+
assert!(!temporary);
54105453
}
54115454
_ => unreachable!(),
54125455
}
@@ -5429,6 +5472,8 @@ fn parse_create_or_replace_materialized_view() {
54295472
materialized,
54305473
cluster_by,
54315474
with_no_schema_binding: late_binding,
5475+
if_not_exists,
5476+
temporary,
54325477
} => {
54335478
assert_eq!("v", name.to_string());
54345479
assert_eq!(columns, vec![]);
@@ -5438,6 +5483,8 @@ fn parse_create_or_replace_materialized_view() {
54385483
assert!(or_replace);
54395484
assert_eq!(cluster_by, vec![]);
54405485
assert!(!late_binding);
5486+
assert!(!if_not_exists);
5487+
assert!(!temporary);
54415488
}
54425489
_ => unreachable!(),
54435490
}
@@ -5456,6 +5503,8 @@ fn parse_create_materialized_view() {
54565503
with_options,
54575504
cluster_by,
54585505
with_no_schema_binding: late_binding,
5506+
if_not_exists,
5507+
temporary,
54595508
} => {
54605509
assert_eq!("myschema.myview", name.to_string());
54615510
assert_eq!(Vec::<Ident>::new(), columns);
@@ -5465,6 +5514,8 @@ fn parse_create_materialized_view() {
54655514
assert!(!or_replace);
54665515
assert_eq!(cluster_by, vec![]);
54675516
assert!(!late_binding);
5517+
assert!(!if_not_exists);
5518+
assert!(!temporary);
54685519
}
54695520
_ => unreachable!(),
54705521
}
@@ -5483,6 +5534,8 @@ fn parse_create_materialized_view_with_cluster_by() {
54835534
with_options,
54845535
cluster_by,
54855536
with_no_schema_binding: late_binding,
5537+
if_not_exists,
5538+
temporary,
54865539
} => {
54875540
assert_eq!("myschema.myview", name.to_string());
54885541
assert_eq!(Vec::<Ident>::new(), columns);
@@ -5492,6 +5545,8 @@ fn parse_create_materialized_view_with_cluster_by() {
54925545
assert!(!or_replace);
54935546
assert_eq!(cluster_by, vec![Ident::new("foo")]);
54945547
assert!(!late_binding);
5548+
assert!(!if_not_exists);
5549+
assert!(!temporary);
54955550
}
54965551
_ => unreachable!(),
54975552
}

tests/sqlparser_sqlite.rs

+31
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,37 @@ fn parse_create_virtual_table() {
6161
sqlite_and_generic().verified_stmt(sql);
6262
}
6363

64+
#[test]
65+
fn parse_create_view_temporary_if_not_exists() {
66+
let sql = "CREATE TEMPORARY VIEW IF NOT EXISTS myschema.myview AS SELECT foo FROM bar";
67+
match sqlite_and_generic().verified_stmt(sql) {
68+
Statement::CreateView {
69+
name,
70+
columns,
71+
query,
72+
or_replace,
73+
materialized,
74+
with_options,
75+
cluster_by,
76+
with_no_schema_binding: late_binding,
77+
if_not_exists,
78+
temporary,
79+
} => {
80+
assert_eq!("myschema.myview", name.to_string());
81+
assert_eq!(Vec::<Ident>::new(), columns);
82+
assert_eq!("SELECT foo FROM bar", query.to_string());
83+
assert!(!materialized);
84+
assert!(!or_replace);
85+
assert_eq!(with_options, vec![]);
86+
assert_eq!(cluster_by, vec![]);
87+
assert!(!late_binding);
88+
assert!(if_not_exists);
89+
assert!(temporary);
90+
}
91+
_ => unreachable!(),
92+
}
93+
}
94+
6495
#[test]
6596
fn double_equality_operator() {
6697
// Sqlite supports this operator: https://www.sqlite.org/lang_expr.html#binaryops

0 commit comments

Comments
 (0)