Merge pull request #12073 from zhang2014/feature/atfer_column_modify_column

ISSUES-4006 support first for ALTER ADD|MODIFY COLUMN
This commit is contained in:
alexey-milovidov 2020-07-03 22:54:05 +03:00 committed by GitHub
commit 6677e0a503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 151 additions and 10 deletions

View File

@ -75,8 +75,9 @@ void ASTAlterCommand::formatImpl(
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "ADD COLUMN " << (if_not_exists ? "IF NOT EXISTS " : "") << (settings.hilite ? hilite_none : "");
col_decl->formatImpl(settings, state, frame);
/// AFTER
if (column)
if (first)
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << " FIRST " << (settings.hilite ? hilite_none : "");
else if (column) /// AFTER
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << " AFTER " << (settings.hilite ? hilite_none : "");
column->formatImpl(settings, state, frame);
@ -97,6 +98,14 @@ void ASTAlterCommand::formatImpl(
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "MODIFY COLUMN " << (if_exists ? "IF EXISTS " : "") << (settings.hilite ? hilite_none : "");
col_decl->formatImpl(settings, state, frame);
if (first)
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << " FIRST " << (settings.hilite ? hilite_none : "");
else if (column) /// AFTER
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << " AFTER " << (settings.hilite ? hilite_none : "");
column->formatImpl(settings, state, frame);
}
}
else if (type == ASTAlterCommand::COMMENT_COLUMN)
{

View File

@ -68,7 +68,7 @@ public:
*/
ASTPtr col_decl;
/** The ADD COLUMN query here optionally stores the name of the column following AFTER
/** The ADD COLUMN and MODIFY COLUMN query here optionally stores the name of the column following AFTER
* The DROP query stores the column name for deletion here
* Also used for RENAME COLUMN.
*/
@ -136,6 +136,8 @@ public:
bool if_exists = false; /// option for DROP_COLUMN, MODIFY_COLUMN, COMMENT_COLUMN
bool first = false; /// option for ADD_COLUMN, MODIFY_COLUMN
DataDestinationType move_destination_type; /// option for MOVE PART/PARTITION
String move_destination_name; /// option for MOVE PART/PARTITION

View File

@ -63,6 +63,7 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
ParserKeyword s_freeze("FREEZE");
ParserKeyword s_partition("PARTITION");
ParserKeyword s_first("FIRST");
ParserKeyword s_after("AFTER");
ParserKeyword s_if_not_exists("IF NOT EXISTS");
ParserKeyword s_if_exists("IF EXISTS");
@ -115,7 +116,9 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
if (!parser_col_decl.parse(pos, command->col_decl, expected))
return false;
if (s_after.ignore(pos, expected))
if (s_first.ignore(pos, expected))
command->first = true;
else if (s_after.ignore(pos, expected))
{
if (!parser_name.parse(pos, command->column, expected))
return false;
@ -429,6 +432,14 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
if (!parser_modify_col_decl.parse(pos, command->col_decl, expected))
return false;
if (s_first.ignore(pos, expected))
command->first = true;
else if (s_after.ignore(pos, expected))
{
if (!parser_name.parse(pos, command->column, expected))
return false;
}
command->type = ASTAlterCommand::MODIFY_COLUMN;
}
else if (s_modify_order_by.ignore(pos, expected))

View File

@ -83,6 +83,7 @@ std::optional<AlterCommand> AlterCommand::parse(const ASTAlterCommand * command_
if (ast_col_decl.ttl)
command.ttl = ast_col_decl.ttl;
command.first = command_ast->first;
command.if_not_exists = command_ast->if_not_exists;
return command;
@ -133,6 +134,10 @@ std::optional<AlterCommand> AlterCommand::parse(const ASTAlterCommand * command_
if (ast_col_decl.codec)
command.codec = compression_codec_factory.get(ast_col_decl.codec, command.data_type, sanity_check_compression_codecs);
if (command_ast->column)
command.after_column = getIdentifierName(command_ast->column);
command.first = command_ast->first;
command.if_exists = command_ast->if_exists;
return command;
@ -269,7 +274,7 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, const Context & con
column.codec = codec;
column.ttl = ttl;
metadata.columns.add(column, after_column);
metadata.columns.add(column, after_column, first);
/// Slow, because each time a list is copied
metadata.columns.flattenNested();
@ -282,7 +287,7 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, const Context & con
}
else if (type == MODIFY_COLUMN)
{
metadata.columns.modify(column_name, [&](ColumnDescription & column)
metadata.columns.modify(column_name, after_column, first, [&](ColumnDescription & column)
{
if (codec)
{

View File

@ -54,9 +54,12 @@ struct AlterCommand
/// For COMMENT column
std::optional<String> comment;
/// For ADD - after which column to add a new one. If an empty string, add to the end. To add to the beginning now it is impossible.
/// For ADD or MODIFY - after which column to add a new one. If an empty string, add to the end.
String after_column;
/// For ADD_COLUMN, MODIFY_COLUMN - Add to the begin if it is true.
bool first = false;
/// For DROP_COLUMN, MODIFY_COLUMN, COMMENT_COLUMN
bool if_exists = false;

View File

@ -167,7 +167,7 @@ static auto getNameRange(const ColumnsDescription::Container & columns, const St
return std::make_pair(begin, end);
}
void ColumnsDescription::add(ColumnDescription column, const String & after_column)
void ColumnsDescription::add(ColumnDescription column, const String & after_column, bool first)
{
if (has(column.name))
throw Exception("Cannot add column " + column.name + ": column with this name already exists",
@ -175,7 +175,9 @@ void ColumnsDescription::add(ColumnDescription column, const String & after_colu
auto insert_it = columns.cend();
if (!after_column.empty())
if (first)
insert_it = columns.cbegin();
else if (!after_column.empty())
{
auto range = getNameRange(columns, after_column);
if (range.first == range.second)
@ -211,6 +213,38 @@ void ColumnsDescription::rename(const String & column_from, const String & colum
});
}
void ColumnsDescription::modifyColumnOrder(const String & column_name, const String & after_column, bool first)
{
const auto & reorder_column = [&](auto get_new_pos)
{
auto column_range = getNameRange(columns, column_name);
if (column_range.first == column_range.second)
throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
std::vector<ColumnDescription> moving_columns;
for (auto list_it = column_range.first; list_it != column_range.second;)
{
moving_columns.emplace_back(*list_it);
list_it = columns.get<0>().erase(list_it);
}
columns.get<0>().insert(get_new_pos(), moving_columns.begin(), moving_columns.end());
};
if (first)
reorder_column([&]() { return columns.cbegin(); });
else if (!after_column.empty() && column_name != after_column)
{
/// Checked first
auto range = getNameRange(columns, after_column);
if (range.first == range.second)
throw Exception("Wrong column name. Cannot find column " + after_column + " to insert after",
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
reorder_column([&]() { return getNameRange(columns, after_column).second; });
}
}
void ColumnsDescription::flattenNested()
{

View File

@ -34,6 +34,8 @@ struct ColumnDescription
ASTPtr ttl;
ColumnDescription() = default;
ColumnDescription(ColumnDescription &&) = default;
ColumnDescription(const ColumnDescription &) = default;
ColumnDescription(String name_, DataTypePtr type_);
bool operator==(const ColumnDescription & other) const;
@ -52,7 +54,7 @@ public:
explicit ColumnsDescription(NamesAndTypesList ordinary_);
/// `after_column` can be a Nested column name;
void add(ColumnDescription column, const String & after_column = String());
void add(ColumnDescription column, const String & after_column = String(), bool first = false);
/// `column_name` can be a Nested column name;
void remove(const String & column_name);
@ -84,12 +86,20 @@ public:
template <typename F>
void modify(const String & column_name, F && f)
{
modify(column_name, String(), false, std::forward<F>(f));
}
template <typename F>
void modify(const String & column_name, const String & after_column, bool first, F && f)
{
auto it = columns.get<1>().find(column_name);
if (it == columns.get<1>().end())
throw Exception("Cannot find column " + column_name + " in ColumnsDescription", ErrorCodes::LOGICAL_ERROR);
if (!columns.get<1>().modify(it, std::forward<F>(f)))
throw Exception("Cannot modify ColumnDescription for column " + column_name + ": column name cannot be changed", ErrorCodes::LOGICAL_ERROR);
modifyColumnOrder(column_name, after_column, first);
}
Names getNamesOfPhysical() const;
@ -120,6 +130,8 @@ public:
private:
Container columns;
void modifyColumnOrder(const String & column_name, const String & after_column, bool first);
};
/// Validate default expressions and corresponding types compatibility, i.e.

View File

@ -0,0 +1,40 @@
Added1 UInt32
CounterID UInt32
StartDate Date
UserID UInt32
VisitID UInt32
NestedColumn.A Array(UInt8)
NestedColumn.S Array(String)
Added2 UInt32
ToDrop UInt32
Added3 UInt32
Added1 UInt32
CounterID UInt32
StartDate Date
UserID UInt32
VisitID UInt32
NestedColumn.A Array(UInt8)
NestedColumn.S Array(String)
Added2 UInt32
ToDrop UInt32
Added3 UInt32
Added2 UInt32
Added1 UInt32
CounterID UInt32
Added3 UInt32
StartDate Date
UserID UInt32
VisitID UInt32
NestedColumn.A Array(UInt8)
NestedColumn.S Array(String)
ToDrop UInt32
Added2 UInt32
Added1 UInt32
CounterID UInt32
Added3 UInt32
StartDate Date
UserID UInt32
VisitID UInt32
NestedColumn.A Array(UInt8)
NestedColumn.S Array(String)
ToDrop UInt32

View File

@ -0,0 +1,25 @@
DROP TABLE IF EXISTS alter_test;
CREATE TABLE alter_test (CounterID UInt32, StartDate Date, UserID UInt32, VisitID UInt32, NestedColumn Nested(A UInt8, S String), ToDrop UInt32) ENGINE = MergeTree(StartDate, intHash32(UserID), (CounterID, StartDate, intHash32(UserID), VisitID), 8192);
ALTER TABLE alter_test ADD COLUMN Added1 UInt32 FIRST;
ALTER TABLE alter_test ADD COLUMN Added2 UInt32 AFTER NestedColumn;
ALTER TABLE alter_test ADD COLUMN Added3 UInt32 AFTER ToDrop;
DESC alter_test;
DETACH TABLE alter_test;
ATTACH TABLE alter_test;
DESC alter_test;
ALTER TABLE alter_test MODIFY COLUMN Added2 UInt32 FIRST;
ALTER TABLE alter_test MODIFY COLUMN Added3 UInt32 AFTER CounterID;
DESC alter_test;
DETACH TABLE alter_test;
ATTACH TABLE alter_test;
DESC alter_test;
DROP TABLE IF EXISTS alter_test;