CLICKHOUSE-784: reset merge tree setting

Add an ability to reset custom setting to default and remove it from table's metadata.
This will allow to rollback the change without knowing the system/config's default.

Signed-off-by: Aleksei Semiglazov <asemiglazov@cloudflare.com>
This commit is contained in:
Aleksei Semiglazov 2020-12-02 21:18:25 +00:00
parent 011ed015fa
commit 9a5365fc41
No known key found for this signature in database
GPG Key ID: C003290795D923C4
15 changed files with 204 additions and 6 deletions

View File

@ -66,7 +66,7 @@ enum class AccessType
M(ALTER_TTL, "ALTER MODIFY TTL, MODIFY TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY TTL */\
M(ALTER_MATERIALIZE_TTL, "MATERIALIZE TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MATERIALIZE TTL;
enabled implicitly by the grant ALTER_TABLE */\
M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\
M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING, RESET SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\
M(ALTER_MOVE_PARTITION, "ALTER MOVE PART, MOVE PARTITION, MOVE PART", TABLE, ALTER_TABLE) \
M(ALTER_FETCH_PARTITION, "ALTER FETCH PART, FETCH PARTITION", TABLE, ALTER_TABLE) \
M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION, UNFREEZE", TABLE, ALTER_TABLE) \

View File

@ -269,6 +269,7 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
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);

View File

@ -52,6 +52,11 @@ ASTPtr ASTAlterCommand::clone() const
res->settings_changes = settings_changes->clone();
res->children.push_back(res->settings_changes);
}
if (settings_resets)
{
res->settings_resets = settings_resets->clone();
res->children.push_back(res->settings_resets);
}
if (values)
{
res->values = values->clone();
@ -378,6 +383,11 @@ void ASTAlterCommand::formatImpl(
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "MODIFY SETTING " << (settings.hilite ? hilite_none : "");
settings_changes->formatImpl(settings, state, frame);
}
else if (type == ASTAlterCommand::RESET_SETTING)
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "RESET SETTING " << (settings.hilite ? hilite_none : "");
settings_resets->formatImpl(settings, state, frame);
}
else if (type == ASTAlterCommand::MODIFY_QUERY)
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "MODIFY QUERY " << settings.nl_or_ws << (settings.hilite ? hilite_none : "");

View File

@ -36,6 +36,7 @@ public:
MODIFY_TTL,
MATERIALIZE_TTL,
MODIFY_SETTING,
RESET_SETTING,
MODIFY_QUERY,
REMOVE_TTL,
@ -141,6 +142,9 @@ public:
/// FOR MODIFY_SETTING
ASTPtr settings_changes;
/// FOR RESET_SETTING
ASTPtr settings_resets;
/// For MODIFY_QUERY
ASTPtr select;

View File

