From f922986ea3b1e9fbfb49aabcb728367efa360edd Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 29 Oct 2025 09:52:39 -0400 Subject: [PATCH 1/3] Add RESET to the Postgres dialect #2078 --- src/ast/mod.rs | 47 +++++++++++++++++++++++++++++++++++++ src/ast/spans.rs | 1 + src/dialect/mod.rs | 11 +++++++++ src/dialect/postgresql.rs | 7 ++++++ src/parser/mod.rs | 38 ++++++++++++++++++++++++++++++ tests/sqlparser_postgres.rs | 27 +++++++++++++++++++++ 6 files changed, 131 insertions(+) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 176d36545..f33914f59 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4263,6 +4263,14 @@ pub enum Statement { /// ``` /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_VACUUM_command.html) Vacuum(VacuumStatement), + /// Restore the value of a run-time parameter to the default value. + /// + /// ```sql + /// RESET configuration_parameter; + /// RESET ALL; + /// ``` + /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-reset.html) + Reset(ResetStatement), } impl From for Statement { @@ -5757,6 +5765,7 @@ impl fmt::Display for Statement { Statement::AlterSchema(s) => write!(f, "{s}"), Statement::Vacuum(s) => write!(f, "{s}"), Statement::AlterUser(s) => write!(f, "{s}"), + Statement::Reset(s) => write!(f, "{s}"), } } } @@ -10519,6 +10528,38 @@ impl fmt::Display for VacuumStatement { } } +/// Variants of the RESET statement +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub enum Reset { + /// Resets all session parameters to their default values. + ALL, + + /// Resets a specific session parameter to its default value. + ConfigurationParameter(ObjectName), +} + +/// Resets a session parameter to its default value. +/// ```sql +/// RESET { ALL | } +/// ``` +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct ResetStatement { + pub reset: Reset, +} + +impl fmt::Display for ResetStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self.reset { + Reset::ALL => write!(f, "RESET ALL"), + Reset::ConfigurationParameter(param) => write!(f, "RESET {}", param), + } + } +} + impl From for Statement { fn from(s: Set) -> Self { Self::Set(s) @@ -10759,6 +10800,12 @@ impl From for Statement { } } +impl From for Statement { + fn from(r: ResetStatement) -> Self { + Self::Reset(r) + } +} + #[cfg(test)] mod tests { use crate::tokenizer::Location; diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 7d2a00095..34edabd97 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -475,6 +475,7 @@ impl Spanned for Statement { Statement::AlterSchema(s) => s.span(), Statement::Vacuum(..) => Span::empty(), Statement::AlterUser(..) => Span::empty(), + Statement::Reset(..) => Span::empty(), } } } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index ef4e1cdde..0fbea3b0c 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -1207,6 +1207,17 @@ pub trait Dialect: Debug + Any { fn supports_semantic_view_table_factor(&self) -> bool { false } + + /// Returns true if the dialect supports the `RESET` statement + /// for resetting session variables. + /// + /// ```sql + /// RESET configuration_parameter; + /// RESET ALL; + /// ``` + fn supports_reset(&self) -> bool { + false + } } /// This represents the operators for which precedence must be defined diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index e861cc515..a4d25a4b0 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -280,4 +280,11 @@ impl Dialect for PostgreSqlDialect { fn supports_interval_options(&self) -> bool { true } + + /// Postgres supports the `RESET` statement for resetting session variables. + /// + /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-reset.html) + fn supports_reset(&self) -> bool { + true + } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b44171c7d..2f3f1157a 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -656,6 +656,7 @@ impl<'a> Parser<'a> { self.prev_token(); self.parse_vacuum() } + Keyword::RESET if self.dialect.supports_reset() => self.parse_reset(), _ => self.expected("an SQL statement", next_token), }, Token::LParen => { @@ -17723,6 +17724,18 @@ impl<'a> Parser<'a> { _ => self.expected("expected option value", self.peek_token()), } } + + fn parse_reset(&mut self) -> Result { + // RESET { ALL | } + if self.parse_keyword(Keyword::ALL) { + return Ok(Statement::Reset(ResetStatement { reset: Reset::ALL })); + } + + let obj = self.parse_object_name(false)?; + Ok(Statement::Reset(ResetStatement { + reset: Reset::ConfigurationParameter(obj), + })) + } } fn maybe_prefixed_expr(expr: Expr, prefix: Option) -> Expr { @@ -18529,4 +18542,29 @@ mod tests { assert!(Parser::parse_sql(&GenericDialect, &sql).is_err()); } } + + #[test] + fn test_reset_all() { + let sql = "RESET ALL"; + let ast = Parser::parse_sql(&PostgreSqlDialect {}, sql).unwrap(); + assert_eq!( + ast, + vec![Statement::Reset(ResetStatement { reset: Reset::ALL })] + ); + } + + #[test] + fn test_reset_parameter() { + for w in ["parameter_name", "extension.parameter_name"] { + let sql = format!("RESET {w}"); + let parts = w.split(".").map(|s| s.into()).collect::>(); + let ast = Parser::parse_sql(&PostgreSqlDialect {}, &sql).unwrap(); + assert_eq!( + ast, + vec![Statement::Reset(ResetStatement { + reset: Reset::ConfigurationParameter(ObjectName::from(parts)) + })] + ); + } + } } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index bcc154287..c2bdf858a 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -6652,3 +6652,30 @@ fn parse_foreign_key_match_with_actions() { pg_and_generic().verified_stmt(sql); } + +#[test] +fn parse_reset_statement() { + match pg().verified_stmt("RESET some_parameter") { + Statement::Reset(ResetStatement { reset }) => match reset { + Reset::ConfigurationParameter(o) => { + assert_eq!(o, ObjectName::from(vec!["some_parameter".into()])) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + match pg().verified_stmt("RESET some_extension.some_parameter") { + Statement::Reset(ResetStatement { reset }) => match reset { + Reset::ConfigurationParameter(o) => assert_eq!( + o, + ObjectName::from(vec!["some_extension".into(), "some_parameter".into()]) + ), + _ => unreachable!(), + }, + _ => unreachable!(), + } + match pg().verified_stmt("RESET ALL") { + Statement::Reset(ResetStatement { reset }) => assert_eq!(reset, Reset::ALL), + _ => unreachable!(), + } +} From f69ff11d0b045e8a4596a26a88ceb826d8ac39cd Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Thu, 30 Oct 2025 08:27:46 -0400 Subject: [PATCH 2/3] Address PR comments --- src/dialect/mod.rs | 11 ----------- src/dialect/postgresql.rs | 7 ------- src/parser/mod.rs | 29 ++--------------------------- tests/sqlparser_common.rs | 27 +++++++++++++++++++++++++++ tests/sqlparser_postgres.rs | 27 --------------------------- 5 files changed, 29 insertions(+), 72 deletions(-) diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 0fbea3b0c..ef4e1cdde 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -1207,17 +1207,6 @@ pub trait Dialect: Debug + Any { fn supports_semantic_view_table_factor(&self) -> bool { false } - - /// Returns true if the dialect supports the `RESET` statement - /// for resetting session variables. - /// - /// ```sql - /// RESET configuration_parameter; - /// RESET ALL; - /// ``` - fn supports_reset(&self) -> bool { - false - } } /// This represents the operators for which precedence must be defined diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index a4d25a4b0..e861cc515 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -280,11 +280,4 @@ impl Dialect for PostgreSqlDialect { fn supports_interval_options(&self) -> bool { true } - - /// Postgres supports the `RESET` statement for resetting session variables. - /// - /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-reset.html) - fn supports_reset(&self) -> bool { - true - } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2f3f1157a..d508ef3d2 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -656,7 +656,7 @@ impl<'a> Parser<'a> { self.prev_token(); self.parse_vacuum() } - Keyword::RESET if self.dialect.supports_reset() => self.parse_reset(), + Keyword::RESET => self.parse_reset(), _ => self.expected("an SQL statement", next_token), }, Token::LParen => { @@ -17725,8 +17725,8 @@ impl<'a> Parser<'a> { } } + /// Parses a RESET statement fn parse_reset(&mut self) -> Result { - // RESET { ALL | } if self.parse_keyword(Keyword::ALL) { return Ok(Statement::Reset(ResetStatement { reset: Reset::ALL })); } @@ -18542,29 +18542,4 @@ mod tests { assert!(Parser::parse_sql(&GenericDialect, &sql).is_err()); } } - - #[test] - fn test_reset_all() { - let sql = "RESET ALL"; - let ast = Parser::parse_sql(&PostgreSqlDialect {}, sql).unwrap(); - assert_eq!( - ast, - vec![Statement::Reset(ResetStatement { reset: Reset::ALL })] - ); - } - - #[test] - fn test_reset_parameter() { - for w in ["parameter_name", "extension.parameter_name"] { - let sql = format!("RESET {w}"); - let parts = w.split(".").map(|s| s.into()).collect::>(); - let ast = Parser::parse_sql(&PostgreSqlDialect {}, &sql).unwrap(); - assert_eq!( - ast, - vec![Statement::Reset(ResetStatement { - reset: Reset::ConfigurationParameter(ObjectName::from(parts)) - })] - ); - } - } } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 99b7ac3fa..e625e7087 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -17613,3 +17613,30 @@ fn test_parse_alter_user() { } verified_stmt("ALTER USER u1 SET DEFAULT_SECONDARY_ROLES=('ALL'), PASSWORD='secret', WORKLOAD_IDENTITY=(TYPE=AWS, ARN='arn:aws:iam::123456789:r1/')"); } + +#[test] +fn parse_reset_statement() { + match verified_stmt("RESET some_parameter") { + Statement::Reset(ResetStatement { reset }) => match reset { + Reset::ConfigurationParameter(o) => { + assert_eq!(o, ObjectName::from(vec!["some_parameter".into()])) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + match verified_stmt("RESET some_extension.some_parameter") { + Statement::Reset(ResetStatement { reset }) => match reset { + Reset::ConfigurationParameter(o) => assert_eq!( + o, + ObjectName::from(vec!["some_extension".into(), "some_parameter".into()]) + ), + _ => unreachable!(), + }, + _ => unreachable!(), + } + match verified_stmt("RESET ALL") { + Statement::Reset(ResetStatement { reset }) => assert_eq!(reset, Reset::ALL), + _ => unreachable!(), + } +} diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index c2bdf858a..bcc154287 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -6652,30 +6652,3 @@ fn parse_foreign_key_match_with_actions() { pg_and_generic().verified_stmt(sql); } - -#[test] -fn parse_reset_statement() { - match pg().verified_stmt("RESET some_parameter") { - Statement::Reset(ResetStatement { reset }) => match reset { - Reset::ConfigurationParameter(o) => { - assert_eq!(o, ObjectName::from(vec!["some_parameter".into()])) - } - _ => unreachable!(), - }, - _ => unreachable!(), - } - match pg().verified_stmt("RESET some_extension.some_parameter") { - Statement::Reset(ResetStatement { reset }) => match reset { - Reset::ConfigurationParameter(o) => assert_eq!( - o, - ObjectName::from(vec!["some_extension".into(), "some_parameter".into()]) - ), - _ => unreachable!(), - }, - _ => unreachable!(), - } - match pg().verified_stmt("RESET ALL") { - Statement::Reset(ResetStatement { reset }) => assert_eq!(reset, Reset::ALL), - _ => unreachable!(), - } -} From 95c46f104f1fd44bbdf9ce970b4c9f301ad7a2da Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Tue, 4 Nov 2025 08:28:15 -0500 Subject: [PATCH 3/3] Fix lint failures #2078 --- src/ast/mod.rs | 9 ++------- tests/sqlparser_common.rs | 22 +++++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index f33914f59..4636e4ba2 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2787,10 +2787,11 @@ impl fmt::Display for Declare { } /// Sql options of a `CREATE TABLE` statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CreateTableOptions { + #[default] None, /// Options specified using the `WITH` keyword. /// e.g. `WITH (description = "123")` @@ -2819,12 +2820,6 @@ pub enum CreateTableOptions { TableProperties(Vec), } -impl Default for CreateTableOptions { - fn default() -> Self { - Self::None - } -} - impl fmt::Display for CreateTableOptions { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index d0732ddd1..9ea91c642 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -17636,22 +17636,18 @@ fn parse_generic_unary_ops() { #[test] fn parse_reset_statement() { match verified_stmt("RESET some_parameter") { - Statement::Reset(ResetStatement { reset }) => match reset { - Reset::ConfigurationParameter(o) => { - assert_eq!(o, ObjectName::from(vec!["some_parameter".into()])) - } - _ => unreachable!(), - }, + Statement::Reset(ResetStatement { + reset: Reset::ConfigurationParameter(o), + }) => assert_eq!(o, ObjectName::from(vec!["some_parameter".into()])), _ => unreachable!(), } match verified_stmt("RESET some_extension.some_parameter") { - Statement::Reset(ResetStatement { reset }) => match reset { - Reset::ConfigurationParameter(o) => assert_eq!( - o, - ObjectName::from(vec!["some_extension".into(), "some_parameter".into()]) - ), - _ => unreachable!(), - }, + Statement::Reset(ResetStatement { + reset: Reset::ConfigurationParameter(o), + }) => assert_eq!( + o, + ObjectName::from(vec!["some_extension".into(), "some_parameter".into()]) + ), _ => unreachable!(), } match verified_stmt("RESET ALL") {