sqltk_parser/dialect/
mssql.rs1use crate::ast::helpers::attached_token::AttachedToken;
19use crate::ast::{
20 BeginEndStatements, ConditionalStatementBlock, ConditionalStatements, IfStatement, Statement,
21 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 convert_type_before_value(&self) -> bool {
58 true
59 }
60
61 fn supports_outer_join_operator(&self) -> bool {
62 true
63 }
64
65 fn supports_connect_by(&self) -> bool {
66 true
67 }
68
69 fn supports_eq_alias_assignment(&self) -> bool {
70 true
71 }
72
73 fn supports_try_convert(&self) -> bool {
74 true
75 }
76
77 fn supports_boolean_literals(&self) -> bool {
79 false
80 }
81
82 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
83 true
84 }
85
86 fn supports_named_fn_args_with_expr_name(&self) -> bool {
87 true
88 }
89
90 fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
91 false
92 }
93
94 fn supports_start_transaction_modifier(&self) -> bool {
95 true
96 }
97
98 fn supports_end_transaction_modifier(&self) -> bool {
99 true
100 }
101
102 fn supports_set_stmt_without_operator(&self) -> bool {
104 true
105 }
106
107 fn supports_timestamp_versioning(&self) -> bool {
109 true
110 }
111
112 fn supports_nested_comments(&self) -> bool {
114 true
115 }
116
117 fn supports_object_name_double_dot_notation(&self) -> bool {
119 true
120 }
121
122 fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
123 !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw) && !RESERVED_FOR_COLUMN_ALIAS.contains(kw)
124 }
125
126 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
127 if parser.peek_keyword(Keyword::IF) {
128 Some(self.parse_if_stmt(parser))
129 } else if parser.parse_keywords(&[Keyword::CREATE, Keyword::TRIGGER]) {
130 Some(self.parse_create_trigger(parser, false))
131 } else if parser.parse_keywords(&[
132 Keyword::CREATE,
133 Keyword::OR,
134 Keyword::ALTER,
135 Keyword::TRIGGER,
136 ]) {
137 Some(self.parse_create_trigger(parser, true))
138 } else {
139 None
140 }
141 }
142}
143
144impl MsSqlDialect {
145 fn parse_if_stmt(&self, parser: &mut Parser) -> Result<Statement, ParserError> {
152 let if_token = parser.expect_keyword(Keyword::IF)?;
153
154 let condition = parser.parse_expr()?;
155
156 let if_block = if parser.peek_keyword(Keyword::BEGIN) {
157 let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
158 let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
159 let end_token = parser.expect_keyword(Keyword::END)?;
160 ConditionalStatementBlock {
161 start_token: AttachedToken(if_token),
162 condition: Some(condition),
163 then_token: None,
164 conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
165 begin_token: AttachedToken(begin_token),
166 statements,
167 end_token: AttachedToken(end_token),
168 }),
169 }
170 } else {
171 let stmt = parser.parse_statement()?;
172 ConditionalStatementBlock {
173 start_token: AttachedToken(if_token),
174 condition: Some(condition),
175 then_token: None,
176 conditional_statements: ConditionalStatements::Sequence {
177 statements: vec![stmt],
178 },
179 }
180 };
181
182 let mut prior_statement_ended_with_semi_colon = false;
183 while let Token::SemiColon = parser.peek_token_ref().token {
184 parser.advance_token();
185 prior_statement_ended_with_semi_colon = true;
186 }
187
188 let mut else_block = None;
189 if parser.peek_keyword(Keyword::ELSE) {
190 let else_token = parser.expect_keyword(Keyword::ELSE)?;
191 if parser.peek_keyword(Keyword::BEGIN) {
192 let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
193 let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
194 let end_token = parser.expect_keyword(Keyword::END)?;
195 else_block = Some(ConditionalStatementBlock {
196 start_token: AttachedToken(else_token),
197 condition: None,
198 then_token: None,
199 conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
200 begin_token: AttachedToken(begin_token),
201 statements,
202 end_token: AttachedToken(end_token),
203 }),
204 });
205 } else {
206 let stmt = parser.parse_statement()?;
207 else_block = Some(ConditionalStatementBlock {
208 start_token: AttachedToken(else_token),
209 condition: None,
210 then_token: None,
211 conditional_statements: ConditionalStatements::Sequence {
212 statements: vec![stmt],
213 },
214 });
215 }
216 } else if prior_statement_ended_with_semi_colon {
217 parser.prev_token();
218 }
219
220 Ok(Statement::If(IfStatement {
221 if_block,
222 else_block,
223 elseif_blocks: Vec::new(),
224 end_token: None,
225 }))
226 }
227
228 fn parse_create_trigger(
232 &self,
233 parser: &mut Parser,
234 or_alter: bool,
235 ) -> Result<Statement, ParserError> {
236 let name = parser.parse_object_name(false)?;
237 parser.expect_keyword_is(Keyword::ON)?;
238 let table_name = parser.parse_object_name(false)?;
239 let period = parser.parse_trigger_period()?;
240 let events = parser.parse_comma_separated(Parser::parse_trigger_event)?;
241
242 parser.expect_keyword_is(Keyword::AS)?;
243 let statements = Some(parser.parse_conditional_statements(&[Keyword::END])?);
244
245 Ok(Statement::CreateTrigger {
246 or_alter,
247 or_replace: false,
248 is_constraint: false,
249 name,
250 period,
251 events,
252 table_name,
253 referenced_table_name: None,
254 referencing: Vec::new(),
255 trigger_object: TriggerObject::Statement,
256 include_each: false,
257 condition: None,
258 exec_body: None,
259 statements,
260 characteristics: None,
261 })
262 }
263
264 fn parse_statement_list(
268 &self,
269 parser: &mut Parser,
270 terminal_keyword: Option<Keyword>,
271 ) -> Result<Vec<Statement>, ParserError> {
272 let mut stmts = Vec::new();
273 loop {
274 if let Token::EOF = parser.peek_token_ref().token {
275 break;
276 }
277 if let Some(term) = terminal_keyword {
278 if parser.peek_keyword(term) {
279 break;
280 }
281 }
282 stmts.push(parser.parse_statement()?);
283 while let Token::SemiColon = parser.peek_token_ref().token {
284 parser.advance_token();
285 }
286 }
287 Ok(stmts)
288 }
289}