diff --git a/src/ast/mod.rs b/src/ast/mod.rs index c06e120aee..ec45a63265 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -9111,9 +9111,10 @@ pub enum SqlOption { /// Any option that consists of a key value pair where the value is an expression. e.g. /// /// WITH(DISTRIBUTION = ROUND_ROBIN) + /// WITH (toast.autovacuum_enabled = false) KeyValue { - /// The option key identifier. - key: Ident, + /// The option key. + key: ObjectName, /// The expression value for the option. value: Expr, }, diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 704b583b8b..785e0dc650 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -1101,7 +1101,7 @@ impl Spanned for SqlOption { match self { SqlOption::Clustered(table_options_clustered) => table_options_clustered.span(), SqlOption::Ident(ident) => ident.span, - SqlOption::KeyValue { key, value } => key.span.union(&value.span()), + SqlOption::KeyValue { key, value } => key.span().union(&value.span()), SqlOption::Partition { column_name, range_direction: _, @@ -3423,4 +3423,22 @@ SETTINGS update_parallel_mode = 'auto'"#; assert_eq!(test.get_source(expr.span()), expected, "{sql}"); } } + + #[test] + fn test_namespaced_storage_parameter_span() { + let dialect = &crate::dialect::PostgreSqlDialect {}; + let sql = "CREATE TABLE t (a INT) WITH (toast.autovacuum_enabled = false)"; + let mut test = SpanTest::new(dialect, sql); + let options = match test.0.parse_statement().unwrap() { + Statement::CreateTable(crate::ast::CreateTable { + table_options: crate::ast::CreateTableOptions::With(options), + .. + }) => options, + stmt => panic!("expected CREATE TABLE WITH, got {stmt:?}"), + }; + assert_eq!( + test.get_source(options[0].span()), + "toast.autovacuum_enabled = false" + ); + } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index f86406fb26..9ba3a5ec31 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9939,7 +9939,10 @@ impl<'a> Parser<'a> { None => Expr::Identifier(self.parse_identifier()?), }; - Ok(Some(SqlOption::KeyValue { key, value })) + Ok(Some(SqlOption::KeyValue { + key: key.into(), + value, + })) } /// Parse plain options. @@ -11123,7 +11126,7 @@ impl<'a> Parser<'a> { self.parse_option_clustered() } _ => { - let name = self.parse_identifier()?; + let name = ObjectName::from(self.parse_period_separated(|p| p.parse_identifier())?); self.expect_token(&Token::Eq)?; let value = self.parse_expr()?; diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index b110423370..cd7d8beb18 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -359,7 +359,7 @@ fn parse_create_view_with_options() { data_type: None, options: Some(ColumnOptions::CommaSeparated(vec![ColumnOption::Options( vec![SqlOption::KeyValue { - key: Ident::new("description"), + key: Ident::new("description").into(), value: Expr::Value( Value::DoubleQuotedString("field age".to_string()).with_span( Span::new(Location::new(1, 42), Location::new(1, 52)) @@ -384,7 +384,7 @@ fn parse_create_view_with_options() { }; assert_eq!( &SqlOption::KeyValue { - key: Ident::new("description"), + key: Ident::new("description").into(), value: Expr::Value( Value::DoubleQuotedString("a view that expires in 2 days".to_string()) .with_empty_span() @@ -511,7 +511,7 @@ fn parse_create_table_with_options() { ColumnOptionDef { name: None, option: ColumnOption::Options(vec![SqlOption::KeyValue { - key: Ident::new("description"), + key: Ident::new("description").into(), value: Expr::Value( Value::DoubleQuotedString("field x".to_string()).with_span( Span::new(Location::new(1, 42), Location::new(1, 52)) @@ -527,7 +527,7 @@ fn parse_create_table_with_options() { options: vec![ColumnOptionDef { name: None, option: ColumnOption::Options(vec![SqlOption::KeyValue { - key: Ident::new("description"), + key: Ident::new("description").into(), value: Expr::Value( Value::DoubleQuotedString("field y".to_string()).with_span( Span::new(Location::new(1, 42), Location::new(1, 52)) @@ -548,7 +548,7 @@ fn parse_create_table_with_options() { ])), CreateTableOptions::Options(vec![ SqlOption::KeyValue { - key: Ident::new("partition_expiration_days"), + key: Ident::new("partition_expiration_days").into(), value: Expr::Value( number("1").with_span(Span::new( Location::new(1, 42), @@ -557,7 +557,7 @@ fn parse_create_table_with_options() { ), }, SqlOption::KeyValue { - key: Ident::new("description"), + key: Ident::new("description").into(), value: Expr::Value( Value::DoubleQuotedString("table option description".to_string()) .with_span(Span::new( @@ -2339,7 +2339,7 @@ fn test_bigquery_create_function() { number("42").with_empty_span() ))), options: Some(vec![SqlOption::KeyValue { - key: Ident::new("x"), + key: Ident::new("x").into(), value: Expr::Value(Value::SingleQuotedString("y".into()).with_empty_span()), }]), behavior: None, @@ -2707,20 +2707,20 @@ fn test_export_data() { Statement::ExportData(ExportData { options: vec![ SqlOption::KeyValue { - key: Ident::new("uri"), + key: Ident::new("uri").into(), value: Expr::Value( Value::SingleQuotedString("gs://bucket/folder/*".to_owned()) .with_empty_span() ), }, SqlOption::KeyValue { - key: Ident::new("format"), + key: Ident::new("format").into(), value: Expr::Value( Value::SingleQuotedString("PARQUET".to_owned()).with_empty_span() ), }, SqlOption::KeyValue { - key: Ident::new("overwrite"), + key: Ident::new("overwrite").into(), value: Expr::Value(Value::Boolean(true).with_empty_span()), }, ], @@ -2809,20 +2809,20 @@ fn test_export_data() { Statement::ExportData(ExportData { options: vec![ SqlOption::KeyValue { - key: Ident::new("uri"), + key: Ident::new("uri").into(), value: Expr::Value( Value::SingleQuotedString("gs://bucket/folder/*".to_owned()) .with_empty_span() ), }, SqlOption::KeyValue { - key: Ident::new("format"), + key: Ident::new("format").into(), value: Expr::Value( Value::SingleQuotedString("PARQUET".to_owned()).with_empty_span() ), }, SqlOption::KeyValue { - key: Ident::new("overwrite"), + key: Ident::new("overwrite").into(), value: Expr::Value(Value::Boolean(true).with_empty_span()), }, ], diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 379e37a660..043ba57843 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -5253,13 +5253,13 @@ fn parse_create_table_with_options() { assert_eq!( vec![ SqlOption::KeyValue { - key: "foo".into(), + key: Ident::new("foo").into(), value: Expr::Value( (Value::SingleQuotedString("bar".into())).with_empty_span() ), }, SqlOption::KeyValue { - key: "a".into(), + key: Ident::new("a").into(), value: Expr::value(number("123")), }, ], @@ -5510,7 +5510,8 @@ fn parse_alter_table() { value: "classification".to_string(), quote_style: Some('\''), span: Span::empty(), - }, + } + .into(), value: Expr::Value( (Value::SingleQuotedString("parquet".to_string())).with_empty_span() ), @@ -5531,7 +5532,8 @@ fn parse_alter_table() { value: "autovacuum_vacuum_scale_factor".to_string(), quote_style: None, span: Span::empty(), - }, + } + .into(), value: Expr::Value(test_utils::number("0.01").with_empty_span()), }, SqlOption::KeyValue { @@ -5539,7 +5541,8 @@ fn parse_alter_table() { value: "autovacuum_vacuum_threshold".to_string(), quote_style: None, span: Span::empty(), - }, + } + .into(), value: Expr::Value(test_utils::number("500").with_empty_span()), } ], @@ -5684,13 +5687,13 @@ fn parse_alter_view_with_options() { assert_eq!( vec![ SqlOption::KeyValue { - key: "foo".into(), + key: Ident::new("foo").into(), value: Expr::Value( (Value::SingleQuotedString("bar".into())).with_empty_span() ), }, SqlOption::KeyValue { - key: "a".into(), + key: Ident::new("a").into(), value: Expr::value(number("123")), }, ], @@ -9231,13 +9234,13 @@ fn parse_create_view_with_options() { assert_eq!( CreateTableOptions::With(vec![ SqlOption::KeyValue { - key: "foo".into(), + key: Ident::new("foo").into(), value: Expr::Value( (Value::SingleQuotedString("bar".into())).with_empty_span() ), }, SqlOption::KeyValue { - key: "a".into(), + key: Ident::new("a").into(), value: Expr::value(number("123")), }, ]), @@ -12032,11 +12035,11 @@ fn parse_cache_table() { has_as: false, options: vec![ SqlOption::KeyValue { - key: Ident::with_quote('\'', "K1"), + key: Ident::with_quote('\'', "K1").into(), value: Expr::Value((Value::SingleQuotedString("V1".into())).with_empty_span()), }, SqlOption::KeyValue { - key: Ident::with_quote('\'', "K2"), + key: Ident::with_quote('\'', "K2").into(), value: Expr::value(number("0.88")), }, ], @@ -12057,11 +12060,11 @@ fn parse_cache_table() { has_as: false, options: vec![ SqlOption::KeyValue { - key: Ident::with_quote('\'', "K1"), + key: Ident::with_quote('\'', "K1").into(), value: Expr::Value((Value::SingleQuotedString("V1".into())).with_empty_span()), }, SqlOption::KeyValue { - key: Ident::with_quote('\'', "K2"), + key: Ident::with_quote('\'', "K2").into(), value: Expr::value(number("0.88")), }, ], @@ -12082,11 +12085,11 @@ fn parse_cache_table() { has_as: true, options: vec![ SqlOption::KeyValue { - key: Ident::with_quote('\'', "K1"), + key: Ident::with_quote('\'', "K1").into(), value: Expr::Value((Value::SingleQuotedString("V1".into())).with_empty_span()), }, SqlOption::KeyValue { - key: Ident::with_quote('\'', "K2"), + key: Ident::with_quote('\'', "K2").into(), value: Expr::value(number("0.88")), }, ], @@ -13640,7 +13643,8 @@ fn parse_unload() { value: "format".to_string(), quote_style: None, span: Span::empty(), - }, + } + .into(), value: Expr::Value( (Value::SingleQuotedString("AVRO".to_string())).with_empty_span() ) @@ -15891,13 +15895,13 @@ fn test_create_connector() { with_dcproperties, Some(vec![ SqlOption::KeyValue { - key: Ident::with_quote('\'', "user"), + key: Ident::with_quote('\'', "user").into(), value: Expr::Value( (Value::SingleQuotedString("root".to_string())).with_empty_span() ) }, SqlOption::KeyValue { - key: Ident::with_quote('\'', "password"), + key: Ident::with_quote('\'', "password").into(), value: Expr::Value( (Value::SingleQuotedString("password".to_string())).with_empty_span() ) @@ -15962,13 +15966,13 @@ fn test_alter_connector() { properties, Some(vec![ SqlOption::KeyValue { - key: Ident::with_quote('\'', "user"), + key: Ident::with_quote('\'', "user").into(), value: Expr::Value( (Value::SingleQuotedString("root".to_string())).with_empty_span() ) }, SqlOption::KeyValue { - key: Ident::with_quote('\'', "password"), + key: Ident::with_quote('\'', "password").into(), value: Expr::Value( (Value::SingleQuotedString("password".to_string())).with_empty_span() ) @@ -22116,7 +22120,7 @@ fn parse_cache_table_options_without_flag() { table_name: ObjectName::from(vec![Ident::new("t")]), has_as, options: vec![SqlOption::KeyValue { - key: Ident::with_quote('\'', "k"), + key: Ident::with_quote('\'', "k").into(), value: Expr::Value(Value::SingleQuotedString("v".into()).with_empty_span()), }], query, diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index fe8531cace..519bc270d2 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -1739,7 +1739,7 @@ fn parse_create_table_with_valid_options() { value: "DISTRIBUTION".to_string(), quote_style: None, span: Span::empty(), - }, + }.into(), value: Expr::Identifier(Ident { value: "ROUND_ROBIN".to_string(), quote_style: None, @@ -1818,7 +1818,7 @@ fn parse_create_table_with_valid_options() { value: "DISTRIBUTION".to_string(), quote_style: None, span: Span::empty(), - }, + }.into(), value: Expr::Function( Function { name: ObjectName::from( diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index a7aaef6b48..a432f95ca3 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -1028,7 +1028,7 @@ fn parse_create_table_auto_increment_offset() { }; assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("AUTO_INCREMENT"), + key: Ident::new("AUTO_INCREMENT").into(), value: Expr::Value(test_utils::number("123").with_empty_span()) })); } @@ -1065,7 +1065,7 @@ fn parse_create_table_multiple_options_order_independent() { ))); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("KEY_BLOCK_SIZE"), + key: Ident::new("KEY_BLOCK_SIZE").into(), value: Expr::Value(test_utils::number("8").with_empty_span()) })); @@ -1073,7 +1073,7 @@ fn parse_create_table_multiple_options_order_independent() { .contains(&SqlOption::Comment(CommentDef::WithEq("abc".to_owned())))); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("ROW_FORMAT"), + key: Ident::new("ROW_FORMAT").into(), value: Expr::Identifier(Ident::new("DYNAMIC".to_owned())) })); } @@ -1109,91 +1109,91 @@ fn parse_create_table_with_all_table_options() { ))); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("COLLATE"), + key: Ident::new("COLLATE").into(), value: Expr::Identifier(Ident::new("utf8mb4_0900_ai_ci".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("DEFAULT CHARSET"), + key: Ident::new("DEFAULT CHARSET").into(), value: Expr::Identifier(Ident::new("utf8mb4".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("AUTO_INCREMENT"), + key: Ident::new("AUTO_INCREMENT").into(), value: Expr::value(test_utils::number("123")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("KEY_BLOCK_SIZE"), + key: Ident::new("KEY_BLOCK_SIZE").into(), value: Expr::value(test_utils::number("8")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("ROW_FORMAT"), + key: Ident::new("ROW_FORMAT").into(), value: Expr::Identifier(Ident::new("DYNAMIC".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("PACK_KEYS"), + key: Ident::new("PACK_KEYS").into(), value: Expr::value(test_utils::number("1")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("STATS_AUTO_RECALC"), + key: Ident::new("STATS_AUTO_RECALC").into(), value: Expr::value(test_utils::number("1")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("STATS_PERSISTENT"), + key: Ident::new("STATS_PERSISTENT").into(), value: Expr::value(test_utils::number("0")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("STATS_SAMPLE_PAGES"), + key: Ident::new("STATS_SAMPLE_PAGES").into(), value: Expr::value(test_utils::number("128")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("STATS_SAMPLE_PAGES"), + key: Ident::new("STATS_SAMPLE_PAGES").into(), value: Expr::value(test_utils::number("128")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("INSERT_METHOD"), + key: Ident::new("INSERT_METHOD").into(), value: Expr::Identifier(Ident::new("FIRST".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("COMPRESSION"), + key: Ident::new("COMPRESSION").into(), value: Expr::value(Value::SingleQuotedString("ZLIB".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("ENCRYPTION"), + key: Ident::new("ENCRYPTION").into(), value: Expr::value(Value::SingleQuotedString("Y".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("MAX_ROWS"), + key: Ident::new("MAX_ROWS").into(), value: Expr::value(test_utils::number("10000")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("MIN_ROWS"), + key: Ident::new("MIN_ROWS").into(), value: Expr::value(test_utils::number("10")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("AUTOEXTEND_SIZE"), + key: Ident::new("AUTOEXTEND_SIZE").into(), value: Expr::value(test_utils::number("64")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("AVG_ROW_LENGTH"), + key: Ident::new("AVG_ROW_LENGTH").into(), value: Expr::value(test_utils::number("128")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("CHECKSUM"), + key: Ident::new("CHECKSUM").into(), value: Expr::value(test_utils::number("1")) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("CONNECTION"), + key: Ident::new("CONNECTION").into(), value: Expr::value(Value::SingleQuotedString("mysql://localhost".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("ENGINE_ATTRIBUTE"), + key: Ident::new("ENGINE_ATTRIBUTE").into(), value: Expr::value(Value::SingleQuotedString("primary".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("PASSWORD"), + key: Ident::new("PASSWORD").into(), value: Expr::value(Value::SingleQuotedString("secure_password".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("SECONDARY_ENGINE_ATTRIBUTE"), + key: Ident::new("SECONDARY_ENGINE_ATTRIBUTE").into(), value: Expr::value(Value::SingleQuotedString("secondary_attr".to_owned())) })); assert!(plain_options.contains(&SqlOption::Ident(Ident::new( @@ -1219,11 +1219,11 @@ fn parse_create_table_with_all_table_options() { ))); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("DATA DIRECTORY"), + key: Ident::new("DATA DIRECTORY").into(), value: Expr::value(Value::SingleQuotedString("/var/lib/mysql/data".to_owned())) })); assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("INDEX DIRECTORY"), + key: Ident::new("INDEX DIRECTORY").into(), value: Expr::value(Value::SingleQuotedString("/var/lib/mysql/index".to_owned())) })); } @@ -1289,7 +1289,7 @@ fn parse_create_table_engine_default_charset() { }; assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("DEFAULT CHARSET"), + key: Ident::new("DEFAULT CHARSET").into(), value: Expr::Identifier(Ident::new("utf8mb3".to_owned())) })); @@ -1331,7 +1331,7 @@ fn parse_create_table_collate() { }; assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("COLLATE"), + key: Ident::new("COLLATE").into(), value: Expr::Identifier(Ident::new("utf8mb4_0900_ai_ci".to_owned())) })); } @@ -1357,7 +1357,7 @@ fn parse_create_table_both_options_and_as_query() { }; assert!(plain_options.contains(&SqlOption::KeyValue { - key: Ident::new("COLLATE"), + key: Ident::new("COLLATE").into(), value: Expr::Identifier(Ident::new("utf8mb4_0900_ai_ci".to_owned())) })); diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index eafc006c04..cd7121915c 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -497,15 +497,15 @@ fn parse_create_table_with_defaults() { with_options, vec![ SqlOption::KeyValue { - key: "fillfactor".into(), + key: Ident::new("fillfactor").into(), value: Expr::value(number("20")) }, SqlOption::KeyValue { - key: "user_catalog_table".into(), + key: Ident::new("user_catalog_table").into(), value: Expr::Value((Value::Boolean(true)).with_empty_span()) }, SqlOption::KeyValue { - key: "autovacuum_vacuum_threshold".into(), + key: Ident::new("autovacuum_vacuum_threshold").into(), value: Expr::value(number("100")) }, ] @@ -992,11 +992,11 @@ fn parse_create_collation() { name: ObjectName::from(vec![Ident::new("test3")]), definition: CreateCollationDefinition::Options(vec![ SqlOption::KeyValue { - key: Ident::new("provider"), + key: Ident::new("provider").into(), value: Expr::Identifier(Ident::new("icu")), }, SqlOption::KeyValue { - key: Ident::new("lc_collate"), + key: Ident::new("lc_collate").into(), value: Expr::Value( Value::SingleQuotedString("en_US.utf8".to_string()).with_empty_span(), ), @@ -1024,11 +1024,11 @@ fn parse_create_collation() { name: ObjectName::from(vec![Ident::new("testx")]), definition: CreateCollationDefinition::Options(vec![ SqlOption::KeyValue { - key: Ident::new("provider"), + key: Ident::new("provider").into(), value: Expr::Identifier(Ident::new("icu")), }, SqlOption::KeyValue { - key: Ident::new("locale"), + key: Ident::new("locale").into(), value: Expr::Value( Value::SingleQuotedString("nonsense-nowhere".to_string()).with_empty_span(), ), @@ -6780,13 +6780,13 @@ fn parse_create_table_with_options() { assert_eq!( vec![ SqlOption::KeyValue { - key: "foo".into(), + key: Ident::new("foo").into(), value: Expr::Value( (Value::SingleQuotedString("bar".into())).with_empty_span() ), }, SqlOption::KeyValue { - key: "a".into(), + key: Ident::new("a").into(), value: Expr::value(number("123")), }, ], @@ -11529,3 +11529,42 @@ fn parse_named_argument_with_assignment_operator() { "sql parser error: Expected: end of statement, found: :=" ); } + +#[test] +fn parse_namespaced_storage_parameters() { + let expected = vec![SqlOption::KeyValue { + key: ObjectName::from(vec![Ident::new("toast"), Ident::new("autovacuum_enabled")]), + value: Expr::Value(Value::Boolean(false).with_empty_span()), + }]; + + match pg().verified_stmt("CREATE TABLE t (a INT) WITH (toast.autovacuum_enabled = false)") { + Statement::CreateTable(CreateTable { + table_options: CreateTableOptions::With(options), + .. + }) => assert_eq!(options, expected), + _ => unreachable!(), + } + + match alter_table_op( + pg().verified_stmt("ALTER TABLE tab SET (toast.autovacuum_enabled = false)"), + ) { + AlterTableOperation::SetOptionsParens { options } => assert_eq!(options, expected), + _ => unreachable!(), + } + + match pg().verified_stmt( + "CREATE MATERIALIZED VIEW m WITH (toast.autovacuum_enabled = false) AS SELECT 1", + ) { + Statement::CreateView(create_view) => { + assert_eq!(create_view.options, CreateTableOptions::With(expected)) + } + _ => unreachable!(), + } + + assert_eq!( + pg().parse_sql_statements("CREATE TABLE t (a INT) WITH (toast. = false)") + .unwrap_err() + .to_string(), + "sql parser error: Expected: identifier, found: =" + ); +}