Add GLOBAL context/modifier to SET statements (#1767)

This commit is contained in:
Mohamed Abdeen 2025-03-20 07:52:56 +02:00 committed by GitHub
parent e3e88290cd
commit f487cbe004
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 72 additions and 39 deletions

View file

@ -2629,7 +2629,7 @@ pub enum Set {
/// SQL Standard-style
/// SET a = 1;
SingleAssignment {
local: bool,
scope: ContextModifier,
hivevar: bool,
variable: ObjectName,
values: Vec<Expr>,
@ -2711,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 {
@ -2758,7 +2758,7 @@ impl Display for Set {
Ok(())
}
Set::SingleAssignment {
local,
scope,
hivevar,
variable,
values,
@ -2766,7 +2766,7 @@ impl Display for Set {
write!(
f,
"SET {}{}{} = {}",
if *local { "LOCAL " } else { "" },
scope,
if *hivevar { "HIVEVAR:" } else { "" },
variable,
display_comma_separated(values)
@ -7955,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))]
@ -7966,6 +7966,8 @@ pub enum ContextModifier {
Local,
/// `SESSION` identifier
Session,
/// `GLOBAL` identifier
Global,
}
impl fmt::Display for ContextModifier {
@ -7975,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 ")
}
}
}

View file

@ -1819,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(_)) {
@ -11138,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
@ -11214,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)?;
@ -11231,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)?,
@ -11321,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,
@ -11349,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)?,

View file

@ -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!(

View file

@ -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"),

View file

@ -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(

View file

@ -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"))],

View file

@ -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"),