Repository: apache/datafusion-sqlparser-rs (rust)

Issue:
Parse MySQL `SET GLOBAL` variables
In addition to `SESSION` and `LOCAL` qualifiers, MySQL allows `GLOBAL` for modifying system variables:

```
mysql> SET GLOBAL max_connections = 1000;
Query OK, 0 rows affected (0.00 sec)
```

sqlparser currently interprets `global` as a variable name and fails to parse:

```
$ echo -n "SET GLOBAL max_connections = 1000;" | cargo run --example cli - --mysql
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/examples/cli - --mysql`
Parsing from stdin using MySqlDialect
2025-01-31T00:44:22.858Z DEBUG [sqlparser::parser] Parsing sql 'SET GLOBAL max_connections = 1000;'...
Error during parsing: ParserError("Expected: equals sign or TO, found: max_connections at Line: 1, Column: 12")
```

Pull request:
Add GLOBAL context/modifier to SET statements
Closes #1694

- Add a `GLOBAL` variant to ContextModifier enum.
- Replace `local: bool` field in `SetVariable` with a `scope: ContextModifier`.
- Convenience impl `From<Option<Keyword>> for ContextModifier`
- Update tests

Patch:
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 99d8521..39e43ef 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -288,6 +288,16 @@ pub enum AlterTableOperation {
         equals: bool,
         algorithm: AlterTableAlgorithm,
     },
+
+    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
+    ///
+    /// [MySQL]-specific table alter lock.
+    ///
+    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
+    Lock {
+        equals: bool,
+        lock: AlterTableLock,
+    },
     /// `AUTO_INCREMENT [=] <value>`
     ///
     /// [MySQL]-specific table option for raising current auto increment value.
@@ -366,6 +376,30 @@ impl fmt::Display for AlterTableAlgorithm {
     }
 }
 
+/// [MySQL] `ALTER TABLE` lock.
+///
+/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum AlterTableLock {
+    Default,
+    None,
+    Shared,
+    Exclusive,
+}
+
+impl fmt::Display for AlterTableLock {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match self {
+            Self::Default => "DEFAULT",
+            Self::None => "NONE",
+            Self::Shared => "SHARED",
+            Self::Exclusive => "EXCLUSIVE",
+        })
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -692,6 +726,9 @@ impl fmt::Display for AlterTableOperation {
                     value
                 )
             }
+            AlterTableOperation::Lock { equals, lock } => {
+                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
+            }
         }
     }
 }
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 8c40792..9f895ee 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -48,7 +48,7 @@ pub use self::dcl::{
 };
 pub use self::ddl::{
     AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
-    AlterTableAlgorithm, AlterTableOperation, AlterType, AlterTypeAddValue,
+    AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue,
     AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
     ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
     ConstraintCharacteristics, CreateConnector, CreateFunction, Deduplicate, DeferrableInitial,
@@ -2256,6 +2256,57 @@ impl fmt::Display for ConditionalStatements {
     }
 }
 
+/// A `RAISE` statement.
+///
+/// Examples:
+/// ```sql
+/// RAISE USING MESSAGE = 'error';
+///
+/// RAISE myerror;
+/// ```
+///
+/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#raise)
+/// [Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/raise)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct RaiseStatement {
+    pub value: Option<RaiseStatementValue>,
+}
+
+impl fmt::Display for RaiseStatement {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let RaiseStatement { value } = self;
+
+        write!(f, "RAISE")?;
+        if let Some(value) = value {
+            write!(f, " {value}")?;
+        }
+
+        Ok(())
+    }
+}
+
+/// Represents the error value of a [RaiseStatement].
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum RaiseStatementValue {
+    /// `RAISE USING MESSAGE = 'error'`
+    UsingMessage(Expr),
+    /// `RAISE myerror`
+    Expr(Expr),
+}
+
+impl fmt::Display for RaiseStatementValue {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            RaiseStatementValue::Expr(expr) => write!(f, "{expr}"),
+            RaiseStatementValue::UsingMessage(expr) => write!(f, "USING MESSAGE = {expr}"),
+        }
+    }
+}
+
 /// Represents an expression assignment within a variable `DECLARE` statement.
 ///
 /// Examples:
@@ -2578,7 +2629,7 @@ pub enum Set {
     /// SQL Standard-style
     /// SET a = 1;
     SingleAssignment {
-        local: bool,
+        scope: ContextModifier,
         hivevar: bool,
         variable: ObjectName,
         values: Vec<Expr>,
@@ -2660,7 +2711,7 @@ impl Display for Set {
                 role_name,
             } => {
                 let role_name = role_name.clone().unwrap_or_else(|| Ident::new("NONE"));
-                write!(f, "SET{context_modifier} ROLE {role_name}")
+                write!(f, "SET {context_modifier}ROLE {role_name}")
             }
             Self::SetSessionParam(kind) => write!(f, "SET {kind}"),
             Self::SetTransaction {
@@ -2707,7 +2758,7 @@ impl Display for Set {
                 Ok(())
             }
             Set::SingleAssignment {
-                local,
+                scope,
                 hivevar,
                 variable,
                 values,
@@ -2715,7 +2766,7 @@ impl Display for Set {
                 write!(
                     f,
                     "SET {}{}{} = {}",
-                    if *local { "LOCAL " } else { "" },
+                    scope,
                     if *hivevar { "HIVEVAR:" } else { "" },
                     variable,
                     display_comma_separated(values)
@@ -2827,6 +2878,8 @@ pub enum Statement {
     Case(CaseStatement),
     /// An `IF` statement.
     If(IfStatement),
+    /// A `RAISE` statement.
+    Raise(RaiseStatement),
     /// ```sql
     /// CALL <function>
     /// ```
@@ -4142,6 +4195,9 @@ impl fmt::Display for Statement {
             Statement::If(stmt) => {
                 write!(f, "{stmt}")
             }
+            Statement::Raise(stmt) => {
+                write!(f, "{stmt}")
+            }
             Statement::AttachDatabase {
                 schema_name,
                 database_file_name,
@@ -7899,7 +7955,7 @@ impl fmt::Display for FlushLocation {
     }
 }
 
-/// Optional context modifier for statements that can be or `LOCAL`, or `SESSION`.
+/// Optional context modifier for statements that can be or `LOCAL`, `GLOBAL`, or `SESSION`.
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -7910,6 +7966,8 @@ pub enum ContextModifier {
     Local,
     /// `SESSION` identifier
     Session,
+    /// `GLOBAL` identifier
+    Global,
 }
 
 impl fmt::Display for ContextModifier {
@@ -7919,10 +7977,13 @@ impl fmt::Display for ContextModifier {
                 write!(f, "")
             }
             Self::Local => {
-                write!(f, " LOCAL")
+                write!(f, "LOCAL ")
             }
             Self::Session => {
-                write!(f, " SESSION")
+                write!(f, "SESSION ")
+            }
+            Self::Global => {
+                write!(f, "GLOBAL ")
             }
         }
     }
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 0ee11f2..65d43c1 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -32,11 +32,11 @@ use super::{
     JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause, MatchRecognizePattern, Measure,
     NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
     OnInsert, OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource, ProjectionSelect,
-    Query, ReferentialAction, RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select,
-    SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias,
-    TableAliasColumnDef, TableConstraint, TableFactor, TableObject, TableOptionsClustered,
-    TableWithJoins, UpdateTableFromKind, Use, Value, Values, ViewColumnDef,
-    WildcardAdditionalOptions, With, WithFill,
+    Query, RaiseStatement, RaiseStatementValue, ReferentialAction, RenameSelectItem,
+    ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption,
+    Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint,
+    TableFactor, TableObject, TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use,
+    Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill,
 };
 
 /// Given an iterator of spans, return the [Span::union] of all spans.
@@ -337,6 +337,7 @@ impl Spanned for Statement {
             } => source.span(),
             Statement::Case(stmt) => stmt.span(),
             Statement::If(stmt) => stmt.span(),
+            Statement::Raise(stmt) => stmt.span(),
             Statement::Call(function) => function.span(),
             Statement::Copy {
                 source,
@@ -782,6 +783,23 @@ impl Spanned for ConditionalStatements {
     }
 }
 
+impl Spanned for RaiseStatement {
+    fn span(&self) -> Span {
+        let RaiseStatement { value } = self;
+
+        union_spans(value.iter().map(|value| value.span()))
+    }
+}
+
+impl Spanned for RaiseStatementValue {
+    fn span(&self) -> Span {
+        match self {
+            RaiseStatementValue::UsingMessage(expr) => expr.span(),
+            RaiseStatementValue::Expr(expr) => expr.span(),
+        }
+    }
+}
+
 /// # partial span
 ///
 /// Missing spans:
@@ -1119,6 +1137,7 @@ impl Spanned for AlterTableOperation {
             AlterTableOperation::ResumeRecluster => Span::empty(),
             AlterTableOperation::Algorithm { .. } => Span::empty(),
             AlterTableOperation::AutoIncrement { value, .. } => value.span(),
+            AlterTableOperation::Lock { .. } => Span::empty(),
         }
     }
 }
diff --git a/src/keywords.rs b/src/keywords.rs
index 47da100..7b9c8bf 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -533,6 +533,7 @@ define_keywords!(
     MEDIUMTEXT,
     MEMBER,
     MERGE,
+    MESSAGE,
     METADATA,
     METHOD,
     METRIC,
@@ -695,6 +696,7 @@ define_keywords!(
     QUARTER,
     QUERY,
     QUOTE,
+    RAISE,
     RAISERROR,
     RANGE,
     RANK,
@@ -797,6 +799,7 @@ define_keywords!(
     SETS,
     SETTINGS,
     SHARE,
+    SHARED,
     SHARING,
     SHOW,
     SIGNED,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index e4c170e..dcf7a4a 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -536,6 +536,10 @@ impl<'a> Parser<'a> {
                     self.prev_token();
                     self.parse_if_stmt()
                 }
+                Keyword::RAISE => {
+                    self.prev_token();
+                    self.parse_raise_stmt()
+                }
                 Keyword::SELECT | Keyword::WITH | Keyword::VALUES | Keyword::FROM => {
                     self.prev_token();
                     self.parse_query().map(Statement::Query)
@@ -719,6 +723,22 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parse a `RAISE` statement.
+    ///
+    /// See [Statement::Raise]
+    pub fn parse_raise_stmt(&mut self) -> Result<Statement, ParserError> {
+        self.expect_keyword_is(Keyword::RAISE)?;
+
+        let value = if self.parse_keywords(&[Keyword::USING, Keyword::MESSAGE]) {
+            self.expect_token(&Token::Eq)?;
+            Some(RaiseStatementValue::UsingMessage(self.parse_expr()?))
+        } else {
+            self.maybe_parse(|parser| parser.parse_expr().map(RaiseStatementValue::Expr))?
+        };
+
+        Ok(Statement::Raise(RaiseStatement { value }))
+    }
+
     pub fn parse_comment(&mut self) -> Result<Statement, ParserError> {
         let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
 
@@ -1799,6 +1819,15 @@ impl<'a> Parser<'a> {
         })
     }
 
+    fn keyword_to_modifier(k: Option<Keyword>) -> ContextModifier {
+        match k {
+            Some(Keyword::LOCAL) => ContextModifier::Local,
+            Some(Keyword::GLOBAL) => ContextModifier::Global,
+            Some(Keyword::SESSION) => ContextModifier::Session,
+            _ => ContextModifier::None,
+        }
+    }
+
     /// Check if the root is an identifier and all fields are identifiers.
     fn is_all_ident(root: &Expr, fields: &[AccessExpr]) -> bool {
         if !matches!(root, Expr::Identifier(_)) {
@@ -8311,6 +8340,24 @@ impl<'a> Parser<'a> {
             AlterTableOperation::SuspendRecluster
         } else if self.parse_keywords(&[Keyword::RESUME, Keyword::RECLUSTER]) {
             AlterTableOperation::ResumeRecluster
+        } else if self.parse_keyword(Keyword::LOCK) {
+            let equals = self.consume_token(&Token::Eq);
+            let lock = match self.parse_one_of_keywords(&[
+                Keyword::DEFAULT,
+                Keyword::EXCLUSIVE,
+                Keyword::NONE,
+                Keyword::SHARED,
+            ]) {
+                Some(Keyword::DEFAULT) => AlterTableLock::Default,
+                Some(Keyword::EXCLUSIVE) => AlterTableLock::Exclusive,
+                Some(Keyword::NONE) => AlterTableLock::None,
+                Some(Keyword::SHARED) => AlterTableLock::Shared,
+                _ => self.expected(
+                    "DEFAULT, EXCLUSIVE, NONE or SHARED after LOCK [=]",
+                    self.peek_token(),
+                )?,
+            };
+            AlterTableOperation::Lock { equals, lock }
         } else if self.parse_keyword(Keyword::ALGORITHM) {
             let equals = self.consume_token(&Token::Eq);
             let algorithm = match self.parse_one_of_keywords(&[
@@ -11100,11 +11147,7 @@ impl<'a> Parser<'a> {
     /// Parse a `SET ROLE` statement. Expects SET to be consumed already.
     fn parse_set_role(&mut self, modifier: Option<Keyword>) -> Result<Statement, ParserError> {
         self.expect_keyword_is(Keyword::ROLE)?;
-        let context_modifier = match modifier {
-            Some(Keyword::LOCAL) => ContextModifier::Local,
-            Some(Keyword::SESSION) => ContextModifier::Session,
-            _ => ContextModifier::None,
-        };
+        let context_modifier = Self::keyword_to_modifier(modifier);
 
         let role_name = if self.parse_keyword(Keyword::NONE) {
             None
@@ -11176,8 +11219,12 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_set(&mut self) -> Result<Statement, ParserError> {
-        let modifier =
-            self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL, Keyword::HIVEVAR]);
+        let modifier = self.parse_one_of_keywords(&[
+            Keyword::SESSION,
+            Keyword::LOCAL,
+            Keyword::HIVEVAR,
+            Keyword::GLOBAL,
+        ]);
 
         if let Some(Keyword::HIVEVAR) = modifier {
             self.expect_token(&Token::Colon)?;
@@ -11193,7 +11240,7 @@ impl<'a> Parser<'a> {
         {
             if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
                 return Ok(Set::SingleAssignment {
-                    local: modifier == Some(Keyword::LOCAL),
+                    scope: Self::keyword_to_modifier(modifier),
                     hivevar: modifier == Some(Keyword::HIVEVAR),
                     variable: ObjectName::from(vec!["TIMEZONE".into()]),
                     values: self.parse_set_values(false)?,
@@ -11283,7 +11330,7 @@ impl<'a> Parser<'a> {
                     }?;
 
                     Ok(Set::SingleAssignment {
-                        local: modifier == Some(Keyword::LOCAL),
+                        scope: Self::keyword_to_modifier(modifier),
                         hivevar: modifier == Some(Keyword::HIVEVAR),
                         variable,
                         values,
@@ -11311,7 +11358,7 @@ impl<'a> Parser<'a> {
         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),
+                    scope: Self::keyword_to_modifier(modifier),
                     hivevar: modifier == Some(Keyword::HIVEVAR),
                     variable: var,
                     values: self.parse_set_values(false)?,


Test patch:
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index c65cc6b..4ba8df7 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -8627,12 +8627,12 @@ fn parse_set_transaction() {
 fn parse_set_variable() {
     match verified_stmt("SET SOMETHING = '1'") {
         Statement::Set(Set::SingleAssignment {
-            local,
+            scope,
             hivevar,
             variable,
             values,
         }) => {
-            assert!(!local);
+            assert_eq!(scope, ContextModifier::None);
             assert!(!hivevar);
             assert_eq!(variable, ObjectName::from(vec!["SOMETHING".into()]));
             assert_eq!(
@@ -8645,6 +8645,26 @@ fn parse_set_variable() {
         _ => unreachable!(),
     }
 
+    match verified_stmt("SET GLOBAL VARIABLE = 'Value'") {
+        Statement::Set(Set::SingleAssignment {
+            scope,
+            hivevar,
+            variable,
+            values,
+        }) => {
+            assert_eq!(scope, ContextModifier::Global);
+            assert!(!hivevar);
+            assert_eq!(variable, ObjectName::from(vec!["VARIABLE".into()]));
+            assert_eq!(
+                values,
+                vec![Expr::Value(
+                    (Value::SingleQuotedString("Value".into())).with_empty_span()
+                )]
+            );
+        }
+        _ => unreachable!(),
+    }
+
     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) {
@@ -8719,12 +8739,12 @@ fn parse_set_variable() {
 fn parse_set_role_as_variable() {
     match verified_stmt("SET role = 'foobar'") {
         Statement::Set(Set::SingleAssignment {
-            local,
+            scope,
             hivevar,
             variable,
             values,
         }) => {
-            assert!(!local);
+            assert_eq!(scope, ContextModifier::None);
             assert!(!hivevar);
             assert_eq!(variable, ObjectName::from(vec!["role".into()]));
             assert_eq!(
@@ -8766,12 +8786,12 @@ fn parse_double_colon_cast_at_timezone() {
 fn parse_set_time_zone() {
     match verified_stmt("SET TIMEZONE = 'UTC'") {
         Statement::Set(Set::SingleAssignment {
-            local,
+            scope,
             hivevar,
             variable,
             values,
         }) => {
-            assert!(!local);
+            assert_eq!(scope, ContextModifier::None);
             assert!(!hivevar);
             assert_eq!(variable, ObjectName::from(vec!["TIMEZONE".into()]));
             assert_eq!(
@@ -14298,6 +14318,29 @@ fn parse_if_statement() {
     );
 }
 
+#[test]
+fn parse_raise_statement() {
+    let sql = "RAISE USING MESSAGE = 42";
+    let Statement::Raise(stmt) = verified_stmt(sql) else {
+        unreachable!()
+    };
+    assert_eq!(
+        Some(RaiseStatementValue::UsingMessage(Expr::value(number("42")))),
+        stmt.value
+    );
+
+    verified_stmt("RAISE USING MESSAGE = 'error'");
+    verified_stmt("RAISE myerror");
+    verified_stmt("RAISE 42");
+    verified_stmt("RAISE using");
+    verified_stmt("RAISE");
+
+    assert_eq!(
+        ParserError::ParserError("Expected: =, found: error".to_string()),
+        parse_sql_statements("RAISE USING MESSAGE error").unwrap_err()
+    );
+}
+
 #[test]
 fn test_lambdas() {
     let dialects = all_dialects_where(|d| d.supports_lambda_functions());
diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs
index 56fe22a..a9549cb 100644
--- a/tests/sqlparser_hive.rs
+++ b/tests/sqlparser_hive.rs
@@ -21,9 +21,10 @@
 //! is also tested (on the inputs it can handle).
 
 use sqlparser::ast::{
-    ClusteredBy, CommentDef, CreateFunction, CreateFunctionBody, CreateFunctionUsing, CreateTable,
-    Expr, Function, FunctionArgumentList, FunctionArguments, Ident, ObjectName, OrderByExpr,
-    OrderByOptions, SelectItem, Set, Statement, TableFactor, UnaryOperator, Use, Value,
+    ClusteredBy, CommentDef, ContextModifier, CreateFunction, CreateFunctionBody,
+    CreateFunctionUsing, CreateTable, 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;
@@ -369,7 +370,7 @@ fn set_statement_with_minus() {
     assert_eq!(
         hive().verified_stmt("SET hive.tez.java.opts = -Xmx4g"),
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![
                 Ident::new("hive"),
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index af71d25..d4e5fa7 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -1251,7 +1251,7 @@ fn parse_mssql_declare() {
                 }]
             },
             Statement::Set(Set::SingleAssignment {
-                local: false,
+                scope: ContextModifier::None,
                 hivevar: false,
                 variable: ObjectName::from(vec![Ident::new("@bar")]),
                 values: vec![Expr::Value(
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index a563359..8843514 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -618,7 +618,7 @@ fn parse_set_variables() {
     assert_eq!(
         mysql_and_generic().verified_stmt("SET LOCAL autocommit = 1"),
         Statement::Set(Set::SingleAssignment {
-            local: true,
+            scope: ContextModifier::Local,
             hivevar: false,
             variable: ObjectName::from(vec!["autocommit".into()]),
             values: vec![Expr::value(number("1"))],
@@ -2454,6 +2454,52 @@ fn parse_alter_table_with_algorithm() {
     mysql_and_generic().verified_stmt("ALTER TABLE `users` ALGORITHM = COPY");
 }
 
+#[test]
+fn parse_alter_table_with_lock() {
+    let sql = "ALTER TABLE tab LOCK = SHARED";
+    let expected_operation = AlterTableOperation::Lock {
+        equals: true,
+        lock: AlterTableLock::Shared,
+    };
+    let operation = alter_table_op(mysql_and_generic().verified_stmt(sql));
+    assert_eq!(expected_operation, operation);
+
+    let sql =
+        "ALTER TABLE users DROP COLUMN password_digest, LOCK = EXCLUSIVE, RENAME COLUMN name TO username";
+    let stmt = mysql_and_generic().verified_stmt(sql);
+    match stmt {
+        Statement::AlterTable { operations, .. } => {
+            assert_eq!(
+                operations,
+                vec![
+                    AlterTableOperation::DropColumn {
+                        column_name: Ident::new("password_digest"),
+                        if_exists: false,
+                        drop_behavior: None,
+                    },
+                    AlterTableOperation::Lock {
+                        equals: true,
+                        lock: AlterTableLock::Exclusive,
+                    },
+                    AlterTableOperation::RenameColumn {
+                        old_column_name: Ident::new("name"),
+                        new_column_name: Ident::new("username")
+                    },
+                ]
+            )
+        }
+        _ => panic!("Unexpected statement {stmt}"),
+    }
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK DEFAULT");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK SHARED");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK NONE");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK EXCLUSIVE");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = DEFAULT");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = SHARED");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = NONE");
+    mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = EXCLUSIVE");
+}
+
 #[test]
 fn parse_alter_table_auto_increment() {
     let sql = "ALTER TABLE tab AUTO_INCREMENT = 42";
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index e62f235..cf66af7 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -988,8 +988,7 @@ fn parse_create_schema_if_not_exists() {
         Statement::CreateSchema {
             if_not_exists: true,
             schema_name,
-            options: _,
-            default_collate_spec: _,
+            ..
         } => assert_eq!("schema_name", schema_name.to_string()),
         _ => unreachable!(),
     }
@@ -1433,7 +1432,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![Ident::new("a")]),
             values: vec![Expr::Identifier(Ident {
@@ -1448,7 +1447,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![Ident::new("a")]),
             values: vec![Expr::Value(
@@ -1461,7 +1460,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![Ident::new("a")]),
             values: vec![Expr::value(number("0"))],
@@ -1472,7 +1471,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![Ident::new("a")]),
             values: vec![Expr::Identifier(Ident::new("DEFAULT"))],
@@ -1483,7 +1482,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: true,
+            scope: ContextModifier::Local,
             hivevar: false,
             variable: ObjectName::from(vec![Ident::new("a")]),
             values: vec![Expr::Identifier("b".into())],
@@ -1494,7 +1493,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![Ident::new("a"), Ident::new("b"), Ident::new("c")]),
             values: vec![Expr::Identifier(Ident {
@@ -1512,7 +1511,7 @@ fn parse_set() {
     assert_eq!(
         stmt,
         Statement::Set(Set::SingleAssignment {
-            local: false,
+            scope: ContextModifier::None,
             hivevar: false,
             variable: ObjectName::from(vec![
                 Ident::new("hive"),
@@ -1526,7 +1525,6 @@ fn parse_set() {
     );
 
     pg_and_generic().one_statement_parses_to("SET a TO b", "SET a = b");
-    pg_and_generic().one_statement_parses_to("SET SESSION a = b", "SET a = b");
 
     assert_eq!(
         pg_and_generic().parse_sql_statements("SET"),