From a8e3e03d8b9e98a625958859510e69069b3e357d Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Mon, 13 Jul 2020 12:16:28 +0800 Subject: [PATCH] ISSUES-4006 add rewrite alter query --- .../InterpreterExternalDDLQuery.cpp | 5 ++ .../MySQL/InterpretersMySQLDDLQuery.cpp | 85 +++++++++++++++++++ .../MySQL/InterpretersMySQLDDLQuery.h | 11 +++ src/Parsers/ParserExternalDDLQuery.cpp | 4 +- 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/Interpreters/InterpreterExternalDDLQuery.cpp b/src/Interpreters/InterpreterExternalDDLQuery.cpp index 0f57d0a688b..2e9c594812b 100644 --- a/src/Interpreters/InterpreterExternalDDLQuery.cpp +++ b/src/Interpreters/InterpreterExternalDDLQuery.cpp @@ -11,6 +11,7 @@ #include #ifdef USE_MYSQL +# include # include # include #endif @@ -49,6 +50,10 @@ BlockIO InterpreterExternalDDLQuery::execute() return MySQLInterpreter::InterpreterMySQLRenameQuery( external_ddl_query.external_ddl, context, getIdentifierName(arguments[0]), getIdentifierName(arguments[1])).execute(); + else if (external_ddl_query.external_ddl->as()) + return MySQLInterpreter::InterpreterMySQLAlterQuery( + external_ddl_query.external_ddl, context, getIdentifierName(arguments[0]), + getIdentifierName(arguments[1])) .execute(); else if (external_ddl_query.external_ddl->as()) return MySQLInterpreter::InterpreterMySQLCreateQuery( external_ddl_query.external_ddl, context, getIdentifierName(arguments[0]), diff --git a/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.cpp b/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.cpp index 54f5bf8d97e..000e650317e 100644 --- a/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.cpp +++ b/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.cpp @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -338,6 +340,89 @@ ASTPtr InterpreterRenameImpl::getRewrittenQuery( return rewritten_query; } +void InterpreterAlterImpl::validate(const InterpreterAlterImpl::TQuery & /*query*/, const Context & /*context*/) +{ +} + +ASTPtr InterpreterAlterImpl::getRewrittenQuery( + const InterpreterAlterImpl::TQuery & alter_query, const Context & context, const String & clickhouse_db, const String & filter_mysql_db) +{ + const auto & database_name = context.resolveDatabase(alter_query.database); + + if (database_name != filter_mysql_db) + return {}; + + auto rewritten_query = std::make_shared(); + rewritten_query->database = clickhouse_db; + rewritten_query->table = alter_query.table; + rewritten_query->set(rewritten_query->command_list, std::make_shared()); + + for (const auto & command_query : alter_query.command_list->children) + { + const auto & alter_command = command_query->as(); + + if (alter_command->type == MySQLParser::ASTAlterCommand::ADD_COLUMN) + { + const auto & additional_columns = getColumnsList(alter_command->additional_columns); + + for (const auto & additional_column : InterpreterCreateQuery::formatColumns(additional_columns)->children) + { + auto rewritten_command = std::make_shared(); + rewritten_command->type = ASTAlterCommand::ADD_COLUMN; + rewritten_command->first = alter_command->first; + rewritten_command->col_decl = additional_column; + rewritten_command->column = std::make_shared(alter_command->column_name); + rewritten_query->command_list->add(rewritten_command); + } + } + else if (alter_command->type == MySQLParser::ASTAlterCommand::DROP_COLUMN) + { + auto rewritten_command = std::make_shared(); + rewritten_command->type = ASTAlterCommand::DROP_COLUMN; + rewritten_command->column = std::make_shared(alter_command->column_name); + rewritten_query->command_list->add(rewritten_command); + } + else if (alter_command->type == MySQLParser::ASTAlterCommand::RENAME_COLUMN) + { + auto rewritten_command = std::make_shared(); + rewritten_command->type = ASTAlterCommand::RENAME_COLUMN; + rewritten_command->column = std::make_shared(alter_command->old_name); + rewritten_command->rename_to = std::make_shared(alter_command->column_name); + rewritten_query->command_list->add(rewritten_command); + } + else if (alter_command->type == MySQLParser::ASTAlterCommand::MODIFY_COLUMN) + { + String new_column_name; + + { + auto rewritten_command = std::make_shared(); + rewritten_command->type = ASTAlterCommand::MODIFY_COLUMN; + rewritten_command->first = alter_command->first; + rewritten_command->column = std::make_shared(alter_command->column_name); + const auto & modify_columns = getColumnsList(alter_command->additional_columns); + + if (modify_columns.size() != 1) + throw Exception("It is a bug", ErrorCodes::LOGICAL_ERROR); + + new_column_name = modify_columns.front().name; + rewritten_command->col_decl = InterpreterCreateQuery::formatColumns(modify_columns)->children[0]; + rewritten_query->command_list->add(rewritten_command); + } + + if (!alter_command->old_name.empty()) + { + auto rewritten_command = std::make_shared(); + rewritten_command->type = ASTAlterCommand::RENAME_COLUMN; + rewritten_command->column = std::make_shared(alter_command->old_name); + rewritten_command->rename_to = std::make_shared(new_column_name); + rewritten_query->command_list->add(rewritten_command); + } + } + } + + return rewritten_query; +} + } } diff --git a/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.h b/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.h index b3aa8293b66..d8920194ea0 100644 --- a/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.h +++ b/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.h @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace DB @@ -23,6 +24,15 @@ struct InterpreterDropImpl static ASTPtr getRewrittenQuery(const TQuery & drop_query, const Context & context, const String & clickhouse_db, const String & filter_mysql_db); }; +struct InterpreterAlterImpl +{ + using TQuery = MySQLParser::ASTAlterQuery; + + static void validate(const TQuery & query, const Context & context); + + static ASTPtr getRewrittenQuery(const TQuery & alter_query, const Context & context, const String & clickhouse_db, const String & filter_mysql_db); +}; + struct InterpreterRenameImpl { using TQuery = ASTRenameQuery; @@ -71,6 +81,7 @@ private: }; using InterpreterMySQLDropQuery = InterpreterMySQLDDLQuery; +using InterpreterMySQLAlterQuery = InterpreterMySQLDDLQuery; using InterpreterMySQLRenameQuery = InterpreterMySQLDDLQuery; using InterpreterMySQLCreateQuery = InterpreterMySQLDDLQuery; diff --git a/src/Parsers/ParserExternalDDLQuery.cpp b/src/Parsers/ParserExternalDDLQuery.cpp index 4364b6bffa4..20020da22bd 100644 --- a/src/Parsers/ParserExternalDDLQuery.cpp +++ b/src/Parsers/ParserExternalDDLQuery.cpp @@ -10,6 +10,7 @@ #include #ifdef USE_MYSQL +# include # include #endif @@ -38,11 +39,12 @@ bool ParserExternalDDLQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expect #ifdef USE_MYSQL ParserDropQuery p_drop_query; ParserRenameQuery p_rename_query; + MySQLParser::ParserAlterQuery p_alter_query; MySQLParser::ParserCreateQuery p_create_query; - /// TODO: alter table res = p_create_query.parse(pos, external_ddl_query->external_ddl, expected) || p_drop_query.parse(pos, external_ddl_query->external_ddl, expected) + || p_alter_query.parse(pos, external_ddl_query->external_ddl, expected) || p_rename_query.parse(pos, external_ddl_query->external_ddl, expected); if (external_ddl_query->external_ddl)