sqlparser/dialect/
mssql.rs1use crate::ast::helpers::attached_token::AttachedToken;
19use crate::ast::{
20 BeginEndStatements, ConditionalStatementBlock, ConditionalStatements, GranteesType,
21 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(Statement::If(IfStatement {
230 if_block,
231 else_block,
232 elseif_blocks: Vec::new(),
233 end_token: None,
234 }))
235 }
236
237 fn parse_create_trigger(
241 &self,
242 parser: &mut Parser,
243 or_alter: bool,
244 ) -> Result<Statement, ParserError> {
245 let name = parser.parse_object_name(false)?;
246 parser.expect_keyword_is(Keyword::ON)?;
247 let table_name = parser.parse_object_name(false)?;
248 let period = parser.parse_trigger_period()?;
249 let events = parser.parse_comma_separated(Parser::parse_trigger_event)?;
250
251 parser.expect_keyword_is(Keyword::AS)?;
252 let statements = Some(parser.parse_conditional_statements(&[Keyword::END])?);
253
254 Ok(Statement::CreateTrigger {
255 or_alter,
256 or_replace: false,
257 is_constraint: false,
258 name,
259 period,
260 events,
261 table_name,
262 referenced_table_name: None,
263 referencing: Vec::new(),
264 trigger_object: TriggerObject::Statement,
265 include_each: false,
266 condition: None,
267 exec_body: None,
268 statements,
269 characteristics: None,
270 })
271 }
272
273 fn parse_statement_list(
277 &self,
278 parser: &mut Parser,
279 terminal_keyword: Option<Keyword>,
280 ) -> Result<Vec<Statement>, ParserError> {
281 let mut stmts = Vec::new();
282 loop {
283 if let Token::EOF = parser.peek_token_ref().token {
284 break;
285 }
286 if let Some(term) = terminal_keyword {
287 if parser.peek_keyword(term) {
288 break;
289 }
290 }
291 stmts.push(parser.parse_statement()?);
292 while let Token::SemiColon = parser.peek_token_ref().token {
293 parser.advance_token();
294 }
295 }
296 Ok(stmts)
297 }
298}