Add ability to change some types for primary key

This commit is contained in:
alesapin 2020-12-22 13:41:12 +03:00
parent 0e807d0647
commit 35413635e7
3 changed files with 91 additions and 7 deletions

View File

@ -5,6 +5,7 @@
#include <DataTypes/DataTypeDateTime.h> #include <DataTypes/DataTypeDateTime.h>
#include <DataTypes/DataTypeEnum.h> #include <DataTypes/DataTypeEnum.h>
#include <DataTypes/DataTypeNullable.h> #include <DataTypes/DataTypeNullable.h>
#include <DataTypes/DataTypeLowCardinality.h>
#include <DataTypes/NestedUtils.h> #include <DataTypes/NestedUtils.h>
#include <Formats/FormatFactory.h> #include <Formats/FormatFactory.h>
#include <Functions/FunctionFactory.h> #include <Functions/FunctionFactory.h>
@ -1316,10 +1317,10 @@ void MergeTreeData::dropIfEmpty()
namespace namespace
{ {
/// Conversion that is allowed for partition key. /// Conversion that is allowed for serializable key (primary key, sorting key).
/// Partition key should be serialized in the same way after conversion. /// Key should be serialized in the same way after conversion.
/// NOTE: The list is not complete. /// NOTE: The list is not complete.
bool isSafeForPartitionKeyConversion(const IDataType * from, const IDataType * to) bool isSafeForKeyConversion(const IDataType * from, const IDataType * to)
{ {
if (from->getName() == to->getName()) if (from->getName() == to->getName())
return true; return true;
@ -1346,6 +1347,12 @@ bool isSafeForPartitionKeyConversion(const IDataType * from, const IDataType * t
return false; return false;
} }
if (const auto * from_lc = typeid_cast<const DataTypeLowCardinality *>(from))
return from_lc->getDictionaryType()->equals(*to);
if (const auto * to_lc = typeid_cast<const DataTypeLowCardinality *>(to))
return to_lc->getDictionaryType()->equals(*from);
return false; return false;
} }
@ -1540,7 +1547,7 @@ void MergeTreeData::checkAlterIsPossible(const AlterCommands & commands, const S
auto it = old_types.find(command.column_name); auto it = old_types.find(command.column_name);
assert(it != old_types.end()); assert(it != old_types.end());
if (!isSafeForPartitionKeyConversion(it->second, command.data_type.get())) if (!isSafeForKeyConversion(it->second, command.data_type.get()))
throw Exception("ALTER of partition key column " + backQuoteIfNeed(command.column_name) + " from type " throw Exception("ALTER of partition key column " + backQuoteIfNeed(command.column_name) + " from type "
+ it->second->getName() + " to type " + command.data_type->getName() + it->second->getName() + " to type " + command.data_type->getName()
+ " is not safe because it can change the representation of partition key", + " is not safe because it can change the representation of partition key",
@ -1554,9 +1561,11 @@ void MergeTreeData::checkAlterIsPossible(const AlterCommands & commands, const S
{ {
auto it = old_types.find(command.column_name); auto it = old_types.find(command.column_name);
assert(it != old_types.end()); assert(it != old_types.end());
throw Exception("ALTER of key column " + backQuoteIfNeed(command.column_name) + " from type " if (!isSafeForKeyConversion(it->second, command.data_type.get()))
+ it->second->getName() + " to type " + command.data_type->getName() + " must be metadata-only", throw Exception("ALTER of key column " + backQuoteIfNeed(command.column_name) + " from type "
ErrorCodes::ALTER_OF_COLUMN_IS_FORBIDDEN); + it->second->getName() + " to type " + command.data_type->getName()
+ " is not safe because it can change the representation of primary key",
ErrorCodes::ALTER_OF_COLUMN_IS_FORBIDDEN);
} }
} }
} }

View File

@ -0,0 +1,8 @@
CREATE TABLE default.table_with_lc_key\n(\n `enum_key` Enum8(\'y\' = 1, \'x\' = 2),\n `lc_key` String,\n `value` String\n)\nENGINE = MergeTree\nORDER BY (enum_key, lc_key)\nSETTINGS index_granularity = 8192
y hello world
CREATE TABLE default.table_with_lc_key\n(\n `enum_key` Enum8(\'y\' = 1, \'x\' = 2, \'z\' = 3),\n `lc_key` String,\n `value` String\n)\nENGINE = MergeTree\nORDER BY (enum_key, lc_key)\nSETTINGS index_granularity = 8192
y hello world
CREATE TABLE default.table_with_lc_key\n(\n `enum_key` Int8,\n `lc_key` String,\n `value` String\n)\nENGINE = MergeTree\nORDER BY (enum_key, lc_key)\nSETTINGS index_granularity = 8192
1 hello world
CREATE TABLE default.table_with_string_key\n(\n `int_key` Int8,\n `str_key` LowCardinality(String),\n `value` String\n)\nENGINE = MergeTree\nORDER BY (int_key, str_key)\nSETTINGS index_granularity = 8192
1 hello world

View File

@ -0,0 +1,67 @@
DROP TABLE IF EXISTS table_with_lc_key;
CREATE TABLE table_with_lc_key
(
enum_key Enum8('x' = 2, 'y' = 1),
lc_key LowCardinality(String),
value String
)
ENGINE MergeTree()
ORDER BY (enum_key, lc_key);
INSERT INTO table_with_lc_key VALUES(1, 'hello', 'world');
ALTER TABLE table_with_lc_key MODIFY COLUMN lc_key String;
SHOW CREATE TABLE table_with_lc_key;
DETACH TABLE table_with_lc_key;
ATTACH TABLE table_with_lc_key;
SELECT * FROM table_with_lc_key WHERE enum_key > 0 and lc_key like 'h%';
ALTER TABLE table_with_lc_key MODIFY COLUMN enum_key Enum('x' = 2, 'y' = 1, 'z' = 3);
ALTER TABLE table_with_lc_key MODIFY COLUMN enum_key Enum16('x' = 2, 'y' = 1, 'z' = 3); --{serverError 524}
SHOW CREATE TABLE table_with_lc_key;
DETACH TABLE table_with_lc_key;
ATTACH TABLE table_with_lc_key;
SELECT * FROM table_with_lc_key WHERE enum_key > 0 and lc_key like 'h%';
ALTER TABLE table_with_lc_key MODIFY COLUMN enum_key Int8;
SHOW CREATE TABLE table_with_lc_key;
DETACH TABLE table_with_lc_key;
ATTACH TABLE table_with_lc_key;
SELECT * FROM table_with_lc_key WHERE enum_key > 0 and lc_key like 'h%';
DROP TABLE IF EXISTS table_with_lc_key;
DROP TABLE IF EXISTS table_with_string_key;
CREATE TABLE table_with_string_key
(
int_key Int8,
str_key String,
value String
)
ENGINE MergeTree()
ORDER BY (int_key, str_key);
INSERT INTO table_with_string_key VALUES(1, 'hello', 'world');
ALTER TABLE table_with_string_key MODIFY COLUMN str_key LowCardinality(String);
SHOW CREATE TABLE table_with_string_key;
DETACH TABLE table_with_string_key;
ATTACH TABLE table_with_string_key;
SELECT * FROM table_with_string_key WHERE int_key > 0 and str_key like 'h%';
ALTER TABLE table_with_string_key MODIFY COLUMN int_key Enum8('y' = 1, 'x' = 2); --{serverError 524}
DROP TABLE IF EXISTS table_with_string_key;