diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index bd797f5b71f..f15d066f8cf 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -429,6 +429,7 @@ namespace ErrorCodes extern const int SETTING_CONSTRAINT_VIOLATION = 452; extern const int MYSQL_CLIENT_INSUFFICIENT_CAPABILITIES = 453; extern const int OPENSSL_ERROR = 454; + extern const int SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY = 455; extern const int KEEPER_EXCEPTION = 999; extern const int POCO_EXCEPTION = 1000; diff --git a/dbms/src/Core/Settings.h b/dbms/src/Core/Settings.h index 21eb792e20c..0cd132ef9ed 100644 --- a/dbms/src/Core/Settings.h +++ b/dbms/src/Core/Settings.h @@ -85,6 +85,7 @@ struct Settings : public SettingsCollection M(SettingFloat, totals_auto_threshold, 0.5, "The threshold for totals_mode = 'auto'.") \ \ M(SettingBool, compile, false, "Whether query compilation is enabled.") \ + M(SettingBool, allow_suspicious_low_cardinality_types, false, "In CREATE TABLE statement allows specifying LowCardinality modifier for types of small fixed size (8 or less). Enabling this may increase merge times and memory consumption.") \ M(SettingBool, compile_expressions, false, "Compile some scalar functions and operators to native code.") \ M(SettingUInt64, min_count_to_compile, 3, "The number of structurally identical queries before they are compiled.") \ M(SettingUInt64, min_count_to_compile_expression, 3, "The number of identical expressions before they are JIT-compiled") \ diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 035b299ac5e..b6cdf35774f 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -65,6 +67,7 @@ namespace ErrorCodes extern const int QUERY_IS_PROHIBITED; extern const int THERE_IS_NO_DEFAULT_VALUE; extern const int BAD_DATABASE_FOR_TEMPORARY_TABLE; + extern const int SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY; } @@ -523,6 +526,20 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create) /// Set and retrieve list of columns. ColumnsDescription columns = setColumns(create, as_select_sample, as_storage); + /// Check low cardinality types in creating table if it was not allowed in setting + if (!create.attach && !context.getSettingsRef().allow_suspicious_low_cardinality_types) + { + for (const auto & name_and_type_pair : columns.getAllPhysical()) + { + if (const auto * current_type_ptr = typeid_cast(name_and_type_pair.type.get())) + { + if (!isStringOrFixedString(*removeNullable(current_type_ptr->getDictionaryType()))) + throw Exception("Creating columns of type " + current_type_ptr->getName() + " is prohibited by default due to expected negative impact on performance. It can be enabled with the \"allow_suspicious_low_cardinality_types\" setting.", + ErrorCodes::SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY); + } + } + } + /// Set the table engine if it was not specified explicitly. setEngine(create); diff --git a/dbms/tests/queries/0_stateless/00688_low_cardinality_in.sql b/dbms/tests/queries/0_stateless/00688_low_cardinality_in.sql index b3ae940e155..09a96743847 100644 --- a/dbms/tests/queries/0_stateless/00688_low_cardinality_in.sql +++ b/dbms/tests/queries/0_stateless/00688_low_cardinality_in.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; drop table if exists lc_00688; create table lc_00688 (str StringWithDictionary, val UInt8WithDictionary) engine = MergeTree order by tuple(); insert into lc_00688 values ('a', 1), ('b', 2); diff --git a/dbms/tests/queries/0_stateless/00688_low_cardinality_nullable_cast.sql b/dbms/tests/queries/0_stateless/00688_low_cardinality_nullable_cast.sql index 1248374aacc..5e25e50d482 100644 --- a/dbms/tests/queries/0_stateless/00688_low_cardinality_nullable_cast.sql +++ b/dbms/tests/queries/0_stateless/00688_low_cardinality_nullable_cast.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; SELECT CAST(NULL, 'LowCardinality(Nullable(Int8))'); drop table if exists lc_null_int8_defnull; diff --git a/dbms/tests/queries/0_stateless/00688_low_cardinality_syntax.sql b/dbms/tests/queries/0_stateless/00688_low_cardinality_syntax.sql index f1c41be16bc..98d7b7f5f8a 100644 --- a/dbms/tests/queries/0_stateless/00688_low_cardinality_syntax.sql +++ b/dbms/tests/queries/0_stateless/00688_low_cardinality_syntax.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; drop table if exists lc_str_0; drop table if exists lc_str_1; drop table if exists lc_null_str_0; diff --git a/dbms/tests/queries/0_stateless/00717_low_cardinaliry_distributed_group_by.sql b/dbms/tests/queries/0_stateless/00717_low_cardinaliry_distributed_group_by.sql index 1ecb512761a..47513cc6f1e 100644 --- a/dbms/tests/queries/0_stateless/00717_low_cardinaliry_distributed_group_by.sql +++ b/dbms/tests/queries/0_stateless/00717_low_cardinaliry_distributed_group_by.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; DROP TABLE IF EXISTS test.test_low_null_float; DROP TABLE IF EXISTS test.dist; diff --git a/dbms/tests/queries/0_stateless/00718_low_cardinaliry_alter.sql b/dbms/tests/queries/0_stateless/00718_low_cardinaliry_alter.sql index 45b647584ad..591ff952132 100644 --- a/dbms/tests/queries/0_stateless/00718_low_cardinaliry_alter.sql +++ b/dbms/tests/queries/0_stateless/00718_low_cardinaliry_alter.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; drop table if exists tab_00718; create table tab_00718 (a String, b LowCardinality(UInt32)) engine = MergeTree order by a; insert into tab_00718 values ('a', 1); diff --git a/dbms/tests/queries/0_stateless/00751_low_cardinality_nullable_group_by.sql b/dbms/tests/queries/0_stateless/00751_low_cardinality_nullable_group_by.sql index c0234eaad8c..0a92037fa89 100644 --- a/dbms/tests/queries/0_stateless/00751_low_cardinality_nullable_group_by.sql +++ b/dbms/tests/queries/0_stateless/00751_low_cardinality_nullable_group_by.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; drop table if exists low_null_float; CREATE TABLE low_null_float (a LowCardinality(Nullable(Float64))) ENGINE = MergeTree order by tuple(); INSERT INTO low_null_float (a) SELECT if(number % 3 == 0, Null, number) FROM system.numbers LIMIT 1000000; diff --git a/dbms/tests/queries/0_stateless/00800_low_cardinality_distinct_numeric.sql b/dbms/tests/queries/0_stateless/00800_low_cardinality_distinct_numeric.sql index da818cb7323..8ba95ce7a8e 100644 --- a/dbms/tests/queries/0_stateless/00800_low_cardinality_distinct_numeric.sql +++ b/dbms/tests/queries/0_stateless/00800_low_cardinality_distinct_numeric.sql @@ -1,3 +1,4 @@ +set allow_suspicious_low_cardinality_types = 1; drop table if exists lc_00800_2; create table lc_00800_2 (val LowCardinality(UInt64)) engine = MergeTree order by val; insert into lc_00800_2 select number % 123 from system.numbers limit 100000;