Skip to content

Commit ecf5bed

Browse files
committed
MsSQL SET for session params
1 parent 8cfc462 commit ecf5bed

File tree

7 files changed

+159
-0
lines changed

7 files changed

+159
-0
lines changed

src/ast/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3426,6 +3426,15 @@ pub enum Statement {
34263426
/// Snowflake `REMOVE`
34273427
/// See: <https://docs.snowflake.com/en/sql-reference/sql/remove>
34283428
Remove(FileStagingCommand),
3429+
/// MS-SQL session
3430+
///
3431+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
3432+
SetSessionParam {
3433+
names: Vec<String>,
3434+
identity_insert_obj: Option<ObjectName>,
3435+
offsets_keywords: Option<Vec<String>>,
3436+
value: String,
3437+
},
34293438
}
34303439

34313440
impl fmt::Display for Statement {
@@ -4988,6 +4997,21 @@ impl fmt::Display for Statement {
49884997
}
49894998
Statement::List(command) => write!(f, "LIST {command}"),
49904999
Statement::Remove(command) => write!(f, "REMOVE {command}"),
5000+
Statement::SetSessionParam {
5001+
names,
5002+
identity_insert_obj,
5003+
offsets_keywords,
5004+
value,
5005+
} => {
5006+
write!(f, "SET")?;
5007+
write!(f, " {}", display_comma_separated(names))?;
5008+
if let Some(obj) = identity_insert_obj {
5009+
write!(f, " {obj}")?;
5010+
} else if let Some(keywords) = offsets_keywords {
5011+
write!(f, " {}", display_comma_separated(keywords))?;
5012+
}
5013+
write!(f, " {value}")
5014+
}
49915015
}
49925016
}
49935017
}
@@ -6374,6 +6398,7 @@ pub enum TransactionIsolationLevel {
63746398
ReadCommitted,
63756399
RepeatableRead,
63766400
Serializable,
6401+
Snapshot,
63776402
}
63786403

63796404
impl fmt::Display for TransactionIsolationLevel {
@@ -6384,6 +6409,7 @@ impl fmt::Display for TransactionIsolationLevel {
63846409
ReadCommitted => "READ COMMITTED",
63856410
RepeatableRead => "REPEATABLE READ",
63866411
Serializable => "SERIALIZABLE",
6412+
Snapshot => "SNAPSHOT",
63876413
})
63886414
}
63896415
}

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ impl Spanned for Statement {
494494
Statement::UNLISTEN { .. } => Span::empty(),
495495
Statement::RenameTable { .. } => Span::empty(),
496496
Statement::List(..) | Statement::Remove(..) => Span::empty(),
497+
Statement::SetSessionParam { .. } => Span::empty(),
497498
}
498499
}
499500
}

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,12 @@ pub trait Dialect: Debug + Any {
782782
fn supports_insert_set(&self) -> bool {
783783
false
784784
}
785+
786+
/// Returns true if this dialect supports `SET` statements without an explicit
787+
/// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
788+
fn supports_set_stmt_without_operator(&self) -> bool {
789+
false
790+
}
785791
}
786792

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

src/dialect/mssql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,9 @@ impl Dialect for MsSqlDialect {
7878
fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
7979
false
8080
}
81+
82+
/// See: <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
83+
fn supports_set_stmt_without_operator(&self) -> bool {
84+
true
85+
}
8186
}

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ define_keywords!(
421421
INTERSECTION,
422422
INTERVAL,
423423
INTO,
424+
IO,
424425
IS,
425426
ISODOW,
426427
ISOLATION,
@@ -615,6 +616,7 @@ define_keywords!(
615616
PRIOR,
616617
PRIVILEGES,
617618
PROCEDURE,
619+
PROFILE,
618620
PROGRAM,
619621
PROJECTION,
620622
PUBLIC,

src/parser/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10307,11 +10307,67 @@ impl<'a> Parser<'a> {
1030710307
snapshot: None,
1030810308
session: false,
1030910309
})
10310+
} else if self.dialect.supports_set_stmt_without_operator() {
10311+
self.prev_token();
10312+
self.parse_set_session_params()
1031010313
} else {
1031110314
self.expected("equals sign or TO", self.peek_token())
1031210315
}
1031310316
}
1031410317

