mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2025-12-22 22:20:02 +00:00
feat: support SQL parsing for trigger show (#6217)
* feat: support SQL parsing for trigger show * add excludes in licenserc * refine comment * fix: typo * fix: add show/trigger.rs to excludes in licenserc
This commit is contained in:
@@ -28,7 +28,9 @@ excludes = [
|
||||
"src/servers/src/http/test_helpers.rs",
|
||||
# enterprise
|
||||
"src/sql/src/statements/create/trigger.rs",
|
||||
"src/sql/src/statements/show/trigger.rs",
|
||||
"src/sql/src/parsers/create_parser/trigger.rs",
|
||||
"src/sql/src/parsers/show_parser/trigger.rs",
|
||||
]
|
||||
|
||||
[properties]
|
||||
|
||||
@@ -550,6 +550,11 @@ pub fn check_permission(
|
||||
Statement::ShowFlows(stmt) => {
|
||||
validate_db_permission!(stmt, query_ctx);
|
||||
}
|
||||
#[cfg(feature = "enterprise")]
|
||||
Statement::ShowTriggers(_stmt) => {
|
||||
// The trigger is organized based on the catalog dimension, so there
|
||||
// is no need to check the permission of the database(schema).
|
||||
}
|
||||
Statement::ShowStatus(_stmt) => {}
|
||||
Statement::ShowSearchPath(_stmt) => {}
|
||||
Statement::DescribeTable(stmt) => {
|
||||
|
||||
@@ -170,6 +170,9 @@ impl StatementExecutor {
|
||||
|
||||
Statement::ShowFlows(stmt) => self.show_flows(stmt, query_ctx).await,
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
Statement::ShowTriggers(stmt) => self.show_triggers(stmt, query_ctx).await,
|
||||
|
||||
Statement::Copy(sql::statements::copy::Copy::CopyQueryTo(stmt)) => {
|
||||
let query_output = self
|
||||
.plan_exec(QueryStatement::Sql(*stmt.query), query_ctx)
|
||||
|
||||
@@ -226,6 +226,16 @@ impl StatementExecutor {
|
||||
.context(ExecuteStatementSnafu)
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) async fn show_triggers(
|
||||
&self,
|
||||
_stmt: sql::statements::show::trigger::ShowTriggers,
|
||||
_query_ctx: QueryContextRef,
|
||||
) -> Result<Output> {
|
||||
crate::error::UnsupportedTriggerSnafu.fail()
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn show_create_flow(
|
||||
&self,
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod trigger;
|
||||
|
||||
use snafu::{ensure, ResultExt};
|
||||
use sqlparser::keywords::Keyword;
|
||||
use sqlparser::tokenizer::Token;
|
||||
@@ -32,6 +35,10 @@ impl ParserContext<'_> {
|
||||
/// Parses SHOW statements
|
||||
/// todo(hl) support `show settings`/`show create`/`show users` etc.
|
||||
pub(crate) fn parse_show(&mut self) -> Result<Statement> {
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.consume_token("TRIGGERS") {
|
||||
return self.parse_show_triggers();
|
||||
}
|
||||
if self.consume_token("DATABASES") || self.consume_token("SCHEMAS") {
|
||||
self.parse_show_databases(false)
|
||||
} else if self.matches_keyword(Keyword::TABLES) {
|
||||
@@ -530,7 +537,7 @@ impl ParserContext<'_> {
|
||||
}));
|
||||
}
|
||||
|
||||
// SHOW FLOWS [in | FROM] [DATABASE]
|
||||
// SHOW VIEWS [in | FROM] [DATABASE]
|
||||
Token::Word(w) => match w.keyword {
|
||||
Keyword::IN | Keyword::FROM => self.parse_db_name()?,
|
||||
_ => None,
|
||||
|
||||
70
src/sql/src/parsers/show_parser/trigger.rs
Normal file
70
src/sql/src/parsers/show_parser/trigger.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use crate::error::Result;
|
||||
use crate::parser::ParserContext;
|
||||
use crate::statements::show::trigger::ShowTriggers;
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
impl ParserContext<'_> {
|
||||
pub(super) fn parse_show_triggers(&mut self) -> Result<Statement> {
|
||||
let kind = self.parse_show_kind()?;
|
||||
let show_triggers = ShowTriggers { kind };
|
||||
Ok(Statement::ShowTriggers(show_triggers))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::dialect::GreptimeDbDialect;
|
||||
use crate::parser::ParserContext;
|
||||
use crate::statements::show::ShowKind;
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
#[test]
|
||||
fn test_parse_show_triggers() {
|
||||
// Valid, sql: `SHOW TRIGGERS`.
|
||||
let sql = "";
|
||||
let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
|
||||
let statement = ctx.parse_show_triggers().unwrap();
|
||||
let Statement::ShowTriggers(show_triggers) = statement else {
|
||||
panic!("Expected ShowTriggers statement");
|
||||
};
|
||||
assert_eq!(show_triggers.kind, ShowKind::All);
|
||||
|
||||
// Valid, sql: `SHOW TRIGGERS;`.
|
||||
let sql = ";";
|
||||
let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
|
||||
let statement = ctx.parse_show_triggers().unwrap();
|
||||
let Statement::ShowTriggers(show_triggers) = statement else {
|
||||
panic!("Expected ShowTriggers statement");
|
||||
};
|
||||
assert_eq!(show_triggers.kind, ShowKind::All);
|
||||
|
||||
// Valid, sql: `SHOW TRIGGERS LIKE 'test_trigger'`.
|
||||
let sql = "LIKE 'test_trigger'";
|
||||
let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
|
||||
let statement = ctx.parse_show_triggers().unwrap();
|
||||
let Statement::ShowTriggers(show_triggers) = statement else {
|
||||
panic!("Expected ShowTriggers statement");
|
||||
};
|
||||
let ShowKind::Like(like) = show_triggers.kind else {
|
||||
panic!("Expected ShowKind::Like");
|
||||
};
|
||||
assert_eq!(like.value, "test_trigger");
|
||||
|
||||
// Valid, sql: `SHOW TRIGGERS WHERE name = 'test_trigger'`.
|
||||
let sql = "WHERE name = 'test_trigger'";
|
||||
let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
|
||||
let statement = ctx.parse_show_triggers().unwrap();
|
||||
let Statement::ShowTriggers(show_triggers) = statement else {
|
||||
panic!("Expected ShowTriggers statement");
|
||||
};
|
||||
let ShowKind::Where(expr) = show_triggers.kind else {
|
||||
panic!("Expected ShowKind::Where");
|
||||
};
|
||||
assert_eq!(expr.to_string(), "name = 'test_trigger'");
|
||||
|
||||
// Invalid, since incorrect keyword `LI`.
|
||||
let sql = "LI 'test_trigger'";
|
||||
let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
|
||||
assert!(ctx.parse_show_triggers().is_err());
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,9 @@ macro_rules! format_kind {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod trigger;
|
||||
|
||||
/// SQL structure for `SHOW DATABASES`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
pub struct ShowDatabases {
|
||||
|
||||
59
src/sql/src/statements/show/trigger.rs
Normal file
59
src/sql/src/statements/show/trigger.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use serde::Serialize;
|
||||
use sqlparser_derive::{Visit, VisitMut};
|
||||
|
||||
use crate::statements::show::ShowKind;
|
||||
|
||||
/// SQL structure for `SHOW TRIGGERS`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
pub struct ShowTriggers {
|
||||
pub kind: ShowKind,
|
||||
}
|
||||
|
||||
impl Display for ShowTriggers {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SHOW TRIGGERS")?;
|
||||
format_kind!(self, f);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::dialect::GreptimeDbDialect;
|
||||
use crate::parser::{ParseOptions, ParserContext};
|
||||
use crate::statements::show::trigger::ShowTriggers;
|
||||
use crate::statements::show::ShowKind;
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
#[test]
|
||||
fn test_show_triggers_display() {
|
||||
let show_triggers = ShowTriggers {
|
||||
kind: ShowKind::All,
|
||||
};
|
||||
assert_eq!(show_triggers.to_string(), "SHOW TRIGGERS");
|
||||
|
||||
let sql = "SHOW TRIGGERS LIKE 'test_trigger'";
|
||||
let result =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
assert_eq!(1, result.len());
|
||||
let Statement::ShowTriggers(show_triggers) = &result[0] else {
|
||||
panic!("Expected ShowTriggers statement");
|
||||
};
|
||||
let expected = "SHOW TRIGGERS LIKE 'test_trigger'";
|
||||
assert_eq!(show_triggers.to_string(), expected);
|
||||
|
||||
let sql = "SHOW TRIGGERS WHERE name = 'test_trigger'";
|
||||
let result =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
assert_eq!(1, result.len());
|
||||
let Statement::ShowTriggers(show_triggers) = &result[0] else {
|
||||
panic!("Expected ShowTriggers statement");
|
||||
};
|
||||
let expected = "SHOW TRIGGERS WHERE name = 'test_trigger'";
|
||||
assert_eq!(show_triggers.to_string(), expected);
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,9 @@ pub enum Statement {
|
||||
ShowCreateFlow(ShowCreateFlow),
|
||||
/// SHOW FLOWS
|
||||
ShowFlows(ShowFlows),
|
||||
// SHOW TRIGGERS
|
||||
#[cfg(feature = "enterprise")]
|
||||
ShowTriggers(crate::statements::show::trigger::ShowTriggers),
|
||||
// SHOW CREATE VIEW
|
||||
ShowCreateView(ShowCreateView),
|
||||
// SHOW STATUS
|
||||
@@ -165,6 +168,8 @@ impl Display for Statement {
|
||||
Statement::ShowCreateTable(s) => s.fmt(f),
|
||||
Statement::ShowCreateFlow(s) => s.fmt(f),
|
||||
Statement::ShowFlows(s) => s.fmt(f),
|
||||
#[cfg(feature = "enterprise")]
|
||||
Statement::ShowTriggers(s) => s.fmt(f),
|
||||
Statement::ShowCreateDatabase(s) => s.fmt(f),
|
||||
Statement::ShowCreateView(s) => s.fmt(f),
|
||||
Statement::ShowViews(s) => s.fmt(f),
|
||||
|
||||
Reference in New Issue
Block a user