Merge pull request #28028 from ClickHouse/replicated-tree-attach-wip

Allow attaching parts with 'compatible' enum types
This commit is contained in:
alesapin 2021-08-26 13:50:29 +03:00 committed by GitHub
commit bcaff65457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 10 deletions

View File

@ -27,6 +27,8 @@ public:
bool isCategorial() const override { return true; }
bool canBeInsideNullable() const override { return true; }
bool isComparable() const override { return true; }
virtual bool contains(const IDataType & rhs) const = 0;
};
@ -76,7 +78,7 @@ public:
/// Example:
/// Enum('a' = 1, 'b' = 2) -> Enum('c' = 1, 'b' = 2, 'd' = 3) OK
/// Enum('a' = 1, 'b' = 2) -> Enum('a' = 2, 'b' = 1) NOT OK
bool contains(const IDataType & rhs) const;
bool contains(const IDataType & rhs) const override;
SerializationPtr doGetDefaultSerialization() const override;
};

View File

@ -5,6 +5,7 @@
#include <Common/quoteString.h>
#include <Common/StringUtils/StringUtils.h>
#include <Core/ColumnWithTypeAndName.h>
#include <DataTypes/DataTypeEnum.h>
#include <IO/ReadBufferFromString.h>
#include <IO/ReadHelpers.h>
#include <IO/Operators.h>
@ -495,6 +496,23 @@ namespace
return res;
}
/*
* This function checks compatibility of enums. It returns true if:
* 1. Both types are enums.
* 2. The first type can represent all possible values of the second one.
* 3. Both types require the same amount of memory.
*/
bool isCompatibleEnumTypes(const IDataType * lhs, const IDataType * rhs)
{
if (IDataTypeEnum const * enum_type = dynamic_cast<IDataTypeEnum const *>(lhs))
{
if (!enum_type->contains(*rhs))
return false;
return enum_type->getMaximumSizeOfValueInMemory() == rhs->getMaximumSizeOfValueInMemory();
}
return false;
}
}
void StorageInMemoryMetadata::check(const Names & column_names, const NamesAndTypesList & virtuals, const StorageID & storage_id) const
@ -546,12 +564,13 @@ void StorageInMemoryMetadata::check(const NamesAndTypesList & provided_columns)
column.name,
listOfColumns(available_columns));
if (!column.type->equals(*it->getMapped()))
const auto * available_type = it->getMapped();
if (!column.type->equals(*available_type) && !isCompatibleEnumTypes(available_type, column.type.get()))
throw Exception(
ErrorCodes::TYPE_MISMATCH,
"Type mismatch for column {}. Column has type {}, got type {}",
column.name,
it->getMapped()->getName(),
available_type->getName(),
column.type->getName());
if (unique_names.end() != unique_names.find(column.name))
@ -590,16 +609,16 @@ void StorageInMemoryMetadata::check(const NamesAndTypesList & provided_columns,
name,
listOfColumns(available_columns));
const auto & provided_column_type = *it->getMapped();
const auto & available_column_type = *jt->getMapped();
const auto * provided_column_type = it->getMapped();
const auto * available_column_type = jt->getMapped();
if (!provided_column_type.equals(available_column_type))
if (!provided_column_type->equals(*available_column_type) && !isCompatibleEnumTypes(available_column_type, provided_column_type))
throw Exception(
ErrorCodes::TYPE_MISMATCH,
"Type mismatch for column {}. Column has type {}, got type {}",
name,
provided_column_type.getName(),
available_column_type.getName());
available_column_type->getName(),
provided_column_type->getName());
if (unique_names.end() != unique_names.find(name))
throw Exception(ErrorCodes::COLUMN_QUERIED_MORE_THAN_ONCE,
@ -634,12 +653,13 @@ void StorageInMemoryMetadata::check(const Block & block, bool need_all) const
column.name,
listOfColumns(available_columns));
if (!column.type->equals(*it->getMapped()))
const auto * available_type = it->getMapped();
if (!column.type->equals(*available_type) && !isCompatibleEnumTypes(available_type, column.type.get()))
throw Exception(
ErrorCodes::TYPE_MISMATCH,
"Type mismatch for column {}. Column has type {}, got type {}",
column.name,
it->getMapped()->getName(),
available_type->getName(),
column.type->getName());
}

View File

@ -0,0 +1,4 @@
one
one
two
two

View File

@ -0,0 +1,8 @@
create table enum_alter_issue (a Enum8('one' = 1, 'two' = 2)) engine = MergeTree() ORDER BY a;
insert into enum_alter_issue values ('one'), ('two');
alter table enum_alter_issue modify column a Enum8('one' = 1, 'two' = 2, 'three' = 3);
insert into enum_alter_issue values ('one'), ('two');
alter table enum_alter_issue detach partition id 'all';
alter table enum_alter_issue attach partition id 'all';
select * from enum_alter_issue order by a;
drop table enum_alter_issue;

View File

@ -0,0 +1,4 @@
one 1
two 2
one 3
two 4

View File

@ -0,0 +1,13 @@
create table enum_alter_issue (a Enum8('one' = 1, 'two' = 2), b Int)
engine = ReplicatedMergeTree('/clickhouse/tables/{database}/test_02012/enum_alter_issue', 'r1')
ORDER BY a;
insert into enum_alter_issue values ('one', 1), ('two', 2);
alter table enum_alter_issue modify column a Enum8('one' = 1, 'two' = 2, 'three' = 3);
insert into enum_alter_issue values ('one', 3), ('two', 4);
alter table enum_alter_issue detach partition id 'all';
alter table enum_alter_issue attach partition id 'all';
select * from enum_alter_issue order by b;
drop table enum_alter_issue;

View File

@ -0,0 +1,12 @@
drop table if exists enum_alter_issue;
create table enum_alter_issue (a Enum16('one' = 1, 'two' = 2), b Int)
engine = ReplicatedMergeTree('/clickhouse/tables/{database}/test_02012/enum_alter_issue', 'r2')
ORDER BY b;
insert into enum_alter_issue values ('one', 1), ('two', 1);
alter table enum_alter_issue detach partition id 'all';
alter table enum_alter_issue modify column a Enum8('one' = 1, 'two' = 2, 'three' = 3);
insert into enum_alter_issue values ('one', 1), ('two', 1);
alter table enum_alter_issue attach partition id 'all'; -- {serverError TYPE_MISMATCH}
drop table enum_alter_issue;

View File

@ -161,6 +161,9 @@
"00980_zookeeper_merge_tree_alter_settings",
"00980_merge_alter_settings",
"02009_array_join_partition",
"02012_changed_enum_type_non_replicated",
"02012_zookeeper_changed_enum_type",
"02012_zookeeper_changed_enum_type_incompatible",
/// Old syntax is not allowed
"01062_alter_on_mutataion_zookeeper",
"00925_zookeeper_empty_replicated_merge_tree_optimize_final",