diff --git a/src/ast/mod.rs b/src/ast/mod.rs index eb8830bb1..11bc37613 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -577,7 +577,7 @@ pub enum Expr { /// /// Syntax: /// ```sql - /// MARCH (, , ...) AGAINST ( []) + /// MATCH (, , ...) AGAINST ( []) /// /// = CompoundIdentifier /// = String literal @@ -1312,6 +1312,7 @@ pub enum Statement { query: Box, with_options: Vec, cluster_by: Vec, + late_binding: bool, }, /// CREATE TABLE CreateTable { @@ -2241,6 +2242,7 @@ impl fmt::Display for Statement { materialized, with_options, cluster_by, + late_binding, } => { write!( f, @@ -2258,7 +2260,11 @@ impl fmt::Display for Statement { if !cluster_by.is_empty() { write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?; } - write!(f, " AS {query}") + write!(f, " AS {query}")?; + if *late_binding { + write!(f, " WITH NO SCHEMA BINDING")?; + } + Ok(()) } Statement::CreateTable { name, diff --git a/src/keywords.rs b/src/keywords.rs index ad0526ccd..16aa36a72 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -109,6 +109,7 @@ define_keywords!( BIGINT, BIGNUMERIC, BINARY, + BINDING, BLOB, BLOOMFILTER, BOOL, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index ba8f5784f..fefe185a0 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -2957,6 +2957,15 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::AS)?; let query = Box::new(self.parse_query()?); // Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here. + + let late_binding = dialect_of!(self is RedshiftSqlDialect) + && self.parse_keywords(&[ + Keyword::WITH, + Keyword::NO, + Keyword::SCHEMA, + Keyword::BINDING, + ]); + Ok(Statement::CreateView { name, columns, @@ -2965,6 +2974,7 @@ impl<'a> Parser<'a> { or_replace, with_options, cluster_by, + late_binding, }) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 6f780de9e..a7e778e59 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -5310,6 +5310,7 @@ fn parse_create_view() { materialized, with_options, cluster_by, + late_binding, } => { assert_eq!("myschema.myview", name.to_string()); assert_eq!(Vec::::new(), columns); @@ -5318,6 +5319,7 @@ fn parse_create_view() { assert!(!or_replace); assert_eq!(with_options, vec![]); assert_eq!(cluster_by, vec![]); + assert_eq!(late_binding, false); } _ => unreachable!(), } @@ -5358,6 +5360,7 @@ fn parse_create_view_with_columns() { query, materialized, cluster_by, + late_binding, } => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![Ident::new("has"), Ident::new("cols")]); @@ -5366,6 +5369,7 @@ fn parse_create_view_with_columns() { assert!(!materialized); assert!(!or_replace); assert_eq!(cluster_by, vec![]); + assert_eq!(late_binding, false); } _ => unreachable!(), } @@ -5383,6 +5387,7 @@ fn parse_create_or_replace_view() { query, materialized, cluster_by, + late_binding, } => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![]); @@ -5391,6 +5396,7 @@ fn parse_create_or_replace_view() { assert!(!materialized); assert!(or_replace); assert_eq!(cluster_by, vec![]); + assert_eq!(late_binding, false); } _ => unreachable!(), } @@ -5412,6 +5418,7 @@ fn parse_create_or_replace_materialized_view() { query, materialized, cluster_by, + late_binding, } => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![]); @@ -5420,6 +5427,7 @@ fn parse_create_or_replace_materialized_view() { assert!(materialized); assert!(or_replace); assert_eq!(cluster_by, vec![]); + assert_eq!(late_binding, false); } _ => unreachable!(), } @@ -5437,6 +5445,7 @@ fn parse_create_materialized_view() { materialized, with_options, cluster_by, + late_binding, } => { assert_eq!("myschema.myview", name.to_string()); assert_eq!(Vec::::new(), columns); @@ -5445,6 +5454,7 @@ fn parse_create_materialized_view() { assert_eq!(with_options, vec![]); assert!(!or_replace); assert_eq!(cluster_by, vec![]); + assert_eq!(late_binding, false); } _ => unreachable!(), } @@ -5462,6 +5472,7 @@ fn parse_create_materialized_view_with_cluster_by() { materialized, with_options, cluster_by, + late_binding, } => { assert_eq!("myschema.myview", name.to_string()); assert_eq!(Vec::::new(), columns); @@ -5470,6 +5481,7 @@ fn parse_create_materialized_view_with_cluster_by() { assert_eq!(with_options, vec![]); assert!(!or_replace); assert_eq!(cluster_by, vec![Ident::new("foo")]); + assert_eq!(late_binding, false); } _ => unreachable!(), } diff --git a/tests/sqlparser_redshift.rs b/tests/sqlparser_redshift.rs index f17ca5841..5ac1e262f 100644 --- a/tests/sqlparser_redshift.rs +++ b/tests/sqlparser_redshift.rs @@ -281,3 +281,9 @@ fn test_sharp() { select.projection[0] ); } + +#[test] +fn test_create_view_late_binding() { + redshift() + .verified_stmt("CREATE VIEW myevent AS SELECT eventname FROM event WITH NO SCHEMA BINDING"); +}