mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
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:
commit
6677e0a503
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
25
tests/queries/0_stateless/01355_alter_column_with_order.sql
Normal file
25
tests/queries/0_stateless/01355_alter_column_with_order.sql
Normal 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;
|
Loading…
Reference in New Issue
Block a user