From 00c2a3d2c26da00c56ee1bbe8b71a38bf21db75d Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Tue, 26 Sep 2023 10:01:37 +0000 Subject: [PATCH 01/12] per-column compress min-max block sizes Signed-off-by: Duc Canh Le --- src/Interpreters/InterpreterCreateQuery.cpp | 19 +++++++++++ src/Parsers/ASTColumnDeclaration.cpp | 12 +++++++ src/Parsers/ASTColumnDeclaration.h | 1 + src/Parsers/ParserCreateQuery.h | 16 ++++++++++ src/Storages/ColumnsDescription.cpp | 17 ++++++++++ src/Storages/ColumnsDescription.h | 1 + .../MergeTree/MergeTreeDataPartWriterWide.cpp | 15 +++++++-- .../02870_per_column_compress_block.reference | 11 +++++++ .../02870_per_column_compress_block.sql | 32 +++++++++++++++++++ 9 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 tests/queries/0_stateless/02870_per_column_compress_block.reference create mode 100644 tests/queries/0_stateless/02870_per_column_compress_block.sql diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index a0635f18214..6e27e2eb598 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -436,6 +436,14 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) column_declaration->children.push_back(column_declaration->codec); } + if (column.compress_block_sizes.first || column.compress_block_sizes.second) + { + Tuple value; + value.push_back(column.compress_block_sizes.first); + value.push_back(column.compress_block_sizes.second); + column_declaration->compress_block_sizes = std::make_shared(Field(value)); + } + if (column.ttl) { column_declaration->ttl = column.ttl; @@ -638,6 +646,17 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription( col_decl.codec, column.type, sanity_check_compression_codecs, allow_experimental_codecs, enable_deflate_qpl_codec); } + if (col_decl.compress_block_sizes) + { + auto sizes = col_decl.compress_block_sizes->as().value.safeGet(); + if (sizes.size() != 2 || sizes[0].getType() != Field::Types::UInt64 || sizes[0].getType() != Field::Types::UInt64) + throw Exception(ErrorCodes::SYNTAX_ERROR, "Column {}: COMPRESSION BLOCK must be tuple of two unsigned integer", column.name); + column.compress_block_sizes.first = sizes[0].safeGet(); + column.compress_block_sizes.second = sizes[1].safeGet(); + if (column.compress_block_sizes.first > column.compress_block_sizes.second) + throw Exception(ErrorCodes::SYNTAX_ERROR, "Column {}: min compress block size must smaller than max compress block size", column.name); + } + if (col_decl.ttl) column.ttl = col_decl.ttl; diff --git a/src/Parsers/ASTColumnDeclaration.cpp b/src/Parsers/ASTColumnDeclaration.cpp index e9b490a1be3..99cb17b0bce 100644 --- a/src/Parsers/ASTColumnDeclaration.cpp +++ b/src/Parsers/ASTColumnDeclaration.cpp @@ -39,6 +39,12 @@ ASTPtr ASTColumnDeclaration::clone() const res->children.push_back(res->codec); } + if (compress_block_sizes) + { + res->compress_block_sizes = compress_block_sizes->clone(); + res->children.push_back(res->compress_block_sizes); + } + if (ttl) { res->ttl = ttl->clone(); @@ -99,6 +105,12 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatSta codec->formatImpl(settings, state, frame); } + if (compress_block_sizes) + { + settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "COMPRESS BLOCK" << (settings.hilite ? hilite_none : "") << ' '; + compress_block_sizes->formatImpl(settings, state, frame); + } + if (ttl) { settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "TTL" << (settings.hilite ? hilite_none : "") << ' '; diff --git a/src/Parsers/ASTColumnDeclaration.h b/src/Parsers/ASTColumnDeclaration.h index 9d486667911..6e73b52ce71 100644 --- a/src/Parsers/ASTColumnDeclaration.h +++ b/src/Parsers/ASTColumnDeclaration.h @@ -20,6 +20,7 @@ public: ASTPtr comment; ASTPtr codec; ASTPtr ttl; + ASTPtr compress_block_sizes; ASTPtr collation; bool primary_key_specifier = false; diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index 4062ed25c6b..8ba81b66fda 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -136,10 +136,12 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ParserKeyword s_type{"TYPE"}; ParserKeyword s_collate{"COLLATE"}; ParserKeyword s_primary_key{"PRIMARY KEY"}; + ParserKeyword s_compress_block{"COMPRESS BLOCK"}; ParserExpression expr_parser; ParserStringLiteral string_literal_parser; ParserLiteral literal_parser; ParserCodec codec_parser; + ParserTupleOfLiterals compress_block_parser; ParserCollation collation_parser; ParserExpression expression_parser; @@ -176,6 +178,7 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ASTPtr default_expression; ASTPtr comment_expression; ASTPtr codec_expression; + ASTPtr compress_block_sizes; ASTPtr ttl_expression; ASTPtr collation_expression; bool primary_key_specifier = false; @@ -301,6 +304,12 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E return false; } + if (s_compress_block.ignore(pos, expected)) + { + if (!compress_block_parser.parse(pos, compress_block_sizes, expected)) + return false; + } + if (s_ttl.ignore(pos, expected)) { if (!expression_parser.parse(pos, ttl_expression, expected)) @@ -342,11 +351,18 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E column_declaration->children.push_back(std::move(codec_expression)); } + if (compress_block_sizes) + { + column_declaration->compress_block_sizes = compress_block_sizes; + column_declaration->children.push_back(std::move(compress_block_sizes)); + } + if (ttl_expression) { column_declaration->ttl = ttl_expression; column_declaration->children.push_back(std::move(ttl_expression)); } + if (collation_expression) { column_declaration->collation = collation_expression; diff --git a/src/Storages/ColumnsDescription.cpp b/src/Storages/ColumnsDescription.cpp index 0d5508b8164..6c0940463a8 100644 --- a/src/Storages/ColumnsDescription.cpp +++ b/src/Storages/ColumnsDescription.cpp @@ -62,6 +62,7 @@ bool ColumnDescription::operator==(const ColumnDescription & other) const && default_desc == other.default_desc && comment == other.comment && ast_to_str(codec) == ast_to_str(other.codec) + && compress_block_sizes == other.compress_block_sizes && ast_to_str(ttl) == ast_to_str(other.ttl); } @@ -94,6 +95,16 @@ void ColumnDescription::writeText(WriteBuffer & buf) const writeEscapedString(queryToString(codec), buf); } + if (compress_block_sizes.first || compress_block_sizes.second) + { + writeChar('\t', buf); + DB::writeText("COMPRESSION BLOCK ", buf); + Tuple value; + value.push_back(compress_block_sizes.first); + value.push_back(compress_block_sizes.second); + writeEscapedString(queryToString(ASTLiteral(Field(value))), buf); + } + if (ttl) { writeChar('\t', buf); @@ -138,6 +149,12 @@ void ColumnDescription::readText(ReadBuffer & buf) if (col_ast->ttl) ttl = col_ast->ttl; + if (col_ast->compress_block_sizes) + { + auto sizes = col_ast->compress_block_sizes->as().value.safeGet(); + compress_block_sizes.first = sizes[0].safeGet(); + compress_block_sizes.second = sizes[1].safeGet(); + } } else throw Exception(ErrorCodes::CANNOT_PARSE_TEXT, "Cannot parse column description"); diff --git a/src/Storages/ColumnsDescription.h b/src/Storages/ColumnsDescription.h index 2d7536765ff..6b7ec279835 100644 --- a/src/Storages/ColumnsDescription.h +++ b/src/Storages/ColumnsDescription.h @@ -82,6 +82,7 @@ struct ColumnDescription ColumnDefault default_desc; String comment; ASTPtr codec; + std::pair compress_block_sizes; ASTPtr ttl; ColumnDescription() = default; diff --git a/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp b/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp index 135cafbca21..74b00bb5ee7 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp +++ b/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace DB { @@ -142,13 +143,19 @@ void MergeTreeDataPartWriterWide::addStreams( auto ast = parseQuery(codec_parser, "(" + Poco::toUpper(settings.marks_compression_codec) + ")", 0, DBMS_DEFAULT_MAX_PARSER_DEPTH); CompressionCodecPtr marks_compression_codec = CompressionCodecFactory::instance().get(ast, nullptr); + const auto column_desc = metadata_snapshot->columns.tryGetColumnDescription(GetColumnsOptions(GetColumnsOptions::AllPhysical), column.getNameInStorage()); + + auto max_compress_block_size = column_desc ? column_desc->compress_block_sizes.second : 0; + if (!max_compress_block_size) + max_compress_block_size = settings.max_compress_block_size; + column_streams[stream_name] = std::make_unique( stream_name, data_part->getDataPartStoragePtr(), stream_name, DATA_FILE_EXTENSION, stream_name, marks_file_extension, compression_codec, - settings.max_compress_block_size, + max_compress_block_size, marks_compression_codec, settings.marks_compress_block_size, settings.query_write_settings); @@ -321,6 +328,10 @@ StreamsWithMarks MergeTreeDataPartWriterWide::getCurrentMarksForColumn( WrittenOffsetColumns & offset_columns) { StreamsWithMarks result; + const auto column_desc = metadata_snapshot->columns.tryGetColumnDescription(GetColumnsOptions(GetColumnsOptions::AllPhysical), column.getNameInStorage()); + auto min_compress_block_size = column_desc ? column_desc->compress_block_sizes.first : 0; + if (!min_compress_block_size) + min_compress_block_size = settings.min_compress_block_size; data_part->getSerialization(column.name)->enumerateStreams([&] (const ISerialization::SubstreamPath & substream_path) { bool is_offsets = !substream_path.empty() && substream_path.back().type == ISerialization::Substream::ArraySizes; @@ -333,7 +344,7 @@ StreamsWithMarks MergeTreeDataPartWriterWide::getCurrentMarksForColumn( Stream & stream = *column_streams[stream_name]; /// There could already be enough data to compress into the new block. - if (stream.compressed_hashing.offset() >= settings.min_compress_block_size) + if (stream.compressed_hashing.offset() >= min_compress_block_size) stream.compressed_hashing.next(); StreamNameAndMark stream_with_mark; diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.reference b/tests/queries/0_stateless/02870_per_column_compress_block.reference new file mode 100644 index 00000000000..ab98fba1668 --- /dev/null +++ b/tests/queries/0_stateless/02870_per_column_compress_block.reference @@ -0,0 +1,11 @@ +1000 +(0,0) 0 +(1,1) 1 +(2,2) 2 +(3,3) 3 +(4,4) 4 +(5,5) 5 +(6,6) 6 +(7,7) 7 +(8,8) 8 +(9,9) 9 diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.sql b/tests/queries/0_stateless/02870_per_column_compress_block.sql new file mode 100644 index 00000000000..5ff0e4fe0c4 --- /dev/null +++ b/tests/queries/0_stateless/02870_per_column_compress_block.sql @@ -0,0 +1,32 @@ +-- Tags: no-random-merge-tree-settings +CREATE TABLE t +( + `id` UInt64 CODEC(ZSTD(1)), + `long_string` String CODEC(ZSTD(9, 24)) COMPRESS BLOCK (67108864, 67108864), + `v1` String CODEC(ZSTD(1)), + `v2` UInt64 CODEC(ZSTD(1)), + `v3` Float32 CODEC(ZSTD(1)), + `v4` Float64 CODEC(ZSTD(1)) +) +ENGINE = MergeTree +ORDER BY id +SETTINGS min_bytes_for_wide_part = 1; + +INSERT INTO TABLE t SELECT number, randomPrintableASCII(1000), randomPrintableASCII(10), rand(number), rand(number+1), rand(number+2) FROM numbers(1000); + +SELECT count() FROM t; + +SET allow_experimental_object_type = 1; + +CREATE TABLE t2 +( + `id` UInt64 CODEC(ZSTD(1)), + `tup` Tuple(UInt64, UInt64) CODEC(ZSTD(1)) COMPRESS BLOCK (1024, 8192), + `json` JSON CODEC(ZSTD(9, 24)) COMPRESS BLOCK (671088, 671088), +) +ENGINE = MergeTree +ORDER BY id +SETTINGS min_bytes_for_wide_part = 1; + +INSERT INTO TABLE t2 SELECT number, tuple(number, number), concat('{"key": ', toString(number), ' ,"value": ', toString(rand(number+1)), '}') FROM numbers(1000); +SELECT tup, json.key AS key FROM t2 ORDER BY key LIMIT 10; From bb9521542da3c880eed5acb6796a7a1eb98e7f9c Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Thu, 28 Sep 2023 09:46:37 +0000 Subject: [PATCH 02/12] change syntax to per-column settings Signed-off-by: Duc Canh Le --- src/Interpreters/InterpreterCreateQuery.cpp | 31 +++++++-------- src/Parsers/ASTColumnDeclaration.cpp | 19 ++++----- src/Parsers/ASTColumnDeclaration.h | 2 +- src/Parsers/ParserCreateQuery.h | 39 +++++++++++++------ src/Storages/ColumnsDescription.cpp | 25 ++++++------ src/Storages/ColumnsDescription.h | 3 +- .../MergeTree/MergeTreeDataPartWriterWide.cpp | 10 ++++- .../02870_per_column_compress_block.sql | 16 ++++++-- 8 files changed, 88 insertions(+), 57 deletions(-) diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index 6e27e2eb598..e3e718c4c15 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -436,12 +438,12 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) column_declaration->children.push_back(column_declaration->codec); } - if (column.compress_block_sizes.first || column.compress_block_sizes.second) + if (!column.settings.empty()) { - Tuple value; - value.push_back(column.compress_block_sizes.first); - value.push_back(column.compress_block_sizes.second); - column_declaration->compress_block_sizes = std::make_shared(Field(value)); + auto per_column_settings = std::make_shared(); + per_column_settings->is_standalone = false; + per_column_settings->changes = column.settings; + column_declaration->per_column_settings = std::move(per_column_settings); } if (column.ttl) @@ -646,20 +648,17 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription( col_decl.codec, column.type, sanity_check_compression_codecs, allow_experimental_codecs, enable_deflate_qpl_codec); } - if (col_decl.compress_block_sizes) - { - auto sizes = col_decl.compress_block_sizes->as().value.safeGet(); - if (sizes.size() != 2 || sizes[0].getType() != Field::Types::UInt64 || sizes[0].getType() != Field::Types::UInt64) - throw Exception(ErrorCodes::SYNTAX_ERROR, "Column {}: COMPRESSION BLOCK must be tuple of two unsigned integer", column.name); - column.compress_block_sizes.first = sizes[0].safeGet(); - column.compress_block_sizes.second = sizes[1].safeGet(); - if (column.compress_block_sizes.first > column.compress_block_sizes.second) - throw Exception(ErrorCodes::SYNTAX_ERROR, "Column {}: min compress block size must smaller than max compress block size", column.name); - } - if (col_decl.ttl) column.ttl = col_decl.ttl; + if (col_decl.per_column_settings) + { + column.settings = col_decl.per_column_settings->as().changes; + /// Sanity check here, assume mergetree + MergeTreeSettings dummy; + dummy.applyChanges(column.settings); + } + res.add(std::move(column)); } diff --git a/src/Parsers/ASTColumnDeclaration.cpp b/src/Parsers/ASTColumnDeclaration.cpp index 99cb17b0bce..80cae040893 100644 --- a/src/Parsers/ASTColumnDeclaration.cpp +++ b/src/Parsers/ASTColumnDeclaration.cpp @@ -39,10 +39,10 @@ ASTPtr ASTColumnDeclaration::clone() const res->children.push_back(res->codec); } - if (compress_block_sizes) + if (per_column_settings) { - res->compress_block_sizes = compress_block_sizes->clone(); - res->children.push_back(res->compress_block_sizes); + res->per_column_settings = per_column_settings->clone(); + res->children.push_back(res->per_column_settings); } if (ttl) @@ -105,12 +105,6 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatSta codec->formatImpl(settings, state, frame); } - if (compress_block_sizes) - { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "COMPRESS BLOCK" << (settings.hilite ? hilite_none : "") << ' '; - compress_block_sizes->formatImpl(settings, state, frame); - } - if (ttl) { settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "TTL" << (settings.hilite ? hilite_none : "") << ' '; @@ -122,6 +116,13 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatSta settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "COLLATE" << (settings.hilite ? hilite_none : "") << ' '; collation->formatImpl(settings, state, frame); } + + if (per_column_settings) + { + settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "SETTINGS" << (settings.hilite ? hilite_none : "") << ' ' << '('; + per_column_settings->formatImpl(settings, state, frame); + settings.ostr << ')'; + } } } diff --git a/src/Parsers/ASTColumnDeclaration.h b/src/Parsers/ASTColumnDeclaration.h index 6e73b52ce71..e311b18e896 100644 --- a/src/Parsers/ASTColumnDeclaration.h +++ b/src/Parsers/ASTColumnDeclaration.h @@ -20,8 +20,8 @@ public: ASTPtr comment; ASTPtr codec; ASTPtr ttl; - ASTPtr compress_block_sizes; ASTPtr collation; + ASTPtr per_column_settings; bool primary_key_specifier = false; String getID(char delim) const override { return "ColumnDeclaration" + (delim + name); } diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index 8ba81b66fda..76e6c174567 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace DB @@ -136,14 +137,14 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ParserKeyword s_type{"TYPE"}; ParserKeyword s_collate{"COLLATE"}; ParserKeyword s_primary_key{"PRIMARY KEY"}; - ParserKeyword s_compress_block{"COMPRESS BLOCK"}; + ParserKeyword s_settings("SETTINGS"); ParserExpression expr_parser; ParserStringLiteral string_literal_parser; ParserLiteral literal_parser; ParserCodec codec_parser; - ParserTupleOfLiterals compress_block_parser; ParserCollation collation_parser; ParserExpression expression_parser; + ParserSetQuery settings_parser(true); /// mandatory column name ASTPtr name; @@ -178,7 +179,7 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ASTPtr default_expression; ASTPtr comment_expression; ASTPtr codec_expression; - ASTPtr compress_block_sizes; + ASTPtr per_column_settings; ASTPtr ttl_expression; ASTPtr collation_expression; bool primary_key_specifier = false; @@ -304,12 +305,6 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E return false; } - if (s_compress_block.ignore(pos, expected)) - { - if (!compress_block_parser.parse(pos, compress_block_sizes, expected)) - return false; - } - if (s_ttl.ignore(pos, expected)) { if (!expression_parser.parse(pos, ttl_expression, expected)) @@ -321,6 +316,26 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E primary_key_specifier = true; } + auto old_pos = pos; + if (s_settings.ignore(pos, expected)) + { + ParserToken parser_opening_bracket(TokenType::OpeningRoundBracket); + if (parser_opening_bracket.ignore(pos, expected)) + { + if (!settings_parser.parse(pos, per_column_settings, expected)) + return false; + ParserToken parser_closing_bracket(TokenType::ClosingRoundBracket); + if (!parser_closing_bracket.ignore(pos, expected)) + return false; + } + else + { + /// This could be settings in alter query + /// E.g: ALTER TABLE alter_enum_array MODIFY COLUMN x String SETTINGS mutations_sync=2; + pos = old_pos; + } + } + node = column_declaration; if (type) @@ -351,10 +366,10 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E column_declaration->children.push_back(std::move(codec_expression)); } - if (compress_block_sizes) + if (per_column_settings) { - column_declaration->compress_block_sizes = compress_block_sizes; - column_declaration->children.push_back(std::move(compress_block_sizes)); + column_declaration->per_column_settings = per_column_settings; + column_declaration->children.push_back(std::move(per_column_settings)); } if (ttl_expression) diff --git a/src/Storages/ColumnsDescription.cpp b/src/Storages/ColumnsDescription.cpp index 6c0940463a8..46eee56afc9 100644 --- a/src/Storages/ColumnsDescription.cpp +++ b/src/Storages/ColumnsDescription.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "Parsers/ASTSetQuery.h" #include #include #include @@ -62,7 +63,7 @@ bool ColumnDescription::operator==(const ColumnDescription & other) const && default_desc == other.default_desc && comment == other.comment && ast_to_str(codec) == ast_to_str(other.codec) - && compress_block_sizes == other.compress_block_sizes + && settings == other.settings && ast_to_str(ttl) == ast_to_str(other.ttl); } @@ -95,14 +96,15 @@ void ColumnDescription::writeText(WriteBuffer & buf) const writeEscapedString(queryToString(codec), buf); } - if (compress_block_sizes.first || compress_block_sizes.second) + if (!settings.empty()) { writeChar('\t', buf); - DB::writeText("COMPRESSION BLOCK ", buf); - Tuple value; - value.push_back(compress_block_sizes.first); - value.push_back(compress_block_sizes.second); - writeEscapedString(queryToString(ASTLiteral(Field(value))), buf); + DB::writeText("SETTINGS ", buf); + DB::writeText("(", buf); + ASTSetQuery ast; + ast.changes = settings; + writeEscapedString(queryToString(ast), buf); + DB::writeText(")", buf); } if (ttl) @@ -149,12 +151,9 @@ void ColumnDescription::readText(ReadBuffer & buf) if (col_ast->ttl) ttl = col_ast->ttl; - if (col_ast->compress_block_sizes) - { - auto sizes = col_ast->compress_block_sizes->as().value.safeGet(); - compress_block_sizes.first = sizes[0].safeGet(); - compress_block_sizes.second = sizes[1].safeGet(); - } + + if (col_ast->per_column_settings) + settings = col_ast->per_column_settings->as().changes; } else throw Exception(ErrorCodes::CANNOT_PARSE_TEXT, "Cannot parse column description"); diff --git a/src/Storages/ColumnsDescription.h b/src/Storages/ColumnsDescription.h index 6b7ec279835..2f2d0c7d77c 100644 --- a/src/Storages/ColumnsDescription.h +++ b/src/Storages/ColumnsDescription.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -82,7 +83,7 @@ struct ColumnDescription ColumnDefault default_desc; String comment; ASTPtr codec; - std::pair compress_block_sizes; + SettingsChanges settings; ASTPtr ttl; ColumnDescription() = default; diff --git a/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp b/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp index 74b00bb5ee7..b7d4d7895c3 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp +++ b/src/Storages/MergeTree/MergeTreeDataPartWriterWide.cpp @@ -145,7 +145,10 @@ void MergeTreeDataPartWriterWide::addStreams( const auto column_desc = metadata_snapshot->columns.tryGetColumnDescription(GetColumnsOptions(GetColumnsOptions::AllPhysical), column.getNameInStorage()); - auto max_compress_block_size = column_desc ? column_desc->compress_block_sizes.second : 0; + UInt64 max_compress_block_size = 0; + if (column_desc) + if (const auto * value = column_desc->settings.tryGet("max_compress_block_size")) + max_compress_block_size = value->safeGet(); if (!max_compress_block_size) max_compress_block_size = settings.max_compress_block_size; @@ -329,7 +332,10 @@ StreamsWithMarks MergeTreeDataPartWriterWide::getCurrentMarksForColumn( { StreamsWithMarks result; const auto column_desc = metadata_snapshot->columns.tryGetColumnDescription(GetColumnsOptions(GetColumnsOptions::AllPhysical), column.getNameInStorage()); - auto min_compress_block_size = column_desc ? column_desc->compress_block_sizes.first : 0; + UInt64 min_compress_block_size = 0; + if (column_desc) + if (const auto * value = column_desc->settings.tryGet("min_compress_block_size")) + min_compress_block_size = value->safeGet(); if (!min_compress_block_size) min_compress_block_size = settings.min_compress_block_size; data_part->getSerialization(column.name)->enumerateStreams([&] (const ISerialization::SubstreamPath & substream_path) diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.sql b/tests/queries/0_stateless/02870_per_column_compress_block.sql index 5ff0e4fe0c4..9b0c0210cf5 100644 --- a/tests/queries/0_stateless/02870_per_column_compress_block.sql +++ b/tests/queries/0_stateless/02870_per_column_compress_block.sql @@ -2,7 +2,7 @@ CREATE TABLE t ( `id` UInt64 CODEC(ZSTD(1)), - `long_string` String CODEC(ZSTD(9, 24)) COMPRESS BLOCK (67108864, 67108864), + `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), `v1` String CODEC(ZSTD(1)), `v2` UInt64 CODEC(ZSTD(1)), `v3` Float32 CODEC(ZSTD(1)), @@ -21,8 +21,8 @@ SET allow_experimental_object_type = 1; CREATE TABLE t2 ( `id` UInt64 CODEC(ZSTD(1)), - `tup` Tuple(UInt64, UInt64) CODEC(ZSTD(1)) COMPRESS BLOCK (1024, 8192), - `json` JSON CODEC(ZSTD(9, 24)) COMPRESS BLOCK (671088, 671088), + `tup` Tuple(UInt64, UInt64) CODEC(ZSTD(1)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), + `json` JSON CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), ) ENGINE = MergeTree ORDER BY id @@ -30,3 +30,13 @@ SETTINGS min_bytes_for_wide_part = 1; INSERT INTO TABLE t2 SELECT number, tuple(number, number), concat('{"key": ', toString(number), ' ,"value": ', toString(rand(number+1)), '}') FROM numbers(1000); SELECT tup, json.key AS key FROM t2 ORDER BY key LIMIT 10; + + +CREATE TABLE t3 +( + `id` UInt64 CODEC(ZSTD(1)), + `long_string` String CODEC(ZSTD(1)) SETTINGS (min_block_size = 81920, max_compress_block_size = 163840), +) +ENGINE = MergeTree +ORDER BY id +SETTINGS min_bytes_for_wide_part = 1; -- {serverError 115} From 4ff4b0a84bccd492d6f09b2cabf64809efa26cab Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Fri, 29 Sep 2023 04:25:34 +0000 Subject: [PATCH 03/12] column-level settings: alter-able Signed-off-by: Duc Canh Le --- src/Interpreters/InterpreterCreateQuery.cpp | 4 +--- src/Parsers/ParserAlterQuery.cpp | 3 +++ src/Storages/AlterCommands.cpp | 22 +++++++++++++++++++- src/Storages/AlterCommands.h | 5 +++-- src/Storages/MergeTree/MergeTreeSettings.cpp | 16 ++++++++++++++ src/Storages/MergeTree/MergeTreeSettings.h | 6 ++++++ 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index e3e718c4c15..15a4efff857 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -654,9 +654,7 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription( if (col_decl.per_column_settings) { column.settings = col_decl.per_column_settings->as().changes; - /// Sanity check here, assume mergetree - MergeTreeSettings dummy; - dummy.applyChanges(column.settings); + MergeTreeColumnSettings::validate(column.settings); } res.add(std::move(column)); diff --git a/src/Parsers/ParserAlterQuery.cpp b/src/Parsers/ParserAlterQuery.cpp index 8292b52f092..2f332e507e3 100644 --- a/src/Parsers/ParserAlterQuery.cpp +++ b/src/Parsers/ParserAlterQuery.cpp @@ -103,6 +103,7 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected ParserKeyword s_comment("COMMENT"); ParserKeyword s_codec("CODEC"); ParserKeyword s_ttl("TTL"); + ParserKeyword s_column_settings("COLUMN SETTINGS"); ParserKeyword s_remove_ttl("REMOVE TTL"); ParserKeyword s_remove_sample_by("REMOVE SAMPLE BY"); @@ -636,6 +637,8 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected command->remove_property = "CODEC"; else if (s_ttl.ignore(pos, expected)) command->remove_property = "TTL"; + else if (s_column_settings.ignore(pos, expected)) + command->remove_property = "COLUMN SETTINGS"; else return false; } diff --git a/src/Storages/AlterCommands.cpp b/src/Storages/AlterCommands.cpp index 3ade4474b6b..52fe6067c84 100644 --- a/src/Storages/AlterCommands.cpp +++ b/src/Storages/AlterCommands.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace DB { @@ -65,6 +66,8 @@ AlterCommand::RemoveProperty removePropertyFromString(const String & property) return AlterCommand::RemoveProperty::CODEC; else if (property == "TTL") return AlterCommand::RemoveProperty::TTL; + else if (property == "COLUMN SETTINGS") + return AlterCommand::RemoveProperty::SETTINGS; throw Exception(ErrorCodes::BAD_ARGUMENTS, "Cannot remove unknown property '{}'", property); } @@ -164,6 +167,9 @@ std::optional AlterCommand::parse(const ASTAlterCommand * command_ if (ast_col_decl.codec) command.codec = ast_col_decl.codec; + if (ast_col_decl.per_column_settings) + command.settings_changes = ast_col_decl.per_column_settings->as().changes; + if (command_ast->column) command.after_column = getIdentifierName(command_ast->column); @@ -428,6 +434,10 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context) { column.ttl.reset(); } + else if (to_remove == RemoveProperty::SETTINGS) + { + column.settings.clear(); + } else { if (codec) @@ -442,6 +452,12 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context) if (data_type) column.type = data_type; + if (!settings_changes.empty()) + { + MergeTreeColumnSettings::validate(settings_changes); + column.settings = settings_changes; + } + /// User specified default expression or changed /// datatype. We have to replace default. if (default_expression || data_type) @@ -1189,7 +1205,11 @@ void AlterCommands::validate(const StoragePtr & table, ContextPtr context) const ErrorCodes::BAD_ARGUMENTS, "Column {} doesn't have COMMENT, cannot remove it", backQuote(column_name)); - + if (command.to_remove == AlterCommand::RemoveProperty::SETTINGS && column_from_table.settings.empty()) + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Column {} doesn't have SETTINGS, cannot remove it", + backQuote(column_name)); } modified_columns.emplace(column_name); diff --git a/src/Storages/AlterCommands.h b/src/Storages/AlterCommands.h index c06872f9757..8afcddc5954 100644 --- a/src/Storages/AlterCommands.h +++ b/src/Storages/AlterCommands.h @@ -61,7 +61,8 @@ struct AlterCommand /// Other properties COMMENT, CODEC, - TTL + TTL, + SETTINGS }; Type type = UNKNOWN; @@ -130,7 +131,7 @@ struct AlterCommand /// For ADD and MODIFY ASTPtr codec = nullptr; - /// For MODIFY SETTING + /// For MODIFY SETTING or MODIFY COLUMN SETTINGS SettingsChanges settings_changes; /// For RESET SETTING diff --git a/src/Storages/MergeTree/MergeTreeSettings.cpp b/src/Storages/MergeTree/MergeTreeSettings.cpp index 1906f130101..33b137b60da 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.cpp +++ b/src/Storages/MergeTree/MergeTreeSettings.cpp @@ -212,4 +212,20 @@ void MergeTreeSettings::sanityCheck(size_t background_pool_tasks) const merge_selecting_sleep_slowdown_factor); } } + +void MergeTreeColumnSettings::validate(const SettingsChanges & changes) +{ + static MergeTreeSettings merge_tree_settings; + static std::set allowed_column_level_settings = {"min_compress_block_size", "max_compress_block_size"}; + for (const auto & change : changes) + { + if (!allowed_column_level_settings.contains(change.name)) + throw Exception( + ErrorCodes::UNKNOWN_SETTING, + "Setting {} is unknown or not supported at column level, supported settings: {}", + change.name, + fmt::join(allowed_column_level_settings, ", ")); + merge_tree_settings.checkCanSet(change.name, change.value); + } +} } diff --git a/src/Storages/MergeTree/MergeTreeSettings.h b/src/Storages/MergeTree/MergeTreeSettings.h index dbae87b0c5e..16a8d726abc 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.h +++ b/src/Storages/MergeTree/MergeTreeSettings.h @@ -245,6 +245,12 @@ struct MergeTreeSettings : public BaseSettings void sanityCheck(size_t background_pool_tasks) const; }; + using MergeTreeSettingsPtr = std::shared_ptr; +namespace MergeTreeColumnSettings +{ + void validate(const SettingsChanges & changes); +} + } From bb62b91f94f29b799cdba178096ae5ed9738414d Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Mon, 2 Oct 2023 05:55:39 +0000 Subject: [PATCH 04/12] only allow column level settings for MergeTree family Signed-off-by: Duc Canh Le --- src/Interpreters/InterpreterCreateQuery.cpp | 41 ++++++++++++------- src/Storages/MergeTree/MergeTreeSettings.cpp | 9 +++- .../02870_per_column_compress_block.sql | 10 ++++- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index 15a4efff857..10f435ceac4 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -841,22 +841,33 @@ void InterpreterCreateQuery::validateTableStructure(const ASTCreateQuery & creat throw Exception(ErrorCodes::DUPLICATE_COLUMN, "Column {} already exists", backQuoteIfNeed(column.name)); } - /// Check if _row_exists for lightweight delete column in column_lists for merge tree family. - if (create.storage && create.storage->engine && endsWith(create.storage->engine->name, "MergeTree")) + if (create.storage && create.storage->engine) { - auto search = all_columns.find(LightweightDeleteDescription::FILTER_COLUMN.name); - if (search != all_columns.end()) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, - "Cannot create table with column '{}' for *MergeTree engines because it " - "is reserved for lightweight delete feature", - LightweightDeleteDescription::FILTER_COLUMN.name); - - auto search_block_number = all_columns.find(BlockNumberColumn::name); - if (search_block_number != all_columns.end()) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, - "Cannot create table with column '{}' for *MergeTree engines because it " - "is reserved for storing block number", - BlockNumberColumn::name); + /// Check if _row_exists for lightweight delete column in column_lists for merge tree family. + if (endsWith(create.storage->engine->name, "MergeTree")) + { + auto search = all_columns.find(LightweightDeleteDescription::FILTER_COLUMN.name); + if (search != all_columns.end()) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, + "Cannot create table with column '{}' for *MergeTree engines because it " + "is reserved for lightweight delete feature", + LightweightDeleteDescription::FILTER_COLUMN.name); + auto search_block_number = all_columns.find(BlockNumberColumn::name); + if (search_block_number != all_columns.end()) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, + "Cannot create table with column '{}' for *MergeTree engines because it " + "is reserved for storing block number", + BlockNumberColumn::name); + } + else + { + /// Only merge tree family supports column with custom column setting + if (std::any_of( + properties.columns.begin(), + properties.columns.end(), + [](const ColumnDescription & column) { return !column.settings.empty(); })) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot create table with column level settings for non-MergeTree engines"); + } } const auto & settings = getContext()->getSettingsRef(); diff --git a/src/Storages/MergeTree/MergeTreeSettings.cpp b/src/Storages/MergeTree/MergeTreeSettings.cpp index 33b137b60da..4042d2d5d33 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.cpp +++ b/src/Storages/MergeTree/MergeTreeSettings.cpp @@ -215,8 +215,12 @@ void MergeTreeSettings::sanityCheck(size_t background_pool_tasks) const void MergeTreeColumnSettings::validate(const SettingsChanges & changes) { - static MergeTreeSettings merge_tree_settings; - static std::set allowed_column_level_settings = {"min_compress_block_size", "max_compress_block_size"}; + static const MergeTreeSettings merge_tree_settings; + static const std::set allowed_column_level_settings = + { + "min_compress_block_size", + "max_compress_block_size" + }; for (const auto & change : changes) { if (!allowed_column_level_settings.contains(change.name)) @@ -228,4 +232,5 @@ void MergeTreeColumnSettings::validate(const SettingsChanges & changes) merge_tree_settings.checkCanSet(change.name, change.value); } } + } diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.sql b/tests/queries/0_stateless/02870_per_column_compress_block.sql index 9b0c0210cf5..589124ac1b4 100644 --- a/tests/queries/0_stateless/02870_per_column_compress_block.sql +++ b/tests/queries/0_stateless/02870_per_column_compress_block.sql @@ -8,7 +8,7 @@ CREATE TABLE t `v3` Float32 CODEC(ZSTD(1)), `v4` Float64 CODEC(ZSTD(1)) ) -ENGINE = MergeTree +ENGINE = ReplicatedMergeTree('/clickhouse/tables/{database}/t/2870', 'r1') ORDER BY id SETTINGS min_bytes_for_wide_part = 1; @@ -40,3 +40,11 @@ CREATE TABLE t3 ENGINE = MergeTree ORDER BY id SETTINGS min_bytes_for_wide_part = 1; -- {serverError 115} + +CREATE TABLE t4 +( + `id` UInt64 CODEC(ZSTD(1)), + `long_string` String CODEC(ZSTD(1)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), +) +ENGINE = TinyLog +ORDER BY id; -- {serverError 44} \ No newline at end of file From 50ad6457e4aa696a12ec6dd82f1bf3fa56136601 Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Mon, 2 Oct 2023 05:56:56 +0000 Subject: [PATCH 05/12] fix wrong column record on zookeeper Signed-off-by: Duc Canh Le --- src/Storages/ColumnsDescription.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Storages/ColumnsDescription.cpp b/src/Storages/ColumnsDescription.cpp index 46eee56afc9..6edc12c33dc 100644 --- a/src/Storages/ColumnsDescription.cpp +++ b/src/Storages/ColumnsDescription.cpp @@ -102,6 +102,7 @@ void ColumnDescription::writeText(WriteBuffer & buf) const DB::writeText("SETTINGS ", buf); DB::writeText("(", buf); ASTSetQuery ast; + ast.is_standalone = false; ast.changes = settings; writeEscapedString(queryToString(ast), buf); DB::writeText(")", buf); From 8e374882ccfc8474b916962e7cd4bf0901c13cf9 Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Tue, 3 Oct 2023 07:27:55 +0000 Subject: [PATCH 06/12] support `ALTER table MODIFY column REMOVE SETTING ..` Signed-off-by: Duc Canh Le --- src/Parsers/ParserAlterQuery.cpp | 10 ++++-- src/Storages/AlterCommands.cpp | 33 ++++++++++++++----- src/Storages/AlterCommands.h | 6 ++-- .../02870_per_column_compress_block.reference | 3 ++ .../02870_per_column_compress_block.sql | 21 ++++++++++-- 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/Parsers/ParserAlterQuery.cpp b/src/Parsers/ParserAlterQuery.cpp index 2f332e507e3..cdf012d752d 100644 --- a/src/Parsers/ParserAlterQuery.cpp +++ b/src/Parsers/ParserAlterQuery.cpp @@ -103,7 +103,7 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected ParserKeyword s_comment("COMMENT"); ParserKeyword s_codec("CODEC"); ParserKeyword s_ttl("TTL"); - ParserKeyword s_column_settings("COLUMN SETTINGS"); + ParserKeyword s_setting("SETTING"); ParserKeyword s_remove_ttl("REMOVE TTL"); ParserKeyword s_remove_sample_by("REMOVE SAMPLE BY"); @@ -637,8 +637,12 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected command->remove_property = "CODEC"; else if (s_ttl.ignore(pos, expected)) command->remove_property = "TTL"; - else if (s_column_settings.ignore(pos, expected)) - command->remove_property = "COLUMN SETTINGS"; + else if (s_setting.ignore(pos, expected)) + { + command->remove_property = "SETTING"; + if (!parser_reset_setting.parse(pos, command->settings_resets, expected)) + return false; + } else return false; } diff --git a/src/Storages/AlterCommands.cpp b/src/Storages/AlterCommands.cpp index 52fe6067c84..515bca2d9b7 100644 --- a/src/Storages/AlterCommands.cpp +++ b/src/Storages/AlterCommands.cpp @@ -66,8 +66,8 @@ AlterCommand::RemoveProperty removePropertyFromString(const String & property) return AlterCommand::RemoveProperty::CODEC; else if (property == "TTL") return AlterCommand::RemoveProperty::TTL; - else if (property == "COLUMN SETTINGS") - return AlterCommand::RemoveProperty::SETTINGS; + else if (property == "SETTING") + return AlterCommand::RemoveProperty::SETTING; throw Exception(ErrorCodes::BAD_ARGUMENTS, "Cannot remove unknown property '{}'", property); } @@ -143,6 +143,16 @@ std::optional AlterCommand::parse(const ASTAlterCommand * command_ const auto & ast_col_decl = command_ast->col_decl->as(); command.column_name = ast_col_decl.name; command.to_remove = removePropertyFromString(command_ast->remove_property); + if (command.to_remove == RemoveProperty::SETTING) + { + for (const ASTPtr & identifier_ast : command_ast->settings_resets->children) + { + const auto & identifier = identifier_ast->as(); + auto insertion = command.settings_resets.emplace(identifier.name()); + if (!insertion.second) + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Duplicate setting name {}", backQuote(identifier.name())); + } + } if (ast_col_decl.type) { @@ -434,9 +444,10 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context) { column.ttl.reset(); } - else if (to_remove == RemoveProperty::SETTINGS) + else if (to_remove == RemoveProperty::SETTING) { - column.settings.clear(); + for (const auto & setting : settings_resets) + column.settings.removeSetting(setting); } else { @@ -1205,11 +1216,15 @@ void AlterCommands::validate(const StoragePtr & table, ContextPtr context) const ErrorCodes::BAD_ARGUMENTS, "Column {} doesn't have COMMENT, cannot remove it", backQuote(column_name)); - if (command.to_remove == AlterCommand::RemoveProperty::SETTINGS && column_from_table.settings.empty()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Column {} doesn't have SETTINGS, cannot remove it", - backQuote(column_name)); + if (command.to_remove == AlterCommand::RemoveProperty::SETTING) + { + for (const auto & setting : command.settings_resets) + { + if (!column_from_table.settings.tryGet(setting)) + throw Exception( + ErrorCodes::BAD_ARGUMENTS, "Column {} doesn't have SETTINGS, cannot remove it", backQuote(column_name)); + } + } } modified_columns.emplace(column_name); diff --git a/src/Storages/AlterCommands.h b/src/Storages/AlterCommands.h index 8afcddc5954..3149d134a99 100644 --- a/src/Storages/AlterCommands.h +++ b/src/Storages/AlterCommands.h @@ -62,7 +62,7 @@ struct AlterCommand COMMENT, CODEC, TTL, - SETTINGS + SETTING }; Type type = UNKNOWN; @@ -131,10 +131,10 @@ struct AlterCommand /// For ADD and MODIFY ASTPtr codec = nullptr; - /// For MODIFY SETTING or MODIFY COLUMN SETTINGS + /// For MODIFY SETTING or MODIFY COLUMN with SETTINGS (...) SettingsChanges settings_changes; - /// For RESET SETTING + /// For RESET SETTING or MODIFY COLUMN REMOVE SETTING (...) std::set settings_resets; /// For MODIFY_QUERY diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.reference b/tests/queries/0_stateless/02870_per_column_compress_block.reference index ab98fba1668..96e01669414 100644 --- a/tests/queries/0_stateless/02870_per_column_compress_block.reference +++ b/tests/queries/0_stateless/02870_per_column_compress_block.reference @@ -1,4 +1,7 @@ +CREATE TABLE db_02780.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/db_02780/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 1000 +CREATE TABLE db_02780.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/db_02780/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE db_02780.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/db_02780/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 (0,0) 0 (1,1) 1 (2,2) 2 diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.sql b/tests/queries/0_stateless/02870_per_column_compress_block.sql index 589124ac1b4..65556edeeb8 100644 --- a/tests/queries/0_stateless/02870_per_column_compress_block.sql +++ b/tests/queries/0_stateless/02870_per_column_compress_block.sql @@ -1,8 +1,11 @@ -- Tags: no-random-merge-tree-settings +DROP DATABASE IF EXISTS db_02780; +CREATE DATABASE db_02780; +USE db_02780; CREATE TABLE t ( `id` UInt64 CODEC(ZSTD(1)), - `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), + `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840), `v1` String CODEC(ZSTD(1)), `v2` UInt64 CODEC(ZSTD(1)), `v3` Float32 CODEC(ZSTD(1)), @@ -12,10 +15,22 @@ ENGINE = ReplicatedMergeTree('/clickhouse/tables/{database}/t/2870', 'r1') ORDER BY id SETTINGS min_bytes_for_wide_part = 1; +SHOW CREATE t; + INSERT INTO TABLE t SELECT number, randomPrintableASCII(1000), randomPrintableASCII(10), rand(number), rand(number+1), rand(number+2) FROM numbers(1000); SELECT count() FROM t; +ALTER TABLE t MODIFY COLUMN long_string REMOVE SETTING min_compress_block_size, max_compress_block_size; + +SHOW CREATE t; + +ALTER TABLE t MODIFY COLUMN long_string String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840); + +SHOW CREATE t; + +DROP TABLE t; + SET allow_experimental_object_type = 1; CREATE TABLE t2 @@ -47,4 +62,6 @@ CREATE TABLE t4 `long_string` String CODEC(ZSTD(1)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), ) ENGINE = TinyLog -ORDER BY id; -- {serverError 44} \ No newline at end of file +ORDER BY id; -- {serverError 44} + +DROP DATABASE db_02780; \ No newline at end of file From f755e775349ac10207378e0774c4b76559fbd7c8 Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Sun, 14 Jan 2024 09:36:32 +0000 Subject: [PATCH 07/12] move column level setting to the end of declaration Signed-off-by: Duc Canh Le --- src/Interpreters/InterpreterCreateQuery.cpp | 16 ++++++++-------- src/Parsers/ASTColumnDeclaration.cpp | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index 01eedca2184..f3ef1e3359e 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -453,14 +453,6 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) column_declaration->children.push_back(column_declaration->codec); } - if (!column.settings.empty()) - { - auto per_column_settings = std::make_shared(); - per_column_settings->is_standalone = false; - per_column_settings->changes = column.settings; - column_declaration->per_column_settings = std::move(per_column_settings); - } - if (column.stat) { column_declaration->stat_type = column.stat->ast; @@ -473,6 +465,14 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) column_declaration->children.push_back(column_declaration->ttl); } + if (!column.settings.empty()) + { + auto per_column_settings = std::make_shared(); + per_column_settings->is_standalone = false; + per_column_settings->changes = column.settings; + column_declaration->per_column_settings = std::move(per_column_settings); + } + columns_list->children.push_back(column_declaration_ptr); } diff --git a/src/Parsers/ASTColumnDeclaration.cpp b/src/Parsers/ASTColumnDeclaration.cpp index 196780ccf29..dd3bf6ae8d8 100644 --- a/src/Parsers/ASTColumnDeclaration.cpp +++ b/src/Parsers/ASTColumnDeclaration.cpp @@ -39,12 +39,6 @@ ASTPtr ASTColumnDeclaration::clone() const res->children.push_back(res->codec); } - if (per_column_settings) - { - res->per_column_settings = per_column_settings->clone(); - res->children.push_back(res->per_column_settings); - } - if (stat_type) { res->stat_type = stat_type->clone(); @@ -63,6 +57,12 @@ ASTPtr ASTColumnDeclaration::clone() const res->children.push_back(res->collation); } + if (per_column_settings) + { + res->per_column_settings = per_column_settings->clone(); + res->children.push_back(res->per_column_settings); + } + return res; } From 22afcd46f44eb531fa67eebd766d73b00324360a Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Thu, 18 Jan 2024 05:17:07 +0000 Subject: [PATCH 08/12] add ALTER COLUMN MODIFY/RESET SETTING Signed-off-by: Duc Canh Le --- src/Interpreters/InterpreterCreateQuery.cpp | 53 +++++++--------- src/Parsers/ASTColumnDeclaration.cpp | 52 ++++++++-------- src/Parsers/ASTColumnDeclaration.h | 4 +- src/Parsers/ParserAlterQuery.cpp | 20 ++++--- src/Parsers/ParserCreateQuery.h | 33 +++++----- src/Storages/AlterCommands.cpp | 60 ++++++++++--------- src/Storages/AlterCommands.h | 9 ++- src/Storages/ColumnsDescription.cpp | 4 +- .../02870_per_column_compress_block.reference | 8 ++- .../02870_per_column_compress_block.sql | 18 ++++-- 10 files changed, 137 insertions(+), 124 deletions(-) diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index f3ef1e3359e..d002cc6d980 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -467,10 +467,10 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) if (!column.settings.empty()) { - auto per_column_settings = std::make_shared(); - per_column_settings->is_standalone = false; - per_column_settings->changes = column.settings; - column_declaration->per_column_settings = std::move(per_column_settings); + auto settings = std::make_shared(); + settings->is_standalone = false; + settings->changes = column.settings; + column_declaration->settings = std::move(settings); } columns_list->children.push_back(column_declaration_ptr); @@ -680,9 +680,9 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription( if (col_decl.ttl) column.ttl = col_decl.ttl; - if (col_decl.per_column_settings) + if (col_decl.settings) { - column.settings = col_decl.per_column_settings->as().changes; + column.settings = col_decl.settings->as().changes; MergeTreeColumnSettings::validate(column.settings); } @@ -890,33 +890,22 @@ void InterpreterCreateQuery::validateTableStructure(const ASTCreateQuery & creat throw Exception(ErrorCodes::DUPLICATE_COLUMN, "Column {} already exists", backQuoteIfNeed(column.name)); } - if (create.storage && create.storage->engine) + /// Check if _row_exists for lightweight delete column in column_lists for merge tree family. + if (create.storage && create.storage->engine && endsWith(create.storage->engine->name, "MergeTree")) { - /// Check if _row_exists for lightweight delete column in column_lists for merge tree family. - if (endsWith(create.storage->engine->name, "MergeTree")) - { - auto search = all_columns.find(LightweightDeleteDescription::FILTER_COLUMN.name); - if (search != all_columns.end()) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, - "Cannot create table with column '{}' for *MergeTree engines because it " - "is reserved for lightweight delete feature", - LightweightDeleteDescription::FILTER_COLUMN.name); - auto search_block_number = all_columns.find(BlockNumberColumn::name); - if (search_block_number != all_columns.end()) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, - "Cannot create table with column '{}' for *MergeTree engines because it " - "is reserved for storing block number", - BlockNumberColumn::name); - } - else - { - /// Only merge tree family supports column with custom column setting - if (std::any_of( - properties.columns.begin(), - properties.columns.end(), - [](const ColumnDescription & column) { return !column.settings.empty(); })) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot create table with column level settings for non-MergeTree engines"); - } + auto search = all_columns.find(LightweightDeleteDescription::FILTER_COLUMN.name); + if (search != all_columns.end()) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, + "Cannot create table with column '{}' for *MergeTree engines because it " + "is reserved for lightweight delete feature", + LightweightDeleteDescription::FILTER_COLUMN.name); + + auto search_block_number = all_columns.find(BlockNumberColumn::name); + if (search_block_number != all_columns.end()) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, + "Cannot create table with column '{}' for *MergeTree engines because it " + "is reserved for storing block number", + BlockNumberColumn::name); } const auto & settings = getContext()->getSettingsRef(); diff --git a/src/Parsers/ASTColumnDeclaration.cpp b/src/Parsers/ASTColumnDeclaration.cpp index dd3bf6ae8d8..a6db1453743 100644 --- a/src/Parsers/ASTColumnDeclaration.cpp +++ b/src/Parsers/ASTColumnDeclaration.cpp @@ -57,83 +57,83 @@ ASTPtr ASTColumnDeclaration::clone() const res->children.push_back(res->collation); } - if (per_column_settings) + if (settings) { - res->per_column_settings = per_column_settings->clone(); - res->children.push_back(res->per_column_settings); + res->settings = settings->clone(); + res->children.push_back(res->settings); } return res; } -void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const +void ASTColumnDeclaration::formatImpl(const FormatSettings & format_settings, FormatState & state, FormatStateStacked frame) const { frame.need_parens = false; /// We have to always backquote column names to avoid ambiguouty with INDEX and other declarations in CREATE query. - settings.ostr << backQuote(name); + format_settings.ostr << backQuote(name); if (type) { - settings.ostr << ' '; + format_settings.ostr << ' '; FormatStateStacked type_frame = frame; type_frame.indent = 0; - type->formatImpl(settings, state, type_frame); + type->formatImpl(format_settings, state, type_frame); } if (null_modifier) { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") - << (*null_modifier ? "" : "NOT ") << "NULL" << (settings.hilite ? hilite_none : ""); + format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") + << (*null_modifier ? "" : "NOT ") << "NULL" << (format_settings.hilite ? hilite_none : ""); } if (default_expression) { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << default_specifier << (settings.hilite ? hilite_none : ""); + format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") << default_specifier << (format_settings.hilite ? hilite_none : ""); if (!ephemeral_default) { - settings.ostr << ' '; - default_expression->formatImpl(settings, state, frame); + format_settings.ostr << ' '; + default_expression->formatImpl(format_settings, state, frame); } } if (comment) { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "COMMENT" << (settings.hilite ? hilite_none : "") << ' '; - comment->formatImpl(settings, state, frame); + format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") << "COMMENT" << (format_settings.hilite ? hilite_none : "") << ' '; + comment->formatImpl(format_settings, state, frame); } if (codec) { - settings.ostr << ' '; - codec->formatImpl(settings, state, frame); + format_settings.ostr << ' '; + codec->formatImpl(format_settings, state, frame); } if (stat_type) { - settings.ostr << ' '; - stat_type->formatImpl(settings, state, frame); + format_settings.ostr << ' '; + stat_type->formatImpl(format_settings, state, frame); } if (ttl) { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "TTL" << (settings.hilite ? hilite_none : "") << ' '; - ttl->formatImpl(settings, state, frame); + format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") << "TTL" << (format_settings.hilite ? hilite_none : "") << ' '; + ttl->formatImpl(format_settings, state, frame); } if (collation) { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "COLLATE" << (settings.hilite ? hilite_none : "") << ' '; - collation->formatImpl(settings, state, frame); + format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") << "COLLATE" << (format_settings.hilite ? hilite_none : "") << ' '; + collation->formatImpl(format_settings, state, frame); } - if (per_column_settings) + if (settings) { - settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << "SETTINGS" << (settings.hilite ? hilite_none : "") << ' ' << '('; - per_column_settings->formatImpl(settings, state, frame); - settings.ostr << ')'; + format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") << "SETTINGS" << (format_settings.hilite ? hilite_none : "") << ' ' << '('; + settings->formatImpl(format_settings, state, frame); + format_settings.ostr << ')'; } } diff --git a/src/Parsers/ASTColumnDeclaration.h b/src/Parsers/ASTColumnDeclaration.h index 980f6252953..d775928d05c 100644 --- a/src/Parsers/ASTColumnDeclaration.h +++ b/src/Parsers/ASTColumnDeclaration.h @@ -22,13 +22,13 @@ public: ASTPtr stat_type; ASTPtr ttl; ASTPtr collation; - ASTPtr per_column_settings; + ASTPtr settings; bool primary_key_specifier = false; String getID(char delim) const override { return "ColumnDeclaration" + (delim + name); } ASTPtr clone() const override; - void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; + void formatImpl(const FormatSettings & format_settings, FormatState & state, FormatStateStacked frame) const override; }; } diff --git a/src/Parsers/ParserAlterQuery.cpp b/src/Parsers/ParserAlterQuery.cpp index e41055ef8d8..527f5af829a 100644 --- a/src/Parsers/ParserAlterQuery.cpp +++ b/src/Parsers/ParserAlterQuery.cpp @@ -110,7 +110,7 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected ParserKeyword s_comment("COMMENT"); ParserKeyword s_codec("CODEC"); ParserKeyword s_ttl("TTL"); - ParserKeyword s_setting("SETTING"); + ParserKeyword s_settings("SETTINGS"); ParserKeyword s_remove_ttl("REMOVE TTL"); ParserKeyword s_remove_sample_by("REMOVE SAMPLE BY"); @@ -702,15 +702,21 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected command->remove_property = "CODEC"; else if (s_ttl.ignore(pos, expected)) command->remove_property = "TTL"; - else if (s_setting.ignore(pos, expected)) - { - command->remove_property = "SETTING"; - if (!parser_reset_setting.parse(pos, command->settings_resets, expected)) - return false; - } + else if (s_settings.ignore(pos, expected)) + command->remove_property = "SETTINGS"; else return false; } + else if (s_modify_setting.ignore(pos, expected)) + { + if (!parser_settings.parse(pos, command->settings_changes, expected)) + return false; + } + else if (s_reset_setting.ignore(pos, expected)) + { + if (!parser_reset_setting.parse(pos, command->settings_resets, expected)) + return false; + } else { if (s_first.ignore(pos, expected)) diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index ad1f24d36f7..80cf541cbdc 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -135,6 +135,8 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ParserKeyword s_stat{"STATISTIC"}; ParserKeyword s_ttl{"TTL"}; ParserKeyword s_remove{"REMOVE"}; + ParserKeyword s_modify_setting("MODIFY SETTING"); + ParserKeyword s_reset_setting("RESET SETTING"); ParserKeyword s_type{"TYPE"}; ParserKeyword s_collate{"COLLATE"}; ParserKeyword s_primary_key{"PRIMARY KEY"}; @@ -159,10 +161,12 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E /// This keyword may occur only in MODIFY COLUMN query. We check it here /// because ParserDataType parses types as an arbitrary identifiers and /// doesn't check that parsed string is existing data type. In this way - /// REMOVE keyword can be parsed as data type and further parsing will fail. - /// So we just check this keyword and in case of success return column - /// declaration with name only. - if (!require_type && s_remove.checkWithoutMoving(pos, expected)) + /// REMOVE, MODIFY SETTING, or RESET SETTING can be parsed as data type + /// and further parsing will fail. So we just check these keyword and in + /// case of success return column declaration with name only. + if (!require_type + && (s_remove.checkWithoutMoving(pos, expected) || s_modify_setting.checkWithoutMoving(pos, expected) + || s_reset_setting.checkWithoutMoving(pos, expected))) { if (!check_keywords_after_name) return false; @@ -181,10 +185,10 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ASTPtr default_expression; ASTPtr comment_expression; ASTPtr codec_expression; - ASTPtr per_column_settings; ASTPtr stat_type_expression; ASTPtr ttl_expression; ASTPtr collation_expression; + ASTPtr settings; bool primary_key_specifier = false; auto null_check_without_moving = [&]() -> bool @@ -325,24 +329,19 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E primary_key_specifier = true; } - auto old_pos = pos; if (s_settings.ignore(pos, expected)) { ParserToken parser_opening_bracket(TokenType::OpeningRoundBracket); - if (parser_opening_bracket.ignore(pos, expected)) + if (parser_opening_bracket.check(pos, expected)) { - if (!settings_parser.parse(pos, per_column_settings, expected)) + if (!settings_parser.parse(pos, settings, expected)) return false; ParserToken parser_closing_bracket(TokenType::ClosingRoundBracket); if (!parser_closing_bracket.ignore(pos, expected)) return false; } - else - { - /// This could be settings in alter query - /// E.g: ALTER TABLE alter_enum_array MODIFY COLUMN x String SETTINGS mutations_sync=2; - pos = old_pos; - } + /// This could be settings in alter query + /// E.g: ALTER TABLE alter_enum_array MODIFY COLUMN x String SETTINGS mutations_sync=2; } node = column_declaration; @@ -375,10 +374,10 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E column_declaration->children.push_back(std::move(codec_expression)); } - if (per_column_settings) + if (settings) { - column_declaration->per_column_settings = per_column_settings; - column_declaration->children.push_back(std::move(per_column_settings)); + column_declaration->settings = settings; + column_declaration->children.push_back(std::move(settings)); } if (stat_type_expression) diff --git a/src/Storages/AlterCommands.cpp b/src/Storages/AlterCommands.cpp index 7638732d2ba..7a9a013e85d 100644 --- a/src/Storages/AlterCommands.cpp +++ b/src/Storages/AlterCommands.cpp @@ -75,8 +75,8 @@ AlterCommand::RemoveProperty removePropertyFromString(const String & property) return AlterCommand::RemoveProperty::CODEC; else if (property == "TTL") return AlterCommand::RemoveProperty::TTL; - else if (property == "SETTING") - return AlterCommand::RemoveProperty::SETTING; + else if (property == "SETTINGS") + return AlterCommand::RemoveProperty::SETTINGS; throw Exception(ErrorCodes::BAD_ARGUMENTS, "Cannot remove unknown property '{}'", property); } @@ -152,16 +152,6 @@ std::optional AlterCommand::parse(const ASTAlterCommand * command_ const auto & ast_col_decl = command_ast->col_decl->as(); command.column_name = ast_col_decl.name; command.to_remove = removePropertyFromString(command_ast->remove_property); - if (command.to_remove == RemoveProperty::SETTING) - { - for (const ASTPtr & identifier_ast : command_ast->settings_resets->children) - { - const auto & identifier = identifier_ast->as(); - auto insertion = command.settings_resets.emplace(identifier.name()); - if (!insertion.second) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Duplicate setting name {}", backQuote(identifier.name())); - } - } if (ast_col_decl.type) { @@ -186,8 +176,24 @@ std::optional AlterCommand::parse(const ASTAlterCommand * command_ if (ast_col_decl.codec) command.codec = ast_col_decl.codec; - if (ast_col_decl.per_column_settings) - command.settings_changes = ast_col_decl.per_column_settings->as().changes; + if (ast_col_decl.settings) + command.settings_changes = ast_col_decl.settings->as().changes; + + /// At most only one of ast_col_decl.settings or command_ast->settings_changes is non-null + if (command_ast->settings_changes) + { + command.settings_changes = command_ast->settings_changes->as().changes; + command.append_column_setting = true; + } + + if (command_ast->settings_resets) + { + for (const ASTPtr & identifier_ast : command_ast->settings_resets->children) + { + const auto & identifier = identifier_ast->as(); + command.settings_resets.emplace(identifier.name()); + } + } if (command_ast->column) command.after_column = getIdentifierName(command_ast->column); @@ -517,10 +523,9 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context) { column.ttl.reset(); } - else if (to_remove == RemoveProperty::SETTING) + else if (to_remove == RemoveProperty::SETTINGS) { - for (const auto & setting : settings_resets) - column.settings.removeSetting(setting); + column.settings.clear(); } else { @@ -539,7 +544,17 @@ void AlterCommand::apply(StorageInMemoryMetadata & metadata, ContextPtr context) if (!settings_changes.empty()) { MergeTreeColumnSettings::validate(settings_changes); - column.settings = settings_changes; + if (append_column_setting) + for (const auto & change : settings_changes) + column.settings.setSetting(change.name, change.value); + else + column.settings = settings_changes; + } + + if (!settings_resets.empty()) + { + for (const auto & setting : settings_resets) + column.settings.removeSetting(setting); } /// User specified default expression or changed @@ -1384,15 +1399,6 @@ void AlterCommands::validate(const StoragePtr & table, ContextPtr context) const ErrorCodes::BAD_ARGUMENTS, "Column {} doesn't have COMMENT, cannot remove it", backQuote(column_name)); - if (command.to_remove == AlterCommand::RemoveProperty::SETTING) - { - for (const auto & setting : command.settings_resets) - { - if (!column_from_table.settings.tryGet(setting)) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, "Column {} doesn't have SETTINGS, cannot remove it", backQuote(column_name)); - } - } } modified_columns.emplace(column_name); diff --git a/src/Storages/AlterCommands.h b/src/Storages/AlterCommands.h index fbd2f811630..f7ab1385f1a 100644 --- a/src/Storages/AlterCommands.h +++ b/src/Storages/AlterCommands.h @@ -65,7 +65,7 @@ struct AlterCommand COMMENT, CODEC, TTL, - SETTING + SETTINGS }; Type type = UNKNOWN; @@ -138,10 +138,10 @@ struct AlterCommand /// For ADD and MODIFY ASTPtr codec = nullptr; - /// For MODIFY SETTING or MODIFY COLUMN with SETTINGS (...) + /// For MODIFY SETTING or MODIFY COLUMN MODIFY SETTING SettingsChanges settings_changes; - /// For RESET SETTING or MODIFY COLUMN REMOVE SETTING (...) + /// For RESET SETTING or MODIFY COLUMN RESET SETTING std::set settings_resets; /// For MODIFY_QUERY @@ -156,6 +156,9 @@ struct AlterCommand /// What to remove from column (or TTL) RemoveProperty to_remove = RemoveProperty::NO_PROPERTY; + /// Is this MODIFY COLUMN MODIFY SETTING or MODIFY COLUMN parse(const ASTAlterCommand * command); void apply(StorageInMemoryMetadata & metadata, ContextPtr context) const; diff --git a/src/Storages/ColumnsDescription.cpp b/src/Storages/ColumnsDescription.cpp index 6e86dc4ddff..94f04c1af1c 100644 --- a/src/Storages/ColumnsDescription.cpp +++ b/src/Storages/ColumnsDescription.cpp @@ -159,8 +159,8 @@ void ColumnDescription::readText(ReadBuffer & buf) if (col_ast->ttl) ttl = col_ast->ttl; - if (col_ast->per_column_settings) - settings = col_ast->per_column_settings->as().changes; + if (col_ast->settings) + settings = col_ast->settings->as().changes; } else throw Exception(ErrorCodes::CANNOT_PARSE_TEXT, "Cannot parse column description"); diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.reference b/tests/queries/0_stateless/02870_per_column_compress_block.reference index 96e01669414..c6b396a11c2 100644 --- a/tests/queries/0_stateless/02870_per_column_compress_block.reference +++ b/tests/queries/0_stateless/02870_per_column_compress_block.reference @@ -1,7 +1,9 @@ -CREATE TABLE db_02780.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/db_02780/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 1000 -CREATE TABLE db_02780.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/db_02780/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 -CREATE TABLE db_02780.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/db_02780/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 8192, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 (0,0) 0 (1,1) 1 (2,2) 2 diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.sql b/tests/queries/0_stateless/02870_per_column_compress_block.sql index 65556edeeb8..079ece80fa0 100644 --- a/tests/queries/0_stateless/02870_per_column_compress_block.sql +++ b/tests/queries/0_stateless/02870_per_column_compress_block.sql @@ -1,7 +1,5 @@ -- Tags: no-random-merge-tree-settings -DROP DATABASE IF EXISTS db_02780; -CREATE DATABASE db_02780; -USE db_02780; + CREATE TABLE t ( `id` UInt64 CODEC(ZSTD(1)), @@ -21,7 +19,15 @@ INSERT INTO TABLE t SELECT number, randomPrintableASCII(1000), randomPrintableAS SELECT count() FROM t; -ALTER TABLE t MODIFY COLUMN long_string REMOVE SETTING min_compress_block_size, max_compress_block_size; +ALTER TABLE t MODIFY COLUMN long_string MODIFY SETTING min_compress_block_size = 8192; + +SHOW CREATE t; + +ALTER TABLE t MODIFY COLUMN long_string RESET SETTING min_compress_block_size; + +SHOW CREATE t; + +ALTER TABLE t MODIFY COLUMN long_string REMOVE SETTINGS; SHOW CREATE t; @@ -46,7 +52,9 @@ SETTINGS min_bytes_for_wide_part = 1; INSERT INTO TABLE t2 SELECT number, tuple(number, number), concat('{"key": ', toString(number), ' ,"value": ', toString(rand(number+1)), '}') FROM numbers(1000); SELECT tup, json.key AS key FROM t2 ORDER BY key LIMIT 10; +DROP TABLE t2; +-- Non-supported column setting CREATE TABLE t3 ( `id` UInt64 CODEC(ZSTD(1)), @@ -56,6 +64,7 @@ ENGINE = MergeTree ORDER BY id SETTINGS min_bytes_for_wide_part = 1; -- {serverError 115} +-- Invalid setting values CREATE TABLE t4 ( `id` UInt64 CODEC(ZSTD(1)), @@ -64,4 +73,3 @@ CREATE TABLE t4 ENGINE = TinyLog ORDER BY id; -- {serverError 44} -DROP DATABASE db_02780; \ No newline at end of file From b16a4cf36104907ce2eb255fdf5148ea53543667 Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Thu, 18 Jan 2024 07:55:44 +0000 Subject: [PATCH 09/12] add document Signed-off-by: Duc Canh Le --- .../mergetree-family/mergetree.md | 43 ++++++++++++++++- .../sql-reference/statements/alter/column.md | 46 +++++++++++++++++-- src/Parsers/ASTColumnDeclaration.cpp | 2 +- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/docs/en/engines/table-engines/mergetree-family/mergetree.md b/docs/en/engines/table-engines/mergetree-family/mergetree.md index 6d60611ae4b..95c962757b7 100644 --- a/docs/en/engines/table-engines/mergetree-family/mergetree.md +++ b/docs/en/engines/table-engines/mergetree-family/mergetree.md @@ -39,8 +39,8 @@ If you need to update rows frequently, we recommend using the [`ReplacingMergeTr ``` sql CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster] ( - name1 [type1] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr1] [COMMENT ...] [CODEC(codec1)] [STATISTIC(stat1)] [TTL expr1] [PRIMARY KEY], - name2 [type2] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr2] [COMMENT ...] [CODEC(codec2)] [STATISTIC(stat2)] [TTL expr2] [PRIMARY KEY], + name1 [type1] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr1] [COMMENT ...] [CODEC(codec1)] [STATISTIC(stat1)] [TTL expr1] [PRIMARY KEY] [SETTINGS (name = value, ...)], + name2 [type2] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr2] [COMMENT ...] [CODEC(codec2)] [STATISTIC(stat2)] [TTL expr2] [PRIMARY KEY] [SETTINGS (name = value, ...)], ... INDEX index_name1 expr1 TYPE type1(...) [GRANULARITY value1], INDEX index_name2 expr2 TYPE type2(...) [GRANULARITY value2], @@ -1390,3 +1390,42 @@ They can be used for query optimization when we enable `set allow_statistic_opti - `tdigest` Stores distribution of values from numeric columns in [TDigest](https://github.com/tdunning/t-digest) sketch. + +## Column Settings {#column-settings} + +Some table parameters can be override at column level by column settings. + +- `max_compress_block_size` — Maximum size of blocks of uncompressed data before compressing for writing to a table. +- `min_compress_block_size` — Minimum size of blocks of uncompressed data required for compression when writing the next mark. + +Example of creating table with column settings: + +```sql +CREATE TABLE example_table +( + id Int64, + document String CODEC(ZSTD(9,24)) SETTINGS (min_compress_block_size = 16777216, max_compress_block_size = 16777216) +) +ENGINE = MergeTree +ORDER BY id +``` + +Column settings can be modified or removed via [ALTER MODIFY COLUMN](/docs/en/sql-reference/statements/alter/column.md) query, for example: + +Remove `SETTINGS` from column declaration: + +```sql +ALTER TABLE example_table MODIFY COLUMN document REMOVE SETTINGS; +``` + +Modify a setting: + +```sql +ALTER TABLE example_table MODIFY COLUMN document MODIFY SETTING min_compress_block_size = 8192; +``` + +Reset one or more settings, after reset the setting expression is also removed from column declaration: + +```sql +ALTER TABLE example_table MODIFY COLUMN document RESET SETTING min_compress_block_size; +``` diff --git a/docs/en/sql-reference/statements/alter/column.md b/docs/en/sql-reference/statements/alter/column.md index 2cb802c863b..87cf8ca9914 100644 --- a/docs/en/sql-reference/statements/alter/column.md +++ b/docs/en/sql-reference/statements/alter/column.md @@ -23,10 +23,11 @@ The following actions are supported: - [RENAME COLUMN](#rename-column) — Renames an existing column. - [CLEAR COLUMN](#clear-column) — Resets column values. - [COMMENT COLUMN](#comment-column) — Adds a text comment to the column. -- [MODIFY COLUMN](#modify-column) — Changes column’s type, default expression and TTL. +- [MODIFY COLUMN](#modify-column) — Changes column’s type, default expression, TTL, and settings. - [MODIFY COLUMN REMOVE](#modify-column-remove) — Removes one of the column properties. +- [MODIFY COLUMN MODIFY SETTING](#modify-column-modify-setting) - Changes column settings. +- [MODIFY COLUMN RESET SETTING](#modify-column-reset-setting) - Reset column settings. - [MATERIALIZE COLUMN](#materialize-column) — Materializes the column in the parts where the column is missing. - These actions are described in detail below. ## ADD COLUMN @@ -75,7 +76,7 @@ Deletes the column with the name `name`. If the `IF EXISTS` clause is specified, Deletes data from the file system. Since this deletes entire files, the query is completed almost instantly. -:::tip +:::tip You can’t delete a column if it is referenced by [materialized view](/docs/en/sql-reference/statements/create/view.md/#materialized). Otherwise, it returns an error. ::: @@ -208,7 +209,7 @@ The `ALTER` query for changing columns is replicated. The instructions are saved ## MODIFY COLUMN REMOVE -Removes one of the column properties: `DEFAULT`, `ALIAS`, `MATERIALIZED`, `CODEC`, `COMMENT`, `TTL`. +Removes one of the column properties: `DEFAULT`, `ALIAS`, `MATERIALIZED`, `CODEC`, `COMMENT`, `TTL`, `SETTING`. Syntax: @@ -228,6 +229,43 @@ ALTER TABLE table_with_ttl MODIFY COLUMN column_ttl REMOVE TTL; - [REMOVE TTL](ttl.md). + +## MODIFY COLUMN MODIFY SETTING + +Modify a column level setting. + +Syntax: + +```sql +ALTER TABLE table_name MODIFY COLUMN MODIFY SETTING name=value,...; +``` + +**Example** + +Modify column's `max_compress_block_size` to `1MB`: + +```sql +ALTER TABLE table_name MODIFY COLUMN MODIFY SETTING max_compress_block_size = 1048576; +``` + +## MODIFY COLUMN RESET SETTING + +Reset a column setting, also remove the setting declaration in column expression in table create query. + +Syntax: + +```sql +ALTER TABLE table_name MODIFY COLUMN RESET SETTING name,...; +``` + +**Example** + +Remove column setting `max_compress_block_size` to `1MB`: + +```sql +ALTER TABLE table_name MODIFY COLUMN REMOVE SETTING max_compress_block_size; +``` + ## MATERIALIZE COLUMN Materializes or updates a column with an expression for a default value (`DEFAULT` or `MATERIALIZED`). diff --git a/src/Parsers/ASTColumnDeclaration.cpp b/src/Parsers/ASTColumnDeclaration.cpp index a6db1453743..6c29e0bf9d5 100644 --- a/src/Parsers/ASTColumnDeclaration.cpp +++ b/src/Parsers/ASTColumnDeclaration.cpp @@ -132,7 +132,7 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & format_settings, Fo if (settings) { format_settings.ostr << ' ' << (format_settings.hilite ? hilite_keyword : "") << "SETTINGS" << (format_settings.hilite ? hilite_none : "") << ' ' << '('; - settings->formatImpl(format_settings, state, frame); + settings->formatImpl(format_settings, state, frame); format_settings.ostr << ')'; } } From 1bfeee1954b2578374e34f5d2f877c96bae3c1a8 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Thu, 18 Jan 2024 19:52:13 +0000 Subject: [PATCH 10/12] Some fixups --- .../mergetree-family/mergetree.md | 42 +++++----- .../sql-reference/statements/alter/column.md | 6 +- src/Parsers/ParserAlterQuery.cpp | 4 +- src/Parsers/ParserCreateQuery.h | 12 +-- src/Storages/AlterCommands.h | 2 +- src/Storages/MergeTree/MergeTreeSettings.cpp | 1 + src/Storages/MergeTree/MergeTreeSettings.h | 3 +- .../02870_per_column_compress_block.reference | 16 ---- .../02870_per_column_compress_block.sql | 75 ------------------ .../02870_per_column_settings.reference | 19 +++++ .../0_stateless/02870_per_column_settings.sql | 78 +++++++++++++++++++ 11 files changed, 133 insertions(+), 125 deletions(-) delete mode 100644 tests/queries/0_stateless/02870_per_column_compress_block.reference delete mode 100644 tests/queries/0_stateless/02870_per_column_compress_block.sql create mode 100644 tests/queries/0_stateless/02870_per_column_settings.reference create mode 100644 tests/queries/0_stateless/02870_per_column_settings.sql diff --git a/docs/en/engines/table-engines/mergetree-family/mergetree.md b/docs/en/engines/table-engines/mergetree-family/mergetree.md index 658f57ceb9a..f185c11bab3 100644 --- a/docs/en/engines/table-engines/mergetree-family/mergetree.md +++ b/docs/en/engines/table-engines/mergetree-family/mergetree.md @@ -56,7 +56,7 @@ ORDER BY expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx' [, ...] ] [WHERE conditions] [GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ] ] -[SETTINGS name=value, ...] +[SETTINGS name = value, ...] ``` For a description of parameters, see the [CREATE query description](/docs/en/sql-reference/statements/create/table.md). @@ -620,7 +620,7 @@ The `TTL` clause can’t be used for key columns. #### Creating a table with `TTL`: ``` sql -CREATE TABLE example_table +CREATE TABLE tab ( d DateTime, a Int TTL d + INTERVAL 1 MONTH, @@ -635,7 +635,7 @@ ORDER BY d; #### Adding TTL to a column of an existing table ``` sql -ALTER TABLE example_table +ALTER TABLE tab MODIFY COLUMN c String TTL d + INTERVAL 1 DAY; ``` @@ -643,7 +643,7 @@ ALTER TABLE example_table #### Altering TTL of the column ``` sql -ALTER TABLE example_table +ALTER TABLE tab MODIFY COLUMN c String TTL d + INTERVAL 1 MONTH; ``` @@ -681,7 +681,7 @@ If a column is not part of the `GROUP BY` expression and is not set explicitly i #### Creating a table with `TTL`: ``` sql -CREATE TABLE example_table +CREATE TABLE tab ( d DateTime, a Int @@ -697,7 +697,7 @@ TTL d + INTERVAL 1 MONTH DELETE, #### Altering `TTL` of the table: ``` sql -ALTER TABLE example_table +ALTER TABLE tab MODIFY TTL d + INTERVAL 1 DAY; ``` @@ -1366,7 +1366,7 @@ In this sample configuration: The statistic declaration is in the columns section of the `CREATE` query for tables from the `*MergeTree*` Family when we enable `set allow_experimental_statistic = 1`. ``` sql -CREATE TABLE example_table +CREATE TABLE tab ( a Int64 STATISTIC(tdigest), b Float64 @@ -1378,8 +1378,8 @@ ORDER BY a We can also manipulate statistics with `ALTER` statements. ```sql -ALTER TABLE example_table ADD STATISTIC b TYPE tdigest; -ALTER TABLE example_table DROP STATISTIC a TYPE tdigest; +ALTER TABLE tab ADD STATISTIC b TYPE tdigest; +ALTER TABLE tab DROP STATISTIC a TYPE tdigest; ``` These lightweight statistics aggregate information about distribution of values in columns. @@ -1391,41 +1391,41 @@ They can be used for query optimization when we enable `set allow_statistic_opti Stores distribution of values from numeric columns in [TDigest](https://github.com/tdunning/t-digest) sketch. -## Column Settings {#column-settings} +## Column-level Settings {#column-level-settings} -Some table parameters can be override at column level by column settings. +Certain MergeTree settings can be override at column level: - `max_compress_block_size` — Maximum size of blocks of uncompressed data before compressing for writing to a table. - `min_compress_block_size` — Minimum size of blocks of uncompressed data required for compression when writing the next mark. -Example of creating table with column settings: +Example: ```sql -CREATE TABLE example_table +CREATE TABLE tab ( id Int64, - document String CODEC(ZSTD(9,24)) SETTINGS (min_compress_block_size = 16777216, max_compress_block_size = 16777216) + document String SETTINGS (min_compress_block_size = 16777216, max_compress_block_size = 16777216) ) ENGINE = MergeTree ORDER BY id ``` -Column settings can be modified or removed via [ALTER MODIFY COLUMN](/docs/en/sql-reference/statements/alter/column.md) query, for example: +Column-level settings can be modified or removed using [ALTER MODIFY COLUMN](/docs/en/sql-reference/statements/alter/column.md), for example: -Remove `SETTINGS` from column declaration: +- Remove `SETTINGS` from column declaration: ```sql -ALTER TABLE example_table MODIFY COLUMN document REMOVE SETTINGS; +ALTER TABLE tab MODIFY COLUMN document REMOVE SETTINGS; ``` -Modify a setting: +- Modify a setting: ```sql -ALTER TABLE example_table MODIFY COLUMN document MODIFY SETTING min_compress_block_size = 8192; +ALTER TABLE tab MODIFY COLUMN document MODIFY SETTING min_compress_block_size = 8192; ``` -Reset one or more settings, after reset the setting expression is also removed from column declaration: +- Reset one or more settings, also removes the setting declaration in the column expression of the table's CREATE query. ```sql -ALTER TABLE example_table MODIFY COLUMN document RESET SETTING min_compress_block_size; +ALTER TABLE tab MODIFY COLUMN document RESET SETTING min_compress_block_size; ``` diff --git a/docs/en/sql-reference/statements/alter/column.md b/docs/en/sql-reference/statements/alter/column.md index 87cf8ca9914..676d30f5e44 100644 --- a/docs/en/sql-reference/statements/alter/column.md +++ b/docs/en/sql-reference/statements/alter/column.md @@ -23,7 +23,7 @@ The following actions are supported: - [RENAME COLUMN](#rename-column) — Renames an existing column. - [CLEAR COLUMN](#clear-column) — Resets column values. - [COMMENT COLUMN](#comment-column) — Adds a text comment to the column. -- [MODIFY COLUMN](#modify-column) — Changes column’s type, default expression, TTL, and settings. +- [MODIFY COLUMN](#modify-column) — Changes column’s type, default expression, TTL, and column settings. - [MODIFY COLUMN REMOVE](#modify-column-remove) — Removes one of the column properties. - [MODIFY COLUMN MODIFY SETTING](#modify-column-modify-setting) - Changes column settings. - [MODIFY COLUMN RESET SETTING](#modify-column-reset-setting) - Reset column settings. @@ -232,7 +232,7 @@ ALTER TABLE table_with_ttl MODIFY COLUMN column_ttl REMOVE TTL; ## MODIFY COLUMN MODIFY SETTING -Modify a column level setting. +Modify a column setting. Syntax: @@ -250,7 +250,7 @@ ALTER TABLE table_name MODIFY COLUMN MODIFY SETTING max_compress_block_size = 10 ## MODIFY COLUMN RESET SETTING -Reset a column setting, also remove the setting declaration in column expression in table create query. +Reset a column setting, also removes the setting declaration in the column expression of the table's CREATE query. Syntax: diff --git a/src/Parsers/ParserAlterQuery.cpp b/src/Parsers/ParserAlterQuery.cpp index 7eb1ed2eff5..d72fb493368 100644 --- a/src/Parsers/ParserAlterQuery.cpp +++ b/src/Parsers/ParserAlterQuery.cpp @@ -733,12 +733,12 @@ bool ParserAlterCommand::parseImpl(Pos & pos, ASTPtr & node, Expected & expected } else if (s_modify_setting.ignore(pos, expected)) { - if (!parser_settings.parse(pos, command->settings_changes, expected)) + if (!parser_settings.parse(pos, command_settings_changes, expected)) return false; } else if (s_reset_setting.ignore(pos, expected)) { - if (!parser_reset_setting.parse(pos, command->settings_resets, expected)) + if (!parser_reset_setting.parse(pos, command_settings_resets, expected)) return false; } else diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index 80cf541cbdc..06973573023 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -121,8 +121,6 @@ using ParserCompoundColumnDeclaration = IParserColumnDeclaration bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) { - NameParser name_parser; - ParserDataType type_parser; ParserKeyword s_default{"DEFAULT"}; ParserKeyword s_null{"NULL"}; ParserKeyword s_not{"NOT"}; @@ -137,10 +135,13 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E ParserKeyword s_remove{"REMOVE"}; ParserKeyword s_modify_setting("MODIFY SETTING"); ParserKeyword s_reset_setting("RESET SETTING"); + ParserKeyword s_settings("SETTINGS"); ParserKeyword s_type{"TYPE"}; ParserKeyword s_collate{"COLLATE"}; ParserKeyword s_primary_key{"PRIMARY KEY"}; - ParserKeyword s_settings("SETTINGS"); + + NameParser name_parser; + ParserDataType type_parser; ParserExpression expr_parser; ParserStringLiteral string_literal_parser; ParserLiteral literal_parser; @@ -160,13 +161,12 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E /// This keyword may occur only in MODIFY COLUMN query. We check it here /// because ParserDataType parses types as an arbitrary identifiers and - /// doesn't check that parsed string is existing data type. In this way + /// doesn't check that parsed string is existing data type. In this way, /// REMOVE, MODIFY SETTING, or RESET SETTING can be parsed as data type /// and further parsing will fail. So we just check these keyword and in /// case of success return column declaration with name only. if (!require_type - && (s_remove.checkWithoutMoving(pos, expected) || s_modify_setting.checkWithoutMoving(pos, expected) - || s_reset_setting.checkWithoutMoving(pos, expected))) + && (s_remove.checkWithoutMoving(pos, expected) || s_modify_setting.checkWithoutMoving(pos, expected) || s_reset_setting.checkWithoutMoving(pos, expected))) { if (!check_keywords_after_name) return false; diff --git a/src/Storages/AlterCommands.h b/src/Storages/AlterCommands.h index f7ab1385f1a..d0d5d02b5f7 100644 --- a/src/Storages/AlterCommands.h +++ b/src/Storages/AlterCommands.h @@ -156,7 +156,7 @@ struct AlterCommand /// What to remove from column (or TTL) RemoveProperty to_remove = RemoveProperty::NO_PROPERTY; - /// Is this MODIFY COLUMN MODIFY SETTING or MODIFY COLUMN parse(const ASTAlterCommand * command); diff --git a/src/Storages/MergeTree/MergeTreeSettings.cpp b/src/Storages/MergeTree/MergeTreeSettings.cpp index b7e366855db..cefee36c124 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.cpp +++ b/src/Storages/MergeTree/MergeTreeSettings.cpp @@ -221,6 +221,7 @@ void MergeTreeColumnSettings::validate(const SettingsChanges & changes) "min_compress_block_size", "max_compress_block_size" }; + for (const auto & change : changes) { if (!allowed_column_level_settings.contains(change.name)) diff --git a/src/Storages/MergeTree/MergeTreeSettings.h b/src/Storages/MergeTree/MergeTreeSettings.h index 11aaec3ac34..b8ab682de08 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.h +++ b/src/Storages/MergeTree/MergeTreeSettings.h @@ -275,9 +275,10 @@ struct MergeTreeSettings : public BaseSettings, public std::vector getAllRegisteredNames() const override; }; - using MergeTreeSettingsPtr = std::shared_ptr; + +/// Column-level Merge-Tree settings which overwrite MergeTree settings namespace MergeTreeColumnSettings { void validate(const SettingsChanges & changes); diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.reference b/tests/queries/0_stateless/02870_per_column_compress_block.reference deleted file mode 100644 index c6b396a11c2..00000000000 --- a/tests/queries/0_stateless/02870_per_column_compress_block.reference +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 -1000 -CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 8192, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 -CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 -CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 -CREATE TABLE default.t\n(\n `id` UInt64 CODEC(ZSTD(1)),\n `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String CODEC(ZSTD(1)),\n `v2` UInt64 CODEC(ZSTD(1)),\n `v3` Float32 CODEC(ZSTD(1)),\n `v4` Float64 CODEC(ZSTD(1))\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/t/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 -(0,0) 0 -(1,1) 1 -(2,2) 2 -(3,3) 3 -(4,4) 4 -(5,5) 5 -(6,6) 6 -(7,7) 7 -(8,8) 8 -(9,9) 9 diff --git a/tests/queries/0_stateless/02870_per_column_compress_block.sql b/tests/queries/0_stateless/02870_per_column_compress_block.sql deleted file mode 100644 index 079ece80fa0..00000000000 --- a/tests/queries/0_stateless/02870_per_column_compress_block.sql +++ /dev/null @@ -1,75 +0,0 @@ --- Tags: no-random-merge-tree-settings - -CREATE TABLE t -( - `id` UInt64 CODEC(ZSTD(1)), - `long_string` String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840), - `v1` String CODEC(ZSTD(1)), - `v2` UInt64 CODEC(ZSTD(1)), - `v3` Float32 CODEC(ZSTD(1)), - `v4` Float64 CODEC(ZSTD(1)) -) -ENGINE = ReplicatedMergeTree('/clickhouse/tables/{database}/t/2870', 'r1') -ORDER BY id -SETTINGS min_bytes_for_wide_part = 1; - -SHOW CREATE t; - -INSERT INTO TABLE t SELECT number, randomPrintableASCII(1000), randomPrintableASCII(10), rand(number), rand(number+1), rand(number+2) FROM numbers(1000); - -SELECT count() FROM t; - -ALTER TABLE t MODIFY COLUMN long_string MODIFY SETTING min_compress_block_size = 8192; - -SHOW CREATE t; - -ALTER TABLE t MODIFY COLUMN long_string RESET SETTING min_compress_block_size; - -SHOW CREATE t; - -ALTER TABLE t MODIFY COLUMN long_string REMOVE SETTINGS; - -SHOW CREATE t; - -ALTER TABLE t MODIFY COLUMN long_string String CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840); - -SHOW CREATE t; - -DROP TABLE t; - -SET allow_experimental_object_type = 1; - -CREATE TABLE t2 -( - `id` UInt64 CODEC(ZSTD(1)), - `tup` Tuple(UInt64, UInt64) CODEC(ZSTD(1)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), - `json` JSON CODEC(ZSTD(9, 24)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), -) -ENGINE = MergeTree -ORDER BY id -SETTINGS min_bytes_for_wide_part = 1; - -INSERT INTO TABLE t2 SELECT number, tuple(number, number), concat('{"key": ', toString(number), ' ,"value": ', toString(rand(number+1)), '}') FROM numbers(1000); -SELECT tup, json.key AS key FROM t2 ORDER BY key LIMIT 10; - -DROP TABLE t2; - --- Non-supported column setting -CREATE TABLE t3 -( - `id` UInt64 CODEC(ZSTD(1)), - `long_string` String CODEC(ZSTD(1)) SETTINGS (min_block_size = 81920, max_compress_block_size = 163840), -) -ENGINE = MergeTree -ORDER BY id -SETTINGS min_bytes_for_wide_part = 1; -- {serverError 115} - --- Invalid setting values -CREATE TABLE t4 -( - `id` UInt64 CODEC(ZSTD(1)), - `long_string` String CODEC(ZSTD(1)) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), -) -ENGINE = TinyLog -ORDER BY id; -- {serverError 44} - diff --git a/tests/queries/0_stateless/02870_per_column_settings.reference b/tests/queries/0_stateless/02870_per_column_settings.reference new file mode 100644 index 00000000000..a57407e4f0e --- /dev/null +++ b/tests/queries/0_stateless/02870_per_column_settings.reference @@ -0,0 +1,19 @@ +CREATE TABLE default.tab\n(\n `id` UInt64,\n `long_string` String SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String,\n `v2` UInt64,\n `v3` Float32,\n `v4` Float64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/tab/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +1000 +CREATE TABLE default.tab\n(\n `id` UInt64,\n `long_string` String SETTINGS (min_compress_block_size = 8192, max_compress_block_size = 163840),\n `v1` String,\n `v2` UInt64,\n `v3` Float32,\n `v4` Float64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/tab/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.tab\n(\n `id` UInt64,\n `long_string` String SETTINGS (max_compress_block_size = 163840),\n `v1` String,\n `v2` UInt64,\n `v3` Float32,\n `v4` Float64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/tab/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.tab\n(\n `id` UInt64,\n `long_string` String,\n `v1` String,\n `v2` UInt64,\n `v3` Float32,\n `v4` Float64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/tab/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +CREATE TABLE default.tab\n(\n `id` UInt64,\n `long_string` String SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840),\n `v1` String,\n `v2` UInt64,\n `v3` Float32,\n `v4` Float64\n)\nENGINE = ReplicatedMergeTree(\'/clickhouse/tables/default/tab/2870\', \'r1\')\nORDER BY id\nSETTINGS min_bytes_for_wide_part = 1, index_granularity = 8192 +--- +(0,0) 0 +(1,1) 1 +(2,2) 2 +(3,3) 3 +(4,4) 4 +(5,5) 5 +(6,6) 6 +(7,7) 7 +(8,8) 8 +(9,9) 9 +--- +--- diff --git a/tests/queries/0_stateless/02870_per_column_settings.sql b/tests/queries/0_stateless/02870_per_column_settings.sql new file mode 100644 index 00000000000..bd115885330 --- /dev/null +++ b/tests/queries/0_stateless/02870_per_column_settings.sql @@ -0,0 +1,78 @@ +-- Tags: no-random-merge-tree-settings + +-- Tests column-level settings for MergeTree* tables + +DROP TABLE IF EXISTS tab; + +CREATE TABLE tab +( + id UInt64, + long_string String SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840), + v1 String, + v2 UInt64, + v3 Float32, + v4 Float64 +) +ENGINE = ReplicatedMergeTree('/clickhouse/tables/{database}/tab/2870', 'r1') +ORDER BY id +SETTINGS min_bytes_for_wide_part = 1; + +SHOW CREATE tab; + +INSERT INTO TABLE tab SELECT number, randomPrintableASCII(1000), randomPrintableASCII(10), rand(number), rand(number+1), rand(number+2) FROM numbers(1000); +SELECT count() FROM tab; + +ALTER TABLE tab MODIFY COLUMN long_string MODIFY SETTING min_compress_block_size = 8192; +SHOW CREATE tab; + +ALTER TABLE tab MODIFY COLUMN long_string RESET SETTING min_compress_block_size; +SHOW CREATE tab; + +ALTER TABLE tab MODIFY COLUMN long_string REMOVE SETTINGS; +SHOW CREATE tab; + +ALTER TABLE tab MODIFY COLUMN long_string String SETTINGS (min_compress_block_size = 163840, max_compress_block_size = 163840); +SHOW CREATE tab; + +DROP TABLE tab; + +SELECT '--- '; + +SET allow_experimental_object_type = 1; + +CREATE TABLE tab +( + id UInt64, + tup Tuple(UInt64, UInt64) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), + json JSON SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), +) +ENGINE = MergeTree +ORDER BY id +SETTINGS min_bytes_for_wide_part = 1; + +INSERT INTO TABLE tab SELECT number, tuple(number, number), concat('{"key": ', toString(number), ' ,"value": ', toString(rand(number+1)), '}') FROM numbers(1000); +SELECT tup, json.key AS key FROM tab ORDER BY key LIMIT 10; + +DROP TABLE tab; + +SELECT '--- '; + +-- Unsupported column-level settings are rejected +CREATE TABLE tab +( + id UInt64, + long_string String SETTINGS (min_block_size = 81920, max_compress_block_size = 163840), +) +ENGINE = MergeTree +ORDER BY id +SETTINGS min_bytes_for_wide_part = 1; -- {serverError UNKNOWN_SETTING} + +SELECT '--- '; + +-- Column-level settings are only supported for MergeTree* tables +CREATE TABLE tab +( + id UInt64 CODEC(ZSTD), + long_string String CODEC(ZSTD) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), +) +ENGINE = TinyLog; -- {serverError ILLEGAL_COLUMN} From ed031f32afb7863f278f125fc99082ead3c1fa68 Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Mon, 22 Jan 2024 16:06:29 +0000 Subject: [PATCH 11/12] address review comments Signed-off-by: Duc Canh Le --- src/Parsers/ParserCreateQuery.h | 13 ++++++++++--- .../0_stateless/02870_per_column_settings.sql | 8 -------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Parsers/ParserCreateQuery.h b/src/Parsers/ParserCreateQuery.h index 06973573023..c9059324bbe 100644 --- a/src/Parsers/ParserCreateQuery.h +++ b/src/Parsers/ParserCreateQuery.h @@ -329,10 +329,17 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E primary_key_specifier = true; } + auto old_pos = pos; if (s_settings.ignore(pos, expected)) { + /// When the keyword `SETTINGS` appear here, it can be a column settings declaration or query settings + /// For example: + /// - Column settings: `ALTER TABLE xx MODIFY COLUMN yy SETTINGS (name = value)` + /// - Query settings: ` ALTER TABLE xx MODIFY COLUMN yy SETTINGS mutation_sync = 2` + /// So after parsing keyword `SETTINGS`, we check if it's followed by an `(` then it's the column + /// settings, otherwise it's the query settings and we need to move `pos` back to origin position. ParserToken parser_opening_bracket(TokenType::OpeningRoundBracket); - if (parser_opening_bracket.check(pos, expected)) + if (parser_opening_bracket.ignore(pos, expected)) { if (!settings_parser.parse(pos, settings, expected)) return false; @@ -340,8 +347,8 @@ bool IParserColumnDeclaration::parseImpl(Pos & pos, ASTPtr & node, E if (!parser_closing_bracket.ignore(pos, expected)) return false; } - /// This could be settings in alter query - /// E.g: ALTER TABLE alter_enum_array MODIFY COLUMN x String SETTINGS mutations_sync=2; + else + pos = old_pos; } node = column_declaration; diff --git a/tests/queries/0_stateless/02870_per_column_settings.sql b/tests/queries/0_stateless/02870_per_column_settings.sql index bd115885330..9f48c666ff9 100644 --- a/tests/queries/0_stateless/02870_per_column_settings.sql +++ b/tests/queries/0_stateless/02870_per_column_settings.sql @@ -68,11 +68,3 @@ ORDER BY id SETTINGS min_bytes_for_wide_part = 1; -- {serverError UNKNOWN_SETTING} SELECT '--- '; - --- Column-level settings are only supported for MergeTree* tables -CREATE TABLE tab -( - id UInt64 CODEC(ZSTD), - long_string String CODEC(ZSTD) SETTINGS (min_compress_block_size = 81920, max_compress_block_size = 163840), -) -ENGINE = TinyLog; -- {serverError ILLEGAL_COLUMN} From 72466557a8c85adf0d07318233d8adb8f183e7b8 Mon Sep 17 00:00:00 2001 From: Duc Canh Le Date: Tue, 23 Jan 2024 01:27:39 +0000 Subject: [PATCH 12/12] update test Signed-off-by: Duc Canh Le --- .../0_stateless/02870_per_column_settings.reference | 1 - tests/queries/0_stateless/02870_per_column_settings.sql | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/queries/0_stateless/02870_per_column_settings.reference b/tests/queries/0_stateless/02870_per_column_settings.reference index a57407e4f0e..144c8c5ee2e 100644 --- a/tests/queries/0_stateless/02870_per_column_settings.reference +++ b/tests/queries/0_stateless/02870_per_column_settings.reference @@ -16,4 +16,3 @@ CREATE TABLE default.tab\n(\n `id` UInt64,\n `long_string` String SETTINGS (8,8) 8 (9,9) 9 --- ---- diff --git a/tests/queries/0_stateless/02870_per_column_settings.sql b/tests/queries/0_stateless/02870_per_column_settings.sql index 9f48c666ff9..345cf5cc744 100644 --- a/tests/queries/0_stateless/02870_per_column_settings.sql +++ b/tests/queries/0_stateless/02870_per_column_settings.sql @@ -1,5 +1,6 @@ --- Tags: no-random-merge-tree-settings - +-- Tags: no-random-merge-tree-settings, no-replicated-database +-- Tag no-replicated-database: Old syntax is not allowed +-- The test use replicated table to test serialize and deserialize column with settings declaration on zookeeper -- Tests column-level settings for MergeTree* tables DROP TABLE IF EXISTS tab; @@ -66,5 +67,3 @@ CREATE TABLE tab ENGINE = MergeTree ORDER BY id SETTINGS min_bytes_for_wide_part = 1; -- {serverError UNKNOWN_SETTING} - -SELECT '--- ';