Skip to content

Commit

Permalink
Merge pull request #4532 from kevinw66/alter_table_rename
Browse files Browse the repository at this point in the history
ISSUE-4459: Add support for alter table rename statement
  • Loading branch information
BohuTANG authored Mar 22, 2022
2 parents b67c9f6 + 296dca0 commit ce01c74
Show file tree
Hide file tree
Showing 17 changed files with 210 additions and 16 deletions.
6 changes: 6 additions & 0 deletions common/meta/api/src/meta_api_test_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ impl MetaApiTestSuite {
tracing::info!("--- rename table on unknown db");
{
let req = RenameTableReq {
if_exists: false,
tenant: tenant.to_string(),
db: db_name.to_string(),
table_name: tbl_name.to_string(),
Expand Down Expand Up @@ -742,6 +743,7 @@ impl MetaApiTestSuite {
tracing::info!("--- rename table, ok");
{
let req = RenameTableReq {
if_exists: false,
tenant: tenant.to_string(),
db: db_name.to_string(),
table_name: tbl_name.to_string(),
Expand Down Expand Up @@ -773,6 +775,7 @@ impl MetaApiTestSuite {
tracing::info!("--- rename table again, error");
{
let req = RenameTableReq {
if_exists: false,
tenant: tenant.to_string(),
db: db_name.to_string(),
table_name: tbl_name.to_string(),
Expand Down Expand Up @@ -808,6 +811,7 @@ impl MetaApiTestSuite {
tracing::info!("--- rename table again after recreate, error");
{
let req = RenameTableReq {
if_exists: false,
tenant: tenant.to_string(),
db: db_name.to_string(),
table_name: tbl_name.to_string(),
Expand All @@ -827,6 +831,7 @@ impl MetaApiTestSuite {
tracing::info!("--- rename table to other db, error");
{
let req = RenameTableReq {
if_exists: false,
tenant: tenant.to_string(),
db: db_name.to_string(),
table_name: tbl_name.to_string(),
Expand Down Expand Up @@ -864,6 +869,7 @@ impl MetaApiTestSuite {
tracing::info!("--- rename table to other db, ok");
{
let req = RenameTableReq {
if_exists: false,
tenant: tenant.to_string(),
db: db_name.to_string(),
table_name: tbl_name.to_string(),
Expand Down
17 changes: 13 additions & 4 deletions common/meta/raft-store/src/state_machine/sm_meta_api_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ impl MetaApi for StateMachine {
}

async fn rename_table(&self, req: RenameTableReq) -> Result<RenameTableReply, MetaError> {
let if_exists = req.if_exists;
let tenant = &req.tenant;
let db_name = &req.db;
let table_name = &req.table_name;
Expand All @@ -222,11 +223,19 @@ impl MetaApi for StateMachine {
new_db_name: new_db_name.to_string(),
new_table_name: new_table_name.to_string(),
};
let res = self.sm_tree.txn(true, |t| self.apply_cmd(&cmd, &t))?;

let mut ch: Change<TableMeta, u64> = res.try_into().unwrap();
let table_id = ch.ident.take().unwrap();
Ok(RenameTableReply { table_id })
let res = self.sm_tree.txn(true, |t| self.apply_cmd(&cmd, &t));
if let Err(MetaStorageError::AppError(AppError::UnknownTable(e))) = res {
if if_exists {
Ok(RenameTableReply { table_id: 0 })
} else {
Err(MetaError::AppError(AppError::UnknownTable(e)))
}
} else {
let mut ch: Change<TableMeta, u64> = res?.try_into().unwrap();
let table_id = ch.ident.take().unwrap();
Ok(RenameTableReply { table_id })
}
}

async fn get_table(&self, req: GetTableReq) -> Result<Arc<TableInfo>, MetaError> {
Expand Down
1 change: 1 addition & 0 deletions common/meta/types/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ pub struct DropTableReply {}

#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq)]
pub struct RenameTableReq {
pub if_exists: bool,
pub tenant: String,
pub db: String,
pub table_name: String,
Expand Down
1 change: 1 addition & 0 deletions common/planners/src/plan_table_rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub struct RenameTablePlan {

#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq)]
pub struct RenameTableEntity {
pub if_exists: bool,
pub db: String,
pub table_name: String,
pub new_db: String,
Expand Down
21 changes: 15 additions & 6 deletions metasrv/src/executor/meta_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ impl RequestHandler<DropTableReq> for ActionHandler {
#[async_trait::async_trait]
impl RequestHandler<RenameTableReq> for ActionHandler {
async fn handle(&self, req: RenameTableReq) -> Result<RenameTableReply, MetaError> {
let if_exists = req.if_exists;
let tenant = req.tenant;
let db_name = &req.db;
let table_name = &req.table_name;
Expand All @@ -241,13 +242,21 @@ impl RequestHandler<RenameTableReq> for ActionHandler {
},
};

let res = self.meta_node.write(cr).await?;
let res = self.meta_node.write(cr).await;

let mut ch: Change<TableMeta> = res
.try_into()
.map_err(|e: &str| MetaError::MetaServiceError(e.to_string()))?;
let table_id = ch.ident.take().unwrap();
Ok(RenameTableReply { table_id })
if let Err(MetaError::AppError(AppError::UnknownTable(e))) = res {
if if_exists {
Ok(RenameTableReply { table_id: 0 })
} else {
Err(MetaError::AppError(AppError::UnknownTable(e)))
}
} else {
let mut ch: Change<TableMeta> = res?
.try_into()
.map_err(|e: &str| MetaError::MetaServiceError(e.to_string()))?;
let table_id = ch.ident.take().unwrap();
Ok(RenameTableReply { table_id })
}
}
}

Expand Down
1 change: 1 addition & 0 deletions query/src/interpreters/interpreter_table_rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl Interpreter for RenameTableInterpreter {
catalog
.rename_table(RenameTableReq {
tenant,
if_exists: entity.if_exists,
db: entity.db.clone(),
table_name: entity.table_name.clone(),
new_db: entity.new_db.clone(),
Expand Down
24 changes: 24 additions & 0 deletions query/src/sql/parsers/parser_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use sqlparser::tokenizer::Token;
use sqlparser::tokenizer::Word;

use crate::parser_err;
use crate::sql::statements::AlterTableAction;
use crate::sql::statements::DfAlterTable;
use crate::sql::statements::DfCreateTable;
use crate::sql::statements::DfDescribeTable;
use crate::sql::statements::DfDropTable;
Expand Down Expand Up @@ -100,6 +102,28 @@ impl<'a> DfParser<'a> {
Ok(DfStatement::DropTable(drop))
}

// Alter table
pub(crate) fn parse_alter_table(&mut self) -> Result<DfStatement, ParserError> {
let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let table_name = self.parser.parse_object_name()?;

if self.parser.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
let new_table_name = self.parser.parse_object_name()?;

let rename = DfAlterTable {
if_exists,
table_name,
action: AlterTableAction::RenameTable(new_table_name),
};

Ok(DfStatement::AlterTable(rename))
} else {
Err(ParserError::ParserError(String::from(
"Alter table only support rename for now!",
)))
}
}

// Rename table.
pub(crate) fn parse_rename_table(&mut self) -> Result<DfStatement, ParserError> {
let mut name_map = HashMap::new();
Expand Down
1 change: 1 addition & 0 deletions query/src/sql/sql_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ impl<'a> DfParser<'a> {
Token::Word(w) => match w.keyword {
Keyword::USER => self.parse_alter_user(),
Keyword::FUNCTION => self.parse_alter_udf(),
Keyword::TABLE => self.parse_alter_table(),
_ => self.expected("keyword USER or FUNCTION", Token::Word(w)),
},
unexpected => self.expected("alter statement", unexpected),
Expand Down
2 changes: 2 additions & 0 deletions query/src/sql/sql_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use super::statements::DfDropUserStage;
use super::statements::DfGrantRoleStatement;
use super::statements::DfList;
use super::statements::DfRevokeRoleStatement;
use crate::sql::statements::DfAlterTable;
use crate::sql::statements::DfAlterUDF;
use crate::sql::statements::DfAlterUser;
use crate::sql::statements::DfCreateDatabase;
Expand Down Expand Up @@ -86,6 +87,7 @@ pub enum DfStatement {
CreateTable(DfCreateTable),
DescribeTable(DfDescribeTable),
DropTable(DfDropTable),
AlterTable(DfAlterTable),
TruncateTable(DfTruncateTable),
OptimizeTable(DfOptimizeTable),
RenameTable(DfRenameTable),
Expand Down
1 change: 1 addition & 0 deletions query/src/sql/statements/analyzer_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ impl AnalyzableStatement for DfStatement {
DfStatement::CreateTable(v) => v.analyze(ctx).await,
DfStatement::DescribeTable(v) => v.analyze(ctx).await,
DfStatement::DropTable(v) => v.analyze(ctx).await,
DfStatement::AlterTable(v) => v.analyze(ctx).await,
DfStatement::RenameTable(v) => v.analyze(ctx).await,
DfStatement::TruncateTable(v) => v.analyze(ctx).await,
DfStatement::OptimizeTable(v) => v.analyze(ctx).await,
Expand Down
3 changes: 3 additions & 0 deletions query/src/sql/statements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod query;
mod analyzer_expr;
mod analyzer_statement;
mod analyzer_value_expr;
mod statement_alter_table;
mod statement_alter_udf;
mod statement_alter_user;
mod statement_call;
Expand Down Expand Up @@ -69,6 +70,8 @@ pub use analyzer_statement::AnalyzedResult;
pub use analyzer_statement::QueryAnalyzeState;
pub use analyzer_statement::QueryRelation;
pub use query::QueryASTIR;
pub use statement_alter_table::AlterTableAction;
pub use statement_alter_table::DfAlterTable;
pub use statement_alter_udf::DfAlterUDF;
pub use statement_alter_user::DfAlterUser;
pub use statement_call::DfCall;
Expand Down
85 changes: 85 additions & 0 deletions query/src/sql/statements/statement_alter_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2021 Datafuse Labs.
//
// 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 std::sync::Arc;

use common_exception::ErrorCode;
use common_exception::Result;
use common_planners::PlanNode;
use common_planners::RenameTableEntity;
use common_planners::RenameTablePlan;
use common_tracing::tracing;
use sqlparser::ast::ObjectName;

use crate::sessions::QueryContext;
use crate::sql::statements::AnalyzableStatement;
use crate::sql::statements::AnalyzedResult;

#[derive(Debug, Clone, PartialEq)]
pub struct DfAlterTable {
pub if_exists: bool,
pub table_name: ObjectName,
pub action: AlterTableAction,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AlterTableAction {
RenameTable(ObjectName),
// TODO AddColumn etc.
}

#[async_trait::async_trait]
impl AnalyzableStatement for DfAlterTable {
#[tracing::instrument(level = "debug", skip(self, ctx), fields(ctx.id = ctx.get_id().as_str()))]
async fn analyze(&self, ctx: Arc<QueryContext>) -> Result<AnalyzedResult> {
let tenant = ctx.get_tenant();
let (db, table_name) = self.resolve_table(ctx.clone(), &self.table_name)?;

match &self.action {
AlterTableAction::RenameTable(o) => {
let mut entities = Vec::new();
let (new_db, new_table_name) = self.resolve_table(ctx, o)?;
entities.push(RenameTableEntity {
if_exists: self.if_exists,
db,
table_name,
new_db,
new_table_name,
});

Ok(AnalyzedResult::SimpleQuery(Box::new(
PlanNode::RenameTable(RenameTablePlan { tenant, entities }),
)))
}
}
}
}

impl DfAlterTable {
fn resolve_table(
&self,
ctx: Arc<QueryContext>,
table_name: &ObjectName,
) -> Result<(String, String)> {
let idents = &table_name.0;
match idents.len() {
0 => Err(ErrorCode::SyntaxException("Alter table name is empty")),
1 => Ok((ctx.get_current_database(), idents[0].value.clone())),
2 => Ok((idents[0].value.clone(), idents[1].value.clone())),
_ => Err(ErrorCode::SyntaxException(
"Alter table name must be [`db`].`table`",
)),
}
}
}
1 change: 1 addition & 0 deletions query/src/sql/statements/statement_rename_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl AnalyzableStatement for DfRenameTable {
let (db, table_name) = self.resolve_table(ctx.clone(), k)?;
let (new_db, new_table_name) = self.resolve_table(ctx.clone(), v)?;
entities.push(RenameTableEntity {
if_exists: false,
db,
table_name,
new_db,
Expand Down
20 changes: 20 additions & 0 deletions query/tests/it/sql/parsers/parser_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use std::collections::HashMap;

use common_exception::Result;
use databend_query::sql::statements::AlterTableAction;
use databend_query::sql::statements::DfAlterTable;
use databend_query::sql::statements::DfCreateTable;
use databend_query::sql::statements::DfDescribeTable;
use databend_query::sql::statements::DfDropTable;
Expand Down Expand Up @@ -191,6 +193,24 @@ fn drop_table() -> Result<()> {
Ok(())
}

#[test]
fn alter_table() -> Result<()> {
// alter table rename
{
let sql = "ALTER TABLE t1 RENAME TO t2";
let table_name = ObjectName(vec![Ident::new("t1")]);
let new_table_name = ObjectName(vec![Ident::new("t2")]);
let expected = DfStatement::AlterTable(DfAlterTable {
if_exists: false,
table_name,
action: AlterTableAction::RenameTable(new_table_name),
});
expect_parse_ok(sql, expected)?;
}

Ok(())
}

#[test]
fn rename_table() -> Result<()> {
{
Expand Down
24 changes: 18 additions & 6 deletions query/tests/it/sql/plan_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ async fn test_plan_parser() -> Result<()> {
expect: "Drop table db1.t1, if_exists:false",
error: "",
},
Test {
name: "drop-table-if-exists-passed",
sql: "DROP TABLE IF EXISTS db1.t1",
expect: "Drop table db1.t1, if_exists:true",
error: "",
},
Test {
name: "alter-table-rename-table-passed",
sql: "ALTER TABLE t1 RENAME TO t2",
expect: "Rename table, [default.t1 to default.t2]",
error: "",
},
Test {
name: "alter-table-rename-table-passed",
sql: "ALTER TABLE db1.t1 RENAME TO db1.t2",
expect: "Rename table, [db1.t1 to db1.t2]",
error: "",
},
Test {
name: "rename-table-passed",
sql: "RENAME TABLE t1 TO t2",
Expand All @@ -99,12 +117,6 @@ async fn test_plan_parser() -> Result<()> {
expect: "Rename table, [db1.t1 to db1.t2]",
error: "",
},
Test {
name: "drop-table-if-exists-passed",
sql: "DROP TABLE IF EXISTS db1.t1",
expect: "Drop table db1.t1, if_exists:true",
error: "",
},
Test {
name: "describe-table-passed",
sql: "DESCRIBE t1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1
1
Loading

0 comments on commit ce01c74

Please sign in to comment.