Skip to content

Commit 11bef3e

Browse files
committed
MsSQL SET for session params
1 parent 687ce2d commit 11bef3e

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

34403449
impl fmt::Display for Statement {
@@ -5012,6 +5021,21 @@ impl fmt::Display for Statement {
50125021
}
50135022
Statement::List(command) => write!(f, "LIST {command}"),
50145023
Statement::Remove(command) => write!(f, "REMOVE {command}"),
5024+
Statement::SetSessionParam {
5025+
names,
5026+
identity_insert_obj,
5027+
offsets_keywords,
5028+
value,
5029+
} => {
5030+
write!(f, "SET")?;
5031+
write!(f, " {}", display_comma_separated(names))?;
5032+
if let Some(obj) = identity_insert_obj {
5033+
write!(f, " {obj}")?;
5034+
} else if let Some(keywords) = offsets_keywords {
5035+
write!(f, " {}", display_comma_separated(keywords))?;
5036+
}
5037+
write!(f, " {value}")
5038+
}
50155039
}
50165040
}
50175041
}
@@ -6398,6 +6422,7 @@ pub enum TransactionIsolationLevel {
63986422
ReadCommitted,
63996423
RepeatableRead,
64006424
Serializable,
6425+
Snapshot,
64016426
}
64026427

64036428
impl fmt::Display for TransactionIsolationLevel {
@@ -6408,6 +6433,7 @@ impl fmt::Display for TransactionIsolationLevel {
64086433
ReadCommitted => "READ COMMITTED",
64096434
RepeatableRead => "REPEATABLE READ",
64106435
Serializable => "SERIALIZABLE",
6436+
Snapshot => "SNAPSHOT",
64116437
})
64126438
}
64136439
}

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
@@ -787,6 +787,12 @@ pub trait Dialect: Debug + Any {
787787
fn supports_insert_set(&self) -> bool {
788788
false
789789
}
790+
791+
/// Returns true if this dialect supports `SET` statements without an explicit
792+
/// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
793+
fn supports_set_stmt_without_operator(&self) -> bool {
794+
false
795+
}
790796
}
791797

792798
/// 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
@@ -423,6 +423,7 @@ define_keywords!(
423423
INTERSECTION,
424424
INTERVAL,
425425
INTO,
426+
IO,
426427
IS,
427428
ISODOW,
428429
ISOLATION,
@@ -619,6 +620,7 @@ define_keywords!(
619620
PRIOR,
620621
PRIVILEGES,
621622
PROCEDURE,
623+
PROFILE,
622624
PROGRAM,
623625
PROJECTION,
624626
PUBLIC,

src/parser/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10321,11 +10321,67 @@ impl<'a> Parser<'a> {
1032110321
snapshot: None,
1032210322
session: false,
1032310323
})
10324+
} else if self.dialect.supports_set_stmt_without_operator() {
10325+
self.prev_token();
10326+
self.parse_set_session_params()
1032410327
} else {
1032510328
self.expected("equals sign or TO", self.peek_token())
1032610329
}
1032710330
}
1032810331

10332+
pub fn parse_set_session_params(&mut self) -> Result<Statement, ParserError> {
10333+
let names = self.parse_comma_separated(Parser::parse_set_session_param_name)?;
10334+
10335+
let last_name = if let Some(last_name) = names.last() {
10336+
last_name.to_uppercase()
10337+
} else {
10338+
return self.expected("Session param name", self.peek_token());
10339+
};
10340+
10341+
let identity_insert_obj = if last_name == "IDENTITY_INSERT" {
10342+
Some(self.parse_object_name(false)?)
10343+
} else {
10344+
None
10345+
};
10346+
10347+
let offsets_keywords = if last_name == "OFFSETS" {
10348+
Some(self.parse_comma_separated(|parser| {
10349+
let next_token = parser.next_token();
10350+
match &next_token.token {
10351+
Token::Word(w) => Ok(w.to_string()),
10352+
_ => parser.expected("SQL keyword", next_token),
10353+
}
10354+
})?)
10355+
} else {
10356+
None
10357+
};
10358+
10359+
let value = self.parse_expr()?.to_string();
10360+
Ok(Statement::SetSessionParam {
10361+
names,
10362+
identity_insert_obj,
10363+
offsets_keywords,
10364+
value,
10365+
})
10366+
}
10367+
10368+
pub fn parse_set_session_param_name(&mut self) -> Result<String, ParserError> {
10369+
if self.parse_keywords(&[Keyword::STATISTICS, Keyword::IO]) {
10370+
return Ok("STATISTICS IO".to_string());
10371+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::XML]) {
10372+
return Ok("STATISTICS XML".to_string());
10373+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::PROFILE]) {
10374+
return Ok("STATISTICS PROFILE".to_string());
10375+
} else if self.parse_keywords(&[Keyword::STATISTICS, Keyword::TIME]) {
10376+
return Ok("STATISTICS TIME".to_string());
10377+
}
10378+
let next_token = self.next_token();
10379+
if let Token::Word(w) = next_token.token {
10380+
return Ok(w.to_string());
10381+
}
10382+
self.expected("Session param name", next_token)
10383+
}
10384+
1032910385
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
1033010386
let terse = self.parse_keyword(Keyword::TERSE);
1033110387
let extended = self.parse_keyword(Keyword::EXTENDED);
@@ -12850,6 +12906,8 @@ impl<'a> Parser<'a> {
1285012906
TransactionIsolationLevel::RepeatableRead
1285112907
} else if self.parse_keyword(Keyword::SERIALIZABLE) {
1285212908
TransactionIsolationLevel::Serializable
12909+
} else if self.parse_keyword(Keyword::SNAPSHOT) {
12910+
TransactionIsolationLevel::Snapshot
1285312911
} else {
1285412912
self.expected("isolation level", self.peek_token())?
1285512913
};

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)