feat: implement truncate table parser (#1932)

* feat: truncate parser

* chore: keyword TABLE as optional
This commit is contained in:
Vanish
2023-07-12 14:59:24 +08:00
committed by GitHub
parent 674bfd85c7
commit 39091421a4
8 changed files with 182 additions and 0 deletions

View File

@@ -645,6 +645,9 @@ pub fn check_permission(
Statement::Copy(sql::statements::copy::Copy::CopyDatabase(stmt)) => {
validate_param(&stmt.database_name, query_ctx)?
}
Statement::TruncateTable(stmt) => {
validate_param(stmt.table_name(), query_ctx)?;
}
}
Ok(())
}

View File

@@ -130,6 +130,7 @@ impl StatementExecutor {
| Statement::CreateExternalTable(_)
| Statement::Alter(_)
| Statement::DropTable(_)
| Statement::TruncateTable(_)
| Statement::ShowCreateTable(_) => self
.sql_stmt_executor
.execute_sql(stmt, query_ctx)

View File

@@ -127,6 +127,8 @@ impl<'a> ParserContext<'a> {
Keyword::COPY => self.parse_copy(),
Keyword::TRUNCATE => self.parse_truncate(),
Keyword::NoKeyword
if w.value.to_uppercase() == tql_parser::TQL && w.quote_style.is_none() =>
{

View File

@@ -19,3 +19,4 @@ pub(crate) mod delete_parser;
pub(crate) mod insert_parser;
pub(crate) mod query_parser;
pub(crate) mod tql_parser;
pub(crate) mod truncate_parser;

View File

@@ -0,0 +1,139 @@
// Copyright 2023 Greptime Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use snafu::{ensure, ResultExt};
use sqlparser::keywords::Keyword;
use crate::error::{self, InvalidTableNameSnafu, Result};
use crate::parser::ParserContext;
use crate::statements::statement::Statement;
use crate::statements::truncate::TruncateTable;
/// TRUNCATE [TABLE] table_name;
impl<'a> ParserContext<'a> {
pub(crate) fn parse_truncate(&mut self) -> Result<Statement> {
let _ = self.parser.next_token();
let _ = self.parser.parse_keyword(Keyword::TABLE);
let table_ident =
self.parser
.parse_object_name()
.with_context(|_| error::UnexpectedSnafu {
sql: self.sql,
expected: "a table name",
actual: self.peek_token_as_string(),
})?;
ensure!(
!table_ident.0.is_empty(),
InvalidTableNameSnafu {
name: table_ident.to_string()
}
);
Ok(Statement::TruncateTable(TruncateTable::new(table_ident)))
}
}
#[cfg(test)]
mod tests {
use sqlparser::ast::{Ident, ObjectName};
use super::*;
use crate::dialect::GreptimeDbDialect;
#[test]
pub fn test_parse_truncate() {
let sql = "TRUNCATE foo";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![Ident::new("foo")])))
);
let sql = "TRUNCATE TABLE foo";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![Ident::new("foo")])))
);
let sql = "TRUNCATE TABLE my_schema.foo";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![
Ident::new("my_schema"),
Ident::new("foo")
])))
);
let sql = "TRUNCATE my_schema.foo";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![
Ident::new("my_schema"),
Ident::new("foo")
])))
);
let sql = "TRUNCATE TABLE my_catalog.my_schema.foo";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![
Ident::new("my_catalog"),
Ident::new("my_schema"),
Ident::new("foo")
])))
);
let sql = "TRUNCATE drop";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![Ident::new("drop")])))
);
let sql = "TRUNCATE `drop`";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![Ident::with_quote(
'`', "drop"
),])))
);
let sql = "TRUNCATE \"drop\"";
let mut stmts = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}).unwrap();
assert_eq!(
stmts.pop().unwrap(),
Statement::TruncateTable(TruncateTable::new(ObjectName(vec![Ident::with_quote(
'"', "drop"
),])))
);
}
#[test]
pub fn test_parse_invalid_truncate() {
let sql = "TRUNCATE SCHEMA foo";
let result = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {});
assert!(result.is_err(), "result is: {result:?}");
let sql = "TRUNCATE";
let result = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {});
assert!(result.is_err(), "result is: {result:?}");
}
}

View File

@@ -24,6 +24,7 @@ pub mod query;
pub mod show;
pub mod statement;
pub mod tql;
pub mod truncate;
use std::str::FromStr;

View File

@@ -26,6 +26,7 @@ use crate::statements::insert::Insert;
use crate::statements::query::Query;
use crate::statements::show::{ShowCreateTable, ShowDatabases, ShowTables};
use crate::statements::tql::Tql;
use crate::statements::truncate::TruncateTable;
/// Tokens parsed by `DFParser` are converted into these values.
#[allow(clippy::large_enum_variant)]
@@ -61,6 +62,8 @@ pub enum Statement {
// COPY
Copy(crate::statements::copy::Copy),
Tql(Tql),
// TRUNCATE TABLE
TruncateTable(TruncateTable),
}
/// Comment hints from SQL.

View File

@@ -0,0 +1,32 @@
// Copyright 2023 Greptime Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use sqlparser::ast::ObjectName;
/// TRUNCATE TABLE statement.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TruncateTable {
table_name: ObjectName,
}
impl TruncateTable {
/// Creates a statement for `TRUNCATE TABLE`
pub fn new(table_name: ObjectName) -> Self {
Self { table_name }
}
pub fn table_name(&self) -> &ObjectName {
&self.table_name
}
}