diff --git a/src/Storages/AlterCommands.cpp b/src/Storages/AlterCommands.cpp index fc72effca9a..1d3ccb3f0ae 100644 --- a/src/Storages/AlterCommands.cpp +++ b/src/Storages/AlterCommands.cpp @@ -844,20 +844,24 @@ void AlterCommands::validate(const StorageInMemoryMetadata & metadata, const Con { if (all_columns.has(command.column_name) || all_columns.hasNested(command.column_name)) { - for (const ColumnDescription & column : all_columns) + if (!command.clear) /// CLEAR column is Ok even if there are dependencies. { - const auto & default_expression = column.default_desc.expression; - if (default_expression) + /// Check if we are going to DROP a column that some other columns depend on. + for (const ColumnDescription & column : all_columns) { - ASTPtr query = default_expression->clone(); - auto syntax_result = SyntaxAnalyzer(context).analyze(query, all_columns.getAll()); - const auto actions = ExpressionAnalyzer(query, syntax_result, context).getActions(true); - const auto required_columns = actions->getRequiredColumns(); + const auto & default_expression = column.default_desc.expression; + if (default_expression) + { + ASTPtr query = default_expression->clone(); + auto syntax_result = SyntaxAnalyzer(context).analyze(query, all_columns.getAll()); + const auto actions = ExpressionAnalyzer(query, syntax_result, context).getActions(true); + const auto required_columns = actions->getRequiredColumns(); - if (required_columns.end() != std::find(required_columns.begin(), required_columns.end(), command.column_name)) - throw Exception( - "Cannot drop column " + backQuote(command.column_name) + ", because column " + backQuote(column.name) + " depends on it", - ErrorCodes::ILLEGAL_COLUMN); + if (required_columns.end() != std::find(required_columns.begin(), required_columns.end(), command.column_name)) + throw Exception("Cannot drop column " + backQuote(command.column_name) + + ", because column " + backQuote(column.name) + " depends on it", + ErrorCodes::ILLEGAL_COLUMN); + } } } all_columns.remove(command.column_name); diff --git a/tests/queries/0_stateless/01387_clear_column_default_depends.reference b/tests/queries/0_stateless/01387_clear_column_default_depends.reference new file mode 100644 index 00000000000..308a6ca52fb --- /dev/null +++ b/tests/queries/0_stateless/01387_clear_column_default_depends.reference @@ -0,0 +1,18 @@ +1 2 +2 3 +3 4 +0 2 +0 3 +0 4 +1 2 +2 3 +3 4 +0 2 +0 3 +0 4 +1 2 +2 3 +3 4 +0 1 +0 1 +0 1 diff --git a/tests/queries/0_stateless/01387_clear_column_default_depends.sql b/tests/queries/0_stateless/01387_clear_column_default_depends.sql new file mode 100644 index 00000000000..21a41f09df6 --- /dev/null +++ b/tests/queries/0_stateless/01387_clear_column_default_depends.sql @@ -0,0 +1,36 @@ +-- It's Ok to CLEAR column when there are columns with default expression depending on it. +-- But it's not Ok to DROP such column. + +DROP TABLE IF EXISTS test; +CREATE TABLE test (x UInt8, y UInt8 DEFAULT x + 1) ENGINE = MergeTree ORDER BY tuple(); +INSERT INTO test (x) VALUES (1), (2), (3); +SELECT * FROM test ORDER BY x, y; +ALTER TABLE test CLEAR COLUMN x; +SELECT * FROM test ORDER BY x, y; +ALTER TABLE test DROP COLUMN x; -- { serverError 44 } +DROP TABLE test; + +DROP TABLE IF EXISTS test; +CREATE TABLE test (x UInt8, y UInt8 MATERIALIZED x + 1) ENGINE = MergeTree ORDER BY tuple(); +INSERT INTO test (x) VALUES (1), (2), (3); +SELECT x, y FROM test ORDER BY x, y; +ALTER TABLE test CLEAR COLUMN x; +SELECT x, y FROM test ORDER BY x, y; +ALTER TABLE test DROP COLUMN x; -- { serverError 44 } +DROP TABLE test; + +DROP TABLE IF EXISTS test; +CREATE TABLE test (x UInt8, y UInt8 ALIAS x + 1, z String DEFAULT 'Hello') ENGINE = MergeTree ORDER BY tuple(); +INSERT INTO test (x) VALUES (1), (2), (3); +SELECT x, y FROM test ORDER BY x, y; +ALTER TABLE test CLEAR COLUMN x; +SELECT x, y FROM test ORDER BY x, y; +ALTER TABLE test DROP COLUMN x; -- { serverError 44 } +DROP TABLE test; + + +-- The original report from Mikhail Petrov +DROP TABLE IF EXISTS Test; +create table Test (impression_id String,impression_id_compressed FixedString(16) DEFAULT UUIDStringToNum(substring(impression_id, 1, 36)), impression_id_hashed UInt16 DEFAULT reinterpretAsUInt16(impression_id_compressed), event_date Date ) ENGINE = MergeTree(event_date, impression_id_hashed, (event_date, impression_id_hashed), 8192); +alter table Test clear column impression_id in partition '202001'; +DROP TABLE Test;