Skip to content

Commit 9b7faec

Browse files
committed
MsSQL SET for session params
1 parent c54ba4d commit 9b7faec

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
@@ -3437,6 +3437,15 @@ pub enum Statement {
34373437
/// Snowflake `REMOVE`
34383438
/// See: <https://docs.snowflake.com/en/sql-reference/sql/remove>
34393439
Remove(FileStagingCommand),
3440+
/// MS-SQL session
3441+
///
3442+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
3443+
SetSessionParam {
3444+
names: Vec<String>,
3445+
identity_insert_obj: Option<ObjectName>,
3446+
offsets_keywords: Option<Vec<String>>,
3447+
value: String,
3448+
},
34403449
}
34413450

34423451
impl fmt::Display for Statement {
@@ -5024,6 +5033,21 @@ impl fmt::Display for Statement {
50245033
}
50255034
Statement::List(command) => write!(f, "LIST {command}"),
50265035
Statement::Remove(command) => write!(f, "REMOVE {command}"),
5036+
Statement::SetSessionParam {
5037+
names,
5038+
identity_insert_obj,
5039+
offsets_keywords,
5040+
value,
5041+
} => {
5042+
write!(f, "SET")?;
5043+
write!(f, " {}", display_comma_separated(names))?;
5044+
if let Some(obj) = identity_insert_obj {
5045+
write!(f, " {obj}")?;
5046+
} else if let Some(keywords) = offsets_keywords {
5047+
write!(f, " {}", display_comma_separated(keywords))?;
5048+
}
5049+
write!(f, " {value}")
5050+
}
50275051
}
50285052
}
50295053
}
@@ -6441,6 +6465,7 @@ pub enum TransactionIsolationLevel {
64416465
ReadCommitted,
64426466
RepeatableRead,
64436467
Serializable,
6468+
Snapshot,
64446469
}
64456470

64466471
impl fmt::Display for TransactionIsolationLevel {
@@ -6451,6 +6476,7 @@ impl fmt::Display for TransactionIsolationLevel {
64516476
ReadCommitted => "READ COMMITTED",
64526477
RepeatableRead => "REPEATABLE READ",
64536478
Serializable => "SERIALIZABLE",
6479+
Snapshot => "SNAPSHOT",
64546480
})
64556481
}
64566482
}

src/ast/spans.rs

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

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,12 @@ pub trait Dialect: Debug + Any {
792792
fn supports_insert_set(&self) -> bool {
793793
false
794794
}
795+
796+
/// Returns true if this dialect supports `SET` statements without an explicit
797+
/// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
798+
fn supports_set_stmt_without_operator(&self) -> bool {
799+
false
800+
}
795801
}
796802

797803
/// 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
@@ -85,4 +85,9 @@ impl Dialect for MsSqlDialect {
8585
fn supports_end_transaction_modifier(&self) -> bool {
8686
true
8787
}
88+
89+
/// See: <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
90+
fn supports_set_stmt_without_operator(&self) -> bool {
91+
true
92+
}
8893
}

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ define_keywords!(
426426
INTERVAL,
427427
INTO,
428428
INVOKER,
429+
IO,
429430
IS,
430431
ISODOW,
431432
ISOLATION,
@@ -623,6 +624,7 @@ define_keywords!(
623624
PRIOR,
624625
PRIVILEGES,
625626
PROCEDURE,
627+
PROFILE,
626628
PROGRAM,
627629
PROJECTION,
628630
PUBLIC,

src/parser/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10416,11 +10416,67 @@ impl<'a> Parser<'a> {
1041610416
snapshot: None,
1041710417
session: false,
1041810418
})
10419+
} else if self.dialect.supports_set_stmt_without_operator() {
10420+
self.prev_token();
10421+
self.parse_set_session_params()
1041910422
} else {
1042010423
self.expected("equals sign or TO", self.peek_token())
1042110424
}
1042210425
}
1042310426

10427+
pub fn parse_set_session_params(&mut self) -> Result<Statement, ParserError> {
10428+
let names = self.parse_comma_separated(Parser::parse_set_session_param_name)?;
10429+
10430+
let last_name = if let Some(last_name) = names.last() {
10431+
last_name.to_uppercase()
10432+
} else {
10433+
return self.expected("Session param name", self.peek_token());
10434+
};
10435+
10436+
let identity_insert_obj = if last_name == "IDENTITY_INSERT" {
10437+
Some(self.parse_object_name(false)?)
10438+
} else {
10439+
None
10440+
};
10441+
10442+
let offsets_keywords = if last_name == "OFFSETS" {
10443+
Some(self.parse_comma_separated(|parser| {
10444+
let next_token = parser.next_token();
10445+
match &next_token.token {
10446+
Token::Word(w) => Ok(w.to_string()),
10447+
_ => parser.expected("SQL keyword", next_token),
10448+
}
10449+
})?)
10450+
} else {
10451+
None
10452+
};
10453+
10454+
let value = self.parse_expr()?.to_string();
10455+
Ok(Statement::SetSessionParam {
10456+
names,
10457+
identity_insert_obj,
10458+
offsets_keywords,
10459+
value,
10460+
})
10461+
}
10462+
10463+
pub fn parse_set_session_param_name(&mut self) -> Result<String, ParserError> {
10464+
if self.parse_keywords(&[Keyword::STATISTICS, Keyword::IO]) {
10465+
return Ok("STATISTICS IO".to_string());
10466+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::XML]) {
10467+
return Ok("STATISTICS XML".to_string());
10468+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::PROFILE]) {
10469+
return Ok("STATISTICS PROFILE".to_string());
10470+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::TIME]) {
10471+
return Ok("STATISTICS TIME".to_string());
10472+
}
10473+
let next_token = self.next_token();
10474+
if let Token::Word(w) = next_token.token {
10475+
return Ok(w.to_string());
10476+
}
10477+
self.expected("Session param name", next_token)
10478+
}
10479+
1042410480
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
1042510481
let terse = self.parse_keyword(Keyword::TERSE);
1042610482
let extended = self.parse_keyword(Keyword::EXTENDED);
@@ -12958,6 +13014,8 @@ impl<'a> Parser<'a> {
1295813014
TransactionIsolationLevel::RepeatableRead
1295913015
} else if self.parse_keyword(Keyword::SERIALIZABLE) {
1296013016
TransactionIsolationLevel::Serializable
13017+
} else if self.parse_keyword(Keyword::SNAPSHOT) {
13018+
TransactionIsolationLevel::Snapshot
1296113019
} else {
1296213020
self.expected("isolation level", self.peek_token())?
1296313021
};

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)