diff --git a/src/Functions/validateNestedArraySizes.cpp b/src/Functions/validateNestedArraySizes.cpp index 6b651ec933e..b589b1e2e5c 100644 --- a/src/Functions/validateNestedArraySizes.cpp +++ b/src/Functions/validateNestedArraySizes.cpp @@ -73,16 +73,16 @@ ColumnPtr FunctionValidateNestedArraySizes::executeImpl( size_t length = 0; for (size_t args_idx = 1; args_idx < args_num; ++args_idx) { - ColumnWithTypeAndName current_arg = arguments[args_idx]; + const auto & current_arg = arguments[args_idx]; const ColumnArray * current_column = nullptr; - if (const auto *const_array = checkAndGetColumnConst(current_arg.column.get())) + if (const auto * const_array = checkAndGetColumnConst(current_arg.column.get())) { current_column = checkAndGetColumn(&const_array->getDataColumn()); length = current_column->getOffsets()[0]; } else { - current_column = typeid_cast(current_arg.column.get()); + current_column = checkAndGetColumn(current_arg.column.get()); const auto & offsets = current_column->getOffsets(); length = offsets[i] - offsets[i - 1]; } @@ -102,12 +102,7 @@ ColumnPtr FunctionValidateNestedArraySizes::executeImpl( } } - auto res = ColumnUInt8::create(input_rows_count); - auto & vec_res = res->getData(); - for (size_t row_num = 0; row_num < input_rows_count; ++row_num) - vec_res[row_num] = 1; - - return res; + return ColumnUInt8::create(input_rows_count, 1); } void registerFunctionValidateNestedArraySizes(FunctionFactory & factory) diff --git a/src/Interpreters/MutationsInterpreter.cpp b/src/Interpreters/MutationsInterpreter.cpp index d403352019c..1315f9efa05 100644 --- a/src/Interpreters/MutationsInterpreter.cpp +++ b/src/Interpreters/MutationsInterpreter.cpp @@ -350,33 +350,34 @@ static void validateUpdateColumns( } } -std::pair> getFullNestedSubColumnUpdatedExpr( - const String & column, - NamesAndTypesList & all_columns, - std::unordered_map & column_to_update_expression) +/// Returns ASTs of updated nested subcolumns, if all of subcolumns were updated. +/// They are used to validate sizes of nested arrays. +/// If some of subcolumns were updated and some weren't, +/// it makes sense to validate only updated columns with their old versions, +/// because their sizes couldn't change, since sizes of all nested subcolumns must be consistent. +static std::optional> getExpressionsOfUpdatedNestedSubcolumns( + const String & column_name, + const NamesAndTypesList & all_columns, + const std::unordered_map & column_to_update_expression) { std::vector res; - auto source_name = Nested::splitName(column).first; + auto source_name = Nested::splitName(column_name).first; /// Check this nested subcolumn - for (const auto & it : all_columns) + for (const auto & column : all_columns) { - auto split = Nested::splitName(it.name); - if (split.first == source_name && !split.second.empty()) + auto split = Nested::splitName(column.name); + if (isArray(column.type) && split.first == source_name && !split.second.empty()) { - if (column_to_update_expression.find(it.name) == column_to_update_expression.end()) - { - /// Update partial nested subcolumns - return std::make_pair(false, res); - } - else - { - res.push_back(column_to_update_expression[it.name]); - } + auto it = column_to_update_expression.find(column.name); + if (it == column_to_update_expression.end()) + return {}; + + res.push_back(it->second); } } - return std::make_pair(true, res); + return res; } ASTPtr MutationsInterpreter::prepare(bool dry_run) @@ -467,19 +468,20 @@ ASTPtr MutationsInterpreter::prepare(bool dry_run) /// /// Outer CAST is added just in case if we don't trust the returning type of 'if'. - auto type_literal = std::make_shared(columns_desc.getPhysical(column).type->getName()); + const auto & type = columns_desc.getPhysical(column).type; + auto type_literal = std::make_shared(type->getName()); const auto & update_expr = kv.second; ASTPtr condition = getPartitionAndPredicateExpressionForMutationCommand(command); /// And new check validateNestedArraySizes for Nested subcolumns - if (!Nested::splitName(column).second.empty()) + if (isArray(type) && !Nested::splitName(column).second.empty()) { std::shared_ptr function = nullptr; - auto nested_update_exprs = getFullNestedSubColumnUpdatedExpr(column, all_columns, command.column_to_update_expression); - if (!nested_update_exprs.first) + auto nested_update_exprs = getExpressionsOfUpdatedNestedSubcolumns(column, all_columns, command.column_to_update_expression); + if (!nested_update_exprs) { function = makeASTFunction("validateNestedArraySizes", condition, @@ -487,14 +489,14 @@ ASTPtr MutationsInterpreter::prepare(bool dry_run) std::make_shared(column)); condition = makeASTFunction("and", condition, function); } - else if (nested_update_exprs.second.size() > 1) + else if (nested_update_exprs->size() > 1) { function = std::make_shared(); function->name = "validateNestedArraySizes"; function->arguments = std::make_shared(); function->children.push_back(function->arguments); function->arguments->children.push_back(condition); - for (const auto & it : nested_update_exprs.second) + for (const auto & it : *nested_update_exprs) function->arguments->children.push_back(it->clone()); condition = makeASTFunction("and", condition, function); } diff --git a/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp b/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp index a1691fe7931..57e8cca46cd 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp +++ b/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace DB { @@ -393,8 +394,9 @@ void MergeTreeDataPartWriterWide::validateColumnOfFixedSize(const String & name, throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot validate column of non fixed type {}", type.getName()); auto disk = data_part->volume->getDisk(); - String mrk_path = fullPath(disk, part_path + name + marks_file_extension); - String bin_path = fullPath(disk, part_path + name + DATA_FILE_EXTENSION); + String escaped_name = escapeForFileName(name); + String mrk_path = fullPath(disk, part_path + escaped_name + marks_file_extension); + String bin_path = fullPath(disk, part_path + escaped_name + DATA_FILE_EXTENSION); DB::ReadBufferFromFile mrk_in(mrk_path); DB::CompressedReadBufferFromFile bin_in(bin_path, 0, 0, 0, nullptr); bool must_be_last = false; diff --git a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference index ffa2b2a735f..c6f75cab8b7 100644 --- a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference +++ b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference @@ -4,10 +4,6 @@ 2 [100,200,300] ['a','b','c'] [10,20,30] 3 [3,4] ['aa','bb'] [3,6] 4 [4,5] ['aa','bb'] [4,8] -waiting default test_wide_nested mutation_2.txt UPDATE `info.id` = [100, 200] WHERE id = 1 -waiting default test_wide_nested mutation_3.txt UPDATE `info.id` = [100, 200, 300], `info.age` = [10, 20, 30], `info.name` = [\'a\', \'b\', \'c\'] WHERE id = 2 -waiting default test_wide_nested mutation_4.txt UPDATE `info.id` = [100, 200], `info.age` = [10, 20, 30], `info.name` = [\'a\', \'b\', \'c\'] WHERE id = 0 -waiting default test_wide_nested mutation_5.txt UPDATE `info.id` = [100, 200, 300], `info.age` = [10, 20, 30] WHERE id = 1 0 [0,1] ['aa','bb'] [0,0] 1 [100,200] ['aa','bb'] [1,2] 2 [100,200,300] ['a','b','c'] [100,200,300] @@ -18,3 +14,8 @@ waiting default test_wide_nested mutation_5.txt UPDATE `info.id` = [100, 200, 30 2 [100,200,300] ['a','b','c'] [100,200,300] 3 [68,72] ['aa','bb'] [68,72] 4 [4,5] ['aa','bb'] [4,8] +0 0 aa 0 +1 1 bb 2 +2 2 aa 4 +3 3 aa 6 +4 4 aa 8 diff --git a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql index 45345da2ff1..8e850b70c24 100644 --- a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql +++ b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql @@ -1,4 +1,3 @@ -USE default; DROP TABLE IF EXISTS test_wide_nested; CREATE TABLE test_wide_nested @@ -12,19 +11,60 @@ ENGINE = MergeTree ORDER BY tuple() SETTINGS min_bytes_for_wide_part = 0; -INSERT INTO test_wide_nested SELECT number, [number,number+1] , ['aa','bb'],[number, number*2] FROM numbers(5); +set mutations_sync = 1; -alter table test_wide_nested update `info.id` =[100,200] where id = 1 settings mutations_sync=1; -select * from test_wide_nested where id = 1; -alter table test_wide_nested update `info.id` =[100,200,300], `info.age`=[10,20,30], `info.name`=['a','b','c'] where id = 2 settings mutations_sync=1; +INSERT INTO test_wide_nested SELECT number, [number,number + 1], ['aa','bb'], [number,number * 2] FROM numbers(5); + +alter table test_wide_nested update `info.id` = [100,200] where id = 1; +select * from test_wide_nested where id = 1 order by id; + +alter table test_wide_nested update `info.id` = [100,200,300], `info.age` = [10,20,30], `info.name` = ['a','b','c'] where id = 2; select * from test_wide_nested; -alter table test_wide_nested update `info.id` =[100,200], `info.age`=[10,20,30], `info.name`=['a','b','c'] where id = 0 settings mutations_sync=1; -- { serverError 341 } -kill mutation where table = 'test_wide_nested'; -alter table test_wide_nested update `info.id` =[100,200,300], `info.age`=[10,20,30] where id = 1 settings mutations_sync=1; -- { serverError 341 } -kill mutation where table = 'test_wide_nested'; -alter table test_wide_nested update `info.id` =[100,200,300], `info.age`=`info.id`, `info.name`=['a','b','c'] where id = 2 settings mutations_sync=1; + +alter table test_wide_nested update `info.id` = [100,200,300], `info.age` = `info.id`, `info.name` = ['a','b','c'] where id = 2; select * from test_wide_nested; -alter table test_wide_nested update `info.id` =[100,200], `info.age`=[68,72] where id = 3 settings mutations_sync=1; -alter table test_wide_nested update `info.id` = `info.age` where id = 3 settings mutations_sync=1; + +alter table test_wide_nested update `info.id` = [100,200], `info.age`=[68,72] where id = 3; +alter table test_wide_nested update `info.id` = `info.age` where id = 3; select * from test_wide_nested; + +alter table test_wide_nested update `info.id` = [100,200], `info.age` = [10,20,30], `info.name` = ['a','b','c'] where id = 0; -- { serverError 341 } + +-- Recreate table, because KILL MUTATION is not suitable for parallel tests execution. DROP TABLE test_wide_nested; + +CREATE TABLE test_wide_nested +( + `id` Int, + `info.id` Array(Int), + `info.name` Array(String), + `info.age` Array(Int) +) +ENGINE = MergeTree +ORDER BY tuple() +SETTINGS min_bytes_for_wide_part = 0; + +INSERT INTO test_wide_nested SELECT number, [number,number + 1], ['aa','bb'], [number,number * 2] FROM numbers(5); + +alter table test_wide_nested update `info.id` = [100,200,300], `info.age` = [10,20,30] where id = 1; -- { serverError 341 } + +DROP TABLE test_wide_nested; + +DROP TABLE IF EXISTS test_wide_not_nested; + +CREATE TABLE test_wide_not_nested +( + `id` Int, + `info.id` Int, + `info.name` String, + `info.age` Int +) +ENGINE = MergeTree +ORDER BY tuple() +SETTINGS min_bytes_for_wide_part = 0; + +INSERT INTO test_wide_not_nested SELECT number, number, 'aa', number * 2 FROM numbers(5); +ALTER TABLE test_wide_not_nested UPDATE `info.name` = 'bb' WHERE id = 1; +SELECT * FROM test_wide_not_nested ORDER BY id; + +DROP TABLE test_wide_not_nested;