ISSUES-4006 support first for ALTER ADD|MODIFY COLUMN by zhang2014 · Pull Request #12073 · ClickHouse/ClickHouse · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/Parsers/ASTAlterQuery.cpp
4 changes: 3 additions & 1 deletion src/Parsers/ASTAlterQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class ASTAlterCommand : public IAST
*/
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.
*/
Expand Down Expand Up @@ -136,6 +136,8 @@ class ASTAlterCommand : public IAST

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
Expand Down
13 changes: 12 additions & 1 deletion src/Parsers/ParserAlterQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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))
Expand Down
9 changes: 7 additions & 2 deletions src/Storages/AlterCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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)
{
Expand Down
5 changes: 4 additions & 1 deletion src/Storages/AlterCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
38 changes: 36 additions & 2 deletions src/Storages/ColumnsDescription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,17 @@ 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",
ErrorCodes::ILLEGAL_COLUMN);

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)
Expand Down Expand Up @@ -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()
{
Expand Down
14 changes: 13 additions & 1 deletion src/Storages/ColumnsDescription.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -52,7 +54,7 @@ class ColumnsDescription
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);

Expand Down Expand Up @@ -84,12 +86,20 @@ class ColumnsDescription

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;
Expand Down Expand Up @@ -120,6 +130,8 @@ class ColumnsDescription

private:
Container columns;

void modifyColumnOrder(const String & column_name, const String & after_column, bool first);
};

/// Validate default expressions and corresponding types compatibility, i.e.
Expand Down
40 changes: 40 additions & 0 deletions tests/queries/0_stateless/01355_alter_column_with_order.reference
Original file line number Diff line number Diff line change
@@ -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 changes: 25 additions & 0 deletions tests/queries/0_stateless/01355_alter_column_with_order.sql