@@ -5124,6 +5124,7 @@ impl<'a> Parser<'a> {
51245124 pub fn parse_create(&mut self) -> Result<Statement, ParserError> {
51255125 let or_replace = self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
51265126 let or_alter = self.parse_keywords(&[Keyword::OR, Keyword::ALTER]);
5127+ let multiset = self.maybe_parse_multiset();
51275128 let local = self.parse_one_of_keywords(&[Keyword::LOCAL]).is_some();
51285129 let global = self.parse_one_of_keywords(&[Keyword::GLOBAL]).is_some();
51295130 let transient = self.parse_one_of_keywords(&[Keyword::TRANSIENT]).is_some();
@@ -5137,13 +5138,14 @@ impl<'a> Parser<'a> {
51375138 let temporary = self
51385139 .parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY])
51395140 .is_some();
5141+ let volatile = self.parse_keyword(Keyword::VOLATILE);
51405142 let persistent = dialect_of!(self is DuckDbDialect)
51415143 && self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some();
51425144 let create_view_params = self.parse_create_view_params()?;
51435145 if self.peek_keywords(&[Keyword::SNAPSHOT, Keyword::TABLE]) {
51445146 self.parse_create_snapshot_table().map(Into::into)
51455147 } else if self.parse_keyword(Keyword::TABLE) {
5146- self.parse_create_table(or_replace, temporary, global, transient)
5148+ self.parse_create_table(or_replace, temporary, global, transient, volatile, multiset )
51475149 .map(Into::into)
51485150 } else if self.peek_keyword(Keyword::MATERIALIZED)
51495151 || self.peek_keyword(Keyword::VIEW)
@@ -8476,11 +8478,25 @@ impl<'a> Parser<'a> {
84768478 temporary: bool,
84778479 global: Option<bool>,
84788480 transient: bool,
8481+ volatile: bool,
8482+ multiset: Option<bool>,
84798483 ) -> Result<CreateTable, ParserError> {
84808484 let allow_unquoted_hyphen = dialect_of!(self is BigQueryDialect);
84818485 let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
84828486 let table_name = self.parse_object_name(allow_unquoted_hyphen)?;
84838487
8488+ let fallback = if self.dialect.supports_leading_comma_before_table_options()
8489+ && self.consume_token(&Token::Comma)
8490+ {
8491+ let fallback = self.maybe_parse_fallback()?;
8492+ if fallback.is_none() {
8493+ self.prev_token(); // Put back comma.
8494+ }
8495+ fallback
8496+ } else {
8497+ None
8498+ };
8499+
84848500 // PostgreSQL PARTITION OF for child partition tables
84858501 // Note: This is a PostgreSQL-specific feature, but the dialect check was intentionally
84868502 // removed to allow GenericDialect and other dialects to parse this syntax. This enables
@@ -8632,13 +8648,23 @@ impl<'a> Parser<'a> {
86328648 None
86338649 };
86348650
8651+ // `WITH DATA` clause only applies if there is a query body.
8652+ let with_data = if query.is_some() {
8653+ self.maybe_parse_with_data()?
8654+ } else {
8655+ None
8656+ };
8657+
86358658 Ok(CreateTableBuilder::new(table_name)
86368659 .temporary(temporary)
86378660 .columns(columns)
86388661 .constraints(constraints)
86398662 .or_replace(or_replace)
86408663 .if_not_exists(if_not_exists)
86418664 .transient(transient)
8665+ .volatile(volatile)
8666+ .multiset(multiset)
8667+ .fallback(fallback)
86428668 .hive_distribution(hive_distribution)
86438669 .hive_formats(hive_formats)
86448670 .global(global)
@@ -8658,6 +8684,7 @@ impl<'a> Parser<'a> {
86588684 .for_values(for_values)
86598685 .table_options(create_table_config.table_options)
86608686 .primary_key(primary_key)
8687+ .with_data(with_data)
86618688 .strict(strict)
86628689 .backup(backup)
86638690 .diststyle(diststyle)
@@ -8666,6 +8693,47 @@ impl<'a> Parser<'a> {
86668693 .build())
86678694 }
86688695
8696+ /// Parse `MULTISET` table-kind prefix on `CREATE TABLE`.
8697+ fn maybe_parse_multiset(&mut self) -> Option<bool> {
8698+ match self.parse_one_of_keywords(&[Keyword::SET, Keyword::MULTISET]) {
8699+ Some(Keyword::MULTISET) => Some(true),
8700+ Some(Keyword::SET) => Some(false),
8701+ _ => None,
8702+ }
8703+ }
8704+
8705+ /// Parse `FALLBACK` option on a `CREATE TABLE` statement,
8706+ fn maybe_parse_fallback(&mut self) -> Result<Option<bool>, ParserError> {
8707+ if self.parse_keywords(&[Keyword::NO, Keyword::FALLBACK]) {
8708+ Ok(Some(false))
8709+ } else if self.parse_keyword(Keyword::FALLBACK) {
8710+ Ok(Some(true))
8711+ } else {
8712+ Ok(None)
8713+ }
8714+ }
8715+
8716+ /// Parse [`WithData`] clause on `CREATE TABLE ... AS` statement.
8717+ fn maybe_parse_with_data(&mut self) -> Result<Option<WithData>, ParserError> {
8718+ let data = if self.parse_keywords(&[Keyword::WITH, Keyword::DATA]) {
8719+ true
8720+ } else if self.parse_keywords(&[Keyword::WITH, Keyword::NO, Keyword::DATA]) {
8721+ false
8722+ } else {
8723+ return Ok(None);
8724+ };
8725+
8726+ let statistics = if self.parse_keywords(&[Keyword::AND, Keyword::STATISTICS]) {
8727+ Some(true)
8728+ } else if self.parse_keywords(&[Keyword::AND, Keyword::NO, Keyword::STATISTICS]) {
8729+ Some(false)
8730+ } else {
8731+ None
8732+ };
8733+
8734+ Ok(Some(WithData { data, statistics }))
8735+ }
8736+
86698737 fn maybe_parse_create_table_like(
86708738 &mut self,
86718739 allow_unquoted_hyphen: bool,
0 commit comments