Skip to content

Commit 9e11da8

Browse files
committed
MsSQL SET for session params
1 parent e23877c commit 9e11da8

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
@@ -3420,6 +3420,15 @@ pub enum Statement {
34203420
///
34213421
/// See Mysql <https://dev.mysql.com/doc/refman/9.1/en/rename-table.html>
34223422
RenameTable(Vec<RenameTable>),
3423+
/// MS-SQL session
3424+
///
3425+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
3426+
SetSessionParam {
3427+
names: Vec<String>,
3428+
identity_insert_obj: Option<ObjectName>,
3429+
offsets_keywords: Option<Vec<String>>,
3430+
value: String,
3431+
},
34233432
}
34243433

34253434
impl fmt::Display for Statement {
@@ -4980,6 +4989,21 @@ impl fmt::Display for Statement {
49804989
Statement::RenameTable(rename_tables) => {
49814990
write!(f, "RENAME TABLE {}", display_comma_separated(rename_tables))
49824991
}
4992+
Statement::SetSessionParam {
4993+
names,
4994+
identity_insert_obj,
4995+
offsets_keywords,
4996+
value,
4997+
} => {
4998+
write!(f, "SET")?;
4999+
write!(f, " {}", display_comma_separated(names))?;
5000+
if let Some(obj) = identity_insert_obj {
5001+
write!(f, " {obj}")?;
5002+
} else if let Some(keywords) = offsets_keywords {
5003+
write!(f, " {}", display_comma_separated(keywords))?;
5004+
}
5005+
write!(f, " {value}")
5006+
}
49835007
}
49845008
}
49855009
}
@@ -6366,6 +6390,7 @@ pub enum TransactionIsolationLevel {
63666390
ReadCommitted,
63676391
RepeatableRead,
63686392
Serializable,
6393+
Snapshot,
63696394
}
63706395

63716396
impl fmt::Display for TransactionIsolationLevel {
@@ -6376,6 +6401,7 @@ impl fmt::Display for TransactionIsolationLevel {
63766401
ReadCommitted => "READ COMMITTED",
63776402
RepeatableRead => "REPEATABLE READ",
63786403
Serializable => "SERIALIZABLE",
6404+
Snapshot => "SNAPSHOT",
63796405
})
63806406
}
63816407
}

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ impl Spanned for Statement {
493493
Statement::LoadData { .. } => Span::empty(),
494494
Statement::UNLISTEN { .. } => Span::empty(),
495495
Statement::RenameTable { .. } => Span::empty(),
496+
Statement::SetSessionParam { .. } => Span::empty(),
496497
}
497498
}
498499
}

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,12 @@ pub trait Dialect: Debug + Any {
774774
fn supports_table_sample_before_alias(&self) -> bool {
775775
false
776776
}
777+
778+
/// Returns true if this dialect supports `SET` statements without an explicit
779+
/// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
780+
fn supports_set_stmt_without_operator(&self) -> bool {
781+
false
782+
}
777783
}
778784

779785
/// 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,
@@ -613,6 +614,7 @@ define_keywords!(
613614
PRIOR,
614615
PRIVILEGES,
615616
PROCEDURE,
617+
PROFILE,
616618
PROGRAM,
617619
PROJECTION,
618620
PUBLIC,

src/parser/mod.rs

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

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

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)