2020-01-13 16:39:20 +00:00
|
|
|
#include <Compression/CompressionFactory.h>
|
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/DataTypeDate.h>
|
|
|
|
#include <DataTypes/DataTypeDateTime.h>
|
|
|
|
#include <DataTypes/DataTypeEnum.h>
|
2018-06-13 13:49:27 +00:00
|
|
|
#include <DataTypes/DataTypeFactory.h>
|
2020-01-13 16:39:20 +00:00
|
|
|
#include <DataTypes/DataTypeNullable.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2017-12-25 18:58:39 +00:00
|
|
|
#include <DataTypes/NestedUtils.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Interpreters/Context.h>
|
|
|
|
#include <Interpreters/ExpressionActions.h>
|
2020-03-03 10:02:43 +00:00
|
|
|
#include <Interpreters/addTypeConversionToAST.h>
|
2020-01-13 16:39:20 +00:00
|
|
|
#include <Interpreters/ExpressionAnalyzer.h>
|
2020-07-22 17:13:05 +00:00
|
|
|
#include <Interpreters/TreeRewriter.h>
|
2020-04-02 16:11:10 +00:00
|
|
|
#include <Interpreters/RenameColumnVisitor.h>
|
2020-02-19 12:52:27 +00:00
|
|
|
#include <Parsers/ASTAlterQuery.h>
|
|
|
|
#include <Parsers/ASTColumnDeclaration.h>
|
|
|
|
#include <Parsers/ASTConstraintDeclaration.h>
|
|
|
|
#include <Parsers/ASTExpressionList.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/ASTIdentifier.h>
|
2019-02-05 14:50:25 +00:00
|
|
|
#include <Parsers/ASTIndexDeclaration.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/ASTLiteral.h>
|
2019-07-24 12:56:39 +00:00
|
|
|
#include <Parsers/ASTSetQuery.h>
|
2020-11-02 18:37:23 +00:00
|
|
|
#include <Parsers/queryToString.h>
|
2020-01-13 16:39:20 +00:00
|
|
|
#include <Storages/AlterCommands.h>
|
|
|
|
#include <Storages/IStorage.h>
|
2018-06-13 13:49:27 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
2020-11-02 18:37:23 +00:00
|
|
|
#include <Common/randomSeed.h>
|
2019-04-15 09:30:45 +00:00
|
|
|
|
2015-10-20 16:22:08 +00:00
|
|
|
|
2014-10-16 13:37:01 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
2016-01-11 21:46:36 +00:00
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int ILLEGAL_COLUMN;
|
2018-11-13 12:51:55 +00:00
|
|
|
extern const int BAD_ARGUMENTS;
|
2020-02-20 10:04:15 +00:00
|
|
|
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2020-02-20 10:04:15 +00:00
|
|
|
extern const int DUPLICATE_COLUMN;
|
2020-03-31 16:18:18 +00:00
|
|
|
extern const int NOT_IMPLEMENTED;
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
AlterCommand::RemoveProperty removePropertyFromString(const String & property)
|
|
|
|
{
|
|
|
|
if (property.empty())
|
|
|
|
return AlterCommand::RemoveProperty::NO_PROPERTY;
|
|
|
|
else if (property == "DEFAULT")
|
|
|
|
return AlterCommand::RemoveProperty::DEFAULT;
|
|
|
|
else if (property == "MATERIALIZED")
|
|
|
|
return AlterCommand::RemoveProperty::MATERIALIZED;
|
|
|
|
else if (property == "ALIAS")
|
|
|
|
return AlterCommand::RemoveProperty::ALIAS;
|
|
|
|
else if (property == "COMMENT")
|
|
|
|
return AlterCommand::RemoveProperty::COMMENT;
|
|
|
|
else if (property == "CODEC")
|
|
|
|
return AlterCommand::RemoveProperty::CODEC;
|
|
|
|
else if (property == "TTL")
|
|
|
|
return AlterCommand::RemoveProperty::TTL;
|
|
|
|
|
|
|
|
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Cannot remove unknown property '{}'", property);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2016-01-11 21:46:36 +00:00
|
|
|
|
2020-08-28 17:40:45 +00:00
|
|
|
std::optional<AlterCommand> AlterCommand::parse(const ASTAlterCommand * command_ast)
|
2018-06-13 13:49:27 +00:00
|
|
|
{
|
|
|
|
const DataTypeFactory & data_type_factory = DataTypeFactory::instance();
|
|
|
|
|
|
|
|
if (command_ast->type == ASTAlterCommand::ADD_COLUMN)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2018-06-13 13:49:27 +00:00
|
|
|
command.type = AlterCommand::ADD_COLUMN;
|
|
|
|
|
2019-03-15 16:14:13 +00:00
|
|
|
const auto & ast_col_decl = command_ast->col_decl->as<ASTColumnDeclaration &>();
|
2018-06-13 13:49:27 +00:00
|
|
|
|
|
|
|
command.column_name = ast_col_decl.name;
|
|
|
|
if (ast_col_decl.type)
|
|
|
|
{
|
|
|
|
command.data_type = data_type_factory.get(ast_col_decl.type);
|
|
|
|
}
|
|
|
|
if (ast_col_decl.default_expression)
|
|
|
|
{
|
|
|
|
command.default_kind = columnDefaultKindFromString(ast_col_decl.default_specifier);
|
|
|
|
command.default_expression = ast_col_decl.default_expression;
|
|
|
|
}
|
|
|
|
|
2019-03-15 14:59:03 +00:00
|
|
|
if (ast_col_decl.comment)
|
|
|
|
{
|
|
|
|
const auto & ast_comment = typeid_cast<ASTLiteral &>(*ast_col_decl.comment);
|
|
|
|
command.comment = ast_comment.value.get<String>();
|
|
|
|
}
|
|
|
|
|
2018-12-21 14:40:20 +00:00
|
|
|
if (ast_col_decl.codec)
|
2020-08-31 06:24:19 +00:00
|
|
|
{
|
|
|
|
if (ast_col_decl.default_specifier == "ALIAS")
|
2020-08-31 15:58:31 +00:00
|
|
|
throw Exception{"Cannot specify codec for column type ALIAS", ErrorCodes::BAD_ARGUMENTS};
|
2020-08-28 17:40:45 +00:00
|
|
|
command.codec = ast_col_decl.codec;
|
2020-08-31 06:24:19 +00:00
|
|
|
}
|
2018-06-13 13:49:27 +00:00
|
|
|
if (command_ast->column)
|
2019-08-08 20:02:30 +00:00
|
|
|
command.after_column = getIdentifierName(command_ast->column);
|
2018-06-13 13:49:27 +00:00
|
|
|
|
2019-04-15 09:30:45 +00:00
|
|
|
if (ast_col_decl.ttl)
|
|
|
|
command.ttl = ast_col_decl.ttl;
|
|
|
|
|
2020-07-01 14:58:52 +00:00
|
|
|
command.first = command_ast->first;
|
2018-12-21 14:53:00 +00:00
|
|
|
command.if_not_exists = command_ast->if_not_exists;
|
|
|
|
|
2018-06-13 13:49:27 +00:00
|
|
|
return command;
|
|
|
|
}
|
2020-03-17 13:49:50 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::DROP_COLUMN)
|
2018-06-13 13:49:27 +00:00
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2018-06-13 13:49:27 +00:00
|
|
|
command.type = AlterCommand::DROP_COLUMN;
|
2019-08-08 20:02:30 +00:00
|
|
|
command.column_name = getIdentifierName(command_ast->column);
|
2018-12-21 14:53:00 +00:00
|
|
|
command.if_exists = command_ast->if_exists;
|
2020-03-17 13:49:50 +00:00
|
|
|
if (command_ast->clear_column)
|
|
|
|
command.clear = true;
|
|
|
|
|
|
|
|
if (command_ast->partition)
|
|
|
|
command.partition = command_ast->partition;
|
2018-06-13 13:49:27 +00:00
|
|
|
return command;
|
|
|
|
}
|
|
|
|
else if (command_ast->type == ASTAlterCommand::MODIFY_COLUMN)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2018-06-13 13:49:27 +00:00
|
|
|
command.type = AlterCommand::MODIFY_COLUMN;
|
|
|
|
|
2019-03-15 16:14:13 +00:00
|
|
|
const auto & ast_col_decl = command_ast->col_decl->as<ASTColumnDeclaration &>();
|
2020-09-11 17:07:00 +00:00
|
|
|
command.column_name = ast_col_decl.name;
|
2020-09-20 13:27:33 +00:00
|
|
|
command.to_remove = removePropertyFromString(command_ast->remove_property);
|
|
|
|
|
2018-06-13 13:49:27 +00:00
|
|
|
if (ast_col_decl.type)
|
|
|
|
{
|
|
|
|
command.data_type = data_type_factory.get(ast_col_decl.type);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ast_col_decl.default_expression)
|
|
|
|
{
|
|
|
|
command.default_kind = columnDefaultKindFromString(ast_col_decl.default_specifier);
|
|
|
|
command.default_expression = ast_col_decl.default_expression;
|
|
|
|
}
|
|
|
|
|
2018-11-14 22:46:39 +00:00
|
|
|
if (ast_col_decl.comment)
|
|
|
|
{
|
2019-03-15 16:14:13 +00:00
|
|
|
const auto & ast_comment = ast_col_decl.comment->as<ASTLiteral &>();
|
2019-12-23 16:44:50 +00:00
|
|
|
command.comment.emplace(ast_comment.value.get<String>());
|
2018-11-14 22:46:39 +00:00
|
|
|
}
|
2019-03-15 14:59:03 +00:00
|
|
|
|
2019-04-15 09:30:45 +00:00
|
|
|
if (ast_col_decl.ttl)
|
|
|
|
command.ttl = ast_col_decl.ttl;
|
|
|
|
|
2019-03-15 14:59:03 +00:00
|
|
|
if (ast_col_decl.codec)
|
2020-08-28 17:40:45 +00:00
|
|
|
command.codec = ast_col_decl.codec;
|
2019-03-15 14:59:03 +00:00
|
|
|
|
2020-07-01 14:58:52 +00:00
|
|
|
if (command_ast->column)
|
|
|
|
command.after_column = getIdentifierName(command_ast->column);
|
|
|
|
|
|
|
|
command.first = command_ast->first;
|
2018-12-21 14:53:00 +00:00
|
|
|
command.if_exists = command_ast->if_exists;
|
2018-11-14 22:46:39 +00:00
|
|
|
|
2018-06-13 13:49:27 +00:00
|
|
|
return command;
|
|
|
|
}
|
2018-11-26 13:01:48 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::COMMENT_COLUMN)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2018-11-26 13:01:48 +00:00
|
|
|
command.type = COMMENT_COLUMN;
|
2019-08-08 20:02:30 +00:00
|
|
|
command.column_name = getIdentifierName(command_ast->column);
|
2019-03-15 16:14:13 +00:00
|
|
|
const auto & ast_comment = command_ast->comment->as<ASTLiteral &>();
|
2018-11-26 13:01:48 +00:00
|
|
|
command.comment = ast_comment.value.get<String>();
|
2018-12-21 14:53:00 +00:00
|
|
|
command.if_exists = command_ast->if_exists;
|
2018-06-13 13:49:27 +00:00
|
|
|
return command;
|
|
|
|
}
|
2018-10-15 18:47:47 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::MODIFY_ORDER_BY)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2018-10-15 18:47:47 +00:00
|
|
|
command.type = AlterCommand::MODIFY_ORDER_BY;
|
2018-11-06 18:25:36 +00:00
|
|
|
command.order_by = command_ast->order_by;
|
2018-10-15 18:47:47 +00:00
|
|
|
return command;
|
|
|
|
}
|
2020-08-27 13:10:10 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::MODIFY_SAMPLE_BY)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
|
|
|
command.ast = command_ast->clone();
|
|
|
|
command.type = AlterCommand::MODIFY_SAMPLE_BY;
|
|
|
|
command.sample_by = command_ast->sample_by;
|
|
|
|
return command;
|
|
|
|
}
|
2019-02-05 14:50:25 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::ADD_INDEX)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2019-02-05 14:50:25 +00:00
|
|
|
command.index_decl = command_ast->index_decl;
|
|
|
|
command.type = AlterCommand::ADD_INDEX;
|
|
|
|
|
2019-03-15 16:14:13 +00:00
|
|
|
const auto & ast_index_decl = command_ast->index_decl->as<ASTIndexDeclaration &>();
|
2019-02-05 14:50:25 +00:00
|
|
|
|
|
|
|
command.index_name = ast_index_decl.name;
|
|
|
|
|
|
|
|
if (command_ast->index)
|
2020-10-24 18:46:10 +00:00
|
|
|
command.after_index_name = command_ast->index->as<ASTIdentifier &>().name();
|
2019-02-05 14:50:25 +00:00
|
|
|
|
|
|
|
command.if_not_exists = command_ast->if_not_exists;
|
|
|
|
|
|
|
|
return command;
|
|
|
|
}
|
2019-06-02 14:41:12 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::ADD_CONSTRAINT)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2019-06-02 14:41:12 +00:00
|
|
|
command.constraint_decl = command_ast->constraint_decl;
|
|
|
|
command.type = AlterCommand::ADD_CONSTRAINT;
|
|
|
|
|
|
|
|
const auto & ast_constraint_decl = command_ast->constraint_decl->as<ASTConstraintDeclaration &>();
|
|
|
|
|
|
|
|
command.constraint_name = ast_constraint_decl.name;
|
|
|
|
|
|
|
|
command.if_not_exists = command_ast->if_not_exists;
|
|
|
|
|
|
|
|
return command;
|
|
|
|
}
|
2020-03-22 00:56:10 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::DROP_CONSTRAINT)
|
2019-06-02 14:41:12 +00:00
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2019-06-02 14:41:12 +00:00
|
|
|
command.if_exists = command_ast->if_exists;
|
2019-08-20 09:17:56 +00:00
|
|
|
command.type = AlterCommand::DROP_CONSTRAINT;
|
2020-10-24 18:46:10 +00:00
|
|
|
command.constraint_name = command_ast->constraint->as<ASTIdentifier &>().name();
|
2019-08-20 09:17:56 +00:00
|
|
|
|
|
|
|
return command;
|
|
|
|
}
|
2020-03-17 13:49:50 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::DROP_INDEX)
|
2019-02-05 14:50:25 +00:00
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2019-02-05 14:50:25 +00:00
|
|
|
command.type = AlterCommand::DROP_INDEX;
|
2020-10-24 18:46:10 +00:00
|
|
|
command.index_name = command_ast->index->as<ASTIdentifier &>().name();
|
2019-02-05 14:50:25 +00:00
|
|
|
command.if_exists = command_ast->if_exists;
|
2020-03-17 13:49:50 +00:00
|
|
|
if (command_ast->clear_index)
|
|
|
|
command.clear = true;
|
|
|
|
|
|
|
|
if (command_ast->partition)
|
|
|
|
command.partition = command_ast->partition;
|
2019-02-05 14:50:25 +00:00
|
|
|
|
|
|
|
return command;
|
|
|
|
}
|
2019-04-15 09:30:45 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::MODIFY_TTL)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2019-04-15 09:30:45 +00:00
|
|
|
command.type = AlterCommand::MODIFY_TTL;
|
|
|
|
command.ttl = command_ast->ttl;
|
|
|
|
return command;
|
|
|
|
}
|
2020-09-20 13:27:33 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::REMOVE_TTL)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
|
|
|
command.ast = command_ast->clone();
|
|
|
|
command.type = AlterCommand::REMOVE_TTL;
|
|
|
|
return command;
|
|
|
|
}
|
2019-07-24 12:56:39 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::MODIFY_SETTING)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-01-15 13:00:08 +00:00
|
|
|
command.ast = command_ast->clone();
|
2019-07-24 12:56:39 +00:00
|
|
|
command.type = AlterCommand::MODIFY_SETTING;
|
|
|
|
command.settings_changes = command_ast->settings_changes->as<ASTSetQuery &>().changes;
|
|
|
|
return command;
|
|
|
|
}
|
2020-01-29 17:44:16 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::MODIFY_QUERY)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
2020-03-24 17:05:38 +00:00
|
|
|
command.ast = command_ast->clone();
|
2020-01-29 17:44:16 +00:00
|
|
|
command.type = AlterCommand::MODIFY_QUERY;
|
|
|
|
command.select = command_ast->select;
|
|
|
|
return command;
|
|
|
|
}
|
2020-03-24 17:05:38 +00:00
|
|
|
else if (command_ast->type == ASTAlterCommand::RENAME_COLUMN)
|
|
|
|
{
|
|
|
|
AlterCommand command;
|
|
|
|
command.ast = command_ast->clone();
|
|
|
|
command.type = AlterCommand::RENAME_COLUMN;
|
2020-10-24 18:46:10 +00:00
|
|
|
command.column_name = command_ast->column->as<ASTIdentifier &>().name();
|
|
|
|
command.rename_to = command_ast->rename_to->as<ASTIdentifier &>().name();
|
2020-04-03 16:45:49 +00:00
|
|
|
command.if_exists = command_ast->if_exists;
|
2020-03-24 17:05:38 +00:00
|
|
|
return command;
|
|
|
|
}
|
2018-06-13 13:49:27 +00:00
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context) const
|
2016-01-11 21:46:36 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (type == ADD_COLUMN)
|
|
|
|
{
|
2020-04-27 13:55:30 +00:00
|
|
|
ColumnDescription column(column_name, data_type);
|
2019-03-14 15:20:51 +00:00
|
|
|
if (default_expression)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2019-03-14 15:20:51 +00:00
|
|
|
column.default_desc.kind = default_kind;
|
|
|
|
column.default_desc.expression = default_expression;
|
|
|
|
}
|
2019-12-24 20:03:33 +00:00
|
|
|
if (comment)
|
|
|
|
column.comment = *comment;
|
|
|
|
|
2020-08-28 17:40:45 +00:00
|
|
|
if (codec)
|
|
|
|
column.codec = CompressionCodecFactory::instance().validateCodecAndGetPreprocessedAST(codec, data_type, false);
|
|
|
|
|
2019-04-15 09:30:45 +00:00
|
|
|
column.ttl = ttl;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-07-01 14:58:52 +00:00
|
|
|
metadata.columns.add(column, after_column, first);
|
2018-12-21 14:40:20 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Slow, because each time a list is copied
|
2021-04-10 23:33:54 +00:00
|
|
|
if (context->getSettingsRef().flatten_nested)
|
2020-11-10 17:32:00 +00:00
|
|
|
metadata.columns.flattenNested();
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else if (type == DROP_COLUMN)
|
|
|
|
{
|
2020-03-17 13:49:50 +00:00
|
|
|
/// Otherwise just clear data on disk
|
|
|
|
if (!clear && !partition)
|
|
|
|
metadata.columns.remove(column_name);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else if (type == MODIFY_COLUMN)
|
|
|
|
{
|
2020-07-01 14:58:52 +00:00
|
|
|
metadata.columns.modify(column_name, after_column, first, [&](ColumnDescription & column)
|
2019-04-02 12:51:31 +00:00
|
|
|
{
|
2020-09-20 13:27:33 +00:00
|
|
|
if (to_remove == RemoveProperty::DEFAULT
|
|
|
|
|| to_remove == RemoveProperty::MATERIALIZED
|
|
|
|
|| to_remove == RemoveProperty::ALIAS)
|
|
|
|
{
|
|
|
|
column.default_desc = ColumnDefault{};
|
|
|
|
}
|
|
|
|
else if (to_remove == RemoveProperty::CODEC)
|
|
|
|
{
|
|
|
|
column.codec.reset();
|
|
|
|
}
|
|
|
|
else if (to_remove == RemoveProperty::COMMENT)
|
|
|
|
{
|
|
|
|
column.comment = String{};
|
|
|
|
}
|
|
|
|
else if (to_remove == RemoveProperty::TTL)
|
|
|
|
{
|
|
|
|
column.ttl.reset();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (codec)
|
|
|
|
column.codec = CompressionCodecFactory::instance().validateCodecAndGetPreprocessedAST(codec, data_type ? data_type : column.type, false);
|
2019-05-01 21:43:05 +00:00
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
if (comment)
|
|
|
|
column.comment = *comment;
|
2019-05-01 21:43:05 +00:00
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
if (ttl)
|
|
|
|
column.ttl = ttl;
|
2019-05-01 21:43:05 +00:00
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
if (data_type)
|
|
|
|
column.type = data_type;
|
2018-11-13 12:08:07 +00:00
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
/// User specified default expression or changed
|
|
|
|
/// datatype. We have to replace default.
|
|
|
|
if (default_expression || data_type)
|
|
|
|
{
|
|
|
|
column.default_desc.kind = default_kind;
|
|
|
|
column.default_desc.expression = default_expression;
|
|
|
|
}
|
2019-12-24 18:07:51 +00:00
|
|
|
}
|
2019-05-01 21:43:05 +00:00
|
|
|
});
|
2020-06-09 17:22:03 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2018-11-13 12:51:55 +00:00
|
|
|
else if (type == MODIFY_ORDER_BY)
|
|
|
|
{
|
2020-06-12 09:37:52 +00:00
|
|
|
auto & sorting_key = metadata.sorting_key;
|
|
|
|
auto & primary_key = metadata.primary_key;
|
|
|
|
if (primary_key.definition_ast == nullptr && sorting_key.definition_ast != nullptr)
|
2018-11-13 12:51:55 +00:00
|
|
|
{
|
2020-06-12 09:37:52 +00:00
|
|
|
/// Primary and sorting key become independent after this ALTER so
|
|
|
|
/// we have to save the old ORDER BY expression as the new primary
|
|
|
|
/// key.
|
|
|
|
primary_key = KeyDescription::getKeyFromAST(sorting_key.definition_ast, metadata.columns, context);
|
2018-11-13 12:51:55 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 10:14:36 +00:00
|
|
|
/// Recalculate key with new order_by expression.
|
2020-06-12 09:37:52 +00:00
|
|
|
sorting_key.recalculateWithNewAST(order_by, metadata.columns, context);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2020-08-27 13:10:10 +00:00
|
|
|
else if (type == MODIFY_SAMPLE_BY)
|
|
|
|
{
|
|
|
|
metadata.sampling_key.recalculateWithNewAST(sample_by, metadata.columns, context);
|
|
|
|
}
|
2018-10-14 15:30:06 +00:00
|
|
|
else if (type == COMMENT_COLUMN)
|
|
|
|
{
|
2020-06-08 18:49:54 +00:00
|
|
|
metadata.columns.modify(column_name,
|
|
|
|
[&](ColumnDescription & column) { column.comment = *comment; });
|
2018-10-14 15:30:06 +00:00
|
|
|
}
|
2019-02-05 14:50:25 +00:00
|
|
|
else if (type == ADD_INDEX)
|
|
|
|
{
|
|
|
|
if (std::any_of(
|
2020-06-01 12:11:23 +00:00
|
|
|
metadata.secondary_indices.cbegin(),
|
|
|
|
metadata.secondary_indices.cend(),
|
2020-05-28 12:37:05 +00:00
|
|
|
[this](const auto & index)
|
2019-02-05 14:50:25 +00:00
|
|
|
{
|
2020-05-28 12:37:05 +00:00
|
|
|
return index.name == index_name;
|
2019-02-05 14:50:25 +00:00
|
|
|
}))
|
|
|
|
{
|
|
|
|
if (if_not_exists)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
throw Exception{"Cannot add index " + index_name + ": index with this name already exists",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN};
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:11:23 +00:00
|
|
|
auto insert_it = metadata.secondary_indices.end();
|
2019-02-05 14:50:25 +00:00
|
|
|
|
|
|
|
if (!after_index_name.empty())
|
|
|
|
{
|
|
|
|
insert_it = std::find_if(
|
2020-06-01 12:11:23 +00:00
|
|
|
metadata.secondary_indices.begin(),
|
|
|
|
metadata.secondary_indices.end(),
|
2020-05-28 12:37:05 +00:00
|
|
|
[this](const auto & index)
|
2019-02-05 14:50:25 +00:00
|
|
|
{
|
2020-05-28 12:37:05 +00:00
|
|
|
return index.name == after_index_name;
|
2019-02-05 14:50:25 +00:00
|
|
|
});
|
|
|
|
|
2020-06-01 12:11:23 +00:00
|
|
|
if (insert_it == metadata.secondary_indices.end())
|
2019-06-15 12:06:22 +00:00
|
|
|
throw Exception("Wrong index name. Cannot find index " + backQuote(after_index_name) + " to insert after.",
|
2019-12-30 14:46:02 +00:00
|
|
|
ErrorCodes::BAD_ARGUMENTS);
|
2019-02-05 14:50:25 +00:00
|
|
|
|
|
|
|
++insert_it;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:11:23 +00:00
|
|
|
metadata.secondary_indices.emplace(insert_it, IndexDescription::getIndexFromAST(index_decl, metadata.columns, context));
|
2019-02-05 14:50:25 +00:00
|
|
|
}
|
|
|
|
else if (type == DROP_INDEX)
|
|
|
|
{
|
2020-03-17 13:49:50 +00:00
|
|
|
if (!partition && !clear)
|
2019-06-03 21:08:52 +00:00
|
|
|
{
|
2020-03-17 13:49:50 +00:00
|
|
|
auto erase_it = std::find_if(
|
2020-06-01 12:11:23 +00:00
|
|
|
metadata.secondary_indices.begin(),
|
|
|
|
metadata.secondary_indices.end(),
|
2020-05-28 12:37:05 +00:00
|
|
|
[this](const auto & index)
|
2020-03-17 13:49:50 +00:00
|
|
|
{
|
2020-05-28 12:37:05 +00:00
|
|
|
return index.name == index_name;
|
2020-03-17 13:49:50 +00:00
|
|
|
});
|
2019-02-05 14:50:25 +00:00
|
|
|
|
2020-06-01 12:11:23 +00:00
|
|
|
if (erase_it == metadata.secondary_indices.end())
|
2020-03-17 13:49:50 +00:00
|
|
|
{
|
|
|
|
if (if_exists)
|
|
|
|
return;
|
|
|
|
throw Exception("Wrong index name. Cannot find index " + backQuote(index_name) + " to drop.", ErrorCodes::BAD_ARGUMENTS);
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:11:23 +00:00
|
|
|
metadata.secondary_indices.erase(erase_it);
|
2020-03-17 13:49:50 +00:00
|
|
|
}
|
2019-02-05 14:50:25 +00:00
|
|
|
}
|
2019-06-02 14:41:12 +00:00
|
|
|
else if (type == ADD_CONSTRAINT)
|
|
|
|
{
|
|
|
|
if (std::any_of(
|
2019-12-26 18:17:05 +00:00
|
|
|
metadata.constraints.constraints.cbegin(),
|
|
|
|
metadata.constraints.constraints.cend(),
|
2019-06-02 14:41:12 +00:00
|
|
|
[this](const ASTPtr & constraint_ast)
|
|
|
|
{
|
|
|
|
return constraint_ast->as<ASTConstraintDeclaration &>().name == constraint_name;
|
|
|
|
}))
|
|
|
|
{
|
|
|
|
if (if_not_exists)
|
|
|
|
return;
|
|
|
|
throw Exception("Cannot add constraint " + constraint_name + ": constraint with this name already exists",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
}
|
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
auto insert_it = metadata.constraints.constraints.end();
|
2019-06-02 14:41:12 +00:00
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
metadata.constraints.constraints.emplace(insert_it, std::dynamic_pointer_cast<ASTConstraintDeclaration>(constraint_decl));
|
2019-06-02 14:41:12 +00:00
|
|
|
}
|
|
|
|
else if (type == DROP_CONSTRAINT)
|
|
|
|
{
|
|
|
|
auto erase_it = std::find_if(
|
2019-12-26 18:17:05 +00:00
|
|
|
metadata.constraints.constraints.begin(),
|
|
|
|
metadata.constraints.constraints.end(),
|
2019-06-02 14:41:12 +00:00
|
|
|
[this](const ASTPtr & constraint_ast)
|
|
|
|
{
|
|
|
|
return constraint_ast->as<ASTConstraintDeclaration &>().name == constraint_name;
|
|
|
|
});
|
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
if (erase_it == metadata.constraints.constraints.end())
|
2019-06-02 15:08:28 +00:00
|
|
|
{
|
2019-06-02 14:41:12 +00:00
|
|
|
if (if_exists)
|
|
|
|
return;
|
|
|
|
throw Exception("Wrong constraint name. Cannot find constraint `" + constraint_name + "` to drop.",
|
2019-12-30 14:46:02 +00:00
|
|
|
ErrorCodes::BAD_ARGUMENTS);
|
2019-06-02 14:41:12 +00:00
|
|
|
}
|
2019-12-26 18:17:05 +00:00
|
|
|
metadata.constraints.constraints.erase(erase_it);
|
2019-06-02 14:41:12 +00:00
|
|
|
}
|
2019-04-15 09:30:45 +00:00
|
|
|
else if (type == MODIFY_TTL)
|
|
|
|
{
|
2020-09-11 17:07:00 +00:00
|
|
|
metadata.table_ttl = TTLTableDescription::getTTLForTableFromAST(ttl, metadata.columns, context, metadata.primary_key);
|
2019-04-15 09:30:45 +00:00
|
|
|
}
|
2020-09-20 13:27:33 +00:00
|
|
|
else if (type == REMOVE_TTL)
|
|
|
|
{
|
|
|
|
metadata.table_ttl = TTLTableDescription{};
|
|
|
|
}
|
2020-01-29 17:44:16 +00:00
|
|
|
else if (type == MODIFY_QUERY)
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.select = SelectQueryDescription::getSelectQueryFromASTForMatView(select, context);
|
2020-01-29 17:44:16 +00:00
|
|
|
}
|
2019-07-24 12:56:39 +00:00
|
|
|
else if (type == MODIFY_SETTING)
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
auto & settings_from_storage = metadata.settings_changes->as<ASTSetQuery &>().changes;
|
2019-12-26 18:17:05 +00:00
|
|
|
for (const auto & change : settings_changes)
|
|
|
|
{
|
|
|
|
auto finder = [&change](const SettingChange & c) { return c.name == change.name; };
|
2019-12-29 11:25:26 +00:00
|
|
|
auto it = std::find_if(settings_from_storage.begin(), settings_from_storage.end(), finder);
|
|
|
|
|
|
|
|
if (it != settings_from_storage.end())
|
2019-12-26 18:17:05 +00:00
|
|
|
it->value = change.value;
|
|
|
|
else
|
2019-12-27 14:36:59 +00:00
|
|
|
settings_from_storage.push_back(change);
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
2019-07-24 12:56:39 +00:00
|
|
|
}
|
2020-03-24 17:05:38 +00:00
|
|
|
else if (type == RENAME_COLUMN)
|
|
|
|
{
|
|
|
|
metadata.columns.rename(column_name, rename_to);
|
2020-04-02 16:11:10 +00:00
|
|
|
RenameColumnData rename_data{column_name, rename_to};
|
|
|
|
RenameColumnVisitor rename_visitor(rename_data);
|
2020-04-22 06:22:14 +00:00
|
|
|
for (const auto & column : metadata.columns)
|
2020-04-02 16:11:10 +00:00
|
|
|
{
|
2020-04-02 18:33:17 +00:00
|
|
|
metadata.columns.modify(column.name, [&](ColumnDescription & column_to_modify)
|
|
|
|
{
|
2020-04-02 16:11:10 +00:00
|
|
|
if (column_to_modify.default_desc.expression)
|
|
|
|
rename_visitor.visit(column_to_modify.default_desc.expression);
|
|
|
|
if (column_to_modify.ttl)
|
|
|
|
rename_visitor.visit(column_to_modify.ttl);
|
|
|
|
});
|
|
|
|
}
|
2020-06-05 17:29:40 +00:00
|
|
|
if (metadata.table_ttl.definition_ast)
|
|
|
|
rename_visitor.visit(metadata.table_ttl.definition_ast);
|
|
|
|
|
2020-05-12 11:26:44 +00:00
|
|
|
for (auto & constraint : metadata.constraints.constraints)
|
|
|
|
rename_visitor.visit(constraint);
|
2020-07-09 14:14:44 +00:00
|
|
|
|
|
|
|
if (metadata.isSortingKeyDefined())
|
|
|
|
rename_visitor.visit(metadata.sorting_key.definition_ast);
|
|
|
|
|
|
|
|
if (metadata.isPrimaryKeyDefined())
|
|
|
|
rename_visitor.visit(metadata.primary_key.definition_ast);
|
|
|
|
|
|
|
|
if (metadata.isSamplingKeyDefined())
|
|
|
|
rename_visitor.visit(metadata.sampling_key.definition_ast);
|
|
|
|
|
|
|
|
if (metadata.isPartitionKeyDefined())
|
|
|
|
rename_visitor.visit(metadata.partition_key.definition_ast);
|
2020-07-09 14:30:38 +00:00
|
|
|
|
|
|
|
for (auto & index : metadata.secondary_indices)
|
|
|
|
rename_visitor.visit(index.definition_ast);
|
2020-03-24 17:05:38 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
else
|
|
|
|
throw Exception("Wrong parameter type in ALTER query", ErrorCodes::LOGICAL_ERROR);
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|
2014-10-21 12:11:20 +00:00
|
|
|
|
2020-01-13 16:39:20 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
/// If true, then in order to ALTER the type of the column from the type from to the type to
|
|
|
|
/// we don't need to rewrite the data, we only need to update metadata and columns.txt in part directories.
|
|
|
|
/// The function works for Arrays and Nullables of the same structure.
|
|
|
|
bool isMetadataOnlyConversion(const IDataType * from, const IDataType * to)
|
|
|
|
{
|
2020-04-20 19:53:19 +00:00
|
|
|
if (from->equals(*to))
|
2020-01-13 16:39:20 +00:00
|
|
|
return true;
|
|
|
|
|
2020-07-21 14:05:30 +00:00
|
|
|
if (const auto * from_enum8 = typeid_cast<const DataTypeEnum8 *>(from))
|
|
|
|
{
|
|
|
|
if (const auto * to_enum8 = typeid_cast<const DataTypeEnum8 *>(to))
|
|
|
|
return to_enum8->contains(*from_enum8);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const auto * from_enum16 = typeid_cast<const DataTypeEnum16 *>(from))
|
|
|
|
{
|
|
|
|
if (const auto * to_enum16 = typeid_cast<const DataTypeEnum16 *>(to))
|
|
|
|
return to_enum16->contains(*from_enum16);
|
|
|
|
}
|
|
|
|
|
2020-01-13 16:39:20 +00:00
|
|
|
static const std::unordered_multimap<std::type_index, const std::type_info &> ALLOWED_CONVERSIONS =
|
|
|
|
{
|
|
|
|
{ typeid(DataTypeEnum8), typeid(DataTypeInt8) },
|
|
|
|
{ typeid(DataTypeEnum16), typeid(DataTypeInt16) },
|
|
|
|
{ typeid(DataTypeDateTime), typeid(DataTypeUInt32) },
|
|
|
|
{ typeid(DataTypeUInt32), typeid(DataTypeDateTime) },
|
|
|
|
{ typeid(DataTypeDate), typeid(DataTypeUInt16) },
|
|
|
|
{ typeid(DataTypeUInt16), typeid(DataTypeDate) },
|
|
|
|
};
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
auto it_range = ALLOWED_CONVERSIONS.equal_range(typeid(*from));
|
|
|
|
for (auto it = it_range.first; it != it_range.second; ++it)
|
|
|
|
{
|
|
|
|
if (it->second == typeid(*to))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto * arr_from = typeid_cast<const DataTypeArray *>(from);
|
|
|
|
const auto * arr_to = typeid_cast<const DataTypeArray *>(to);
|
|
|
|
if (arr_from && arr_to)
|
|
|
|
{
|
|
|
|
from = arr_from->getNestedType().get();
|
|
|
|
to = arr_to->getNestedType().get();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto * nullable_from = typeid_cast<const DataTypeNullable *>(from);
|
|
|
|
const auto * nullable_to = typeid_cast<const DataTypeNullable *>(to);
|
|
|
|
if (nullable_from && nullable_to)
|
|
|
|
{
|
|
|
|
from = nullable_from->getNestedType().get();
|
|
|
|
to = nullable_to->getNestedType().get();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-07-21 14:05:30 +00:00
|
|
|
bool AlterCommand::isSettingsAlter() const
|
|
|
|
{
|
|
|
|
return type == MODIFY_SETTING;
|
|
|
|
}
|
2020-01-13 16:39:20 +00:00
|
|
|
|
|
|
|
bool AlterCommand::isRequireMutationStage(const StorageInMemoryMetadata & metadata) const
|
|
|
|
{
|
2020-01-15 13:00:08 +00:00
|
|
|
if (ignore)
|
|
|
|
return false;
|
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
/// We remove properties on metadata level
|
|
|
|
if (isRemovingProperty() || type == REMOVE_TTL)
|
|
|
|
return false;
|
|
|
|
|
2020-03-30 12:51:05 +00:00
|
|
|
if (type == DROP_COLUMN || type == DROP_INDEX || type == RENAME_COLUMN)
|
2020-01-15 13:00:08 +00:00
|
|
|
return true;
|
|
|
|
|
2020-01-13 16:39:20 +00:00
|
|
|
if (type != MODIFY_COLUMN || data_type == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (const auto & column : metadata.columns.getAllPhysical())
|
|
|
|
{
|
2020-01-15 13:00:08 +00:00
|
|
|
if (column.name == column_name && !isMetadataOnlyConversion(column.type.get(), data_type.get()))
|
2020-01-13 16:39:20 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-27 14:36:59 +00:00
|
|
|
bool AlterCommand::isCommentAlter() const
|
|
|
|
{
|
|
|
|
if (type == COMMENT_COLUMN)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (type == MODIFY_COLUMN)
|
|
|
|
{
|
|
|
|
return comment.has_value()
|
|
|
|
&& codec == nullptr
|
|
|
|
&& data_type == nullptr
|
|
|
|
&& default_expression == nullptr
|
|
|
|
&& ttl == nullptr;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-19 01:53:01 +00:00
|
|
|
bool AlterCommand::isTTLAlter(const StorageInMemoryMetadata & metadata) const
|
|
|
|
{
|
|
|
|
if (type == MODIFY_TTL)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!ttl || type != MODIFY_COLUMN)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool ttl_changed = true;
|
|
|
|
for (const auto & [name, ttl_ast] : metadata.columns.getColumnTTLs())
|
|
|
|
{
|
|
|
|
if (name == column_name && queryToString(*ttl) == queryToString(*ttl_ast))
|
|
|
|
{
|
|
|
|
ttl_changed = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ttl_changed;
|
|
|
|
}
|
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
bool AlterCommand::isRemovingProperty() const
|
|
|
|
{
|
|
|
|
return to_remove != RemoveProperty::NO_PROPERTY;
|
|
|
|
}
|
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
std::optional<MutationCommand> AlterCommand::tryConvertToMutationCommand(StorageInMemoryMetadata & metadata, ContextPtr context) const
|
2020-01-13 16:39:20 +00:00
|
|
|
{
|
|
|
|
if (!isRequireMutationStage(metadata))
|
|
|
|
return {};
|
|
|
|
|
|
|
|
MutationCommand result;
|
|
|
|
|
2020-01-17 13:54:22 +00:00
|
|
|
if (type == MODIFY_COLUMN)
|
|
|
|
{
|
|
|
|
result.type = MutationCommand::Type::READ_COLUMN;
|
|
|
|
result.column_name = column_name;
|
|
|
|
result.data_type = data_type;
|
|
|
|
result.predicate = nullptr;
|
|
|
|
}
|
|
|
|
else if (type == DROP_COLUMN)
|
|
|
|
{
|
|
|
|
result.type = MutationCommand::Type::DROP_COLUMN;
|
|
|
|
result.column_name = column_name;
|
2020-03-17 13:49:50 +00:00
|
|
|
if (clear)
|
|
|
|
result.clear = true;
|
|
|
|
if (partition)
|
|
|
|
result.partition = partition;
|
2020-01-17 13:54:22 +00:00
|
|
|
result.predicate = nullptr;
|
|
|
|
}
|
|
|
|
else if (type == DROP_INDEX)
|
|
|
|
{
|
|
|
|
result.type = MutationCommand::Type::DROP_INDEX;
|
2020-03-17 13:49:50 +00:00
|
|
|
result.column_name = index_name;
|
|
|
|
if (clear)
|
|
|
|
result.clear = true;
|
|
|
|
if (partition)
|
|
|
|
result.partition = partition;
|
|
|
|
|
2020-01-17 13:54:22 +00:00
|
|
|
result.predicate = nullptr;
|
|
|
|
}
|
2020-03-30 12:51:05 +00:00
|
|
|
else if (type == RENAME_COLUMN)
|
|
|
|
{
|
|
|
|
result.type = MutationCommand::Type::RENAME_COLUMN;
|
|
|
|
result.column_name = column_name;
|
|
|
|
result.rename_to = rename_to;
|
|
|
|
}
|
2020-01-17 13:54:22 +00:00
|
|
|
|
2020-01-15 13:00:08 +00:00
|
|
|
result.ast = ast->clone();
|
2020-05-28 12:37:05 +00:00
|
|
|
apply(metadata, context);
|
2020-01-13 16:39:20 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
|
|
|
|
String alterTypeToString(const AlterCommand::Type type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case AlterCommand::Type::ADD_COLUMN:
|
|
|
|
return "ADD COLUMN";
|
|
|
|
case AlterCommand::Type::ADD_CONSTRAINT:
|
|
|
|
return "ADD CONSTRAINT";
|
|
|
|
case AlterCommand::Type::ADD_INDEX:
|
|
|
|
return "ADD INDEX";
|
|
|
|
case AlterCommand::Type::COMMENT_COLUMN:
|
|
|
|
return "COMMENT COLUMN";
|
|
|
|
case AlterCommand::Type::DROP_COLUMN:
|
|
|
|
return "DROP COLUMN";
|
|
|
|
case AlterCommand::Type::DROP_CONSTRAINT:
|
|
|
|
return "DROP CONSTRAINT";
|
|
|
|
case AlterCommand::Type::DROP_INDEX:
|
|
|
|
return "DROP INDEX";
|
|
|
|
case AlterCommand::Type::MODIFY_COLUMN:
|
|
|
|
return "MODIFY COLUMN";
|
|
|
|
case AlterCommand::Type::MODIFY_ORDER_BY:
|
|
|
|
return "MODIFY ORDER BY";
|
2020-08-27 13:10:10 +00:00
|
|
|
case AlterCommand::Type::MODIFY_SAMPLE_BY:
|
|
|
|
return "MODIFY SAMPLE BY";
|
2019-12-26 18:17:05 +00:00
|
|
|
case AlterCommand::Type::MODIFY_TTL:
|
|
|
|
return "MODIFY TTL";
|
|
|
|
case AlterCommand::Type::MODIFY_SETTING:
|
|
|
|
return "MODIFY SETTING";
|
2020-01-29 17:44:16 +00:00
|
|
|
case AlterCommand::Type::MODIFY_QUERY:
|
|
|
|
return "MODIFY QUERY";
|
2020-03-24 17:05:38 +00:00
|
|
|
case AlterCommand::Type::RENAME_COLUMN:
|
|
|
|
return "RENAME COLUMN";
|
2020-09-20 13:27:33 +00:00
|
|
|
case AlterCommand::Type::REMOVE_TTL:
|
|
|
|
return "REMOVE TTL";
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
|
|
|
__builtin_unreachable();
|
|
|
|
}
|
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
void AlterCommands::apply(StorageInMemoryMetadata & metadata, ContextPtr context) const
|
2016-01-11 21:46:36 +00:00
|
|
|
{
|
2019-12-26 18:17:05 +00:00
|
|
|
if (!prepared)
|
|
|
|
throw DB::Exception("Alter commands is not prepared. Cannot apply. It's a bug", ErrorCodes::LOGICAL_ERROR);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
auto metadata_copy = metadata;
|
2020-12-16 07:26:18 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
for (const AlterCommand & command : *this)
|
2018-12-21 14:53:00 +00:00
|
|
|
if (!command.ignore)
|
2020-05-28 12:37:05 +00:00
|
|
|
command.apply(metadata_copy, context);
|
2019-12-26 18:17:05 +00:00
|
|
|
|
2020-06-15 08:12:01 +00:00
|
|
|
/// Changes in columns may lead to changes in keys expression.
|
2020-07-09 14:14:44 +00:00
|
|
|
metadata_copy.sorting_key.recalculateWithNewAST(metadata_copy.sorting_key.definition_ast, metadata_copy.columns, context);
|
2020-06-10 09:09:51 +00:00
|
|
|
if (metadata_copy.primary_key.definition_ast != nullptr)
|
|
|
|
{
|
2020-07-09 14:14:44 +00:00
|
|
|
metadata_copy.primary_key.recalculateWithNewAST(metadata_copy.primary_key.definition_ast, metadata_copy.columns, context);
|
2020-06-10 09:09:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-10 11:16:31 +00:00
|
|
|
metadata_copy.primary_key = KeyDescription::getKeyFromAST(metadata_copy.sorting_key.definition_ast, metadata_copy.columns, context);
|
2020-06-10 09:09:51 +00:00
|
|
|
metadata_copy.primary_key.definition_ast = nullptr;
|
|
|
|
}
|
|
|
|
|
2020-06-25 23:21:04 +00:00
|
|
|
/// And in partition key expression
|
|
|
|
if (metadata_copy.partition_key.definition_ast != nullptr)
|
2020-07-09 14:14:44 +00:00
|
|
|
metadata_copy.partition_key.recalculateWithNewAST(metadata_copy.partition_key.definition_ast, metadata_copy.columns, context);
|
2020-06-25 23:21:04 +00:00
|
|
|
|
2020-08-27 13:10:10 +00:00
|
|
|
// /// And in sample key expression
|
|
|
|
if (metadata_copy.sampling_key.definition_ast != nullptr)
|
|
|
|
metadata_copy.sampling_key.recalculateWithNewAST(metadata_copy.sampling_key.definition_ast, metadata_copy.columns, context);
|
|
|
|
|
2020-06-19 10:53:20 +00:00
|
|
|
/// Changes in columns may lead to changes in secondary indices
|
|
|
|
for (auto & index : metadata_copy.secondary_indices)
|
2020-07-09 14:14:44 +00:00
|
|
|
index = IndexDescription::getIndexFromAST(index.definition_ast, metadata_copy.columns, context);
|
2020-06-19 10:53:20 +00:00
|
|
|
|
2020-06-15 08:12:01 +00:00
|
|
|
/// Changes in columns may lead to changes in TTL expressions.
|
2020-06-10 09:09:51 +00:00
|
|
|
auto column_ttl_asts = metadata_copy.columns.getColumnTTLs();
|
2020-12-16 07:26:18 +00:00
|
|
|
metadata_copy.column_ttls_by_name.clear();
|
2020-06-10 09:09:51 +00:00
|
|
|
for (const auto & [name, ast] : column_ttl_asts)
|
|
|
|
{
|
|
|
|
auto new_ttl_entry = TTLDescription::getTTLFromAST(ast, metadata_copy.columns, context, metadata_copy.primary_key);
|
|
|
|
metadata_copy.column_ttls_by_name[name] = new_ttl_entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (metadata_copy.table_ttl.definition_ast != nullptr)
|
2020-12-16 07:26:18 +00:00
|
|
|
metadata_copy.table_ttl = TTLTableDescription::getTTLForTableFromAST(
|
2020-06-10 09:09:51 +00:00
|
|
|
metadata_copy.table_ttl.definition_ast, metadata_copy.columns, context, metadata_copy.primary_key);
|
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
metadata = std::move(metadata_copy);
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|
2014-10-21 12:11:20 +00:00
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
|
2020-02-20 10:04:15 +00:00
|
|
|
void AlterCommands::prepare(const StorageInMemoryMetadata & metadata)
|
2016-01-11 21:46:36 +00:00
|
|
|
{
|
2019-12-26 18:17:05 +00:00
|
|
|
auto columns = metadata.columns;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2019-03-14 15:20:51 +00:00
|
|
|
for (size_t i = 0; i < size(); ++i)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2019-03-14 15:20:51 +00:00
|
|
|
auto & command = (*this)[i];
|
2020-02-19 14:39:01 +00:00
|
|
|
bool has_column = columns.has(command.column_name) || columns.hasNested(command.column_name);
|
2020-02-19 12:52:27 +00:00
|
|
|
if (command.type == AlterCommand::MODIFY_COLUMN)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-02-19 12:52:27 +00:00
|
|
|
if (!has_column && command.if_exists)
|
|
|
|
command.ignore = true;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-09-20 13:27:33 +00:00
|
|
|
if (has_column)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-02-19 12:52:27 +00:00
|
|
|
auto column_from_table = columns.get(command.column_name);
|
2020-09-20 13:27:33 +00:00
|
|
|
if (command.data_type && !command.default_expression && column_from_table.default_desc.expression)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-02-19 12:52:27 +00:00
|
|
|
command.default_kind = column_from_table.default_desc.kind;
|
|
|
|
command.default_expression = column_from_table.default_desc.expression;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2020-09-20 13:27:33 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-19 14:39:01 +00:00
|
|
|
else if (command.type == AlterCommand::ADD_COLUMN)
|
|
|
|
{
|
|
|
|
if (has_column && command.if_not_exists)
|
|
|
|
command.ignore = true;
|
|
|
|
}
|
|
|
|
else if (command.type == AlterCommand::DROP_COLUMN
|
2020-04-03 16:45:49 +00:00
|
|
|
|| command.type == AlterCommand::COMMENT_COLUMN
|
|
|
|
|| command.type == AlterCommand::RENAME_COLUMN)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-02-19 12:52:27 +00:00
|
|
|
if (!has_column && command.if_exists)
|
2019-03-14 15:20:51 +00:00
|
|
|
command.ignore = true;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-26 18:17:05 +00:00
|
|
|
prepared = true;
|
2014-10-16 13:37:01 +00:00
|
|
|
}
|
2016-01-11 21:46:36 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
void AlterCommands::validate(const StorageInMemoryMetadata & metadata, ContextPtr context) const
|
2018-11-28 12:06:52 +00:00
|
|
|
{
|
2020-02-19 14:39:01 +00:00
|
|
|
auto all_columns = metadata.columns;
|
2020-03-03 10:04:05 +00:00
|
|
|
/// Default expression for all added/modified columns
|
2020-03-03 10:02:43 +00:00
|
|
|
ASTPtr default_expr_list = std::make_shared<ASTExpressionList>();
|
2020-05-19 09:54:56 +00:00
|
|
|
NameSet modified_columns, renamed_columns;
|
2019-12-26 18:17:05 +00:00
|
|
|
for (size_t i = 0; i < size(); ++i)
|
|
|
|
{
|
2020-04-22 06:22:14 +00:00
|
|
|
const auto & command = (*this)[i];
|
2020-02-19 12:52:27 +00:00
|
|
|
|
|
|
|
const auto & column_name = command.column_name;
|
|
|
|
if (command.type == AlterCommand::ADD_COLUMN)
|
2019-12-26 18:17:05 +00:00
|
|
|
{
|
2020-05-19 09:54:56 +00:00
|
|
|
if (all_columns.has(column_name) || all_columns.hasNested(column_name))
|
2020-02-19 14:39:01 +00:00
|
|
|
{
|
2020-02-19 12:52:27 +00:00
|
|
|
if (!command.if_not_exists)
|
2020-02-20 10:04:15 +00:00
|
|
|
throw Exception{"Cannot add column " + backQuote(column_name) + ": column with this name already exists",
|
|
|
|
ErrorCodes::DUPLICATE_COLUMN};
|
2020-02-19 14:39:01 +00:00
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
2019-08-06 12:52:08 +00:00
|
|
|
|
2020-02-19 12:52:27 +00:00
|
|
|
if (!command.data_type)
|
2020-02-20 10:04:15 +00:00
|
|
|
throw Exception{"Data type have to be specified for column " + backQuote(column_name) + " to add",
|
|
|
|
ErrorCodes::BAD_ARGUMENTS};
|
2020-02-19 12:52:27 +00:00
|
|
|
|
2020-08-28 17:40:45 +00:00
|
|
|
if (command.codec)
|
2021-04-10 23:33:54 +00:00
|
|
|
CompressionCodecFactory::instance().validateCodecAndGetPreprocessedAST(command.codec, command.data_type, !context->getSettingsRef().allow_suspicious_codecs);
|
2020-08-28 17:40:45 +00:00
|
|
|
|
2020-04-27 13:55:30 +00:00
|
|
|
all_columns.add(ColumnDescription(column_name, command.data_type));
|
2020-02-19 12:52:27 +00:00
|
|
|
}
|
|
|
|
else if (command.type == AlterCommand::MODIFY_COLUMN)
|
|
|
|
{
|
2020-05-19 09:54:56 +00:00
|
|
|
if (!all_columns.has(column_name))
|
2020-02-19 14:39:01 +00:00
|
|
|
{
|
2020-02-19 12:52:27 +00:00
|
|
|
if (!command.if_exists)
|
2020-02-20 10:04:15 +00:00
|
|
|
throw Exception{"Wrong column name. Cannot find column " + backQuote(column_name) + " to modify",
|
|
|
|
ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK};
|
2020-02-19 14:39:01 +00:00
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
2020-05-19 09:54:56 +00:00
|
|
|
|
|
|
|
if (renamed_columns.count(column_name))
|
|
|
|
throw Exception{"Cannot rename and modify the same column " + backQuote(column_name) + " in a single ALTER query",
|
|
|
|
ErrorCodes::NOT_IMPLEMENTED};
|
2020-08-28 17:40:45 +00:00
|
|
|
|
|
|
|
if (command.codec)
|
2021-04-10 23:33:54 +00:00
|
|
|
CompressionCodecFactory::instance().validateCodecAndGetPreprocessedAST(command.codec, command.data_type, !context->getSettingsRef().allow_suspicious_codecs);
|
2020-09-20 13:27:33 +00:00
|
|
|
auto column_default = all_columns.getDefault(column_name);
|
|
|
|
if (column_default)
|
|
|
|
{
|
|
|
|
if (command.to_remove == AlterCommand::RemoveProperty::DEFAULT && column_default->kind != ColumnDefaultKind::Default)
|
|
|
|
{
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Cannot remove DEFAULT from column {}, because column default type is {}. Use REMOVE {} to delete it",
|
|
|
|
backQuote(column_name), toString(column_default->kind), toString(column_default->kind));
|
|
|
|
}
|
|
|
|
if (command.to_remove == AlterCommand::RemoveProperty::MATERIALIZED && column_default->kind != ColumnDefaultKind::Materialized)
|
|
|
|
{
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Cannot remove MATERIALIZED from column {}, because column default type is {}. Use REMOVE {} to delete it",
|
|
|
|
backQuote(column_name), toString(column_default->kind), toString(column_default->kind));
|
|
|
|
}
|
|
|
|
if (command.to_remove == AlterCommand::RemoveProperty::ALIAS && column_default->kind != ColumnDefaultKind::Alias)
|
|
|
|
{
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Cannot remove ALIAS from column {}, because column default type is {}. Use REMOVE {} to delete it",
|
|
|
|
backQuote(column_name), toString(column_default->kind), toString(column_default->kind));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (command.isRemovingProperty())
|
|
|
|
{
|
|
|
|
if (!column_default && command.to_remove == AlterCommand::RemoveProperty::DEFAULT)
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Column {} doesn't have DEFAULT, cannot remove it",
|
|
|
|
backQuote(column_name));
|
|
|
|
|
|
|
|
if (!column_default && command.to_remove == AlterCommand::RemoveProperty::ALIAS)
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Column {} doesn't have ALIAS, cannot remove it",
|
|
|
|
backQuote(column_name));
|
|
|
|
|
|
|
|
if (!column_default && command.to_remove == AlterCommand::RemoveProperty::MATERIALIZED)
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Column {} doesn't have MATERIALIZED, cannot remove it",
|
|
|
|
backQuote(column_name));
|
|
|
|
|
|
|
|
auto column_from_table = all_columns.get(column_name);
|
|
|
|
if (command.to_remove == AlterCommand::RemoveProperty::TTL && column_from_table.ttl == nullptr)
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Column {} doesn't have TTL, cannot remove it",
|
|
|
|
backQuote(column_name));
|
|
|
|
if (command.to_remove == AlterCommand::RemoveProperty::CODEC && column_from_table.codec == nullptr)
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Column {} doesn't have TTL, cannot remove it",
|
|
|
|
backQuote(column_name));
|
|
|
|
if (command.to_remove == AlterCommand::RemoveProperty::COMMENT && column_from_table.comment.empty())
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::BAD_ARGUMENTS,
|
|
|
|
"Column {} doesn't have COMMENT, cannot remove it",
|
|
|
|
backQuote(column_name));
|
|
|
|
|
|
|
|
}
|
2020-08-28 17:40:45 +00:00
|
|
|
|
2020-05-19 09:54:56 +00:00
|
|
|
modified_columns.emplace(column_name);
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
|
|
|
else if (command.type == AlterCommand::DROP_COLUMN)
|
|
|
|
{
|
2020-05-19 09:54:56 +00:00
|
|
|
if (all_columns.has(command.column_name) || all_columns.hasNested(command.column_name))
|
2019-12-26 18:17:05 +00:00
|
|
|
{
|
2020-07-10 05:54:35 +00:00
|
|
|
if (!command.clear) /// CLEAR column is Ok even if there are dependencies.
|
2019-12-26 18:17:05 +00:00
|
|
|
{
|
2020-07-10 05:54:35 +00:00
|
|
|
/// Check if we are going to DROP a column that some other columns depend on.
|
|
|
|
for (const ColumnDescription & column : all_columns)
|
2020-02-19 12:52:27 +00:00
|
|
|
{
|
2020-07-10 05:54:35 +00:00
|
|
|
const auto & default_expression = column.default_desc.expression;
|
|
|
|
if (default_expression)
|
|
|
|
{
|
|
|
|
ASTPtr query = default_expression->clone();
|
2020-07-22 17:13:05 +00:00
|
|
|
auto syntax_result = TreeRewriter(context).analyze(query, all_columns.getAll());
|
2020-07-10 05:54:35 +00:00
|
|
|
const auto actions = ExpressionAnalyzer(query, syntax_result, context).getActions(true);
|
|
|
|
const auto required_columns = actions->getRequiredColumns();
|
|
|
|
|
|
|
|
if (required_columns.end() != std::find(required_columns.begin(), required_columns.end(), command.column_name))
|
|
|
|
throw Exception("Cannot drop column " + backQuote(command.column_name)
|
|
|
|
+ ", because column " + backQuote(column.name) + " depends on it",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
}
|
2020-02-19 12:52:27 +00:00
|
|
|
}
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
2020-05-19 09:54:56 +00:00
|
|
|
all_columns.remove(command.column_name);
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
|
|
|
else if (!command.if_exists)
|
2020-02-20 10:04:15 +00:00
|
|
|
throw Exception(
|
|
|
|
"Wrong column name. Cannot find column " + backQuote(command.column_name) + " to drop",
|
|
|
|
ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
|
|
|
else if (command.type == AlterCommand::COMMENT_COLUMN)
|
|
|
|
{
|
2020-05-19 09:54:56 +00:00
|
|
|
if (!all_columns.has(command.column_name))
|
2019-12-26 18:17:05 +00:00
|
|
|
{
|
|
|
|
if (!command.if_exists)
|
2020-02-20 10:04:15 +00:00
|
|
|
throw Exception{"Wrong column name. Cannot find column " + backQuote(command.column_name) + " to comment",
|
|
|
|
ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK};
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-28 12:44:50 +00:00
|
|
|
else if (command.type == AlterCommand::MODIFY_SETTING)
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
if (metadata.settings_changes == nullptr)
|
2020-02-28 12:44:50 +00:00
|
|
|
throw Exception{"Cannot alter settings, because table engine doesn't support settings changes", ErrorCodes::BAD_ARGUMENTS};
|
|
|
|
}
|
2020-03-30 13:34:19 +00:00
|
|
|
else if (command.type == AlterCommand::RENAME_COLUMN)
|
|
|
|
{
|
2020-05-13 17:43:30 +00:00
|
|
|
for (size_t j = i + 1; j < size(); ++j)
|
|
|
|
{
|
|
|
|
auto next_command = (*this)[j];
|
|
|
|
if (next_command.type == AlterCommand::RENAME_COLUMN)
|
|
|
|
{
|
|
|
|
if (next_command.column_name == command.rename_to)
|
2020-05-15 15:11:13 +00:00
|
|
|
throw Exception{"Transitive renames in a single ALTER query are not allowed (don't make sense)",
|
2020-05-13 17:43:30 +00:00
|
|
|
ErrorCodes::NOT_IMPLEMENTED};
|
|
|
|
else if (next_command.column_name == command.column_name)
|
|
|
|
throw Exception{"Cannot rename column '" + backQuote(command.column_name)
|
|
|
|
+ "' to two different names in a single ALTER query",
|
|
|
|
ErrorCodes::BAD_ARGUMENTS};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 16:18:18 +00:00
|
|
|
/// TODO Implement nested rename
|
2020-05-13 17:43:30 +00:00
|
|
|
if (all_columns.hasNested(command.column_name))
|
2020-03-31 16:18:18 +00:00
|
|
|
{
|
|
|
|
throw Exception{"Cannot rename whole Nested struct", ErrorCodes::NOT_IMPLEMENTED};
|
|
|
|
}
|
|
|
|
|
2020-05-13 17:43:30 +00:00
|
|
|
if (!all_columns.has(command.column_name))
|
2020-03-30 13:34:19 +00:00
|
|
|
{
|
|
|
|
if (!command.if_exists)
|
|
|
|
throw Exception{"Wrong column name. Cannot find column " + backQuote(command.column_name) + " to rename",
|
|
|
|
ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK};
|
2020-05-13 17:43:30 +00:00
|
|
|
else
|
|
|
|
continue;
|
2020-03-30 13:34:19 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 17:43:30 +00:00
|
|
|
if (all_columns.has(command.rename_to))
|
2020-03-30 13:34:19 +00:00
|
|
|
throw Exception{"Cannot rename to " + backQuote(command.rename_to) + ": column with this name already exists",
|
|
|
|
ErrorCodes::DUPLICATE_COLUMN};
|
|
|
|
|
2020-05-19 09:54:56 +00:00
|
|
|
if (modified_columns.count(column_name))
|
|
|
|
throw Exception{"Cannot rename and modify the same column " + backQuote(column_name) + " in a single ALTER query",
|
|
|
|
ErrorCodes::NOT_IMPLEMENTED};
|
2020-03-30 13:34:19 +00:00
|
|
|
|
2020-03-31 16:18:18 +00:00
|
|
|
String from_nested_table_name = Nested::extractTableName(command.column_name);
|
|
|
|
String to_nested_table_name = Nested::extractTableName(command.rename_to);
|
|
|
|
bool from_nested = from_nested_table_name != command.column_name;
|
|
|
|
bool to_nested = to_nested_table_name != command.rename_to;
|
|
|
|
|
|
|
|
if (from_nested && to_nested)
|
|
|
|
{
|
|
|
|
if (from_nested_table_name != to_nested_table_name)
|
|
|
|
throw Exception{"Cannot rename column from one nested name to another", ErrorCodes::BAD_ARGUMENTS};
|
|
|
|
}
|
|
|
|
else if (!from_nested && !to_nested)
|
|
|
|
{
|
2020-05-13 17:43:30 +00:00
|
|
|
all_columns.rename(command.column_name, command.rename_to);
|
2020-05-19 09:54:56 +00:00
|
|
|
renamed_columns.emplace(command.column_name);
|
|
|
|
renamed_columns.emplace(command.rename_to);
|
2020-03-31 16:18:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw Exception{"Cannot rename column from nested struct to normal column and vice versa", ErrorCodes::BAD_ARGUMENTS};
|
|
|
|
}
|
2020-03-30 13:34:19 +00:00
|
|
|
}
|
2020-09-20 13:27:33 +00:00
|
|
|
else if (command.type == AlterCommand::REMOVE_TTL && !metadata.hasAnyTableTTL())
|
|
|
|
{
|
|
|
|
throw Exception{"Table doesn't have any table TTL expression, cannot remove", ErrorCodes::BAD_ARGUMENTS};
|
|
|
|
}
|
2020-02-19 12:52:27 +00:00
|
|
|
|
2020-03-03 10:02:43 +00:00
|
|
|
/// Collect default expressions for MODIFY and ADD comands
|
|
|
|
if (command.type == AlterCommand::MODIFY_COLUMN || command.type == AlterCommand::ADD_COLUMN)
|
|
|
|
{
|
|
|
|
if (command.default_expression)
|
|
|
|
{
|
2020-10-12 11:02:35 +00:00
|
|
|
DataTypePtr data_type_ptr;
|
|
|
|
/// If we modify default, but not type.
|
|
|
|
if (!command.data_type) /// it's not ADD COLUMN, because we cannot add column without type
|
|
|
|
data_type_ptr = all_columns.get(column_name).type;
|
2020-03-03 10:02:43 +00:00
|
|
|
else
|
2020-10-12 11:02:35 +00:00
|
|
|
data_type_ptr = command.data_type;
|
2020-02-19 12:52:27 +00:00
|
|
|
|
2020-10-12 11:02:35 +00:00
|
|
|
const auto & final_column_name = column_name;
|
2020-11-02 18:37:23 +00:00
|
|
|
const auto tmp_column_name = final_column_name + "_tmp_alter" + toString(randomSeed());
|
2020-03-03 10:02:43 +00:00
|
|
|
|
2020-10-12 11:02:35 +00:00
|
|
|
default_expr_list->children.emplace_back(setAlias(
|
|
|
|
addTypeConversionToAST(std::make_shared<ASTIdentifier>(tmp_column_name), data_type_ptr->getName()),
|
|
|
|
final_column_name));
|
2020-03-03 10:02:43 +00:00
|
|
|
|
2020-10-12 11:02:35 +00:00
|
|
|
default_expr_list->children.emplace_back(setAlias(command.default_expression->clone(), tmp_column_name));
|
2020-03-03 10:02:43 +00:00
|
|
|
} /// if we change data type for column with default
|
2020-05-19 09:54:56 +00:00
|
|
|
else if (all_columns.has(column_name) && command.data_type)
|
2020-03-03 10:02:43 +00:00
|
|
|
{
|
2020-05-19 09:54:56 +00:00
|
|
|
auto column_in_table = all_columns.get(column_name);
|
2020-03-03 10:02:43 +00:00
|
|
|
/// Column doesn't have a default, nothing to check
|
|
|
|
if (!column_in_table.default_desc.expression)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const auto & final_column_name = column_name;
|
2020-11-02 18:37:23 +00:00
|
|
|
const auto tmp_column_name = final_column_name + "_tmp_alter" + toString(randomSeed());
|
2020-03-03 10:02:43 +00:00
|
|
|
const auto data_type_ptr = command.data_type;
|
|
|
|
|
|
|
|
default_expr_list->children.emplace_back(setAlias(
|
|
|
|
addTypeConversionToAST(std::make_shared<ASTIdentifier>(tmp_column_name), data_type_ptr->getName()), final_column_name));
|
|
|
|
|
|
|
|
default_expr_list->children.emplace_back(setAlias(column_in_table.default_desc.expression->clone(), tmp_column_name));
|
|
|
|
}
|
|
|
|
}
|
2020-02-19 12:52:27 +00:00
|
|
|
}
|
2020-03-03 10:02:43 +00:00
|
|
|
|
2020-07-14 08:19:39 +00:00
|
|
|
if (all_columns.empty())
|
2020-07-13 17:27:52 +00:00
|
|
|
throw Exception{"Cannot DROP or CLEAR all columns", ErrorCodes::BAD_ARGUMENTS};
|
|
|
|
|
2020-03-03 10:02:43 +00:00
|
|
|
validateColumnsDefaultsAndGetSampleBlock(default_expr_list, all_columns.getAll(), context);
|
2020-02-19 12:52:27 +00:00
|
|
|
}
|
2019-08-06 12:52:08 +00:00
|
|
|
|
|
|
|
bool AlterCommands::isSettingsAlter() const
|
|
|
|
{
|
|
|
|
return std::all_of(begin(), end(), [](const AlterCommand & c) { return c.isSettingsAlter(); });
|
|
|
|
}
|
2019-12-27 14:36:59 +00:00
|
|
|
|
|
|
|
bool AlterCommands::isCommentAlter() const
|
|
|
|
{
|
|
|
|
return std::all_of(begin(), end(), [](const AlterCommand & c) { return c.isCommentAlter(); });
|
|
|
|
}
|
2020-01-13 16:39:20 +00:00
|
|
|
|
2020-05-19 01:53:01 +00:00
|
|
|
static MutationCommand createMaterializeTTLCommand()
|
|
|
|
{
|
|
|
|
MutationCommand command;
|
|
|
|
auto ast = std::make_shared<ASTAlterCommand>();
|
|
|
|
ast->type = ASTAlterCommand::MATERIALIZE_TTL;
|
|
|
|
command.type = MutationCommand::MATERIALIZE_TTL;
|
|
|
|
command.ast = std::move(ast);
|
|
|
|
return command;
|
|
|
|
}
|
2020-01-13 16:39:20 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
MutationCommands AlterCommands::getMutationCommands(StorageInMemoryMetadata metadata, bool materialize_ttl, ContextPtr context) const
|
2020-01-13 16:39:20 +00:00
|
|
|
{
|
|
|
|
MutationCommands result;
|
|
|
|
for (const auto & alter_cmd : *this)
|
2020-05-28 12:37:05 +00:00
|
|
|
if (auto mutation_cmd = alter_cmd.tryConvertToMutationCommand(metadata, context); mutation_cmd)
|
2020-01-13 16:39:20 +00:00
|
|
|
result.push_back(*mutation_cmd);
|
2020-05-19 01:53:01 +00:00
|
|
|
|
|
|
|
if (materialize_ttl)
|
|
|
|
{
|
|
|
|
for (const auto & alter_cmd : *this)
|
|
|
|
{
|
2020-09-11 17:07:00 +00:00
|
|
|
if (alter_cmd.isTTLAlter(metadata))
|
2020-05-19 01:53:01 +00:00
|
|
|
{
|
|
|
|
result.push_back(createMaterializeTTLCommand());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-13 16:39:20 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|