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(Debug, Clone)]
12pub enum FlushOption<'a> {
13 BinaryLogs(Span),
14 EngineLogs(Span),
15 ErrorLogs(Span),
16 GeneralLogs(Span),
17 Logs(Span),
18 Privileges(Span),
19 OptimizerCosts(Span),
20 RelayLogs(Span),
21 RelayLogsForChannel {
22 span: Span,
23 channel: Identifier<'a>,
24 },
25 SlowLogs(Span),
26 Status(Span),
27 UserResources(Span),
28 Table {
29 span: Span,
30 tables: Vec<QualifiedName<'a>>,
31 with_read_lock: Option<Span>,
32 for_export: Option<Span>,
33 },
34}
35
36impl Spanned for FlushOption<'_> {
37 fn span(&self) -> Span {
38 match self {
39 FlushOption::BinaryLogs(span)
40 | FlushOption::EngineLogs(span)
41 | FlushOption::ErrorLogs(span)
42 | FlushOption::GeneralLogs(span)
43 | FlushOption::Logs(span)
44 | FlushOption::Privileges(span)
45 | FlushOption::OptimizerCosts(span)
46 | FlushOption::RelayLogs(span)
47 | FlushOption::SlowLogs(span)
48 | FlushOption::Status(span)
49 | FlushOption::UserResources(span) => span.clone(),
50 FlushOption::RelayLogsForChannel { span, channel } => span.join_span(channel),
51 FlushOption::Table {
52 span,
53 tables,
54 with_read_lock,
55 for_export,
56 } => span
57 .join_span(tables)
58 .join_span(with_read_lock)
59 .join_span(for_export),
60 }
61 }
62}
63
64#[derive(Debug, Clone)]
78pub struct Flush<'a> {
79 pub flush_span: Span,
80 pub no_write_to_binlog: Option<Span>,
81 pub local: Option<Span>,
82 pub options: Vec<FlushOption<'a>>,
83}
84
85impl Spanned for Flush<'_> {
86 fn span(&self) -> Span {
87 self.flush_span
88 .join_span(&self.no_write_to_binlog)
89 .join_span(&self.local)
90 .join_span(&self.options)
91 }
92}
93
94pub(crate) fn parse_flush<'a>(parser: &mut Parser<'a, '_>) -> Result<Flush<'a>, ParseError> {
95 let flush_span = parser.consume_keyword(Keyword::FLUSH)?;
96
97 let no_write_to_binlog = parser.skip_keyword(Keyword::NO_WRITE_TO_BINLOG);
98 let local = parser.skip_keyword(Keyword::LOCAL);
99 let mut options = Vec::new();
100 loop {
101 match &parser.token {
102 Token::Ident(_, Keyword::BINARY) => {
103 let span = parser.consume_keywords(&[Keyword::BINARY, Keyword::LOGS])?;
104 options.push(FlushOption::BinaryLogs(span));
105 }
106 Token::Ident(_, Keyword::ENGINE) => {
107 let span = parser.consume_keywords(&[Keyword::ENGINE, Keyword::LOGS])?;
108 options.push(FlushOption::EngineLogs(span));
109 }
110 Token::Ident(_, Keyword::ERROR) => {
111 let span = parser.consume_keywords(&[Keyword::ERROR, Keyword::LOGS])?;
112 options.push(FlushOption::ErrorLogs(span));
113 }
114 Token::Ident(_, Keyword::GENERAL) => {
115 let span = parser.consume_keywords(&[Keyword::GENERAL, Keyword::LOGS])?;
116 options.push(FlushOption::GeneralLogs(span));
117 }
118 Token::Ident(_, Keyword::LOGS) => {
119 let span = parser.consume_keyword(Keyword::LOGS)?;
120 options.push(FlushOption::Logs(span));
121 }
122 Token::Ident(_, Keyword::PRIVILEGES) => {
123 let span = parser.consume_keyword(Keyword::PRIVILEGES)?;
124 options.push(FlushOption::Privileges(span));
125 }
126 Token::Ident(_, Keyword::OPTIMIZER_COSTS) => {
127 let span = parser.consume_keyword(Keyword::OPTIMIZER_COSTS)?;
128 options.push(FlushOption::OptimizerCosts(span));
129 }
130 Token::Ident(_, Keyword::RELAY) => {
131 let span = parser.consume_keywords(&[Keyword::RELAY, Keyword::LOGS])?;
132 if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
133 let span = span
134 .join_span(&for_span)
135 .join_span(&parser.consume_keyword(Keyword::CHANNEL)?);
136 options.push(FlushOption::RelayLogsForChannel {
137 span,
138 channel: parser.consume_plain_identifier_unreserved()?,
139 });
140 } else {
141 options.push(FlushOption::RelayLogs(span));
142 };
143 }
144 Token::Ident(_, Keyword::SLOW) => {
145 let span = parser.consume_keywords(&[Keyword::SLOW, Keyword::LOGS])?;
146 options.push(FlushOption::SlowLogs(span));
147 }
148 Token::Ident(_, Keyword::STATUS) => {
149 let span = parser.consume_keyword(Keyword::STATUS)?;
150 options.push(FlushOption::Status(span));
151 }
152 Token::Ident(_, Keyword::USER_RESOURCES) => {
153 let span = parser.consume_keyword(Keyword::USER_RESOURCES)?;
154 options.push(FlushOption::UserResources(span));
155 }
156 Token::Ident(_, Keyword::TABLE | Keyword::TABLES) => {
157 let span = parser.consume_keyword(Keyword::TABLES)?;
158 let mut tables = Vec::new();
159
160 if let Token::Ident(_, kw) = parser.token
161 && !kw.restricted(parser.reserved())
162 {
163 loop {
164 tables.push(parse_qualified_name_unreserved(parser)?);
165 if parser.skip_token(Token::Comma).is_none() {
166 break;
167 }
168 }
169 }
170
171 let with_read_lock = if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
172 Some(
173 with_span
174 .join_span(&parser.consume_keywords(&[Keyword::READ, Keyword::LOCK])?),
175 )
176 } else {
177 None
178 };
179 let for_export = if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
180 Some(for_span.join_span(&parser.consume_keyword(Keyword::EXPORT)?))
181 } else {
182 None
183 };
184
185 options.push(FlushOption::Table {
186 span,
187 tables,
188 with_read_lock,
189 for_export,
190 });
191 }
192 _ => break,
193 }
194 }
195
196 Ok(Flush {
197 flush_span,
198 no_write_to_binlog,
199 local,
200 options,
201 })
202}