From 23a0fc79f5c5b9f23e25bd18ea57ab8e400f07a1 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Wed, 6 Mar 2019 17:19:40 -0500 Subject: [PATCH] Support CREATE MATERIALIZED VIEW --- src/dialect/keywords.rs | 2 ++ src/sqlast/mod.rs | 6 ++++-- src/sqlparser.rs | 7 +++++-- tests/sqlparser_generic.rs | 16 +++++++++++++++- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/dialect/keywords.rs b/src/dialect/keywords.rs index d51e0cf2..e270e8a9 100644 --- a/src/dialect/keywords.rs +++ b/src/dialect/keywords.rs @@ -191,6 +191,7 @@ keyword!( LOCATION, LOWER, MATCH, + MATERIALIZED, MAX, MEMBER, MERGE, @@ -539,6 +540,7 @@ pub const ALL_KEYWORDS: &'static [&'static str] = &[ LOCATION, LOWER, MATCH, + MATERIALIZED, MAX, MEMBER, MERGE, diff --git a/src/sqlast/mod.rs b/src/sqlast/mod.rs index 0981eb89..a37a171c 100644 --- a/src/sqlast/mod.rs +++ b/src/sqlast/mod.rs @@ -241,6 +241,7 @@ pub enum SQLStatement { /// View name name: SQLObjectName, query: SQLQuery, + materialized: bool, }, /// CREATE TABLE SQLCreateTable { @@ -347,8 +348,9 @@ impl ToString for SQLStatement { } s } - SQLStatement::SQLCreateView { name, query } => { - format!("CREATE VIEW {} AS {}", name.to_string(), query.to_string()) + SQLStatement::SQLCreateView { name, query, materialized } => { + let modifier = if *materialized { " MATERIALIZED" } else { "" }; + format!("CREATE{} VIEW {} AS {}", modifier, name.to_string(), query.to_string()) } SQLStatement::SQLCreateTable { name, columns } => format!( "CREATE TABLE {} ({})", diff --git a/src/sqlparser.rs b/src/sqlparser.rs index 263e6e99..6b199724 100644 --- a/src/sqlparser.rs +++ b/src/sqlparser.rs @@ -617,7 +617,8 @@ impl Parser { pub fn parse_create(&mut self) -> Result { if self.parse_keyword("TABLE") { self.parse_create_table() - } else if self.parse_keyword("VIEW") { + } else if self.parse_keyword("MATERIALIZED") || self.parse_keyword("VIEW") { + self.prev_token(); self.parse_create_view() } else { parser_err!(format!( @@ -628,6 +629,8 @@ impl Parser { } pub fn parse_create_view(&mut self) -> Result { + let materialized = self.parse_keyword("MATERIALIZED"); + self.expect_keyword("VIEW")?; // Many dialects support `OR REPLACE` | `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 name = self.parse_object_name()?; @@ -637,7 +640,7 @@ impl Parser { self.expect_keyword("AS")?; let query = self.parse_query()?; // Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here. - Ok(SQLStatement::SQLCreateView { name, query }) + Ok(SQLStatement::SQLCreateView { name, query, materialized }) } pub fn parse_create_table(&mut self) -> Result { diff --git a/tests/sqlparser_generic.rs b/tests/sqlparser_generic.rs index e9be58ea..bbfeb447 100644 --- a/tests/sqlparser_generic.rs +++ b/tests/sqlparser_generic.rs @@ -901,9 +901,23 @@ fn parse_scalar_subqueries() { fn parse_create_view() { let sql = "CREATE VIEW myschema.myview AS SELECT foo FROM bar"; match verified_stmt(sql) { - SQLStatement::SQLCreateView { name, query } => { + SQLStatement::SQLCreateView { name, query, materialized } => { assert_eq!("myschema.myview", name.to_string()); assert_eq!("SELECT foo FROM bar", query.to_string()); + assert!(!materialized); + } + _ => assert!(false), + } +} + +#[test] +fn parse_create_materialized_view() { + let sql = "CREATE MATERIALIZED VIEW myschema.myview AS SELECT foo FROM bar"; + match verified_stmt(sql) { + SQLStatement::SQLCreateView { name, query, materialized } => { + assert_eq!("myschema.myview", name.to_string()); + assert_eq!("SELECT foo FROM bar", query.to_string()); + assert!(materialized); } _ => assert!(false), }