This is an automated email from the ASF dual-hosted git repository.

iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 85f85515 SET with a list of comma separated assignments (#1757)
85f85515 is described below

commit 85f855150fddf9326b0c2de0a5808fb46a1f2527
Author: Mohamed Abdeen <[email protected]>
AuthorDate: Wed Mar 12 22:02:39 2025 +0200

    SET with a list of comma separated assignments (#1757)
---
 src/ast/mod.rs              | 361 ++++++++++++++++++++++++++------------------
 src/ast/spans.rs            |  15 +-
 src/dialect/mod.rs          |  10 ++
 src/dialect/mssql.rs        |   1 +
 src/dialect/mysql.rs        |   4 +
 src/keywords.rs             |   2 +
 src/parser/mod.rs           | 294 ++++++++++++++++++++++++------------
 tests/sqlparser_common.rs   | 119 ++++++++-------
 tests/sqlparser_hive.rs     |  17 +--
 tests/sqlparser_mssql.rs    |   8 +-
 tests/sqlparser_mysql.rs    |  22 +--
 tests/sqlparser_postgres.rs |  82 +++++-----
 12 files changed, 562 insertions(+), 373 deletions(-)

diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index e5e4aef0..8ab3fc0f 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -2394,6 +2394,168 @@ pub enum CreatePolicyCommand {
     Delete,
 }
 
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum Set {
+    /// SQL Standard-style
+    /// SET a = 1;
+    SingleAssignment {
+        local: bool,
+        hivevar: bool,
+        variable: ObjectName,
+        values: Vec<Expr>,
+    },
+    /// Snowflake-style
+    /// SET (a, b, ..) = (1, 2, ..);
+    ParenthesizedAssignments {
+        variables: Vec<ObjectName>,
+        values: Vec<Expr>,
+    },
+    /// MySQL-style
+    /// SET a = 1, b = 2, ..;
+    MultipleAssignments { assignments: Vec<SetAssignment> },
+    /// MS-SQL session
+    ///
+    /// See 
<https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
+    SetSessionParam(SetSessionParamKind),
+    /// ```sql
+    /// SET [ SESSION | LOCAL ] ROLE role_name
+    /// ```
+    ///
+    /// Sets session state. Examples: [ANSI][1], [Postgresql][2], [MySQL][3], 
and [Oracle][4]
+    ///
+    /// [1]: 
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#set-role-statement
+    /// [2]: https://www.postgresql.org/docs/14/sql-set-role.html
+    /// [3]: https://dev.mysql.com/doc/refman/8.0/en/set-role.html
+    /// [4]: 
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10004.htm
+    SetRole {
+        /// Non-ANSI optional identifier to inform if the role is defined 
inside the current session (`SESSION`) or transaction (`LOCAL`).
+        context_modifier: ContextModifier,
+        /// Role name. If NONE is specified, then the current role name is 
removed.
+        role_name: Option<Ident>,
+    },
+    /// ```sql
+    /// SET TIME ZONE <value>
+    /// ```
+    ///
+    /// Note: this is a PostgreSQL-specific statements
+    /// `SET TIME ZONE <value>` is an alias for `SET timezone TO <value>` in 
PostgreSQL
+    /// However, we allow it for all dialects.
+    SetTimeZone { local: bool, value: Expr },
+    /// ```sql
+    /// SET NAMES 'charset_name' [COLLATE 'collation_name']
+    /// ```
+    SetNames {
+        charset_name: Ident,
+        collation_name: Option<String>,
+    },
+    /// ```sql
+    /// SET NAMES DEFAULT
+    /// ```
+    ///
+    /// Note: this is a MySQL-specific statement.
+    SetNamesDefault {},
+    /// ```sql
+    /// SET TRANSACTION ...
+    /// ```
+    SetTransaction {
+        modes: Vec<TransactionMode>,
+        snapshot: Option<Value>,
+        session: bool,
+    },
+}
+
+impl Display for Set {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::ParenthesizedAssignments { variables, values } => write!(
+                f,
+                "SET ({}) = ({})",
+                display_comma_separated(variables),
+                display_comma_separated(values)
+            ),
+            Self::MultipleAssignments { assignments } => {
+                write!(f, "SET {}", display_comma_separated(assignments))
+            }
+            Self::SetRole {
+                context_modifier,
+                role_name,
+            } => {
+                let role_name = role_name.clone().unwrap_or_else(|| 
Ident::new("NONE"));
+                write!(f, "SET{context_modifier} ROLE {role_name}")
+            }
+            Self::SetSessionParam(kind) => write!(f, "SET {kind}"),
+            Self::SetTransaction {
+                modes,
+                snapshot,
+                session,
+            } => {
+                if *session {
+                    write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
+                } else {
+                    write!(f, "SET TRANSACTION")?;
+                }
+                if !modes.is_empty() {
+                    write!(f, " {}", display_comma_separated(modes))?;
+                }
+                if let Some(snapshot_id) = snapshot {
+                    write!(f, " SNAPSHOT {snapshot_id}")?;
+                }
+                Ok(())
+            }
+            Self::SetTimeZone { local, value } => {
+                f.write_str("SET ")?;
+                if *local {
+                    f.write_str("LOCAL ")?;
+                }
+                write!(f, "TIME ZONE {value}")
+            }
+            Self::SetNames {
+                charset_name,
+                collation_name,
+            } => {
+                write!(f, "SET NAMES {}", charset_name)?;
+
+                if let Some(collation) = collation_name {
+                    f.write_str(" COLLATE ")?;
+                    f.write_str(collation)?;
+                };
+
+                Ok(())
+            }
+            Self::SetNamesDefault {} => {
+                f.write_str("SET NAMES DEFAULT")?;
+
+                Ok(())
+            }
+            Set::SingleAssignment {
+                local,
+                hivevar,
+                variable,
+                values,
+            } => {
+                write!(
+                    f,
+                    "SET {}{}{} = {}",
+                    if *local { "LOCAL " } else { "" },
+                    if *hivevar { "HIVEVAR:" } else { "" },
+                    variable,
+                    display_comma_separated(values)
+                )
+            }
+        }
+    }
+}
+
+/// Convert a `Set` into a `Statement`.
+/// Convenience function, instead of writing `Statement::Set(Set::Set...{...})`
+impl From<Set> for Statement {
+    fn from(set: Set) -> Self {
+        Statement::Set(set)
+    }
+}
+
 /// A top-level statement (SELECT, INSERT, CREATE, etc.)
 #[allow(clippy::large_enum_variant)]
 #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
