@@ -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)
@@ -8470,11 +8472,25 @@ impl<'a> Parser<'a> {
84708472 temporary: bool,
84718473 global: Option<bool>,
84728474 transient: bool,
8475+ volatile: bool,
8476+ multiset: Option<bool>,
84738477 ) -> Result<CreateTable, ParserError> {
84748478 let allow_unquoted_hyphen = dialect_of!(self is BigQueryDialect);
84758479 let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
84768480 let table_name = self.parse_object_name(allow_unquoted_hyphen)?;
84778481
8482+ let fallback = if self.dialect.supports_leading_comma_before_table_options()
8483+ && self.consume_token(&Token::Comma)
8484+ {
8485+ let fallback = self.maybe_parse_fallback()?;
8486+ if fallback.is_none() {
8487+ self.prev_token(); // Put back comma.
8488+ }
8489+ fallback
8490+ } else {
8491+ None
8492+ };
8493+
84788494 // PostgreSQL PARTITION OF for child partition tables
84798495 // Note: This is a PostgreSQL-specific feature, but the dialect check was intentionally
84808496 // removed to allow GenericDialect and other dialects to parse this syntax. This enables
@@ -8626,13 +8642,23 @@ impl<'a> Parser<'a> {
86268642 None
86278643 };
86288644
8645+ // `WITH DATA` clause only applies if there is a query body.
8646+ let with_data = if query.is_some() {
8647+ self.maybe_parse_with_data()?
8648+ } else {
8649+ None
8650+ };
8651+
86298652 Ok(CreateTableBuilder::new(table_name)
86308653 .temporary(temporary)
86318654 .columns(columns)
86328655 .constraints(constraints)
86338656 .or_replace(or_replace)
86348657 .if_not_exists(if_not_exists)
86358658 .transient(transient)
8659+ .volatile(volatile)
8660+ .multiset(multiset)
8661+ .fallback(fallback)
86368662 .hive_distribution(hive_distribution)
86378663 .hive_formats(hive_formats)
86388664 .global(global)
@@ -8652,6 +8678,7 @@ impl<'a> Parser<'a> {
86528678 .for_values(for_values)
86538679 .table_options(create_table_config.table_options)
86548680 .primary_key(primary_key)
8681+ .with_data(with_data)
86558682 .strict(strict)
86568683 .backup(backup)
86578684 .diststyle(diststyle)
@@ -8660,6 +8687,47 @@ impl<'a> Parser<'a> {
86608687 .build())
86618688 }
86628689
8690+ /// Parse `MULTISET` table-kind prefix on `CREATE TABLE`.
8691+ fn maybe_parse_multiset(&mut self) -> Option<bool> {
8692+ match self.parse_one_of_keywords(&[Keyword::SET, Keyword::MULTISET]) {
8693+ Some(Keyword::MULTISET) => Some(true),
8694+ Some(Keyword::SET) => Some(false),
8695+ _ => None,
8696+ }
8697+ }
8698+
8699+ /// Parse `FALLBACK` option on a `CREATE TABLE` statement,
8700+ fn maybe_parse_fallback(&mut self) -> Result<Option<bool>, ParserError> {
8701+ if self.parse_keywords(&[Keyword::NO, Keyword::FALLBACK]) {
8702+ Ok(Some(false))
8703+ } else if self.parse_keyword(Keyword::FALLBACK) {
8704+ Ok(Some(true))
8705+ } else {
8706+ Ok(None)
8707+ }
8708+ }
8709+
8710+ /// Parse [`WithData`] clause on `CREATE TABLE ... AS` statement.
8711+ fn maybe_parse_with_data(&mut self) -> Result<Option<WithData>, ParserError> {
8712+ let data = if self.parse_keywords(&[Keyword::WITH, Keyword::DATA]) {
8713+ true
8714+ } else if self.parse_keywords(&[Keyword::WITH, Keyword::NO, Keyword::DATA]) {
8715+ false
8716+ } else {
8717+ return Ok(None);
8718+ };
8719+
8720+ let statistics = if self.parse_keywords(&[Keyword::AND, Keyword::STATISTICS]) {
8721+ Some(true)
8722+ } else if self.parse_keywords(&[Keyword::AND, Keyword::NO, Keyword::STATISTICS]) {
8723+ Some(false)
8724+ } else {
8725+ None
8726+ };
8727+
8728+ Ok(Some(WithData { data, statistics }))
8729+ }
8730+
86638731 fn maybe_parse_create_table_like(
86648732 &mut self,
86658733 allow_unquoted_hyphen: bool,
0 commit comments