Skip to content

Commit 593c090

Browse files
authored
Support MySQL FLUSH statement (#1076)
1 parent c62ecb1 commit 593c090

File tree

4 files changed

+370
-0
lines changed

4 files changed

+370
-0
lines changed

src/ast/mod.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,20 @@ pub enum Statement {
17771777
into: Option<ObjectName>,
17781778
},
17791779
/// ```sql
1780+
/// FLUSH [NO_WRITE_TO_BINLOG | LOCAL] flush_option [, flush_option] ... | tables_option
1781+
/// ```
1782+
///
1783+
/// Note: this is a Mysql-specific statement,
1784+
/// but may also compatible with other SQL.
1785+
Flush {
1786+
object_type: FlushType,
1787+
location: Option<FlushLocation>,
1788+
channel: Option<String>,
1789+
read_lock: bool,
1790+
export: bool,
1791+
tables: Vec<ObjectName>,
1792+
},
1793+
/// ```sql
17801794
/// DISCARD [ ALL | PLANS | SEQUENCES | TEMPORARY | TEMP ]
17811795
/// ```
17821796
///
@@ -2199,6 +2213,36 @@ impl fmt::Display for Statement {
21992213
#[allow(clippy::cognitive_complexity)]
22002214
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22012215
match self {
2216+
Statement::Flush {
2217+
object_type,
2218+
location,
2219+
channel,
2220+
read_lock,
2221+
export,
2222+
tables,
2223+
} => {
2224+
write!(f, "FLUSH")?;
2225+
if let Some(location) = location {
2226+
write!(f, " {location}")?;
2227+
}
2228+
write!(f, " {object_type}")?;
2229+
2230+
if let Some(channel) = channel {
2231+
write!(f, " FOR CHANNEL {channel}")?;
2232+
}
2233+
2234+
write!(
2235+
f,
2236+
"{tables}{read}{export}",
2237+
tables = if !tables.is_empty() {
2238+
" ".to_string() + &display_comma_separated(tables).to_string()
2239+
} else {
2240+
"".to_string()
2241+
},
2242+
export = if *export { " FOR EXPORT" } else { "" },
2243+
read = if *read_lock { " WITH READ LOCK" } else { "" }
2244+
)
2245+
}
22022246
Statement::Kill { modifier, id } => {
22032247
write!(f, "KILL ")?;
22042248

@@ -4818,6 +4862,62 @@ impl fmt::Display for DiscardObject {
48184862
}
48194863
}
48204864

4865+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4866+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4867+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4868+
pub enum FlushType {
4869+
BinaryLogs,
4870+
EngineLogs,
4871+
ErrorLogs,
4872+
GeneralLogs,
4873+
Hosts,
4874+
Logs,
4875+
Privileges,
4876+
OptimizerCosts,
4877+
RelayLogs,
4878+
SlowLogs,
4879+
Status,
4880+
UserResources,
4881+
Tables,
4882+
}
4883+
4884+
impl fmt::Display for FlushType {
4885+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4886+
match self {
4887+
FlushType::BinaryLogs => f.write_str("BINARY LOGS"),
4888+
FlushType::EngineLogs => f.write_str("ENGINE LOGS"),
4889+
FlushType::ErrorLogs => f.write_str("ERROR LOGS"),
4890+
FlushType::GeneralLogs => f.write_str("GENERAL LOGS"),
4891+
FlushType::Hosts => f.write_str("HOSTS"),
4892+
FlushType::Logs => f.write_str("LOGS"),
4893+
FlushType::Privileges => f.write_str("PRIVILEGES"),
4894+
FlushType::OptimizerCosts => f.write_str("OPTIMIZER_COSTS"),
4895+
FlushType::RelayLogs => f.write_str("RELAY LOGS"),
4896+
FlushType::SlowLogs => f.write_str("SLOW LOGS"),
4897+
FlushType::Status => f.write_str("STATUS"),
4898+
FlushType::UserResources => f.write_str("USER_RESOURCES"),
4899+
FlushType::Tables => f.write_str("TABLES"),
4900+
}
4901+
}
4902+
}
4903+
4904+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4905+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4906+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4907+
pub enum FlushLocation {
4908+
NoWriteToBinlog,
4909+
Local,
4910+
}
4911+
4912+
impl fmt::Display for FlushLocation {
4913+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4914+
match self {
4915+
FlushLocation::NoWriteToBinlog => f.write_str("NO_WRITE_TO_BINLOG"),
4916+
FlushLocation::Local => f.write_str("LOCAL"),
4917+
}
4918+
}
4919+
}
4920+
48214921
/// Optional context modifier for statements that can be or `LOCAL`, or `SESSION`.
48224922
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
48234923
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

src/keywords.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ define_keywords!(
137137
CENTURY,
138138
CHAIN,
139139
CHANGE,
140+
CHANNEL,
140141
CHAR,
141142
CHARACTER,
142143
CHARACTERS,
@@ -265,6 +266,7 @@ define_keywords!(
265266
EXPANSION,
266267
EXPLAIN,
267268
EXPLICIT,
269+
EXPORT,
268270
EXTENDED,
269271
EXTERNAL,
270272
EXTRACT,
@@ -283,6 +285,7 @@ define_keywords!(
283285
FLOAT64,
284286
FLOAT8,
285287
FLOOR,
288+
FLUSH,
286289
FOLLOWING,
287290
FOR,
288291
FORCE,
@@ -302,6 +305,7 @@ define_keywords!(
302305
FUNCTION,
303306
FUNCTIONS,
304307
FUSION,
308+
GENERAL,
305309
GENERATE,
306310
GENERATED,
307311
GEOGRAPHY,
@@ -320,6 +324,7 @@ define_keywords!(
320324
HISTORY,
321325
HIVEVAR,
322326
HOLD,
327+
HOSTS,
323328
HOUR,
324329
HOURS,
325330
IDENTITY,
@@ -385,6 +390,7 @@ define_keywords!(
385390
LOCK,
386391
LOCKED,
387392
LOGIN,
393+
LOGS,
388394
LOWER,
389395
LOW_PRIORITY,
390396
MACRO,
@@ -439,6 +445,7 @@ define_keywords!(
439445
NOT,
440446
NOTHING,
441447
NOWAIT,
448+
NO_WRITE_TO_BINLOG,
442449
NTH_VALUE,
443450
NTILE,
444451
NULL,
@@ -458,6 +465,7 @@ define_keywords!(
458465
OPEN,
459466
OPERATOR,
460467
OPTIMIZE,
468+
OPTIMIZER_COSTS,
461469
OPTION,
462470
OPTIONS,
463471
OR,
@@ -531,6 +539,7 @@ define_keywords!(
531539
REGR_SXY,
532540
REGR_SYY,
533541
RELATIVE,
542+
RELAY,
534543
RELEASE,
535544
RENAME,
536545
REORG,
@@ -581,6 +590,7 @@ define_keywords!(
581590
SHOW,
582591
SIMILAR,
583592
SKIP,
593+
SLOW,
584594
SMALLINT,
585595
SNAPSHOT,
586596
SOME,
@@ -598,6 +608,7 @@ define_keywords!(
598608
START,
599609
STATIC,
600610
STATISTICS,
611+
STATUS,
601612
STDDEV_POP,
602613
STDDEV_SAMP,
603614
STDIN,
@@ -673,6 +684,7 @@ define_keywords!(
673684
USAGE,
674685
USE,
675686
USER,
687+
USER_RESOURCES,
676688
USING,
677689
UUID,
678690
VACUUM,

src/parser/mod.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ impl<'a> Parser<'a> {
472472
match &next_token.token {
473473
Token::Word(w) => match w.keyword {
474474
Keyword::KILL => Ok(self.parse_kill()?),
475+
Keyword::FLUSH => Ok(self.parse_flush()?),
475476
Keyword::DESCRIBE => Ok(self.parse_explain(true)?),
476477
Keyword::EXPLAIN => Ok(self.parse_explain(false)?),
477478
Keyword::ANALYZE => Ok(self.parse_analyze()?),
@@ -534,6 +535,93 @@ impl<'a> Parser<'a> {
534535
}
535536
}
536537

538+
pub fn parse_flush(&mut self) -> Result<Statement, ParserError> {
539+
let mut channel = None;
540+
let mut tables: Vec<ObjectName> = vec![];
541+
let mut read_lock = false;
542+
let mut export = false;
543+
544+
if !dialect_of!(self is MySqlDialect | GenericDialect) {
545+
return parser_err!("Unsupported statement FLUSH", self.peek_token().location);
546+
}
547+
548+
let location = if self.parse_keyword(Keyword::NO_WRITE_TO_BINLOG) {
549+
Some(FlushLocation::NoWriteToBinlog)
550+
} else if self.parse_keyword(Keyword::LOCAL) {
551+
Some(FlushLocation::Local)
552+
} else {
553+
None
554+
};
555+
556+
let object_type = if self.parse_keywords(&[Keyword::BINARY, Keyword::LOGS]) {
557+
FlushType::BinaryLogs
558+
} else if self.parse_keywords(&[Keyword::ENGINE, Keyword::LOGS]) {
559+
FlushType::EngineLogs
560+
} else if self.parse_keywords(&[Keyword::ERROR, Keyword::LOGS]) {
561+
FlushType::ErrorLogs
562+
} else if self.parse_keywords(&[Keyword::GENERAL, Keyword::LOGS]) {
563+
FlushType::GeneralLogs
564+
} else if self.parse_keywords(&[Keyword::HOSTS]) {
565+
FlushType::Hosts
566+
} else if self.parse_keyword(Keyword::PRIVILEGES) {
567+
FlushType::Privileges
568+
} else if self.parse_keyword(Keyword::OPTIMIZER_COSTS) {
569+
FlushType::OptimizerCosts
570+
} else if self.parse_keywords(&[Keyword::RELAY, Keyword::LOGS]) {
571+
if self.parse_keywords(&[Keyword::FOR, Keyword::CHANNEL]) {
572+
channel = Some(self.parse_object_name().unwrap().to_string());
573+
}
574+
FlushType::RelayLogs
575+
} else if self.parse_keywords(&[Keyword::SLOW, Keyword::LOGS]) {
576+
FlushType::SlowLogs
577+
} else if self.parse_keyword(Keyword::STATUS) {
578+
FlushType::Status
579+
} else if self.parse_keyword(Keyword::USER_RESOURCES) {
580+
FlushType::UserResources
581+
} else if self.parse_keywords(&[Keyword::LOGS]) {
582+
FlushType::Logs
583+
} else if self.parse_keywords(&[Keyword::TABLES]) {
584+
loop {
585+
let next_token = self.next_token();
586+
match &next_token.token {
587+
Token::Word(w) => match w.keyword {
588+
Keyword::WITH => {
589+
read_lock = self.parse_keywords(&[Keyword::READ, Keyword::LOCK]);
590+
}
591+
Keyword::FOR => {
592+
export = self.parse_keyword(Keyword::EXPORT);
593+
}
594+
Keyword::NoKeyword => {
595+
self.prev_token();
596+
tables = self.parse_comma_separated(Parser::parse_object_name)?;
597+
}
598+
_ => {}
599+
},
600+
_ => {
601+
break;
602+
}
603+
}
604+
}
605+
606+
FlushType::Tables
607+
} else {
608+
return self.expected(
609+
"BINARY LOGS, ENGINE LOGS, ERROR LOGS, GENERAL LOGS, HOSTS, LOGS, PRIVILEGES, OPTIMIZER_COSTS,\
610+
RELAY LOGS [FOR CHANNEL channel], SLOW LOGS, STATUS, USER_RESOURCES",
611+
self.peek_token(),
612+
);
613+
};
614+
615+
Ok(Statement::Flush {
616+
object_type,
617+
location,
618+
channel,
619+
read_lock,
620+
export,
621+
tables,
622+
})
623+
}
624+
537625
pub fn parse_msck(&mut self) -> Result<Statement, ParserError> {
538626
let repair = self.parse_keyword(Keyword::REPAIR);
539627
self.expect_keyword(Keyword::TABLE)?;

0 commit comments

Comments
 (0)