Postgres: Apply ONLY keyword per table in TRUNCATE stmt (#1872)

This commit is contained in:
Mohamed Abdeen 2025-06-06 08:10:03 +01:00 committed by GitHub
parent de2cc7b502
commit 4cf5e571d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 44 additions and 14 deletions

View file

@ -3014,9 +3014,6 @@ pub enum Statement {
/// TABLE - optional keyword; /// TABLE - optional keyword;
table: bool, table: bool,
/// Postgres-specific option /// Postgres-specific option
/// [ TRUNCATE TABLE ONLY ]
only: bool,
/// Postgres-specific option
/// [ RESTART IDENTITY | CONTINUE IDENTITY ] /// [ RESTART IDENTITY | CONTINUE IDENTITY ]
identity: Option<TruncateIdentityOption>, identity: Option<TruncateIdentityOption>,
/// Postgres-specific option /// Postgres-specific option
@ -4425,17 +4422,15 @@ impl fmt::Display for Statement {
table_names, table_names,
partitions, partitions,
table, table,
only,
identity, identity,
cascade, cascade,
on_cluster, on_cluster,
} => { } => {
let table = if *table { "TABLE " } else { "" }; let table = if *table { "TABLE " } else { "" };
let only = if *only { "ONLY " } else { "" };
write!( write!(
f, f,
"TRUNCATE {table}{only}{table_names}", "TRUNCATE {table}{table_names}",
table_names = display_comma_separated(table_names) table_names = display_comma_separated(table_names)
)?; )?;
@ -6106,10 +6101,17 @@ pub struct TruncateTableTarget {
/// name of the table being truncated /// name of the table being truncated
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))] #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub name: ObjectName, pub name: ObjectName,
/// Postgres-specific option
/// [ TRUNCATE TABLE ONLY ]
/// <https://www.postgresql.org/docs/current/sql-truncate.html>
pub only: bool,
} }
impl fmt::Display for TruncateTableTarget { impl fmt::Display for TruncateTableTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.only {
write!(f, "ONLY ")?;
};
write!(f, "{}", self.name) write!(f, "{}", self.name)
} }
} }

View file

@ -311,7 +311,6 @@ impl Spanned for Statement {
table_names, table_names,
partitions, partitions,
table: _, table: _,
only: _,
identity: _, identity: _,
cascade: _, cascade: _,
on_cluster: _, on_cluster: _,

View file

@ -960,12 +960,13 @@ impl<'a> Parser<'a> {
pub fn parse_truncate(&mut self) -> Result<Statement, ParserError> { pub fn parse_truncate(&mut self) -> Result<Statement, ParserError> {
let table = self.parse_keyword(Keyword::TABLE); let table = self.parse_keyword(Keyword::TABLE);
let only = self.parse_keyword(Keyword::ONLY);
let table_names = self let table_names = self
.parse_comma_separated(|p| p.parse_object_name(false))? .parse_comma_separated(|p| {
Ok((p.parse_keyword(Keyword::ONLY), p.parse_object_name(false)?))
})?
.into_iter() .into_iter()
.map(|n| TruncateTableTarget { name: n }) .map(|(only, name)| TruncateTableTarget { name, only })
.collect(); .collect();
let mut partitions = None; let mut partitions = None;
@ -996,7 +997,6 @@ impl<'a> Parser<'a> {
table_names, table_names,
partitions, partitions,
table, table,
only,
identity, identity,
cascade, cascade,
on_cluster, on_cluster,

View file

@ -15302,3 +15302,31 @@ fn test_open() {
}) })
); );
} }
#[test]
fn parse_truncate_only() {
let truncate = all_dialects().verified_stmt("TRUNCATE TABLE employee, ONLY dept");
let table_names = vec![
TruncateTableTarget {
name: ObjectName::from(vec![Ident::new("employee")]),
only: false,
},
TruncateTableTarget {
name: ObjectName::from(vec![Ident::new("dept")]),
only: true,
},
];
assert_eq!(
Statement::Truncate {
table_names,
partitions: None,
table: true,
identity: None,
cascade: None,
on_cluster: None,
},
truncate
);
}

View file

@ -4788,13 +4788,13 @@ fn parse_truncate() {
let table_name = ObjectName::from(vec![Ident::new("db"), Ident::new("table_name")]); let table_name = ObjectName::from(vec![Ident::new("db"), Ident::new("table_name")]);
let table_names = vec![TruncateTableTarget { let table_names = vec![TruncateTableTarget {
name: table_name.clone(), name: table_name.clone(),
only: false,
}]; }];
assert_eq!( assert_eq!(
Statement::Truncate { Statement::Truncate {
table_names, table_names,
partitions: None, partitions: None,
table: false, table: false,
only: false,
identity: None, identity: None,
cascade: None, cascade: None,
on_cluster: None, on_cluster: None,
@ -4811,6 +4811,7 @@ fn parse_truncate_with_options() {
let table_name = ObjectName::from(vec![Ident::new("db"), Ident::new("table_name")]); let table_name = ObjectName::from(vec![Ident::new("db"), Ident::new("table_name")]);
let table_names = vec![TruncateTableTarget { let table_names = vec![TruncateTableTarget {
name: table_name.clone(), name: table_name.clone(),
only: true,
}]; }];
assert_eq!( assert_eq!(
@ -4818,7 +4819,6 @@ fn parse_truncate_with_options() {
table_names, table_names,
partitions: None, partitions: None,
table: true, table: true,
only: true,
identity: Some(TruncateIdentityOption::Restart), identity: Some(TruncateIdentityOption::Restart),
cascade: Some(CascadeOption::Cascade), cascade: Some(CascadeOption::Cascade),
on_cluster: None, on_cluster: None,
@ -4839,9 +4839,11 @@ fn parse_truncate_with_table_list() {
let table_names = vec![ let table_names = vec![
TruncateTableTarget { TruncateTableTarget {
name: table_name_a.clone(), name: table_name_a.clone(),
only: false,
}, },
TruncateTableTarget { TruncateTableTarget {
name: table_name_b.clone(), name: table_name_b.clone(),
only: false,
}, },
]; ];
@ -4850,7 +4852,6 @@ fn parse_truncate_with_table_list() {
table_names, table_names,
partitions: None, partitions: None,
table: true, table: true,
only: false,
identity: Some(TruncateIdentityOption::Restart), identity: Some(TruncateIdentityOption::Restart),
cascade: Some(CascadeOption::Cascade), cascade: Some(CascadeOption::Cascade),
on_cluster: None, on_cluster: None,