redshift: add support for CREATE VIEW … WITH NO SCHEMA BINDING (#979)

This commit is contained in:
Lukasz Stefaniak 2023-10-02 19:42:01 +02:00 committed by GitHub
parent 40e2ecbdf3
commit c811e22605
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 2 deletions

View file

@ -577,7 +577,7 @@ pub enum Expr {
/// ///
/// Syntax: /// Syntax:
/// ```sql /// ```sql
/// MARCH (<col>, <col>, ...) AGAINST (<expr> [<search modifier>]) /// MATCH (<col>, <col>, ...) AGAINST (<expr> [<search modifier>])
/// ///
/// <col> = CompoundIdentifier /// <col> = CompoundIdentifier
/// <expr> = String literal /// <expr> = String literal
@ -1316,6 +1316,8 @@ pub enum Statement {
query: Box<Query>, query: Box<Query>,
with_options: Vec<SqlOption>, with_options: Vec<SqlOption>,
cluster_by: Vec<Ident>, cluster_by: Vec<Ident>,
/// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
with_no_schema_binding: bool,
}, },
/// CREATE TABLE /// CREATE TABLE
CreateTable { CreateTable {
@ -2271,6 +2273,7 @@ impl fmt::Display for Statement {
materialized, materialized,
with_options, with_options,
cluster_by, cluster_by,
with_no_schema_binding,
} => { } => {
write!( write!(
f, f,
@ -2288,7 +2291,11 @@ impl fmt::Display for Statement {
if !cluster_by.is_empty() { if !cluster_by.is_empty() {
write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?; write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?;
} }
write!(f, " AS {query}") write!(f, " AS {query}")?;
if *with_no_schema_binding {
write!(f, " WITH NO SCHEMA BINDING")?;
}
Ok(())
} }
Statement::CreateTable { Statement::CreateTable {
name, name,

View file

@ -110,6 +110,7 @@ define_keywords!(
BIGINT, BIGINT,
BIGNUMERIC, BIGNUMERIC,
BINARY, BINARY,
BINDING,
BLOB, BLOB,
BLOOMFILTER, BLOOMFILTER,
BOOL, BOOL,

View file

@ -2974,6 +2974,15 @@ impl<'a> Parser<'a> {
self.expect_keyword(Keyword::AS)?; self.expect_keyword(Keyword::AS)?;
let query = Box::new(self.parse_query()?); let query = Box::new(self.parse_query()?);
// Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here. // Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here.
let with_no_schema_binding = dialect_of!(self is RedshiftSqlDialect | GenericDialect)
&& self.parse_keywords(&[
Keyword::WITH,
Keyword::NO,
Keyword::SCHEMA,
Keyword::BINDING,
]);
Ok(Statement::CreateView { Ok(Statement::CreateView {
name, name,
columns, columns,
@ -2982,6 +2991,7 @@ impl<'a> Parser<'a> {
or_replace, or_replace,
with_options, with_options,
cluster_by, cluster_by,
with_no_schema_binding,
}) })
} }

View file

@ -5320,6 +5320,7 @@ fn parse_create_view() {
materialized, materialized,
with_options, with_options,
cluster_by, cluster_by,
with_no_schema_binding: late_binding,
} => { } => {
assert_eq!("myschema.myview", name.to_string()); assert_eq!("myschema.myview", name.to_string());
assert_eq!(Vec::<Ident>::new(), columns); assert_eq!(Vec::<Ident>::new(), columns);
@ -5328,6 +5329,7 @@ fn parse_create_view() {
assert!(!or_replace); assert!(!or_replace);
assert_eq!(with_options, vec![]); assert_eq!(with_options, vec![]);
assert_eq!(cluster_by, vec![]); assert_eq!(cluster_by, vec![]);
assert!(!late_binding);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -5368,6 +5370,7 @@ fn parse_create_view_with_columns() {
query, query,
materialized, materialized,
cluster_by, cluster_by,
with_no_schema_binding: late_binding,
} => { } => {
assert_eq!("v", name.to_string()); assert_eq!("v", name.to_string());
assert_eq!(columns, vec![Ident::new("has"), Ident::new("cols")]); assert_eq!(columns, vec![Ident::new("has"), Ident::new("cols")]);
@ -5376,6 +5379,7 @@ fn parse_create_view_with_columns() {
assert!(!materialized); assert!(!materialized);
assert!(!or_replace); assert!(!or_replace);
assert_eq!(cluster_by, vec![]); assert_eq!(cluster_by, vec![]);
assert!(!late_binding);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -5393,6 +5397,7 @@ fn parse_create_or_replace_view() {
query, query,
materialized, materialized,
cluster_by, cluster_by,
with_no_schema_binding: late_binding,
} => { } => {
assert_eq!("v", name.to_string()); assert_eq!("v", name.to_string());
assert_eq!(columns, vec![]); assert_eq!(columns, vec![]);
@ -5401,6 +5406,7 @@ fn parse_create_or_replace_view() {
assert!(!materialized); assert!(!materialized);
assert!(or_replace); assert!(or_replace);
assert_eq!(cluster_by, vec![]); assert_eq!(cluster_by, vec![]);
assert!(!late_binding);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -5422,6 +5428,7 @@ fn parse_create_or_replace_materialized_view() {
query, query,
materialized, materialized,
cluster_by, cluster_by,
with_no_schema_binding: late_binding,
} => { } => {
assert_eq!("v", name.to_string()); assert_eq!("v", name.to_string());
assert_eq!(columns, vec![]); assert_eq!(columns, vec![]);
@ -5430,6 +5437,7 @@ fn parse_create_or_replace_materialized_view() {
assert!(materialized); assert!(materialized);
assert!(or_replace); assert!(or_replace);
assert_eq!(cluster_by, vec![]); assert_eq!(cluster_by, vec![]);
assert!(!late_binding);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -5447,6 +5455,7 @@ fn parse_create_materialized_view() {
materialized, materialized,
with_options, with_options,
cluster_by, cluster_by,
with_no_schema_binding: late_binding,
} => { } => {
assert_eq!("myschema.myview", name.to_string()); assert_eq!("myschema.myview", name.to_string());
assert_eq!(Vec::<Ident>::new(), columns); assert_eq!(Vec::<Ident>::new(), columns);
@ -5455,6 +5464,7 @@ fn parse_create_materialized_view() {
assert_eq!(with_options, vec![]); assert_eq!(with_options, vec![]);
assert!(!or_replace); assert!(!or_replace);
assert_eq!(cluster_by, vec![]); assert_eq!(cluster_by, vec![]);
assert!(!late_binding);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -5472,6 +5482,7 @@ fn parse_create_materialized_view_with_cluster_by() {
materialized, materialized,
with_options, with_options,
cluster_by, cluster_by,
with_no_schema_binding: late_binding,
} => { } => {
assert_eq!("myschema.myview", name.to_string()); assert_eq!("myschema.myview", name.to_string());
assert_eq!(Vec::<Ident>::new(), columns); assert_eq!(Vec::<Ident>::new(), columns);
@ -5480,6 +5491,7 @@ fn parse_create_materialized_view_with_cluster_by() {
assert_eq!(with_options, vec![]); assert_eq!(with_options, vec![]);
assert!(!or_replace); assert!(!or_replace);
assert_eq!(cluster_by, vec![Ident::new("foo")]); assert_eq!(cluster_by, vec![Ident::new("foo")]);
assert!(!late_binding);
} }
_ => unreachable!(), _ => unreachable!(),
} }

View file

@ -16,6 +16,7 @@ mod test_utils;
use test_utils::*; use test_utils::*;
use sqlparser::ast::*; use sqlparser::ast::*;
use sqlparser::dialect::GenericDialect;
use sqlparser::dialect::RedshiftSqlDialect; use sqlparser::dialect::RedshiftSqlDialect;
#[test] #[test]
@ -272,6 +273,13 @@ fn redshift() -> TestedDialects {
} }
} }
fn redshift_and_generic() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(RedshiftSqlDialect {}), Box::new(GenericDialect {})],
options: None,
}
}
#[test] #[test]
fn test_sharp() { fn test_sharp() {
let sql = "SELECT #_of_values"; let sql = "SELECT #_of_values";
@ -281,3 +289,9 @@ fn test_sharp() {
select.projection[0] select.projection[0]
); );
} }
#[test]
fn test_create_view_with_no_schema_binding() {
redshift_and_generic()
.verified_stmt("CREATE VIEW myevent AS SELECT eventname FROM event WITH NO SCHEMA BINDING");
}