sqlparser/dialect/
mssql.rs1use crate::ast::helpers::attached_token::AttachedToken;
19use crate::ast::{
20 BeginEndStatements, ConditionalStatementBlock, ConditionalStatements, CreateTrigger,
21 GranteesType, IfStatement, Statement, TriggerObject,
22};
23use crate::dialect::Dialect;
24use crate::keywords::{self, Keyword};
25use crate::parser::{Parser, ParserError};
26use crate::tokenizer::Token;
27#[cfg(not(feature = "std"))]
28use alloc::{vec, vec::Vec};
29
30const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[Keyword::IF, Keyword::ELSE];
31
32#[derive(Debug)]
34pub struct MsSqlDialect {}
35
36impl Dialect for MsSqlDialect {
37 fn is_delimited_identifier_start(&self, ch: char) -> bool {
38 ch == '"' || ch == '['
39 }
40
41 fn is_identifier_start(&self, ch: char) -> bool {
42 ch.is_alphabetic() || ch == '_' || ch == '#' || ch == '@'
44 }
45
46 fn is_identifier_part(&self, ch: char) -> bool {
47 ch.is_alphabetic()
48 || ch.is_ascii_digit()
49 || ch == '@'
50 || ch == '$'
51 || ch == '#'
52 || ch == '_'
53 }
54
55 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
56 Some('[')
57 }
58
59 fn convert_type_before_value(&self) -> bool {
62 true
63 }
64
65 fn supports_outer_join_operator(&self) -> bool {
66 true
67 }
68
69 fn supports_connect_by(&self) -> bool {
70 true
71 }
72
73 fn supports_eq_alias_assignment(&self) -> bool {
74 true
75 }
76
77 fn supports_try_convert(&self) -> bool {
78 true
79 }
80
81 fn supports_boolean_literals(&self) -> bool {
83 false
84 }
85
86 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
87 true
88 }
89
90 fn supports_named_fn_args_with_expr_name(&self) -> bool {
91 true
92 }
93
94 fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
95 false
96 }
97
98 fn supports_start_transaction_modifier(&self) -> bool {
99 true
100 }
101
102 fn supports_end_transaction_modifier(&self) -> bool {
103 true
104 }
105
106 fn supports_set_stmt_without_operator(&self) -> bool {
108 true
109 }
110
111 fn supports_timestamp_versioning(&self) -> bool {
113 true
114 }
115
116 fn supports_nested_comments(&self) -> bool {
118 true
119 }
120
121 fn supports_object_name_double_dot_notation(&self) -> bool {
123 true
124 }
125
126 fn get_reserved_grantees_types(&self) -> &[GranteesType] {
128 &[GranteesType::Public]
129 }
130
131 fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
132 !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw) && !RESERVED_FOR_COLUMN_ALIAS.contains(kw)
133 }
134
135 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
136 if parser.peek_keyword(Keyword::IF) {
137 Some(self.parse_if_stmt(parser))
138 } else if parser.parse_keywords(&[Keyword::CREATE, Keyword::TRIGGER]) {
139 Some(self.parse_create_trigger(parser, false))
140 } else if parser.parse_keywords(&[
141 Keyword::CREATE,
142 Keyword::OR,
143 Keyword::ALTER,
144 Keyword::TRIGGER,
145 ]) {
146 Some(self.parse_create_trigger(parser, true))
147 } else {
148 None
149 }
150 }
151}
152
153impl MsSqlDialect {
154 fn parse_if_stmt(&self, parser: &mut Parser) -> Result<Statement, ParserError> {
161 let if_token = parser.expect_keyword(Keyword::IF)?;
162
163 let condition = parser.parse_expr()?;
164
165 let if_block = if parser.peek_keyword(Keyword::BEGIN) {
166 let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
167 let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
168 let end_token = parser.expect_keyword(Keyword::END)?;
169 ConditionalStatementBlock {
170 start_token: AttachedToken(if_token),
171 condition: Some(condition),
172 then_token: None,
173 conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
174 begin_token: AttachedToken(begin_token),
175 statements,
176 end_token: AttachedToken(end_token),
177 }),
178 }
179 } else {
180 let stmt = parser.parse_statement()?;
181 ConditionalStatementBlock {
182 start_token: AttachedToken(if_token),
183 condition: Some(condition),
184 then_token: None,
185 conditional_statements: ConditionalStatements::Sequence {
186 statements: vec![stmt],
187 },
188 }
189 };
190
191 let mut prior_statement_ended_with_semi_colon = false;
192 while let Token::SemiColon = parser.peek_token_ref().token {
193 parser.advance_token();
194 prior_statement_ended_with_semi_colon = true;
195 }
196
197 let mut else_block = None;
198 if parser.peek_keyword(Keyword::ELSE) {
199 let else_token = parser.expect_keyword(Keyword::ELSE)?;
200 if parser.peek_keyword(Keyword::BEGIN) {
201 let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
202 let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
203 let end_token = parser.expect_keyword(Keyword::END)?;
204 else_block = Some(ConditionalStatementBlock {
205 start_token: AttachedToken(else_token),
206 condition: None,
207 then_token: None,
208 conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
209 begin_token: AttachedToken(begin_token),
210 statements,
211 end_token: AttachedToken(end_token),
212 }),
213 });
214 } else {
215 let stmt = parser.parse_statement()?;
216 else_block = Some(ConditionalStatementBlock {
217 start_token: AttachedToken(else_token),
218 condition: None,
219 then_token: None,
220 conditional_statements: ConditionalStatements::Sequence {
221 statements: vec![stmt],
222 },
223 });
224 }
225 } else if prior_statement_ended_with_semi_colon {
226 parser.prev_token();
227 }
228
229 Ok(IfStatement {
230 if_block,
231 else_block,
232 elseif_blocks: Vec::new(),
233 end_token: None,
234 }
235 .into())
236 }
237
238 fn parse_create_trigger(
242 &self,
243 parser: &mut Parser,
244 or_alter: bool,
245 ) -> Result<Statement, ParserError> {
246 let name = parser.parse_object_name(false)?;
247 parser.expect_keyword_is(Keyword::ON)?;
248 let table_name = parser.parse_object_name(false)?;
249 let period = parser.parse_trigger_period()?;
250 let events = parser.parse_comma_separated(Parser::parse_trigger_event)?;
251
252 parser.expect_keyword_is(Keyword::AS)?;
253 let statements = Some(parser.parse_conditional_statements(&[Keyword::END])?);
254
255 Ok(CreateTrigger {
256 or_alter,
257 or_replace: false,
258 is_constraint: false,
259 name,
260 period,
261 period_before_table: false,
262 events,
263 table_name,
264 referenced_table_name: None,
265 referencing: Vec::new(),
266 trigger_object: TriggerObject::Statement,
267 include_each: false,
268 condition: None,
269 exec_body: None,
270 statements_as: true,
271 statements,
272 characteristics: None,
273 }
274 .into())
275 }
276
277 fn parse_statement_list(
281 &self,
282 parser: &mut Parser,
283 terminal_keyword: Option<Keyword>,
284 ) -> Result<Vec<Statement>, ParserError> {
285 let mut stmts = Vec::new();
286 loop {
287 if let Token::EOF = parser.peek_token_ref().token {
288 break;
289 }
290 if let Some(term) = terminal_keyword {
291 if parser.peek_keyword(term) {
292 break;
293 }
294 }
295 stmts.push(parser.parse_statement()?);
296 while let Token::SemiColon = parser.peek_token_ref().token {
297 parser.advance_token();
298 }
299 }
300 Ok(stmts)
301 }
302}