diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 444fc1c015..677de2b494 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -3067,20 +3067,6 @@ pub struct CreateTable { /// Redshift `BACKUP` option: `BACKUP { YES | NO }` /// pub backup: Option, - /// `MULTISET | SET` table-kind prefix. - /// `Some(true)` => `MULTISET`, `Some(false)` => `SET`. - /// - /// [Teradata](https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/SQL-Data-Definition-Language-Syntax-and-Examples/Table-Statements/CREATE-TABLE-and-CREATE-TABLE-AS/Syntax-Elements/MULTISET-or-SET) - pub multiset: Option, - /// `FALLBACK` clause. - /// `Some(true)` => `FALLBACK`, `Some(false)` => `NO FALLBACK` - /// - /// [Teradata](https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/SQL-Data-Definition-Language-Syntax-and-Examples/Table-Statements/CREATE-TABLE-and-CREATE-TABLE-AS/Syntax-Elements/FALLBACK-or-NO-FALLBACK) - pub fallback: Option, - /// `WITH DATA` clause on a `CREATE TABLE ... AS` statement. - /// - /// [Teradata](https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/SQL-Data-Definition-Language-Syntax-and-Examples/Table-Statements/CREATE-TABLE-and-CREATE-TABLE-AS/Syntax-Elements/AS_clause/WITH-Clause-Phrase) - pub with_data: Option, } impl fmt::Display for CreateTable { @@ -3094,7 +3080,7 @@ impl fmt::Display for CreateTable { // `CREATE TABLE t (a INT) AS SELECT a from t2` write!( f, - "CREATE {or_replace}{external}{global}{multiset}{temporary}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}", + "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}", or_replace = if self.or_replace { "OR REPLACE " } else { "" }, external = if self.external { "EXTERNAL " } else { "" }, snapshot = if self.snapshot { "SNAPSHOT " } else { "" }, @@ -3108,20 +3094,14 @@ impl fmt::Display for CreateTable { }) .unwrap_or(""), if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" }, - multiset = self - .multiset - .map(|m| if m { "MULTISET " } else { "SET " }) - .unwrap_or(""), temporary = if self.temporary { "TEMPORARY " } else { "" }, transient = if self.transient { "TRANSIENT " } else { "" }, volatile = if self.volatile { "VOLATILE " } else { "" }, + // Only for Snowflake iceberg = if self.iceberg { "ICEBERG " } else { "" }, dynamic = if self.dynamic { "DYNAMIC " } else { "" }, name = self.name, )?; - if let Some(fallback) = self.fallback { - write!(f, ", {}", if fallback { "FALLBACK" } else { "NO FALLBACK" })?; - } if let Some(partition_of) = &self.partition_of { write!(f, " PARTITION OF {partition_of}")?; } @@ -3409,41 +3389,6 @@ impl fmt::Display for CreateTable { if let Some(query) = &self.query { write!(f, " AS {query}")?; } - if let Some(with_data) = &self.with_data { - write!(f, " {with_data}")?; - } - Ok(()) - } -} - -/// `WITH DATA` clause on `CREATE TABLE ... AS` statement. -/// -/// [Teradata](https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/SQL-Data-Definition-Language-Syntax-and-Examples/Table-Statements/CREATE-TABLE-and-CREATE-TABLE-AS/Syntax-Elements/AS_clause/WITH-Clause-Phrase) -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] -pub struct WithData { - /// `true` for `WITH DATA`, `false` for `WITH NO DATA`. - pub data: bool, - /// `Some(true)` for `AND STATISTICS`, `Some(false)` for `AND NO STATISTICS`, - /// `None` if the `AND [NO] STATISTICS` sub-clause is omitted. - pub statistics: Option, -} - -impl fmt::Display for WithData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("WITH ")?; - if !self.data { - f.write_str("NO ")?; - } - f.write_str("DATA")?; - if let Some(stats) = self.statistics { - f.write_str(" AND ")?; - if !stats { - f.write_str("NO ")?; - } - f.write_str("STATISTICS")?; - } Ok(()) } } diff --git a/src/ast/helpers/stmt_create_table.rs b/src/ast/helpers/stmt_create_table.rs index 9ec9ab28ce..fe91e0360f 100644 --- a/src/ast/helpers/stmt_create_table.rs +++ b/src/ast/helpers/stmt_create_table.rs @@ -29,7 +29,7 @@ use crate::ast::{ DistStyle, Expr, FileFormat, ForValues, HiveDistributionStyle, HiveFormat, Ident, InitializeKind, ObjectName, OnCommit, OneOrManyWithParens, Query, RefreshModeKind, RowAccessPolicy, Statement, StorageLifecyclePolicy, StorageSerializationPolicy, - TableConstraint, TableVersion, Tag, WithData, WrappedCollection, + TableConstraint, TableVersion, Tag, WrappedCollection, }; use crate::parser::ParserError; @@ -186,12 +186,6 @@ pub struct CreateTableBuilder { pub sortkey: Option>, /// Redshift `BACKUP` option. pub backup: Option, - /// `MULTISET | SET` table-kind prefix. - pub multiset: Option, - /// `FALLBACK` clause. - pub fallback: Option, - /// `WITH DATA` clause. - pub with_data: Option, } impl CreateTableBuilder { @@ -258,9 +252,6 @@ impl CreateTableBuilder { distkey: None, sortkey: None, backup: None, - multiset: None, - fallback: None, - with_data: None, } } /// Set `OR REPLACE` for the CREATE TABLE statement. @@ -574,22 +565,6 @@ impl CreateTableBuilder { self.backup = backup; self } - /// Set `MULTISET | SET` table-kind prefix. - /// Some(true) => `MULTISET`, Some(false) => `SET`. - pub fn multiset(mut self, multiset: Option) -> Self { - self.multiset = multiset; - self - } - /// Set `FALLBACK` / `NO FALLBACK` flag. - pub fn fallback(mut self, fallback: Option) -> Self { - self.fallback = fallback; - self - } - /// Set `WITH DATA` clause. - pub fn with_data(mut self, with_data: Option) -> Self { - self.with_data = with_data; - self - } /// Consume the builder and produce a `CreateTable`. pub fn build(self) -> CreateTable { CreateTable { @@ -653,9 +628,6 @@ impl CreateTableBuilder { distkey: self.distkey, sortkey: self.sortkey, backup: self.backup, - multiset: self.multiset, - fallback: self.fallback, - with_data: self.with_data, } } } @@ -738,9 +710,6 @@ impl From for CreateTableBuilder { distkey: table.distkey, sortkey: table.sortkey, backup: table.backup, - multiset: table.multiset, - fallback: table.fallback, - with_data: table.with_data, } } } diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 23944c4591..a7fc23e59e 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -83,7 +83,7 @@ pub use self::ddl::{ ReplicaIdentity, TagsColumnOption, TextSearchObjectType, TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation, UserDefinedTypeSqlDefinitionOption, - UserDefinedTypeStorage, ViewColumnDef, WithData, + UserDefinedTypeStorage, ViewColumnDef, }; pub use self::dml::{ Delete, Insert, Merge, MergeAction, MergeClause, MergeClauseKind, MergeInsertExpr, diff --git a/src/ast/spans.rs b/src/ast/spans.rs index cd4034c7da..13285f5b01 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -609,9 +609,6 @@ impl Spanned for CreateTable { distkey: _, sortkey: _, backup: _, - multiset: _, - fallback: _, - with_data: _, } = self; union_spans( diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 4b791d8ed6..881a69af49 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -30,7 +30,6 @@ mod redshift; mod snowflake; mod spark; mod sqlite; -mod teradata; use core::any::{Any, TypeId}; use core::fmt::Debug; @@ -55,7 +54,6 @@ pub use self::snowflake::parse_snowflake_stage_name; pub use self::snowflake::SnowflakeDialect; pub use self::spark::SparkSqlDialect; pub use self::sqlite::SQLiteDialect; -pub use self::teradata::TeradataDialect; /// Macro for streamlining the creation of derived `Dialect` objects. /// The generated struct includes `new()` and `default()` constructors. @@ -1226,16 +1224,6 @@ pub trait Dialect: Debug + Any { false } - /// Returns true if the dialect accepts a comma-separated list of table-level - /// options placed between the table name and the column-list parenthesis, e.g. - /// - /// ```sql - /// CREATE TABLE foo, NO FALLBACK, NO BEFORE JOURNAL (col INTEGER) - /// ``` - fn supports_leading_comma_before_table_options(&self) -> bool { - false - } - /// Returns true if the dialect supports PartiQL for querying semi-structured data /// fn supports_partiql(&self) -> bool { @@ -1886,7 +1874,6 @@ pub fn dialect_from_str(dialect_name: impl AsRef) -> Option Some(Box::new(DatabricksDialect {})), "spark" | "sparksql" => Some(Box::new(SparkSqlDialect {})), "oracle" => Some(Box::new(OracleDialect {})), - "teradata" => Some(Box::new(TeradataDialect {})), _ => None, } } @@ -1940,8 +1927,6 @@ mod tests { assert!(parse_dialect("DuckDb").is::()); assert!(parse_dialect("DataBricks").is::()); assert!(parse_dialect("databricks").is::()); - assert!(parse_dialect("teradata").is::()); - assert!(parse_dialect("Teradata").is::()); // error cases assert!(dialect_from_str("Unknown").is_none()); diff --git a/src/dialect/teradata.rs b/src/dialect/teradata.rs deleted file mode 100644 index c8470cb642..0000000000 --- a/src/dialect/teradata.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use crate::dialect::Dialect; - -/// A [`Dialect`] for [Teradata](https://docs.teradata.com/). -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TeradataDialect; - -impl Dialect for TeradataDialect { - /// See - fn identifier_quote_style(&self, _identifier: &str) -> Option { - Some('"') - } - - /// See - fn is_delimited_identifier_start(&self, ch: char) -> bool { - ch == '"' - } - - /// See - fn is_identifier_start(&self, ch: char) -> bool { - ch.is_alphabetic() || ch == '_' || ch == '#' || ch == '$' - } - - // See - fn is_identifier_part(&self, ch: char) -> bool { - ch.is_alphanumeric() || self.is_identifier_start(ch) - } - - /// See - fn supports_group_by_expr(&self) -> bool { - true - } - - /// Teradata has no native `BOOLEAN` data type. - /// - /// See - fn supports_boolean_literals(&self) -> bool { - false - } - - /// See - fn require_interval_qualifier(&self) -> bool { - true - } - - /// See - fn supports_comment_on(&self) -> bool { - true - } - - /// See - fn supports_create_table_select(&self) -> bool { - true - } - - /// See - fn supports_execute_immediate(&self) -> bool { - true - } - - /// See - fn supports_top_before_distinct(&self) -> bool { - true - } - - /// See - fn supports_window_function_null_treatment_arg(&self) -> bool { - true - } - - /// See - fn supports_string_literal_concatenation(&self) -> bool { - true - } - - /// See - fn supports_leading_comma_before_table_options(&self) -> bool { - true - } -} diff --git a/src/keywords.rs b/src/keywords.rs index 0ff32948f0..bfb3a9a146 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -417,7 +417,6 @@ define_keywords!( FACTS, FAIL, FAILOVER, - FALLBACK, FALSE, FAMILY, FETCH, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d36e1adcd1..9fe2b6f2e9 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -5224,7 +5224,6 @@ impl<'a> Parser<'a> { pub fn parse_create(&mut self) -> Result { let or_replace = self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]); let or_alter = self.parse_keywords(&[Keyword::OR, Keyword::ALTER]); - let multiset = self.maybe_parse_multiset(); let local = self.parse_one_of_keywords(&[Keyword::LOCAL]).is_some(); let global = self.parse_one_of_keywords(&[Keyword::GLOBAL]).is_some(); let transient = self.parse_one_of_keywords(&[Keyword::TRANSIENT]).is_some(); @@ -5238,7 +5237,6 @@ impl<'a> Parser<'a> { let temporary = self .parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY]) .is_some(); - let volatile = self.parse_keyword(Keyword::VOLATILE); let persistent = dialect_of!(self is DuckDbDialect) && self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some(); let create_view_params = self.parse_create_view_params()?; @@ -5247,7 +5245,7 @@ impl<'a> Parser<'a> { } else if self.peek_keywords(&[Keyword::TEXT, Keyword::SEARCH]) { self.parse_create_text_search().map(Into::into) } else if self.parse_keyword(Keyword::TABLE) { - self.parse_create_table(or_replace, temporary, global, transient, volatile, multiset) + self.parse_create_table(or_replace, temporary, global, transient) .map(Into::into) } else if self.peek_keyword(Keyword::MATERIALIZED) || self.peek_keyword(Keyword::VIEW) @@ -8663,25 +8661,11 @@ impl<'a> Parser<'a> { temporary: bool, global: Option, transient: bool, - volatile: bool, - multiset: Option, ) -> Result { let allow_unquoted_hyphen = dialect_of!(self is BigQueryDialect); let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let table_name = self.parse_object_name(allow_unquoted_hyphen)?; - let fallback = if self.dialect.supports_leading_comma_before_table_options() - && self.consume_token(&Token::Comma) - { - let fallback = self.maybe_parse_fallback()?; - if fallback.is_none() { - self.prev_token(); // Put back comma. - } - fallback - } else { - None - }; - // PostgreSQL PARTITION OF for child partition tables // Note: This is a PostgreSQL-specific feature, but the dialect check was intentionally // removed to allow GenericDialect and other dialects to parse this syntax. This enables @@ -8833,13 +8817,6 @@ impl<'a> Parser<'a> { None }; - // `WITH DATA` clause only applies if there is a query body. - let with_data = if query.is_some() { - self.maybe_parse_with_data()? - } else { - None - }; - Ok(CreateTableBuilder::new(table_name) .temporary(temporary) .columns(columns) @@ -8847,9 +8824,6 @@ impl<'a> Parser<'a> { .or_replace(or_replace) .if_not_exists(if_not_exists) .transient(transient) - .volatile(volatile) - .multiset(multiset) - .fallback(fallback) .hive_distribution(hive_distribution) .hive_formats(hive_formats) .global(global) @@ -8869,7 +8843,6 @@ impl<'a> Parser<'a> { .for_values(for_values) .table_options(create_table_config.table_options) .primary_key(primary_key) - .with_data(with_data) .strict(strict) .backup(backup) .diststyle(diststyle) @@ -8878,47 +8851,6 @@ impl<'a> Parser<'a> { .build()) } - /// Parse `MULTISET` table-kind prefix on `CREATE TABLE`. - fn maybe_parse_multiset(&mut self) -> Option { - match self.parse_one_of_keywords(&[Keyword::SET, Keyword::MULTISET]) { - Some(Keyword::MULTISET) => Some(true), - Some(Keyword::SET) => Some(false), - _ => None, - } - } - - /// Parse `FALLBACK` option on a `CREATE TABLE` statement, - fn maybe_parse_fallback(&mut self) -> Result, ParserError> { - if self.parse_keywords(&[Keyword::NO, Keyword::FALLBACK]) { - Ok(Some(false)) - } else if self.parse_keyword(Keyword::FALLBACK) { - Ok(Some(true)) - } else { - Ok(None) - } - } - - /// Parse [`WithData`] clause on `CREATE TABLE ... AS` statement. - fn maybe_parse_with_data(&mut self) -> Result, ParserError> { - let data = if self.parse_keywords(&[Keyword::WITH, Keyword::DATA]) { - true - } else if self.parse_keywords(&[Keyword::WITH, Keyword::NO, Keyword::DATA]) { - false - } else { - return Ok(None); - }; - - let statistics = if self.parse_keywords(&[Keyword::AND, Keyword::STATISTICS]) { - Some(true) - } else if self.parse_keywords(&[Keyword::AND, Keyword::NO, Keyword::STATISTICS]) { - Some(false) - } else { - None - }; - - Ok(Some(WithData { data, statistics })) - } - fn maybe_parse_create_table_like( &mut self, allow_unquoted_hyphen: bool, diff --git a/src/test_utils.rs b/src/test_utils.rs index c4d1d0db2e..669ea1ecdb 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -292,7 +292,6 @@ pub fn all_dialects() -> TestedDialects { Box::new(DatabricksDialect {}), Box::new(ClickHouseDialect {}), Box::new(OracleDialect {}), - Box::new(TeradataDialect {}), ]) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index be3026f637..a96e4facd2 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -18706,7 +18706,7 @@ fn test_parse_semantic_view_table_factor() { #[test] fn parse_adjacent_string_literal_concatenation() { - let sql = r#"SELECT 'M' 'y' 'S' 'q' 'l'"#; + let sql = r#"SELECT 'M' "y" 'S' "q" 'l'"#; let dialects = all_dialects_where(|d| d.supports_string_literal_concatenation()); dialects.one_statement_parses_to(sql, r"SELECT 'MySql'"); diff --git a/tests/sqlparser_duckdb.rs b/tests/sqlparser_duckdb.rs index 86c7658131..f1b492c03b 100644 --- a/tests/sqlparser_duckdb.rs +++ b/tests/sqlparser_duckdb.rs @@ -795,9 +795,6 @@ fn test_duckdb_union_datatype() { distkey: Default::default(), sortkey: Default::default(), backup: Default::default(), - multiset: Default::default(), - fallback: Default::default(), - with_data: Default::default(), }), stmt ); diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 6e866746d7..7168f0ad23 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -2014,9 +2014,6 @@ fn parse_create_table_with_valid_options() { distkey: None, sortkey: None, backup: None, - multiset: None, - fallback: None, - with_data: None, }) ); } @@ -2192,9 +2189,6 @@ fn parse_create_table_with_identity_column() { distkey: None, sortkey: None, backup: None, - multiset: None, - fallback: None, - with_data: None, }), ); } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index a61dd9afea..379d37c0c9 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -6753,9 +6753,6 @@ fn parse_trigger_related_functions() { distkey: None, sortkey: None, backup: None, - multiset: None, - fallback: None, - with_data: None, } ); diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 6bebd58633..65c26c3a53 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -471,6 +471,13 @@ fn test_snowflake_create_invalid_temporal_table() { )) ); + assert_eq!( + snowflake().parse_sql_statements("CREATE TEMP VOLATILE TABLE my_table (a INT)"), + Err(ParserError::ParserError( + "Expected: an object type after CREATE, found: VOLATILE".to_string() + )) + ); + assert_eq!( snowflake().parse_sql_statements("CREATE TEMP TRANSIENT TABLE my_table (a INT)"), Err(ParserError::ParserError( @@ -484,7 +491,7 @@ fn test_snowflake_create_invalid_temporal_file_format() { assert_eq!( snowflake().parse_sql_statements("CREATE TEMPORARY VOLATILE FILE FORMAT my_fmt"), Err(ParserError::ParserError( - "Expected: an object type after CREATE, found: FILE".to_string() + "Expected: an object type after CREATE, found: VOLATILE".to_string() )) ); } diff --git a/tests/sqlparser_teradata.rs b/tests/sqlparser_teradata.rs deleted file mode 100644 index a4e66af0d9..0000000000 --- a/tests/sqlparser_teradata.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -//! Test SQL syntax, specific to [sqlparser::dialect::TeradataDialect]. - -use sqlparser::dialect::{Dialect, GenericDialect, TeradataDialect}; -use sqlparser::test_utils::all_dialects_where; -use test_utils::TestedDialects; - -mod test_utils; - -fn teradata() -> TestedDialects { - TestedDialects::new(vec![Box::new(TeradataDialect)]) -} - -fn teradata_and_generic() -> TestedDialects { - TestedDialects::new(vec![Box::new(TeradataDialect), Box::new(GenericDialect {})]) -} - -#[test] -fn dialect_methods() { - let d: &dyn Dialect = &TeradataDialect; - assert_eq!(d.identifier_quote_style("x"), Some('"')); - assert!(d.is_delimited_identifier_start('"')); - assert!(!d.is_delimited_identifier_start('`')); - assert!(d.is_identifier_start('$')); - assert!(d.is_identifier_start('#')); - assert!(d.is_identifier_part('$')); - assert!(d.is_identifier_part('#')); - assert!(d.supports_group_by_expr()); - assert!(!d.supports_boolean_literals()); - assert!(d.require_interval_qualifier()); - assert!(d.supports_comment_on()); - assert!(d.supports_create_table_select()); - assert!(d.supports_execute_immediate()); - assert!(d.supports_top_before_distinct()); - assert!(d.supports_window_function_null_treatment_arg()); - assert!(d.supports_string_literal_concatenation()); - assert!(d.supports_leading_comma_before_table_options()); -} - -#[test] -fn parse_identifier() { - teradata().verified_stmt(concat!( - "SELECT ", - "NULL AS foo, ", - "NULL AS _bar, ", - "NULL AS #baz, ", - "NULL AS $qux, ", - "NULL AS a$1, ", - "NULL AS a#1, ", - "NULL AS a_1, ", - r#"NULL AS "quoted id""# - )); -} - -#[test] -fn parse_create_table_multiset() { - teradata_and_generic().verified_stmt("CREATE MULTISET TABLE foo (id INT)"); - teradata_and_generic().verified_stmt("CREATE SET TABLE foo (id INT)"); -} - -#[test] -fn parse_create_table_volatile() { - teradata_and_generic().verified_stmt("CREATE VOLATILE TABLE foo (id INT)"); - teradata_and_generic().verified_stmt("CREATE MULTISET VOLATILE TABLE foo (id INT)"); -} - -#[test] -fn parse_create_table_fallback() { - teradata().verified_stmt("CREATE TABLE foo, FALLBACK (id INT)"); - teradata().verified_stmt("CREATE TABLE foo, NO FALLBACK (id INT)"); - teradata().verified_stmt("CREATE MULTISET TABLE foo, NO FALLBACK (id INT)"); -} - -#[test] -fn parse_create_table_as_with_data() { - teradata_and_generic().verified_stmt("CREATE TABLE foo AS (SELECT 1 AS a) WITH DATA"); - teradata_and_generic().verified_stmt("CREATE TABLE foo AS (SELECT 1 AS a) WITH NO DATA"); - teradata_and_generic() - .verified_stmt("CREATE TABLE foo AS (SELECT 1 AS a) WITH DATA AND STATISTICS"); - teradata_and_generic() - .verified_stmt("CREATE TABLE foo AS (SELECT 1 AS a) WITH DATA AND NO STATISTICS"); - teradata_and_generic() - .verified_stmt("CREATE TABLE foo AS (SELECT 1 AS a) WITH NO DATA AND STATISTICS"); - teradata_and_generic() - .verified_stmt("CREATE TABLE foo AS (SELECT 1 AS a) WITH NO DATA AND NO STATISTICS"); -} - -#[test] -fn parse_create_table_options() { - teradata().verified_stmt(concat!( - "CREATE MULTISET VOLATILE TABLE foo, NO FALLBACK ", - "(id INT, name VARCHAR(100)) ", - "ON COMMIT PRESERVE ROWS" - )); -} - -#[test] -fn parse_leading_comma_before_table_options() { - let dialect = all_dialects_where(|d| d.supports_leading_comma_before_table_options()); - dialect.verified_stmt("CREATE TABLE foo, FALLBACK (id INT)"); - - let unsupported_dialects = - all_dialects_where(|d| !d.supports_leading_comma_before_table_options()); - assert!(unsupported_dialects - .parse_sql_statements("CREATE TABLE foo, FALLBACK (id INT)") - .is_err()); -}