@@ -2419,6 +2581,7 @@ pub enum Statement {
         compute_statistics: bool,
         has_table_keyword: bool,
     },
+    Set(Set),
     /// ```sql
     /// TRUNCATE
     /// ```
@@ -2846,7 +3009,10 @@ pub enum Statement {
     /// DROP CONNECTOR
     /// ```
     /// See 
[Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
-    DropConnector { if_exists: bool, name: Ident },
+    DropConnector {
+        if_exists: bool,
+        name: Ident,
+    },
     /// ```sql
     /// DECLARE
     /// ```
@@ -2854,7 +3020,9 @@ pub enum Statement {
     ///
     /// Note: this is a PostgreSQL-specific statement,
     /// but may also compatible with other SQL.
-    Declare { stmts: Vec<Declare> },
+    Declare {
+        stmts: Vec<Declare>,
+    },
     /// ```sql
     /// CREATE EXTENSION [ IF NOT EXISTS ] extension_name
     ///     [ WITH ] [ SCHEMA schema_name ]
@@ -2916,67 +3084,23 @@ pub enum Statement {
     ///
     /// Note: this is a PostgreSQL-specific statement,
     /// but may also compatible with other SQL.
-    Discard { object_type: DiscardObject },
-    /// ```sql
-    /// SET [ SESSION | LOCAL ] ROLE role_name
-    /// ```
-    ///
-    /// Sets session state. Examples: [ANSI][1], [Postgresql][2], [MySQL][3], 
and [Oracle][4]
-    ///
-    /// [1]: 
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#set-role-statement
-    /// [2]: https://www.postgresql.org/docs/14/sql-set-role.html
-    /// [3]: https://dev.mysql.com/doc/refman/8.0/en/set-role.html
-    /// [4]: 
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10004.htm
-    SetRole {
-        /// Non-ANSI optional identifier to inform if the role is defined 
inside the current session (`SESSION`) or transaction (`LOCAL`).
-        context_modifier: ContextModifier,
-        /// Role name. If NONE is specified, then the current role name is 
removed.
-        role_name: Option<Ident>,
-    },
-    /// ```sql
-    /// SET <variable> = expression;
-    /// SET (variable[, ...]) = (expression[, ...]);
-    /// ```
-    ///
-    /// Note: this is not a standard SQL statement, but it is supported by at
-    /// least MySQL and PostgreSQL. Not all MySQL-specific syntactic forms are
-    /// supported yet.
-    SetVariable {
-        local: bool,
-        hivevar: bool,
-        variables: OneOrManyWithParens<ObjectName>,
-        value: Vec<Expr>,
+    Discard {
+        object_type: DiscardObject,
     },
-    /// ```sql
-    /// SET TIME ZONE <value>
-    /// ```
-    ///
-    /// Note: this is a PostgreSQL-specific statements
-    /// `SET TIME ZONE <value>` is an alias for `SET timezone TO <value>` in 
PostgreSQL
-    SetTimeZone { local: bool, value: Expr },
-    /// ```sql
-    /// SET NAMES 'charset_name' [COLLATE 'collation_name']
-    /// ```
-    SetNames {
-        charset_name: Ident,
-        collation_name: Option<String>,
-    },
-    /// ```sql
-    /// SET NAMES DEFAULT
-    /// ```
-    ///
-    /// Note: this is a MySQL-specific statement.
-    SetNamesDefault {},
     /// `SHOW FUNCTIONS`
     ///
     /// Note: this is a Presto-specific statement.
-    ShowFunctions { filter: Option<ShowStatementFilter> },
+    ShowFunctions {
+        filter: Option<ShowStatementFilter>,
+    },
     /// ```sql
     /// SHOW <variable>
     /// ```
     ///
     /// Note: this is a PostgreSQL-specific statement.
-    ShowVariable { variable: Vec<Ident> },
+    ShowVariable {
+        variable: Vec<Ident>,
+    },
     /// ```sql
     /// SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern' | WHERE expr]
     /// ```
@@ -3060,7 +3184,9 @@ pub enum Statement {
     /// ```
     ///
     /// Note: this is a MySQL-specific statement.
-    ShowCollation { filter: Option<ShowStatementFilter> },
+    ShowCollation {
+        filter: Option<ShowStatementFilter>,
+    },
     /// ```sql
     /// `USE ...`
     /// ```
@@ -3103,14 +3229,6 @@ pub enum Statement {
         has_end_keyword: bool,
     },
     /// ```sql
-    /// SET TRANSACTION ...
-    /// ```
-    SetTransaction {
-        modes: Vec<TransactionMode>,
-        snapshot: Option<Value>,
-        session: bool,
-    },
-    /// ```sql
     /// COMMENT ON ...
     /// ```
     ///
@@ -3329,7 +3447,10 @@ pub enum Statement {
     /// ```
     ///
     /// Note: this is a PostgreSQL-specific statement.
-    Deallocate { name: Ident, prepare: bool },
+    Deallocate {
+        name: Ident,
+        prepare: bool,
+    },
     /// ```sql
     /// An `EXECUTE` statement
     /// ```
@@ -3415,11 +3536,15 @@ pub enum Statement {
     /// SAVEPOINT
     /// ```
     /// Define a new savepoint within the current transaction
-    Savepoint { name: Ident },
+    Savepoint {
+        name: Ident,
+    },
     /// ```sql
     /// RELEASE [ SAVEPOINT ] savepoint_name
     /// ```
-    ReleaseSavepoint { name: Ident },
+    ReleaseSavepoint {
+        name: Ident,
+    },
     /// A `MERGE` statement.
     ///
     /// ```sql
@@ -3499,7 +3624,9 @@ pub enum Statement {
     /// LOCK TABLES <table_name> [READ [LOCAL] | [LOW_PRIORITY] WRITE]
     /// ```
     /// Note: this is a MySQL-specific statement. See 
<https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
-    LockTables { tables: Vec<LockTable> },
+    LockTables {
+        tables: Vec<LockTable>,
+    },
     /// ```sql
     /// UNLOCK TABLES
     /// ```
@@ -3533,14 +3660,18 @@ pub enum Statement {
     /// listen for a notification channel
     ///
     /// See Postgres <https://www.postgresql.org/docs/current/sql-listen.html>
-    LISTEN { channel: Ident },
+    LISTEN {
+        channel: Ident,
+    },
     /// ```sql
     /// UNLISTEN
     /// ```
     /// stop listening for a notification
     ///
     /// See Postgres 
<https://www.postgresql.org/docs/current/sql-unlisten.html>
-    UNLISTEN { channel: Ident },
+    UNLISTEN {
+        channel: Ident,
+    },
     /// ```sql
     /// NOTIFY channel [ , payload ]
     /// ```
@@ -3580,10 +3711,6 @@ pub enum Statement {
     /// Snowflake `REMOVE`
     /// See: <https://docs.snowflake.com/en/sql-reference/sql/remove>
     Remove(FileStagingCommand),
-    /// MS-SQL session
-    ///
-    /// See 
<https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
-    SetSessionParam(SetSessionParamKind),
     /// RaiseError (MSSQL)
     /// RAISERROR ( { msg_id | msg_str | @local_variable }
     /// { , severity , state }
@@ -4644,59 +4771,7 @@ impl fmt::Display for Statement {
                 write!(f, "DISCARD {object_type}")?;
                 Ok(())
             }
-            Self::SetRole {
-                context_modifier,
-                role_name,
-            } => {
-                let role_name = role_name.clone().unwrap_or_else(|| 
Ident::new("NONE"));
-                write!(f, "SET{context_modifier} ROLE {role_name}")
-            }
-            Statement::SetVariable {
-                local,
-                variables,
-                hivevar,
-                value,
-            } => {
-                f.write_str("SET ")?;
-                if *local {
-                    f.write_str("LOCAL ")?;
-                }
-                let parenthesized = matches!(variables, 
OneOrManyWithParens::Many(_));
-                write!(
-                    f,
-                    "{hivevar}{name} = {l_paren}{value}{r_paren}",
-                    hivevar = if *hivevar { "HIVEVAR:" } else { "" },
-                    name = variables,
-                    l_paren = parenthesized.then_some("(").unwrap_or_default(),
-                    value = display_comma_separated(value),
-                    r_paren = parenthesized.then_some(")").unwrap_or_default(),
-                )
-            }
-            Statement::SetTimeZone { local, value } => {
-                f.write_str("SET ")?;
-                if *local {
-                    f.write_str("LOCAL ")?;
-                }
-                write!(f, "TIME ZONE {value}")
-            }
-            Statement::SetNames {
-                charset_name,
-                collation_name,
-            } => {
-                write!(f, "SET NAMES {}", charset_name)?;
-
-                if let Some(collation) = collation_name {
-                    f.write_str(" COLLATE ")?;
-                    f.write_str(collation)?;
-                };
-
-                Ok(())
-            }
-            Statement::SetNamesDefault {} => {
-                f.write_str("SET NAMES DEFAULT")?;
-
-                Ok(())
-            }
+            Self::Set(set) => write!(f, "{set}"),
             Statement::ShowVariable { variable } => {
                 write!(f, "SHOW")?;
                 if !variable.is_empty() {
@@ -4885,24 +4960,6 @@ impl fmt::Display for Statement {
                 }
                 Ok(())
             }
-            Statement::SetTransaction {
-                modes,
-                snapshot,
-                session,
-            } => {
-                if *session {
-                    write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
-                } else {
-                    write!(f, "SET TRANSACTION")?;
-                }
-                if !modes.is_empty() {
-                    write!(f, " {}", display_comma_separated(modes))?;
-                }
-                if let Some(snapshot_id) = snapshot {
-                    write!(f, " SNAPSHOT {snapshot_id}")?;
-                }
-                Ok(())
-            }
             Statement::Commit {
                 chain,
                 end: end_syntax,
@@ -5333,7 +5390,6 @@ impl fmt::Display for Statement {
 
             Statement::List(command) => write!(f, "LIST {command}"),
             Statement::Remove(command) => write!(f, "REMOVE {command}"),
-            Statement::SetSessionParam(kind) => write!(f, "SET {kind}"),
         }
     }
 }
@@ -5397,6 +5453,21 @@ impl fmt::Display for SequenceOptions {
     }
 }
 
+/// Assignment for a `SET` statement (name [=|TO] value)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct SetAssignment {
+    pub name: ObjectName,
+    pub value: Expr,
+}
+
+impl fmt::Display for SetAssignment {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} = {}", self.name, self.value)
+    }
+}
+
 /// Target of a `TRUNCATE TABLE` command
 ///
 /// Note this is its own struct because `visit_relation` requires an 
`ObjectName` (not a `Vec<ObjectName>`)
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 8c3eff3c..fb0fc3f3 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -230,11 +230,7 @@ impl Spanned for Values {
 /// - [Statement::Fetch]
 /// - [Statement::Flush]
 /// - [Statement::Discard]
-/// - [Statement::SetRole]
-/// - [Statement::SetVariable]
-/// - [Statement::SetTimeZone]
-/// - [Statement::SetNames]
-/// - [Statement::SetNamesDefault]
+/// - [Statement::Set]
 /// - [Statement::ShowFunctions]
 /// - [Statement::ShowVariable]
 /// - [Statement::ShowStatus]
@@ -244,7 +240,6 @@ impl Spanned for Values {
 /// - [Statement::ShowTables]
 /// - [Statement::ShowCollation]
 /// - [Statement::StartTransaction]
-/// - [Statement::SetTransaction]
 /// - [Statement::Comment]
 /// - [Statement::Commit]
 /// - [Statement::Rollback]
@@ -445,11 +440,7 @@ impl Spanned for Statement {
             Statement::Fetch { .. } => Span::empty(),
             Statement::Flush { .. } => Span::empty(),
             Statement::Discard { .. } => Span::empty(),
-            Statement::SetRole { .. } => Span::empty(),
-            Statement::SetVariable { .. } => Span::empty(),
-            Statement::SetTimeZone { .. } => Span::empty(),
-            Statement::SetNames { .. } => Span::empty(),
-            Statement::SetNamesDefault {} => Span::empty(),
+            Statement::Set(_) => Span::empty(),
             Statement::ShowFunctions { .. } => Span::empty(),
             Statement::ShowVariable { .. } => Span::empty(),
             Statement::ShowStatus { .. } => Span::empty(),
@@ -460,7 +451,6 @@ impl Spanned for Statement {
             Statement::ShowCollation { .. } => Span::empty(),
             Statement::Use(u) => u.span(),
             Statement::StartTransaction { .. } => Span::empty(),
-            Statement::SetTransaction { .. } => Span::empty(),
             Statement::Comment { .. } => Span::empty(),
             Statement::Commit { .. } => Span::empty(),
             Statement::Rollback { .. } => Span::empty(),
@@ -509,7 +499,6 @@ impl Spanned for Statement {
             Statement::RenameTable { .. } => Span::empty(),
             Statement::RaisError { .. } => Span::empty(),
             Statement::List(..) | Statement::Remove(..) => Span::empty(),
-            Statement::SetSessionParam { .. } => Span::empty(),
         }
     }
 }
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index aeb097cf..8d4557e2 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -399,6 +399,16 @@ pub trait Dialect: Debug + Any {
         false
     }
 
+    /// Returns true if the dialect supports multiple `SET` statements
+    /// in a single statement.
+    ///
+    /// ```sql
+    /// SET variable = expression [, variable = expression];
+    /// ```
+    fn supports_comma_separated_set_assignments(&self) -> bool {
+        false
+    }
+
     /// Returns true if the dialect supports an `EXCEPT` clause following a
     /// wildcard in a select list.
     ///
diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs
index aeed1eb7..3db34748 100644
--- a/src/dialect/mssql.rs
+++ b/src/dialect/mssql.rs
@@ -82,6 +82,7 @@ impl Dialect for MsSqlDialect {
     fn supports_start_transaction_modifier(&self) -> bool {
         true
     }
+
     fn supports_end_transaction_modifier(&self) -> bool {
         true
     }
diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs
index 0bdfc9bf..2077ea19 100644
--- a/src/dialect/mysql.rs
+++ b/src/dialect/mysql.rs
@@ -141,6 +141,10 @@ impl Dialect for MySqlDialect {
     fn supports_set_names(&self) -> bool {
         true
     }
+
+    fn supports_comma_separated_set_assignments(&self) -> bool {
+        true
+    }
 }
 
 /// `LOCK TABLES`
diff --git a/src/keywords.rs b/src/keywords.rs
index bda817df..195bbb17 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -173,6 +173,7 @@ define_keywords!(
     CHANNEL,
     CHAR,
     CHARACTER,
+    CHARACTERISTICS,
     CHARACTERS,
     CHARACTER_LENGTH,
     CHARSET,
@@ -557,6 +558,7 @@ define_keywords!(
     MULTISET,
     MUTATION,
     NAME,
+    NAMES,
     NANOSECOND,
     NANOSECONDS,
     NATIONAL,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 400a9480..32a7bccd 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -4314,7 +4314,8 @@ impl<'a> Parser<'a> {
     }
 
     /// Run a parser method `f`, reverting back to the current position if 
unsuccessful.
-    /// Returns `None` if `f` returns an error
+    /// Returns `ParserError::RecursionLimitExceeded` if `f` returns a 
`RecursionLimitExceeded`.
+    /// Returns `Ok(None)` if `f` returns any other error.
     pub fn maybe_parse<T, F>(&mut self, f: F) -> Result<Option<T>, ParserError>
     where
         F: FnMut(&mut Parser) -> Result<T, ParserError>,
@@ -10978,47 +10979,108 @@ impl<'a> Parser<'a> {
         } else {
             Some(self.parse_identifier()?)
         };
-        Ok(Statement::SetRole {
+        Ok(Statement::Set(Set::SetRole {
             context_modifier,
             role_name,
-        })
+        }))
     }
 
-    pub fn parse_set(&mut self) -> Result<Statement, ParserError> {
-        let modifier =
-            self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL, 
Keyword::HIVEVAR]);
-        if let Some(Keyword::HIVEVAR) = modifier {
-            self.expect_token(&Token::Colon)?;
-        } else if let Some(set_role_stmt) =
-            self.maybe_parse(|parser| parser.parse_set_role(modifier))?
-        {
-            return Ok(set_role_stmt);
+    fn parse_set_values(
+        &mut self,
+        parenthesized_assignment: bool,
+    ) -> Result<Vec<Expr>, ParserError> {
+        let mut values = vec![];
+
+        if parenthesized_assignment {
+            self.expect_token(&Token::LParen)?;
+        }
+
+        loop {
+            let value = if let Some(expr) = self.try_parse_expr_sub_query()? {
+                expr
+            } else if let Ok(expr) = self.parse_expr() {
+                expr
+            } else {
+                self.expected("variable value", self.peek_token())?
+            };
+
+            values.push(value);
+            if self.consume_token(&Token::Comma) {
+                continue;
+            }
+
+            if parenthesized_assignment {
+                self.expect_token(&Token::RParen)?;
+            }
+            return Ok(values);
         }
+    }
 
-        let variables = if self.parse_keywords(&[Keyword::TIME, 
Keyword::ZONE]) {
-            OneOrManyWithParens::One(ObjectName::from(vec!["TIMEZONE".into()]))
-        } else if self.dialect.supports_parenthesized_set_variables()
+    fn parse_set_assignment(
+        &mut self,
+    ) -> Result<(OneOrManyWithParens<ObjectName>, Expr), ParserError> {
+        let variables = if self.dialect.supports_parenthesized_set_variables()
             && self.consume_token(&Token::LParen)
         {
-            let variables = OneOrManyWithParens::Many(
+            let vars = OneOrManyWithParens::Many(
                 self.parse_comma_separated(|parser: &mut Parser<'a>| 
parser.parse_identifier())?
                     .into_iter()
                     .map(|ident| ObjectName::from(vec![ident]))
                     .collect(),
             );
             self.expect_token(&Token::RParen)?;
-            variables
+            vars
         } else {
             OneOrManyWithParens::One(self.parse_object_name(false)?)
         };
 
-        let names = matches!(&variables, OneOrManyWithParens::One(variable) if 
variable.to_string().eq_ignore_ascii_case("NAMES"));
+        if !(self.consume_token(&Token::Eq) || 
self.parse_keyword(Keyword::TO)) {
+            return self.expected("assignment operator", self.peek_token());
+        }
+
+        let values = self.parse_expr()?;
+
+        Ok((variables, values))
+    }
+
+    fn parse_set(&mut self) -> Result<Statement, ParserError> {
+        let modifier =
+            self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL, 
Keyword::HIVEVAR]);
 
-        if names && self.dialect.supports_set_names() {
+        if let Some(Keyword::HIVEVAR) = modifier {
+            self.expect_token(&Token::Colon)?;
+        }
+
+        if let Some(set_role_stmt) = self.maybe_parse(|parser| 
parser.parse_set_role(modifier))? {
+            return Ok(set_role_stmt);
+        }
+
+        // Handle special cases first
+        if self.parse_keywords(&[Keyword::TIME, Keyword::ZONE])
+            || self.parse_keyword(Keyword::TIMEZONE)
+        {
+            if self.consume_token(&Token::Eq) || 
self.parse_keyword(Keyword::TO) {
+                return Ok(Set::SingleAssignment {
+                    local: modifier == Some(Keyword::LOCAL),
+                    hivevar: modifier == Some(Keyword::HIVEVAR),
+                    variable: ObjectName::from(vec!["TIMEZONE".into()]),
+                    values: self.parse_set_values(false)?,
+                }
+                .into());
+            } else {
+                // A shorthand alias for SET TIME ZONE that doesn't require
+                // the assignment operator. It's originally PostgreSQL 
specific,
+                // but we allow it for all the dialects
+                return Ok(Set::SetTimeZone {
+                    local: modifier == Some(Keyword::LOCAL),
+                    value: self.parse_expr()?,
+                }
+                .into());
+            }
+        } else if self.dialect.supports_set_names() && 
self.parse_keyword(Keyword::NAMES) {
             if self.parse_keyword(Keyword::DEFAULT) {
-                return Ok(Statement::SetNamesDefault {});
+                return Ok(Set::SetNamesDefault {}.into());
             }
-
             let charset_name = self.parse_identifier()?;
             let collation_name = if 
self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some() {
                 Some(self.parse_literal_string()?)
@@ -11026,86 +11088,117 @@ impl<'a> Parser<'a> {
                 None
             };
 
-            return Ok(Statement::SetNames {
+            return Ok(Set::SetNames {
                 charset_name,
                 collation_name,
-            });
-        }
-
-        let parenthesized_assignment = matches!(&variables, 
OneOrManyWithParens::Many(_));
-
-        if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
-            if parenthesized_assignment {
-                self.expect_token(&Token::LParen)?;
-            }
-
-            let mut values = vec![];
-            loop {
-                let value = if let Some(expr) = 
self.try_parse_expr_sub_query()? {
-                    expr
-                } else if let Ok(expr) = self.parse_expr() {
-                    expr
-                } else {
-                    self.expected("variable value", self.peek_token())?
-                };
-
-                values.push(value);
-                if self.consume_token(&Token::Comma) {
-                    continue;
-                }
-
-                if parenthesized_assignment {
-                    self.expect_token(&Token::RParen)?;
-                }
-                return Ok(Statement::SetVariable {
-                    local: modifier == Some(Keyword::LOCAL),
-                    hivevar: Some(Keyword::HIVEVAR) == modifier,
-                    variables,
-                    value: values,
-                });
             }
-        }
-
-        let OneOrManyWithParens::One(variable) = variables else {
-            return self.expected("set variable", self.peek_token());
-        };
-
-        if variable.to_string().eq_ignore_ascii_case("TIMEZONE") {
-            // for some db (e.g. postgresql), SET TIME ZONE <value> is an 
alias for SET TIMEZONE [TO|=] <value>
-            match self.parse_expr() {
-                Ok(expr) => Ok(Statement::SetTimeZone {
-                    local: modifier == Some(Keyword::LOCAL),
-                    value: expr,
-                }),
-                _ => self.expected("timezone value", self.peek_token())?,
-            }
-        } else if variable.to_string() == "CHARACTERISTICS" {
+            .into());
+        } else if self.parse_keyword(Keyword::CHARACTERISTICS) {
             self.expect_keywords(&[Keyword::AS, Keyword::TRANSACTION])?;
-            Ok(Statement::SetTransaction {
+            return Ok(Set::SetTransaction {
                 modes: self.parse_transaction_modes()?,
                 snapshot: None,
                 session: true,
-            })
-        } else if variable.to_string() == "TRANSACTION" && modifier.is_none() {
+            }
+            .into());
+        } else if self.parse_keyword(Keyword::TRANSACTION) {
             if self.parse_keyword(Keyword::SNAPSHOT) {
                 let snapshot_id = self.parse_value()?.value;
-                return Ok(Statement::SetTransaction {
+                return Ok(Set::SetTransaction {
                     modes: vec![],
                     snapshot: Some(snapshot_id),
                     session: false,
-                });
+                }
+                .into());
             }
-            Ok(Statement::SetTransaction {
+            return Ok(Set::SetTransaction {
                 modes: self.parse_transaction_modes()?,
                 snapshot: None,
                 session: false,
-            })
-        } else if self.dialect.supports_set_stmt_without_operator() {
-            self.prev_token();
-            self.parse_set_session_params()
+            }
+            .into());
+        }
+
+        if self.dialect.supports_comma_separated_set_assignments() {
+            if let Some(assignments) = self
+                .maybe_parse(|parser| 
parser.parse_comma_separated(Parser::parse_set_assignment))?
+            {
+                return if assignments.len() > 1 {
+                    let assignments = assignments
+                        .into_iter()
+                        .map(|(var, val)| match var {
+                            OneOrManyWithParens::One(v) => Ok(SetAssignment {
+                                name: v,
+                                value: val,
+                            }),
+                            OneOrManyWithParens::Many(_) => {
+                                self.expected("List of single identifiers", 
self.peek_token())
+                            }
+                        })
+                        .collect::<Result<_, _>>()?;
+
+                    Ok(Set::MultipleAssignments { assignments }.into())
+                } else {
+                    let (vars, values): (Vec<_>, Vec<_>) = 
assignments.into_iter().unzip();
+
+                    let variable = match vars.into_iter().next() {
+                        Some(OneOrManyWithParens::One(v)) => Ok(v),
+                        Some(OneOrManyWithParens::Many(_)) => self.expected(
+                            "Single assignment or list of assignments",
+                            self.peek_token(),
+                        ),
+                        None => self.expected("At least one identifier", 
self.peek_token()),
+                    }?;
+
+                    Ok(Set::SingleAssignment {
+                        local: modifier == Some(Keyword::LOCAL),
+                        hivevar: modifier == Some(Keyword::HIVEVAR),
+                        variable,
+                        values,
+                    }
+                    .into())
+                };
+            }
+        }
+
+        let variables = if self.dialect.supports_parenthesized_set_variables()
+            && self.consume_token(&Token::LParen)
+        {
+            let vars = OneOrManyWithParens::Many(
+                self.parse_comma_separated(|parser: &mut Parser<'a>| 
parser.parse_identifier())?
+                    .into_iter()
+                    .map(|ident| ObjectName::from(vec![ident]))
+                    .collect(),
+            );
+            self.expect_token(&Token::RParen)?;
+            vars
         } else {
-            self.expected("equals sign or TO", self.peek_token())
+            OneOrManyWithParens::One(self.parse_object_name(false)?)
+        };
+
+        if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
+            let stmt = match variables {
+                OneOrManyWithParens::One(var) => Set::SingleAssignment {
+                    local: modifier == Some(Keyword::LOCAL),
+                    hivevar: modifier == Some(Keyword::HIVEVAR),
+                    variable: var,
+                    values: self.parse_set_values(false)?,
+                },
+                OneOrManyWithParens::Many(vars) => 
Set::ParenthesizedAssignments {
+                    variables: vars,
+                    values: self.parse_set_values(true)?,
+                },
+            };
+
+            return Ok(stmt.into());
         }
+
+        if self.dialect.supports_set_stmt_without_operator() {
+            self.prev_token();
+            return self.parse_set_session_params();
+        };
+
+        self.expected("equals sign or TO", self.peek_token())
     }
 
     pub fn parse_set_session_params(&mut self) -> Result<Statement, 
ParserError> {
@@ -11123,15 +11216,20 @@ impl<'a> Parser<'a> {
                 _ => return self.expected("IO, PROFILE, TIME or XML", 
self.peek_token()),
             };
             let value = self.parse_session_param_value()?;
-            Ok(Statement::SetSessionParam(SetSessionParamKind::Statistics(
-                SetSessionParamStatistics { topic, value },
-            )))
+            Ok(
+                
Set::SetSessionParam(SetSessionParamKind::Statistics(SetSessionParamStatistics {
+                    topic,
+                    value,
+                }))
+                .into(),
+            )
         } else if self.parse_keyword(Keyword::IDENTITY_INSERT) {
             let obj = self.parse_object_name(false)?;
             let value = self.parse_session_param_value()?;
-            Ok(Statement::SetSessionParam(
-                
SetSessionParamKind::IdentityInsert(SetSessionParamIdentityInsert { obj, value 
}),
+            Ok(Set::SetSessionParam(SetSessionParamKind::IdentityInsert(
+                SetSessionParamIdentityInsert { obj, value },
             ))
+            .into())
         } else if self.parse_keyword(Keyword::OFFSETS) {
             let keywords = self.parse_comma_separated(|parser| {
                 let next_token = parser.next_token();
@@ -11141,9 +11239,13 @@ impl<'a> Parser<'a> {
                 }
             })?;
             let value = self.parse_session_param_value()?;
-            Ok(Statement::SetSessionParam(SetSessionParamKind::Offsets(
-                SetSessionParamOffsets { keywords, value },
-            )))
+            Ok(
+                
Set::SetSessionParam(SetSessionParamKind::Offsets(SetSessionParamOffsets {
+                    keywords,
+                    value,
+                }))
+                .into(),
+            )
         } else {
             let names = self.parse_comma_separated(|parser| {
                 let next_token = parser.next_token();
@@ -11153,9 +11255,13 @@ impl<'a> Parser<'a> {
                 }
             })?;
             let value = self.parse_expr()?.to_string();
-            Ok(Statement::SetSessionParam(SetSessionParamKind::Generic(
-                SetSessionParamGeneric { names, value },
-            )))
+            Ok(
+                
Set::SetSessionParam(SetSessionParamKind::Generic(SetSessionParamGeneric {
+                    names,
+                    value,
+                }))
+                .into(),
+            )
         }
     }
 
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 8225d367..c7bf287c 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -8555,11 +8555,11 @@ fn parse_set_transaction() {
     // TRANSACTION, so no need to duplicate the tests here. We just do a quick
     // sanity check.
     match verified_stmt("SET TRANSACTION READ ONLY, READ WRITE, ISOLATION 
LEVEL SERIALIZABLE") {
-        Statement::SetTransaction {
+        Statement::Set(Set::SetTransaction {
             modes,
             session,
             snapshot,
-        } => {
+        }) => {
             assert_eq!(
                 modes,
                 vec![
@@ -8578,20 +8578,17 @@ fn parse_set_transaction() {
 #[test]
 fn parse_set_variable() {
     match verified_stmt("SET SOMETHING = '1'") {
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local,
             hivevar,
-            variables,
-            value,
-        } => {
+            variable,
+            values,
+        }) => {
             assert!(!local);
             assert!(!hivevar);
+            assert_eq!(variable, ObjectName::from(vec!["SOMETHING".into()]));
             assert_eq!(
-                variables,
-                
OneOrManyWithParens::One(ObjectName::from(vec!["SOMETHING".into()]))
-            );
-            assert_eq!(
-                value,
+                values,
                 vec![Expr::Value(
                     (Value::SingleQuotedString("1".into())).with_empty_span()
                 )]
@@ -8603,24 +8600,17 @@ fn parse_set_variable() {
     let multi_variable_dialects = all_dialects_where(|d| 
d.supports_parenthesized_set_variables());
     let sql = r#"SET (a, b, c) = (1, 2, 3)"#;
     match multi_variable_dialects.verified_stmt(sql) {
-        Statement::SetVariable {
-            local,
-            hivevar,
-            variables,
-            value,
-        } => {
-            assert!(!local);
-            assert!(!hivevar);
+        Statement::Set(Set::ParenthesizedAssignments { variables, values }) => 
{
             assert_eq!(
                 variables,
-                OneOrManyWithParens::Many(vec![
+                vec![
                     ObjectName::from(vec!["a".into()]),
                     ObjectName::from(vec!["b".into()]),
                     ObjectName::from(vec!["c".into()]),
-                ])
+                ]
             );
             assert_eq!(
-                value,
+                values,
                 vec![
                     Expr::value(number("1")),
                     Expr::value(number("2")),
@@ -8680,20 +8670,17 @@ fn parse_set_variable() {
 #[test]
 fn parse_set_role_as_variable() {
     match verified_stmt("SET role = 'foobar'") {
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local,
             hivevar,
-            variables,
-            value,
-        } => {
+            variable,
+            values,
+        }) => {
             assert!(!local);
             assert!(!hivevar);
+            assert_eq!(variable, ObjectName::from(vec!["role".into()]));
             assert_eq!(
-                variables,
-                OneOrManyWithParens::One(ObjectName::from(vec!["role".into()]))
-            );
-            assert_eq!(
-                value,
+                values,
                 vec![Expr::Value(
                     
(Value::SingleQuotedString("foobar".into())).with_empty_span()
                 )]
@@ -8730,20 +8717,17 @@ fn parse_double_colon_cast_at_timezone() {
 #[test]
 fn parse_set_time_zone() {
     match verified_stmt("SET TIMEZONE = 'UTC'") {
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local,
             hivevar,
-            variables: variable,
-            value,
-        } => {
+            variable,
+            values,
+        }) => {
             assert!(!local);
             assert!(!hivevar);
+            assert_eq!(variable, ObjectName::from(vec!["TIMEZONE".into()]));
             assert_eq!(
-                variable,
-                
OneOrManyWithParens::One(ObjectName::from(vec!["TIMEZONE".into()]))
-            );
-            assert_eq!(
-                value,
+                values,
                 vec![Expr::Value(
                     (Value::SingleQuotedString("UTC".into())).with_empty_span()
                 )]
@@ -8755,20 +8739,6 @@ fn parse_set_time_zone() {
     one_statement_parses_to("SET TIME ZONE TO 'UTC'", "SET TIMEZONE = 'UTC'");
 }
 
-#[test]
-fn parse_set_time_zone_alias() {
-    match verified_stmt("SET TIME ZONE 'UTC'") {
-        Statement::SetTimeZone { local, value } => {
-            assert!(!local);
-            assert_eq!(
-                value,
-                
Expr::Value((Value::SingleQuotedString("UTC".into())).with_empty_span())
-            );
-        }
-        _ => unreachable!(),
-    }
-}
-
 #[test]
 fn parse_commit() {
     match verified_stmt("COMMIT") {
@@ -14681,3 +14651,44 @@ fn parse_set_names() {
     dialects.verified_stmt("SET NAMES 'utf8'");
     dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
 }
+
+#[test]
+fn parse_multiple_set_statements() -> Result<(), ParserError> {
+    let dialects = all_dialects_where(|d| 
d.supports_comma_separated_set_assignments());
+    let stmt = dialects.verified_stmt("SET @a = 1, b = 2");
+
+    match stmt {
+        Statement::Set(Set::MultipleAssignments { assignments }) => {
+            assert_eq!(
+                assignments,
+                vec![
+                    SetAssignment {
+                        name: ObjectName::from(vec!["@a".into()]),
+                        value: Expr::value(number("1"))
+                    },
+                    SetAssignment {
+                        name: ObjectName::from(vec!["b".into()]),
+                        value: Expr::value(number("2"))
+                    }
+                ]
+            );
+        }
+        _ => panic!("Expected SetVariable with 2 variables and 2 values"),
+    };
+
+    Ok(())
+}
+
+#[test]
+fn parse_set_time_zone_alias() {
+    match all_dialects().verified_stmt("SET TIME ZONE 'UTC'") {
+        Statement::Set(Set::SetTimeZone { local, value }) => {
+            assert!(!local);
+            assert_eq!(
+                value,
+                
Expr::Value((Value::SingleQuotedString("UTC".into())).with_empty_span())
+            );
+        }
+        _ => unreachable!(),
+    }
+}
diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs
index d7f3c014..56fe22a0 100644
--- a/tests/sqlparser_hive.rs
+++ b/tests/sqlparser_hive.rs
@@ -22,9 +22,8 @@
 
 use sqlparser::ast::{
     ClusteredBy, CommentDef, CreateFunction, CreateFunctionBody, 
CreateFunctionUsing, CreateTable,
-    Expr, Function, FunctionArgumentList, FunctionArguments, Ident, ObjectName,
-    OneOrManyWithParens, OrderByExpr, OrderByOptions, SelectItem, Statement, 
TableFactor,
-    UnaryOperator, Use, Value,
+    Expr, Function, FunctionArgumentList, FunctionArguments, Ident, 
ObjectName, OrderByExpr,
+    OrderByOptions, SelectItem, Set, Statement, TableFactor, UnaryOperator, 
Use, Value,
 };
 use sqlparser::dialect::{GenericDialect, HiveDialect, MsSqlDialect};
 use sqlparser::parser::ParserError;
@@ -92,7 +91,7 @@ fn parse_msck() {
 }
 
 #[test]
-fn parse_set() {
+fn parse_set_hivevar() {
     let set = "SET HIVEVAR:name = a, b, c_d";
     hive().verified_stmt(set);
 }
@@ -369,20 +368,20 @@ fn from_cte() {
 fn set_statement_with_minus() {
     assert_eq!(
         hive().verified_stmt("SET hive.tez.java.opts = -Xmx4g"),
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: OneOrManyWithParens::One(ObjectName::from(vec![
+            variable: ObjectName::from(vec![
                 Ident::new("hive"),
                 Ident::new("tez"),
                 Ident::new("java"),
                 Ident::new("opts")
-            ])),
-            value: vec![Expr::UnaryOp {
+            ]),
+            values: vec![Expr::UnaryOp {
                 op: UnaryOperator::Minus,
                 expr: Box::new(Expr::Identifier(Ident::new("Xmx4g")))
             }],
-        }
+        })
     );
 
     assert_eq!(
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index 3f313af4..386bd178 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -1254,14 +1254,14 @@ fn parse_mssql_declare() {
                     for_query: None
                 }]
             },
-            Statement::SetVariable {
+            Statement::Set(Set::SingleAssignment {
                 local: false,
                 hivevar: false,
-                variables: 
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("@bar")])),
-                value: vec![Expr::Value(
+                variable: ObjectName::from(vec![Ident::new("@bar")]),
+                values: vec![Expr::Value(
                     (Value::Number("2".parse().unwrap(), 
false)).with_empty_span()
                 )],
-            },
+            }),
             Statement::Query(Box::new(Query {
                 with: None,
                 limit: None,
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 560ea9da..13a8a6cc 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -617,12 +617,12 @@ fn parse_set_variables() {
     mysql_and_generic().verified_stmt("SET sql_mode = CONCAT(@@sql_mode, 
',STRICT_TRANS_TABLES')");
     assert_eq!(
         mysql_and_generic().verified_stmt("SET LOCAL autocommit = 1"),
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: true,
             hivevar: false,
-            variables: 
OneOrManyWithParens::One(ObjectName::from(vec!["autocommit".into()])),
-            value: vec![Expr::value(number("1"))],
-        }
+            variable: ObjectName::from(vec!["autocommit".into()]),
+            values: vec![Expr::value(number("1"))],
+        })
     );
 }
 
@@ -2705,19 +2705,19 @@ fn parse_set_names() {
     let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4");
     assert_eq!(
         stmt,
-        Statement::SetNames {
+        Statement::Set(Set::SetNames {
             charset_name: "utf8mb4".into(),
             collation_name: None,
-        }
+        })
     );
 
     let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4 COLLATE 
bogus");
     assert_eq!(
         stmt,
-        Statement::SetNames {
+        Statement::Set(Set::SetNames {
             charset_name: "utf8mb4".into(),
             collation_name: Some("bogus".to_string()),
-        }
+        })
     );
 
     let stmt = mysql_and_generic()
@@ -2725,14 +2725,14 @@ fn parse_set_names() {
         .unwrap();
     assert_eq!(
         stmt,
-        vec![Statement::SetNames {
+        vec![Statement::Set(Set::SetNames {
             charset_name: "utf8mb4".into(),
             collation_name: Some("bogus".to_string()),
-        }]
+        })]
     );
 
     let stmt = mysql_and_generic().verified_stmt("SET NAMES DEFAULT");
-    assert_eq!(stmt, Statement::SetNamesDefault {});
+    assert_eq!(stmt, Statement::Set(Set::SetNamesDefault {}));
 }
 
 #[test]
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 0dfcc24e..a65c4fa3 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -1432,81 +1432,77 @@ fn parse_set() {
     let stmt = pg_and_generic().verified_stmt("SET a = b");
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: 
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
-            value: vec![Expr::Identifier(Ident {
+            variable: ObjectName::from(vec![Ident::new("a")]),
+            values: vec![Expr::Identifier(Ident {
                 value: "b".into(),
                 quote_style: None,
                 span: Span::empty(),
             })],
-        }
+        })
     );
 
     let stmt = pg_and_generic().verified_stmt("SET a = 'b'");
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: 
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
-            value: vec![Expr::Value(
+            variable: ObjectName::from(vec![Ident::new("a")]),
+            values: vec![Expr::Value(
                 (Value::SingleQuotedString("b".into())).with_empty_span()
             )],
-        }
+        })
     );
 
     let stmt = pg_and_generic().verified_stmt("SET a = 0");
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: 
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
-            value: vec![Expr::value(number("0"))],
-        }
+            variable: ObjectName::from(vec![Ident::new("a")]),
+            values: vec![Expr::value(number("0"))],
+        })
     );
 
     let stmt = pg_and_generic().verified_stmt("SET a = DEFAULT");
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: 
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
-            value: vec![Expr::Identifier(Ident::new("DEFAULT"))],
-        }
+            variable: ObjectName::from(vec![Ident::new("a")]),
+            values: vec![Expr::Identifier(Ident::new("DEFAULT"))],
+        })
     );
 
     let stmt = pg_and_generic().verified_stmt("SET LOCAL a = b");
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: true,
             hivevar: false,
-            variables: 
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
-            value: vec![Expr::Identifier("b".into())],
-        }
+            variable: ObjectName::from(vec![Ident::new("a")]),
+            values: vec![Expr::Identifier("b".into())],
+        })
     );
 
     let stmt = pg_and_generic().verified_stmt("SET a.b.c = b");
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: OneOrManyWithParens::One(ObjectName::from(vec![
-                Ident::new("a"),
-                Ident::new("b"),
-                Ident::new("c")
-            ])),
-            value: vec![Expr::Identifier(Ident {
+            variable: ObjectName::from(vec![Ident::new("a"), Ident::new("b"), 
Ident::new("c")]),
+            values: vec![Expr::Identifier(Ident {
                 value: "b".into(),
                 quote_style: None,
                 span: Span::empty(),
             })],
-        }
+        })
     );
 
     let stmt = pg_and_generic().one_statement_parses_to(
@@ -1515,18 +1511,18 @@ fn parse_set() {
     );
     assert_eq!(
         stmt,
-        Statement::SetVariable {
+        Statement::Set(Set::SingleAssignment {
             local: false,
             hivevar: false,
-            variables: OneOrManyWithParens::One(ObjectName::from(vec![
+            variable: ObjectName::from(vec![
                 Ident::new("hive"),
                 Ident::new("tez"),
                 Ident::new("auto"),
                 Ident::new("reducer"),
                 Ident::new("parallelism")
-            ])),
-            value: 
vec![Expr::Value((Value::Boolean(false)).with_empty_span())],
-        }
+            ]),
+            values: 
vec![Expr::Value((Value::Boolean(false)).with_empty_span())],
+        })
     );
 
     pg_and_generic().one_statement_parses_to("SET a TO b", "SET a = b");
@@ -1560,10 +1556,10 @@ fn parse_set_role() {
     let stmt = pg_and_generic().verified_stmt(query);
     assert_eq!(
         stmt,
-        Statement::SetRole {
+        Statement::Set(Set::SetRole {
             context_modifier: ContextModifier::Session,
             role_name: None,
-        }
+        })
     );
     assert_eq!(query, stmt.to_string());
 
@@ -1571,14 +1567,14 @@ fn parse_set_role() {
     let stmt = pg_and_generic().verified_stmt(query);
     assert_eq!(
         stmt,
-        Statement::SetRole {
+        Statement::Set(Set::SetRole {
             context_modifier: ContextModifier::Local,
             role_name: Some(Ident {
                 value: "rolename".to_string(),
                 quote_style: Some('\"'),
                 span: Span::empty(),
             }),
-        }
+        })
     );
     assert_eq!(query, stmt.to_string());
 
@@ -1586,14 +1582,14 @@ fn parse_set_role() {
     let stmt = pg_and_generic().verified_stmt(query);
     assert_eq!(
         stmt,
-        Statement::SetRole {
+        Statement::Set(Set::SetRole {
             context_modifier: ContextModifier::None,
             role_name: Some(Ident {
                 value: "rolename".to_string(),
                 quote_style: Some('\''),
                 span: Span::empty(),
             }),
-        }
+        })
     );
     assert_eq!(query, stmt.to_string());
 }
@@ -2982,16 +2978,16 @@ fn test_transaction_statement() {
     let statement = pg().verified_stmt("SET TRANSACTION SNAPSHOT 
'000003A1-1'");
     assert_eq!(
         statement,
-        Statement::SetTransaction {
+        Statement::Set(Set::SetTransaction {
             modes: vec![],
             snapshot: 
Some(Value::SingleQuotedString(String::from("000003A1-1"))),
             session: false
-        }
+        })
     );
     let statement = pg().verified_stmt("SET SESSION CHARACTERISTICS AS 
TRANSACTION READ ONLY, READ WRITE, ISOLATION LEVEL SERIALIZABLE");
     assert_eq!(
         statement,
-        Statement::SetTransaction {
+        Statement::Set(Set::SetTransaction {
             modes: vec![
                 TransactionMode::AccessMode(TransactionAccessMode::ReadOnly),
                 TransactionMode::AccessMode(TransactionAccessMode::ReadWrite),
@@ -2999,7 +2995,7 @@ fn test_transaction_statement() {
             ],
             snapshot: None,
             session: true
-        }
+        })
     );
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to