sqltk_parser/dialect/
mysql.rs1#[cfg(not(feature = "std"))]
19use alloc::boxed::Box;
20
21use crate::{
22 ast::{BinaryOperator, Expr, LockTableType, LockTables, MySqlTableLock, Statement},
23 dialect::Dialect,
24 keywords::Keyword,
25 parser::{Parser, ParserError},
26};
27
28#[derive(Debug)]
30pub struct MySqlDialect {}
31
32impl Dialect for MySqlDialect {
33 fn is_identifier_start(&self, ch: char) -> bool {
34 ch.is_alphabetic()
38 || ch == '_'
39 || ch == '$'
40 || ch == '@'
41 || ('\u{0080}'..='\u{ffff}').contains(&ch)
42 }
43
44 fn is_identifier_part(&self, ch: char) -> bool {
45 self.is_identifier_start(ch) || ch.is_ascii_digit()
46 }
47
48 fn is_delimited_identifier_start(&self, ch: char) -> bool {
49 ch == '`'
50 }
51
52 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
53 Some('`')
54 }
55
56 fn supports_string_literal_backslash_escape(&self) -> bool {
58 true
59 }
60
61 fn supports_numeric_prefix(&self) -> bool {
62 true
63 }
64
65 fn parse_infix(
66 &self,
67 parser: &mut crate::parser::Parser,
68 expr: &crate::ast::Expr,
69 _precedence: u8,
70 ) -> Option<Result<crate::ast::Expr, ParserError>> {
71 if parser.parse_keyword(Keyword::DIV) {
73 Some(Ok(Expr::BinaryOp {
74 left: Box::new(expr.clone()),
75 op: BinaryOperator::MyIntegerDivide,
76 right: Box::new(parser.parse_expr().unwrap()),
77 }))
78 } else {
79 None
80 }
81 }
82
83 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
84 if parser.parse_keywords(&[Keyword::LOCK, Keyword::TABLE]) {
85 Some(parse_lock_tables(parser, false))
86 } else if parser.parse_keywords(&[Keyword::LOCK, Keyword::TABLES]) {
87 Some(parse_lock_tables(parser, true))
88 } else if parser.parse_keywords(&[Keyword::UNLOCK, Keyword::TABLE]) {
89 Some(parse_unlock_tables(parser, false))
90 } else if parser.parse_keywords(&[Keyword::UNLOCK, Keyword::TABLES]) {
91 Some(parse_unlock_tables(parser, true))
92 } else {
93 None
94 }
95 }
96
97 fn require_interval_qualifier(&self) -> bool {
98 true
99 }
100
101 fn supports_limit_comma(&self) -> bool {
102 true
103 }
104
105 fn supports_create_table_select(&self) -> bool {
107 true
108 }
109}
110
111fn parse_lock_tables(
114 parser: &mut Parser,
115 pluralized_table_keyword: bool,
116) -> Result<Statement, ParserError> {
117 let tables = parser.parse_comma_separated(parse_lock_table)?;
118 Ok(Statement::LockTables(LockTables::MySql {
119 pluralized_table_keyword,
120 tables,
121 }))
122}
123
124fn parse_lock_table(parser: &mut Parser) -> Result<MySqlTableLock, ParserError> {
126 let table = parser.parse_object_name(false)?;
127 let alias =
128 parser.parse_optional_alias(&[Keyword::READ, Keyword::WRITE, Keyword::LOW_PRIORITY])?;
129 let lock_type = parse_lock_tables_type(parser)?;
130
131 Ok(MySqlTableLock {
132 table,
133 alias,
134 lock_type: Some(lock_type),
135 })
136}
137
138fn parse_lock_tables_type(parser: &mut Parser) -> Result<LockTableType, ParserError> {
140 if parser.parse_keyword(Keyword::READ) {
141 if parser.parse_keyword(Keyword::LOCAL) {
142 Ok(LockTableType::Read { local: true })
143 } else {
144 Ok(LockTableType::Read { local: false })
145 }
146 } else if parser.parse_keyword(Keyword::WRITE) {
147 Ok(LockTableType::Write {
148 low_priority: false,
149 })
150 } else if parser.parse_keywords(&[Keyword::LOW_PRIORITY, Keyword::WRITE]) {
151 Ok(LockTableType::Write { low_priority: true })
152 } else {
153 parser.expected("an lock type in LOCK TABLES", parser.peek_token())
154 }
155}
156
157fn parse_unlock_tables(
160 _parser: &mut Parser,
161 pluralized_table: bool,
162) -> Result<Statement, ParserError> {
163 Ok(Statement::UnlockTables(pluralized_table))
164}