@ -33,6 +33,7 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
ParserKeyword s_modify_ttl("MODIFY TTL");
ParserKeyword s_materialize_ttl("MATERIALIZE TTL");
ParserKeyword s_modify_setting("MODIFY SETTING");
ParserKeyword s_reset_setting("RESET SETTING");
ParserKeyword s_modify_query("MODIFY QUERY");
ParserKeyword s_add_index("ADD INDEX");
@ -115,6 +116,9 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
std::make_unique<ParserAssignment>(), std::make_unique<ParserToken>(TokenType::Comma),
/* allow_empty = */ false);
ParserSetQuery parser_settings(true);
ParserList parser_reset_setting(
std::make_unique<ParserIdentifier>(), std::make_unique<ParserToken>(TokenType::Comma),
/* allow_empty = */ false);
ParserNameList values_p;
ParserSelectWithUnionQuery select_p;
ParserTTLExpressionList parser_ttl_list;
@ -703,6 +707,12 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
return false;
command->type = ASTAlterCommand::MODIFY_SETTING;
}
else if (s_reset_setting.ignore(pos, expected))
{
if (!parser_reset_setting.parse(pos, command->settings_resets, expected))
return false;
command->type = ASTAlterCommand::RESET_SETTING;
}
else if (s_modify_query.ignore(pos, expected))
{
if (!select_p.parse(pos, command->select, expected))

View File

@ -15,6 +15,7 @@ namespace DB
* [RENAME COLUMN [IF EXISTS] col_name TO col_name]
* [MODIFY PRIMARY KEY (a, b, c...)]
* [MODIFY SETTING setting_name=setting_value, ...]
* [RESET SETTING setting_name, ...]
* [COMMENT COLUMN [IF EXISTS] col_name string]
* [DROP|DETACH|ATTACH PARTITION|PART partition, ...]
* [FETCH PARTITION partition FROM ...]

View File

@ -311,6 +311,21 @@ std::optional<AlterCommand> AlterCommand::parse(const ASTAlterCommand * command_
command.settings_changes = command_ast->settings_changes->as<ASTSetQuery &>().changes;
return command;
}
else if (command_ast->type == ASTAlterCommand::RESET_SETTING)
{
AlterCommand command;
command.ast = command_ast->clone();
command.type = AlterCommand::RESET_SETTING;
for (const ASTPtr & identifier_ast : command_ast->settings_resets->children)
{
const auto & identifier = identifier_ast->as<ASTIdentifier &>();
auto insertion = command.settings_resets.emplace(identifier.name());
if (!insertion.second)
throw Exception("Duplicate setting name " + backQuote(identifier.name()),
ErrorCodes::BAD_ARGUMENTS);
}
return command;
}
else if (command_ast->type == ASTAlterCommand::MODIFY_QUERY)
{
AlterCommand command;
@ -570,6 +585,20 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context)
settings_from_storage.push_back(change);
}
}
else if (type == RESET_SETTING)
{
auto & settings_from_storage = metadata.settings_changes->as<ASTSetQuery &>().changes;
for (const auto & setting_name : settings_resets)
{
auto finder = [&setting_name](const SettingChange & c) { return c.name == setting_name; };
auto it = std::find_if(settings_from_storage.begin(), settings_from_storage.end(), finder);
if (it != settings_from_storage.end())
settings_from_storage.erase(it);
/// Intentionally ignore if there is no such setting name
}
}
else if (type == RENAME_COLUMN)
{
metadata.columns.rename(column_name, rename_to);
@ -678,7 +707,7 @@ bool isMetadataOnlyConversion(const IDataType * from, const IDataType * to)
bool AlterCommand::isSettingsAlter() const
{
return type == MODIFY_SETTING;
return type == MODIFY_SETTING || type == RESET_SETTING;
}
bool AlterCommand::isRequireMutationStage(const StorageInMemoryMetadata & metadata) const
@ -838,6 +867,8 @@ String alterTypeToString(const AlterCommand::Type type)
return "MODIFY TTL";
case AlterCommand::Type::MODIFY_SETTING:
return "MODIFY SETTING";
case AlterCommand::Type::RESET_SETTING:
return "RESET SETTING";
case AlterCommand::Type::MODIFY_QUERY:
return "MODIFY QUERY";
case AlterCommand::Type::RENAME_COLUMN:
@ -1123,7 +1154,7 @@ void AlterCommands::validate(const StorageInMemoryMetadata & metadata, ContextPt
ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK};
}
}
else if (command.type == AlterCommand::MODIFY_SETTING)
else if (command.type == AlterCommand::MODIFY_SETTING || command.type == AlterCommand::RESET_SETTING)
{
if (metadata.settings_changes == nullptr)
throw Exception{"Cannot alter settings, because table engine doesn't support settings changes", ErrorCodes::BAD_ARGUMENTS};

View File

@ -38,6 +38,7 @@ struct AlterCommand
DROP_PROJECTION,
MODIFY_TTL,
MODIFY_SETTING,
RESET_SETTING,
MODIFY_QUERY,
RENAME_COLUMN,
REMOVE_TTL,
@ -80,7 +81,7 @@ struct AlterCommand
/// For ADD_COLUMN, MODIFY_COLUMN - Add to the begin if it is true.
bool first = false;
/// For DROP_COLUMN, MODIFY_COLUMN, COMMENT_COLUMN
/// For DROP_COLUMN, MODIFY_COLUMN, COMMENT_COLUMN, RESET_SETTING
bool if_exists = false;
/// For ADD_COLUMN
@ -127,6 +128,9 @@ struct AlterCommand
/// For MODIFY SETTING
SettingsChanges settings_changes;
/// For RESET SETTING
std::set<String> settings_resets;
/// For MODIFY_QUERY
ASTPtr select = nullptr;

View File

@ -1802,6 +1802,31 @@ void MergeTreeData::checkAlterIsPossible(const AlterCommands & commands, Context
if (setting_name == "storage_policy")
checkStoragePolicy(getContext()->getStoragePolicy(new_value.safeGet<String>()));
}
/// Check if it is safe to reset the settings
for (const auto & current_setting : current_changes)
{
const auto & setting_name = current_setting.name;
const Field * new_value = new_changes.tryGet(setting_name);
/// Prevent unsetting readonly setting
if (MergeTreeSettings::isReadonlySetting(setting_name) && !new_value)
{
throw Exception{"Setting '" + setting_name + "' is readonly for storage '" + getName() + "'",
ErrorCodes::READONLY_SETTING};
}
if (MergeTreeSettings::isPartFormatSetting(setting_name) && !new_value)
{
/// Use default settings + new and check if doesn't affect part format settings
MergeTreeSettings copy = *getSettings();
copy.resetToDefault();
copy.applyChanges(new_changes);
String reason;
if (!canUsePolymorphicParts(copy, &reason) && !reason.empty())
throw Exception("Can't change settings. Reason: " + reason, ErrorCodes::NOT_IMPLEMENTED);
}
}
}
for (const auto & part : getDataPartsVector())
@ -1960,6 +1985,8 @@ void MergeTreeData::changeSettings(
}
MergeTreeSettings copy = *getSettings();
/// reset to default settings before applying existing
copy.resetToDefault();
copy.applyChanges(new_changes);
copy.sanityCheck(getContext()->getSettingsRef());

