diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index f2b9dfd9508..5e429c6ce06 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -702,9 +702,8 @@ void Context::checkDatabaseAccessRightsImpl(const std::string & database_name) c throw Exception("Access denied to database " + database_name + " for user " + client_info.current_user , ErrorCodes::DATABASE_ACCESS_DENIED); } -void Context::addDependency(const DatabaseAndTableName & from, const DatabaseAndTableName & where) +void Context::addDependencyUnsafe(const DatabaseAndTableName & from, const DatabaseAndTableName & where) { - auto lock = getLock(); checkDatabaseAccessRightsImpl(from.first); checkDatabaseAccessRightsImpl(where.first); shared->view_dependencies[from].insert(where); @@ -715,9 +714,14 @@ void Context::addDependency(const DatabaseAndTableName & from, const DatabaseAnd table->updateDependencies(); } -void Context::removeDependency(const DatabaseAndTableName & from, const DatabaseAndTableName & where) +void Context::addDependency(const DatabaseAndTableName & from, const DatabaseAndTableName & where) { auto lock = getLock(); + addDependencyUnsafe(from, where); +} + +void Context::removeDependencyUnsafe(const DatabaseAndTableName & from, const DatabaseAndTableName & where) +{ checkDatabaseAccessRightsImpl(from.first); checkDatabaseAccessRightsImpl(where.first); shared->view_dependencies[from].erase(where); @@ -728,6 +732,12 @@ void Context::removeDependency(const DatabaseAndTableName & from, const Database table->updateDependencies(); } +void Context::removeDependency(const DatabaseAndTableName & from, const DatabaseAndTableName & where) +{ + auto lock = getLock(); + removeDependencyUnsafe(from, where); +} + Dependencies Context::getDependencies(const String & database_name, const String & table_name) const { auto lock = getLock(); diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index 3bfd7d06d3b..d590bb41c4c 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -215,6 +215,10 @@ public: void removeDependency(const DatabaseAndTableName & from, const DatabaseAndTableName & where); Dependencies getDependencies(const String & database_name, const String & table_name) const; + /// Functions where we can lock the context manually + void addDependencyUnsafe(const DatabaseAndTableName & from, const DatabaseAndTableName & where); + void removeDependencyUnsafe(const DatabaseAndTableName & from, const DatabaseAndTableName & where); + /// Checking the existence of the table/database. Database can be empty - in this case the current database is used. bool isTableExist(const String & database_name, const String & table_name) const; bool isDatabaseExist(const String & database_name) const; diff --git a/dbms/src/Storages/StorageMaterializedView.cpp b/dbms/src/Storages/StorageMaterializedView.cpp index d367309e825..93c42473d46 100644 --- a/dbms/src/Storages/StorageMaterializedView.cpp +++ b/dbms/src/Storages/StorageMaterializedView.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,10 @@ namespace ErrorCodes extern const int QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW; } +static inline String generateInnerTableName(const String & table_name) +{ + return ".inner." + table_name; +} static void extractDependentTable(ASTSelectQuery & query, String & select_database_name, String & select_table_name) { @@ -128,7 +133,7 @@ StorageMaterializedView::StorageMaterializedView( else { target_database_name = database_name; - target_table_name = ".inner." + table_name; + target_table_name = generateInnerTableName(table_name); has_inner_table = true; } @@ -265,6 +270,53 @@ void StorageMaterializedView::mutate(const MutationCommands & commands, const Co getTargetTable()->mutate(commands, context); } +static void executeRenameQuery(Context & global_context, const String & database_name, const String & table_original_name, const String & new_table_name) +{ + if (global_context.tryGetTable(database_name, table_original_name)) + { + auto rename = std::make_shared(); + + ASTRenameQuery::Table from; + from.database = database_name; + from.table = table_original_name; + + ASTRenameQuery::Table to; + to.database = database_name; + to.table = new_table_name; + + ASTRenameQuery::Element elem; + elem.from = from; + elem.to = to; + + rename->elements.emplace_back(elem); + + InterpreterRenameQuery(rename, global_context).execute(); + } +} + + +void StorageMaterializedView::rename(const String & /*new_path_to_db*/, const String & /*new_database_name*/, const String & new_table_name) +{ + if (has_inner_table && tryGetTargetTable()) + { + String new_target_table_name = generateInnerTableName(new_table_name); + executeRenameQuery(global_context, target_database_name, target_table_name, new_target_table_name); + target_table_name = new_target_table_name; + } + + auto lock = global_context.getLock(); + + global_context.removeDependencyUnsafe( + DatabaseAndTableName(select_database_name, select_table_name), + DatabaseAndTableName(database_name, table_name)); + + table_name = new_table_name; + + global_context.addDependencyUnsafe( + DatabaseAndTableName(select_database_name, select_table_name), + DatabaseAndTableName(database_name, table_name)); +} + void StorageMaterializedView::shutdown() { /// Make sure the dependency is removed after DETACH TABLE diff --git a/dbms/src/Storages/StorageMaterializedView.h b/dbms/src/Storages/StorageMaterializedView.h index 665f6243a32..8214875528d 100644 --- a/dbms/src/Storages/StorageMaterializedView.h +++ b/dbms/src/Storages/StorageMaterializedView.h @@ -39,6 +39,8 @@ public: void mutate(const MutationCommands & commands, const Context & context) override; + void rename(const String & new_path_to_db, const String & new_database_name, const String & new_table_name) override; + void shutdown() override; void checkTableCanBeDropped() const override; diff --git a/dbms/tests/queries/0_stateless/00942_mv_rename_table.reference b/dbms/tests/queries/0_stateless/00942_mv_rename_table.reference new file mode 100644 index 00000000000..2c9d316b3d6 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00942_mv_rename_table.reference @@ -0,0 +1,6 @@ +1 +2 +3 +1 +2 +3 diff --git a/dbms/tests/queries/0_stateless/00942_mv_rename_table.sql b/dbms/tests/queries/0_stateless/00942_mv_rename_table.sql new file mode 100644 index 00000000000..372996438b6 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00942_mv_rename_table.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS test.src; +DROP TABLE IF EXISTS test.view_table; +DROP TABLE IF EXISTS test.new_view_table; + +CREATE TABLE test.src (x UInt8) ENGINE = Null; + +USE test; + +CREATE MATERIALIZED VIEW test.view_table Engine = Memory AS SELECT * FROM test.src; + +INSERT INTO test.src VALUES (1), (2), (3); +SELECT * FROM test.view_table ORDER BY x; + +--Check if we can rename the view and if we can still fetch datas + +RENAME TABLE test.view_table TO test.new_view_table; +SELECT * FROM test.new_view_table ORDER BY x; + +DROP TABLE test.src; +DROP TABLE IF EXISTS test.view_table; +DROP TABLE IF EXISTS test.new_view_table; diff --git a/dbms/tests/queries/0_stateless/00943_mv_rename_without_inner_table.reference b/dbms/tests/queries/0_stateless/00943_mv_rename_without_inner_table.reference new file mode 100644 index 00000000000..c7ac27ddfbe --- /dev/null +++ b/dbms/tests/queries/0_stateless/00943_mv_rename_without_inner_table.reference @@ -0,0 +1,8 @@ +1 +2 +1 +2 +3 +1 +2 +3 diff --git a/dbms/tests/queries/0_stateless/00943_mv_rename_without_inner_table.sql b/dbms/tests/queries/0_stateless/00943_mv_rename_without_inner_table.sql new file mode 100644 index 00000000000..2edcd07dca4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00943_mv_rename_without_inner_table.sql @@ -0,0 +1,26 @@ +DROP TABLE IF EXISTS test.src; +DROP TABLE IF EXISTS test.dst; +DROP TABLE IF EXISTS test.original_mv; +DROP TABLE IF EXISTS test.new_mv; + +CREATE TABLE test.src (x UInt8) ENGINE = Null; +CREATE TABLE test.dst (x UInt8) ENGINE = Memory; + +USE test; + +CREATE MATERIALIZED VIEW test.original_mv TO dst AS SELECT * FROM src; + +INSERT INTO src VALUES (1), (2); +SELECT * FROM test.original_mv ORDER BY x; + +RENAME TABLE test.original_mv TO test.new_mv; + +INSERT INTO src VALUES (3); +SELECT * FROM dst ORDER BY x; + +SELECT * FROM test.new_mv ORDER BY x; + +DROP TABLE IF EXISTS test.src; +DROP TABLE IF EXISTS test.dst; +DROP TABLE IF EXISTS test.original_mv; +DROP TABLE IF EXISTS test.new_mv;