mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 16:42:05 +00:00
Merge pull request #36352 from awakeljw/fork_chmaster
Possible range issues in automatic assigned enums, also fix error message.
This commit is contained in:
commit
f6a7b6c2a1
@ -7,7 +7,7 @@ toc_title: Enum
|
||||
|
||||
Enumerated type consisting of named values.
|
||||
|
||||
Named values must be declared as `'string' = integer` pairs. ClickHouse stores only numbers, but supports operations with the values through their names.
|
||||
Named values can be declared as `'string' = integer` pairs or `'string'` names . ClickHouse stores only numbers, but supports operations with the values through their names.
|
||||
|
||||
ClickHouse supports:
|
||||
|
||||
@ -28,6 +28,39 @@ CREATE TABLE t_enum
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
Similarly, you could omit numbers. ClickHouse will assign consecutive numbers automatically. Numbers are assigned starting from 1 by default.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_enum
|
||||
(
|
||||
x Enum('hello', 'world')
|
||||
)
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
You can also specify legal starting number for the first name.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_enum
|
||||
(
|
||||
x Enum('hello' = 1, 'world')
|
||||
)
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_enum
|
||||
(
|
||||
x Enum8('hello' = -129, 'world')
|
||||
)
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
``` text
|
||||
Exception on server:
|
||||
Code: 69. DB::Exception: Value -129 for element 'hello' exceeds range of Enum8.
|
||||
```
|
||||
|
||||
Column `x` can only store values that are listed in the type definition: `'hello'` or `'world'`. If you try to save any other value, ClickHouse will raise an exception. 8-bit size for this `Enum` is chosen automatically.
|
||||
|
||||
``` sql
|
||||
|
@ -7,7 +7,7 @@ toc_title: Enum
|
||||
|
||||
Перечисляемый тип данных, содержащий именованные значения.
|
||||
|
||||
Именованные значения задаются парами `'string' = integer`. ClickHouse хранит только числа, но допускает операции над ними с помощью заданных имён.
|
||||
Именованные значения задаются либо парами `'string' = integer`, либо именами `'string'`. ClickHouse хранит только числа, но допускает операции над ними с помощью заданных имён.
|
||||
|
||||
ClickHouse поддерживает:
|
||||
|
||||
@ -28,6 +28,39 @@ CREATE TABLE t_enum
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
Номера могут быть опущены - в этом случае ClickHouse автоматически присвоит последовательные номера, начиная с 1.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_enum
|
||||
(
|
||||
x Enum('hello', 'world')
|
||||
)
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
Можно также указать допустимый стартовый номер для первого имени.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_enum
|
||||
(
|
||||
x Enum('hello' = 1, 'world')
|
||||
)
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_enum
|
||||
(
|
||||
x Enum8('hello' = -129, 'world')
|
||||
)
|
||||
ENGINE = TinyLog
|
||||
```
|
||||
|
||||
``` text
|
||||
Exception on server:
|
||||
Code: 69. DB::Exception: Value -129 for element 'hello' exceeds range of Enum8.
|
||||
```
|
||||
|
||||
В столбец `x` можно сохранять только значения, перечисленные при определении типа, т.е. `'hello'` или `'world'`. Если вы попытаетесь сохранить любое другое значение, ClickHouse сгенерирует исключение. ClickHouse автоматически выберет размерность 8-bit для этого `Enum`.
|
||||
|
||||
``` sql
|
||||
|
@ -193,26 +193,46 @@ static void checkASTStructure(const ASTPtr & child)
|
||||
|
||||
static void autoAssignNumberForEnum(const ASTPtr & arguments)
|
||||
{
|
||||
UInt64 literal_child_count = 0;
|
||||
UInt64 func_child_count = 0;
|
||||
Int64 literal_child_assign_num = 1;
|
||||
ASTs assign_number_child;
|
||||
assign_number_child.reserve(arguments->children.size());
|
||||
bool is_first_child = true;
|
||||
size_t assign_count= 0;
|
||||
|
||||
for (const ASTPtr & child : arguments->children)
|
||||
{
|
||||
if (child->as<ASTLiteral>())
|
||||
{
|
||||
ASTPtr func = makeASTFunction("equals", child, std::make_shared<ASTLiteral>(++literal_child_count));
|
||||
assign_count += !is_first_child;
|
||||
ASTPtr func = makeASTFunction("equals", child, std::make_shared<ASTLiteral>(literal_child_assign_num + assign_count));
|
||||
assign_number_child.emplace_back(func);
|
||||
}
|
||||
else
|
||||
else if (child->as<ASTFunction>())
|
||||
{
|
||||
++func_child_count;
|
||||
if (is_first_child)
|
||||
{
|
||||
checkASTStructure(child);
|
||||
const auto * func = child->as<ASTFunction>();
|
||||
const auto * value_literal = func->arguments->children[1]->as<ASTLiteral>();
|
||||
|
||||
if (!value_literal
|
||||
|| (value_literal->value.getType() != Field::Types::UInt64 && value_literal->value.getType() != Field::Types::Int64))
|
||||
throw Exception("Elements of Enum data type must be of form: 'name' = number or 'name', where name is string literal and number is an integer",
|
||||
ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||
|
||||
literal_child_assign_num = value_literal->value.get<Int64>();
|
||||
}
|
||||
assign_number_child.emplace_back(child);
|
||||
}
|
||||
else
|
||||
throw Exception("Elements of Enum data type must be of form: 'name' = number or 'name', where name is string literal and number is an integer",
|
||||
ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||
|
||||
is_first_child = false;
|
||||
}
|
||||
|
||||
if (func_child_count > 0 && literal_child_count > 0)
|
||||
throw Exception("ALL Elements of Enum data type must be of form: 'name' = number or 'name', where name is string literal and number is an integer",
|
||||
if (assign_count != 0 && assign_count != arguments->children.size() - 1)
|
||||
throw Exception("All elements of Enum data type must be of form: 'name' = number or 'name', where name is string literal and number is an integer",
|
||||
ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||
|
||||
arguments->children = assign_number_child;
|
||||
@ -243,7 +263,7 @@ static DataTypePtr createExact(const ASTPtr & arguments)
|
||||
|| !value_literal
|
||||
|| name_literal->value.getType() != Field::Types::String
|
||||
|| (value_literal->value.getType() != Field::Types::UInt64 && value_literal->value.getType() != Field::Types::Int64))
|
||||
throw Exception("Elements of Enum data type must be of form: 'name' = number, where name is string literal and number is an integer",
|
||||
throw Exception("Elements of Enum data type must be of form: 'name' = number or 'name', where name is string literal and number is an integer",
|
||||
ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||
|
||||
const String & field_name = name_literal->value.get<String>();
|
||||
@ -275,7 +295,7 @@ static DataTypePtr create(const ASTPtr & arguments)
|
||||
|
||||
if (!value_literal
|
||||
|| (value_literal->value.getType() != Field::Types::UInt64 && value_literal->value.getType() != Field::Types::Int64))
|
||||
throw Exception("Elements of Enum data type must be of form: 'name' = number, where name is string literal and number is an integer",
|
||||
throw Exception("Elements of Enum data type must be of form: 'name' = number or 'name', where name is string literal and number is an integer",
|
||||
ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||
|
||||
Int64 value = value_literal->value.get<Int64>();
|
||||
|
@ -6,3 +6,12 @@ iphone 1
|
||||
\N 1
|
||||
a
|
||||
b
|
||||
1
|
||||
2
|
||||
a
|
||||
a
|
||||
b
|
||||
-1000
|
||||
-999
|
||||
b
|
||||
-1
|
||||
|
@ -1,12 +1,41 @@
|
||||
select os_name, count() from (SELECT CAST('iphone' AS Enum8('iphone' = 1, 'android' = 2)) AS os_name) group by os_name WITH TOTALS;
|
||||
select toNullable(os_name) AS os_name, count() from (SELECT CAST('iphone' AS Enum8('iphone' = 1, 'android' = 2)) AS os_name) group by os_name WITH TOTALS;
|
||||
|
||||
DROP TABLE IF EXISTS auto_assgin_enum;
|
||||
DROP TABLE IF EXISTS auto_assgin_enum1;
|
||||
DROP TABLE IF EXISTS auto_assign_enum;
|
||||
DROP TABLE IF EXISTS auto_assign_enum1;
|
||||
DROP TABLE IF EXISTS auto_assign_enum2;
|
||||
DROP TABLE IF EXISTS auto_assign_enum3;
|
||||
|
||||
CREATE TABLE auto_assgin_enum (x enum('a', 'b')) ENGINE=MergeTree() order by x;
|
||||
CREATE TABLE auto_assgin_enum1 (x enum('a' = 1, 'b')) ENGINE=MergeTree() order by x; -- { serverError 223 }
|
||||
INSERT INTO auto_assgin_enum VALUES('a'), ('b');
|
||||
select * from auto_assgin_enum;
|
||||
CREATE TABLE auto_assign_enum (x enum('a', 'b')) ENGINE=MergeTree() order by x;
|
||||
INSERT INTO auto_assign_enum VALUES('a'), ('b');
|
||||
select * from auto_assign_enum;
|
||||
select CAST(x, 'Int8') from auto_assign_enum;
|
||||
select * from auto_assign_enum where x = 1;
|
||||
|
||||
DROP TABLE auto_assgin_enum;
|
||||
CREATE TABLE auto_assign_enum1 (x enum('a' = -1000, 'b')) ENGINE=MergeTree() order by x;
|
||||
INSERT INTO auto_assign_enum1 VALUES('a'), ('b');
|
||||
select * from auto_assign_enum1;
|
||||
select CAST(x, 'Int16') from auto_assign_enum1;
|
||||
select * from auto_assign_enum1 where x = -999;
|
||||
|
||||
CREATE TABLE auto_assign_enum2 (x enum('a' = -1000, 'b', 'c' = -99)) ENGINE=MergeTree() order by x; -- { serverError 223 }
|
||||
|
||||
CREATE TABLE auto_assign_enum2 (x Enum8(
|
||||
'00' = -128 ,'01','02','03','04','05','06','07','08','09','0A','0B','0C','0D','0E','0F',
|
||||
'10','11','12','13','14','15','16','17','18','19','1A','1B','1C','1D','1E','1F',
|
||||
'20','21','22','23','24','25','26','27','28','29','2A','2B','2C','2D','2E','2F',
|
||||
'30','31','32','33','34','35','36','37','38','39','3A','3B','3C','3D','3E','3F',
|
||||
'40','41','42','43','44','45','46','47','48','49','4A','4B','4C','4D','4E','4F',
|
||||
'50','51','52','53','54','55','56','57','58','59','5A','5B','5C','5D','5E','5F',
|
||||
'60','61','62','63','64','65','66','67','68','69','6A','6B','6C','6D','6E','6F',
|
||||
'70','71','72','73','74','75','76','77','78','79','7A','7B','7C','7D','7E','7F'
|
||||
)) ENGINE=MergeTree() order by x;
|
||||
|
||||
INSERT INTO auto_assign_enum2 VALUES('7F');
|
||||
select CAST(x, 'Int8') from auto_assign_enum2;
|
||||
|
||||
CREATE TABLE auto_assign_enum3 (x enum('a', 'b', NULL)) ENGINE=MergeTree() order by x; -- { serverError 223 }
|
||||
|
||||
DROP TABLE auto_assign_enum;
|
||||
DROP TABLE auto_assign_enum1;
|
||||
DROP TABLE auto_assign_enum2;
|
||||
|
Loading…
Reference in New Issue
Block a user