mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-19 04:09:49 +00:00
Snowflake: Support CREATE VIEW myview IF NOT EXISTS
(#1961)
Some checks are pending
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Some checks are pending
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
This commit is contained in:
parent
15d8bfea62
commit
91273703d4
4 changed files with 56 additions and 6 deletions
|
@ -3255,6 +3255,17 @@ pub enum Statement {
|
||||||
materialized: bool,
|
materialized: bool,
|
||||||
/// View name
|
/// View name
|
||||||
name: ObjectName,
|
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.
|
||||||
|
/// Example:
|
||||||
|
/// ```sql
|
||||||
|
/// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
|
||||||
|
/// ```
|
||||||
|
/// Otherwise, the flag is set to false if the view name comes after the clause
|
||||||
|
/// Example:
|
||||||
|
/// ```sql
|
||||||
|
/// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
|
||||||
|
/// ```
|
||||||
|
name_before_not_exists: bool,
|
||||||
columns: Vec<ViewColumnDef>,
|
columns: Vec<ViewColumnDef>,
|
||||||
query: Box<Query>,
|
query: Box<Query>,
|
||||||
options: CreateTableOptions,
|
options: CreateTableOptions,
|
||||||
|
@ -4994,6 +5005,7 @@ impl fmt::Display for Statement {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists,
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -5006,11 +5018,18 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{materialized}{temporary}VIEW {if_not_exists}{name}{to}",
|
"{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")
|
||||||
|
} else {
|
||||||
|
format!("IF NOT EXISTS {name}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format!("{name}")
|
||||||
|
},
|
||||||
materialized = if *materialized { "MATERIALIZED " } else { "" },
|
materialized = if *materialized { "MATERIALIZED " } else { "" },
|
||||||
name = name,
|
|
||||||
temporary = if *temporary { "TEMPORARY " } else { "" },
|
temporary = if *temporary { "TEMPORARY " } else { "" },
|
||||||
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
|
|
||||||
to = to
|
to = to
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|to| format!(" TO {to}"))
|
.map(|to| format!(" TO {to}"))
|
||||||
|
|
|
@ -400,6 +400,7 @@ impl Spanned for Statement {
|
||||||
if_not_exists: _,
|
if_not_exists: _,
|
||||||
temporary: _,
|
temporary: _,
|
||||||
to,
|
to,
|
||||||
|
name_before_not_exists: _,
|
||||||
params: _,
|
params: _,
|
||||||
} => union_spans(
|
} => union_spans(
|
||||||
core::iter::once(name.span())
|
core::iter::once(name.span())
|
||||||
|
|
|
@ -5818,12 +5818,17 @@ impl<'a> Parser<'a> {
|
||||||
) -> Result<Statement, ParserError> {
|
) -> Result<Statement, ParserError> {
|
||||||
let materialized = self.parse_keyword(Keyword::MATERIALIZED);
|
let materialized = self.parse_keyword(Keyword::MATERIALIZED);
|
||||||
self.expect_keyword_is(Keyword::VIEW)?;
|
self.expect_keyword_is(Keyword::VIEW)?;
|
||||||
let if_not_exists = dialect_of!(self is BigQueryDialect|SQLiteDialect|GenericDialect)
|
let allow_unquoted_hyphen = dialect_of!(self is BigQueryDialect);
|
||||||
|
// Tries to parse IF NOT EXISTS either before name or after name
|
||||||
|
// Name before IF NOT EXISTS is supported by snowflake but undocumented
|
||||||
|
let if_not_exists_first =
|
||||||
|
self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
||||||
|
let name = self.parse_object_name(allow_unquoted_hyphen)?;
|
||||||
|
let name_before_not_exists = !if_not_exists_first
|
||||||
&& self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
&& self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
||||||
|
let if_not_exists = if_not_exists_first || name_before_not_exists;
|
||||||
// Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet).
|
// Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet).
|
||||||
// ANSI SQL and Postgres support RECURSIVE here, but we don't support it either.
|
// ANSI SQL and Postgres support RECURSIVE here, but we don't support it either.
|
||||||
let allow_unquoted_hyphen = dialect_of!(self is BigQueryDialect);
|
|
||||||
let name = self.parse_object_name(allow_unquoted_hyphen)?;
|
|
||||||
let columns = self.parse_view_columns()?;
|
let columns = self.parse_view_columns()?;
|
||||||
let mut options = CreateTableOptions::None;
|
let mut options = CreateTableOptions::None;
|
||||||
let with_options = self.parse_options(Keyword::WITH)?;
|
let with_options = self.parse_options(Keyword::WITH)?;
|
||||||
|
@ -5890,6 +5895,7 @@ impl<'a> Parser<'a> {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params: create_view_params,
|
params: create_view_params,
|
||||||
|
name_before_not_exists,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8058,6 +8058,7 @@ fn parse_create_view() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("myschema.myview", name.to_string());
|
assert_eq!("myschema.myview", name.to_string());
|
||||||
|
@ -8126,6 +8127,7 @@ fn parse_create_view_with_columns() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("v", name.to_string());
|
assert_eq!("v", name.to_string());
|
||||||
|
@ -8175,6 +8177,7 @@ fn parse_create_view_temporary() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("myschema.myview", name.to_string());
|
assert_eq!("myschema.myview", name.to_string());
|
||||||
|
@ -8214,6 +8217,7 @@ fn parse_create_or_replace_view() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("v", name.to_string());
|
assert_eq!("v", name.to_string());
|
||||||
|
@ -8257,6 +8261,7 @@ fn parse_create_or_replace_materialized_view() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("v", name.to_string());
|
assert_eq!("v", name.to_string());
|
||||||
|
@ -8296,6 +8301,7 @@ fn parse_create_materialized_view() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("myschema.myview", name.to_string());
|
assert_eq!("myschema.myview", name.to_string());
|
||||||
|
@ -8335,6 +8341,7 @@ fn parse_create_materialized_view_with_cluster_by() {
|
||||||
temporary,
|
temporary,
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
name_before_not_exists: _,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(or_alter, false);
|
assert_eq!(or_alter, false);
|
||||||
assert_eq!("myschema.myview", name.to_string());
|
assert_eq!("myschema.myview", name.to_string());
|
||||||
|
@ -16427,3 +16434,20 @@ fn parse_drop_stream() {
|
||||||
}
|
}
|
||||||
verified_stmt("DROP STREAM IF EXISTS s1");
|
verified_stmt("DROP STREAM IF EXISTS s1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_create_view_if_not_exists() {
|
||||||
|
// Name after IF NOT EXISTS
|
||||||
|
let sql: &'static str = "CREATE VIEW IF NOT EXISTS v AS SELECT 1";
|
||||||
|
let _ = all_dialects().verified_stmt(sql);
|
||||||
|
// Name before IF NOT EXISTS
|
||||||
|
let sql = "CREATE VIEW v IF NOT EXISTS AS SELECT 1";
|
||||||
|
let _ = all_dialects().verified_stmt(sql);
|
||||||
|
// Name missing from query
|
||||||
|
let sql = "CREATE VIEW IF NOT EXISTS AS SELECT 1";
|
||||||
|
let res = all_dialects().parse_sql_statements(sql);
|
||||||
|
assert_eq!(
|
||||||
|
ParserError::ParserError("Expected: AS, found: SELECT".to_string()),
|
||||||
|
res.unwrap_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue