Skip to content

Commit c0b5b20

Browse files
committed
Parse SET GLOBAL variable modifier for MySQL
This also stops rewriting `SESSION` away. Closes apache#1694
1 parent 447142c commit c0b5b20

10 files changed

+87
-30
lines changed

src/ast/mod.rs

+28-6
Original file line numberDiff line numberDiff line change
@@ -2889,7 +2889,7 @@ pub enum Statement {
28892889
/// least MySQL and PostgreSQL. Not all MySQL-specific syntactic forms are
28902890
/// supported yet.
28912891
SetVariable {
2892-
local: bool,
2892+
scope: SetVariableScope,
28932893
hivevar: bool,
28942894
variables: OneOrManyWithParens<ObjectName>,
28952895
value: Vec<Expr>,
@@ -4510,15 +4510,12 @@ impl fmt::Display for Statement {
45104510
write!(f, "SET{context_modifier} ROLE {role_name}")
45114511
}
45124512
Statement::SetVariable {
4513-
local,
4513+
scope,
45144514
variables,
45154515
hivevar,
45164516
value,
45174517
} => {
4518-
f.write_str("SET ")?;
4519-
if *local {
4520-
f.write_str("LOCAL ")?;
4521-
}
4518+
write!(f, "SET{scope} ")?;
45224519
let parenthesized = matches!(variables, OneOrManyWithParens::Many(_));
45234520
write!(
45244521
f,
@@ -8433,6 +8430,31 @@ impl fmt::Display for SessionParamValue {
84338430
}
84348431
}
84358432

8433+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
8434+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8435+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
8436+
pub enum SetVariableScope {
8437+
/// LOCAL (transaction or function) scope
8438+
Local,
8439+
/// SESSION scope
8440+
Session,
8441+
/// MySQL-specific `GLOBAL` scope
8442+
Global,
8443+
/// Not specified; usually implies SESSION
8444+
None,
8445+
}
8446+
8447+
impl fmt::Display for SetVariableScope {
8448+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8449+
match self {
8450+
Self::Local => write!(f, " LOCAL"),
8451+
Self::Session => write!(f, " SESSION"),
8452+
Self::Global => write!(f, " GLOBAL"),
8453+
Self::None => write!(f, ""),
8454+
}
8455+
}
8456+
}
8457+
84368458
/// Snowflake StorageSerializationPolicy for Iceberg Tables
84378459
/// ```sql
84388460
/// [ STORAGE_SERIALIZATION_POLICY = { COMPATIBLE | OPTIMIZED } ]

src/dialect/generic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,8 @@ impl Dialect for GenericDialect {
143143
fn supports_string_escape_constant(&self) -> bool {
144144
true
145145
}
146+
147+
fn supports_global_variable_modifier(&self) -> bool {
148+
true
149+
}
146150
}

src/dialect/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -876,10 +876,16 @@ pub trait Dialect: Debug + Any {
876876
fn supports_string_escape_constant(&self) -> bool {
877877
false
878878
}
879+
879880
/// Returns true if the dialect supports the table hints in the `FROM` clause.
880881
fn supports_table_hints(&self) -> bool {
881882
false
882883
}
884+
885+
/// Returns true if the dialect allows the `GLOBAL` variable modifier in `SET` statements.
886+
fn supports_global_variable_modifier(&self) -> bool {
887+
false
888+
}
883889
}
884890

885891
/// This represents the operators for which precedence must be defined

src/dialect/mysql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ impl Dialect for MySqlDialect {
125125
fn supports_table_hints(&self) -> bool {
126126
true
127127
}
128+
129+
fn supports_global_variable_modifier(&self) -> bool {
130+
true
131+
}
128132
}
129133

130134
/// `LOCK TABLES`

src/parser/mod.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -10533,8 +10533,17 @@ impl<'a> Parser<'a> {
1053310533
}
1053410534

1053510535
pub fn parse_set(&mut self) -> Result<Statement, ParserError> {
10536-
let modifier =
10537-
self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL, Keyword::HIVEVAR]);
10536+
let modifier_keywords = if self.dialect.supports_global_variable_modifier() {
10537+
&[
10538+
Keyword::SESSION,
10539+
Keyword::LOCAL,
10540+
Keyword::GLOBAL,
10541+
Keyword::HIVEVAR,
10542+
][..]
10543+
} else {
10544+
&[Keyword::SESSION, Keyword::LOCAL, Keyword::HIVEVAR][..]
10545+
};
10546+
let modifier = self.parse_one_of_keywords(modifier_keywords);
1053810547
if let Some(Keyword::HIVEVAR) = modifier {
1053910548
self.expect_token(&Token::Colon)?;
1054010549
} else if let Some(set_role_stmt) =
@@ -10605,8 +10614,14 @@ impl<'a> Parser<'a> {
1060510614
if parenthesized_assignment {
1060610615
self.expect_token(&Token::RParen)?;
1060710616
}
10617+
let scope = match modifier {
10618+
Some(Keyword::LOCAL) => SetVariableScope::Local,
10619+
Some(Keyword::GLOBAL) => SetVariableScope::Global,
10620+
Some(Keyword::SESSION) => SetVariableScope::Session,
10621+
_ => SetVariableScope::None,
10622+
};
1060810623
return Ok(Statement::SetVariable {
10609-
local: modifier == Some(Keyword::LOCAL),
10624+
scope,
1061010625
hivevar: Some(Keyword::HIVEVAR) == modifier,
1061110626
variables,
1061210627
value: values,

tests/sqlparser_common.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -8148,12 +8148,12 @@ fn parse_set_transaction() {
81488148
fn parse_set_variable() {
81498149
match verified_stmt("SET SOMETHING = '1'") {
81508150
Statement::SetVariable {
8151-
local,
8151+
scope,
81528152
hivevar,
81538153
variables,
81548154
value,
81558155
} => {
8156-
assert!(!local);
8156+
assert_eq!(scope, SetVariableScope::None);
81578157
assert!(!hivevar);
81588158
assert_eq!(
81598159
variables,
@@ -8171,12 +8171,12 @@ fn parse_set_variable() {
81718171
let sql = r#"SET (a, b, c) = (1, 2, 3)"#;
81728172
match multi_variable_dialects.verified_stmt(sql) {
81738173
Statement::SetVariable {
8174-
local,
8174+
scope,
81758175
hivevar,
81768176
variables,
81778177
value,
81788178
} => {
8179-
assert!(!local);
8179+
assert_eq!(scope, SetVariableScope::None);
81808180
assert!(!hivevar);
81818181
assert_eq!(
81828182
variables,
@@ -8248,12 +8248,12 @@ fn parse_set_variable() {
82488248
fn parse_set_role_as_variable() {
82498249
match verified_stmt("SET role = 'foobar'") {
82508250
Statement::SetVariable {
8251-
local,
8251+
scope,
82528252
hivevar,
82538253
variables,
82548254
value,
82558255
} => {
8256-
assert!(!local);
8256+
assert_eq!(scope, SetVariableScope::None);
82578257
assert!(!hivevar);
82588258
assert_eq!(
82598259
variables,
@@ -8295,12 +8295,12 @@ fn parse_double_colon_cast_at_timezone() {
82958295
fn parse_set_time_zone() {
82968296
match verified_stmt("SET TIMEZONE = 'UTC'") {
82978297
Statement::SetVariable {
8298-
local,
8298+
scope,
82998299
hivevar,
83008300
variables: variable,
83018301
value,
83028302
} => {
8303-
assert!(!local);
8303+
assert_eq!(scope, SetVariableScope::None);
83048304
assert!(!hivevar);
83058305
assert_eq!(
83068306
variable,

tests/sqlparser_hive.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
use sqlparser::ast::{
2424
ClusteredBy, CommentDef, CreateFunction, CreateFunctionBody, CreateFunctionUsing, CreateTable,
2525
Expr, Function, FunctionArgumentList, FunctionArguments, Ident, ObjectName,
26-
OneOrManyWithParens, OrderByExpr, SelectItem, Statement, TableFactor, UnaryOperator, Use,
27-
Value,
26+
OneOrManyWithParens, OrderByExpr, SelectItem, SetVariableScope, Statement, TableFactor,
27+
UnaryOperator, Use, Value,
2828
};
2929
use sqlparser::dialect::{GenericDialect, HiveDialect, MsSqlDialect};
3030
use sqlparser::parser::ParserError;
@@ -366,7 +366,7 @@ fn set_statement_with_minus() {
366366
assert_eq!(
367367
hive().verified_stmt("SET hive.tez.java.opts = -Xmx4g"),
368368
Statement::SetVariable {
369-
local: false,
369+
scope: SetVariableScope::None,
370370
hivevar: false,
371371
variables: OneOrManyWithParens::One(ObjectName::from(vec![
372372
Ident::new("hive"),

tests/sqlparser_mssql.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ fn parse_mssql_declare() {
12101210
}]
12111211
},
12121212
Statement::SetVariable {
1213-
local: false,
1213+
scope: SetVariableScope::None,
12141214
hivevar: false,
12151215
variables: OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("@bar")])),
12161216
value: vec![Expr::Value(Value::Number("2".parse().unwrap(), false))],

tests/sqlparser_mysql.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ fn parse_set_variables() {
618618
assert_eq!(
619619
mysql_and_generic().verified_stmt("SET LOCAL autocommit = 1"),
620620
Statement::SetVariable {
621-
local: true,
621+
scope: SetVariableScope::Local,
622622
hivevar: false,
623623
variables: OneOrManyWithParens::One(ObjectName::from(vec!["autocommit".into()])),
624624
value: vec![Expr::Value(number("1"))],
@@ -3244,3 +3244,9 @@ fn parse_double_precision() {
32443244
"CREATE TABLE foo (bar DOUBLE(11,0))",
32453245
);
32463246
}
3247+
3248+
#[test]
3249+
fn parse_set_global() {
3250+
mysql_and_generic().verified_stmt("SET GLOBAL max_connections = 1000");
3251+
mysql_and_generic().verified_stmt("SET @@GLOBAL.max_connections = 1000");
3252+
}

tests/sqlparser_postgres.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ fn parse_set() {
14311431
assert_eq!(
14321432
stmt,
14331433
Statement::SetVariable {
1434-
local: false,
1434+
scope: SetVariableScope::None,
14351435
hivevar: false,
14361436
variables: OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
14371437
value: vec![Expr::Identifier(Ident {
@@ -1446,7 +1446,7 @@ fn parse_set() {
14461446
assert_eq!(
14471447
stmt,
14481448
Statement::SetVariable {
1449-
local: false,
1449+
scope: SetVariableScope::None,
14501450
hivevar: false,
14511451
variables: OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
14521452
value: vec![Expr::Value(Value::SingleQuotedString("b".into()))],
@@ -1457,7 +1457,7 @@ fn parse_set() {
14571457
assert_eq!(
14581458
stmt,
14591459
Statement::SetVariable {
1460-
local: false,
1460+
scope: SetVariableScope::None,
14611461
hivevar: false,
14621462
variables: OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
14631463
value: vec![Expr::Value(number("0"))],
@@ -1468,7 +1468,7 @@ fn parse_set() {
14681468
assert_eq!(
14691469
stmt,
14701470
Statement::SetVariable {
1471-
local: false,
1471+
scope: SetVariableScope::None,
14721472
hivevar: false,
14731473
variables: OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
14741474
value: vec![Expr::Identifier(Ident::new("DEFAULT"))],
@@ -1479,7 +1479,7 @@ fn parse_set() {
14791479
assert_eq!(
14801480
stmt,
14811481
Statement::SetVariable {
1482-
local: true,
1482+
scope: SetVariableScope::Local,
14831483
hivevar: false,
14841484
variables: OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
14851485
value: vec![Expr::Identifier("b".into())],
@@ -1490,7 +1490,7 @@ fn parse_set() {
14901490
assert_eq!(
14911491
stmt,
14921492
Statement::SetVariable {
1493-
local: false,
1493+
scope: SetVariableScope::None,
14941494
hivevar: false,
14951495
variables: OneOrManyWithParens::One(ObjectName::from(vec![
14961496
Ident::new("a"),
@@ -1512,7 +1512,7 @@ fn parse_set() {
15121512
assert_eq!(
15131513
stmt,
15141514
Statement::SetVariable {
1515-
local: false,
1515+
scope: SetVariableScope::None,
15161516
hivevar: false,
15171517
variables: OneOrManyWithParens::One(ObjectName::from(vec![
15181518
Ident::new("hive"),
@@ -1526,7 +1526,7 @@ fn parse_set() {
15261526
);
15271527

15281528
pg_and_generic().one_statement_parses_to("SET a TO b", "SET a = b");
1529-
pg_and_generic().one_statement_parses_to("SET SESSION a = b", "SET a = b");
1529+
pg_and_generic().verified_stmt("SET SESSION a = b");
15301530

15311531
assert_eq!(
15321532
pg_and_generic().parse_sql_statements("SET"),

0 commit comments

Comments
 (0)