Skip to content

Commit 6c0e437

Browse files
postgres: support UNLOGGED tables and SET LOGGED/UNLOGGED
Add parser and AST support for PostgreSQL CREATE UNLOGGED TABLE and\nALTER TABLE ... SET LOGGED|UNLOGGED operations.\n\n- add LOGGED keyword\n- add CreateTable.unlogged and wire it through CreateTableBuilder\n- render UNLOGGED in CreateTable display\n- add AlterTableOperation::SetLogged and ::SetUnlogged display/spans\n- parse UNLOGGED only for PostgreSqlDialect|GenericDialect\n- parse ALTER TABLE SET LOGGED|UNLOGGED operations
1 parent 6f8e7b8 commit 6c0e437

File tree

5 files changed

+47
-2
lines changed

5 files changed

+47
-2
lines changed

src/ast/ddl.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,14 @@ pub enum AlterTableOperation {
442442
/// Table properties specified as SQL options.
443443
table_properties: Vec<SqlOption>,
444444
},
445+
/// `SET LOGGED`
446+
///
447+
/// Note: this is PostgreSQL-specific.
448+
SetLogged,
449+
/// `SET UNLOGGED`
450+
///
451+
/// Note: this is PostgreSQL-specific.
452+
SetUnlogged,
445453
/// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
446454
///
447455
/// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
@@ -971,6 +979,12 @@ impl fmt::Display for AlterTableOperation {
971979
display_comma_separated(table_properties)
972980
)
973981
}
982+
AlterTableOperation::SetLogged => {
983+
write!(f, "SET LOGGED")
984+
}
985+
AlterTableOperation::SetUnlogged => {
986+
write!(f, "SET UNLOGGED")
987+
}
974988
AlterTableOperation::FreezePartition {
975989
partition,
976990
with_name,
@@ -2899,6 +2913,8 @@ pub struct CreateTable {
28992913
pub or_replace: bool,
29002914
/// `TEMP` or `TEMPORARY` clause
29012915
pub temporary: bool,
2916+
/// `UNLOGGED` clause
2917+
pub unlogged: bool,
29022918
/// `EXTERNAL` clause
29032919
pub external: bool,
29042920
/// `DYNAMIC` clause
@@ -3073,7 +3089,7 @@ impl fmt::Display for CreateTable {
30733089
// `CREATE TABLE t (a INT) AS SELECT a from t2`
30743090
write!(
30753091
f,
3076-
"CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}",
3092+
"CREATE {or_replace}{external}{global}{temporary}{unlogged}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}",
30773093
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
30783094
external = if self.external { "EXTERNAL " } else { "" },
30793095
snapshot = if self.snapshot { "SNAPSHOT " } else { "" },
@@ -3088,6 +3104,7 @@ impl fmt::Display for CreateTable {
30883104
.unwrap_or(""),
30893105
if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
30903106
temporary = if self.temporary { "TEMPORARY " } else { "" },
3107+
unlogged = if self.unlogged { "UNLOGGED " } else { "" },
30913108
transient = if self.transient { "TRANSIENT " } else { "" },
30923109
volatile = if self.volatile { "VOLATILE " } else { "" },
30933110
// Only for Snowflake

src/ast/helpers/stmt_create_table.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ pub struct CreateTableBuilder {
6969
pub or_replace: bool,
7070
/// Whether the table is `TEMPORARY`.
7171
pub temporary: bool,
72+
/// Whether the table is `UNLOGGED`.
73+
pub unlogged: bool,
7274
/// Whether the table is `EXTERNAL`.
7375
pub external: bool,
7476
/// Optional `GLOBAL` flag for dialects that support it.
@@ -191,6 +193,7 @@ impl CreateTableBuilder {
191193
Self {
192194
or_replace: false,
193195
temporary: false,
196+
unlogged: false,
194197
external: false,
195198
global: None,
196199
if_not_exists: false,
@@ -260,6 +263,11 @@ impl CreateTableBuilder {
260263
self.temporary = temporary;
261264
self
262265
}
266+
/// Mark the table as `UNLOGGED`.
267+
pub fn unlogged(mut self, unlogged: bool) -> Self {
268+
self.unlogged = unlogged;
269+
self
270+
}
263271
/// Mark the table as `EXTERNAL`.
264272
pub fn external(mut self, external: bool) -> Self {
265273
self.external = external;
@@ -561,6 +569,7 @@ impl CreateTableBuilder {
561569
CreateTable {
562570
or_replace: self.or_replace,
563571
temporary: self.temporary,
572+
unlogged: self.unlogged,
564573
external: self.external,
565574
global: self.global,
566575
if_not_exists: self.if_not_exists,
@@ -642,6 +651,7 @@ impl From<CreateTable> for CreateTableBuilder {
642651
Self {
643652
or_replace: table.or_replace,
644653
temporary: table.temporary,
654+
unlogged: table.unlogged,
645655
external: table.external,
646656
global: table.global,
647657
if_not_exists: table.if_not_exists,

src/ast/spans.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ impl Spanned for CreateTable {
533533
let CreateTable {
534534
or_replace: _, // bool
535535
temporary: _, // bool
536+
unlogged: _, // bool
536537
external: _, // bool
537538
global: _, // bool
538539
dynamic: _, // bool
@@ -1196,6 +1197,8 @@ impl Spanned for AlterTableOperation {
11961197
AlterTableOperation::SetTblProperties { table_properties } => {
11971198
union_spans(table_properties.iter().map(|i| i.span()))
11981199
}
1200+
AlterTableOperation::SetLogged => Span::empty(),
1201+
AlterTableOperation::SetUnlogged => Span::empty(),
11991202
AlterTableOperation::OwnerTo { .. } => Span::empty(),
12001203
AlterTableOperation::ClusterBy { exprs } => union_spans(exprs.iter().map(|e| e.span())),
12011204
AlterTableOperation::DropClusteringKey => Span::empty(),

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ define_keywords!(
593593
LOCK,
594594
LOCKED,
595595
LOG,
596+
LOGGED,
596597
LOGIN,
597598
LOGS,
598599
LONG,

src/parser/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5108,14 +5108,18 @@ impl<'a> Parser<'a> {
51085108
let temporary = self
51095109
.parse_one_of_keywords(&[Keyword::TEMP, Keyword::TEMPORARY])
51105110
.is_some();
5111+
let unlogged = dialect_of!(self is PostgreSqlDialect | GenericDialect)
5112+
&& self.parse_keyword(Keyword::UNLOGGED);
51115113
let persistent = dialect_of!(self is DuckDbDialect)
51125114
&& self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some();
51135115
let create_view_params = self.parse_create_view_params()?;
51145116
if self.peek_keywords(&[Keyword::SNAPSHOT, Keyword::TABLE]) {
51155117
self.parse_create_snapshot_table().map(Into::into)
51165118
} else if self.parse_keyword(Keyword::TABLE) {
5117-
self.parse_create_table(or_replace, temporary, global, transient)
5119+
self.parse_create_table(or_replace, temporary, unlogged, global, transient)
51185120
.map(Into::into)
5121+
} else if unlogged {
5122+
self.expected_ref("TABLE after UNLOGGED", self.peek_token_ref())
51195123
} else if self.peek_keyword(Keyword::MATERIALIZED)
51205124
|| self.peek_keyword(Keyword::VIEW)
51215125
|| self.peek_keywords(&[Keyword::SECURE, Keyword::MATERIALIZED, Keyword::VIEW])
@@ -8340,6 +8344,7 @@ impl<'a> Parser<'a> {
83408344
&mut self,
83418345
or_replace: bool,
83428346
temporary: bool,
8347+
unlogged: bool,
83438348
global: Option<bool>,
83448349
transient: bool,
83458350
) -> Result<CreateTable, ParserError> {
@@ -8489,6 +8494,7 @@ impl<'a> Parser<'a> {
84898494

84908495
Ok(CreateTableBuilder::new(table_name)
84918496
.temporary(temporary)
8497+
.unlogged(unlogged)
84928498
.columns(columns)
84938499
.constraints(constraints)
84948500
.or_replace(or_replace)
@@ -10525,6 +10531,14 @@ impl<'a> Parser<'a> {
1052510531
} else if self.parse_keywords(&[Keyword::VALIDATE, Keyword::CONSTRAINT]) {
1052610532
let name = self.parse_identifier()?;
1052710533
AlterTableOperation::ValidateConstraint { name }
10534+
} else if dialect_of!(self is PostgreSqlDialect | GenericDialect)
10535+
&& self.parse_keywords(&[Keyword::SET, Keyword::LOGGED])
10536+
{
10537+
AlterTableOperation::SetLogged
10538+
} else if dialect_of!(self is PostgreSqlDialect | GenericDialect)
10539+
&& self.parse_keywords(&[Keyword::SET, Keyword::UNLOGGED])
10540+
{
10541+
AlterTableOperation::SetUnlogged
1052810542
} else {
1052910543
let mut options =
1053010544
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;

0 commit comments

Comments
 (0)