From b374f0eaefd00355a69220499bb03b219b164706 Mon Sep 17 00:00:00 2001 From: ifeanyi Date: Fri, 1 Dec 2023 18:43:01 +0100 Subject: [PATCH] Add support for BigQuery table and view options Extends the parser with BigQuery support for - Table/View level options - Column level options - Table creation configurations `CLUSTER BY`, `PARTITION BY` --- src/ast/ddl.rs | 35 +++++ src/ast/helpers/stmt_create_table.rs | 17 ++- src/ast/mod.rs | 91 ++++++++++++- src/parser/mod.rs | 98 +++++++++++++- tests/sqlparser_bigquery.rs | 183 +++++++++++++++++++++++++++ tests/sqlparser_common.rs | 79 +++++++----- tests/sqlparser_postgres.rs | 6 +- tests/sqlparser_sqlite.rs | 6 +- 8 files changed, 462 insertions(+), 53 deletions(-) diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 3192af8bb..8a785b9da 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -26,6 +26,7 @@ use sqlparser_derive::{Visit, VisitMut}; use crate::ast::value::escape_single_quote_string; use crate::ast::{ display_comma_separated, display_separated, DataType, Expr, Ident, ObjectName, SequenceOptions, + SqlOption, }; use crate::tokenizer::Token; @@ -527,6 +528,29 @@ impl fmt::Display for ColumnDef { } } +/// Column definition for a view. +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct ViewColumnDef { + pub name: Ident, + pub options: Option>, +} + +impl fmt::Display for ViewColumnDef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name)?; + if let Some(options) = self.options.as_ref() { + write!( + f, + " OPTIONS ({})", + display_comma_separated(options.as_slice()) + )?; + } + Ok(()) + } +} + /// An optionally-named `ColumnOption`: `[ CONSTRAINT ] `. /// /// Note that implementations are substantially more permissive than the ANSI @@ -601,6 +625,14 @@ pub enum ColumnOption { generation_expr: Option, generation_expr_mode: Option, }, + /// BigQuery specific: Explicit column options in a view [1] or table [2] + /// Syntax + /// ```sql + /// OPTIONS (description="field desc") + /// ``` + /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list + /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list + SqlOptions(Vec), } impl fmt::Display for ColumnOption { @@ -674,6 +706,9 @@ impl fmt::Display for ColumnOption { Ok(()) } } + SqlOptions(options) => { + write!(f, "OPTIONS ({})", display_comma_separated(options)) + } } } } diff --git a/src/ast/helpers/stmt_create_table.rs b/src/ast/helpers/stmt_create_table.rs index 17327e7f8..be31b10e1 100644 --- a/src/ast/helpers/stmt_create_table.rs +++ b/src/ast/helpers/stmt_create_table.rs @@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize}; use sqlparser_derive::{Visit, VisitMut}; use crate::ast::{ - ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, Ident, ObjectName, OnCommit, Query, - SqlOption, Statement, TableConstraint, + BigQueryCreateTableConfiguration, ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, + Ident, ObjectName, OnCommit, Query, SqlOption, Statement, TableConstraint, }; use crate::parser::ParserError; @@ -72,6 +72,7 @@ pub struct CreateTableBuilder { pub on_commit: Option, pub on_cluster: Option, pub order_by: Option>, + pub big_query_config: Option>, pub strict: bool, } @@ -105,6 +106,7 @@ impl CreateTableBuilder { on_commit: None, on_cluster: None, order_by: None, + big_query_config: None, strict: false, } } @@ -236,6 +238,14 @@ impl CreateTableBuilder { self } + pub fn big_query_config( + mut self, + big_query_config: Option>, + ) -> Self { + self.big_query_config = big_query_config; + self + } + pub fn strict(mut self, strict: bool) -> Self { self.strict = strict; self @@ -270,6 +280,7 @@ impl CreateTableBuilder { on_commit: self.on_commit, on_cluster: self.on_cluster, order_by: self.order_by, + big_query_config: self.big_query_config, strict: self.strict, } } @@ -310,6 +321,7 @@ impl TryFrom for CreateTableBuilder { on_commit, on_cluster, order_by, + big_query_config, strict, } => Ok(Self { or_replace, @@ -339,6 +351,7 @@ impl TryFrom for CreateTableBuilder { on_commit, on_cluster, order_by, + big_query_config, strict, }), _ => Err(ParserError::ParserError(format!( diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4769ea9bd..976aef50c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -33,7 +33,7 @@ pub use self::ddl::{ AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef, GeneratedAs, GeneratedExpressionMode, IndexType, KeyOrIndexDisplay, Partition, ProcedureParam, ReferentialAction, TableConstraint, UserDefinedTypeCompositeAttributeDef, - UserDefinedTypeRepresentation, + UserDefinedTypeRepresentation, ViewColumnDef, }; pub use self::operator::{BinaryOperator, UnaryOperator}; pub use self::query::{ @@ -1364,6 +1364,38 @@ pub enum Password { NullPassword, } +/// Sql options of a `CREATE TABLE` statement. +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub enum CreateTableOptions { + None, + /// Options specified using the `WITH` keyword. + /// e.g. `WITH (description = "123")` + /// + /// + With(Vec), + /// Options specified using the `OPTIONS` keyword. + /// e.g. `OPTIONS (description = "123")` + /// + /// + Options(Vec), +} + +impl fmt::Display for CreateTableOptions { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CreateTableOptions::With(with_options) => { + write!(f, "WITH ({})", display_comma_separated(with_options)) + } + CreateTableOptions::Options(options) => { + write!(f, "OPTIONS ({})", display_comma_separated(options)) + } + CreateTableOptions::None => Ok(()), + } + } +} + /// A top-level statement (SELECT, INSERT, CREATE, etc.) #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] @@ -1512,9 +1544,9 @@ pub enum Statement { materialized: bool, /// View name name: ObjectName, - columns: Vec, + columns: Vec, query: Box, - with_options: Vec, + options: CreateTableOptions, cluster_by: Vec, /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause with_no_schema_binding: bool, @@ -1560,6 +1592,9 @@ pub enum Statement { /// than empty (represented as ()), the latter meaning "no sorting". /// order_by: Option>, + /// BigQuery specific configuration during table creation. + /// + big_query_config: Option>, /// SQLite "STRICT" clause. /// if the "STRICT" table-option keyword is added to the end, after the closing ")", /// then strict typing rules apply to that table. @@ -2499,7 +2534,7 @@ impl fmt::Display for Statement { columns, query, materialized, - with_options, + options, cluster_by, with_no_schema_binding, if_not_exists, @@ -2514,8 +2549,8 @@ impl fmt::Display for Statement { temporary = if *temporary { "TEMPORARY " } else { "" }, if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" } )?; - if !with_options.is_empty() { - write!(f, " WITH ({})", display_comma_separated(with_options))?; + if matches!(options, CreateTableOptions::With(_)) { + write!(f, " {options}")?; } if !columns.is_empty() { write!(f, " ({})", display_comma_separated(columns))?; @@ -2523,6 +2558,9 @@ impl fmt::Display for Statement { if !cluster_by.is_empty() { write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?; } + if matches!(options, CreateTableOptions::Options(_)) { + write!(f, " {options}")?; + } write!(f, " AS {query}")?; if *with_no_schema_binding { write!(f, " WITH NO SCHEMA BINDING")?; @@ -2557,6 +2595,7 @@ impl fmt::Display for Statement { on_commit, on_cluster, order_by, + big_query_config, strict, } => { // We want to allow the following options @@ -2713,6 +2752,25 @@ impl fmt::Display for Statement { if let Some(order_by) = order_by { write!(f, " ORDER BY ({})", display_comma_separated(order_by))?; } + if let Some(bigquery_config) = big_query_config { + if let Some(partition_by) = bigquery_config.partition_by.as_ref() { + write!(f, " PARTITION BY {partition_by}")?; + } + if let Some(cluster_by) = bigquery_config.cluster_by.as_ref() { + write!( + f, + " CLUSTER BY {}", + display_comma_separated(cluster_by.as_slice()) + )?; + } + if let Some(options) = bigquery_config.options.as_ref() { + write!( + f, + " OPTIONS({})", + display_comma_separated(options.as_slice()) + )?; + } + } if let Some(query) = query { write!(f, " AS {query}")?; } @@ -4220,12 +4278,31 @@ pub struct HiveFormat { pub location: Option, } +/// Represents BigQuery specific configuration like partitioning, clustering +/// information during table creation. +/// +/// +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct BigQueryCreateTableConfiguration { + /// A partition expression for the table. + /// + pub partition_by: Option, + /// Table clustering column list. + /// + pub cluster_by: Option>, + /// Table options list. + /// + pub options: Option>, +} + #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct SqlOption { pub name: Ident, - pub value: Value, + pub value: Expr, } impl fmt::Display for SqlOption { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d9d4761c3..16bef84d2 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3357,8 +3357,12 @@ impl<'a> Parser<'a> { // 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. let name = self.parse_object_name()?; - let columns = self.parse_parenthesized_column_list(Optional, false)?; + let columns = self.parse_view_columns()?; + let mut options = CreateTableOptions::None; let with_options = self.parse_options(Keyword::WITH)?; + if !with_options.is_empty() { + options = CreateTableOptions::With(with_options); + } let cluster_by = if self.parse_keyword(Keyword::CLUSTER) { self.expect_keyword(Keyword::BY)?; @@ -3367,6 +3371,17 @@ impl<'a> Parser<'a> { vec![] }; + if dialect_of!(self is BigQueryDialect | GenericDialect) { + if let Token::Word(word) = self.peek_token().token { + if word.keyword == Keyword::OPTIONS { + let opts = self.parse_options(Keyword::OPTIONS)?; + if !opts.is_empty() { + options = CreateTableOptions::Options(opts); + } + } + }; + } + self.expect_keyword(Keyword::AS)?; let query = Box::new(self.parse_query()?); // Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here. @@ -3385,7 +3400,7 @@ impl<'a> Parser<'a> { query, materialized, or_replace, - with_options, + options, cluster_by, with_no_schema_binding, if_not_exists, @@ -4049,6 +4064,12 @@ impl<'a> Parser<'a> { None }; + let big_query_config = if dialect_of!(self is BigQueryDialect | GenericDialect) { + self.parse_optional_big_query_create_table_config()? + } else { + None + }; + // Parse optional `AS ( query )` let query = if self.parse_keyword(Keyword::AS) { Some(Box::new(self.parse_query()?)) @@ -4120,10 +4141,44 @@ impl<'a> Parser<'a> { .collation(collation) .on_commit(on_commit) .on_cluster(on_cluster) + .big_query_config(big_query_config) .strict(strict) .build()) } + /// Parse configuration like partitioning, clustering information during big-query table creation. + /// + fn parse_optional_big_query_create_table_config( + &mut self, + ) -> Result>, ParserError> { + let mut partition_by = None; + if self.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) { + partition_by = Some(self.parse_expr()?); + }; + + let mut cluster_by = None; + if self.parse_keywords(&[Keyword::CLUSTER, Keyword::BY]) { + cluster_by = Some(self.parse_comma_separated(Parser::parse_identifier)?); + }; + + let mut options = None; + if let Token::Word(word) = self.peek_token().token { + if word.keyword == Keyword::OPTIONS { + options = Some(self.parse_options(Keyword::OPTIONS)?); + } + }; + + if partition_by.is_some() || cluster_by.is_some() || options.is_some() { + Ok(Some(Box::new(BigQueryCreateTableConfiguration { + partition_by, + cluster_by, + options, + }))) + } else { + Ok(None) + } + } + pub fn parse_optional_procedure_parameters( &mut self, ) -> Result>, ParserError> { @@ -4282,6 +4337,13 @@ impl<'a> Parser<'a> { Ok(Some(ColumnOption::OnUpdate(expr))) } else if self.parse_keyword(Keyword::GENERATED) { self.parse_optional_column_option_generated() + } else if dialect_of!(self is BigQueryDialect | GenericDialect) + && self.parse_keyword(Keyword::OPTIONS) + { + self.prev_token(); + Ok(Some(ColumnOption::SqlOptions( + self.parse_options(Keyword::OPTIONS)?, + ))) } else { Ok(None) } @@ -4527,7 +4589,7 @@ impl<'a> Parser<'a> { pub fn parse_sql_option(&mut self) -> Result { let name = self.parse_identifier()?; self.expect_token(&Token::Eq)?; - let value = self.parse_value()?; + let value = self.parse_expr()?; Ok(SqlOption { name, value }) } @@ -5649,6 +5711,36 @@ impl<'a> Parser<'a> { } } + /// Parses a parenthesized, comma-separated list of column definitions within a view. + fn parse_view_columns(&mut self) -> Result, ParserError> { + if self.consume_token(&Token::LParen) { + if self.peek_token().token == Token::RParen { + self.next_token(); + Ok(vec![]) + } else { + let cols = self.parse_comma_separated(Parser::parse_view_column)?; + self.expect_token(&Token::RParen)?; + Ok(cols) + } + } else { + Ok(vec![]) + } + } + + /// Parses a column definition within a view. + fn parse_view_column(&mut self) -> Result { + let name = self.parse_identifier()?; + let options = if dialect_of!(self is BigQueryDialect | GenericDialect) + && self.parse_keyword(Keyword::OPTIONS) + { + self.prev_token(); + Some(self.parse_options(Keyword::OPTIONS)?) + } else { + None + }; + Ok(ViewColumnDef { name, options }) + } + /// Parse a parenthesized comma-separated list of unqualified, possibly quoted identifiers pub fn parse_parenthesized_column_list( &mut self, diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 04cca0b7c..99ce0bd3a 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -21,6 +21,18 @@ use sqlparser::dialect::{BigQueryDialect, GenericDialect}; use sqlparser::parser::ParserError; use test_utils::*; +/// Strips out newlines and spaces from the `sql` so that it can +/// be comparable with the serialized result +fn trim_sql(sql: &str) -> String { + sql.split('\n') + .filter(|line| !line.trim().is_empty()) + .map(|line| line.trim_start()) + .collect::>() + .join(" ") + .trim() + .to_string() +} + #[test] fn parse_literal_string() { let sql = r#"SELECT 'single', "double""#; @@ -86,6 +98,177 @@ fn parse_raw_literal() { panic!("invalid query") } +#[test] +fn parse_create_view_with_options() { + let sql = trim_sql( + r#" + CREATE VIEW myproject.mydataset.newview + (name, age OPTIONS (description = "field age")) + OPTIONS + (expiration_timestamp = TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 48 HOUR), + friendly_name = "newview", + description = "a view that expires in 2 days", + labels = [("org_unit", "development")]) + AS SELECT column_1, column_2, column_3 FROM myproject.mydataset.mytable"#, + ); + match bigquery().verified_stmt(sql.as_str()) { + Statement::CreateView { + name, + query, + options, + columns, + .. + } => { + assert_eq!( + name, + ObjectName(vec![ + "myproject".into(), + "mydataset".into(), + "newview".into() + ]) + ); + assert_eq!( + vec![ + ViewColumnDef { + name: Ident::new("name"), + options: None, + }, + ViewColumnDef { + name: Ident::new("age"), + options: Some(vec![SqlOption { + name: Ident::new("description"), + value: Expr::Value(Value::DoubleQuotedString("field age".to_string())), + }]) + }, + ], + columns + ); + assert_eq!( + "SELECT column_1, column_2, column_3 FROM myproject.mydataset.mytable", + query.to_string() + ); + assert_eq!( + r#"OPTIONS (expiration_timestamp = TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 48 HOUR), friendly_name = "newview", description = "a view that expires in 2 days", labels = [("org_unit", "development")])"#, + options.to_string() + ); + let CreateTableOptions::Options(options) = options else { + unreachable!() + }; + assert_eq!( + &SqlOption { + name: Ident::new("description"), + value: Expr::Value(Value::DoubleQuotedString( + "a view that expires in 2 days".to_string() + )), + }, + &options[2], + ); + } + _ => unreachable!(), + } +} + +#[test] +fn parse_create_table_with_options() { + let sql = trim_sql( + r#" + CREATE TABLE mydataset.newtable + (x INT64 NOT NULL OPTIONS (description = "field x"), + y BOOL OPTIONS (description = "field y")) + + PARTITION BY _PARTITIONDATE + CLUSTER BY userid, age + OPTIONS(partition_expiration_days = 1, + description = "table option description") + "#, + ); + match bigquery().verified_stmt(sql.as_str()) { + Statement::CreateTable { + name, + columns, + big_query_config, + .. + } => { + assert_eq!( + name, + ObjectName(vec!["mydataset".into(), "newtable".into()]) + ); + assert_eq!( + vec![ + ColumnDef { + name: Ident::new("x"), + data_type: DataType::Int64, + collation: None, + options: vec![ + ColumnOptionDef { + name: None, + option: ColumnOption::NotNull, + }, + ColumnOptionDef { + name: None, + option: ColumnOption::SqlOptions(vec![SqlOption { + name: Ident::new("description"), + value: Expr::Value(Value::DoubleQuotedString( + "field x".to_string() + )), + },]) + }, + ] + }, + ColumnDef { + name: Ident::new("y"), + data_type: DataType::Bool, + collation: None, + options: vec![ColumnOptionDef { + name: None, + option: ColumnOption::SqlOptions(vec![SqlOption { + name: Ident::new("description"), + value: Expr::Value(Value::DoubleQuotedString( + "field y".to_string() + )), + },]) + }] + }, + ], + columns + ); + assert_eq!( + BigQueryCreateTableConfiguration { + partition_by: Some(Expr::Identifier(Ident::new("_PARTITIONDATE"))), + cluster_by: Some(vec![Ident::new("userid"), Ident::new("age"),]), + options: Some(vec![ + SqlOption { + name: Ident::new("partition_expiration_days"), + value: Expr::Value(number("1")), + }, + SqlOption { + name: Ident::new("description"), + value: Expr::Value(Value::DoubleQuotedString( + "table option description".to_string() + )), + }, + ]) + }, + *big_query_config.unwrap(), + ) + } + _ => unreachable!(), + } + + let sql = trim_sql( + r#" + CREATE TABLE mydataset.newtable + (x INT64 NOT NULL OPTIONS (description = "field x"), + y BOOL OPTIONS (description = "field y")) + + CLUSTER BY userid + OPTIONS(partition_expiration_days = 1, + description = "table option description") + "#, + ); + bigquery().verified_stmt(sql.as_str()); +} + #[test] fn parse_nested_data_types() { let sql = "CREATE TABLE table (x STRUCT, b BYTES(42)>, y ARRAY>)"; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 1d0923b4f..089e9db92 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -2972,11 +2972,11 @@ fn parse_create_table_with_options() { vec![ SqlOption { name: "foo".into(), - value: Value::SingleQuotedString("bar".into()), + value: Expr::Value(Value::SingleQuotedString("bar".into())), }, SqlOption { name: "a".into(), - value: number("123"), + value: Expr::Value(number("123")), }, ], with_options @@ -3235,11 +3235,11 @@ fn parse_alter_view_with_options() { vec![ SqlOption { name: "foo".into(), - value: Value::SingleQuotedString("bar".into()), + value: Expr::Value(Value::SingleQuotedString("bar".into())), }, SqlOption { name: "a".into(), - value: number("123"), + value: Expr::Value(number("123")), }, ], with_options @@ -5564,18 +5564,18 @@ fn parse_create_view() { query, or_replace, materialized, - with_options, + options, cluster_by, with_no_schema_binding: late_binding, if_not_exists, temporary, } => { assert_eq!("myschema.myview", name.to_string()); - assert_eq!(Vec::::new(), columns); + assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); assert!(!materialized); assert!(!or_replace); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert_eq!(cluster_by, vec![]); assert!(!late_binding); assert!(!if_not_exists); @@ -5589,19 +5589,19 @@ fn parse_create_view() { fn parse_create_view_with_options() { let sql = "CREATE VIEW v WITH (foo = 'bar', a = 123) AS SELECT 1"; match verified_stmt(sql) { - Statement::CreateView { with_options, .. } => { + Statement::CreateView { options, .. } => { assert_eq!( - vec![ + CreateTableOptions::With(vec![ SqlOption { name: "foo".into(), - value: Value::SingleQuotedString("bar".into()), + value: Expr::Value(Value::SingleQuotedString("bar".into())), }, SqlOption { name: "a".into(), - value: number("123"), + value: Expr::Value(number("123")), }, - ], - with_options + ]), + options ); } _ => unreachable!(), @@ -5616,7 +5616,7 @@ fn parse_create_view_with_columns() { name, columns, or_replace, - with_options, + options, query, materialized, cluster_by, @@ -5625,8 +5625,17 @@ fn parse_create_view_with_columns() { temporary, } => { assert_eq!("v", name.to_string()); - assert_eq!(columns, vec![Ident::new("has"), Ident::new("cols")]); - assert_eq!(with_options, vec![]); + assert_eq!( + columns, + vec![Ident::new("has"), Ident::new("cols"),] + .into_iter() + .map(|name| ViewColumnDef { + name, + options: None + }) + .collect::>() + ); + assert_eq!(options, CreateTableOptions::None); assert_eq!("SELECT 1, 2", query.to_string()); assert!(!materialized); assert!(!or_replace); @@ -5649,18 +5658,18 @@ fn parse_create_view_temporary() { query, or_replace, materialized, - with_options, + options, cluster_by, with_no_schema_binding: late_binding, if_not_exists, temporary, } => { assert_eq!("myschema.myview", name.to_string()); - assert_eq!(Vec::::new(), columns); + assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); assert!(!materialized); assert!(!or_replace); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert_eq!(cluster_by, vec![]); assert!(!late_binding); assert!(!if_not_exists); @@ -5678,7 +5687,7 @@ fn parse_create_or_replace_view() { name, columns, or_replace, - with_options, + options, query, materialized, cluster_by, @@ -5688,7 +5697,7 @@ fn parse_create_or_replace_view() { } => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![]); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert_eq!("SELECT 1", query.to_string()); assert!(!materialized); assert!(or_replace); @@ -5713,7 +5722,7 @@ fn parse_create_or_replace_materialized_view() { name, columns, or_replace, - with_options, + options, query, materialized, cluster_by, @@ -5723,7 +5732,7 @@ fn parse_create_or_replace_materialized_view() { } => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![]); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert_eq!("SELECT 1", query.to_string()); assert!(materialized); assert!(or_replace); @@ -5746,17 +5755,17 @@ fn parse_create_materialized_view() { columns, query, materialized, - with_options, + options, cluster_by, with_no_schema_binding: late_binding, if_not_exists, temporary, } => { assert_eq!("myschema.myview", name.to_string()); - assert_eq!(Vec::::new(), columns); + assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); assert!(materialized); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert!(!or_replace); assert_eq!(cluster_by, vec![]); assert!(!late_binding); @@ -5777,17 +5786,17 @@ fn parse_create_materialized_view_with_cluster_by() { columns, query, materialized, - with_options, + options, cluster_by, with_no_schema_binding: late_binding, if_not_exists, temporary, } => { assert_eq!("myschema.myview", name.to_string()); - assert_eq!(Vec::::new(), columns); + assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); assert!(materialized); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert!(!or_replace); assert_eq!(cluster_by, vec![Ident::new("foo")]); assert!(!late_binding); @@ -7414,11 +7423,11 @@ fn parse_cache_table() { options: vec![ SqlOption { name: Ident::with_quote('\'', "K1"), - value: Value::SingleQuotedString("V1".into()), + value: Expr::Value(Value::SingleQuotedString("V1".into())), }, SqlOption { name: Ident::with_quote('\'', "K2"), - value: number("0.88"), + value: Expr::Value(number("0.88")), }, ], query: None, @@ -7439,11 +7448,11 @@ fn parse_cache_table() { options: vec![ SqlOption { name: Ident::with_quote('\'', "K1"), - value: Value::SingleQuotedString("V1".into()), + value: Expr::Value(Value::SingleQuotedString("V1".into())), }, SqlOption { name: Ident::with_quote('\'', "K2"), - value: number("0.88"), + value: Expr::Value(number("0.88")), }, ], query: Some(query.clone()), @@ -7464,11 +7473,11 @@ fn parse_cache_table() { options: vec![ SqlOption { name: Ident::with_quote('\'', "K1"), - value: Value::SingleQuotedString("V1".into()), + value: Expr::Value(Value::SingleQuotedString("V1".into())), }, SqlOption { name: Ident::with_quote('\'', "K2"), - value: number("0.88"), + value: Expr::Value(number("0.88")), }, ], query: Some(query.clone()), diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index b075a9b4d..dde1b8d00 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -459,15 +459,15 @@ fn parse_create_table_with_defaults() { vec![ SqlOption { name: "fillfactor".into(), - value: number("20") + value: Expr::Value(number("20")) }, SqlOption { name: "user_catalog_table".into(), - value: Value::Boolean(true) + value: Expr::Value(Value::Boolean(true)) }, SqlOption { name: "autovacuum_vacuum_threshold".into(), - value: number("100") + value: Expr::Value(number("100")) }, ] ); diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs index cc0d53b14..5c9cf9068 100644 --- a/tests/sqlparser_sqlite.rs +++ b/tests/sqlparser_sqlite.rs @@ -117,18 +117,18 @@ fn parse_create_view_temporary_if_not_exists() { query, or_replace, materialized, - with_options, + options, cluster_by, with_no_schema_binding: late_binding, if_not_exists, temporary, } => { assert_eq!("myschema.myview", name.to_string()); - assert_eq!(Vec::::new(), columns); + assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); assert!(!materialized); assert!(!or_replace); - assert_eq!(with_options, vec![]); + assert_eq!(options, CreateTableOptions::None); assert_eq!(cluster_by, vec![]); assert!(!late_binding); assert!(if_not_exists);