10318+
pub fn parse_set_session_params(&mut self) -> Result<Statement, ParserError> {
10319+
let names = self.parse_comma_separated(Parser::parse_set_session_param_name)?;
10320+
10321+
let last_name = if let Some(last_name) = names.last() {
10322+
last_name.to_uppercase()
10323+
} else {
10324+
return self.expected("Session param name", self.peek_token());
10325+
};
10326+
10327+
let identity_insert_obj = if last_name == "IDENTITY_INSERT" {
10328+
Some(self.parse_object_name(false)?)
10329+
} else {
10330+
None
10331+
};
10332+
10333+
let offsets_keywords = if last_name == "OFFSETS" {
10334+
Some(self.parse_comma_separated(|parser| {
10335+
let next_token = parser.next_token();
10336+
match &next_token.token {
10337+
Token::Word(w) => Ok(w.to_string()),
10338+
_ => parser.expected("SQL keyword", next_token),
10339+
}
10340+
})?)
10341+
} else {
10342+
None
10343+
};
10344+
10345+
let value = self.parse_expr()?.to_string();
10346+
Ok(Statement::SetSessionParam {
10347+
names,
10348+
identity_insert_obj,
10349+
offsets_keywords,
10350+
value,
10351+
})
10352+
}
10353+
10354+
pub fn parse_set_session_param_name(&mut self) -> Result<String, ParserError> {
10355+
if self.parse_keywords(&[Keyword::STATISTICS, Keyword::IO]) {
10356+
return Ok("STATISTICS IO".to_string());
10357+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::XML]) {
10358+
return Ok("STATISTICS XML".to_string());
10359+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::PROFILE]) {
10360+
return Ok("STATISTICS PROFILE".to_string());
10361+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::TIME]) {
10362+
return Ok("STATISTICS TIME".to_string());
10363+
}
10364+
let next_token = self.next_token();
10365+
if let Token::Word(w) = next_token.token {
10366+
return Ok(w.to_string());
10367+
}
10368+
self.expected("Session param name", next_token)
10369+
}
10370+
1031510371
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
1031610372
let terse = self.parse_keyword(Keyword::TERSE);
1031710373
let extended = self.parse_keyword(Keyword::EXTENDED);
@@ -12821,6 +12877,8 @@ impl<'a> Parser<'a> {
1282112877
TransactionIsolationLevel::RepeatableRead
1282212878
} else if self.parse_keyword(Keyword::SERIALIZABLE) {
1282312879
TransactionIsolationLevel::Serializable
12880+
} else if self.parse_keyword(Keyword::SNAPSHOT) {
12881+
TransactionIsolationLevel::Snapshot
1282412882
} else {
1282512883
self.expected("isolation level", self.peek_token())?
1282612884
};

tests/sqlparser_mssql.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,67 @@ fn parse_true_false_as_identifiers() {
16791679
);
16801680
}
16811681

