diff --git a/Cargo.toml b/Cargo.toml index ab9c88e20..7d384228e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ [package] name = "sqlparser-dsql" description = "SQL parser fork with Aurora DSQL extensions (CREATE INDEX ASYNC, ALTER TABLE ASYNC, ALTER COLUMN SET STORAGE, order-independent CREATE SEQUENCE, INCLUDE on table constraints). Based on sqlparser 0.62.0." -version = "0.62.3" +version = "0.62.4" authors = [ "Apache DataFusion ", "Amazon Web Services", diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index b95d74639..6923bea4a 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -1358,7 +1358,7 @@ impl fmt::Display for AlterColumnOperation { } } -/// PostgreSQL column storage strategy used by `ALTER COLUMN ... SET STORAGE`. +/// PostgreSQL column storage strategy. #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] @@ -1935,6 +1935,8 @@ pub enum ColumnOption { NotNull, /// `DEFAULT ` Default(Expr), + /// `STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT }` + Storage(AlterColumnStorage), /// `MATERIALIZE ` /// Syntax: `b INT MATERIALIZE (a + 1)` @@ -2070,6 +2072,7 @@ impl fmt::Display for ColumnOption { Null => write!(f, "NULL"), NotNull => write!(f, "NOT NULL"), Default(expr) => write!(f, "DEFAULT {expr}"), + Storage(storage) => write!(f, "STORAGE {storage}"), Materialized(expr) => write!(f, "MATERIALIZED {expr}"), Ephemeral(expr) => { if let Some(e) = expr { diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 1910a9490..8b318bf0d 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -814,6 +814,7 @@ impl Spanned for RaiseStatementValue { /// Missing spans: /// - [ColumnOption::Null] /// - [ColumnOption::NotNull] +/// - [ColumnOption::Storage] /// - [ColumnOption::Comment] /// - [ColumnOption::PrimaryKey] /// - [ColumnOption::Unique] @@ -825,6 +826,7 @@ impl Spanned for ColumnOption { ColumnOption::Null => Span::empty(), ColumnOption::NotNull => Span::empty(), ColumnOption::Default(expr) => expr.span(), + ColumnOption::Storage(_) => Span::empty(), ColumnOption::Materialized(expr) => expr.span(), ColumnOption::Ephemeral(expr) => expr.as_ref().map_or(Span::empty(), |e| e.span()), ColumnOption::Alias(expr) => expr.span(), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 5202202cb..65db3a711 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9349,6 +9349,10 @@ impl<'a> Parser<'a> { Ok(Some(ColumnOption::Null)) } else if self.parse_keyword(Keyword::DEFAULT) { Ok(Some(ColumnOption::Default(self.parse_expr()?))) + } else if dialect_of!(self is PostgreSqlDialect | GenericDialect) + && self.parse_keyword(Keyword::STORAGE) + { + Ok(Some(ColumnOption::Storage(self.parse_column_storage()?))) } else if dialect_of!(self is ClickHouseDialect| GenericDialect) && self.parse_keyword(Keyword::MATERIALIZED) { @@ -10612,25 +10616,7 @@ impl<'a> Parser<'a> { } else if self.parse_keywords(&[Keyword::DROP, Keyword::DEFAULT]) { AlterColumnOperation::DropDefault {} } else if self.parse_keywords(&[Keyword::SET, Keyword::STORAGE]) { - let storage = match self.parse_one_of_keywords(&[ - Keyword::PLAIN, - Keyword::EXTERNAL, - Keyword::EXTENDED, - Keyword::MAIN, - Keyword::DEFAULT, - ]) { - Some(Keyword::PLAIN) => AlterColumnStorage::Plain, - Some(Keyword::EXTERNAL) => AlterColumnStorage::External, - Some(Keyword::EXTENDED) => AlterColumnStorage::Extended, - Some(Keyword::MAIN) => AlterColumnStorage::Main, - Some(Keyword::DEFAULT) => AlterColumnStorage::Default, - _ => { - return self.expected_ref( - "storage value (PLAIN, EXTERNAL, EXTENDED, MAIN, or DEFAULT)", - self.peek_token_ref(), - ) - } - }; + let storage = self.parse_column_storage()?; AlterColumnOperation::SetStorage { storage } } else if self.parse_keywords(&[Keyword::SET, Keyword::DATA, Keyword::TYPE]) { self.parse_set_data_type(true)? @@ -10809,6 +10795,26 @@ impl<'a> Parser<'a> { Ok(operation) } + fn parse_column_storage(&mut self) -> Result { + match self.parse_one_of_keywords(&[ + Keyword::PLAIN, + Keyword::EXTERNAL, + Keyword::EXTENDED, + Keyword::MAIN, + Keyword::DEFAULT, + ]) { + Some(Keyword::PLAIN) => Ok(AlterColumnStorage::Plain), + Some(Keyword::EXTERNAL) => Ok(AlterColumnStorage::External), + Some(Keyword::EXTENDED) => Ok(AlterColumnStorage::Extended), + Some(Keyword::MAIN) => Ok(AlterColumnStorage::Main), + Some(Keyword::DEFAULT) => Ok(AlterColumnStorage::Default), + _ => self.expected_ref( + "storage value (PLAIN, EXTERNAL, EXTENDED, MAIN, or DEFAULT)", + self.peek_token_ref(), + ), + } + } + fn parse_set_data_type(&mut self, had_set: bool) -> Result { let data_type = self.parse_data_type()?; let using = if self.dialect.supports_alter_column_type_using() diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index e803bcd9a..94421d60a 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1110,6 +1110,30 @@ fn parse_alter_table_alter_column_set_storage() { } } +#[test] +fn parse_create_table_column_storage() { + for (storage, expected) in [ + ("PLAIN", AlterColumnStorage::Plain), + ("EXTERNAL", AlterColumnStorage::External), + ("EXTENDED", AlterColumnStorage::Extended), + ("MAIN", AlterColumnStorage::Main), + ("DEFAULT", AlterColumnStorage::Default), + ] { + let sql = format!("CREATE TABLE tab (payload TEXT STORAGE {storage})"); + let statement = pg_and_generic().verified_stmt(&sql); + + match statement { + Statement::CreateTable(CreateTable { columns, .. }) => { + assert_eq!( + columns[0].options[0].option, + ColumnOption::Storage(expected) + ); + } + _ => unreachable!(), + } + } +} + #[test] fn parse_alter_table_alter_column_add_generated() { pg_and_generic()