Skip to content
This repository was archived by the owner on Jun 20, 2025. It is now read-only.

Commit e0b438b

Browse files
committed
Support pg truncate: ONLY, IDENTITY, CASCADE
1 parent 222b7d1 commit e0b438b

File tree

4 files changed

+103
-5
lines changed

4 files changed

+103
-5
lines changed

src/ast/mod.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,15 @@ pub enum Statement {
20162016
partitions: Option<Vec<Expr>>,
20172017
/// TABLE - optional keyword;
20182018
table: bool,
2019+
/// Postgres-specific option
2020+
/// TRUNCATE [ TABLE ] [ ONLY ] name
2021+
only: bool,
2022+
/// Postgres-specific option
2023+
/// [ RESTART IDENTITY | CONTINUE IDENTITY ]
2024+
identity: Option<TruncateIdentityOption>,
2025+
/// Postgres-specific option
2026+
/// [ CASCADE | RESTRICT ]
2027+
cascade: Option<TruncateCascadeOption>,
20192028
},
20202029
/// ```sql
20212030
/// MSCK
@@ -3134,9 +3143,26 @@ impl fmt::Display for Statement {
31343143
table_name,
31353144
partitions,
31363145
table,
3146+
only,
3147+
identity,
3148+
cascade,
31373149
} => {
31383150
let table = if *table { "TABLE " } else { "" };
3139-
write!(f, "TRUNCATE {table}{table_name}")?;
3151+
let only = if *only { "ONLY " } else { "" };
3152+
write!(f, "TRUNCATE {table}{only}{table_name}")?;
3153+
if let Some(identity) = identity {
3154+
match identity {
3155+
TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
3156+
TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
3157+
}
3158+
}
3159+
if let Some(cascade) = cascade {
3160+
match cascade {
3161+
TruncateCascadeOption::Cascade => write!(f, " CASCADE")?,
3162+
TruncateCascadeOption::Restrict => write!(f, " RESTRICT")?,
3163+
}
3164+
}
3165+
31403166
if let Some(ref parts) = partitions {
31413167
if !parts.is_empty() {
31423168
write!(f, " PARTITION ({})", display_comma_separated(parts))?;
@@ -4587,6 +4613,26 @@ impl fmt::Display for SequenceOptions {
45874613
}
45884614
}
45894615

4616+
/// PostgreSQL identity option for TRUNCATE table
4617+
/// [ RESTART IDENTITY | CONTINUE IDENTITY ]
4618+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4619+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4620+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4621+
pub enum TruncateIdentityOption {
4622+
Restart,
4623+
Continue,
4624+
}
4625+
4626+
/// PostgreSQL cascade option for TRUNCATE table
4627+
/// [ CASCADE | RESTRICT ]
4628+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4629+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4630+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4631+
pub enum TruncateCascadeOption {
4632+
Cascade,
4633+
Restrict,
4634+
}
4635+
45904636
/// Can use to describe options in create sequence or table column type identity
45914637
/// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
45924638
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ define_keywords!(
175175
CONNECTION,
176176
CONSTRAINT,
177177
CONTAINS,
178+
CONTINUE,
178179
CONVERT,
179180
COPY,
180181
COPY_OPTIONS,

src/parser/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,17 +681,44 @@ impl<'a> Parser<'a> {
681681

682682
pub fn parse_truncate(&mut self) -> Result<Statement, ParserError> {
683683
let table = self.parse_keyword(Keyword::TABLE);
684+
let only = self.parse_keyword(Keyword::ONLY);
684685
let table_name = self.parse_object_name(false)?;
686+
685687
let mut partitions = None;
686688
if self.parse_keyword(Keyword::PARTITION) {
687689
self.expect_token(&Token::LParen)?;
688690
partitions = Some(self.parse_comma_separated(Parser::parse_expr)?);
689691
self.expect_token(&Token::RParen)?;
690692
}
693+
694+
let mut identity = None;
695+
let mut cascade = None;
696+
697+
if dialect_of!(self is PostgreSqlDialect | GenericDialect) {
698+
identity = if self.parse_keywords(&[Keyword::RESTART, Keyword::IDENTITY]) {
699+
Some(TruncateIdentityOption::Restart)
700+
} else if self.parse_keywords(&[Keyword::CONTINUE, Keyword::IDENTITY]) {
701+
Some(TruncateIdentityOption::Continue)
702+
} else {
703+
None
704+
};
705+
706+
cascade = if self.parse_keyword(Keyword::CASCADE) {
707+
Some(TruncateCascadeOption::Cascade)
708+
} else if self.parse_keyword(Keyword::RESTRICT) {
709+
Some(TruncateCascadeOption::Restrict)
710+
} else {
711+
None
712+
};
713+
};
714+
691715
Ok(Statement::Truncate {
692716
table_name,
693717
partitions,
694718
table,
719+
only,
720+
identity,
721+
cascade,
695722
})
696723
}
697724

tests/sqlparser_postgres.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@ fn parse_alter_table_constraints_rename() {
571571
fn parse_alter_table_disable() {
572572
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE ROW LEVEL SECURITY");
573573
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE RULE rule_name");
574+
}
575+
576+
#[test]
577+
fn parse_alter_table_disable_trigger() {
574578
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER ALL");
575579
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER USER");
576580
pg_and_generic().verified_stmt("ALTER TABLE tab DISABLE TRIGGER trigger_name");
@@ -3957,7 +3961,27 @@ fn parse_truncate() {
39573961
Statement::Truncate {
39583962
table_name: ObjectName(vec![Ident::new("db"), Ident::new("table_name")]),
39593963
partitions: None,
3960-
table: false
3964+
table: false,
3965+
only: false,
3966+
identity: None,
3967+
cascade: None,
3968+
},
3969+
truncate
3970+
);
3971+
}
3972+
3973+
#[test]
3974+
fn parse_truncate_with_options() {
3975+
let truncate = pg_and_generic()
3976+
.verified_stmt("TRUNCATE TABLE ONLY db.table_name RESTART IDENTITY CASCADE");
3977+
assert_eq!(
3978+
Statement::Truncate {
3979+
table_name: ObjectName(vec![Ident::new("db"), Ident::new("table_name")]),
3980+
partitions: None,
3981+
table: true,
3982+
only: true,
3983+
identity: Some(TruncateIdentityOption::Restart),
3984+
cascade: Some(TruncateCascadeOption::Cascade)
39613985
},
39623986
truncate
39633987
);
@@ -4731,12 +4755,12 @@ fn parse_trigger_related_functions() {
47314755
IF NEW.salary IS NULL THEN
47324756
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
47334757
END IF;
4734-
4758+
47354759
-- Who works for us when they must pay for it?
47364760
IF NEW.salary < 0 THEN
47374761
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
47384762
END IF;
4739-
4763+
47404764
-- Remember who changed the payroll when
47414765
NEW.last_date := current_timestamp;
47424766
NEW.last_user := current_user;
@@ -4868,7 +4892,7 @@ fn parse_trigger_related_functions() {
48684892
Expr::Value(
48694893
Value::DollarQuotedString(
48704894
DollarQuotedString {
4871-
value: "\n BEGIN\n -- Check that empname and salary are given\n IF NEW.empname IS NULL THEN\n RAISE EXCEPTION 'empname cannot be null';\n END IF;\n IF NEW.salary IS NULL THEN\n RAISE EXCEPTION '% cannot have null salary', NEW.empname;\n END IF;\n \n -- Who works for us when they must pay for it?\n IF NEW.salary < 0 THEN\n RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;\n END IF;\n \n -- Remember who changed the payroll when\n NEW.last_date := current_timestamp;\n NEW.last_user := current_user;\n RETURN NEW;\n END;\n ".to_owned(),
4895+
value: "\n BEGIN\n -- Check that empname and salary are given\n IF NEW.empname IS NULL THEN\n RAISE EXCEPTION 'empname cannot be null';\n END IF;\n IF NEW.salary IS NULL THEN\n RAISE EXCEPTION '% cannot have null salary', NEW.empname;\n END IF;\n\n -- Who works for us when they must pay for it?\n IF NEW.salary < 0 THEN\n RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;\n END IF;\n\n -- Remember who changed the payroll when\n NEW.last_date := current_timestamp;\n NEW.last_user := current_user;\n RETURN NEW;\n END;\n ".to_owned(),
48724896
tag: Some(
48734897
"emp_stamp".to_owned(),
48744898
),

0 commit comments

Comments
 (0)