1682+
#[test]
1683+
fn parse_mssql_set_session_value() {
1684+
ms().verified_stmt(
1685+
"SET OFFSETS SELECT, FROM, ORDER, TABLE, PROCEDURE, STATEMENT, PARAM, EXECUTE ON",
1686+
);
1687+
ms().verified_stmt("SET IDENTITY_INSERT dbo.Tool ON");
1688+
ms().verified_stmt("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
1689+
ms().verified_stmt("SET TRANSACTION ISOLATION LEVEL READ COMMITTED");
1690+
ms().verified_stmt("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
1691+
ms().verified_stmt("SET TRANSACTION ISOLATION LEVEL SNAPSHOT");
1692+
ms().verified_stmt("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1693+
ms().verified_stmt("SET STATISTICS IO ON");
1694+
ms().verified_stmt("SET STATISTICS XML ON");
1695+
ms().verified_stmt("SET STATISTICS PROFILE ON");
1696+
ms().verified_stmt("SET STATISTICS TIME ON");
1697+
ms().verified_stmt("SET DATEFIRST 7");
1698+
ms().verified_stmt("SET DATEFIRST @xxx");
1699+
ms().verified_stmt("SET DATEFIRST @@xxx");
1700+
ms().verified_stmt("SET DATEFORMAT dmy");
1701+
ms().verified_stmt("SET DATEFORMAT @datevar");
1702+
ms().verified_stmt("SET DATEFORMAT @@datevar");
1703+
ms().verified_stmt("SET DEADLOCK_PRIORITY 'LOW'");
1704+
ms().verified_stmt("SET DEADLOCK_PRIORITY LOW");
1705+
ms().verified_stmt("SET DEADLOCK_PRIORITY 8");
1706+
ms().verified_stmt("SET DEADLOCK_PRIORITY -8");
1707+
ms().verified_stmt("SET DEADLOCK_PRIORITY @xxx");
1708+
ms().verified_stmt("SET DEADLOCK_PRIORITY @@xxx");
1709+
ms().verified_stmt("SET LOCK_TIMEOUT 1800");
1710+
ms().verified_stmt("SET CONCAT_NULL_YIELDS_NULL ON");
1711+
ms().verified_stmt("SET CURSOR_CLOSE_ON_COMMIT ON");
1712+
ms().verified_stmt("SET FIPS_FLAGGER 'level'");
1713+
ms().verified_stmt("SET FIPS_FLAGGER OFF");
1714+
ms().verified_stmt("SET LANGUAGE Italian");
1715+
ms().verified_stmt("SET QUOTED_IDENTIFIER ON");
1716+
ms().verified_stmt("SET ARITHABORT ON");
1717+
ms().verified_stmt("SET ARITHIGNORE OFF");
1718+
ms().verified_stmt("SET FMTONLY ON");
1719+
ms().verified_stmt("SET NOCOUNT OFF");
1720+
ms().verified_stmt("SET NOEXEC ON");
1721+
ms().verified_stmt("SET NUMERIC_ROUNDABORT ON");
1722+
ms().verified_stmt("SET QUERY_GOVERNOR_COST_LIMIT 11");
1723+
ms().verified_stmt("SET ROWCOUNT 4");
1724+
ms().verified_stmt("SET ROWCOUNT @xxx");
1725+
ms().verified_stmt("SET ROWCOUNT @@xxx");
1726+
ms().verified_stmt("SET TEXTSIZE 11");
1727+
ms().verified_stmt("SET ANSI_DEFAULTS ON");
1728+
ms().verified_stmt("SET ANSI_NULL_DFLT_OFF ON");
1729+
ms().verified_stmt("SET ANSI_NULL_DFLT_ON ON");
1730+
ms().verified_stmt("SET ANSI_NULLS ON");
1731+
ms().verified_stmt("SET ANSI_PADDING ON");
1732+
ms().verified_stmt("SET ANSI_WARNINGS ON");
1733+
ms().verified_stmt("SET FORCEPLAN ON");
1734+
ms().verified_stmt("SET SHOWPLAN_ALL ON");
1735+
ms().verified_stmt("SET SHOWPLAN_TEXT ON");
1736+
ms().verified_stmt("SET SHOWPLAN_XML ON");
1737+
ms().verified_stmt("SET IMPLICIT_TRANSACTIONS ON");
1738+
ms().verified_stmt("SET REMOTE_PROC_TRANSACTIONS ON");
1739+
ms().verified_stmt("SET XACT_ABORT ON");
1740+
ms().verified_stmt("SET ANSI_NULLS, ANSI_PADDING ON");
1741+
}
1742+
16821743
fn ms() -> TestedDialects {
16831744
TestedDialects::new(vec![Box::new(MsSqlDialect {})])
16841745
}

0 commit comments

Comments
 (0)