ClickHouse/src/Interpreters/InterpreterAlterQuery.cpp

398 lines
16 KiB
C++
Raw Normal View History

#include <Interpreters/InterpreterAlterQuery.h>
#include <Access/AccessRightsElement.h>
#include <Databases/DatabaseFactory.h>
#include <Databases/DatabaseReplicated.h>
#include <Databases/IDatabase.h>
#include <Interpreters/AddDefaultDatabaseVisitor.h>
2018-12-25 23:11:36 +00:00
#include <Interpreters/Context.h>
#include <Interpreters/MutationsInterpreter.h>
2020-12-14 03:30:39 +00:00
#include <Interpreters/QueryLog.h>
#include <Interpreters/executeDDLQueryOnCluster.h>
#include <Parsers/ASTAlterQuery.h>
2020-01-24 16:20:36 +00:00
#include <Parsers/ASTAssignment.h>
2018-12-25 23:11:36 +00:00
#include <Storages/AlterCommands.h>
#include <Storages/IStorage.h>
2019-08-22 23:22:57 +00:00
#include <Storages/LiveView/LiveViewCommands.h>
#include <Storages/LiveView/StorageLiveView.h>
#include <Storages/MutationCommands.h>
#include <Storages/PartitionCommands.h>
#include <Common/typeid_cast.h>
#include <boost/range/algorithm_ext/push_back.hpp>
2013-08-07 13:07:42 +00:00
#include <algorithm>
2013-08-09 00:12:59 +00:00
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
2020-01-22 13:24:20 +00:00
extern const int INCORRECT_QUERY;
2021-02-08 19:36:17 +00:00
extern const int NOT_IMPLEMENTED;
}
2013-09-23 12:01:19 +00:00
InterpreterAlterQuery::InterpreterAlterQuery(const ASTPtr & query_ptr_, ContextPtr context_) : WithContext(context_), query_ptr(query_ptr_)
2013-08-07 13:07:42 +00:00
{
}
2015-06-18 02:11:05 +00:00
BlockIO InterpreterAlterQuery::execute()
{
2020-07-28 15:10:36 +00:00
BlockIO res;
const auto & alter = query_ptr->as<ASTAlterQuery &>();
2017-04-25 15:21:03 +00:00
2020-05-11 12:55:17 +00:00
if (!alter.cluster.empty())
return executeDDLQueryOnCluster(query_ptr, getContext(), getRequiredAccess());
2020-01-24 16:20:36 +00:00
getContext()->checkAccess(getRequiredAccess());
auto table_id = getContext()->resolveStorageID(alter, Context::ResolveOrdinary);
2021-03-16 22:50:37 +00:00
query_ptr->as<ASTAlterQuery &>().database = table_id.database_name;
2020-05-11 12:55:17 +00:00
DatabasePtr database = DatabaseCatalog::instance().getDatabase(table_id.database_name);
if (typeid_cast<DatabaseReplicated *>(database.get())
2021-07-30 16:34:18 +00:00
&& !getContext()->getClientInfo().is_replicated_database_internal)
{
2021-02-02 19:39:04 +00:00
auto guard = DatabaseCatalog::instance().getDDLGuard(table_id.database_name, table_id.table_name);
guard->releaseTableLock();
return typeid_cast<DatabaseReplicated *>(database.get())->tryEnqueueReplicatedDDL(query_ptr, getContext());
}
2020-05-11 12:55:17 +00:00
StoragePtr table = DatabaseCatalog::instance().getTable(table_id, getContext());
auto alter_lock = table->lockForAlter(getContext()->getCurrentQueryId(), getContext()->getSettingsRef().lock_acquire_timeout);
2021-02-02 19:39:04 +00:00
auto metadata_snapshot = table->getInMemoryMetadataPtr();
2021-04-14 15:35:52 +00:00
/// Add default database to table identifiers that we can encounter in e.g. default expressions, mutation expression, etc.
2020-02-17 19:28:25 +00:00
AddDefaultDatabaseVisitor visitor(table_id.getDatabaseName());
ASTPtr command_list_ptr = alter.command_list->ptr();
visitor.visit(command_list_ptr);
AlterCommands alter_commands;
PartitionCommands partition_commands;
MutationCommands mutation_commands;
LiveViewCommands live_view_commands;
for (const auto & child : alter.command_list->children)
{
auto * command_ast = child->as<ASTAlterCommand>();
if (auto alter_command = AlterCommand::parse(command_ast))
alter_commands.emplace_back(std::move(*alter_command));
else if (auto partition_command = PartitionCommand::parse(command_ast))
2019-07-22 11:23:11 +00:00
{
partition_commands.emplace_back(std::move(*partition_command));
2019-07-22 11:23:11 +00:00
}
else if (auto mut_command = MutationCommand::parse(command_ast))
2020-01-22 13:24:20 +00:00
{
2020-06-17 13:39:26 +00:00
if (mut_command->type == MutationCommand::MATERIALIZE_TTL && !metadata_snapshot->hasAnyTTL())
2020-01-22 13:24:20 +00:00
throw Exception("Cannot MATERIALIZE TTL as there is no TTL set for table "
+ table->getStorageID().getNameForLogs(), ErrorCodes::INCORRECT_QUERY);
mutation_commands.emplace_back(std::move(*mut_command));
2020-01-22 13:24:20 +00:00
}
else if (auto live_view_command = LiveViewCommand::parse(command_ast))
live_view_commands.emplace_back(std::move(*live_view_command));
else
throw Exception("Wrong parameter type in ALTER query", ErrorCodes::LOGICAL_ERROR);
}
2021-02-08 19:36:17 +00:00
if (typeid_cast<DatabaseReplicated *>(database.get()))
{
int command_types_count = !mutation_commands.empty() + !partition_commands.empty() + !live_view_commands.empty() + !alter_commands.empty();
2021-07-30 16:34:18 +00:00
bool mixed_settings_amd_metadata_alter = alter_commands.hasSettingsAlterCommand() && !alter_commands.isSettingsAlter();
if (1 < command_types_count || mixed_settings_amd_metadata_alter)
2021-02-08 19:36:17 +00:00
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "For Replicated databases it's not allowed "
"to execute ALTERs of different types in single query");
}
if (!mutation_commands.empty())
{
table->checkMutationIsPossible(mutation_commands, getContext()->getSettingsRef());
MutationsInterpreter(table, metadata_snapshot, mutation_commands, getContext(), false).validate();
table->mutate(mutation_commands, getContext());
}
if (!partition_commands.empty())
{
table->checkAlterPartitionIsPossible(partition_commands, metadata_snapshot, getContext()->getSettingsRef());
auto partition_commands_pipe = table->alterPartition(metadata_snapshot, partition_commands, getContext());
2020-08-04 15:51:56 +00:00
if (!partition_commands_pipe.empty())
2020-08-06 12:24:05 +00:00
res.pipeline.init(std::move(partition_commands_pipe));
}
if (!live_view_commands.empty())
{
2019-06-10 11:41:33 +00:00
live_view_commands.validate(*table);
for (const LiveViewCommand & command : live_view_commands)
2019-06-10 11:41:33 +00:00
{
auto live_view = std::dynamic_pointer_cast<StorageLiveView>(table);
switch (command.type)
{
case LiveViewCommand::REFRESH:
live_view->refresh();
2019-06-10 11:41:33 +00:00
break;
}
2019-06-10 11:41:33 +00:00
}
}
if (!alter_commands.empty())
{
2019-12-26 18:17:05 +00:00
StorageInMemoryMetadata metadata = table->getInMemoryMetadata();
alter_commands.validate(metadata, getContext());
alter_commands.prepare(metadata);
table->checkAlterIsPossible(alter_commands, getContext());
table->alter(alter_commands, getContext(), alter_lock);
}
2020-07-28 15:10:36 +00:00
return res;
}
2020-01-24 16:20:36 +00:00
AccessRightsElements InterpreterAlterQuery::getRequiredAccess() const
{
AccessRightsElements required_access;
const auto & alter = query_ptr->as<ASTAlterQuery &>();
for (const auto & child : alter.command_list->children)
boost::range::push_back(required_access, getRequiredAccessForCommand(child->as<ASTAlterCommand&>(), alter.database, alter.table));
return required_access;
}
AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const ASTAlterCommand & command, const String & database, const String & table)
{
AccessRightsElements required_access;
auto column_name = [&]() -> String { return getIdentifierName(command.column); };
auto column_name_from_col_decl = [&]() -> std::string_view { return command.col_decl->as<ASTColumnDeclaration &>().name; };
auto column_names_from_update_assignments = [&]() -> std::vector<std::string_view>
2020-01-24 16:20:36 +00:00
{
std::vector<std::string_view> column_names;
for (const ASTPtr & assignment_ast : command.update_assignments->children)
column_names.emplace_back(assignment_ast->as<const ASTAssignment &>().column_name);
return column_names;
};
2020-01-24 16:20:36 +00:00
switch (command.type)
{
case ASTAlterCommand::UPDATE:
2020-01-24 16:20:36 +00:00
{
required_access.emplace_back(AccessType::ALTER_UPDATE, database, table, column_names_from_update_assignments());
break;
}
case ASTAlterCommand::ADD_COLUMN:
{
required_access.emplace_back(AccessType::ALTER_ADD_COLUMN, database, table, column_name_from_col_decl());
break;
}
case ASTAlterCommand::DROP_COLUMN:
{
if (command.clear_column)
required_access.emplace_back(AccessType::ALTER_CLEAR_COLUMN, database, table, column_name());
else
required_access.emplace_back(AccessType::ALTER_DROP_COLUMN, database, table, column_name());
break;
}
case ASTAlterCommand::MODIFY_COLUMN:
{
required_access.emplace_back(AccessType::ALTER_MODIFY_COLUMN, database, table, column_name_from_col_decl());
break;
}
case ASTAlterCommand::COMMENT_COLUMN:
{
required_access.emplace_back(AccessType::ALTER_COMMENT_COLUMN, database, table, column_name());
break;
}
case ASTAlterCommand::MODIFY_ORDER_BY:
{
required_access.emplace_back(AccessType::ALTER_ORDER_BY, database, table);
break;
}
2020-08-27 13:10:10 +00:00
case ASTAlterCommand::MODIFY_SAMPLE_BY:
{
required_access.emplace_back(AccessType::ALTER_SAMPLE_BY, database, table);
break;
}
case ASTAlterCommand::ADD_INDEX:
{
required_access.emplace_back(AccessType::ALTER_ADD_INDEX, database, table);
break;
}
case ASTAlterCommand::DROP_INDEX:
{
if (command.clear_index)
required_access.emplace_back(AccessType::ALTER_CLEAR_INDEX, database, table);
else
required_access.emplace_back(AccessType::ALTER_DROP_INDEX, database, table);
break;
}
case ASTAlterCommand::MATERIALIZE_INDEX:
{
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_INDEX, database, table);
break;
}
case ASTAlterCommand::ADD_CONSTRAINT:
{
required_access.emplace_back(AccessType::ALTER_ADD_CONSTRAINT, database, table);
break;
}
case ASTAlterCommand::DROP_CONSTRAINT:
{
required_access.emplace_back(AccessType::ALTER_DROP_CONSTRAINT, database, table);
break;
}
case ASTAlterCommand::ADD_PROJECTION:
{
required_access.emplace_back(AccessType::ALTER_ADD_PROJECTION, database, table);
break;
}
case ASTAlterCommand::DROP_PROJECTION:
{
if (command.clear_projection)
required_access.emplace_back(AccessType::ALTER_CLEAR_PROJECTION, database, table);
else
required_access.emplace_back(AccessType::ALTER_DROP_PROJECTION, database, table);
break;
}
case ASTAlterCommand::MATERIALIZE_PROJECTION:
{
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_PROJECTION, database, table);
break;
}
case ASTAlterCommand::MODIFY_TTL:
case ASTAlterCommand::REMOVE_TTL:
{
required_access.emplace_back(AccessType::ALTER_TTL, database, table);
break;
}
case ASTAlterCommand::MATERIALIZE_TTL:
{
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_TTL, database, table);
break;
}
case ASTAlterCommand::RESET_SETTING: [[fallthrough]];
case ASTAlterCommand::MODIFY_SETTING:
{
required_access.emplace_back(AccessType::ALTER_SETTINGS, database, table);
break;
}
case ASTAlterCommand::ATTACH_PARTITION:
{
required_access.emplace_back(AccessType::INSERT, database, table);
break;
}
2021-04-22 19:50:48 +00:00
case ASTAlterCommand::DELETE:
case ASTAlterCommand::DROP_PARTITION:
case ASTAlterCommand::DROP_DETACHED_PARTITION:
{
required_access.emplace_back(AccessType::ALTER_DELETE, database, table);
break;
}
case ASTAlterCommand::MOVE_PARTITION:
{
switch (command.move_destination_type)
2020-01-24 16:20:36 +00:00
{
case DataDestinationType::DISK: [[fallthrough]];
case DataDestinationType::VOLUME:
required_access.emplace_back(AccessType::ALTER_MOVE_PARTITION, database, table);
break;
case DataDestinationType::TABLE:
required_access.emplace_back(AccessType::SELECT | AccessType::ALTER_DELETE, database, table);
required_access.emplace_back(AccessType::INSERT, command.to_database, command.to_table);
break;
case DataDestinationType::SHARD:
required_access.emplace_back(AccessType::SELECT | AccessType::ALTER_DELETE, database, table);
required_access.emplace_back(AccessType::MOVE_PARTITION_BETWEEN_SHARDS);
break;
case DataDestinationType::DELETE:
throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected destination type for command.");
2020-01-24 16:20:36 +00:00
}
break;
}
case ASTAlterCommand::REPLACE_PARTITION:
{
required_access.emplace_back(AccessType::SELECT, command.from_database, command.from_table);
required_access.emplace_back(AccessType::ALTER_DELETE | AccessType::INSERT, database, table);
break;
}
case ASTAlterCommand::FETCH_PARTITION:
{
required_access.emplace_back(AccessType::ALTER_FETCH_PARTITION, database, table);
break;
}
case ASTAlterCommand::FREEZE_PARTITION: [[fallthrough]];
2021-02-24 14:26:46 +00:00
case ASTAlterCommand::FREEZE_ALL: [[fallthrough]];
2021-03-02 21:10:09 +00:00
case ASTAlterCommand::UNFREEZE_PARTITION: [[fallthrough]];
case ASTAlterCommand::UNFREEZE_ALL:
{
required_access.emplace_back(AccessType::ALTER_FREEZE_PARTITION, database, table);
break;
}
case ASTAlterCommand::MODIFY_QUERY:
{
required_access.emplace_back(AccessType::ALTER_VIEW_MODIFY_QUERY, database, table);
break;
}
case ASTAlterCommand::LIVE_VIEW_REFRESH:
{
required_access.emplace_back(AccessType::ALTER_VIEW_REFRESH, database, table);
break;
2020-01-24 16:20:36 +00:00
}
2020-03-24 17:05:38 +00:00
case ASTAlterCommand::RENAME_COLUMN:
{
required_access.emplace_back(AccessType::ALTER_RENAME_COLUMN, database, table, column_name());
break;
2020-01-24 16:20:36 +00:00
}
case ASTAlterCommand::NO_TYPE: break;
2020-01-24 16:20:36 +00:00
}
return required_access;
}
void InterpreterAlterQuery::extendQueryLogElemImpl(QueryLogElement & elem, const ASTPtr & ast, ContextPtr) const
2020-12-14 03:30:39 +00:00
{
const auto & alter = ast->as<const ASTAlterQuery &>();
elem.query_kind = "Alter";
if (alter.command_list != nullptr)
{
// Alter queries already have their target table inserted into `elem`.
if (elem.query_tables.size() != 1)
throw Exception("Alter query should have target table recorded already", ErrorCodes::LOGICAL_ERROR);
String prefix = *elem.query_tables.begin() + ".";
for (const auto & child : alter.command_list->children)
{
const auto * command = child->as<ASTAlterCommand>();
if (command->column)
elem.query_columns.insert(prefix + command->column->getColumnName());
if (command->rename_to)
elem.query_columns.insert(prefix + command->rename_to->getColumnName());
// ADD COLUMN
if (command->col_decl)
{
elem.query_columns.insert(prefix + command->col_decl->as<ASTColumnDeclaration &>().name);
}
if (!command->from_table.empty())
{
String database = command->from_database.empty() ? getContext()->getCurrentDatabase() : command->from_database;
2020-12-14 03:30:39 +00:00
elem.query_databases.insert(database);
elem.query_tables.insert(database + "." + command->from_table);
}
if (!command->to_table.empty())
{
String database = command->to_database.empty() ? getContext()->getCurrentDatabase() : command->to_database;
2020-12-14 03:30:39 +00:00
elem.query_databases.insert(database);
elem.query_tables.insert(database + "." + command->to_table);
}
}
}
}
}