1use alloc::vec::Vec;
2
3use crate::{
4 Identifier, QualifiedName, Span, Spanned,
5 keywords::Keyword,
6 lexer::Token,
7 parser::{ParseError, Parser},
8 qualified_name::parse_qualified_name_unreserved,
9};
10
11#[derive(Clone, Debug)]
12pub enum LockType {
13 Read(Span),
14 ReadLocal(Span),
15 Write(Span),
16 LowPriorityWrite(Span),
17}
18
19impl Spanned for LockType {
20 fn span(&self) -> Span {
21 match self {
22 LockType::Read(s) => s.clone(),
23 LockType::ReadLocal(s) => s.clone(),
24 LockType::Write(s) => s.clone(),
25 LockType::LowPriorityWrite(s) => s.clone(),
26 }
27 }
28}
29
30#[derive(Clone, Debug)]
31pub struct LockMember<'a> {
32 pub table_name: QualifiedName<'a>,
33 pub alias: Option<Identifier<'a>>,
34 pub lock_type: LockType,
35}
36
37impl Spanned for LockMember<'_> {
38 fn span(&self) -> Span {
39 self.table_name
40 .span()
41 .join_span(&self.alias)
42 .join_span(&self.lock_type)
43 }
44}
45
46#[derive(Clone, Debug)]
61pub struct Lock<'a> {
62 pub lock_span: Span,
63 pub tables_span: Span,
64 pub members: Vec<LockMember<'a>>,
65}
66
67impl Spanned for Lock<'_> {
68 fn span(&self) -> Span {
69 self.lock_span
70 .join_span(&self.tables_span)
71 .join_span(&self.members)
72 }
73}
74
75pub(crate) fn parse_lock<'a>(parser: &mut Parser<'a, '_>) -> Result<Lock<'a>, ParseError> {
76 let lock_span = parser.consume_keyword(Keyword::LOCK)?;
77
78 let tables_span = match parser.token {
79 Token::Ident(_, Keyword::TABLE) => parser.consume_keyword(Keyword::TABLE)?,
80 Token::Ident(_, Keyword::TABLES) => parser.consume_keyword(Keyword::TABLES)?,
81 _ => return parser.expected_failure("'TABLE' | 'TABLES'"),
82 };
83
84 let mut members = Vec::new();
85 loop {
86 let table_name = parse_qualified_name_unreserved(parser)?;
87
88 let alias = if parser.skip_keyword(Keyword::AS).is_some() {
89 Some(parser.consume_plain_identifier_unreserved()?)
90 } else if matches!(
91 parser.token,
92 Token::Ident(_, kw) if !matches!(kw, Keyword::READ | Keyword::WRITE | Keyword::LOW_PRIORITY)
93 ) {
94 Some(parser.consume_plain_identifier_unreserved()?)
96 } else {
97 None
98 };
99
100 let lock_type = match &parser.token {
101 Token::Ident(_, Keyword::READ) => {
102 let read_span = parser.consume_keyword(Keyword::READ)?;
103 if let Some(local_span) = parser.skip_keyword(Keyword::LOCAL) {
104 LockType::ReadLocal(read_span.join_span(&local_span))
105 } else {
106 LockType::Read(read_span)
107 }
108 }
109 Token::Ident(_, Keyword::LOW_PRIORITY) => {
110 let span = parser.consume_keywords(&[Keyword::LOW_PRIORITY, Keyword::WRITE])?;
111 LockType::LowPriorityWrite(span)
112 }
113 Token::Ident(_, Keyword::WRITE) => {
114 let write_span = parser.consume_keyword(Keyword::WRITE)?;
115 LockType::Write(write_span)
116 }
117 _ => return parser.expected_failure("'READ' | 'WRITE'"),
118 };
119
120 members.push(LockMember {
121 table_name,
122 alias,
123 lock_type,
124 });
125
126 if parser.skip_token(Token::Comma).is_none() {
127 break;
128 }
129 }
130 Ok(Lock {
131 lock_span,
132 tables_span,
133 members,
134 })
135}
136
137#[derive(Clone, Debug)]
152pub struct Unlock {
153 pub unlock_span: Span,
154 pub tables_span: Span,
155}
156
157impl Spanned for Unlock {
158 fn span(&self) -> Span {
159 self.unlock_span.join_span(&self.tables_span)
160 }
161}
162
163pub(crate) fn parse_unlock<'a>(parser: &mut Parser<'a, '_>) -> Result<Unlock, ParseError> {
164 let unlock_span = parser.consume_keyword(Keyword::UNLOCK)?;
165
166 let tables_span = match parser.token {
167 Token::Ident(_, Keyword::TABLE) => parser.consume_keyword(Keyword::TABLE)?,
168 Token::Ident(_, Keyword::TABLES) => parser.consume_keyword(Keyword::TABLES)?,
169 _ => return parser.expected_failure("'TABLE' | 'TABLES'"),
170 };
171
172 Ok(Unlock {
173 unlock_span,
174 tables_span,
175 })
176}