View File

@ -4,3 +4,9 @@ CREATE TABLE default.table_for_alter\n(\n `id` UInt64,\n `Data` String\n)\
2
CREATE TABLE default.table_for_alter\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096, parts_to_throw_insert = 100, parts_to_delay_insert = 100, check_delay_period = 30
CREATE TABLE default.table_for_alter\n(\n `id` UInt64,\n `Data` String,\n `Data2` UInt64\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096, parts_to_throw_insert = 100, parts_to_delay_insert = 100, check_delay_period = 15
CREATE TABLE default.table_for_reset_setting\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096
CREATE TABLE default.table_for_reset_setting\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096, parts_to_throw_insert = 1, parts_to_delay_insert = 1
CREATE TABLE default.table_for_reset_setting\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096
CREATE TABLE default.table_for_reset_setting\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096
CREATE TABLE default.table_for_reset_setting\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096, merge_with_ttl_timeout = 300, max_concurrent_queries = 1
CREATE TABLE default.table_for_reset_setting\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = MergeTree\nORDER BY id\nSETTINGS index_granularity = 4096

View File

@ -53,3 +53,50 @@ SHOW CREATE TABLE table_for_alter;
DROP TABLE IF EXISTS table_for_alter;
DROP TABLE IF EXISTS table_for_reset_setting;
CREATE TABLE table_for_reset_setting (
id UInt64,
Data String
) ENGINE = MergeTree() ORDER BY id SETTINGS index_granularity=4096;
ALTER TABLE table_for_reset_setting MODIFY SETTING index_granularity=555; -- { serverError 472 }
SHOW CREATE TABLE table_for_reset_setting;
INSERT INTO table_for_reset_setting VALUES (1, '1');
INSERT INTO table_for_reset_setting VALUES (2, '2');
ALTER TABLE table_for_reset_setting MODIFY SETTING parts_to_throw_insert = 1, parts_to_delay_insert = 1;
SHOW CREATE TABLE table_for_reset_setting;
INSERT INTO table_for_reset_setting VALUES (1, '1'); -- { serverError 252 }
ALTER TABLE table_for_reset_setting RESET SETTING parts_to_delay_insert, parts_to_throw_insert;
SHOW CREATE TABLE table_for_reset_setting;
INSERT INTO table_for_reset_setting VALUES (1, '1');
INSERT INTO table_for_reset_setting VALUES (2, '2');
DETACH TABLE table_for_reset_setting;
ATTACH TABLE table_for_reset_setting;
SHOW CREATE TABLE table_for_reset_setting;
ALTER TABLE table_for_reset_setting RESET SETTING index_granularity; -- { serverError 472 }
-- ignore undefined setting
ALTER TABLE table_for_reset_setting RESET SETTING merge_with_ttl_timeout, unknown_setting;
ALTER TABLE table_for_reset_setting MODIFY SETTING merge_with_ttl_timeout = 300, max_concurrent_queries = 1;
SHOW CREATE TABLE table_for_reset_setting;
ALTER TABLE table_for_reset_setting RESET SETTING max_concurrent_queries, merge_with_ttl_timeout;
SHOW CREATE TABLE table_for_reset_setting;
DROP TABLE IF EXISTS table_for_reset_setting;

View File

@ -10,3 +10,12 @@ CREATE TABLE default.replicated_table_for_alter1\n(\n `id` UInt64,\n `Data
CREATE TABLE default.replicated_table_for_alter2\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_alter\', \'2\')\nORDER BY id\nSETTINGS index_granularity = 8192, parts_to_throw_insert = 1, parts_to_delay_insert = 1
CREATE TABLE default.replicated_table_for_alter1\n(\n `id` UInt64,\n `Data` String,\n `Data2` UInt64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_alter\', \'1\')\nORDER BY id\nSETTINGS index_granularity = 8192, use_minimalistic_part_header_in_zookeeper = 1, check_delay_period = 15
CREATE TABLE default.replicated_table_for_alter2\n(\n `id` UInt64,\n `Data` String,\n `Data2` UInt64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_alter\', \'2\')\nORDER BY id\nSETTINGS index_granularity = 8192, parts_to_throw_insert = 1, parts_to_delay_insert = 1
CREATE TABLE default.replicated_table_for_reset_setting1\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'1\')\nORDER BY id\nSETTINGS index_granularity = 8192
CREATE TABLE default.replicated_table_for_reset_setting2\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'2\')\nORDER BY id\nSETTINGS index_granularity = 8192
CREATE TABLE default.replicated_table_for_reset_setting1\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'1\')\nORDER BY id\nSETTINGS index_granularity = 8192
CREATE TABLE default.replicated_table_for_reset_setting1\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'1\')\nORDER BY id\nSETTINGS index_granularity = 8192, merge_with_ttl_timeout = 100
CREATE TABLE default.replicated_table_for_reset_setting2\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'2\')\nORDER BY id\nSETTINGS index_granularity = 8192, merge_with_ttl_timeout = 200
CREATE TABLE default.replicated_table_for_reset_setting1\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'1\')\nORDER BY id\nSETTINGS index_granularity = 8192, merge_with_ttl_timeout = 100
CREATE TABLE default.replicated_table_for_reset_setting2\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'2\')\nORDER BY id\nSETTINGS index_granularity = 8192, merge_with_ttl_timeout = 200
CREATE TABLE default.replicated_table_for_reset_setting1\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'1\')\nORDER BY id\nSETTINGS index_granularity = 8192
CREATE TABLE default.replicated_table_for_reset_setting2\n(\n `id` UInt64,\n `Data` String\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test_00980/replicated_table_for_reset_setting\', \'2\')\nORDER BY id\nSETTINGS index_granularity = 8192

View File

@ -67,3 +67,51 @@ SHOW CREATE TABLE replicated_table_for_alter2;
DROP TABLE IF EXISTS replicated_table_for_alter2;
DROP TABLE IF EXISTS replicated_table_for_alter1;
DROP TABLE IF EXISTS replicated_table_for_reset_setting1;
DROP TABLE IF EXISTS replicated_table_for_reset_setting2;
SET replication_alter_partitions_sync = 2;
CREATE TABLE replicated_table_for_reset_setting1 (
id UInt64,
Data String
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/test_00980/replicated_table_for_reset_setting', '1') ORDER BY id;
CREATE TABLE replicated_table_for_reset_setting2 (
id UInt64,
Data String
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/test_00980/replicated_table_for_reset_setting', '2') ORDER BY id;
SHOW CREATE TABLE replicated_table_for_reset_setting1;
SHOW CREATE TABLE replicated_table_for_reset_setting2;
ALTER TABLE replicated_table_for_reset_setting1 MODIFY SETTING index_granularity = 4096; -- { serverError 472 }
SHOW CREATE TABLE replicated_table_for_reset_setting1;
ALTER TABLE replicated_table_for_reset_setting1 MODIFY SETTING merge_with_ttl_timeout = 100;
ALTER TABLE replicated_table_for_reset_setting2 MODIFY SETTING merge_with_ttl_timeout = 200;
SHOW CREATE TABLE replicated_table_for_reset_setting1;
SHOW CREATE TABLE replicated_table_for_reset_setting2;
DETACH TABLE replicated_table_for_reset_setting2;
ATTACH TABLE replicated_table_for_reset_setting2;
DETACH TABLE replicated_table_for_reset_setting1;
ATTACH TABLE replicated_table_for_reset_setting1;
SHOW CREATE TABLE replicated_table_for_reset_setting1;
SHOW CREATE TABLE replicated_table_for_reset_setting2;
-- ignore undefined setting
ALTER TABLE replicated_table_for_reset_setting1 RESET SETTING check_delay_period, unknown_setting;
ALTER TABLE replicated_table_for_reset_setting1 RESET SETTING merge_with_ttl_timeout;
ALTER TABLE replicated_table_for_reset_setting2 RESET SETTING merge_with_ttl_timeout;
SHOW CREATE TABLE replicated_table_for_reset_setting1;
SHOW CREATE TABLE replicated_table_for_reset_setting2;
DROP TABLE IF EXISTS replicated_table_for_reset_setting2;
DROP TABLE IF EXISTS replicated_table_for_reset_setting1;

View File

@ -31,7 +31,7 @@ ALTER DROP CONSTRAINT ['DROP CONSTRAINT'] TABLE ALTER CONSTRAINT
ALTER CONSTRAINT ['CONSTRAINT'] \N ALTER TABLE
ALTER TTL ['ALTER MODIFY TTL','MODIFY TTL'] TABLE ALTER TABLE
ALTER MATERIALIZE TTL ['MATERIALIZE TTL'] TABLE ALTER TABLE
ALTER SETTINGS ['ALTER SETTING','ALTER MODIFY SETTING','MODIFY SETTING'] TABLE ALTER TABLE
ALTER SETTINGS ['ALTER SETTING','ALTER MODIFY SETTING','MODIFY SETTING','RESET SETTING'] TABLE ALTER TABLE
ALTER MOVE PARTITION ['ALTER MOVE PART','MOVE PARTITION','MOVE PART'] TABLE ALTER TABLE
ALTER FETCH PARTITION ['ALTER FETCH PART','FETCH PARTITION'] TABLE ALTER TABLE
ALTER FREEZE PARTITION ['FREEZE PARTITION','UNFREEZE'] TABLE ALTER TABLE

View File

@ -1,6 +1,6 @@
AlterQuery t1 (children 1)
ExpressionList (children 1)
AlterCommand 30 (children 1)
AlterCommand 31 (children 1)
Function equals (children 1)
ExpressionList (children 2)
Identifier date