feat: Support KILL statement (#479)

This commit is contained in:
Dmitry Patsura 2022-05-02 21:04:33 +03:00 committed by GitHub
parent 7732c34b19
commit f5980cd30f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 0 deletions

View file

@ -1005,6 +1005,13 @@ pub enum Statement {
data_types: Vec<DataType>, data_types: Vec<DataType>,
statement: Box<Statement>, statement: Box<Statement>,
}, },
/// See <https://clickhouse.com/docs/ru/sql-reference/statements/kill/>
/// See <https://dev.mysql.com/doc/refman/8.0/en/kill.html>
Kill {
modifier: Option<KillType>,
// processlist_id
id: u64,
},
/// EXPLAIN TABLE /// EXPLAIN TABLE
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/explain.html> /// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/explain.html>
ExplainTable { ExplainTable {
@ -1047,6 +1054,15 @@ impl fmt::Display for Statement {
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Statement::Kill { modifier, id } => {
write!(f, "KILL ")?;
if let Some(m) = modifier {
write!(f, "{} ", m)?;
}
write!(f, "{}", id)
}
Statement::ExplainTable { Statement::ExplainTable {
describe_alias, describe_alias,
table_name, table_name,
@ -2097,6 +2113,26 @@ impl fmt::Display for ObjectType {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum KillType {
Connection,
Query,
Mutation,
}
impl fmt::Display for KillType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
// MySQL
KillType::Connection => "CONNECTION",
KillType::Query => "QUERY",
// Clickhouse supports Mutation
KillType::Mutation => "MUTATION",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum HiveDistributionStyle { pub enum HiveDistributionStyle {

View file

@ -136,6 +136,7 @@ define_keywords!(
COMPUTE, COMPUTE,
CONDITION, CONDITION,
CONNECT, CONNECT,
CONNECTION,
CONSTRAINT, CONSTRAINT,
CONTAINS, CONTAINS,
CONVERT, CONVERT,
@ -279,6 +280,7 @@ define_keywords!(
JSONFILE, JSONFILE,
JULIAN, JULIAN,
KEY, KEY,
KILL,
LAG, LAG,
LANGUAGE, LANGUAGE,
LARGE, LARGE,
@ -319,6 +321,7 @@ define_keywords!(
MONTH, MONTH,
MSCK, MSCK,
MULTISET, MULTISET,
MUTATION,
NATIONAL, NATIONAL,
NATURAL, NATURAL,
NCHAR, NCHAR,
@ -384,6 +387,7 @@ define_keywords!(
PURGE, PURGE,
QUALIFY, QUALIFY,
QUARTER, QUARTER,
QUERY,
QUOTE, QUOTE,
RANGE, RANGE,
RANK, RANK,

View file

@ -154,6 +154,7 @@ impl<'a> Parser<'a> {
pub fn parse_statement(&mut self) -> Result<Statement, ParserError> { pub fn parse_statement(&mut self) -> Result<Statement, ParserError> {
match self.next_token() { match self.next_token() {
Token::Word(w) => match w.keyword { Token::Word(w) => match w.keyword {
Keyword::KILL => Ok(self.parse_kill()?),
Keyword::DESCRIBE => Ok(self.parse_explain(true)?), Keyword::DESCRIBE => Ok(self.parse_explain(true)?),
Keyword::EXPLAIN => Ok(self.parse_explain(false)?), Keyword::EXPLAIN => Ok(self.parse_explain(false)?),
Keyword::ANALYZE => Ok(self.parse_analyze()?), Keyword::ANALYZE => Ok(self.parse_analyze()?),
@ -2878,6 +2879,32 @@ impl<'a> Parser<'a> {
}) })
} }
// KILL [CONNECTION | QUERY] processlist_id
pub fn parse_kill(&mut self) -> Result<Statement, ParserError> {
let modifier_keyword =
self.parse_one_of_keywords(&[Keyword::CONNECTION, Keyword::QUERY, Keyword::MUTATION]);
let id = self.parse_literal_uint()?;
let modifier = match modifier_keyword {
Some(Keyword::CONNECTION) => Some(KillType::Connection),
Some(Keyword::QUERY) => Some(KillType::Query),
Some(Keyword::MUTATION) => {
if dialect_of!(self is ClickHouseDialect | GenericDialect) {
Some(KillType::Mutation)
} else {
self.expected(
"Unsupported type for KILL, allowed: CONNECTION | QUERY",
self.peek_token(),
)?
}
}
_ => None,
};
Ok(Statement::Kill { modifier, id })
}
pub fn parse_explain(&mut self, describe_alias: bool) -> Result<Statement, ParserError> { pub fn parse_explain(&mut self, describe_alias: bool) -> Result<Statement, ParserError> {
let analyze = self.parse_keyword(Keyword::ANALYZE); let analyze = self.parse_keyword(Keyword::ANALYZE);
let verbose = self.parse_keyword(Keyword::VERBOSE); let verbose = self.parse_keyword(Keyword::VERBOSE);

View file

@ -770,6 +770,36 @@ fn parse_substring_in_select() {
} }
} }
#[test]
fn parse_kill() {
let stmt = mysql_and_generic().verified_stmt("KILL CONNECTION 5");
assert_eq!(
stmt,
Statement::Kill {
modifier: Some(KillType::Connection),
id: 5,
}
);
let stmt = mysql_and_generic().verified_stmt("KILL QUERY 5");
assert_eq!(
stmt,
Statement::Kill {
modifier: Some(KillType::Query),
id: 5,
}
);
let stmt = mysql_and_generic().verified_stmt("KILL 5");
assert_eq!(
stmt,
Statement::Kill {
modifier: None,
id: 5,
}
);
}
fn mysql() -> TestedDialects { fn mysql() -> TestedDialects {
TestedDialects { TestedDialects {
dialects: vec![Box::new(MySqlDialect {})], dialects: vec![Box::new(MySqlDialect {})],

View file

@ -119,6 +119,18 @@ fn parse_array_expr() {
) )
} }
#[test]
fn parse_kill() {
let stmt = clickhouse().verified_stmt("KILL MUTATION 5");
assert_eq!(
stmt,
Statement::Kill {
modifier: Some(KillType::Mutation),
id: 5,
}
);
}
fn clickhouse() -> TestedDialects { fn clickhouse() -> TestedDialects {
TestedDialects { TestedDialects {
dialects: vec![Box::new(ClickHouseDialect {})], dialects: vec![Box::new(ClickHouseDialect {})],