From 58d579e7e2ee4a3861fb21da91e65b609f6900fd Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 24 Jul 2019 21:00:09 +0300 Subject: [PATCH 001/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Formats/FormatFactory.cpp | 70 +++++++++---------- dbms/src/Formats/FormatFactory.h | 18 +++-- dbms/src/Processors/Formats/IOutputFormat.h | 11 +++ dbms/src/Processors/Formats/IRowInputFormat.h | 5 ++ .../Formats/InputStreamFromInputFormat.h | 58 +++++++++++++++ .../Formats/OutputStreamToOutputFormat.cpp | 34 +++++++++ .../Formats/OutputStreamToOutputFormat.h | 38 ++++++++++ 7 files changed, 192 insertions(+), 42 deletions(-) create mode 100644 dbms/src/Processors/Formats/InputStreamFromInputFormat.h create mode 100644 dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp create mode 100644 dbms/src/Processors/Formats/OutputStreamToOutputFormat.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 4fae140abee..5f1e2f25605 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include namespace DB @@ -18,14 +20,14 @@ namespace ErrorCodes extern const int FORMAT_IS_NOT_SUITABLE_FOR_OUTPUT; } - -const FormatFactory::Creators & FormatFactory::getCreators(const String & name) const -{ - auto it = dict.find(name); - if (dict.end() != it) - return it->second; - throw Exception("Unknown format " + name, ErrorCodes::UNKNOWN_FORMAT); -} +// +//const FormatFactory::Creators & FormatFactory::getCreators(const String & name) const +//{ +// auto it = dict.find(name); +// if (dict.end() != it) +// return it->second; +// throw Exception("Unknown format " + name, ErrorCodes::UNKNOWN_FORMAT); +//} const FormatFactory::ProcessorCreators & FormatFactory::getProcessorCreators(const String & name) const { @@ -81,36 +83,30 @@ BlockInputStreamPtr FormatFactory::getInput( UInt64 rows_portion_size, ReadCallback callback) const { - const auto & input_getter = getCreators(name).first; - if (!input_getter) - throw Exception("Format " + name + " is not suitable for input", ErrorCodes::FORMAT_IS_NOT_SUITABLE_FOR_INPUT); - - const Settings & settings = context.getSettingsRef(); - FormatSettings format_settings = getInputFormatSetting(settings); - - return input_getter( - buf, sample, context, max_block_size, rows_portion_size, callback ? callback : ReadCallback(), format_settings); + auto format = getInputFormat(name, buf, sample, context, max_block_size, rows_portion_size, std::move(callback)); + return std::make_shared(std::move(format)); } BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const { - const auto & output_getter = getCreators(name).second; - if (!output_getter) - throw Exception("Format " + name + " is not suitable for output", ErrorCodes::FORMAT_IS_NOT_SUITABLE_FOR_OUTPUT); - - const Settings & settings = context.getSettingsRef(); - FormatSettings format_settings = getOutputFormatSetting(settings); + auto format = getOutputFormat(name, buf, sample, context); /** Materialization is needed, because formats can use the functions `IDataType`, * which only work with full columns. */ - return std::make_shared( - output_getter(buf, sample, context, format_settings), sample); + return std::make_shared(std::make_shared(format)); } -InputFormatPtr FormatFactory::getInputFormat(const String & name, ReadBuffer & buf, const Block & sample, const Context & context, UInt64 max_block_size) const +InputFormatPtr FormatFactory::getInputFormat( + const String & name, + ReadBuffer & buf, + const Block & sample, + const Context & context, + UInt64 max_block_size, + UInt64 rows_portion_size, + ReadCallback callback) const { const auto & input_getter = getProcessorCreators(name).first; if (!input_getter) @@ -123,6 +119,8 @@ InputFormatPtr FormatFactory::getInputFormat(const String & name, ReadBuffer & b params.max_block_size = max_block_size; params.allow_errors_num = format_settings.input_allow_errors_num; params.allow_errors_ratio = format_settings.input_allow_errors_ratio; + params.rows_portion_size = rows_portion_size; + params.callback = std::move(callback); return input_getter(buf, sample, context, params, format_settings); } @@ -144,20 +142,20 @@ OutputFormatPtr FormatFactory::getOutputFormat(const String & name, WriteBuffer } -void FormatFactory::registerInputFormat(const String & name, InputCreator input_creator) +void FormatFactory::registerInputFormat(const String & /*name*/, InputCreator /*input_creator*/) { - auto & target = dict[name].first; - if (target) - throw Exception("FormatFactory: Input format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); - target = std::move(input_creator); +// auto & target = dict[name].first; +// if (target) +// throw Exception("FormatFactory: Input format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); +// target = std::move(input_creator); } -void FormatFactory::registerOutputFormat(const String & name, OutputCreator output_creator) +void FormatFactory::registerOutputFormat(const String & /*name*/, OutputCreator /*output_creator*/) { - auto & target = dict[name].second; - if (target) - throw Exception("FormatFactory: Output format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); - target = std::move(output_creator); +// auto & target = dict[name].second; +// if (target) +// throw Exception("FormatFactory: Output format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); +// target = std::move(output_creator); } void FormatFactory::registerInputFormatProcessor(const String & name, InputProcessorCreator input_creator) diff --git a/dbms/src/Formats/FormatFactory.h b/dbms/src/Formats/FormatFactory.h index 5cc1fcecb93..23fd71aa9ad 100644 --- a/dbms/src/Formats/FormatFactory.h +++ b/dbms/src/Formats/FormatFactory.h @@ -89,8 +89,14 @@ public: BlockOutputStreamPtr getOutput(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const; - InputFormatPtr getInputFormat(const String & name, ReadBuffer & buf, - const Block & sample, const Context & context, UInt64 max_block_size) const; + InputFormatPtr getInputFormat( + const String & name, + ReadBuffer & buf, + const Block & sample, + const Context & context, + UInt64 max_block_size, + UInt64 rows_portion_size = 0, + ReadCallback callback = {}) const; OutputFormatPtr getOutputFormat(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const; @@ -102,19 +108,19 @@ public: void registerInputFormatProcessor(const String & name, InputProcessorCreator input_creator); void registerOutputFormatProcessor(const String & name, OutputProcessorCreator output_creator); - const FormatsDictionary & getAllFormats() const + const FormatProcessorsDictionary & getAllFormats() const { - return dict; + return processors_dict; } private: - FormatsDictionary dict; + /// FormatsDictionary dict; FormatProcessorsDictionary processors_dict; FormatFactory(); friend class ext::singleton; - const Creators & getCreators(const String & name) const; + //const Creators & getCreators(const String & name) const; const ProcessorCreators & getProcessorCreators(const String & name) const; }; diff --git a/dbms/src/Processors/Formats/IOutputFormat.h b/dbms/src/Processors/Formats/IOutputFormat.h index 280f64593b7..55555717070 100644 --- a/dbms/src/Processors/Formats/IOutputFormat.h +++ b/dbms/src/Processors/Formats/IOutputFormat.h @@ -58,6 +58,17 @@ public: virtual std::string getContentType() const { return "text/plain; charset=UTF-8"; } InputPort & getPort(PortKind kind) { return *std::next(inputs.begin(), kind); } + +public: + /// Compatible to IBlockOutputStream interface + + void write(const Block & block) { consume(Chunk(block.getColumns(), block.rows())); } + + void writePrefix() {} + void writeSuffix() { finalize(); } + + void setTotals(const Block & totals) { consume(Chunk(totals.getColumns(), totals.rows())); } + void setExtremes(const Block & extremes) { consume(Chunk(extremes.getColumns(), extremes.rows())); } }; } diff --git a/dbms/src/Processors/Formats/IRowInputFormat.h b/dbms/src/Processors/Formats/IRowInputFormat.h index 9d0ee7cb0c9..b574af8c39a 100644 --- a/dbms/src/Processors/Formats/IRowInputFormat.h +++ b/dbms/src/Processors/Formats/IRowInputFormat.h @@ -23,6 +23,11 @@ struct RowInputFormatParams UInt64 allow_errors_num; Float64 allow_errors_ratio; + + UInt64 rows_portion_size; + + using ReadCallback = std::function; + ReadCallback callback; }; ///Row oriented input format: reads data row by row. diff --git a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h new file mode 100644 index 00000000000..445f45068d4 --- /dev/null +++ b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include + +namespace DB +{ + +class IInputFormat; +using InputFormatPtr = std::shared_ptr; + +class InputStreamFromInputFormat : public IBlockInputStream +{ +public: + explicit InputStreamFromInputFormat(InputFormatPtr input_format_) + : input_format(std::move(input_format_)) + , port(input_format->getPort().getHeader()) + { + connect(input_format->getPort(), port); + } + + String getName() const override { return input_format->getName(); } + Block getHeader() const override { return input_format->getPort().getHeader(); } + +protected: + + Block readImpl() override + { + while (true) + { + auto status = input_format->prepare(); + + switch (status) + { + case IProcessor::Status::Ready: + input_format->work(); + break; + + case IProcessor::Status::Finished: + return {}; + + case IProcessor::Status::PortFull: + return input_format->getPort().getHeader().cloneWithColumns(port.pull().detachColumns()); + + case IProcessor::Status::NeedData: + case IProcessor::Status::Async: + case IProcessor::Status::Wait: + case IProcessor::Status::ExpandPipeline: + throw Exception("Source processor returned status " + IProcessor::statusToName(status), ErrorCodes::LOGICAL_ERROR); + } + } + } + +private: + InputFormatPtr input_format; + InputPort port; +}; + +} diff --git a/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp new file mode 100644 index 00000000000..153972fc65d --- /dev/null +++ b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp @@ -0,0 +1,34 @@ +#include +#include + +namespace DB +{ + +Block OutputStreamToOutputFormat::getHeader() const +{ + return output_format->getPort(IOutputFormat::PortKind::Main).getHeader(); +} + +void OutputStreamToOutputFormat::write(const Block & block) +{ + output_format->write(block); +} + +void OutputStreamToOutputFormat::writePrefix() { output_format->writePrefix(); } +void OutputStreamToOutputFormat::writeSuffix() { output_format->writeSuffix(); } + +void OutputStreamToOutputFormat::flush() { output_format->flush(); } + +void OutputStreamToOutputFormat::setRowsBeforeLimit(size_t rows_before_limit) +{ + output_format->setRowsBeforeLimit(rows_before_limit); +} + +void OutputStreamToOutputFormat::setTotals(const Block & totals) { output_format->setTotals(totals); } +void OutputStreamToOutputFormat::setExtremes(const Block & extremes) { output_format->setExtremes(extremes); } + +void OutputStreamToOutputFormat::onProgress(const Progress & progress) { output_format->onProgress(progress); } + +std::string OutputStreamToOutputFormat::getContentType() const { return output_format->getContentType(); } + +} diff --git a/dbms/src/Processors/Formats/OutputStreamToOutputFormat.h b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.h new file mode 100644 index 00000000000..350486f9b41 --- /dev/null +++ b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.h @@ -0,0 +1,38 @@ +#pragma once +#include + +namespace DB +{ + + +class IOutputFormat; + +using OutputFormatPtr = std::shared_ptr; + +class OutputStreamToOutputFormat : public IBlockOutputStream +{ +public: + explicit OutputStreamToOutputFormat(OutputFormatPtr output_format_) : output_format(std::move(output_format_)) {} + + Block getHeader() const override; + + void write(const Block & block) override; + + void writePrefix() override; + void writeSuffix() override; + + void flush() override; + + void setRowsBeforeLimit(size_t rows_before_limit) override; + void setTotals(const Block & totals) override; + void setExtremes(const Block & extremes) override; + + void onProgress(const Progress & progress) override; + + std::string getContentType() const override; + +private: + OutputFormatPtr output_format; +}; + +} From 7f1fd1a918228376afa31874083a5de9067b58b0 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 11:37:21 +0300 Subject: [PATCH 002/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Formats/FormatFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 5f1e2f25605..9e5645492a8 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -95,7 +95,7 @@ BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & /** Materialization is needed, because formats can use the functions `IDataType`, * which only work with full columns. */ - return std::make_shared(std::make_shared(format)); + return std::make_shared(std::make_shared(format), sample); } From 4cc3bf77241320f5fca973fdbe7f3f7a0e0f9c44 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 12:15:33 +0300 Subject: [PATCH 003/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Processors/Formats/InputStreamFromInputFormat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h index 445f45068d4..4d690239adf 100644 --- a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h +++ b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h @@ -13,7 +13,7 @@ class InputStreamFromInputFormat : public IBlockInputStream public: explicit InputStreamFromInputFormat(InputFormatPtr input_format_) : input_format(std::move(input_format_)) - , port(input_format->getPort().getHeader()) + , port(input_format->getPort().getHeader(), input_format.get()) { connect(input_format->getPort(), port); } From a22540d010557479a13d106d403c31162e024112 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 12:20:00 +0300 Subject: [PATCH 004/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Processors/Formats/InputStreamFromInputFormat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h index 4d690239adf..266473f95de 100644 --- a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h +++ b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h @@ -16,6 +16,7 @@ public: , port(input_format->getPort().getHeader(), input_format.get()) { connect(input_format->getPort(), port); + port.setNeeded(); } String getName() const override { return input_format->getName(); } From 69f860a5efe93b190a5e7e2b142371df26ce3bfd Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 12:28:33 +0300 Subject: [PATCH 005/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Processors/Formats/IOutputFormat.h | 4 ++-- dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/src/Processors/Formats/IOutputFormat.h b/dbms/src/Processors/Formats/IOutputFormat.h index 55555717070..63561749a7c 100644 --- a/dbms/src/Processors/Formats/IOutputFormat.h +++ b/dbms/src/Processors/Formats/IOutputFormat.h @@ -64,8 +64,8 @@ public: void write(const Block & block) { consume(Chunk(block.getColumns(), block.rows())); } - void writePrefix() {} - void writeSuffix() { finalize(); } + void doWritePrefix() {} + void doWriteSuffix() { finalize(); } void setTotals(const Block & totals) { consume(Chunk(totals.getColumns(), totals.rows())); } void setExtremes(const Block & extremes) { consume(Chunk(extremes.getColumns(), extremes.rows())); } diff --git a/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp index 153972fc65d..7acf41f6cf7 100644 --- a/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp +++ b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp @@ -14,8 +14,8 @@ void OutputStreamToOutputFormat::write(const Block & block) output_format->write(block); } -void OutputStreamToOutputFormat::writePrefix() { output_format->writePrefix(); } -void OutputStreamToOutputFormat::writeSuffix() { output_format->writeSuffix(); } +void OutputStreamToOutputFormat::writePrefix() { output_format->doWritePrefix(); } +void OutputStreamToOutputFormat::writeSuffix() { output_format->doWriteSuffix(); } void OutputStreamToOutputFormat::flush() { output_format->flush(); } From 36a0275ff17a907bd2137d3474809c6fe579b72e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 12:31:38 +0300 Subject: [PATCH 006/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Processors/Formats/IOutputFormat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Processors/Formats/IOutputFormat.h b/dbms/src/Processors/Formats/IOutputFormat.h index 63561749a7c..3242ab9da9a 100644 --- a/dbms/src/Processors/Formats/IOutputFormat.h +++ b/dbms/src/Processors/Formats/IOutputFormat.h @@ -67,8 +67,8 @@ public: void doWritePrefix() {} void doWriteSuffix() { finalize(); } - void setTotals(const Block & totals) { consume(Chunk(totals.getColumns(), totals.rows())); } - void setExtremes(const Block & extremes) { consume(Chunk(extremes.getColumns(), extremes.rows())); } + void setTotals(const Block & totals) { consumeTotals(Chunk(totals.getColumns(), totals.rows())); } + void setExtremes(const Block & extremes) { consumeExtremes(Chunk(extremes.getColumns(), extremes.rows())); } }; } From 78f056d83fba0693de4bbe319d6264967d0913d5 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 12:35:16 +0300 Subject: [PATCH 007/105] Use IInputFormat and IOutputFormat by default. --- .../Formats/OutputStreamToOutputFormat.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp index 7acf41f6cf7..5d4e7832327 100644 --- a/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp +++ b/dbms/src/Processors/Formats/OutputStreamToOutputFormat.cpp @@ -24,8 +24,17 @@ void OutputStreamToOutputFormat::setRowsBeforeLimit(size_t rows_before_limit) output_format->setRowsBeforeLimit(rows_before_limit); } -void OutputStreamToOutputFormat::setTotals(const Block & totals) { output_format->setTotals(totals); } -void OutputStreamToOutputFormat::setExtremes(const Block & extremes) { output_format->setExtremes(extremes); } +void OutputStreamToOutputFormat::setTotals(const Block & totals) +{ + if (totals) + output_format->setTotals(totals); +} + +void OutputStreamToOutputFormat::setExtremes(const Block & extremes) +{ + if (extremes) + output_format->setExtremes(extremes); +} void OutputStreamToOutputFormat::onProgress(const Progress & progress) { output_format->onProgress(progress); } From 079e41ac26d6f20f65f1352dec73ed8af35026aa Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 13:51:32 +0300 Subject: [PATCH 008/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h b/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h index 296f198b01a..961f2b77bca 100644 --- a/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h +++ b/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h @@ -32,7 +32,7 @@ public: String getName() const override { return "NullAndDoCopy"; } - Block getHeader() const override { return {}; } + Block getHeader() const override { return input->getHeader(); } protected: Block readImpl() override From 95dd6222fe8f112561e56ed1408b9b7c6b4c134b Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 25 Jul 2019 15:17:57 +0300 Subject: [PATCH 009/105] Use IInputFormat and IOutputFormat by default. --- dbms/src/Processors/Formats/Impl/JSONCompactRowOutputFormat.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/JSONCompactRowOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/JSONCompactRowOutputFormat.cpp index 0f63a4cf72d..72292cc0a26 100644 --- a/dbms/src/Processors/Formats/Impl/JSONCompactRowOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/JSONCompactRowOutputFormat.cpp @@ -34,8 +34,6 @@ void JSONCompactRowOutputFormat::writeTotalsFieldDelimiter() void JSONCompactRowOutputFormat::writeRowStartDelimiter() { - if (row_count > 0) - writeCString(",\n", *ostr); writeCString("\t\t[", *ostr); } From 5aa968c2217ea7cd9451bf402f20d3b285a50858 Mon Sep 17 00:00:00 2001 From: Big Elephant Date: Fri, 26 Jul 2019 09:36:11 +0800 Subject: [PATCH 010/105] Update ipv4.md --- docs/zh/data_types/domains/ipv4.md | 80 +++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/docs/zh/data_types/domains/ipv4.md b/docs/zh/data_types/domains/ipv4.md index eb4cc7d57b5..baecb7d86b1 120000 --- a/docs/zh/data_types/domains/ipv4.md +++ b/docs/zh/data_types/domains/ipv4.md @@ -1 +1,79 @@ -../../../en/data_types/domains/ipv4.md \ No newline at end of file +## IPv4 + +`IPv4` 是基于 `UInt32` 的domain类型,用来存储IPv4地址。它使用紧凑的存储方式,提供用户友好的输入输出格式, +自动检查列类型。 + +### Basic Usage + +``` sql +CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY url; + +DESCRIBE TABLE hits; +``` + +``` +┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┐ +│ url │ String │ │ │ │ │ +│ from │ IPv4 │ │ │ │ │ +└──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ +``` + +或者你可以使用IPv4 domain作主键: + +``` sql +CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY from; +``` + +`IPv4` domain支持定制化的IPv4地址字符串格式: + +``` sql +INSERT INTO hits (url, from) VALUES ('https://wikipedia.org', '116.253.40.133')('https://clickhouse.yandex', '183.247.232.58')('https://clickhouse.yandex/docs/en/', '116.106.34.242'); + +SELECT * FROM hits; +``` + +``` +┌─url────────────────────────────────┬───────────from─┐ +│ https://clickhouse.yandex/docs/en/ │ 116.106.34.242 │ +│ https://wikipedia.org │ 116.253.40.133 │ +│ https://clickhouse.yandex │ 183.247.232.58 │ +└────────────────────────────────────┴────────────────┘ +``` + +数据值以紧凑的二进制格式存储: + +``` sql +SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; +``` + +``` +┌─toTypeName(from)─┬─hex(from)─┐ +│ IPv4 │ B7F7E83A │ +└──────────────────┴───────────┘ +``` + +Domain不可隐式转换为除`UInt32`以外的类型。如果要将IPv4值转换为字符串,则必须使用`IPv4NumToString()`函数显示的进行此操作。 + +``` sql +SELECT toTypeName(s), IPv4NumToString(from) as s FROM hits LIMIT 1; +``` + +``` +┌─toTypeName(IPv4NumToString(from))─┬─s──────────────┐ +│ String │ 183.247.232.58 │ +└───────────────────────────────────┴────────────────┘ +``` + +或转换为 `UInt32` 类型: + +``` sql +SELECT toTypeName(i), CAST(from as UInt32) as i FROM hits LIMIT 1; +``` + +``` +┌─toTypeName(CAST(from, 'UInt32'))─┬──────────i─┐ +│ UInt32 │ 3086477370 │ +└──────────────────────────────────┴────────────┘ +``` + +[Original article](https://clickhouse.yandex/docs/en/data_types/domains/ipv4) From 24498668a05c421ea563101608834692c23509b6 Mon Sep 17 00:00:00 2001 From: Big Elephant Date: Mon, 29 Jul 2019 14:24:11 +0800 Subject: [PATCH 011/105] Update overview.md --- docs/zh/data_types/domains/overview.md | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/zh/data_types/domains/overview.md b/docs/zh/data_types/domains/overview.md index 13465d655ee..25fc5d3850a 120000 --- a/docs/zh/data_types/domains/overview.md +++ b/docs/zh/data_types/domains/overview.md @@ -1 +1,26 @@ -../../../en/data_types/domains/overview.md \ No newline at end of file +# Domains + +Domains是特殊用途的类型,它在现有的基础类型之上添加了一些额外的特性,能够让线上和磁盘上的表格式保持不变。目前,ClickHouse暂不支持自定义的domains. + +您可以在任何地方使用domains,相应的基础类型的使用方式如下: + +* 构建一列domain类型的数据 +* 从/向domain列读/写数据 +* 作为索引,如果基础类型能够被作为索引的话 +* 以domain列的值作为参数调用函数 +* 等等. + +### Domains的额外特性 + +* 在使用`SHOW CREATE TABLE` 或 `DESCRIBE TABLE`时,明确地显示列类型名称 +* 使用 `INSERT INTO domain_table(domain_column) VALUES(...)`实现人性化格式输入 +* 使用`SELECT domain_column FROM domain_table`实现人性化格式输出 +* 使用 `INSERT INTO domain_table FORMAT CSV ...`实现外部源数据的人性化格式载入 + +### 缺陷 + +* 无法通过 `ALTER TABLE`将基础类型的索引转换为domain类型的索引. +* 当从其他列或表插入数据时,无法将string类型的值隐式地转换为domain类型的值. +* 无法对存储为domain类型的值添加约束. + +[Original article](https://clickhouse.yandex/docs/en/data_types/domains/overview) From 98b5c741315c96f9dee2f5b63d8473c7b0a959f3 Mon Sep 17 00:00:00 2001 From: Big Elephant Date: Mon, 29 Jul 2019 14:33:46 +0800 Subject: [PATCH 012/105] Update ipv6.md --- docs/zh/data_types/domains/ipv6.md | 78 +++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/docs/zh/data_types/domains/ipv6.md b/docs/zh/data_types/domains/ipv6.md index cca37a22458..13c6809e4a9 120000 --- a/docs/zh/data_types/domains/ipv6.md +++ b/docs/zh/data_types/domains/ipv6.md @@ -1 +1,77 @@ -../../../en/data_types/domains/ipv6.md \ No newline at end of file +## IPv6 + +`IPv6` 是基于`FixedString(16)` 类型的domain类型,用来存储IPv6地址值。它使用紧凑的存储方式,提供用户友好的输入输出格式, 自动检查列类型。 + +### 基本用法 + +``` sql +CREATE TABLE hits (url String, from IPv6) ENGINE = MergeTree() ORDER BY url; + +DESCRIBE TABLE hits; +``` + +``` +┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┐ +│ url │ String │ │ │ │ │ +│ from │ IPv6 │ │ │ │ │ +└──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ +``` + +您也可以使用 `IPv6`domain做主键: + +``` sql +CREATE TABLE hits (url String, from IPv6) ENGINE = MergeTree() ORDER BY from; +``` + +`IPv6` domain支持定制化的IPv6地址字符串格式: + +``` sql +INSERT INTO hits (url, from) VALUES ('https://wikipedia.org', '2a02:aa08:e000:3100::2')('https://clickhouse.yandex', '2001:44c8:129:2632:33:0:252:2')('https://clickhouse.yandex/docs/en/', '2a02:e980:1e::1'); + +SELECT * FROM hits; +``` + +``` +┌─url────────────────────────────────┬─from──────────────────────────┐ +│ https://clickhouse.yandex │ 2001:44c8:129:2632:33:0:252:2 │ +│ https://clickhouse.yandex/docs/en/ │ 2a02:e980:1e::1 │ +│ https://wikipedia.org │ 2a02:aa08:e000:3100::2 │ +└────────────────────────────────────┴───────────────────────────────┘ +``` + +它以紧凑的二进制格式存储数值: + +``` sql +SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; +``` + +``` +┌─toTypeName(from)─┬─hex(from)────────────────────────┐ +│ IPv6 │ 200144C8012926320033000002520002 │ +└──────────────────┴──────────────────────────────────┘ +``` +Domain不可隐式转换为除`FixedString(16)`以外的类型。如果要将`IPv6`值转换为字符串,则必须使用`IPv6NumToString()`函数显示地进行此操作: + +``` sql +SELECT toTypeName(s), IPv6NumToString(from) as s FROM hits LIMIT 1; +``` + +``` +┌─toTypeName(IPv6NumToString(from))─┬─s─────────────────────────────┐ +│ String │ 2001:44c8:129:2632:33:0:252:2 │ +└───────────────────────────────────┴───────────────────────────────┘ +``` + +或转换为 `FixedString(16)`类型: + +``` sql +SELECT toTypeName(i), CAST(from as FixedString(16)) as i FROM hits LIMIT 1; +``` + +``` +┌─toTypeName(CAST(from, 'FixedString(16)'))─┬─i───────┐ +│ FixedString(16) │ ��� │ +└───────────────────────────────────────────┴─────────┘ +``` + +[Original article](https://clickhouse.yandex/docs/en/data_types/domains/ipv6) From bb16ffaadc6e4ed7778c2cef3272370d5a1e0d73 Mon Sep 17 00:00:00 2001 From: Big Elephant Date: Mon, 29 Jul 2019 14:35:08 +0800 Subject: [PATCH 013/105] Update ipv4.md --- docs/zh/data_types/domains/ipv4.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/zh/data_types/domains/ipv4.md b/docs/zh/data_types/domains/ipv4.md index baecb7d86b1..1dd2cb03794 120000 --- a/docs/zh/data_types/domains/ipv4.md +++ b/docs/zh/data_types/domains/ipv4.md @@ -3,7 +3,7 @@ `IPv4` 是基于 `UInt32` 的domain类型,用来存储IPv4地址。它使用紧凑的存储方式,提供用户友好的输入输出格式, 自动检查列类型。 -### Basic Usage +### 基本使用 ``` sql CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY url; @@ -18,7 +18,7 @@ DESCRIBE TABLE hits; └──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ ``` -或者你可以使用IPv4 domain作主键: +您也可以使用IPv4 domain作主键: ``` sql CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY from; From d4da486b51f5e4a672fd8d01fd55d927643285bf Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 30 Jul 2019 17:55:59 +0300 Subject: [PATCH 014/105] Update CSVRowInputFormat. --- .../Formats/Impl/CSVRowInputFormat.cpp | 321 +++++++++++++----- .../Formats/Impl/CSVRowInputFormat.h | 20 +- 2 files changed, 262 insertions(+), 79 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp index 3038c9e02f6..6dc7493187b 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp @@ -18,16 +18,55 @@ namespace ErrorCodes CSVRowInputFormat::CSVRowInputFormat( ReadBuffer & in_, Block header, Params params, bool with_names_, const FormatSettings & format_settings) - : IRowInputFormat(std::move(header), in_, params), with_names(with_names_), format_settings(format_settings) + : IRowInputFormat(std::move(header), in_, std::move(params)) + , with_names(with_names_) + , format_settings(format_settings) { auto & sample = getPort().getHeader(); size_t num_columns = sample.columns(); + data_types.resize(num_columns); + column_indexes_by_names.reserve(num_columns); + for (size_t i = 0; i < num_columns; ++i) - data_types[i] = sample.safeGetByPosition(i).type; + { + const auto & column_info = sample.getByPosition(i); + + data_types[i] = column_info.type; + column_indexes_by_names.emplace(column_info.name, i); + } } +/// Map an input file column to a table column, based on its name. +void CSVRowInputFormat::addInputColumn(const String & column_name) +{ + const auto column_it = column_indexes_by_names.find(column_name); + if (column_it == column_indexes_by_names.end()) + { + if (format_settings.skip_unknown_fields) + { + column_indexes_for_input_fields.push_back(std::nullopt); + return; + } + + throw Exception( + "Unknown field found in CSV header: '" + column_name + "' " + + "at position " + std::to_string(column_indexes_for_input_fields.size()) + + "\nSet the 'input_format_skip_unknown_fields' parameter explicitly to ignore and proceed", + ErrorCodes::INCORRECT_DATA + ); + } + + const auto column_index = column_it->second; + + if (read_columns[column_index]) + throw Exception("Duplicate field found while parsing CSV header: " + column_name, ErrorCodes::INCORRECT_DATA); + + read_columns[column_index] = true; + column_indexes_for_input_fields.emplace_back(column_index); +} + static void skipEndOfLine(ReadBuffer & istr) { /// \n (Unix) or \r\n (DOS/Windows) or \n\r (Mac OS Classic) @@ -108,26 +147,119 @@ void CSVRowInputFormat::readPrefix() String tmp; if (with_names) - skipRow(in, format_settings.csv, num_columns); + { + /// This CSV file has a header row with column names. Depending on the + /// settings, use it or skip it. + if (format_settings.with_names_use_header) + { + /// Look at the file header to see which columns we have there. + /// The missing columns are filled with defaults. + read_columns.assign(getPort().getHeader().columns(), false); + do + { + String column_name; + skipWhitespacesAndTabs(in); + readCSVString(column_name, in, format_settings.csv); + skipWhitespacesAndTabs(in); + + addInputColumn(column_name); + } + while (checkChar(format_settings.csv.delimiter, in)); + + skipDelimiter(in, format_settings.csv.delimiter, true); + + for (auto read_column : read_columns) + { + if (read_column) + { + have_always_default_columns = true; + break; + } + } + + return; + } + else + skipRow(in, format_settings.csv, num_columns); + } } -bool CSVRowInputFormat::readRow(MutableColumns & columns, RowReadExtension &) +bool CSVRowInputFormat::readRow(MutableColumns & columns, RowReadExtension & ext) { if (in.eof()) return false; updateDiagnosticInfo(); - size_t size = data_types.size(); + /// Track whether we have to fill any columns in this row with default + /// values. If not, we return an empty column mask to the caller, so that + /// it doesn't have to check it. + bool have_default_columns = have_always_default_columns; - for (size_t i = 0; i < size; ++i) + const auto delimiter = format_settings.csv.delimiter; + for (size_t file_column = 0; file_column < column_indexes_for_input_fields.size(); ++file_column) { - skipWhitespacesAndTabs(in); - data_types[i]->deserializeAsTextCSV(*columns[i], in, format_settings); - skipWhitespacesAndTabs(in); + const auto & table_column = column_indexes_for_input_fields[file_column]; + const bool is_last_file_column = + file_column + 1 == column_indexes_for_input_fields.size(); - skipDelimiter(in, format_settings.csv.delimiter, i + 1 == size); + if (table_column) + { + const auto & type = data_types[*table_column]; + const bool at_delimiter = *in.position() == delimiter; + const bool at_last_column_line_end = is_last_file_column + && (*in.position() == '\n' || *in.position() == '\r' + || in.eof()); + + if (format_settings.csv.empty_as_default + && (at_delimiter || at_last_column_line_end)) + { + /// Treat empty unquoted column value as default value, if + /// specified in the settings. Tuple columns might seem + /// problematic, because they are never quoted but still contain + /// commas, which might be also used as delimiters. However, + /// they do not contain empty unquoted fields, so this check + /// works for tuples as well. + read_columns[*table_column] = false; + have_default_columns = true; + } + else + { + /// Read the column normally. + read_columns[*table_column] = true; + skipWhitespacesAndTabs(in); + type->deserializeAsTextCSV(*columns[*table_column], in, + format_settings); + skipWhitespacesAndTabs(in); + } + } + else + { + /// We never read this column from the file, just skip it. + String tmp; + readCSVString(tmp, in, format_settings.csv); + } + + skipDelimiter(in, delimiter, is_last_file_column); + } + + if (have_default_columns) + { + for (size_t i = 0; i < read_columns.size(); i++) + { + if (!read_columns[i]) + { + /// The column value for this row is going to be overwritten + /// with default by the caller, but the general assumption is + /// that the column size increases for each row, so we have + /// to insert something. Since we do not care about the exact + /// value, we do not have to use the default value specified by + /// the data type, and can just use IColumn::insertDefault(). + columns[i]->insertDefault(); + } + } + ext.read_columns = read_columns; } return true; @@ -190,93 +322,126 @@ String CSVRowInputFormat::getDiagnosticInfo() return out.str(); } - -bool CSVRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & columns, +/** gcc-7 generates wrong code with optimization level greater than 1. + * See tests: dbms/src/IO/tests/write_int.cpp + * and dbms/tests/queries/0_stateless/00898_parsing_bad_diagnostic_message.sh + * This is compiler bug. The bug does not present in gcc-8 and clang-8. + * Nevertheless, we don't need high optimization of this function. + */ +bool OPTIMIZE(1) CSVRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & columns, WriteBuffer & out, size_t max_length_of_column_name, size_t max_length_of_data_type_name) { const char delimiter = format_settings.csv.delimiter; - auto & header = getPort().getHeader(); - size_t size = data_types.size(); - for (size_t i = 0; i < size; ++i) + for (size_t file_column = 0; file_column < column_indexes_for_input_fields.size(); ++file_column) { - if (i == 0 && in.eof()) + if (file_column == 0 && in.eof()) { out << "\n"; return false; } - out << "Column " << i << ", " << std::string((i < 10 ? 2 : i < 100 ? 1 : 0), ' ') - << "name: " << header.safeGetByPosition(i).name << ", " << std::string(max_length_of_column_name - header.safeGetByPosition(i).name.size(), ' ') - << "type: " << data_types[i]->getName() << ", " << std::string(max_length_of_data_type_name - data_types[i]->getName().size(), ' '); - - BufferBase::Position prev_position = in.position(); - BufferBase::Position curr_position = in.position(); - std::exception_ptr exception; - - try + if (column_indexes_for_input_fields[file_column].has_value()) { - skipWhitespacesAndTabs(in); - prev_position = in.position(); - data_types[i]->deserializeAsTextCSV(*columns[i], in, format_settings); - curr_position = in.position(); - skipWhitespacesAndTabs(in); - } - catch (...) - { - exception = std::current_exception(); - } + const auto & table_column = *column_indexes_for_input_fields[file_column]; + const auto & current_column_type = data_types[table_column]; + const bool is_last_file_column = + file_column + 1 == column_indexes_for_input_fields.size(); + const bool at_delimiter = *in.position() == delimiter; + const bool at_last_column_line_end = is_last_file_column + && (*in.position() == '\n' || *in.position() == '\r' + || in.eof()); - if (curr_position < prev_position) - throw Exception("Logical error: parsing is non-deterministic.", ErrorCodes::LOGICAL_ERROR); + auto & header = getPort().getHeader(); + out << "Column " << file_column << ", " << std::string((file_column < 10 ? 2 : file_column < 100 ? 1 : 0), ' ') + << "name: " << header.safeGetByPosition(table_column).name << ", " << std::string(max_length_of_column_name - header.safeGetByPosition(table_column).name.size(), ' ') + << "type: " << current_column_type->getName() << ", " << std::string(max_length_of_data_type_name - current_column_type->getName().size(), ' '); - if (isNumber(data_types[i]) || isDateOrDateTime(data_types[i])) - { - /// An empty string instead of a value. - if (curr_position == prev_position) + if (format_settings.csv.empty_as_default + && (at_delimiter || at_last_column_line_end)) { - out << "ERROR: text "; - verbosePrintString(prev_position, std::min(prev_position + 10, in.buffer().end()), out); - out << " is not like " << data_types[i]->getName() << "\n"; - return false; + columns[table_column]->insertDefault(); } - } - - out << "parsed text: "; - verbosePrintString(prev_position, curr_position, out); - - if (exception) - { - if (data_types[i]->getName() == "DateTime") - out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; - else if (data_types[i]->getName() == "Date") - out << "ERROR: Date must be in YYYY-MM-DD format.\n"; else - out << "ERROR\n"; - return false; - } - - out << "\n"; - - if (data_types[i]->haveMaximumSizeOfValue()) - { - if (*curr_position != '\n' && *curr_position != '\r' && *curr_position != delimiter) { - out << "ERROR: garbage after " << data_types[i]->getName() << ": "; - verbosePrintString(curr_position, std::min(curr_position + 10, in.buffer().end()), out); + BufferBase::Position prev_position = in.position(); + BufferBase::Position curr_position = in.position(); + std::exception_ptr exception; + + try + { + skipWhitespacesAndTabs(in); + prev_position = in.position(); + current_column_type->deserializeAsTextCSV(*columns[table_column], in, format_settings); + curr_position = in.position(); + skipWhitespacesAndTabs(in); + } + catch (...) + { + exception = std::current_exception(); + } + + if (curr_position < prev_position) + throw Exception("Logical error: parsing is non-deterministic.", ErrorCodes::LOGICAL_ERROR); + + if (isNativeNumber(current_column_type) || isDateOrDateTime(current_column_type)) + { + /// An empty string instead of a value. + if (curr_position == prev_position) + { + out << "ERROR: text "; + verbosePrintString(prev_position, std::min(prev_position + 10, in.buffer().end()), out); + out << " is not like " << current_column_type->getName() << "\n"; + return false; + } + } + + out << "parsed text: "; + verbosePrintString(prev_position, curr_position, out); + + if (exception) + { + if (current_column_type->getName() == "DateTime") + out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; + else if (current_column_type->getName() == "Date") + out << "ERROR: Date must be in YYYY-MM-DD format.\n"; + else + out << "ERROR\n"; + return false; + } + out << "\n"; - if (data_types[i]->getName() == "DateTime") - out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; - else if (data_types[i]->getName() == "Date") - out << "ERROR: Date must be in YYYY-MM-DD format.\n"; + if (current_column_type->haveMaximumSizeOfValue() + && *curr_position != '\n' && *curr_position != '\r' + && *curr_position != delimiter) + { + out << "ERROR: garbage after " << current_column_type->getName() << ": "; + verbosePrintString(curr_position, std::min(curr_position + 10, in.buffer().end()), out); + out << "\n"; - return false; + if (current_column_type->getName() == "DateTime") + out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; + else if (current_column_type->getName() == "Date") + out << "ERROR: Date must be in YYYY-MM-DD format.\n"; + + return false; + } } } + else + { + static const String skipped_column_str = ""; + out << "Column " << file_column << ", " << std::string((file_column < 10 ? 2 : file_column < 100 ? 1 : 0), ' ') + << "name: " << skipped_column_str << ", " << std::string(max_length_of_column_name - skipped_column_str.length(), ' ') + << "type: " << skipped_column_str << ", " << std::string(max_length_of_data_type_name - skipped_column_str.length(), ' '); + + String tmp; + readCSVString(tmp, in, format_settings.csv); + } /// Delimiters - if (i + 1 == size) + if (file_column + 1 == column_indexes_for_input_fields.size()) { if (in.eof()) return false; @@ -294,8 +459,8 @@ bool CSVRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & columns, out << "ERROR: There is no line feed. "; verbosePrintString(in.position(), in.position() + 1, out); out << " found instead.\n" - " It's like your file has more columns than expected.\n" - "And if your file have right number of columns, maybe it have unquoted string value with comma.\n"; + " It's like your file has more columns than expected.\n" + "And if your file have right number of columns, maybe it have unquoted string value with comma.\n"; return false; } @@ -313,8 +478,8 @@ bool CSVRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & columns, if (*in.position() == '\n' || *in.position() == '\r') { out << "ERROR: Line feed found where delimiter (" << delimiter << ") is expected." - " It's like your file has less columns than expected.\n" - "And if your file have right number of columns, maybe it have unescaped quotes in values.\n"; + " It's like your file has less columns than expected.\n" + "And if your file have right number of columns, maybe it have unescaped quotes in values.\n"; } else { @@ -359,7 +524,7 @@ void registerInputFormatProcessorCSV(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, params, with_names, settings); + return std::make_shared(buf, sample, std::move(params), with_names, settings); }); } } diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h index db7041bc90a..b7e29157e0f 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h @@ -36,8 +36,26 @@ private: const FormatSettings format_settings; - /// For convenient diagnostics in case of an error. + using IndexesMap = std::unordered_map; + IndexesMap column_indexes_by_names; + /// Maps indexes of columns in the input file to indexes of table columns + using OptionalIndexes = std::vector>; + OptionalIndexes column_indexes_for_input_fields; + + /// Tracks which colums we have read in a single read() call. + /// For columns that are never read, it is initialized to false when we + /// read the file header, and never changed afterwards. + /// For other columns, it is updated on each read() call. + std::vector read_columns; + + /// Whether we have any columns that are not read from file at all, + /// and must be always initialized with defaults. + bool have_always_default_columns = false; + + void addInputColumn(const String & column_name); + + /// For convenient diagnostics in case of an error. size_t row_num = 0; /// How many bytes were read, not counting those that are still in the buffer. From ee3a93bab591b3b62c48da17d4f900529e43d45a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 30 Jul 2019 21:21:12 +0300 Subject: [PATCH 015/105] Update CSVRowInputFormat. --- dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp index 6dc7493187b..0c23070a95a 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp @@ -182,6 +182,16 @@ void CSVRowInputFormat::readPrefix() else skipRow(in, format_settings.csv, num_columns); } + + /// The default: map each column of the file to the column of the table with + /// the same index. + read_columns.assign(header.columns(), true); + column_indexes_for_input_fields.resize(header.columns()); + + for (size_t i = 0; i < column_indexes_for_input_fields.size(); ++i) + { + column_indexes_for_input_fields[i] = i; + } } From e8b643e03285de33e54e819c1f00ad2a2f314d53 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 30 Jul 2019 21:22:01 +0300 Subject: [PATCH 016/105] Update CSVRowInputFormat. --- dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp index 0c23070a95a..bdcabc58042 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp @@ -145,6 +145,7 @@ void CSVRowInputFormat::readPrefix() size_t num_columns = data_types.size(); String tmp; + auto & header = getPort().getHeader(); if (with_names) { @@ -154,7 +155,7 @@ void CSVRowInputFormat::readPrefix() { /// Look at the file header to see which columns we have there. /// The missing columns are filled with defaults. - read_columns.assign(getPort().getHeader().columns(), false); + read_columns.assign(header.columns(), false); do { String column_name; From b274545bb701f51ea2244bad21b83501a423da39 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 30 Jul 2019 21:48:40 +0300 Subject: [PATCH 017/105] Update CSVRowInputFormat. --- dbms/src/Processors/Formats/IInputFormat.h | 6 ++++++ dbms/src/Processors/Formats/IRowInputFormat.cpp | 6 +++--- dbms/src/Processors/Formats/IRowInputFormat.h | 4 ++++ dbms/src/Processors/Formats/InputStreamFromInputFormat.h | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dbms/src/Processors/Formats/IInputFormat.h b/dbms/src/Processors/Formats/IInputFormat.h index 7e4e00c1a33..ed26f60c058 100644 --- a/dbms/src/Processors/Formats/IInputFormat.h +++ b/dbms/src/Processors/Formats/IInputFormat.h @@ -27,6 +27,12 @@ public: : ISource(std::move(header)), in(in) { } + + virtual const BlockMissingValues & getMissingValues() const + { + static const BlockMissingValues none; + return none; + } }; } diff --git a/dbms/src/Processors/Formats/IRowInputFormat.cpp b/dbms/src/Processors/Formats/IRowInputFormat.cpp index b0212d2b89f..1565ec82e1d 100644 --- a/dbms/src/Processors/Formats/IRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/IRowInputFormat.cpp @@ -43,7 +43,7 @@ Chunk IRowInputFormat::generate() MutableColumns columns = header.cloneEmptyColumns(); size_t prev_rows = total_rows; - auto chunk_missing_values = std::make_unique(); + ///auto chunk_missing_values = std::make_unique(); try { @@ -64,7 +64,7 @@ Chunk IRowInputFormat::generate() size_t column_size = columns[column_idx]->size(); if (column_size == 0) throw Exception("Unexpected empty column", ErrorCodes::INCORRECT_NUMBER_OF_COLUMNS); - chunk_missing_values->setBit(column_idx, column_size - 1); + block_missing_values.setBit(column_idx, column_size - 1); } } } @@ -139,7 +139,7 @@ Chunk IRowInputFormat::generate() } Chunk chunk(std::move(columns), total_rows - prev_rows); - chunk.setChunkInfo(std::move(chunk_missing_values)); + //chunk.setChunkInfo(std::move(chunk_missing_values)); return chunk; } diff --git a/dbms/src/Processors/Formats/IRowInputFormat.h b/dbms/src/Processors/Formats/IRowInputFormat.h index b574af8c39a..b70edf47a64 100644 --- a/dbms/src/Processors/Formats/IRowInputFormat.h +++ b/dbms/src/Processors/Formats/IRowInputFormat.h @@ -66,11 +66,15 @@ protected: /// If not implemented, returns empty string. virtual std::string getDiagnosticInfo() { return {}; } + const BlockMissingValues & getMissingValues() const override { return block_missing_values; } + private: Params params; size_t total_rows = 0; size_t num_errors = 0; + + BlockMissingValues block_missing_values; }; } diff --git a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h index 266473f95de..4f94652fac7 100644 --- a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h +++ b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h @@ -22,6 +22,8 @@ public: String getName() const override { return input_format->getName(); } Block getHeader() const override { return input_format->getPort().getHeader(); } + const BlockMissingValues & getMissingValues() const override { return input_format->getMissingValues(); } + protected: Block readImpl() override From 5bdb6aa9f3edb307f5511aa24573cdf5be82747e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 12:43:08 +0300 Subject: [PATCH 018/105] Update TSKVRowInputFormat. --- dbms/src/Processors/Formats/Impl/TSKVRowInputFormat.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/TSKVRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/TSKVRowInputFormat.cpp index 7750962beec..b03480834c5 100644 --- a/dbms/src/Processors/Formats/Impl/TSKVRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/TSKVRowInputFormat.cpp @@ -16,15 +16,16 @@ namespace ErrorCodes TSKVRowInputFormat::TSKVRowInputFormat(ReadBuffer & in_, Block header, Params params, const FormatSettings & format_settings) - : IRowInputFormat(std::move(header), in_, params), format_settings(format_settings), name_map(header.columns()) + : IRowInputFormat(std::move(header), in_, std::move(params)), format_settings(format_settings), name_map(header.columns()) { /// In this format, we assume that column name cannot contain BOM, /// so BOM at beginning of stream cannot be confused with name of field, and it is safe to skip it. skipBOMIfExists(in); - size_t num_columns = header.columns(); + const auto & sample_block = getPort().getHeader(); + size_t num_columns = sample_block.columns(); for (size_t i = 0; i < num_columns; ++i) - name_map[header.safeGetByPosition(i).name] = i; /// NOTE You could place names more cache-locally. + name_map[sample_block.getByPosition(i).name] = i; /// NOTE You could place names more cache-locally. } @@ -200,7 +201,7 @@ void registerInputFormatProcessorTSKV(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, params, settings); + return std::make_shared(buf, sample, std::move(params), settings); }); } From 8bfd909f5b9b15f5cc59f9f0cb95f4644556d7e6 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 13:06:46 +0300 Subject: [PATCH 019/105] Update JSONEachRowRowOutputFormat. --- .../Processors/Formats/Impl/JSONEachRowRowInputFormat.cpp | 4 ++-- .../src/Processors/Formats/Impl/JSONEachRowRowOutputFormat.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.cpp index b1dde6d2275..100edb20f37 100644 --- a/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.cpp @@ -28,7 +28,7 @@ enum JSONEachRowRowInputFormat::JSONEachRowRowInputFormat( ReadBuffer & in_, const Block & header, Params params, const FormatSettings & format_settings) - : IRowInputFormat(header, in_, params), format_settings(format_settings), name_map(header.columns()) + : IRowInputFormat(header, in_, std::move(params)), format_settings(format_settings), name_map(header.columns()) { /// In this format, BOM at beginning of stream cannot be confused with value, so it is safe to skip it. skipBOMIfExists(in); @@ -263,7 +263,7 @@ void registerInputFormatProcessorJSONEachRow(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, params, settings); + return std::make_shared(buf, sample, std::move(params), settings); }); } diff --git a/dbms/src/Processors/Formats/Impl/JSONEachRowRowOutputFormat.h b/dbms/src/Processors/Formats/Impl/JSONEachRowRowOutputFormat.h index 0ceeb5352c7..a45f193ea39 100644 --- a/dbms/src/Processors/Formats/Impl/JSONEachRowRowOutputFormat.h +++ b/dbms/src/Processors/Formats/Impl/JSONEachRowRowOutputFormat.h @@ -24,6 +24,11 @@ public: void writeRowStartDelimiter() override; void writeRowEndDelimiter() override; +protected: + /// No totals and extremes. + void consumeTotals(Chunk) override {} + void consumeExtremes(Chunk) override {} + private: size_t field_number = 0; Names fields; From 4bea8541d1d48497f406a1fa01d88b325f174300 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 13:28:54 +0300 Subject: [PATCH 020/105] Update FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 9e5645492a8..e812eda944a 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace DB @@ -90,6 +91,16 @@ BlockInputStreamPtr FormatFactory::getInput( BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const { + if (name == "PrettyCompactMonoBlock") + { + /// TODO: rewrite + auto format = getOutputFormat(name, buf, sample, context); + return std::make_shared( + std::make_shared( + std::make_shared(format), sample), + sample, context.getSettingsRef().output_format_pretty_max_rows, 0); + } + auto format = getOutputFormat(name, buf, sample, context); /** Materialization is needed, because formats can use the functions `IDataType`, From cc74c5ec78036e55a8c03630c6e9051da4cb3012 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 13:31:14 +0300 Subject: [PATCH 021/105] Update FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index e812eda944a..0c28d1ec8e7 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -97,8 +97,8 @@ BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & auto format = getOutputFormat(name, buf, sample, context); return std::make_shared( std::make_shared( - std::make_shared(format), sample), - sample, context.getSettingsRef().output_format_pretty_max_rows, 0); + std::make_shared(format), + sample, context.getSettingsRef().output_format_pretty_max_rows, 0), sample); } auto format = getOutputFormat(name, buf, sample, context); From 0e61ca79d01ae415dcd3f40f1679d573222eace3 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 13:34:31 +0300 Subject: [PATCH 022/105] Update FormatFactory. --- dbms/src/DataStreams/SquashingBlockOutputStream.cpp | 4 ++-- dbms/src/DataStreams/SquashingBlockOutputStream.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/DataStreams/SquashingBlockOutputStream.cpp b/dbms/src/DataStreams/SquashingBlockOutputStream.cpp index 5698ee99f64..48156ed090f 100644 --- a/dbms/src/DataStreams/SquashingBlockOutputStream.cpp +++ b/dbms/src/DataStreams/SquashingBlockOutputStream.cpp @@ -4,8 +4,8 @@ namespace DB { -SquashingBlockOutputStream::SquashingBlockOutputStream(BlockOutputStreamPtr & dst, const Block & header, size_t min_block_size_rows, size_t min_block_size_bytes) - : output(dst), header(header), transform(min_block_size_rows, min_block_size_bytes) +SquashingBlockOutputStream::SquashingBlockOutputStream(BlockOutputStreamPtr dst, Block header, size_t min_block_size_rows, size_t min_block_size_bytes) + : output(std::move(dst)), header(std::move(header)), transform(min_block_size_rows, min_block_size_bytes) { } diff --git a/dbms/src/DataStreams/SquashingBlockOutputStream.h b/dbms/src/DataStreams/SquashingBlockOutputStream.h index 153f671a600..f255d18e331 100644 --- a/dbms/src/DataStreams/SquashingBlockOutputStream.h +++ b/dbms/src/DataStreams/SquashingBlockOutputStream.h @@ -12,7 +12,7 @@ namespace DB class SquashingBlockOutputStream : public IBlockOutputStream { public: - SquashingBlockOutputStream(BlockOutputStreamPtr & dst, const Block & header, size_t min_block_size_rows, size_t min_block_size_bytes); + SquashingBlockOutputStream(BlockOutputStreamPtr dst, Block header, size_t min_block_size_rows, size_t min_block_size_bytes); Block getHeader() const override { return header; } void write(const Block & block) override; From 2d5b282a31369db34d4f07e66da246a281ecc6f7 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 13:37:28 +0300 Subject: [PATCH 023/105] Update FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 0c28d1ec8e7..3dfdc07b71d 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -94,7 +94,7 @@ BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & if (name == "PrettyCompactMonoBlock") { /// TODO: rewrite - auto format = getOutputFormat(name, buf, sample, context); + auto format = getOutputFormat("PrettyCompact", buf, sample, context); return std::make_shared( std::make_shared( std::make_shared(format), From 77d81687b3f4813af2be3d393d9cb37e0c190884 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 13:54:50 +0300 Subject: [PATCH 024/105] Update FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 3dfdc07b71d..c4315528e4b 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -95,10 +95,13 @@ BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & { /// TODO: rewrite auto format = getOutputFormat("PrettyCompact", buf, sample, context); - return std::make_shared( - std::make_shared( - std::make_shared(format), - sample, context.getSettingsRef().output_format_pretty_max_rows, 0), sample); + auto res = std::make_shared( + std::make_shared(format), + sample, context.getSettingsRef().output_format_pretty_max_rows, 0); + + res->disableFlush(); + + return std::make_shared(res, sample); } auto format = getOutputFormat(name, buf, sample, context); From 2c638d577d8c5257eeba6924c9664e5fe5cb2fef Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 14:51:00 +0300 Subject: [PATCH 025/105] Update VerticalRowOutputFormat. --- dbms/src/Processors/Formats/Impl/VerticalRowOutputFormat.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/VerticalRowOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/VerticalRowOutputFormat.cpp index 8e9d0cd37c5..55f04584c19 100644 --- a/dbms/src/Processors/Formats/Impl/VerticalRowOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/VerticalRowOutputFormat.cpp @@ -110,12 +110,15 @@ void VerticalRowOutputFormat::writeSuffix() void VerticalRowOutputFormat::writeBeforeTotals() { writeCString("\n", out); + writeCString("\n", out); } void VerticalRowOutputFormat::writeBeforeExtremes() { if (!was_totals_written) writeCString("\n", out); + + writeCString("\n", out); } void VerticalRowOutputFormat::writeMinExtreme(const Columns & columns, size_t row_num) @@ -136,8 +139,6 @@ void VerticalRowOutputFormat::writeTotals(const Columns & columns, size_t row_nu void VerticalRowOutputFormat::writeSpecialRow(const Columns & columns, size_t row_num, PortKind port_kind, const char * title) { - writeCString("\n", out); - row_number = 0; field_number = 0; From 4e38a4592290537953585e9cd065fd58705b6f0e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 16:26:08 +0300 Subject: [PATCH 026/105] Update FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index c4315528e4b..c5280e45b48 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace DB @@ -84,6 +85,9 @@ BlockInputStreamPtr FormatFactory::getInput( UInt64 rows_portion_size, ReadCallback callback) const { + if (name == "Native") + return std::make_shared(buf, sample, 0); + auto format = getInputFormat(name, buf, sample, context, max_block_size, rows_portion_size, std::move(callback)); return std::make_shared(std::move(format)); } From f0bf083efc92d3397bd646c300f24c3d13f74b4b Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 17:16:28 +0300 Subject: [PATCH 027/105] Update CSVRowInputStream. --- dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp index bdcabc58042..5936ab0a369 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp @@ -171,7 +171,7 @@ void CSVRowInputFormat::readPrefix() for (auto read_column : read_columns) { - if (read_column) + if (!read_column) { have_always_default_columns = true; break; From 3a8fefdda8a0c752477d1c2b30f488a8d63bd0f3 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 17:43:08 +0300 Subject: [PATCH 028/105] Update CSVRowInputStream. --- .../Impl/TabSeparatedRowInputFormat.cpp | 329 ++++++++++++------ .../Formats/Impl/TabSeparatedRowInputFormat.h | 13 + 2 files changed, 235 insertions(+), 107 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.cpp index ab7562a0036..5834d46b322 100644 --- a/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.cpp @@ -16,24 +16,114 @@ namespace ErrorCodes } +static void skipTSVRow(ReadBuffer & istr, const size_t num_columns) +{ + NullSink null_sink; + + for (size_t i = 0; i < num_columns; ++i) + { + readEscapedStringInto(null_sink, istr); + assertChar(i == num_columns - 1 ? '\n' : '\t', istr); + } +} + + +/** Check for a common error case - usage of Windows line feed. + */ +static void checkForCarriageReturn(ReadBuffer & istr) +{ + if (istr.position()[0] == '\r' || (istr.position() != istr.buffer().begin() && istr.position()[-1] == '\r')) + throw Exception("\nYou have carriage return (\\r, 0x0D, ASCII 13) at end of first row." + "\nIt's like your input data has DOS/Windows style line separators, that are illegal in TabSeparated format." + " You must transform your file to Unix format." + "\nBut if you really need carriage return at end of string value of last column, you need to escape it as \\r.", + ErrorCodes::INCORRECT_DATA); +} + + TabSeparatedRowInputFormat::TabSeparatedRowInputFormat( ReadBuffer & in_, Block header, bool with_names, bool with_types, Params params, const FormatSettings & format_settings) - : IRowInputFormat(std::move(header), in_, params), with_names(with_names), with_types(with_types), format_settings(format_settings) + : IRowInputFormat(std::move(header), in_, std::move(params)), with_names(with_names), with_types(with_types), format_settings(format_settings) { auto & sample = getPort().getHeader(); size_t num_columns = sample.columns(); + data_types.resize(num_columns); + column_indexes_by_names.reserve(num_columns); + for (size_t i = 0; i < num_columns; ++i) - data_types[i] = sample.safeGetByPosition(i).type; + { + const auto & column_info = sample.getByPosition(i); + + data_types[i] = column_info.type; + column_indexes_by_names.emplace(column_info.name, i); + } + + column_indexes_for_input_fields.reserve(num_columns); + read_columns.assign(num_columns, false); +} + + +void TabSeparatedRowInputFormat::setupAllColumnsByTableSchema() +{ + auto & header = getPort().getHeader(); + read_columns.assign(header.columns(), true); + column_indexes_for_input_fields.resize(header.columns()); + + for (size_t i = 0; i < column_indexes_for_input_fields.size(); ++i) + column_indexes_for_input_fields[i] = i; +} + + +void TabSeparatedRowInputFormat::addInputColumn(const String & column_name) +{ + const auto column_it = column_indexes_by_names.find(column_name); + if (column_it == column_indexes_by_names.end()) + { + if (format_settings.skip_unknown_fields) + { + column_indexes_for_input_fields.push_back(std::nullopt); + return; + } + + throw Exception( + "Unknown field found in TSV header: '" + column_name + "' " + + "at position " + std::to_string(column_indexes_for_input_fields.size()) + + "\nSet the 'input_format_skip_unknown_fields' parameter explicitly to ignore and proceed", + ErrorCodes::INCORRECT_DATA + ); + } + + const auto column_index = column_it->second; + + if (read_columns[column_index]) + throw Exception("Duplicate field found while parsing TSV header: " + column_name, ErrorCodes::INCORRECT_DATA); + + read_columns[column_index] = true; + column_indexes_for_input_fields.emplace_back(column_index); +} + + +void TabSeparatedRowInputFormat::fillUnreadColumnsWithDefaults(MutableColumns & columns, RowReadExtension & row_read_extension) +{ + /// It is safe to memorize this on the first run - the format guarantees this does not change + if (unlikely(row_num == 1)) + { + columns_to_fill_with_default_values.clear(); + for (size_t index = 0; index < read_columns.size(); ++index) + if (read_columns[index] == 0) + columns_to_fill_with_default_values.push_back(index); + } + + for (const auto column_index : columns_to_fill_with_default_values) + data_types[column_index]->insertDefaultInto(*columns[column_index]); + + row_read_extension.read_columns = read_columns; } void TabSeparatedRowInputFormat::readPrefix() { - auto & header = getPort().getHeader(); - size_t num_columns = header.columns(); - String tmp; - if (with_names || with_types) { /// In this format, we assume that column name or type cannot contain BOM, @@ -44,65 +134,74 @@ void TabSeparatedRowInputFormat::readPrefix() if (with_names) { - for (size_t i = 0; i < num_columns; ++i) + if (format_settings.with_names_use_header) { - readEscapedString(tmp, in); - assertChar(i == num_columns - 1 ? '\n' : '\t', in); + String column_name; + do + { + readEscapedString(column_name, in); + addInputColumn(column_name); + } + while (checkChar('\t', in)); + + if (!in.eof()) + { + checkForCarriageReturn(in); + assertChar('\n', in); + } + } + else + { + setupAllColumnsByTableSchema(); + skipTSVRow(in, column_indexes_for_input_fields.size()); } } + else + setupAllColumnsByTableSchema(); if (with_types) { - for (size_t i = 0; i < num_columns; ++i) - { - readEscapedString(tmp, in); - assertChar(i == num_columns - 1 ? '\n' : '\t', in); - } + skipTSVRow(in, column_indexes_for_input_fields.size()); } } -/** Check for a common error case - usage of Windows line feed. - */ -static void checkForCarriageReturn(ReadBuffer & in) -{ - if (in.position()[0] == '\r' || (in.position() != in.buffer().begin() && in.position()[-1] == '\r')) - throw Exception("\nYou have carriage return (\\r, 0x0D, ASCII 13) at end of first row." - "\nIt's like your input data has DOS/Windows style line separators, that are illegal in TabSeparated format." - " You must transform your file to Unix format." - "\nBut if you really need carriage return at end of string value of last column, you need to escape it as \\r.", - ErrorCodes::INCORRECT_DATA); -} - - -bool TabSeparatedRowInputFormat::readRow(MutableColumns & columns, RowReadExtension &) +bool TabSeparatedRowInputFormat::readRow(MutableColumns & columns, RowReadExtension & ext) { if (in.eof()) return false; updateDiagnosticInfo(); - size_t size = data_types.size(); - - for (size_t i = 0; i < size; ++i) + for (size_t input_position = 0; input_position < column_indexes_for_input_fields.size(); ++input_position) { - data_types[i]->deserializeAsTextEscaped(*columns[i], in, format_settings); - - /// skip separators - if (i + 1 == size) + const auto & column_index = column_indexes_for_input_fields[input_position]; + if (column_index) { - if (!in.eof()) - { - if (unlikely(row_num == 1)) - checkForCarriageReturn(in); - - assertChar('\n', in); - } + data_types[*column_index]->deserializeAsTextEscaped(*columns[*column_index], in, format_settings); } else + { + NullSink null_sink; + readEscapedStringInto(null_sink, in); + } + + /// skip separators + if (input_position + 1 < column_indexes_for_input_fields.size()) + { assertChar('\t', in); + } + else if (!in.eof()) + { + if (unlikely(row_num == 1)) + checkForCarriageReturn(in); + + assertChar('\n', in); + } } + fillUnreadColumnsWithDefaults(columns, ext); + return true; } @@ -166,84 +265,100 @@ String TabSeparatedRowInputFormat::getDiagnosticInfo() bool TabSeparatedRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & columns, WriteBuffer & out, size_t max_length_of_column_name, size_t max_length_of_data_type_name) { - auto & header = getPort().getHeader(); - size_t size = data_types.size(); - for (size_t i = 0; i < size; ++i) + for (size_t input_position = 0; input_position < column_indexes_for_input_fields.size(); ++input_position) { - if (i == 0 && in.eof()) + if (input_position == 0 && in.eof()) { out << "\n"; return false; } - out << "Column " << i << ", " << std::string((i < 10 ? 2 : i < 100 ? 1 : 0), ' ') - << "name: " << header.safeGetByPosition(i).name << ", " << std::string(max_length_of_column_name - header.safeGetByPosition(i).name.size(), ' ') - << "type: " << data_types[i]->getName() << ", " << std::string(max_length_of_data_type_name - data_types[i]->getName().size(), ' '); - - auto prev_position = in.position(); - std::exception_ptr exception; - - try + if (column_indexes_for_input_fields[input_position].has_value()) { - data_types[i]->deserializeAsTextEscaped(*columns[i], in, format_settings); - } - catch (...) - { - exception = std::current_exception(); - } + const auto & column_index = *column_indexes_for_input_fields[input_position]; + const auto & current_column_type = data_types[column_index]; - auto curr_position = in.position(); + const auto & header = getPort().getHeader(); - if (curr_position < prev_position) - throw Exception("Logical error: parsing is non-deterministic.", ErrorCodes::LOGICAL_ERROR); + out << "Column " << input_position << ", " << std::string((input_position < 10 ? 2 : input_position < 100 ? 1 : 0), ' ') + << "name: " << header.safeGetByPosition(column_index).name << ", " << std::string(max_length_of_column_name - header.safeGetByPosition(column_index).name.size(), ' ') + << "type: " << current_column_type->getName() << ", " << std::string(max_length_of_data_type_name - current_column_type->getName().size(), ' '); - if (isNumber(data_types[i]) || isDateOrDateTime(data_types[i])) - { - /// An empty string instead of a value. - if (curr_position == prev_position) + auto prev_position = in.position(); + std::exception_ptr exception; + + try { - out << "ERROR: text "; - verbosePrintString(prev_position, std::min(prev_position + 10, in.buffer().end()), out); - out << " is not like " << data_types[i]->getName() << "\n"; - return false; + current_column_type->deserializeAsTextEscaped(*columns[column_index], in, format_settings); } - } - - out << "parsed text: "; - verbosePrintString(prev_position, curr_position, out); - - if (exception) - { - if (data_types[i]->getName() == "DateTime") - out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; - else if (data_types[i]->getName() == "Date") - out << "ERROR: Date must be in YYYY-MM-DD format.\n"; - else - out << "ERROR\n"; - return false; - } - - out << "\n"; - - if (data_types[i]->haveMaximumSizeOfValue()) - { - if (*curr_position != '\n' && *curr_position != '\t') + catch (...) { - out << "ERROR: garbage after " << data_types[i]->getName() << ": "; - verbosePrintString(curr_position, std::min(curr_position + 10, in.buffer().end()), out); - out << "\n"; + exception = std::current_exception(); + } - if (data_types[i]->getName() == "DateTime") + auto curr_position = in.position(); + + if (curr_position < prev_position) + throw Exception("Logical error: parsing is non-deterministic.", ErrorCodes::LOGICAL_ERROR); + + if (isNativeNumber(current_column_type) || isDateOrDateTime(current_column_type)) + { + /// An empty string instead of a value. + if (curr_position == prev_position) + { + out << "ERROR: text "; + verbosePrintString(prev_position, std::min(prev_position + 10, in.buffer().end()), out); + out << " is not like " << current_column_type->getName() << "\n"; + return false; + } + } + + out << "parsed text: "; + verbosePrintString(prev_position, curr_position, out); + + if (exception) + { + if (current_column_type->getName() == "DateTime") out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; - else if (data_types[i]->getName() == "Date") + else if (current_column_type->getName() == "Date") out << "ERROR: Date must be in YYYY-MM-DD format.\n"; - + else + out << "ERROR\n"; return false; } + + out << "\n"; + + if (current_column_type->haveMaximumSizeOfValue()) + { + if (*curr_position != '\n' && *curr_position != '\t') + { + out << "ERROR: garbage after " << current_column_type->getName() << ": "; + verbosePrintString(curr_position, std::min(curr_position + 10, in.buffer().end()), out); + out << "\n"; + + if (current_column_type->getName() == "DateTime") + out << "ERROR: DateTime must be in YYYY-MM-DD hh:mm:ss or NNNNNNNNNN (unix timestamp, exactly 10 digits) format.\n"; + else if (current_column_type->getName() == "Date") + out << "ERROR: Date must be in YYYY-MM-DD format.\n"; + + return false; + } + } + } + else + { + static const String skipped_column_str = ""; + out << "Column " << input_position << ", " << std::string((input_position < 10 ? 2 : input_position < 100 ? 1 : 0), ' ') + << "name: " << skipped_column_str << ", " << std::string(max_length_of_column_name - skipped_column_str.length(), ' ') + << "type: " << skipped_column_str << ", " << std::string(max_length_of_data_type_name - skipped_column_str.length(), ' '); + + NullSink null_sink; + readEscapedStringInto(null_sink, in); } /// Delimiters - if (i + 1 == size) + if (input_position + 1 == column_indexes_for_input_fields.size()) { if (!in.eof()) { @@ -256,13 +371,13 @@ bool TabSeparatedRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & if (*in.position() == '\t') { out << "ERROR: Tab found where line feed is expected." - " It's like your file has more columns than expected.\n" - "And if your file have right number of columns, maybe it have unescaped tab in value.\n"; + " It's like your file has more columns than expected.\n" + "And if your file have right number of columns, maybe it have unescaped tab in value.\n"; } else if (*in.position() == '\r') { out << "ERROR: Carriage return found where line feed is expected." - " It's like your file has DOS/Windows style line separators, that is illegal in TabSeparated format.\n"; + " It's like your file has DOS/Windows style line separators, that is illegal in TabSeparated format.\n"; } else { @@ -285,8 +400,8 @@ bool TabSeparatedRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumns & if (*in.position() == '\n') { out << "ERROR: Line feed found where tab is expected." - " It's like your file has less columns than expected.\n" - "And if your file have right number of columns, maybe it have unescaped backslash in value before tab, which cause tab has escaped.\n"; + " It's like your file has less columns than expected.\n" + "And if your file have right number of columns, maybe it have unescaped backslash in value before tab, which cause tab has escaped.\n"; } else if (*in.position() == '\r') { @@ -336,7 +451,7 @@ void registerInputFormatProcessorTabSeparated(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, false, false, params, settings); + return std::make_shared(buf, sample, false, false, std::move(params), settings); }); } @@ -349,7 +464,7 @@ void registerInputFormatProcessorTabSeparated(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, true, false, params, settings); + return std::make_shared(buf, sample, true, false, std::move(params), settings); }); } @@ -362,7 +477,7 @@ void registerInputFormatProcessorTabSeparated(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, true, true, params, settings); + return std::make_shared(buf, sample, true, true, std::move(params), settings); }); } } diff --git a/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.h b/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.h index b91884d9db5..47256e0b9a7 100644 --- a/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/TabSeparatedRowInputFormat.h @@ -37,6 +37,19 @@ private: const FormatSettings format_settings; DataTypes data_types; + using IndexesMap = std::unordered_map; + IndexesMap column_indexes_by_names; + + using OptionalIndexes = std::vector>; + OptionalIndexes column_indexes_for_input_fields; + + std::vector read_columns; + std::vector columns_to_fill_with_default_values; + + void addInputColumn(const String & column_name); + void setupAllColumnsByTableSchema(); + void fillUnreadColumnsWithDefaults(MutableColumns & columns, RowReadExtension& ext); + /// For convenient diagnostics in case of an error. size_t row_num = 0; From 1347cf13594d3682ae13df7c6c7af5c8cd68a35a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 17:58:56 +0300 Subject: [PATCH 029/105] Update ODBCDriver2BlockOutputFormat. --- .../Formats/Impl/ODBCDriver2BlockOutputFormat.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp index 543edade0e8..29effe47d5d 100644 --- a/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp @@ -6,6 +6,7 @@ #include +#include namespace DB @@ -95,8 +96,10 @@ void ODBCDriver2BlockOutputFormat::writePrefix() writeODBCString(out, "type"); for (size_t i = 0; i < columns; ++i) { - const ColumnWithTypeAndName & col = header.getByPosition(i); - writeODBCString(out, col.type->getName()); + auto type = header.getByPosition(i).type; + if (type->lowCardinality()) + type = recursiveRemoveLowCardinality(type); + writeODBCString(out, type->getName()); } } From 9c4aefe2ae380a49f8360871684f9972cd74959a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 31 Jul 2019 18:10:51 +0300 Subject: [PATCH 030/105] Update ODBCDriver2BlockOutputFormat. --- .../Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp index 29effe47d5d..d2a4842fa24 100644 --- a/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ODBCDriver2BlockOutputFormat.cpp @@ -39,7 +39,7 @@ void ODBCDriver2BlockOutputFormat::writeRow(const Block & header, const Columns { { WriteBufferFromString text_out(buffer); - header.getByPosition(row_idx).type->serializeAsText(*column, row_idx, text_out, format_settings); + header.getByPosition(column_idx).type->serializeAsText(*column, row_idx, text_out, format_settings); } writeODBCString(out, buffer); } From 9811fdcdc7ff96590d6ffdd56266feae78b99482 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 1 Aug 2019 11:31:08 +0300 Subject: [PATCH 031/105] Update CapnProtoRowInputFormat. --- .../Formats/Impl/CapnProtoRowInputFormat.cpp | 55 +++++++++++-------- .../Formats/Impl/CapnProtoRowInputFormat.h | 2 + 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp index 9ed84e89780..a6bead68bc5 100644 --- a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp @@ -206,28 +206,42 @@ CapnProtoRowInputFormat::CapnProtoRowInputFormat(ReadBuffer & in_, Block header, createActions(list, root); } +kj::Array CapnProtoRowInputFormat::readMessage() +{ + uint32_t segment_count; + in.readStrict(reinterpret_cast(&segment_count), sizeof(uint32_t)); + + // one for segmentCount and one because segmentCount starts from 0 + const auto prefix_size = (2 + segment_count) * sizeof(uint32_t); + const auto words_prefix_size = (segment_count + 1) / 2 + 1; + auto prefix = kj::heapArray(words_prefix_size); + auto prefix_chars = prefix.asChars(); + ::memcpy(prefix_chars.begin(), &segment_count, sizeof(uint32_t)); + + // read size of each segment + for (size_t i = 0; i <= segment_count; ++i) + in.readStrict(prefix_chars.begin() + ((i + 1) * sizeof(uint32_t)), sizeof(uint32_t)); + + // calculate size of message + const auto expected_words = capnp::expectedSizeInWordsFromPrefix(prefix); + const auto expected_bytes = expected_words * sizeof(capnp::word); + const auto data_size = expected_bytes - prefix_size; + auto msg = kj::heapArray(expected_words); + auto msg_chars = msg.asChars(); + + // read full message + ::memcpy(msg_chars.begin(), prefix_chars.begin(), prefix_size); + in.readStrict(msg_chars.begin() + prefix_size, data_size); + + return msg; +} bool CapnProtoRowInputFormat::readRow(MutableColumns & columns, RowReadExtension &) { if (in.eof()) return false; - // Read from underlying buffer directly - auto buf = in.buffer(); - auto base = reinterpret_cast(in.position()); - - // Check if there's enough bytes in the buffer to read the full message - kj::Array heap_array; - auto array = kj::arrayPtr(base, buf.size() - in.offset()); - auto expected_words = capnp::expectedSizeInWordsFromPrefix(array); - if (expected_words * sizeof(capnp::word) > array.size()) - { - // We'll need to reassemble the message in a contiguous buffer - heap_array = kj::heapArray(expected_words); - in.readStrict(heap_array.asChars().begin(), heap_array.asChars().size()); - array = heap_array.asPtr(); - } - + auto array = readMessage(); #if CAPNP_VERSION >= 8000 capnp::UnalignedFlatArrayMessageReader msg(array); @@ -281,13 +295,6 @@ bool CapnProtoRowInputFormat::readRow(MutableColumns & columns, RowReadExtension } } - // Advance buffer position if used directly - if (heap_array.size() == 0) - { - auto parsed = (msg.getEnd() - base) * sizeof(capnp::word); - in.position() += parsed; - } - return true; } @@ -297,7 +304,7 @@ void registerInputFormatProcessorCapnProto(FormatFactory & factory) "CapnProto", [](ReadBuffer & buf, const Block & sample, const Context & context, IRowInputFormat::Params params, const FormatSettings &) { - return std::make_shared(buf, sample, params, FormatSchemaInfo(context, "capnp")); + return std::make_shared(buf, sample, std::move(params), FormatSchemaInfo(context, "capnp")); }); } diff --git a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.h b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.h index 8d768538719..b941ceb514d 100644 --- a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.h @@ -40,6 +40,8 @@ public: bool readRow(MutableColumns & columns, RowReadExtension &) override; private: + kj::Array readMessage(); + // Build a traversal plan from a sorted list of fields void createActions(const NestedFieldList & sortedFields, capnp::StructSchema reader); From a5bb2e2b3ff1d0f42282a1372cb4f232e8e23120 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 1 Aug 2019 12:56:30 +0300 Subject: [PATCH 032/105] Update Schema name in Protobuf and CapnProto formats. --- dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp | 4 ++-- dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp index a6bead68bc5..87cad3022fb 100644 --- a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp @@ -179,7 +179,7 @@ void CapnProtoRowInputFormat::createActions(const NestedFieldList & sorted_field } CapnProtoRowInputFormat::CapnProtoRowInputFormat(ReadBuffer & in_, Block header, Params params, const FormatSchemaInfo & info) - : IRowInputFormat(std::move(header), in_, params), parser(std::make_shared()) + : IRowInputFormat(std::move(header), in_, std::move(params)), parser(std::make_shared()) { // Parse the schema and fetch the root object @@ -304,7 +304,7 @@ void registerInputFormatProcessorCapnProto(FormatFactory & factory) "CapnProto", [](ReadBuffer & buf, const Block & sample, const Context & context, IRowInputFormat::Params params, const FormatSettings &) { - return std::make_shared(buf, sample, std::move(params), FormatSchemaInfo(context, "capnp")); + return std::make_shared(buf, sample, std::move(params), FormatSchemaInfo(context, "CapnProto")); }); } diff --git a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp index a2f3a47def3..771aa9ea42e 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp @@ -75,7 +75,7 @@ void registerInputFormatProcessorProtobuf(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings &) { - return std::make_shared(buf, sample, params, FormatSchemaInfo(context, "proto")); + return std::make_shared(buf, sample, params, FormatSchemaInfo(context, "Protobuf")); }); } From c228f1813046c206720db202fa108da21857af56 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 1 Aug 2019 17:25:41 +0300 Subject: [PATCH 033/105] Update IRowInputFormat and FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 2 + .../Processors/Executors/PipelineExecutor.cpp | 17 ++++++- .../Processors/Executors/PipelineExecutor.h | 11 ++--- .../Processors/Formats/IRowInputFormat.cpp | 46 ++++++++++++++++++- dbms/src/Processors/Formats/IRowInputFormat.h | 7 +++ .../Formats/InputStreamFromInputFormat.h | 6 +++ dbms/src/Processors/IProcessor.h | 13 +++++- 7 files changed, 90 insertions(+), 12 deletions(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index c5280e45b48..022d6ae5915 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -139,6 +139,8 @@ InputFormatPtr FormatFactory::getInputFormat( params.allow_errors_ratio = format_settings.input_allow_errors_ratio; params.rows_portion_size = rows_portion_size; params.callback = std::move(callback); + params.max_execution_time = settings.max_execution_time; + params.timeout_overflow_mode = settings.timeout_overflow_mode; return input_getter(buf, sample, context, params, format_settings); } diff --git a/dbms/src/Processors/Executors/PipelineExecutor.cpp b/dbms/src/Processors/Executors/PipelineExecutor.cpp index 9da53793e81..e45bded427c 100644 --- a/dbms/src/Processors/Executors/PipelineExecutor.cpp +++ b/dbms/src/Processors/Executors/PipelineExecutor.cpp @@ -185,9 +185,12 @@ void PipelineExecutor::expandPipeline(Stack & stack, UInt64 pid) graph.emplace_back(processor.get(), graph.size()); } - processors.insert(processors.end(), new_processors.begin(), new_processors.end()); - UInt64 num_processors = processors.size(); + { + std::lock_guard guard(processors_mutex); + processors.insert(processors.end(), new_processors.begin(), new_processors.end()); + } + UInt64 num_processors = processors.size(); for (UInt64 node = 0; node < num_processors; ++node) { if (addEdges(node)) @@ -374,6 +377,16 @@ void PipelineExecutor::doExpandPipeline(ExpandPipelineTask * task, bool processi } } +void PipelineExecutor::cancel() +{ + cancelled = true; + finish(); + + std::lock_guard guard(processors_mutex); + for (auto & processor : processors) + processor->cancel(); +} + void PipelineExecutor::finish() { { diff --git a/dbms/src/Processors/Executors/PipelineExecutor.h b/dbms/src/Processors/Executors/PipelineExecutor.h index 0994532f953..02149cb042f 100644 --- a/dbms/src/Processors/Executors/PipelineExecutor.h +++ b/dbms/src/Processors/Executors/PipelineExecutor.h @@ -35,14 +35,11 @@ public: const Processors & getProcessors() const { return processors; } /// Cancel execution. May be called from another thread. - void cancel() - { - cancelled = true; - finish(); - } + void cancel(); private: Processors & processors; + std::mutex processors_mutex; struct Edge { @@ -75,8 +72,8 @@ private: std::exception_ptr exception; std::function job; - IProcessor * processor; - UInt64 processors_id; + IProcessor * processor = nullptr; + UInt64 processors_id = 0; /// Counters for profiling. size_t num_executed_jobs = 0; diff --git a/dbms/src/Processors/Formats/IRowInputFormat.cpp b/dbms/src/Processors/Formats/IRowInputFormat.cpp index 1565ec82e1d..2860587cbf2 100644 --- a/dbms/src/Processors/Formats/IRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/IRowInputFormat.cpp @@ -1,5 +1,6 @@ #include #include // toString +#include namespace DB @@ -16,6 +17,7 @@ namespace ErrorCodes extern const int CANNOT_PARSE_UUID; extern const int TOO_LARGE_STRING_SIZE; extern const int INCORRECT_NUMBER_OF_COLUMNS; + extern const int TIMEOUT_EXCEEDED; } @@ -32,6 +34,33 @@ static bool isParseError(int code) } +static bool handleOverflowMode(OverflowMode mode, const String & message, int code) +{ + switch (mode) + { + case OverflowMode::THROW: + throw Exception(message, code); + case OverflowMode::BREAK: + return false; + default: + throw Exception("Logical error: unknown overflow mode", ErrorCodes::LOGICAL_ERROR); + } +} + + +static bool checkTimeLimit(const IRowInputFormat::Params & params, const Stopwatch & stopwatch) +{ + if (params.max_execution_time != 0 + && stopwatch.elapsed() > static_cast(params.max_execution_time.totalMicroseconds()) * 1000) + return handleOverflowMode(params.timeout_overflow_mode, + "Timeout exceeded: elapsed " + toString(stopwatch.elapsedSeconds()) + + " seconds, maximum: " + toString(params.max_execution_time.totalMicroseconds() / 1000000.0), + ErrorCodes::TIMEOUT_EXCEEDED); + + return true; +} + + Chunk IRowInputFormat::generate() { if (total_rows == 0) @@ -47,8 +76,15 @@ Chunk IRowInputFormat::generate() try { - for (size_t rows = 0; rows < params.max_block_size; ++rows) + for (size_t rows = 0, batch = 0; rows < params.max_block_size; ++rows, ++batch) { + if (params.rows_portion_size && batch == params.rows_portion_size) + { + batch = 0; + if (!checkTimeLimit(params, total_stopwatch) || isCancelled()) + break; + } + try { ++total_rows; @@ -56,6 +92,8 @@ Chunk IRowInputFormat::generate() RowReadExtension info; if (!readRow(columns, info)) break; + if (params.callback) + params.callback(); for (size_t column_idx = 0; column_idx < info.read_columns.size(); ++column_idx) { @@ -134,6 +172,12 @@ Chunk IRowInputFormat::generate() if (columns.empty() || columns[0]->empty()) { + if (params.allow_errors_num > 0 || params.allow_errors_ratio > 0) + { + Logger * log = &Logger::get("BlockInputStreamFromRowInputStream"); + LOG_TRACE(log, "Skipped " << num_errors << " rows with errors while reading the input stream"); + } + readSuffix(); return {}; } diff --git a/dbms/src/Processors/Formats/IRowInputFormat.h b/dbms/src/Processors/Formats/IRowInputFormat.h index b70edf47a64..26d1a11a657 100644 --- a/dbms/src/Processors/Formats/IRowInputFormat.h +++ b/dbms/src/Processors/Formats/IRowInputFormat.h @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include namespace DB @@ -28,6 +31,9 @@ struct RowInputFormatParams using ReadCallback = std::function; ReadCallback callback; + + Poco::Timespan max_execution_time = 0; + OverflowMode timeout_overflow_mode = OverflowMode::THROW; }; ///Row oriented input format: reads data row by row. @@ -70,6 +76,7 @@ protected: private: Params params; + Stopwatch total_stopwatch {CLOCK_MONOTONIC_COARSE}; size_t total_rows = 0; size_t num_errors = 0; diff --git a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h index 4f94652fac7..963193940b8 100644 --- a/dbms/src/Processors/Formats/InputStreamFromInputFormat.h +++ b/dbms/src/Processors/Formats/InputStreamFromInputFormat.h @@ -22,6 +22,12 @@ public: String getName() const override { return input_format->getName(); } Block getHeader() const override { return input_format->getPort().getHeader(); } + void cancel(bool kill) override + { + input_format->cancel(); + IBlockInputStream::cancel(kill); + } + const BlockMissingValues & getMissingValues() const override { return input_format->getMissingValues(); } protected: diff --git a/dbms/src/Processors/IProcessor.h b/dbms/src/Processors/IProcessor.h index c5f9ef64b4a..18d34f29c99 100644 --- a/dbms/src/Processors/IProcessor.h +++ b/dbms/src/Processors/IProcessor.h @@ -211,6 +211,11 @@ public: throw Exception("Method 'expandPipeline' is not implemented for " + getName() + " processor", ErrorCodes::NOT_IMPLEMENTED); } + /// In case if query was cancelled executor will wait till all processors finish their jobs. + /// Generally, there is no reason to check this flag. However, it may be reasonable for long operations (e.g. i/o). + bool isCancelled() const { return is_cancelled; } + void cancel() { is_cancelled = true; } + virtual ~IProcessor() = default; auto & getInputs() { return inputs; } @@ -219,10 +224,14 @@ public: /// Debug output. void dump() const; - std::string processor_description; - + /// Used to print pipeline. void setDescription(const std::string & description_) { processor_description = description_; } const std::string & getDescription() const { return processor_description; } + +private: + std::atomic is_cancelled{false}; + + std::string processor_description; }; From 48818aef7ff252699bcf157599da89ae8eb6dbd0 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 15:41:21 +0300 Subject: [PATCH 034/105] Update MySQLOutputFormat. --- .../Formats/Impl/MySQLOutputFormat.cpp | 33 ++++++++++--------- .../Formats/Impl/MySQLOutputFormat.h | 4 +-- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp index 446fd687503..0487d6334b1 100644 --- a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp @@ -17,9 +17,10 @@ using namespace MySQLProtocol; MySQLOutputFormat::MySQLOutputFormat(WriteBuffer & out_, const Block & header, const Context & context, const FormatSettings & settings) : IOutputFormat(header, out_) , context(context) - , packet_sender(std::make_shared(out, const_cast(context.mysql.sequence_id))) /// TODO: fix it + , packet_sender(out, const_cast(context.mysql.sequence_id)) /// TODO: fix it , format_settings(settings) { + packet_sender.max_packet_size = context.mysql.max_packet_size; } void MySQLOutputFormat::consume(Chunk chunk) @@ -30,22 +31,21 @@ void MySQLOutputFormat::consume(Chunk chunk) { initialized = true; - if (header.columns()) { - packet_sender->sendPacket(LengthEncodedNumber(header.columns())); + packet_sender.sendPacket(LengthEncodedNumber(header.columns())); for (const ColumnWithTypeAndName & column : header.getColumnsWithTypeAndName()) { ColumnDefinition column_definition(column.name, CharacterSet::binary, 0, ColumnType::MYSQL_TYPE_STRING, 0, 0); - packet_sender->sendPacket(column_definition); + packet_sender.sendPacket(column_definition); } if (!(context.mysql.client_capabilities & Capability::CLIENT_DEPRECATE_EOF)) { - packet_sender->sendPacket(EOF_Packet(0, 0)); + packet_sender.sendPacket(EOF_Packet(0, 0)); } } } @@ -58,14 +58,11 @@ void MySQLOutputFormat::consume(Chunk chunk) ResultsetRow row_packet; for (size_t col = 0; col < columns.size(); ++col) { - String column_value; - WriteBufferFromString ostr(column_value); + WriteBufferFromOwnString ostr; header.getByPosition(col).type->serializeAsText(*columns[col], i, ostr, format_settings); - ostr.finish(); - - row_packet.appendColumn(std::move(column_value)); + row_packet.appendColumn(std::move(ostr.str())); } - packet_sender->sendPacket(row_packet); + packet_sender.sendPacket(row_packet); } } @@ -84,15 +81,19 @@ void MySQLOutputFormat::finalize() << formatReadableSizeWithBinarySuffix(info.read_bytes / info.elapsed_seconds) << "/sec."; } - auto & header = getPort(PortKind::Main).getHeader(); - + const auto & header = getPort(PortKind::Main).getHeader(); if (header.columns() == 0) - packet_sender->sendPacket(OK_Packet(0x0, context.mysql.client_capabilities, affected_rows, 0, 0, "", human_readable_info.str()), true); + packet_sender.sendPacket(OK_Packet(0x0, context.mysql.client_capabilities, affected_rows, 0, 0, "", human_readable_info.str()), true); else if (context.mysql.client_capabilities & CLIENT_DEPRECATE_EOF) - packet_sender->sendPacket(OK_Packet(0xfe, context.mysql.client_capabilities, affected_rows, 0, 0, "", human_readable_info.str()), true); + packet_sender.sendPacket(OK_Packet(0xfe, context.mysql.client_capabilities, affected_rows, 0, 0, "", human_readable_info.str()), true); else - packet_sender->sendPacket(EOF_Packet(0, 0), true); + packet_sender.sendPacket(EOF_Packet(0, 0), true); +} + +void MySQLOutputFormat::flush() +{ + packet_sender.out->next(); } void registerOutputFormatProcessorMySQLWrite(FormatFactory & factory) diff --git a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h index b959342ca4d..b9457a6369d 100644 --- a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h +++ b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h @@ -25,13 +25,13 @@ public: void consume(Chunk) override; void finalize() override; - + void flush() override; private: bool initialized = false; const Context & context; - std::shared_ptr packet_sender; + MySQLProtocol::PacketSender packet_sender; FormatSettings format_settings; }; From 49632a74b73f7748d7a5d96147b16d70739c7406 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 17:41:19 +0300 Subject: [PATCH 035/105] Update FormatFactory. --- dbms/src/Formats/FormatFactory.cpp | 72 +++++++++++++++--------------- dbms/src/Formats/FormatFactory.h | 19 ++++---- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 640682c2e64..820be203c6a 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -22,23 +22,15 @@ namespace ErrorCodes extern const int FORMAT_IS_NOT_SUITABLE_FOR_OUTPUT; } -// -//const FormatFactory::Creators & FormatFactory::getCreators(const String & name) const -//{ -// auto it = dict.find(name); -// if (dict.end() != it) -// return it->second; -// throw Exception("Unknown format " + name, ErrorCodes::UNKNOWN_FORMAT); -//} - -const FormatFactory::ProcessorCreators & FormatFactory::getProcessorCreators(const String & name) const +const FormatFactory::Creators & FormatFactory::getCreators(const String & name) const { - auto it = processors_dict.find(name); - if (processors_dict.end() != it) + auto it = dict.find(name); + if (dict.end() != it) return it->second; throw Exception("Unknown format " + name, ErrorCodes::UNKNOWN_FORMAT); } + static FormatSettings getInputFormatSetting(const Settings & settings) { FormatSettings format_settings; @@ -90,6 +82,9 @@ BlockInputStreamPtr FormatFactory::getInput( if (name == "Native") return std::make_shared(buf, sample, 0); + if (!getCreators(name).input_processor_creator) + return getInput(name, buf, sample, context, max_block_size, rows_portion_size, std::move(callback)); + auto format = getInputFormat(name, buf, sample, context, max_block_size, rows_portion_size, std::move(callback)); return std::make_shared(std::move(format)); } @@ -97,18 +92,21 @@ BlockInputStreamPtr FormatFactory::getInput( BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const { - if (name == "PrettyCompactMonoBlock") - { - /// TODO: rewrite - auto format = getOutputFormat("PrettyCompact", buf, sample, context); - auto res = std::make_shared( - std::make_shared(format), - sample, context.getSettingsRef().output_format_pretty_max_rows, 0); +// if (name == "PrettyCompactMonoBlock") +// { +// /// TODO: rewrite +// auto format = getOutputFormat("PrettyCompact", buf, sample, context); +// auto res = std::make_shared( +// std::make_shared(format), +// sample, context.getSettingsRef().output_format_pretty_max_rows, 0); +// +// res->disableFlush(); +// +// return std::make_shared(res, sample); +// } - res->disableFlush(); - - return std::make_shared(res, sample); - } + if (!getCreators(name).output_processor_creator) + return getOutput(name, buf, sample, context); auto format = getOutputFormat(name, buf, sample, context); @@ -128,7 +126,7 @@ InputFormatPtr FormatFactory::getInputFormat( UInt64 rows_portion_size, ReadCallback callback) const { - const auto & input_getter = getProcessorCreators(name).first; + const auto & input_getter = getCreators(name).input_processor_creator; if (!input_getter) throw Exception("Format " + name + " is not suitable for input", ErrorCodes::FORMAT_IS_NOT_SUITABLE_FOR_INPUT); @@ -150,7 +148,7 @@ InputFormatPtr FormatFactory::getInputFormat( OutputFormatPtr FormatFactory::getOutputFormat(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const { - const auto & output_getter = getProcessorCreators(name).second; + const auto & output_getter = getCreators(name).output_processor_creator; if (!output_getter) throw Exception("Format " + name + " is not suitable for output", ErrorCodes::FORMAT_IS_NOT_SUITABLE_FOR_OUTPUT); @@ -164,25 +162,25 @@ OutputFormatPtr FormatFactory::getOutputFormat(const String & name, WriteBuffer } -void FormatFactory::registerInputFormat(const String & /*name*/, InputCreator /*input_creator*/) +void FormatFactory::registerInputFormat(const String & name, InputCreator input_creator) { -// auto & target = dict[name].first; -// if (target) -// throw Exception("FormatFactory: Input format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); -// target = std::move(input_creator); + auto & target = dict[name].inout_creator; + if (target) + throw Exception("FormatFactory: Input format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); + target = std::move(input_creator); } -void FormatFactory::registerOutputFormat(const String & /*name*/, OutputCreator /*output_creator*/) +void FormatFactory::registerOutputFormat(const String & name, OutputCreator output_creator) { -// auto & target = dict[name].second; -// if (target) -// throw Exception("FormatFactory: Output format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); -// target = std::move(output_creator); + auto & target = dict[name].output_creator; + if (target) + throw Exception("FormatFactory: Output format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); + target = std::move(output_creator); } void FormatFactory::registerInputFormatProcessor(const String & name, InputProcessorCreator input_creator) { - auto & target = processors_dict[name].first; + auto & target = dict[name].input_processor_creator; if (target) throw Exception("FormatFactory: Input format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); target = std::move(input_creator); @@ -190,7 +188,7 @@ void FormatFactory::registerInputFormatProcessor(const String & name, InputProce void FormatFactory::registerOutputFormatProcessor(const String & name, OutputProcessorCreator output_creator) { - auto & target = processors_dict[name].second; + auto & target = dict[name].output_processor_creator; if (target) throw Exception("FormatFactory: Output format " + name + " is already registered", ErrorCodes::LOGICAL_ERROR); target = std::move(output_creator); diff --git a/dbms/src/Formats/FormatFactory.h b/dbms/src/Formats/FormatFactory.h index 23fd71aa9ad..83728c96cd2 100644 --- a/dbms/src/Formats/FormatFactory.h +++ b/dbms/src/Formats/FormatFactory.h @@ -70,11 +70,15 @@ private: const Context & context, const FormatSettings & settings)>; - using Creators = std::pair; - using ProcessorCreators = std::pair; + struct Creators + { + InputCreator inout_creator; + OutputCreator output_creator; + InputProcessorCreator input_processor_creator; + OutputProcessorCreator output_processor_creator; + }; using FormatsDictionary = std::unordered_map; - using FormatProcessorsDictionary = std::unordered_map; public: BlockInputStreamPtr getInput( @@ -108,20 +112,19 @@ public: void registerInputFormatProcessor(const String & name, InputProcessorCreator input_creator); void registerOutputFormatProcessor(const String & name, OutputProcessorCreator output_creator); - const FormatProcessorsDictionary & getAllFormats() const + const FormatsDictionary & getAllFormats() const { - return processors_dict; + return dict; } private: /// FormatsDictionary dict; - FormatProcessorsDictionary processors_dict; + FormatsDictionary dict; FormatFactory(); friend class ext::singleton; - //const Creators & getCreators(const String & name) const; - const ProcessorCreators & getProcessorCreators(const String & name) const; + const Creators & getCreators(const String & name) const; }; } From dd909322229eecb201e14a6fa83596aa578b2e33 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:06:31 +0300 Subject: [PATCH 036/105] Update FormatFactory. --- dbms/src/Storages/System/StorageSystemFormats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/System/StorageSystemFormats.cpp b/dbms/src/Storages/System/StorageSystemFormats.cpp index 96ce7ea7ed9..f0d97db5a98 100644 --- a/dbms/src/Storages/System/StorageSystemFormats.cpp +++ b/dbms/src/Storages/System/StorageSystemFormats.cpp @@ -20,9 +20,9 @@ void StorageSystemFormats::fillData(MutableColumns & res_columns, const Context const auto & formats = FormatFactory::instance().getAllFormats(); for (const auto & pair : formats) { - const auto & [name, creator_pair] = pair; - UInt64 has_input_format(creator_pair.first != nullptr); - UInt64 has_output_format(creator_pair.second != nullptr); + const auto & [name, creators] = pair; + UInt64 has_input_format(creators.inout_creator != nullptr || creators.input_processor_creator != nullptr); + UInt64 has_output_format(creators.output_creator != nullptr || creators.output_processor_creator != nullptr); res_columns[0]->insert(name); res_columns[1]->insert(has_input_format); res_columns[2]->insert(has_output_format); From 03ece9dc997cd925610477b2fd7fe1f8d66e7fea Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:21:48 +0300 Subject: [PATCH 037/105] Remove BinaryRowInputStream. --- dbms/src/Formats/BinaryRowInputStream.cpp | 91 ----------------------- dbms/src/Formats/BinaryRowInputStream.h | 30 -------- dbms/src/Formats/FormatFactory.cpp | 2 - 3 files changed, 123 deletions(-) delete mode 100644 dbms/src/Formats/BinaryRowInputStream.cpp delete mode 100644 dbms/src/Formats/BinaryRowInputStream.h diff --git a/dbms/src/Formats/BinaryRowInputStream.cpp b/dbms/src/Formats/BinaryRowInputStream.cpp deleted file mode 100644 index 9177a70bb18..00000000000 --- a/dbms/src/Formats/BinaryRowInputStream.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace DB -{ - -BinaryRowInputStream::BinaryRowInputStream(ReadBuffer & istr_, const Block & header_, bool with_names_, bool with_types_) - : istr(istr_), header(header_), with_names(with_names_), with_types(with_types_) -{ -} - - -bool BinaryRowInputStream::read(MutableColumns & columns, RowReadExtension &) -{ - if (istr.eof()) - return false; - - size_t num_columns = columns.size(); - for (size_t i = 0; i < num_columns; ++i) - header.getByPosition(i).type->deserializeBinary(*columns[i], istr); - - return true; -} - - -void BinaryRowInputStream::readPrefix() -{ - /// NOTE The header is completely ignored. This can be easily improved. - - UInt64 columns = 0; - String tmp; - - if (with_names || with_types) - { - readVarUInt(columns, istr); - } - - if (with_names) - { - for (size_t i = 0; i < columns; ++i) - { - readStringBinary(tmp, istr); - } - } - - if (with_types) - { - for (size_t i = 0; i < columns; ++i) - { - readStringBinary(tmp, istr); - } - } -} - - -void registerInputFormatRowBinary(FormatFactory & factory) -{ - factory.registerInputFormat("RowBinary", []( - ReadBuffer & buf, - const Block & sample, - const Context &, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, false, false), - sample, max_block_size, rows_portion_size, callback, settings); - }); - - factory.registerInputFormat("RowBinaryWithNamesAndTypes", []( - ReadBuffer & buf, - const Block & sample, - const Context &, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, true, true), - sample, max_block_size, rows_portion_size, callback, settings); - }); -} - -} diff --git a/dbms/src/Formats/BinaryRowInputStream.h b/dbms/src/Formats/BinaryRowInputStream.h deleted file mode 100644 index 43af4076f9c..00000000000 --- a/dbms/src/Formats/BinaryRowInputStream.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include - - -namespace DB -{ - -class ReadBuffer; - - -/** A stream for inputting data in a binary line-by-line format. - */ -class BinaryRowInputStream : public IRowInputStream -{ -public: - BinaryRowInputStream(ReadBuffer & istr_, const Block & sample_, bool with_names_, bool with_types_); - - bool read(MutableColumns & columns, RowReadExtension &) override; - void readPrefix() override; - -private: - ReadBuffer & istr; - Block header; - bool with_names; - bool with_types; -}; - -} diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 820be203c6a..7a83ff2e7ae 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -199,7 +199,6 @@ void FormatFactory::registerOutputFormatProcessor(const String & name, OutputPro void registerInputFormatNative(FormatFactory & factory); void registerOutputFormatNative(FormatFactory & factory); -void registerInputFormatRowBinary(FormatFactory & factory); void registerOutputFormatRowBinary(FormatFactory & factory); void registerInputFormatTabSeparated(FormatFactory & factory); void registerOutputFormatTabSeparated(FormatFactory & factory); @@ -271,7 +270,6 @@ FormatFactory::FormatFactory() { registerInputFormatNative(*this); registerOutputFormatNative(*this); - registerInputFormatRowBinary(*this); registerOutputFormatRowBinary(*this); registerInputFormatTabSeparated(*this); registerOutputFormatTabSeparated(*this); From 342f044241a6d73de36cf2a56622a44bce8689c3 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:25:32 +0300 Subject: [PATCH 038/105] Remove BinaryRowOutputStream. --- dbms/src/Formats/BinaryRowOutputStream.cpp | 77 ---------------------- dbms/src/Formats/BinaryRowOutputStream.h | 37 ----------- dbms/src/Formats/FormatFactory.cpp | 2 - 3 files changed, 116 deletions(-) delete mode 100644 dbms/src/Formats/BinaryRowOutputStream.cpp delete mode 100644 dbms/src/Formats/BinaryRowOutputStream.h diff --git a/dbms/src/Formats/BinaryRowOutputStream.cpp b/dbms/src/Formats/BinaryRowOutputStream.cpp deleted file mode 100644 index bbc01f5db04..00000000000 --- a/dbms/src/Formats/BinaryRowOutputStream.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -BinaryRowOutputStream::BinaryRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_, bool with_types_) - : ostr(ostr_), with_names(with_names_), with_types(with_types_), sample(sample_) -{ -} - -void BinaryRowOutputStream::writePrefix() -{ - size_t columns = sample.columns(); - - if (with_names || with_types) - { - writeVarUInt(columns, ostr); - } - - if (with_names) - { - for (size_t i = 0; i < columns; ++i) - { - writeStringBinary(sample.safeGetByPosition(i).name, ostr); - } - } - - if (with_types) - { - for (size_t i = 0; i < columns; ++i) - { - writeStringBinary(sample.safeGetByPosition(i).type->getName(), ostr); - } - } -} - -void BinaryRowOutputStream::flush() -{ - ostr.next(); -} - -void BinaryRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - type.serializeBinary(column, row_num, ostr); -} - -void registerOutputFormatRowBinary(FormatFactory & factory) -{ - factory.registerOutputFormat("RowBinary", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings &) - { - return std::make_shared( - std::make_shared(buf, sample, false, false), sample); - }); - - factory.registerOutputFormat("RowBinaryWithNamesAndTypes", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings &) - { - return std::make_shared( - std::make_shared(buf, sample, true, true), sample); - }); -} - -} diff --git a/dbms/src/Formats/BinaryRowOutputStream.h b/dbms/src/Formats/BinaryRowOutputStream.h deleted file mode 100644 index d16bcfa6c03..00000000000 --- a/dbms/src/Formats/BinaryRowOutputStream.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include - - -namespace DB -{ - -class IColumn; -class IDataType; -class WriteBuffer; - - -/** A stream for outputting data in a binary line-by-line format. - */ -class BinaryRowOutputStream : public IRowOutputStream -{ -public: - BinaryRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_, bool with_types_); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writePrefix() override; - - void flush() override; - - String getContentType() const override { return "application/octet-stream"; } - -protected: - WriteBuffer & ostr; - bool with_names; - bool with_types; - const Block sample; -}; - -} - diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 7a83ff2e7ae..ee569b3fa60 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -199,7 +199,6 @@ void FormatFactory::registerOutputFormatProcessor(const String & name, OutputPro void registerInputFormatNative(FormatFactory & factory); void registerOutputFormatNative(FormatFactory & factory); -void registerOutputFormatRowBinary(FormatFactory & factory); void registerInputFormatTabSeparated(FormatFactory & factory); void registerOutputFormatTabSeparated(FormatFactory & factory); void registerInputFormatValues(FormatFactory & factory); @@ -270,7 +269,6 @@ FormatFactory::FormatFactory() { registerInputFormatNative(*this); registerOutputFormatNative(*this); - registerOutputFormatRowBinary(*this); registerInputFormatTabSeparated(*this); registerOutputFormatTabSeparated(*this); registerInputFormatValues(*this); From 2833ca6d2f210923f5693c9b29985f2c651a2c5b Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:28:13 +0300 Subject: [PATCH 039/105] Remove CapnProtoRowInputStream. --- dbms/src/Formats/CapnProtoRowInputStream.cpp | 334 ------------------- dbms/src/Formats/CapnProtoRowInputStream.h | 76 ----- dbms/src/Formats/FormatFactory.cpp | 4 - 3 files changed, 414 deletions(-) delete mode 100644 dbms/src/Formats/CapnProtoRowInputStream.cpp delete mode 100644 dbms/src/Formats/CapnProtoRowInputStream.h diff --git a/dbms/src/Formats/CapnProtoRowInputStream.cpp b/dbms/src/Formats/CapnProtoRowInputStream.cpp deleted file mode 100644 index 96c3c5fded3..00000000000 --- a/dbms/src/Formats/CapnProtoRowInputStream.cpp +++ /dev/null @@ -1,334 +0,0 @@ -#include "config_formats.h" -#if USE_CAPNP - -#include "CapnProtoRowInputStream.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int BAD_TYPE_OF_FIELD; - extern const int BAD_ARGUMENTS; - extern const int THERE_IS_NO_COLUMN; - extern const int LOGICAL_ERROR; -} - -CapnProtoRowInputStream::NestedField split(const Block & header, size_t i) -{ - CapnProtoRowInputStream::NestedField field = {{}, i}; - - // Remove leading dot in field definition, e.g. ".msg" -> "msg" - String name(header.safeGetByPosition(i).name); - if (name.size() > 0 && name[0] == '.') - name.erase(0, 1); - - boost::split(field.tokens, name, boost::is_any_of("._")); - return field; -} - - -Field convertNodeToField(capnp::DynamicValue::Reader value) -{ - switch (value.getType()) - { - case capnp::DynamicValue::UNKNOWN: - throw Exception("Unknown field type", ErrorCodes::BAD_TYPE_OF_FIELD); - case capnp::DynamicValue::VOID: - return Field(); - case capnp::DynamicValue::BOOL: - return value.as() ? 1u : 0u; - case capnp::DynamicValue::INT: - return value.as(); - case capnp::DynamicValue::UINT: - return value.as(); - case capnp::DynamicValue::FLOAT: - return value.as(); - case capnp::DynamicValue::TEXT: - { - auto arr = value.as(); - return String(arr.begin(), arr.size()); - } - case capnp::DynamicValue::DATA: - { - auto arr = value.as().asChars(); - return String(arr.begin(), arr.size()); - } - case capnp::DynamicValue::LIST: - { - auto listValue = value.as(); - Array res(listValue.size()); - for (auto i : kj::indices(listValue)) - res[i] = convertNodeToField(listValue[i]); - - return res; - } - case capnp::DynamicValue::ENUM: - return value.as().getRaw(); - case capnp::DynamicValue::STRUCT: - { - auto structValue = value.as(); - const auto & fields = structValue.getSchema().getFields(); - - Field field = Tuple(TupleBackend(fields.size())); - TupleBackend & tuple = get(field).toUnderType(); - for (auto i : kj::indices(fields)) - tuple[i] = convertNodeToField(structValue.get(fields[i])); - - return field; - } - case capnp::DynamicValue::CAPABILITY: - throw Exception("CAPABILITY type not supported", ErrorCodes::BAD_TYPE_OF_FIELD); - case capnp::DynamicValue::ANY_POINTER: - throw Exception("ANY_POINTER type not supported", ErrorCodes::BAD_TYPE_OF_FIELD); - } - return Field(); -} - -capnp::StructSchema::Field getFieldOrThrow(capnp::StructSchema node, const std::string & field) -{ - KJ_IF_MAYBE(child, node.findFieldByName(field)) - return *child; - else - throw Exception("Field " + field + " doesn't exist in schema " + node.getShortDisplayName().cStr(), ErrorCodes::THERE_IS_NO_COLUMN); -} - - -void CapnProtoRowInputStream::createActions(const NestedFieldList & sorted_fields, capnp::StructSchema reader) -{ - /// Columns in a table can map to fields in Cap'n'Proto or to structs. - - /// Store common parents and their tokens in order to backtrack. - std::vector parents; - std::vector parent_tokens; - - capnp::StructSchema cur_reader = reader; - - for (const auto & field : sorted_fields) - { - if (field.tokens.empty()) - throw Exception("Logical error in CapnProtoRowInputStream", ErrorCodes::LOGICAL_ERROR); - - // Backtrack to common parent - while (field.tokens.size() < parent_tokens.size() + 1 - || !std::equal(parent_tokens.begin(), parent_tokens.end(), field.tokens.begin())) - { - actions.push_back({Action::POP}); - parents.pop_back(); - parent_tokens.pop_back(); - - if (parents.empty()) - { - cur_reader = reader; - break; - } - else - cur_reader = parents.back().getType().asStruct(); - } - - // Go forward - while (parent_tokens.size() + 1 < field.tokens.size()) - { - const auto & token = field.tokens[parents.size()]; - auto node = getFieldOrThrow(cur_reader, token); - if (node.getType().isStruct()) - { - // Descend to field structure - parents.emplace_back(node); - parent_tokens.emplace_back(token); - cur_reader = node.getType().asStruct(); - actions.push_back({Action::PUSH, node}); - } - else if (node.getType().isList()) - { - break; // Collect list - } - else - throw Exception("Field " + token + " is neither Struct nor List", ErrorCodes::BAD_TYPE_OF_FIELD); - } - - // Read field from the structure - auto node = getFieldOrThrow(cur_reader, field.tokens[parents.size()]); - if (node.getType().isList() && actions.size() > 0 && actions.back().field == node) - { - // The field list here flattens Nested elements into multiple arrays - // In order to map Nested types in Cap'nProto back, they need to be collected - // Since the field names are sorted, the order of field positions must be preserved - // For example, if the fields are { b @0 :Text, a @1 :Text }, the `a` would come first - // even though it's position is second. - auto & columns = actions.back().columns; - auto it = std::upper_bound(columns.cbegin(), columns.cend(), field.pos); - columns.insert(it, field.pos); - } - else - { - actions.push_back({Action::READ, node, {field.pos}}); - } - } -} - -CapnProtoRowInputStream::CapnProtoRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSchemaInfo& info) - : istr(istr_), header(header_), parser(std::make_shared()) -{ - // Parse the schema and fetch the root object - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - auto schema = parser->impl.parseDiskFile(info.schemaPath(), info.absoluteSchemaPath(), {}); -#pragma GCC diagnostic pop - - root = schema.getNested(info.messageName()).asStruct(); - - /** - * The schema typically consists of fields in various nested structures. - * Here we gather the list of fields and sort them in a way so that fields in the same structure are adjacent, - * and the nesting level doesn't decrease to make traversal easier. - */ - NestedFieldList list; - size_t num_columns = header.columns(); - for (size_t i = 0; i < num_columns; ++i) - list.push_back(split(header, i)); - - // Order list first by value of strings then by length of string vector. - std::sort(list.begin(), list.end(), [](const NestedField & a, const NestedField & b) { return a.tokens < b.tokens; }); - createActions(list, root); -} - -kj::Array CapnProtoRowInputStream::readMessage() -{ - uint32_t segment_count; - istr.readStrict(reinterpret_cast(&segment_count), sizeof(uint32_t)); - - // one for segmentCount and one because segmentCount starts from 0 - const auto prefix_size = (2 + segment_count) * sizeof(uint32_t); - const auto words_prefix_size = (segment_count + 1) / 2 + 1; - auto prefix = kj::heapArray(words_prefix_size); - auto prefix_chars = prefix.asChars(); - ::memcpy(prefix_chars.begin(), &segment_count, sizeof(uint32_t)); - - // read size of each segment - for (size_t i = 0; i <= segment_count; ++i) - istr.readStrict(prefix_chars.begin() + ((i + 1) * sizeof(uint32_t)), sizeof(uint32_t)); - - // calculate size of message - const auto expected_words = capnp::expectedSizeInWordsFromPrefix(prefix); - const auto expected_bytes = expected_words * sizeof(capnp::word); - const auto data_size = expected_bytes - prefix_size; - auto msg = kj::heapArray(expected_words); - auto msg_chars = msg.asChars(); - - // read full message - ::memcpy(msg_chars.begin(), prefix_chars.begin(), prefix_size); - istr.readStrict(msg_chars.begin() + prefix_size, data_size); - - return msg; -} - -bool CapnProtoRowInputStream::read(MutableColumns & columns, RowReadExtension &) -{ - if (istr.eof()) - return false; - - auto array = readMessage(); - -#if CAPNP_VERSION >= 8000 - capnp::UnalignedFlatArrayMessageReader msg(array); -#else - capnp::FlatArrayMessageReader msg(array); -#endif - std::vector stack; - stack.push_back(msg.getRoot(root)); - - for (auto action : actions) - { - switch (action.type) - { - case Action::READ: - { - Field value = convertNodeToField(stack.back().get(action.field)); - if (action.columns.size() > 1) - { - // Nested columns must be flattened into several arrays - // e.g. Array(Tuple(x ..., y ...)) -> Array(x ...), Array(y ...) - const Array & collected = DB::get(value); - size_t size = collected.size(); - // The flattened array contains an array of a part of the nested tuple - Array flattened(size); - for (size_t column_index = 0; column_index < action.columns.size(); ++column_index) - { - // Populate array with a single tuple elements - for (size_t off = 0; off < size; ++off) - { - const TupleBackend & tuple = DB::get(collected[off]).toUnderType(); - flattened[off] = tuple[column_index]; - } - auto & col = columns[action.columns[column_index]]; - col->insert(flattened); - } - } - else - { - auto & col = columns[action.columns[0]]; - col->insert(value); - } - - break; - } - case Action::POP: - stack.pop_back(); - break; - case Action::PUSH: - stack.push_back(stack.back().get(action.field).as()); - break; - } - } - - return true; -} - -void registerInputFormatCapnProto(FormatFactory & factory) -{ - factory.registerInputFormat( - "CapnProto", - [](ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, FormatSchemaInfo(context, "CapnProto")), - sample, - max_block_size, - rows_portion_size, - callback, - settings); - }); -} - -} - -#else - -namespace DB -{ - class FormatFactory; - void registerInputFormatCapnProto(FormatFactory &) {} -} - -#endif // USE_CAPNP diff --git a/dbms/src/Formats/CapnProtoRowInputStream.h b/dbms/src/Formats/CapnProtoRowInputStream.h deleted file mode 100644 index 07023c3eb4c..00000000000 --- a/dbms/src/Formats/CapnProtoRowInputStream.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include "config_formats.h" -#if USE_CAPNP - -#include -#include -#include - -namespace DB -{ - -class FormatSchemaInfo; -class ReadBuffer; - -/** A stream for reading messages in Cap'n Proto format in given schema. - * Like Protocol Buffers and Thrift (but unlike JSON or MessagePack), - * Cap'n Proto messages are strongly-typed and not self-describing. - * The schema in this case cannot be compiled in, so it uses a runtime schema parser. - * See https://capnproto.org/cxx.html - */ -class CapnProtoRowInputStream : public IRowInputStream -{ -public: - struct NestedField - { - std::vector tokens; - size_t pos; - }; - using NestedFieldList = std::vector; - - /** schema_dir - base path for schema files - * schema_file - location of the capnproto schema, e.g. "schema.capnp" - * root_object - name to the root object, e.g. "Message" - */ - CapnProtoRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSchemaInfo & info); - - bool read(MutableColumns & columns, RowReadExtension &) override; - -private: - kj::Array readMessage(); - - // Build a traversal plan from a sorted list of fields - void createActions(const NestedFieldList & sortedFields, capnp::StructSchema reader); - - /* Action for state machine for traversing nested structures. */ - using BlockPositionList = std::vector; - struct Action - { - enum Type { POP, PUSH, READ }; - Type type{}; - capnp::StructSchema::Field field{}; - BlockPositionList columns{}; - }; - - // Wrapper for classes that could throw in destructor - // https://github.com/capnproto/capnproto/issues/553 - template - struct DestructorCatcher - { - T impl; - template - DestructorCatcher(Arg && ... args) : impl(kj::fwd(args)...) {} - ~DestructorCatcher() noexcept try { } catch (...) { return; } - }; - using SchemaParser = DestructorCatcher; - - ReadBuffer & istr; - Block header; - std::shared_ptr parser; - capnp::StructSchema root; - std::vector actions; -}; - -} - -#endif // USE_CAPNP diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index ee569b3fa60..7cc02f0938d 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -260,11 +260,8 @@ void registerOutputFormatProcessorNull(FormatFactory & factory); void registerOutputFormatProcessorMySQLWrite(FormatFactory & factory); /// Input only formats. - -void registerInputFormatCapnProto(FormatFactory & factory); void registerInputFormatProcessorCapnProto(FormatFactory & factory); - FormatFactory::FormatFactory() { registerInputFormatNative(*this); @@ -281,7 +278,6 @@ FormatFactory::FormatFactory() registerOutputFormatJSONEachRow(*this); registerInputFormatProtobuf(*this); registerOutputFormatProtobuf(*this); - registerInputFormatCapnProto(*this); registerInputFormatParquet(*this); registerOutputFormatParquet(*this); From cd299bb162f2d55fb5e5772f6ecf77b63cf69cfd Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:32:07 +0300 Subject: [PATCH 040/105] Remove JSONCompactRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - .../Formats/JSONCompactRowOutputStream.cpp | 120 ------------------ dbms/src/Formats/JSONCompactRowOutputStream.h | 31 ----- 3 files changed, 153 deletions(-) delete mode 100644 dbms/src/Formats/JSONCompactRowOutputStream.cpp delete mode 100644 dbms/src/Formats/JSONCompactRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 7cc02f0938d..0448e45a444 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -240,7 +240,6 @@ void registerOutputFormatPrettyCompact(FormatFactory & factory); void registerOutputFormatPrettySpace(FormatFactory & factory); void registerOutputFormatVertical(FormatFactory & factory); void registerOutputFormatJSON(FormatFactory & factory); -void registerOutputFormatJSONCompact(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatODBCDriver(FormatFactory & factory); void registerOutputFormatODBCDriver2(FormatFactory & factory); @@ -308,7 +307,6 @@ FormatFactory::FormatFactory() registerOutputFormatPrettySpace(*this); registerOutputFormatVertical(*this); registerOutputFormatJSON(*this); - registerOutputFormatJSONCompact(*this); registerOutputFormatXML(*this); registerOutputFormatODBCDriver(*this); registerOutputFormatODBCDriver2(*this); diff --git a/dbms/src/Formats/JSONCompactRowOutputStream.cpp b/dbms/src/Formats/JSONCompactRowOutputStream.cpp deleted file mode 100644 index b9d54604c51..00000000000 --- a/dbms/src/Formats/JSONCompactRowOutputStream.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include - -#include - - -namespace DB -{ - -JSONCompactRowOutputStream::JSONCompactRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & settings_) - : JSONRowOutputStream(ostr_, sample_, settings_) -{ -} - - -void JSONCompactRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - type.serializeAsTextJSON(column, row_num, *ostr, settings); - ++field_number; -} - - -void JSONCompactRowOutputStream::writeFieldDelimiter() -{ - writeCString(", ", *ostr); -} - - -void JSONCompactRowOutputStream::writeRowStartDelimiter() -{ - if (row_count > 0) - writeCString(",\n", *ostr); - writeCString("\t\t[", *ostr); -} - - -void JSONCompactRowOutputStream::writeRowEndDelimiter() -{ - writeChar(']', *ostr); - field_number = 0; - ++row_count; -} - - -void JSONCompactRowOutputStream::writeTotals() -{ - if (totals) - { - writeCString(",\n", *ostr); - writeChar('\n', *ostr); - writeCString("\t\"totals\": [", *ostr); - - size_t totals_columns = totals.columns(); - for (size_t i = 0; i < totals_columns; ++i) - { - if (i != 0) - writeChar(',', *ostr); - - const ColumnWithTypeAndName & column = totals.safeGetByPosition(i); - column.type->serializeAsTextJSON(*column.column.get(), 0, *ostr, settings); - } - - writeChar(']', *ostr); - } -} - - -static void writeExtremesElement(const char * title, const Block & extremes, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) -{ - writeCString("\t\t\"", ostr); - writeCString(title, ostr); - writeCString("\": [", ostr); - - size_t extremes_columns = extremes.columns(); - for (size_t i = 0; i < extremes_columns; ++i) - { - if (i != 0) - writeChar(',', ostr); - - const ColumnWithTypeAndName & column = extremes.safeGetByPosition(i); - column.type->serializeAsTextJSON(*column.column.get(), row_num, ostr, settings); - } - - writeChar(']', ostr); -} - -void JSONCompactRowOutputStream::writeExtremes() -{ - if (extremes) - { - writeCString(",\n", *ostr); - writeChar('\n', *ostr); - writeCString("\t\"extremes\":\n", *ostr); - writeCString("\t{\n", *ostr); - - writeExtremesElement("min", extremes, 0, *ostr, settings); - writeCString(",\n", *ostr); - writeExtremesElement("max", extremes, 1, *ostr, settings); - - writeChar('\n', *ostr); - writeCString("\t}", *ostr); - } -} - - -void registerOutputFormatJSONCompact(FormatFactory & factory) -{ - factory.registerOutputFormat("JSONCompact", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared( - std::make_shared(buf, sample, format_settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/JSONCompactRowOutputStream.h b/dbms/src/Formats/JSONCompactRowOutputStream.h deleted file mode 100644 index 726e0d4acaa..00000000000 --- a/dbms/src/Formats/JSONCompactRowOutputStream.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include -#include -#include - - -namespace DB -{ - -struct FormatSettings; - -/** The stream for outputting data in the JSONCompact format. - */ -class JSONCompactRowOutputStream : public JSONRowOutputStream -{ -public: - JSONCompactRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeFieldDelimiter() override; - void writeRowStartDelimiter() override; - void writeRowEndDelimiter() override; - -protected: - void writeTotals() override; - void writeExtremes() override; -}; - -} From ae50ab69073211a408978833ab40a5875ea19fe1 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:36:36 +0300 Subject: [PATCH 041/105] Remove JSONEachRowRowInputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - .../src/Formats/JSONEachRowRowInputStream.cpp | 272 ------------------ dbms/src/Formats/JSONEachRowRowInputStream.h | 68 ----- .../Formats/Impl/JSONEachRowRowInputFormat.h | 2 +- 4 files changed, 1 insertion(+), 343 deletions(-) delete mode 100644 dbms/src/Formats/JSONEachRowRowInputStream.cpp delete mode 100644 dbms/src/Formats/JSONEachRowRowInputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 0448e45a444..d49c630cd82 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -207,7 +207,6 @@ void registerInputFormatCSV(FormatFactory & factory); void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); -void registerInputFormatJSONEachRow(FormatFactory & factory); void registerOutputFormatJSONEachRow(FormatFactory & factory); void registerInputFormatParquet(FormatFactory & factory); void registerOutputFormatParquet(FormatFactory & factory); @@ -273,7 +272,6 @@ FormatFactory::FormatFactory() registerOutputFormatCSV(*this); registerInputFormatTSKV(*this); registerOutputFormatTSKV(*this); - registerInputFormatJSONEachRow(*this); registerOutputFormatJSONEachRow(*this); registerInputFormatProtobuf(*this); registerOutputFormatProtobuf(*this); diff --git a/dbms/src/Formats/JSONEachRowRowInputStream.cpp b/dbms/src/Formats/JSONEachRowRowInputStream.cpp deleted file mode 100644 index 72acf722ae7..00000000000 --- a/dbms/src/Formats/JSONEachRowRowInputStream.cpp +++ /dev/null @@ -1,272 +0,0 @@ -#include - -#include -#include -#include -#include - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int INCORRECT_DATA; - extern const int CANNOT_READ_ALL_DATA; - extern const int LOGICAL_ERROR; -} - -namespace -{ - -enum -{ - UNKNOWN_FIELD = size_t(-1), - NESTED_FIELD = size_t(-2) -}; - -} - - -JSONEachRowRowInputStream::JSONEachRowRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSettings & format_settings) - : istr(istr_), header(header_), format_settings(format_settings), name_map(header.columns()) -{ - /// In this format, BOM at beginning of stream cannot be confused with value, so it is safe to skip it. - skipBOMIfExists(istr); - - size_t num_columns = header.columns(); - for (size_t i = 0; i < num_columns; ++i) - { - const String & colname = columnName(i); - name_map[colname] = i; /// NOTE You could place names more cache-locally. - if (format_settings.import_nested_json) - { - const auto splitted = Nested::splitName(colname); - if (!splitted.second.empty()) - { - const StringRef table_name(colname.data(), splitted.first.size()); - name_map[table_name] = NESTED_FIELD; - } - } - } - - prev_positions.assign(num_columns, name_map.end()); -} - -const String & JSONEachRowRowInputStream::columnName(size_t i) const -{ - return header.getByPosition(i).name; -} - -inline size_t JSONEachRowRowInputStream::columnIndex(const StringRef & name, size_t key_index) -{ - /// Optimization by caching the order of fields (which is almost always the same) - /// and a quick check to match the next expected field, instead of searching the hash table. - - if (prev_positions.size() > key_index - && prev_positions[key_index] != name_map.end() - && name == prev_positions[key_index]->getFirst()) - { - return prev_positions[key_index]->getSecond(); - } - else - { - const auto it = name_map.find(name); - - if (name_map.end() != it) - { - if (key_index < prev_positions.size()) - prev_positions[key_index] = it; - - return it->getSecond(); - } - else - return UNKNOWN_FIELD; - } -} - -/** Read the field name and convert it to column name - * (taking into account the current nested name prefix) - * Resulting StringRef is valid only before next read from buf. - */ -StringRef JSONEachRowRowInputStream::readColumnName(ReadBuffer & buf) -{ - // This is just an optimization: try to avoid copying the name into current_column_name - - if (nested_prefix_length == 0 && buf.position() + 1 < buf.buffer().end()) - { - char * next_pos = find_first_symbols<'\\', '"'>(buf.position() + 1, buf.buffer().end()); - - if (next_pos != buf.buffer().end() && *next_pos != '\\') - { - /// The most likely option is that there is no escape sequence in the key name, and the entire name is placed in the buffer. - assertChar('"', buf); - StringRef res(buf.position(), next_pos - buf.position()); - buf.position() = next_pos + 1; - return res; - } - } - - current_column_name.resize(nested_prefix_length); - readJSONStringInto(current_column_name, buf); - return current_column_name; -} - - -static inline void skipColonDelimeter(ReadBuffer & istr) -{ - skipWhitespaceIfAny(istr); - assertChar(':', istr); - skipWhitespaceIfAny(istr); -} - -void JSONEachRowRowInputStream::skipUnknownField(const StringRef & name_ref) -{ - if (!format_settings.skip_unknown_fields) - throw Exception("Unknown field found while parsing JSONEachRow format: " + name_ref.toString(), ErrorCodes::INCORRECT_DATA); - - skipJSONField(istr, name_ref); -} - -void JSONEachRowRowInputStream::readField(size_t index, MutableColumns & columns) -{ - if (read_columns[index]) - throw Exception("Duplicate field found while parsing JSONEachRow format: " + columnName(index), ErrorCodes::INCORRECT_DATA); - - try - { - header.getByPosition(index).type->deserializeAsTextJSON(*columns[index], istr, format_settings); - } - catch (Exception & e) - { - e.addMessage("(while read the value of key " + columnName(index) + ")"); - throw; - } - - read_columns[index] = true; -} - -inline bool JSONEachRowRowInputStream::advanceToNextKey(size_t key_index) -{ - skipWhitespaceIfAny(istr); - - if (istr.eof()) - throw Exception("Unexpected end of stream while parsing JSONEachRow format", ErrorCodes::CANNOT_READ_ALL_DATA); - else if (*istr.position() == '}') - { - ++istr.position(); - return false; - } - - if (key_index > 0) - { - assertChar(',', istr); - skipWhitespaceIfAny(istr); - } - return true; -} - -void JSONEachRowRowInputStream::readJSONObject(MutableColumns & columns) -{ - assertChar('{', istr); - - for (size_t key_index = 0; advanceToNextKey(key_index); ++key_index) - { - StringRef name_ref = readColumnName(istr); - const size_t column_index = columnIndex(name_ref, key_index); - - if (unlikely(ssize_t(column_index) < 0)) - { - /// name_ref may point directly to the input buffer - /// and input buffer may be filled with new data on next read - /// If we want to use name_ref after another reads from buffer, we must copy it to temporary string. - - current_column_name.assign(name_ref.data, name_ref.size); - name_ref = StringRef(current_column_name); - - skipColonDelimeter(istr); - - if (column_index == UNKNOWN_FIELD) - skipUnknownField(name_ref); - else if (column_index == NESTED_FIELD) - readNestedData(name_ref.toString(), columns); - else - throw Exception("Logical error: illegal value of column_index", ErrorCodes::LOGICAL_ERROR); - } - else - { - skipColonDelimeter(istr); - readField(column_index, columns); - } - } -} - -void JSONEachRowRowInputStream::readNestedData(const String & name, MutableColumns & columns) -{ - current_column_name = name; - current_column_name.push_back('.'); - nested_prefix_length = current_column_name.size(); - readJSONObject(columns); - nested_prefix_length = 0; -} - - -bool JSONEachRowRowInputStream::read(MutableColumns & columns, RowReadExtension & ext) -{ - skipWhitespaceIfAny(istr); - - /// We consume ;, or \n before scanning a new row, instead scanning to next row at the end. - /// The reason is that if we want an exact number of rows read with LIMIT x - /// from a streaming table engine with text data format, like File or Kafka - /// then seeking to next ;, or \n would trigger reading of an extra row at the end. - - /// Semicolon is added for convenience as it could be used at end of INSERT query. - if (!istr.eof() && (*istr.position() == ',' || *istr.position() == ';')) - ++istr.position(); - - skipWhitespaceIfAny(istr); - if (istr.eof()) - return false; - - size_t num_columns = columns.size(); - - /// Set of columns for which the values were read. The rest will be filled with default values. - read_columns.assign(num_columns, false); - - nested_prefix_length = 0; - readJSONObject(columns); - - /// Fill non-visited columns with the default values. - for (size_t i = 0; i < num_columns; ++i) - if (!read_columns[i]) - header.getByPosition(i).type->insertDefaultInto(*columns[i]); - - /// return info about defaults set - ext.read_columns = read_columns; - return true; -} - - -void JSONEachRowRowInputStream::syncAfterError() -{ - skipToUnescapedNextLineOrEOF(istr); -} - - -void registerInputFormatJSONEachRow(FormatFactory & factory) -{ - factory.registerInputFormat("JSONEachRow", []( - ReadBuffer & buf, - const Block & sample, - const Context &, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, settings), - sample, max_block_size, rows_portion_size, callback, settings); - }); -} - -} diff --git a/dbms/src/Formats/JSONEachRowRowInputStream.h b/dbms/src/Formats/JSONEachRowRowInputStream.h deleted file mode 100644 index 726b63b084e..00000000000 --- a/dbms/src/Formats/JSONEachRowRowInputStream.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include -#include - - -namespace DB -{ - -class ReadBuffer; - - -/** A stream for reading data in JSON format, where each row is represented by a separate JSON object. - * Objects can be separated by line feed, other whitespace characters in any number and possibly a comma. - * Fields can be listed in any order (including, in different lines there may be different order), - * and some fields may be missing. - */ -class JSONEachRowRowInputStream : public IRowInputStream -{ -public: - JSONEachRowRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSettings & format_settings); - - bool read(MutableColumns & columns, RowReadExtension & ext) override; - bool allowSyncAfterError() const override { return true; } - void syncAfterError() override; - -private: - const String & columnName(size_t i) const; - size_t columnIndex(const StringRef & name, size_t key_index); - bool advanceToNextKey(size_t key_index); - void skipUnknownField(const StringRef & name_ref); - StringRef readColumnName(ReadBuffer & buf); - void readField(size_t index, MutableColumns & columns); - void readJSONObject(MutableColumns & columns); - void readNestedData(const String & name, MutableColumns & columns); - -private: - ReadBuffer & istr; - Block header; - - const FormatSettings format_settings; - - /// Buffer for the read from the stream field name. Used when you have to copy it. - /// Also, if processing of Nested data is in progress, it holds the common prefix - /// of the nested column names (so that appending the field name to it produces - /// the full column name) - String current_column_name; - - /// If processing Nested data, holds the length of the common prefix - /// of the names of related nested columns. For example, for a table - /// created as follows - /// CREATE TABLE t (n Nested (i Int32, s String)) - /// the nested column names are 'n.i' and 'n.s' and the nested prefix is 'n.' - size_t nested_prefix_length = 0; - - std::vector read_columns; - - /// Hash table match `field name -> position in the block`. NOTE You can use perfect hash map. - using NameMap = HashMap; - NameMap name_map; - - /// Cached search results for previous row (keyed as index in JSON object) - used as a hint. - std::vector prev_positions; -}; - -} diff --git a/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.h b/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.h index 901e35af6e8..1aed7c9dc49 100644 --- a/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/JSONEachRowRowInputFormat.h @@ -13,7 +13,7 @@ class ReadBuffer; /** A stream for reading data in JSON format, where each row is represented by a separate JSON object. - * Objects can be separated by feed return, other whitespace characters in any number and possibly a comma. + * Objects can be separated by line feed, other whitespace characters in any number and possibly a comma. * Fields can be listed in any order (including, in different lines there may be different order), * and some fields may be missing. */ From ce712d881ab80eaaa9401088dd2c449bf53f4fd0 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:39:12 +0300 Subject: [PATCH 042/105] Remove JSONEachRowRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - .../Formats/JSONEachRowRowOutputStream.cpp | 67 ------------------- dbms/src/Formats/JSONEachRowRowOutputStream.h | 39 ----------- 3 files changed, 108 deletions(-) delete mode 100644 dbms/src/Formats/JSONEachRowRowOutputStream.cpp delete mode 100644 dbms/src/Formats/JSONEachRowRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index d49c630cd82..85b215aac33 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -207,7 +207,6 @@ void registerInputFormatCSV(FormatFactory & factory); void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); -void registerOutputFormatJSONEachRow(FormatFactory & factory); void registerInputFormatParquet(FormatFactory & factory); void registerOutputFormatParquet(FormatFactory & factory); void registerInputFormatProtobuf(FormatFactory & factory); @@ -272,7 +271,6 @@ FormatFactory::FormatFactory() registerOutputFormatCSV(*this); registerInputFormatTSKV(*this); registerOutputFormatTSKV(*this); - registerOutputFormatJSONEachRow(*this); registerInputFormatProtobuf(*this); registerOutputFormatProtobuf(*this); registerInputFormatParquet(*this); diff --git a/dbms/src/Formats/JSONEachRowRowOutputStream.cpp b/dbms/src/Formats/JSONEachRowRowOutputStream.cpp deleted file mode 100644 index 6850060dbfb..00000000000 --- a/dbms/src/Formats/JSONEachRowRowOutputStream.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace DB -{ - - -JSONEachRowRowOutputStream::JSONEachRowRowOutputStream(WriteBuffer & ostr_, const Block & sample, const FormatSettings & settings) - : ostr(ostr_), settings(settings) -{ - size_t columns = sample.columns(); - fields.resize(columns); - - for (size_t i = 0; i < columns; ++i) - { - WriteBufferFromString out(fields[i]); - writeJSONString(sample.getByPosition(i).name, out, settings); - } -} - - -void JSONEachRowRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - writeString(fields[field_number], ostr); - writeChar(':', ostr); - type.serializeAsTextJSON(column, row_num, ostr, settings); - ++field_number; -} - - -void JSONEachRowRowOutputStream::writeFieldDelimiter() -{ - writeChar(',', ostr); -} - - -void JSONEachRowRowOutputStream::writeRowStartDelimiter() -{ - writeChar('{', ostr); -} - - -void JSONEachRowRowOutputStream::writeRowEndDelimiter() -{ - writeCString("}\n", ostr); - field_number = 0; -} - - -void registerOutputFormatJSONEachRow(FormatFactory & factory) -{ - factory.registerOutputFormat("JSONEachRow", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared( - std::make_shared(buf, sample, format_settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/JSONEachRowRowOutputStream.h b/dbms/src/Formats/JSONEachRowRowOutputStream.h deleted file mode 100644 index 4f2dc690aed..00000000000 --- a/dbms/src/Formats/JSONEachRowRowOutputStream.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include - - -namespace DB -{ - -/** The stream for outputting data in JSON format, by object per line. - * Does not validate UTF-8. - */ -class JSONEachRowRowOutputStream : public IRowOutputStream -{ -public: - JSONEachRowRowOutputStream(WriteBuffer & ostr_, const Block & sample, const FormatSettings & settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeFieldDelimiter() override; - void writeRowStartDelimiter() override; - void writeRowEndDelimiter() override; - - void flush() override - { - ostr.next(); - } - -private: - WriteBuffer & ostr; - size_t field_number = 0; - Names fields; - - FormatSettings settings; -}; - -} - From 4019f5e102bfd314406d4566185c5dad5d399748 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:42:33 +0300 Subject: [PATCH 043/105] Remove JSONRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/JSONRowOutputStream.cpp | 246 ----------------------- dbms/src/Formats/JSONRowOutputStream.h | 74 ------- 3 files changed, 322 deletions(-) delete mode 100644 dbms/src/Formats/JSONRowOutputStream.cpp delete mode 100644 dbms/src/Formats/JSONRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 85b215aac33..f7e00693f9b 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -237,7 +237,6 @@ void registerOutputFormatPretty(FormatFactory & factory); void registerOutputFormatPrettyCompact(FormatFactory & factory); void registerOutputFormatPrettySpace(FormatFactory & factory); void registerOutputFormatVertical(FormatFactory & factory); -void registerOutputFormatJSON(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatODBCDriver(FormatFactory & factory); void registerOutputFormatODBCDriver2(FormatFactory & factory); @@ -302,7 +301,6 @@ FormatFactory::FormatFactory() registerOutputFormatPrettyCompact(*this); registerOutputFormatPrettySpace(*this); registerOutputFormatVertical(*this); - registerOutputFormatJSON(*this); registerOutputFormatXML(*this); registerOutputFormatODBCDriver(*this); registerOutputFormatODBCDriver2(*this); diff --git a/dbms/src/Formats/JSONRowOutputStream.cpp b/dbms/src/Formats/JSONRowOutputStream.cpp deleted file mode 100644 index f008e83899a..00000000000 --- a/dbms/src/Formats/JSONRowOutputStream.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace DB -{ - -JSONRowOutputStream::JSONRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & settings) - : dst_ostr(ostr_), settings(settings) -{ - NamesAndTypesList columns(sample_.getNamesAndTypesList()); - fields.assign(columns.begin(), columns.end()); - - bool need_validate_utf8 = false; - for (size_t i = 0; i < sample_.columns(); ++i) - { - if (!sample_.getByPosition(i).type->textCanContainOnlyValidUTF8()) - need_validate_utf8 = true; - - WriteBufferFromOwnString out; - writeJSONString(fields[i].name, out, settings); - - fields[i].name = out.str(); - } - - if (need_validate_utf8) - { - validating_ostr = std::make_unique(dst_ostr); - ostr = validating_ostr.get(); - } - else - ostr = &dst_ostr; -} - - -void JSONRowOutputStream::writePrefix() -{ - writeCString("{\n", *ostr); - writeCString("\t\"meta\":\n", *ostr); - writeCString("\t[\n", *ostr); - - for (size_t i = 0; i < fields.size(); ++i) - { - writeCString("\t\t{\n", *ostr); - - writeCString("\t\t\t\"name\": ", *ostr); - writeString(fields[i].name, *ostr); - writeCString(",\n", *ostr); - writeCString("\t\t\t\"type\": ", *ostr); - writeJSONString(fields[i].type->getName(), *ostr, settings); - writeChar('\n', *ostr); - - writeCString("\t\t}", *ostr); - if (i + 1 < fields.size()) - writeChar(',', *ostr); - writeChar('\n', *ostr); - } - - writeCString("\t],\n", *ostr); - writeChar('\n', *ostr); - writeCString("\t\"data\":\n", *ostr); - writeCString("\t[\n", *ostr); -} - - -void JSONRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - writeCString("\t\t\t", *ostr); - writeString(fields[field_number].name, *ostr); - writeCString(": ", *ostr); - type.serializeAsTextJSON(column, row_num, *ostr, settings); - ++field_number; -} - - -void JSONRowOutputStream::writeFieldDelimiter() -{ - writeCString(",\n", *ostr); -} - - -void JSONRowOutputStream::writeRowStartDelimiter() -{ - if (row_count > 0) - writeCString(",\n", *ostr); - writeCString("\t\t{\n", *ostr); -} - - -void JSONRowOutputStream::writeRowEndDelimiter() -{ - writeChar('\n', *ostr); - writeCString("\t\t}", *ostr); - field_number = 0; - ++row_count; -} - - -void JSONRowOutputStream::writeSuffix() -{ - writeChar('\n', *ostr); - writeCString("\t]", *ostr); - - writeTotals(); - writeExtremes(); - - writeCString(",\n\n", *ostr); - writeCString("\t\"rows\": ", *ostr); - writeIntText(row_count, *ostr); - - writeRowsBeforeLimitAtLeast(); - - if (settings.write_statistics) - writeStatistics(); - - writeChar('\n', *ostr); - writeCString("}\n", *ostr); - ostr->next(); -} - -void JSONRowOutputStream::writeRowsBeforeLimitAtLeast() -{ - if (applied_limit) - { - writeCString(",\n\n", *ostr); - writeCString("\t\"rows_before_limit_at_least\": ", *ostr); - writeIntText(rows_before_limit, *ostr); - } -} - -void JSONRowOutputStream::writeTotals() -{ - if (totals) - { - writeCString(",\n", *ostr); - writeChar('\n', *ostr); - writeCString("\t\"totals\":\n", *ostr); - writeCString("\t{\n", *ostr); - - size_t totals_columns = totals.columns(); - for (size_t i = 0; i < totals_columns; ++i) - { - const ColumnWithTypeAndName & column = totals.safeGetByPosition(i); - - if (i != 0) - writeCString(",\n", *ostr); - - writeCString("\t\t", *ostr); - writeJSONString(column.name, *ostr, settings); - writeCString(": ", *ostr); - column.type->serializeAsTextJSON(*column.column.get(), 0, *ostr, settings); - } - - writeChar('\n', *ostr); - writeCString("\t}", *ostr); - } -} - - -static void writeExtremesElement(const char * title, const Block & extremes, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) -{ - writeCString("\t\t\"", ostr); - writeCString(title, ostr); - writeCString("\":\n", ostr); - writeCString("\t\t{\n", ostr); - - size_t extremes_columns = extremes.columns(); - for (size_t i = 0; i < extremes_columns; ++i) - { - const ColumnWithTypeAndName & column = extremes.safeGetByPosition(i); - - if (i != 0) - writeCString(",\n", ostr); - - writeCString("\t\t\t", ostr); - writeJSONString(column.name, ostr, settings); - writeCString(": ", ostr); - column.type->serializeAsTextJSON(*column.column.get(), row_num, ostr, settings); - } - - writeChar('\n', ostr); - writeCString("\t\t}", ostr); -} - -void JSONRowOutputStream::writeExtremes() -{ - if (extremes) - { - writeCString(",\n", *ostr); - writeChar('\n', *ostr); - writeCString("\t\"extremes\":\n", *ostr); - writeCString("\t{\n", *ostr); - - writeExtremesElement("min", extremes, 0, *ostr, settings); - writeCString(",\n", *ostr); - writeExtremesElement("max", extremes, 1, *ostr, settings); - - writeChar('\n', *ostr); - writeCString("\t}", *ostr); - } -} - - -void JSONRowOutputStream::onProgress(const Progress & value) -{ - progress.incrementPiecewiseAtomically(value); -} - - -void JSONRowOutputStream::writeStatistics() -{ - writeCString(",\n\n", *ostr); - writeCString("\t\"statistics\":\n", *ostr); - writeCString("\t{\n", *ostr); - - writeCString("\t\t\"elapsed\": ", *ostr); - writeText(watch.elapsedSeconds(), *ostr); - writeCString(",\n", *ostr); - writeCString("\t\t\"rows_read\": ", *ostr); - writeText(progress.read_rows.load(), *ostr); - writeCString(",\n", *ostr); - writeCString("\t\t\"bytes_read\": ", *ostr); - writeText(progress.read_bytes.load(), *ostr); - writeChar('\n', *ostr); - - writeCString("\t}", *ostr); -} - - -void registerOutputFormatJSON(FormatFactory & factory) -{ - factory.registerOutputFormat("JSON", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared( - std::make_shared(buf, sample, format_settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/JSONRowOutputStream.h b/dbms/src/Formats/JSONRowOutputStream.h deleted file mode 100644 index 99f94762bcc..00000000000 --- a/dbms/src/Formats/JSONRowOutputStream.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -/** Stream for output data in JSON format. - */ -class JSONRowOutputStream : public IRowOutputStream -{ -public: - JSONRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeFieldDelimiter() override; - void writeRowStartDelimiter() override; - void writeRowEndDelimiter() override; - void writePrefix() override; - void writeSuffix() override; - - void flush() override - { - ostr->next(); - - if (validating_ostr) - dst_ostr.next(); - } - - void setRowsBeforeLimit(size_t rows_before_limit_) override - { - applied_limit = true; - rows_before_limit = rows_before_limit_; - } - - void setTotals(const Block & totals_) override { totals = totals_; } - void setExtremes(const Block & extremes_) override { extremes = extremes_; } - - void onProgress(const Progress & value) override; - - String getContentType() const override { return "application/json; charset=UTF-8"; } - -protected: - - void writeRowsBeforeLimitAtLeast(); - virtual void writeTotals(); - virtual void writeExtremes(); - void writeStatistics(); - - WriteBuffer & dst_ostr; - std::unique_ptr validating_ostr; /// Validates UTF-8 sequences, replaces bad sequences with replacement character. - WriteBuffer * ostr; - - size_t field_number = 0; - size_t row_count = 0; - bool applied_limit = false; - size_t rows_before_limit = 0; - NamesAndTypes fields; - Block totals; - Block extremes; - - Progress progress; - Stopwatch watch; - FormatSettings settings; -}; - -} - From d57d8a609f7f13712628e59bc1b4bbbaca57e356 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:45:21 +0300 Subject: [PATCH 044/105] Remove MySQLWireBlockOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 3 - .../Formats/MySQLWireBlockOutputStream.cpp | 85 ------------------- dbms/src/Formats/MySQLWireBlockOutputStream.h | 36 -------- dbms/src/Formats/MySQLWireFormat.cpp | 19 ----- 4 files changed, 143 deletions(-) delete mode 100644 dbms/src/Formats/MySQLWireBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/MySQLWireBlockOutputStream.h delete mode 100644 dbms/src/Formats/MySQLWireFormat.cpp diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index f7e00693f9b..4a51e6e1189 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -241,7 +241,6 @@ void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatODBCDriver(FormatFactory & factory); void registerOutputFormatODBCDriver2(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); -void registerOutputFormatMySQLWire(FormatFactory & factory); void registerOutputFormatProcessorPretty(FormatFactory & factory); void registerOutputFormatProcessorPrettyCompact(FormatFactory & factory); @@ -275,8 +274,6 @@ FormatFactory::FormatFactory() registerInputFormatParquet(*this); registerOutputFormatParquet(*this); - registerOutputFormatMySQLWire(*this); - registerInputFormatProcessorNative(*this); registerOutputFormatProcessorNative(*this); registerInputFormatProcessorRowBinary(*this); diff --git a/dbms/src/Formats/MySQLWireBlockOutputStream.cpp b/dbms/src/Formats/MySQLWireBlockOutputStream.cpp deleted file mode 100644 index f032d5b84d4..00000000000 --- a/dbms/src/Formats/MySQLWireBlockOutputStream.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "MySQLWireBlockOutputStream.h" -#include -#include -#include -#include - -namespace DB -{ - -using namespace MySQLProtocol; - -MySQLWireBlockOutputStream::MySQLWireBlockOutputStream(WriteBuffer & buf, const Block & header, Context & context) - : header(header) - , context(context) - , packet_sender(buf, context.mysql.sequence_id) -{ - packet_sender.max_packet_size = context.mysql.max_packet_size; -} - -void MySQLWireBlockOutputStream::writePrefix() -{ - if (header.columns() == 0) - return; - - packet_sender.sendPacket(LengthEncodedNumber(header.columns())); - - for (const ColumnWithTypeAndName & column : header.getColumnsWithTypeAndName()) - { - ColumnDefinition column_definition(column.name, CharacterSet::binary, 0, ColumnType::MYSQL_TYPE_STRING, 0, 0); - packet_sender.sendPacket(column_definition); - } - - if (!(context.mysql.client_capabilities & Capability::CLIENT_DEPRECATE_EOF)) - { - packet_sender.sendPacket(EOF_Packet(0, 0)); - } -} - -void MySQLWireBlockOutputStream::write(const Block & block) -{ - size_t rows = block.rows(); - - for (size_t i = 0; i < rows; i++) - { - ResultsetRow row_packet; - for (const ColumnWithTypeAndName & column : block) - { - WriteBufferFromOwnString ostr; - column.type->serializeAsText(*column.column.get(), i, ostr, format_settings); - row_packet.appendColumn(std::move(ostr.str())); - } - packet_sender.sendPacket(row_packet); - } -} - -void MySQLWireBlockOutputStream::writeSuffix() -{ - size_t affected_rows = 0; - std::stringstream human_readable_info; - if (QueryStatus * process_list_elem = context.getProcessListElement()) - { - CurrentThread::finalizePerformanceCounters(); - QueryStatusInfo info = process_list_elem->getInfo(); - affected_rows = info.written_rows; - human_readable_info << std::fixed << std::setprecision(3) - << "Read " << info.read_rows << " rows, " << formatReadableSizeWithBinarySuffix(info.read_bytes) << " in " << info.elapsed_seconds << " sec., " - << static_cast(info.read_rows / info.elapsed_seconds) << " rows/sec., " - << formatReadableSizeWithBinarySuffix(info.read_bytes / info.elapsed_seconds) << "/sec."; - } - - if (header.columns() == 0) - packet_sender.sendPacket(OK_Packet(0x0, context.mysql.client_capabilities, affected_rows, 0, 0, "", human_readable_info.str()), true); - else - if (context.mysql.client_capabilities & CLIENT_DEPRECATE_EOF) - packet_sender.sendPacket(OK_Packet(0xfe, context.mysql.client_capabilities, affected_rows, 0, 0, "", human_readable_info.str()), true); - else - packet_sender.sendPacket(EOF_Packet(0, 0), true); -} - -void MySQLWireBlockOutputStream::flush() -{ - packet_sender.out->next(); -} - -} diff --git a/dbms/src/Formats/MySQLWireBlockOutputStream.h b/dbms/src/Formats/MySQLWireBlockOutputStream.h deleted file mode 100644 index f54bc83eabc..00000000000 --- a/dbms/src/Formats/MySQLWireBlockOutputStream.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace DB -{ - -/** Interface for writing rows in MySQL Client/Server Protocol format. - */ -class MySQLWireBlockOutputStream : public IBlockOutputStream -{ -public: - MySQLWireBlockOutputStream(WriteBuffer & buf, const Block & header, Context & context); - - Block getHeader() const { return header; } - - void write(const Block & block); - - void writePrefix(); - void writeSuffix(); - - void flush(); -private: - Block header; - Context & context; - MySQLProtocol::PacketSender packet_sender; - FormatSettings format_settings; -}; - -using MySQLWireBlockOutputStreamPtr = std::shared_ptr; - -} diff --git a/dbms/src/Formats/MySQLWireFormat.cpp b/dbms/src/Formats/MySQLWireFormat.cpp deleted file mode 100644 index c0694cd5a54..00000000000 --- a/dbms/src/Formats/MySQLWireFormat.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - - -namespace DB -{ - -void registerOutputFormatMySQLWire(FormatFactory & factory) -{ - factory.registerOutputFormat("MySQLWire", []( - WriteBuffer & buf, - const Block & sample, - const Context & context, - const FormatSettings &) - { - return std::make_shared(buf, sample, const_cast(context)); - }); -} - -} From 51bd715781bbb551a9c7d20589e0ed3d756fd33a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:49:46 +0300 Subject: [PATCH 045/105] Remove ODBCDriver2BlockOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - .../Formats/ODBCDriver2BlockOutputStream.cpp | 103 ------------------ .../Formats/ODBCDriver2BlockOutputStream.h | 51 --------- 3 files changed, 156 deletions(-) delete mode 100644 dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp delete mode 100644 dbms/src/Formats/ODBCDriver2BlockOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 4a51e6e1189..9a18608d1d7 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -239,7 +239,6 @@ void registerOutputFormatPrettySpace(FormatFactory & factory); void registerOutputFormatVertical(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatODBCDriver(FormatFactory & factory); -void registerOutputFormatODBCDriver2(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); void registerOutputFormatProcessorPretty(FormatFactory & factory); @@ -300,7 +299,6 @@ FormatFactory::FormatFactory() registerOutputFormatVertical(*this); registerOutputFormatXML(*this); registerOutputFormatODBCDriver(*this); - registerOutputFormatODBCDriver2(*this); registerOutputFormatNull(*this); registerOutputFormatProcessorPretty(*this); diff --git a/dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp b/dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp deleted file mode 100644 index 8e9dbfdd5c2..00000000000 --- a/dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace DB -{ -ODBCDriver2BlockOutputStream::ODBCDriver2BlockOutputStream( - WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings) - : out(out_), header(header_), format_settings(format_settings) -{ -} - -void ODBCDriver2BlockOutputStream::flush() -{ - out.next(); -} - -void writeODBCString(WriteBuffer & out, const std::string & str) -{ - writeIntBinary(Int32(str.size()), out); - out.write(str.data(), str.size()); -} - -static void writeRow(const Block & block, size_t row_idx, WriteBuffer & out, const FormatSettings & format_settings, std::string & buffer) -{ - size_t columns = block.columns(); - for (size_t column_idx = 0; column_idx < columns; ++column_idx) - { - buffer.clear(); - const ColumnWithTypeAndName & col = block.getByPosition(column_idx); - - if (col.column->isNullAt(row_idx)) - { - writeIntBinary(Int32(-1), out); - } - else - { - { - WriteBufferFromString text_out(buffer); - col.type->serializeAsText(*col.column, row_idx, text_out, format_settings); - } - writeODBCString(out, buffer); - } - } -} - -void ODBCDriver2BlockOutputStream::write(const Block & block) -{ - String text_value; - const size_t rows = block.rows(); - for (size_t i = 0; i < rows; ++i) - writeRow(block, i, out, format_settings, text_value); -} - -void ODBCDriver2BlockOutputStream::writeSuffix() -{ - if (totals) - write(totals); -} - -void ODBCDriver2BlockOutputStream::writePrefix() -{ - const size_t columns = header.columns(); - - /// Number of header rows. - writeIntBinary(Int32(2), out); - - /// Names of columns. - /// Number of columns + 1 for first name column. - writeIntBinary(Int32(columns + 1), out); - writeODBCString(out, "name"); - for (size_t i = 0; i < columns; ++i) - { - const ColumnWithTypeAndName & col = header.getByPosition(i); - writeODBCString(out, col.name); - } - - /// Types of columns. - writeIntBinary(Int32(columns + 1), out); - writeODBCString(out, "type"); - for (size_t i = 0; i < columns; ++i) - { - auto type = header.getByPosition(i).type; - if (type->lowCardinality()) - type = recursiveRemoveLowCardinality(type); - writeODBCString(out, type->getName()); - } -} - - -void registerOutputFormatODBCDriver2(FormatFactory & factory) -{ - factory.registerOutputFormat( - "ODBCDriver2", [](WriteBuffer & buf, const Block & sample, const Context &, const FormatSettings & format_settings) - { - return std::make_shared(buf, sample, format_settings); - }); -} - -} diff --git a/dbms/src/Formats/ODBCDriver2BlockOutputStream.h b/dbms/src/Formats/ODBCDriver2BlockOutputStream.h deleted file mode 100644 index 096204e5b94..00000000000 --- a/dbms/src/Formats/ODBCDriver2BlockOutputStream.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include -#include - - -namespace DB -{ -class WriteBuffer; - - -/** A data format designed to simplify the implementation of the ODBC driver. - * ODBC driver is designed to be build for different platforms without dependencies from the main code, - * so the format is made that way so that it can be as easy as possible to parse it. - * A header is displayed with the required information. - * The data is then output in the order of the rows. Each value is displayed as follows: length in Int32 format (-1 for NULL), then data in text form. - */ -class ODBCDriver2BlockOutputStream final : public IBlockOutputStream -{ -public: - ODBCDriver2BlockOutputStream(WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings); - - Block getHeader() const override - { - return header; - } - void write(const Block & block) override; - void writePrefix() override; - void writeSuffix() override; - - void flush() override; - std::string getContentType() const override - { - return "application/octet-stream"; - } - void setTotals(const Block & totals_) override { totals = totals_; } - -private: - WriteBuffer & out; - const Block header; - const FormatSettings format_settings; - -protected: - Block totals; -}; - - - -} From 978bdc4bfc197a81d0a877ac61d812d9eb7a1962 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 18:51:27 +0300 Subject: [PATCH 046/105] Remove ODBCDriverBlockOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - .../Formats/ODBCDriverBlockOutputStream.cpp | 74 ------------------- .../src/Formats/ODBCDriverBlockOutputStream.h | 39 ---------- 3 files changed, 115 deletions(-) delete mode 100644 dbms/src/Formats/ODBCDriverBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/ODBCDriverBlockOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 9a18608d1d7..7094f1280fc 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -238,7 +238,6 @@ void registerOutputFormatPrettyCompact(FormatFactory & factory); void registerOutputFormatPrettySpace(FormatFactory & factory); void registerOutputFormatVertical(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); -void registerOutputFormatODBCDriver(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); void registerOutputFormatProcessorPretty(FormatFactory & factory); @@ -298,7 +297,6 @@ FormatFactory::FormatFactory() registerOutputFormatPrettySpace(*this); registerOutputFormatVertical(*this); registerOutputFormatXML(*this); - registerOutputFormatODBCDriver(*this); registerOutputFormatNull(*this); registerOutputFormatProcessorPretty(*this); diff --git a/dbms/src/Formats/ODBCDriverBlockOutputStream.cpp b/dbms/src/Formats/ODBCDriverBlockOutputStream.cpp deleted file mode 100644 index 3cd1ad3c1d6..00000000000 --- a/dbms/src/Formats/ODBCDriverBlockOutputStream.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace DB -{ - -ODBCDriverBlockOutputStream::ODBCDriverBlockOutputStream(WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings) - : out(out_), header(header_), format_settings(format_settings) -{ -} - -void ODBCDriverBlockOutputStream::flush() -{ - out.next(); -} - -void ODBCDriverBlockOutputStream::write(const Block & block) -{ - const size_t rows = block.rows(); - const size_t columns = block.columns(); - String text_value; - - for (size_t i = 0; i < rows; ++i) - { - for (size_t j = 0; j < columns; ++j) - { - text_value.resize(0); - const ColumnWithTypeAndName & col = block.getByPosition(j); - - { - WriteBufferFromString text_out(text_value); - col.type->serializeAsText(*col.column, i, text_out, format_settings); - } - - writeStringBinary(text_value, out); - } - } -} - -void ODBCDriverBlockOutputStream::writePrefix() -{ - const size_t columns = header.columns(); - - /// Number of columns. - writeVarUInt(columns, out); - - /// Names and types of columns. - for (size_t i = 0; i < columns; ++i) - { - const ColumnWithTypeAndName & col = header.getByPosition(i); - - writeStringBinary(col.name, out); - writeStringBinary(col.type->getName(), out); - } -} - - -void registerOutputFormatODBCDriver(FormatFactory & factory) -{ - factory.registerOutputFormat("ODBCDriver", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared(buf, sample, format_settings); - }); -} - -} diff --git a/dbms/src/Formats/ODBCDriverBlockOutputStream.h b/dbms/src/Formats/ODBCDriverBlockOutputStream.h deleted file mode 100644 index 7dbde1c5814..00000000000 --- a/dbms/src/Formats/ODBCDriverBlockOutputStream.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include - - -namespace DB -{ - -class WriteBuffer; - - -/** A data format designed to simplify the implementation of the ODBC driver. - * ODBC driver is designed to be build for different platforms without dependencies from the main code, - * so the format is made that way so that it can be as easy as possible to parse it. - * A header is displayed with the required information. - * The data is then output in the order of the rows. Each value is displayed as follows: length in VarUInt format, then data in text form. - */ -class ODBCDriverBlockOutputStream : public IBlockOutputStream -{ -public: - ODBCDriverBlockOutputStream(WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings); - - Block getHeader() const override { return header; } - void write(const Block & block) override; - void writePrefix() override; - - void flush() override; - std::string getContentType() const override { return "application/octet-stream"; } - -private: - WriteBuffer & out; - const Block header; - const FormatSettings format_settings; -}; - -} From fcecbbda73ae5fed196f0712720e92f854bf7b45 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:00:24 +0300 Subject: [PATCH 047/105] Remove OParquetBlockInputStream --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/ParquetBlockInputStream.cpp | 495 ------------------ dbms/src/Formats/ParquetBlockInputStream.h | 43 -- .../Formats/Impl/ParquetBlockInputFormat.cpp | 8 +- .../Formats/Impl/ParquetBlockInputFormat.h | 8 +- 5 files changed, 4 insertions(+), 552 deletions(-) delete mode 100644 dbms/src/Formats/ParquetBlockInputStream.cpp delete mode 100644 dbms/src/Formats/ParquetBlockInputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 7094f1280fc..0d346027d49 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -207,7 +207,6 @@ void registerInputFormatCSV(FormatFactory & factory); void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); -void registerInputFormatParquet(FormatFactory & factory); void registerOutputFormatParquet(FormatFactory & factory); void registerInputFormatProtobuf(FormatFactory & factory); void registerOutputFormatProtobuf(FormatFactory & factory); @@ -269,7 +268,6 @@ FormatFactory::FormatFactory() registerOutputFormatTSKV(*this); registerInputFormatProtobuf(*this); registerOutputFormatProtobuf(*this); - registerInputFormatParquet(*this); registerOutputFormatParquet(*this); registerInputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/ParquetBlockInputStream.cpp b/dbms/src/Formats/ParquetBlockInputStream.cpp deleted file mode 100644 index deba953bab4..00000000000 --- a/dbms/src/Formats/ParquetBlockInputStream.cpp +++ /dev/null @@ -1,495 +0,0 @@ -#include "config_formats.h" -#if USE_PARQUET -# include "ParquetBlockInputStream.h" - -# include -# include -# include -// TODO: clear includes -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -namespace DB -{ -namespace ErrorCodes -{ - extern const int UNKNOWN_TYPE; - extern const int VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE; - extern const int CANNOT_READ_ALL_DATA; - extern const int EMPTY_DATA_PASSED; - extern const int SIZES_OF_COLUMNS_DOESNT_MATCH; - extern const int CANNOT_CONVERT_TYPE; - extern const int CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN; - extern const int THERE_IS_NO_COLUMN; -} - -ParquetBlockInputStream::ParquetBlockInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_) - : istr{istr_}, header{header_}, context{context_} -{ -} - -Block ParquetBlockInputStream::getHeader() const -{ - return header; -} - -/// Inserts numeric data right into internal column data to reduce an overhead -template > -void fillColumnWithNumericData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - std::shared_ptr chunk = arrow_column->data()->chunk(chunk_i); - /// buffers[0] is a null bitmap and buffers[1] are actual values - std::shared_ptr buffer = chunk->data()->buffers[1]; - - const auto * raw_data = reinterpret_cast(buffer->data()); - column_data.insert_assume_reserved(raw_data, raw_data + chunk->length()); - } -} - -/// Inserts chars and offsets right into internal column data to reduce an overhead. -/// Internal offsets are shifted by one to the right in comparison with Arrow ones. So the last offset should map to the end of all chars. -/// Also internal strings are null terminated. -void fillColumnWithStringData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - PaddedPODArray & column_chars_t = static_cast(*internal_column).getChars(); - PaddedPODArray & column_offsets = static_cast(*internal_column).getOffsets(); - - size_t chars_t_size = 0; - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::BinaryArray & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - const size_t chunk_length = chunk.length(); - - chars_t_size += chunk.value_offset(chunk_length - 1) + chunk.value_length(chunk_length - 1); - chars_t_size += chunk_length; /// additional space for null bytes - } - - column_chars_t.reserve(chars_t_size); - column_offsets.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::BinaryArray & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - std::shared_ptr buffer = chunk.value_data(); - const size_t chunk_length = chunk.length(); - - for (size_t offset_i = 0; offset_i != chunk_length; ++offset_i) - { - if (!chunk.IsNull(offset_i) && buffer) - { - const UInt8 * raw_data = buffer->data() + chunk.value_offset(offset_i); - column_chars_t.insert_assume_reserved(raw_data, raw_data + chunk.value_length(offset_i)); - } - column_chars_t.emplace_back('\0'); - - column_offsets.emplace_back(column_chars_t.size()); - } - } -} - -void fillColumnWithBooleanData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast &>(*internal_column).getData(); - column_data.resize(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::BooleanArray & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - /// buffers[0] is a null bitmap and buffers[1] are actual values - std::shared_ptr buffer = chunk.data()->buffers[1]; - - for (size_t bool_i = 0; bool_i != static_cast(chunk.length()); ++bool_i) - column_data[bool_i] = chunk.Value(bool_i); - } -} - -/// Arrow stores Parquet::DATE in Int32, while ClickHouse stores Date in UInt16. Therefore, it should be checked before saving -void fillColumnWithDate32Data(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - PaddedPODArray & column_data = static_cast &>(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::Date32Array & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - UInt32 days_num = static_cast(chunk.Value(value_i)); - if (days_num > DATE_LUT_MAX_DAY_NUM) - { - // TODO: will it rollback correctly? - throw Exception{"Input value " + std::to_string(days_num) + " of a column \"" + arrow_column->name() - + "\" is greater than " - "max allowed Date value, which is " - + std::to_string(DATE_LUT_MAX_DAY_NUM), - ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE}; - } - - column_data.emplace_back(days_num); - } - } -} - -/// Arrow stores Parquet::DATETIME in Int64, while ClickHouse stores DateTime in UInt32. Therefore, it should be checked before saving -void fillColumnWithDate64Data(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast &>(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - auto & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - auto timestamp = static_cast(chunk.Value(value_i) / 1000); // Always? in ms - column_data.emplace_back(timestamp); - } - } -} - -void fillColumnWithTimestampData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast &>(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - auto & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - const auto & type = static_cast(*chunk.type()); - - UInt32 divide = 1; - const auto unit = type.unit(); - switch (unit) - { - case arrow::TimeUnit::SECOND: - divide = 1; - break; - case arrow::TimeUnit::MILLI: - divide = 1000; - break; - case arrow::TimeUnit::MICRO: - divide = 1000000; - break; - case arrow::TimeUnit::NANO: - divide = 1000000000; - break; - } - - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - auto timestamp = static_cast(chunk.Value(value_i) / divide); // ms! TODO: check other 's' 'ns' ... - column_data.emplace_back(timestamp); - } - } -} - -void fillColumnWithDecimalData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column = static_cast &>(*internal_column); - auto & column_data = column.getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - auto & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - column_data.emplace_back( - chunk.IsNull(value_i) ? Decimal128(0) : *reinterpret_cast(chunk.Value(value_i))); // TODO: copy column - } - } -} - -/// Creates a null bytemap from arrow's null bitmap -void fillByteMapFromArrowColumn(std::shared_ptr & arrow_column, MutableColumnPtr & bytemap) -{ - PaddedPODArray & bytemap_data = static_cast &>(*bytemap).getData(); - bytemap_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0; chunk_i != static_cast(arrow_column->data()->num_chunks()); ++chunk_i) - { - std::shared_ptr chunk = arrow_column->data()->chunk(chunk_i); - - for (size_t value_i = 0; value_i != static_cast(chunk->length()); ++value_i) - bytemap_data.emplace_back(chunk->IsNull(value_i)); - } -} - -# define FOR_ARROW_NUMERIC_TYPES(M) \ - M(arrow::Type::UINT8, UInt8) \ - M(arrow::Type::INT8, Int8) \ - M(arrow::Type::UINT16, UInt16) \ - M(arrow::Type::INT16, Int16) \ - M(arrow::Type::UINT32, UInt32) \ - M(arrow::Type::INT32, Int32) \ - M(arrow::Type::UINT64, UInt64) \ - M(arrow::Type::INT64, Int64) \ - M(arrow::Type::FLOAT, Float32) \ - M(arrow::Type::DOUBLE, Float64) -//M(arrow::Type::HALF_FLOAT, Float32) // TODO - - -using NameToColumnPtr = std::unordered_map>; - - -Block ParquetBlockInputStream::readImpl() -{ - static const std::unordered_map> arrow_type_to_internal_type = { - //{arrow::Type::DECIMAL, std::make_shared()}, - {arrow::Type::UINT8, std::make_shared()}, - {arrow::Type::INT8, std::make_shared()}, - {arrow::Type::UINT16, std::make_shared()}, - {arrow::Type::INT16, std::make_shared()}, - {arrow::Type::UINT32, std::make_shared()}, - {arrow::Type::INT32, std::make_shared()}, - {arrow::Type::UINT64, std::make_shared()}, - {arrow::Type::INT64, std::make_shared()}, - {arrow::Type::HALF_FLOAT, std::make_shared()}, - {arrow::Type::FLOAT, std::make_shared()}, - {arrow::Type::DOUBLE, std::make_shared()}, - - {arrow::Type::BOOL, std::make_shared()}, - //{arrow::Type::DATE32, std::make_shared()}, - {arrow::Type::DATE32, std::make_shared()}, - //{arrow::Type::DATE32, std::make_shared()}, - {arrow::Type::DATE64, std::make_shared()}, - {arrow::Type::TIMESTAMP, std::make_shared()}, - //{arrow::Type::TIME32, std::make_shared()}, - - - {arrow::Type::STRING, std::make_shared()}, - {arrow::Type::BINARY, std::make_shared()}, - //{arrow::Type::FIXED_SIZE_BINARY, std::make_shared()}, - //{arrow::Type::UUID, std::make_shared()}, - - - // TODO: add other types that are convertable to internal ones: - // 0. ENUM? - // 1. UUID -> String - // 2. JSON -> String - // Full list of types: contrib/arrow/cpp/src/arrow/type.h - }; - - - Block res; - - if (!istr.eof()) - { - /* - First we load whole stream into string (its very bad and limiting .parquet file size to half? of RAM) - Then producing blocks for every row_group (dont load big .parquet files with one row_group - it can eat x10+ RAM from .parquet file size) - */ - - if (row_group_current < row_group_total) - throw Exception{"Got new data, but data from previous chunks not readed " + std::to_string(row_group_current) + "/" - + std::to_string(row_group_total), - ErrorCodes::CANNOT_READ_ALL_DATA}; - - file_data.clear(); - { - WriteBufferFromString file_buffer(file_data); - copyData(istr, file_buffer); - } - - buffer = std::make_unique(file_data); - // TODO: maybe use parquet::RandomAccessSource? - auto reader = parquet::ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(*buffer)); - file_reader = std::make_unique(::arrow::default_memory_pool(), std::move(reader)); - row_group_total = file_reader->num_row_groups(); - row_group_current = 0; - } - if (row_group_current >= row_group_total) - return res; - - // TODO: also catch a ParquetException thrown by filereader? - //arrow::Status read_status = filereader.ReadTable(&table); - std::shared_ptr table; - arrow::Status read_status = file_reader->ReadRowGroup(row_group_current, &table); - - if (!read_status.ok()) - throw Exception{"Error while reading parquet data: " + read_status.ToString(), ErrorCodes::CANNOT_READ_ALL_DATA}; - - if (0 == table->num_rows()) - throw Exception{"Empty table in input data", ErrorCodes::EMPTY_DATA_PASSED}; - - if (header.columns() > static_cast(table->num_columns())) - // TODO: What if some columns were not presented? Insert NULLs? What if a column is not nullable? - throw Exception{"Number of columns is less than the table has", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH}; - - ++row_group_current; - - NameToColumnPtr name_to_column_ptr; - for (size_t i = 0, num_columns = static_cast(table->num_columns()); i < num_columns; ++i) - { - std::shared_ptr arrow_column = table->column(i); - name_to_column_ptr[arrow_column->name()] = arrow_column; - } - - for (size_t column_i = 0, columns = header.columns(); column_i < columns; ++column_i) - { - ColumnWithTypeAndName header_column = header.getByPosition(column_i); - - if (name_to_column_ptr.find(header_column.name) == name_to_column_ptr.end()) - // TODO: What if some columns were not presented? Insert NULLs? What if a column is not nullable? - throw Exception{"Column \"" + header_column.name + "\" is not presented in input data", ErrorCodes::THERE_IS_NO_COLUMN}; - - std::shared_ptr arrow_column = name_to_column_ptr[header_column.name]; - arrow::Type::type arrow_type = arrow_column->type()->id(); - - // TODO: check if a column is const? - if (!header_column.type->isNullable() && arrow_column->null_count()) - { - throw Exception{"Can not insert NULL data into non-nullable column \"" + header_column.name + "\"", - ErrorCodes::CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN}; - } - - const bool target_column_is_nullable = header_column.type->isNullable() || arrow_column->null_count(); - - DataTypePtr internal_nested_type; - - if (arrow_type == arrow::Type::DECIMAL) - { - const auto decimal_type = static_cast(arrow_column->type().get()); - internal_nested_type = std::make_shared>(decimal_type->precision(), decimal_type->scale()); - } - else if (arrow_type_to_internal_type.find(arrow_type) != arrow_type_to_internal_type.end()) - { - internal_nested_type = arrow_type_to_internal_type.at(arrow_type); - } - else - { - throw Exception{"The type \"" + arrow_column->type()->name() + "\" of an input column \"" + arrow_column->name() - + "\" is not supported for conversion from a Parquet data format", - ErrorCodes::CANNOT_CONVERT_TYPE}; - } - - const DataTypePtr internal_type = target_column_is_nullable ? makeNullable(internal_nested_type) : internal_nested_type; - const std::string internal_nested_type_name = internal_nested_type->getName(); - - const DataTypePtr column_nested_type = header_column.type->isNullable() - ? static_cast(header_column.type.get())->getNestedType() - : header_column.type; - - const DataTypePtr column_type = header_column.type; - - const std::string column_nested_type_name = column_nested_type->getName(); - - ColumnWithTypeAndName column; - column.name = header_column.name; - column.type = internal_type; - - /// Data - MutableColumnPtr read_column = internal_nested_type->createColumn(); - switch (arrow_type) - { - case arrow::Type::STRING: - case arrow::Type::BINARY: - //case arrow::Type::FIXED_SIZE_BINARY: - fillColumnWithStringData(arrow_column, read_column); - break; - case arrow::Type::BOOL: - fillColumnWithBooleanData(arrow_column, read_column); - break; - case arrow::Type::DATE32: - fillColumnWithDate32Data(arrow_column, read_column); - break; - case arrow::Type::DATE64: - fillColumnWithDate64Data(arrow_column, read_column); - break; - case arrow::Type::TIMESTAMP: - fillColumnWithTimestampData(arrow_column, read_column); - break; - case arrow::Type::DECIMAL: - //fillColumnWithNumericData>(arrow_column, read_column); // Have problems with trash values under NULL, but faster - fillColumnWithDecimalData(arrow_column, read_column /*, internal_nested_type*/); - break; -# define DISPATCH(ARROW_NUMERIC_TYPE, CPP_NUMERIC_TYPE) \ - case ARROW_NUMERIC_TYPE: \ - fillColumnWithNumericData(arrow_column, read_column); \ - break; - - FOR_ARROW_NUMERIC_TYPES(DISPATCH) -# undef DISPATCH - // TODO: support TIMESTAMP_MICROS and TIMESTAMP_MILLIS with truncated micro- and milliseconds? - // TODO: read JSON as a string? - // TODO: read UUID as a string? - default: - throw Exception{"Unsupported parquet type \"" + arrow_column->type()->name() + "\" of an input column \"" - + arrow_column->name() + "\"", - ErrorCodes::UNKNOWN_TYPE}; - } - - if (column.type->isNullable()) - { - MutableColumnPtr null_bytemap = DataTypeUInt8().createColumn(); - fillByteMapFromArrowColumn(arrow_column, null_bytemap); - column.column = ColumnNullable::create(std::move(read_column), std::move(null_bytemap)); - } - else - { - column.column = std::move(read_column); - } - - column.column = castColumn(column, column_type, context); - column.type = column_type; - - res.insert(std::move(column)); - } - - return res; -} - -void registerInputFormatParquet(FormatFactory & factory) -{ - factory.registerInputFormat( - "Parquet", - [](ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 /* max_block_size */, - UInt64 /* rows_portion_size */, - FormatFactory::ReadCallback /* callback */, - const FormatSettings & /* settings */) { return std::make_shared(buf, sample, context); }); -} - -} - -#else - -namespace DB -{ -class FormatFactory; -void registerInputFormatParquet(FormatFactory &) -{ -} -} - -#endif diff --git a/dbms/src/Formats/ParquetBlockInputStream.h b/dbms/src/Formats/ParquetBlockInputStream.h deleted file mode 100644 index 636f0cec7b8..00000000000 --- a/dbms/src/Formats/ParquetBlockInputStream.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "config_formats.h" -#if USE_PARQUET -# include - - -namespace parquet { namespace arrow { class FileReader; } } -namespace arrow { class Buffer; } - -namespace DB -{ -class Context; - -class ParquetBlockInputStream : public IBlockInputStream -{ -public: - ParquetBlockInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_); - - String getName() const override { return "Parquet"; } - Block getHeader() const override; - -protected: - Block readImpl() override; - -private: - ReadBuffer & istr; - Block header; - - // TODO: check that this class implements every part of its parent - - const Context & context; - - std::unique_ptr file_reader; - std::string file_data; - std::unique_ptr buffer; - int row_group_total = 0; - int row_group_current = 0; -}; - -} - -#endif diff --git a/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp b/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp index 9e19f0881ed..597c6cb4af1 100644 --- a/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp @@ -1,7 +1,7 @@ #include "config_formats.h" #if USE_PARQUET -#include "ParquetBlockInputFormat.h" +#include #include #include @@ -29,15 +29,9 @@ #include #include #include -//#include -//#include #include -//#include -//#include #include -#include // REMOVE ME - namespace DB { namespace ErrorCodes diff --git a/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.h b/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.h index bbb7abdd5d4..8fa9013fbd1 100644 --- a/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.h @@ -1,11 +1,9 @@ #pragma once -#include +#include "config_formats.h" #if USE_PARQUET -# include -//# include -//# include -//# include + +#include namespace parquet { namespace arrow { class FileReader; } } From 529e06e5cbeb102e3231cab3247dc6ca4356bab7 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:09:52 +0300 Subject: [PATCH 048/105] Remove ParquetBlockOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 3 +- dbms/src/Formats/ParquetBlockOutputStream.cpp | 451 ------------------ dbms/src/Formats/ParquetBlockOutputStream.h | 46 -- .../Formats/Impl/ParquetBlockOutputFormat.cpp | 2 +- .../Formats/Impl/ParquetBlockOutputFormat.h | 2 +- 5 files changed, 3 insertions(+), 501 deletions(-) delete mode 100644 dbms/src/Formats/ParquetBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/ParquetBlockOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 0d346027d49..258786a93c9 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -207,7 +207,7 @@ void registerInputFormatCSV(FormatFactory & factory); void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); -void registerOutputFormatParquet(FormatFactory & factory); +void registerOutputFormatTSKV(FormatFactory & factory); void registerInputFormatProtobuf(FormatFactory & factory); void registerOutputFormatProtobuf(FormatFactory & factory); @@ -268,7 +268,6 @@ FormatFactory::FormatFactory() registerOutputFormatTSKV(*this); registerInputFormatProtobuf(*this); registerOutputFormatProtobuf(*this); - registerOutputFormatParquet(*this); registerInputFormatProcessorNative(*this); registerOutputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/ParquetBlockOutputStream.cpp b/dbms/src/Formats/ParquetBlockOutputStream.cpp deleted file mode 100644 index f03aa181bc3..00000000000 --- a/dbms/src/Formats/ParquetBlockOutputStream.cpp +++ /dev/null @@ -1,451 +0,0 @@ -#include "config_formats.h" -#if USE_PARQUET -# include "ParquetBlockOutputStream.h" - -// TODO: clean includes -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -namespace DB -{ -namespace ErrorCodes -{ - extern const int UNKNOWN_EXCEPTION; - extern const int UNKNOWN_TYPE; -} - -ParquetBlockOutputStream::ParquetBlockOutputStream(WriteBuffer & ostr, const Block & header, const FormatSettings & format_settings) : ostr{ostr}, header{header}, format_settings{format_settings} -{ -} - -void ParquetBlockOutputStream::flush() -{ - ostr.next(); -} - -void checkStatus(arrow::Status & status, const std::string & column_name) -{ - if (!status.ok()) - throw Exception{"Error with a parquet column \"" + column_name + "\": " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; -} - -template -void fillArrowArrayWithNumericColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - const PaddedPODArray & internal_data = static_cast &>(*write_column).getData(); - ArrowBuilderType builder; - arrow::Status status; - - const UInt8 * arrow_null_bytemap_raw_ptr = nullptr; - PaddedPODArray arrow_null_bytemap; - if (null_bytemap) - { - /// Invert values since Arrow interprets 1 as a non-null value, while CH as a null - arrow_null_bytemap.reserve(null_bytemap->size()); - for (size_t i = 0, size = null_bytemap->size(); i < size; ++i) - arrow_null_bytemap.emplace_back(1 ^ (*null_bytemap)[i]); - - arrow_null_bytemap_raw_ptr = arrow_null_bytemap.data(); - } - - status = builder.AppendValues(internal_data.data(), internal_data.size(), arrow_null_bytemap_raw_ptr); - checkStatus(status, write_column->getName()); - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -template -void fillArrowArrayWithStringColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - const auto & internal_column = static_cast(*write_column); - arrow::StringBuilder builder; - arrow::Status status; - - for (size_t string_i = 0, size = internal_column.size(); string_i < size; ++string_i) - { - if (null_bytemap && (*null_bytemap)[string_i]) - { - status = builder.AppendNull(); - } - else - { - StringRef string_ref = internal_column.getDataAt(string_i); - status = builder.Append(string_ref.data, string_ref.size); - } - - checkStatus(status, write_column->getName()); - } - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -void fillArrowArrayWithDateColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - const PaddedPODArray & internal_data = static_cast &>(*write_column).getData(); - //arrow::Date32Builder date_builder; - arrow::UInt16Builder builder; - arrow::Status status; - - for (size_t value_i = 0, size = internal_data.size(); value_i < size; ++value_i) - { - if (null_bytemap && (*null_bytemap)[value_i]) - status = builder.AppendNull(); - else - /// Implicitly converts UInt16 to Int32 - status = builder.Append(internal_data[value_i]); - checkStatus(status, write_column->getName()); - } - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -void fillArrowArrayWithDateTimeColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - auto & internal_data = static_cast &>(*write_column).getData(); - //arrow::Date64Builder builder; - arrow::UInt32Builder builder; - arrow::Status status; - - for (size_t value_i = 0, size = internal_data.size(); value_i < size; ++value_i) - { - if (null_bytemap && (*null_bytemap)[value_i]) - status = builder.AppendNull(); - else - /// Implicitly converts UInt16 to Int32 - //status = date_builder.Append(static_cast(internal_data[value_i]) * 1000); // now ms. TODO check other units - status = builder.Append(internal_data[value_i]); - - checkStatus(status, write_column->getName()); - } - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -template -void fillArrowArrayWithDecimalColumnData( - ColumnPtr write_column, - std::shared_ptr & arrow_array, - const PaddedPODArray * null_bytemap, - const DataType * decimal_type) -{ - const auto & column = static_cast(*write_column); - arrow::DecimalBuilder builder(arrow::decimal(decimal_type->getPrecision(), decimal_type->getScale())); - arrow::Status status; - - for (size_t value_i = 0, size = column.size(); value_i < size; ++value_i) - { - if (null_bytemap && (*null_bytemap)[value_i]) - status = builder.AppendNull(); - else - status = builder.Append( - arrow::Decimal128(reinterpret_cast(&column.getElement(value_i).value))); // TODO: try copy column - - checkStatus(status, write_column->getName()); - } - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); - -/* TODO column copy - const auto & internal_data = static_cast(*write_column).getData(); - //ArrowBuilderType numeric_builder; - arrow::DecimalBuilder builder(arrow::decimal(decimal_type->getPrecision(), decimal_type->getScale())); - arrow::Status status; - - const uint8_t * arrow_null_bytemap_raw_ptr = nullptr; - PaddedPODArray arrow_null_bytemap; - if (null_bytemap) - { - /// Invert values since Arrow interprets 1 as a non-null value, while CH as a null - arrow_null_bytemap.reserve(null_bytemap->size()); - for (size_t i = 0, size = null_bytemap->size(); i < size; ++i) - arrow_null_bytemap.emplace_back(1 ^ (*null_bytemap)[i]); - - arrow_null_bytemap_raw_ptr = arrow_null_bytemap.data(); - } - - status = builder.AppendValues(reinterpret_cast(internal_data.data()), internal_data.size(), arrow_null_bytemap_raw_ptr); - checkStatus(status, write_column->getName()); - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -*/ -} - -# define FOR_INTERNAL_NUMERIC_TYPES(M) \ - M(UInt8, arrow::UInt8Builder) \ - M(Int8, arrow::Int8Builder) \ - M(UInt16, arrow::UInt16Builder) \ - M(Int16, arrow::Int16Builder) \ - M(UInt32, arrow::UInt32Builder) \ - M(Int32, arrow::Int32Builder) \ - M(UInt64, arrow::UInt64Builder) \ - M(Int64, arrow::Int64Builder) \ - M(Float32, arrow::FloatBuilder) \ - M(Float64, arrow::DoubleBuilder) - -const std::unordered_map> internal_type_to_arrow_type = { - {"UInt8", arrow::uint8()}, - {"Int8", arrow::int8()}, - {"UInt16", arrow::uint16()}, - {"Int16", arrow::int16()}, - {"UInt32", arrow::uint32()}, - {"Int32", arrow::int32()}, - {"UInt64", arrow::uint64()}, - {"Int64", arrow::int64()}, - {"Float32", arrow::float32()}, - {"Float64", arrow::float64()}, - - //{"Date", arrow::date64()}, - //{"Date", arrow::date32()}, - {"Date", arrow::uint16()}, // CHECK - //{"DateTime", arrow::date64()}, // BUG! saves as date32 - {"DateTime", arrow::uint32()}, - - // TODO: ClickHouse can actually store non-utf8 strings! - {"String", arrow::utf8()}, - {"FixedString", arrow::utf8()}, -}; - -const PaddedPODArray * extractNullBytemapPtr(ColumnPtr column) -{ - ColumnPtr null_column = static_cast(*column).getNullMapColumnPtr(); - const PaddedPODArray & null_bytemap = static_cast &>(*null_column).getData(); - return &null_bytemap; -} - - -class OstreamOutputStream : public parquet::OutputStream -{ -public: - explicit OstreamOutputStream(WriteBuffer & ostr_) : ostr(ostr_) {} - virtual ~OstreamOutputStream() {} - virtual void Close() {} - virtual int64_t Tell() { return total_length; } - virtual void Write(const uint8_t * data, int64_t length) - { - ostr.write(reinterpret_cast(data), length); - total_length += length; - } - -private: - WriteBuffer & ostr; - int64_t total_length = 0; - - PARQUET_DISALLOW_COPY_AND_ASSIGN(OstreamOutputStream); -}; - - -void ParquetBlockOutputStream::write(const Block & block) -{ - block.checkNumberOfRows(); - - const size_t columns_num = block.columns(); - - /// For arrow::Schema and arrow::Table creation - std::vector> arrow_fields; - std::vector> arrow_arrays; - arrow_fields.reserve(columns_num); - arrow_arrays.reserve(columns_num); - - for (size_t column_i = 0; column_i < columns_num; ++column_i) - { - // TODO: constructed every iteration - const ColumnWithTypeAndName & column = block.safeGetByPosition(column_i); - - const bool is_column_nullable = column.type->isNullable(); - const auto & column_nested_type - = is_column_nullable ? static_cast(column.type.get())->getNestedType() : column.type; - const std::string column_nested_type_name = column_nested_type->getFamilyName(); - - if (isDecimal(column_nested_type)) - { - const auto add_decimal_field = [&](const auto & types) -> bool { - using Types = std::decay_t; - using ToDataType = typename Types::LeftType; - - if constexpr ( - std::is_same_v< - ToDataType, - DataTypeDecimal< - Decimal32>> || std::is_same_v> || std::is_same_v>) - { - const auto & decimal_type = static_cast(column_nested_type.get()); - arrow_fields.emplace_back(std::make_shared( - column.name, arrow::decimal(decimal_type->getPrecision(), decimal_type->getScale()), is_column_nullable)); - } - - return false; - }; - callOnIndexAndDataType(column_nested_type->getTypeId(), add_decimal_field); - } - else - { - if (internal_type_to_arrow_type.find(column_nested_type_name) == internal_type_to_arrow_type.end()) - { - throw Exception{"The type \"" + column_nested_type_name + "\" of a column \"" + column.name - + "\"" - " is not supported for conversion into a Parquet data format", - ErrorCodes::UNKNOWN_TYPE}; - } - - arrow_fields.emplace_back(std::make_shared(column.name, internal_type_to_arrow_type.at(column_nested_type_name), is_column_nullable)); - } - - std::shared_ptr arrow_array; - - ColumnPtr nested_column - = is_column_nullable ? static_cast(*column.column).getNestedColumnPtr() : column.column; - const PaddedPODArray * null_bytemap = is_column_nullable ? extractNullBytemapPtr(column.column) : nullptr; - - if ("String" == column_nested_type_name) - { - fillArrowArrayWithStringColumnData(nested_column, arrow_array, null_bytemap); - } - else if ("FixedString" == column_nested_type_name) - { - fillArrowArrayWithStringColumnData(nested_column, arrow_array, null_bytemap); - } - else if ("Date" == column_nested_type_name) - { - fillArrowArrayWithDateColumnData(nested_column, arrow_array, null_bytemap); - } - else if ("DateTime" == column_nested_type_name) - { - fillArrowArrayWithDateTimeColumnData(nested_column, arrow_array, null_bytemap); - } - - else if (isDecimal(column_nested_type)) - { - auto fill_decimal = [&](const auto & types) -> bool - { - using Types = std::decay_t; - using ToDataType = typename Types::LeftType; - if constexpr ( - std::is_same_v< - ToDataType, - DataTypeDecimal< - Decimal32>> || std::is_same_v> || std::is_same_v>) - { - const auto & decimal_type = static_cast(column_nested_type.get()); - fillArrowArrayWithDecimalColumnData(nested_column, arrow_array, null_bytemap, decimal_type); - } - return false; - }; - callOnIndexAndDataType(column_nested_type->getTypeId(), fill_decimal); - } -# define DISPATCH(CPP_NUMERIC_TYPE, ARROW_BUILDER_TYPE) \ - else if (#CPP_NUMERIC_TYPE == column_nested_type_name) \ - { \ - fillArrowArrayWithNumericColumnData(nested_column, arrow_array, null_bytemap); \ - } - - FOR_INTERNAL_NUMERIC_TYPES(DISPATCH) -# undef DISPATCH - else - { - throw Exception{"Internal type \"" + column_nested_type_name + "\" of a column \"" + column.name - + "\"" - " is not supported for conversion into a Parquet data format", - ErrorCodes::UNKNOWN_TYPE}; - } - - - arrow_arrays.emplace_back(std::move(arrow_array)); - } - - std::shared_ptr arrow_schema = std::make_shared(std::move(arrow_fields)); - - std::shared_ptr arrow_table = arrow::Table::Make(arrow_schema, arrow_arrays); - - auto sink = std::make_shared(ostr); - - if (!file_writer) - { - - parquet::WriterProperties::Builder builder; -#if USE_SNAPPY - builder.compression(parquet::Compression::SNAPPY); -#endif - auto props = builder.build(); - auto status = parquet::arrow::FileWriter::Open( - *arrow_table->schema(), - arrow::default_memory_pool(), - sink, - props, /*parquet::default_writer_properties(),*/ - parquet::arrow::default_arrow_writer_properties(), - &file_writer); - if (!status.ok()) - throw Exception{"Error while opening a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; - } - - // TODO: calculate row_group_size depending on a number of rows and table size - auto status = file_writer->WriteTable(*arrow_table, format_settings.parquet.row_group_size); - - if (!status.ok()) - throw Exception{"Error while writing a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; -} - -void ParquetBlockOutputStream::writeSuffix() -{ - if (file_writer) - { - auto status = file_writer->Close(); - if (!status.ok()) - throw Exception{"Error while closing a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; - } -} - - -void registerOutputFormatParquet(FormatFactory & factory) -{ - factory.registerOutputFormat( - "Parquet", [](WriteBuffer & buf, const Block & sample, const Context & /*context*/, const FormatSettings & format_settings) - { - BlockOutputStreamPtr impl = std::make_shared(buf, sample, format_settings); - auto res = std::make_shared(impl, impl->getHeader(), format_settings.parquet.row_group_size, 0); - res->disableFlush(); - return res; - }); -} - -} - - -#else - -namespace DB -{ -class FormatFactory; -void registerOutputFormatParquet(FormatFactory &) -{ -} -} - - -#endif diff --git a/dbms/src/Formats/ParquetBlockOutputStream.h b/dbms/src/Formats/ParquetBlockOutputStream.h deleted file mode 100644 index 7cd484fc52b..00000000000 --- a/dbms/src/Formats/ParquetBlockOutputStream.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "config_formats.h" -#if USE_PARQUET -# include -# include - -namespace arrow -{ -class Array; -class DataType; -} - -namespace parquet -{ -namespace arrow -{ - class FileWriter; -} -} - -namespace DB -{ -class ParquetBlockOutputStream : public IBlockOutputStream -{ -public: - ParquetBlockOutputStream(WriteBuffer & ostr_, const Block & header_, const FormatSettings & format_settings); - - Block getHeader() const override { return header; } - void write(const Block & block) override; - void writeSuffix() override; - void flush() override; - - String getContentType() const override { return "application/octet-stream"; } - -private: - WriteBuffer & ostr; - Block header; - const FormatSettings format_settings; - - std::unique_ptr file_writer; -}; - -} - -#endif diff --git a/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp index 26b3dd84f14..5b546e863de 100644 --- a/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp @@ -1,7 +1,7 @@ #include "config_formats.h" #if USE_PARQUET -# include "ParquetBlockOutputFormat.h" +# include // TODO: clean includes # include diff --git a/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.h b/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.h index de2deba50b3..f7ca6f11f00 100644 --- a/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.h +++ b/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "config_formats.h" #if USE_PARQUET # include # include From bd4f0182e47d4bd3f135955ef0fd4b3aeaeb3e6a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:20:25 +0300 Subject: [PATCH 049/105] Remove PrettyBlockOutputStreams. --- dbms/src/Formats/FormatFactory.cpp | 7 +- dbms/src/Formats/PrettyBlockOutputStream.cpp | 277 ------------------ dbms/src/Formats/PrettyBlockOutputStream.h | 55 ---- .../PrettyCompactBlockOutputStream.cpp | 161 ---------- .../Formats/PrettyCompactBlockOutputStream.h | 25 -- .../Formats/PrettySpaceBlockOutputStream.cpp | 116 -------- .../Formats/PrettySpaceBlockOutputStream.h | 21 -- 7 files changed, 1 insertion(+), 661 deletions(-) delete mode 100644 dbms/src/Formats/PrettyBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/PrettyBlockOutputStream.h delete mode 100644 dbms/src/Formats/PrettyCompactBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/PrettyCompactBlockOutputStream.h delete mode 100644 dbms/src/Formats/PrettySpaceBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/PrettySpaceBlockOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 258786a93c9..af0bd2e6c88 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -232,9 +232,6 @@ void registerOutputFormatProcessorProtobuf(FormatFactory & factory); /// Output only (presentational) formats. -void registerOutputFormatPretty(FormatFactory & factory); -void registerOutputFormatPrettyCompact(FormatFactory & factory); -void registerOutputFormatPrettySpace(FormatFactory & factory); void registerOutputFormatVertical(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); @@ -289,9 +286,7 @@ FormatFactory::FormatFactory() registerInputFormatProcessorParquet(*this); registerOutputFormatProcessorParquet(*this); - registerOutputFormatPretty(*this); - registerOutputFormatPrettyCompact(*this); - registerOutputFormatPrettySpace(*this); + registerOutputFormatVertical(*this); registerOutputFormatXML(*this); registerOutputFormatNull(*this); diff --git a/dbms/src/Formats/PrettyBlockOutputStream.cpp b/dbms/src/Formats/PrettyBlockOutputStream.cpp deleted file mode 100644 index 9c4c9a20965..00000000000 --- a/dbms/src/Formats/PrettyBlockOutputStream.cpp +++ /dev/null @@ -1,277 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int ILLEGAL_COLUMN; -} - - -PrettyBlockOutputStream::PrettyBlockOutputStream( - WriteBuffer & ostr_, const Block & header_, const FormatSettings & format_settings) - : ostr(ostr_), header(header_), format_settings(format_settings) -{ - struct winsize w; - if (0 == ioctl(STDOUT_FILENO, TIOCGWINSZ, &w)) - terminal_width = w.ws_col; -} - - -void PrettyBlockOutputStream::flush() -{ - ostr.next(); -} - - -/// Evaluate the visible width of the values and column names. -/// Note that number of code points is just a rough approximation of visible string width. -void PrettyBlockOutputStream::calculateWidths( - const Block & block, WidthsPerColumn & widths, Widths & max_widths, Widths & name_widths, const FormatSettings & format_settings) -{ - size_t rows = block.rows(); - size_t columns = block.columns(); - - widths.resize(columns); - max_widths.resize_fill(columns); - name_widths.resize(columns); - - /// Calculate widths of all values. - String serialized_value; - size_t prefix = 2; // Tab character adjustment - for (size_t i = 0; i < columns; ++i) - { - const ColumnWithTypeAndName & elem = block.getByPosition(i); - - widths[i].resize(rows); - - for (size_t j = 0; j < rows; ++j) - { - { - WriteBufferFromString out(serialized_value); - elem.type->serializeAsText(*elem.column, j, out, format_settings); - } - - widths[i][j] = std::min(format_settings.pretty.max_column_pad_width, - UTF8::computeWidth(reinterpret_cast(serialized_value.data()), serialized_value.size(), prefix)); - max_widths[i] = std::max(max_widths[i], widths[i][j]); - } - - /// And also calculate widths for names of columns. - { - // name string doesn't contain Tab, no need to pass `prefix` - name_widths[i] = std::min(format_settings.pretty.max_column_pad_width, - UTF8::computeWidth(reinterpret_cast(elem.name.data()), elem.name.size())); - max_widths[i] = std::max(max_widths[i], name_widths[i]); - } - prefix += max_widths[i] + 3; - } -} - - -void PrettyBlockOutputStream::write(const Block & block) -{ - UInt64 max_rows = format_settings.pretty.max_rows; - - if (total_rows >= max_rows) - { - total_rows += block.rows(); - return; - } - - size_t rows = block.rows(); - size_t columns = block.columns(); - - WidthsPerColumn widths; - Widths max_widths; - Widths name_widths; - calculateWidths(block, widths, max_widths, name_widths, format_settings); - - /// Create separators - std::stringstream top_separator; - std::stringstream middle_names_separator; - std::stringstream middle_values_separator; - std::stringstream bottom_separator; - - top_separator << "┏"; - middle_names_separator << "┡"; - middle_values_separator << "├"; - bottom_separator << "└"; - for (size_t i = 0; i < columns; ++i) - { - if (i != 0) - { - top_separator << "┳"; - middle_names_separator << "╇"; - middle_values_separator << "┼"; - bottom_separator << "┴"; - } - - for (size_t j = 0; j < max_widths[i] + 2; ++j) - { - top_separator << "━"; - middle_names_separator << "━"; - middle_values_separator << "─"; - bottom_separator << "─"; - } - } - top_separator << "┓\n"; - middle_names_separator << "┩\n"; - middle_values_separator << "┤\n"; - bottom_separator << "┘\n"; - - std::string top_separator_s = top_separator.str(); - std::string middle_names_separator_s = middle_names_separator.str(); - std::string middle_values_separator_s = middle_values_separator.str(); - std::string bottom_separator_s = bottom_separator.str(); - - /// Output the block - writeString(top_separator_s, ostr); - - /// Names - writeCString("┃ ", ostr); - for (size_t i = 0; i < columns; ++i) - { - if (i != 0) - writeCString(" ┃ ", ostr); - - const ColumnWithTypeAndName & col = block.getByPosition(i); - - if (format_settings.pretty.color) - writeCString("\033[1m", ostr); - - if (col.type->shouldAlignRightInPrettyFormats()) - { - for (size_t k = 0; k < max_widths[i] - name_widths[i]; ++k) - writeChar(' ', ostr); - - writeString(col.name, ostr); - } - else - { - writeString(col.name, ostr); - - for (size_t k = 0; k < max_widths[i] - name_widths[i]; ++k) - writeChar(' ', ostr); - } - - if (format_settings.pretty.color) - writeCString("\033[0m", ostr); - } - writeCString(" ┃\n", ostr); - - writeString(middle_names_separator_s, ostr); - - for (size_t i = 0; i < rows && total_rows + i < max_rows; ++i) - { - if (i != 0) - writeString(middle_values_separator_s, ostr); - - writeCString("│ ", ostr); - - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeCString(" │ ", ostr); - - writeValueWithPadding(block.getByPosition(j), i, widths[j].empty() ? max_widths[j] : widths[j][i], max_widths[j]); - } - - writeCString(" │\n", ostr); - } - - writeString(bottom_separator_s, ostr); - - total_rows += rows; -} - - -void PrettyBlockOutputStream::writeValueWithPadding(const ColumnWithTypeAndName & elem, size_t row_num, size_t value_width, size_t pad_to_width) -{ - auto writePadding = [&]() - { - for (size_t k = 0; k < pad_to_width - value_width; ++k) - writeChar(' ', ostr); - }; - - if (elem.type->shouldAlignRightInPrettyFormats()) - { - writePadding(); - elem.type->serializeAsText(*elem.column.get(), row_num, ostr, format_settings); - } - else - { - elem.type->serializeAsText(*elem.column.get(), row_num, ostr, format_settings); - writePadding(); - } -} - - -void PrettyBlockOutputStream::writeSuffix() -{ - if (total_rows >= format_settings.pretty.max_rows) - { - writeCString(" Showed first ", ostr); - writeIntText(format_settings.pretty.max_rows, ostr); - writeCString(".\n", ostr); - } - - total_rows = 0; - writeTotals(); - writeExtremes(); -} - - -void PrettyBlockOutputStream::writeTotals() -{ - if (totals) - { - writeCString("\nTotals:\n", ostr); - write(totals); - } -} - - -void PrettyBlockOutputStream::writeExtremes() -{ - if (extremes) - { - writeCString("\nExtremes:\n", ostr); - write(extremes); - } -} - - -void registerOutputFormatPretty(FormatFactory & factory) -{ - factory.registerOutputFormat("Pretty", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared(buf, sample, format_settings); - }); - - factory.registerOutputFormat("PrettyNoEscapes", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - FormatSettings changed_settings = format_settings; - changed_settings.pretty.color = false; - return std::make_shared(buf, sample, changed_settings); - }); -} - -} diff --git a/dbms/src/Formats/PrettyBlockOutputStream.h b/dbms/src/Formats/PrettyBlockOutputStream.h deleted file mode 100644 index ca23ba2cf61..00000000000 --- a/dbms/src/Formats/PrettyBlockOutputStream.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace DB -{ - -class WriteBuffer; -class Context; - - -/** Prints the result in the form of beautiful tables. - */ -class PrettyBlockOutputStream : public IBlockOutputStream -{ -public: - /// no_escapes - do not use ANSI escape sequences - to display in the browser, not in the console. - PrettyBlockOutputStream(WriteBuffer & ostr_, const Block & header_, const FormatSettings & format_settings); - - Block getHeader() const override { return header; } - void write(const Block & block) override; - void writeSuffix() override; - - void flush() override; - - void setTotals(const Block & totals_) override { totals = totals_; } - void setExtremes(const Block & extremes_) override { extremes = extremes_; } - -protected: - void writeTotals(); - void writeExtremes(); - - WriteBuffer & ostr; - const Block header; - size_t total_rows = 0; - size_t terminal_width = 0; - - const FormatSettings format_settings; - - Block totals; - Block extremes; - - using Widths = PODArray; - using WidthsPerColumn = std::vector; - - static void calculateWidths( - const Block & block, WidthsPerColumn & widths, Widths & max_widths, Widths & name_widths, const FormatSettings & format_settings); - - void writeValueWithPadding(const ColumnWithTypeAndName & elem, size_t row_num, size_t value_width, size_t pad_to_width); -}; - -} diff --git a/dbms/src/Formats/PrettyCompactBlockOutputStream.cpp b/dbms/src/Formats/PrettyCompactBlockOutputStream.cpp deleted file mode 100644 index b4085fb256b..00000000000 --- a/dbms/src/Formats/PrettyCompactBlockOutputStream.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace DB -{ - -namespace ErrorCodes -{ - -extern const int ILLEGAL_COLUMN; - -} - -void PrettyCompactBlockOutputStream::writeHeader( - const Block & block, - const Widths & max_widths, - const Widths & name_widths) -{ - /// Names - writeCString("┌─", ostr); - for (size_t i = 0; i < max_widths.size(); ++i) - { - if (i != 0) - writeCString("─┬─", ostr); - - const ColumnWithTypeAndName & col = block.getByPosition(i); - - if (col.type->shouldAlignRightInPrettyFormats()) - { - for (size_t k = 0; k < max_widths[i] - name_widths[i]; ++k) - writeCString("─", ostr); - - if (format_settings.pretty.color) - writeCString("\033[1m", ostr); - writeString(col.name, ostr); - if (format_settings.pretty.color) - writeCString("\033[0m", ostr); - } - else - { - if (format_settings.pretty.color) - writeCString("\033[1m", ostr); - writeString(col.name, ostr); - if (format_settings.pretty.color) - writeCString("\033[0m", ostr); - - for (size_t k = 0; k < max_widths[i] - name_widths[i]; ++k) - writeCString("─", ostr); - } - } - writeCString("─┐\n", ostr); -} - -void PrettyCompactBlockOutputStream::writeBottom(const Widths & max_widths) -{ - /// Create delimiters - std::stringstream bottom_separator; - - bottom_separator << "└"; - for (size_t i = 0; i < max_widths.size(); ++i) - { - if (i != 0) - bottom_separator << "┴"; - - for (size_t j = 0; j < max_widths[i] + 2; ++j) - bottom_separator << "─"; - } - bottom_separator << "┘\n"; - - writeString(bottom_separator.str(), ostr); -} - -void PrettyCompactBlockOutputStream::writeRow( - size_t row_num, - const Block & block, - const WidthsPerColumn & widths, - const Widths & max_widths) -{ - size_t columns = max_widths.size(); - - writeCString("│ ", ostr); - - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeCString(" │ ", ostr); - - writeValueWithPadding(block.getByPosition(j), row_num, widths[j].empty() ? max_widths[j] : widths[j][row_num], max_widths[j]); - } - - writeCString(" │\n", ostr); -} - -void PrettyCompactBlockOutputStream::write(const Block & block) -{ - UInt64 max_rows = format_settings.pretty.max_rows; - - if (total_rows >= max_rows) - { - total_rows += block.rows(); - return; - } - - size_t rows = block.rows(); - - WidthsPerColumn widths; - Widths max_widths; - Widths name_widths; - calculateWidths(block, widths, max_widths, name_widths, format_settings); - - writeHeader(block, max_widths, name_widths); - - for (size_t i = 0; i < rows && total_rows + i < max_rows; ++i) - writeRow(i, block, widths, max_widths); - - writeBottom(max_widths); - - total_rows += rows; -} - - -void registerOutputFormatPrettyCompact(FormatFactory & factory) -{ - factory.registerOutputFormat("PrettyCompact", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared(buf, sample, format_settings); - }); - - factory.registerOutputFormat("PrettyCompactNoEscapes", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - FormatSettings changed_settings = format_settings; - changed_settings.pretty.color = false; - return std::make_shared(buf, sample, changed_settings); - }); - - factory.registerOutputFormat("PrettyCompactMonoBlock", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - BlockOutputStreamPtr impl = std::make_shared(buf, sample, format_settings); - auto res = std::make_shared(impl, impl->getHeader(), format_settings.pretty.max_rows, 0); - res->disableFlush(); - return res; - }); -} - -} diff --git a/dbms/src/Formats/PrettyCompactBlockOutputStream.h b/dbms/src/Formats/PrettyCompactBlockOutputStream.h deleted file mode 100644 index d0e3826bece..00000000000 --- a/dbms/src/Formats/PrettyCompactBlockOutputStream.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - - -namespace DB -{ - -/** Prints the result in the form of beautiful tables, but with fewer delimiter lines. - */ -class PrettyCompactBlockOutputStream : public PrettyBlockOutputStream -{ -public: - PrettyCompactBlockOutputStream(WriteBuffer & ostr_, const Block & header_, const FormatSettings & format_settings_) - : PrettyBlockOutputStream(ostr_, header_, format_settings_) {} - - void write(const Block & block) override; - -protected: - void writeHeader(const Block & block, const Widths & max_widths, const Widths & name_widths); - void writeBottom(const Widths & max_widths); - void writeRow(size_t row_num, const Block & block, const WidthsPerColumn & widths, const Widths & max_widths); -}; - -} diff --git a/dbms/src/Formats/PrettySpaceBlockOutputStream.cpp b/dbms/src/Formats/PrettySpaceBlockOutputStream.cpp deleted file mode 100644 index b210af2551a..00000000000 --- a/dbms/src/Formats/PrettySpaceBlockOutputStream.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include -#include -#include - - -namespace DB -{ - -void PrettySpaceBlockOutputStream::write(const Block & block) -{ - UInt64 max_rows = format_settings.pretty.max_rows; - - if (total_rows >= max_rows) - { - total_rows += block.rows(); - return; - } - - size_t rows = block.rows(); - size_t columns = block.columns(); - - WidthsPerColumn widths; - Widths max_widths; - Widths name_widths; - calculateWidths(block, widths, max_widths, name_widths, format_settings); - - /// Names - for (size_t i = 0; i < columns; ++i) - { - if (i != 0) - writeCString(" ", ostr); - - const ColumnWithTypeAndName & col = block.getByPosition(i); - - if (col.type->shouldAlignRightInPrettyFormats()) - { - for (ssize_t k = 0; k < std::max(static_cast(0), static_cast(max_widths[i] - name_widths[i])); ++k) - writeChar(' ', ostr); - - if (format_settings.pretty.color) - writeCString("\033[1m", ostr); - writeString(col.name, ostr); - if (format_settings.pretty.color) - writeCString("\033[0m", ostr); - } - else - { - if (format_settings.pretty.color) - writeCString("\033[1m", ostr); - writeString(col.name, ostr); - if (format_settings.pretty.color) - writeCString("\033[0m", ostr); - - for (ssize_t k = 0; k < std::max(static_cast(0), static_cast(max_widths[i] - name_widths[i])); ++k) - writeChar(' ', ostr); - } - } - writeCString("\n\n", ostr); - - for (size_t i = 0; i < rows && total_rows + i < max_rows; ++i) - { - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeCString(" ", ostr); - - writeValueWithPadding(block.getByPosition(j), i, widths[j].empty() ? max_widths[j] : widths[j][i], max_widths[j]); - } - - writeChar('\n', ostr); - } - - total_rows += rows; -} - - -void PrettySpaceBlockOutputStream::writeSuffix() -{ - if (total_rows >= format_settings.pretty.max_rows) - { - writeCString("\nShowed first ", ostr); - writeIntText(format_settings.pretty.max_rows, ostr); - writeCString(".\n", ostr); - } - - total_rows = 0; - writeTotals(); - writeExtremes(); -} - - -void registerOutputFormatPrettySpace(FormatFactory & factory) -{ - factory.registerOutputFormat("PrettySpace", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared(buf, sample, format_settings); - }); - - factory.registerOutputFormat("PrettySpaceNoEscapes", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - FormatSettings changed_settings = format_settings; - changed_settings.pretty.color = false; - return std::make_shared(buf, sample, changed_settings); - }); -} - -} diff --git a/dbms/src/Formats/PrettySpaceBlockOutputStream.h b/dbms/src/Formats/PrettySpaceBlockOutputStream.h deleted file mode 100644 index 9807bf85767..00000000000 --- a/dbms/src/Formats/PrettySpaceBlockOutputStream.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - - -namespace DB -{ - -/** Prints the result, aligned with spaces. - */ -class PrettySpaceBlockOutputStream : public PrettyBlockOutputStream -{ -public: - PrettySpaceBlockOutputStream(WriteBuffer & ostr_, const Block & header_, const FormatSettings & format_settings_) - : PrettyBlockOutputStream(ostr_, header_, format_settings_) {} - - void write(const Block & block) override; - void writeSuffix() override; -}; - -} From 8c66d106e4fb16b4e1d3b4bc24519206b80796b3 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:23:44 +0300 Subject: [PATCH 050/105] Remove ProtobufRowInputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/ProtobufRowInputStream.cpp | 96 ------------------- dbms/src/Formats/ProtobufRowInputStream.h | 40 -------- .../Formats/Impl/ProtobufRowInputFormat.cpp | 2 +- .../Formats/Impl/ProtobufRowInputFormat.h | 8 +- 5 files changed, 8 insertions(+), 140 deletions(-) delete mode 100644 dbms/src/Formats/ProtobufRowInputStream.cpp delete mode 100644 dbms/src/Formats/ProtobufRowInputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index af0bd2e6c88..30a08b37153 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -208,7 +208,6 @@ void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); -void registerInputFormatProtobuf(FormatFactory & factory); void registerOutputFormatProtobuf(FormatFactory & factory); void registerInputFormatProcessorNative(FormatFactory & factory); @@ -263,7 +262,6 @@ FormatFactory::FormatFactory() registerOutputFormatCSV(*this); registerInputFormatTSKV(*this); registerOutputFormatTSKV(*this); - registerInputFormatProtobuf(*this); registerOutputFormatProtobuf(*this); registerInputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/ProtobufRowInputStream.cpp b/dbms/src/Formats/ProtobufRowInputStream.cpp deleted file mode 100644 index 799b53c9d6e..00000000000 --- a/dbms/src/Formats/ProtobufRowInputStream.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "config_formats.h" -#if USE_PROTOBUF - -#include "ProtobufRowInputStream.h" - -#include -#include -#include -#include -#include - - -namespace DB -{ - -ProtobufRowInputStream::ProtobufRowInputStream(ReadBuffer & in_, const Block & header, const FormatSchemaInfo & format_schema) - : data_types(header.getDataTypes()), reader(in_, ProtobufSchemas::instance().getMessageTypeForFormatSchema(format_schema), header.getNames()) -{ -} - -ProtobufRowInputStream::~ProtobufRowInputStream() = default; - -bool ProtobufRowInputStream::read(MutableColumns & columns, RowReadExtension & extra) -{ - if (!reader.startMessage()) - return false; // EOF reached, no more messages. - - // Set of columns for which the values were read. The rest will be filled with default values. - auto & read_columns = extra.read_columns; - read_columns.assign(columns.size(), false); - - // Read values from this message and put them to the columns while it's possible. - size_t column_index; - while (reader.readColumnIndex(column_index)) - { - bool allow_add_row = !static_cast(read_columns[column_index]); - do - { - bool row_added; - data_types[column_index]->deserializeProtobuf(*columns[column_index], reader, allow_add_row, row_added); - if (row_added) - { - read_columns[column_index] = true; - allow_add_row = false; - } - } while (reader.canReadMoreValues()); - } - - // Fill non-visited columns with the default values. - for (column_index = 0; column_index < read_columns.size(); ++column_index) - if (!read_columns[column_index]) - data_types[column_index]->insertDefaultInto(*columns[column_index]); - - reader.endMessage(); - return true; -} - -bool ProtobufRowInputStream::allowSyncAfterError() const -{ - return true; -} - -void ProtobufRowInputStream::syncAfterError() -{ - reader.endMessage(true); -} - - -void registerInputFormatProtobuf(FormatFactory & factory) -{ - factory.registerInputFormat("Protobuf", []( - ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, FormatSchemaInfo(context, "Protobuf")), - sample, max_block_size, rows_portion_size, callback, settings); - }); -} - -} - -#else - -namespace DB -{ -class FormatFactory; -void registerInputFormatProtobuf(FormatFactory &) {} -} - -#endif diff --git a/dbms/src/Formats/ProtobufRowInputStream.h b/dbms/src/Formats/ProtobufRowInputStream.h deleted file mode 100644 index 1dcfeaf0246..00000000000 --- a/dbms/src/Formats/ProtobufRowInputStream.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "config_formats.h" -#if USE_PROTOBUF - -#include -#include -#include - -namespace DB -{ -class Block; -class FormatSchemaInfo; - - -/** Stream designed to deserialize data from the google protobuf format. - * Each row is read as a separated message. - * These messages are delimited according to documentation - * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/util/delimited_message_util.h - * Serializing in the protobuf format requires the 'format_schema' setting to be set, e.g. - * INSERT INTO table FORMAT Protobuf SETTINGS format_schema = 'schema:Message' - * where schema is the name of "schema.proto" file specifying protobuf schema. - */ -class ProtobufRowInputStream : public IRowInputStream -{ -public: - ProtobufRowInputStream(ReadBuffer & in_, const Block & header, const FormatSchemaInfo & format_schema); - ~ProtobufRowInputStream() override; - - bool read(MutableColumns & columns, RowReadExtension & extra) override; - bool allowSyncAfterError() const override; - void syncAfterError() override; - -private: - DataTypes data_types; - ProtobufReader reader; -}; - -} -#endif diff --git a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp index 448b6b3efa1..d67bad4320c 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp @@ -75,7 +75,7 @@ void registerInputFormatProcessorProtobuf(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings &) { - return std::make_shared(buf, sample, params, FormatSchemaInfo(context, "Protobuf")); + return std::make_shared(buf, sample, std::move(params), FormatSchemaInfo(context, "Protobuf")); }); } diff --git a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.h b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.h index 77c6350d371..89ace7fec90 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.h @@ -13,7 +13,13 @@ class Block; class FormatSchemaInfo; -/** Interface of stream, that allows to read data by rows. +/** Stream designed to deserialize data from the google protobuf format. + * Each row is read as a separated message. + * These messages are delimited according to documentation + * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/util/delimited_message_util.h + * Serializing in the protobuf format requires the 'format_schema' setting to be set, e.g. + * INSERT INTO table FORMAT Protobuf SETTINGS format_schema = 'schema:Message' + * where schema is the name of "schema.proto" file specifying protobuf schema. */ class ProtobufRowInputFormat : public IRowInputFormat { From 5fb548c99454abf04917bcfea2264819d4783fd2 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:31:17 +0300 Subject: [PATCH 051/105] Remove ProtobufRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 3 - dbms/src/Formats/ProtobufRowOutputStream.cpp | 55 ------------------- dbms/src/Formats/ProtobufRowOutputStream.h | 44 --------------- ...Format.cpp => ProtobufRowOutputFormat.cpp} | 30 ++++------ ...tputFormat.h => ProtobufRowOutputFormat.h} | 11 ++-- 5 files changed, 17 insertions(+), 126 deletions(-) delete mode 100644 dbms/src/Formats/ProtobufRowOutputStream.cpp delete mode 100644 dbms/src/Formats/ProtobufRowOutputStream.h rename dbms/src/Processors/Formats/Impl/{ProtobufBlockOutputFormat.cpp => ProtobufRowOutputFormat.cpp} (56%) rename dbms/src/Processors/Formats/Impl/{ProtobufBlockOutputFormat.h => ProtobufRowOutputFormat.h} (80%) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 30a08b37153..5ef86844b67 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -207,8 +207,6 @@ void registerInputFormatCSV(FormatFactory & factory); void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); -void registerOutputFormatTSKV(FormatFactory & factory); -void registerOutputFormatProtobuf(FormatFactory & factory); void registerInputFormatProcessorNative(FormatFactory & factory); void registerOutputFormatProcessorNative(FormatFactory & factory); @@ -262,7 +260,6 @@ FormatFactory::FormatFactory() registerOutputFormatCSV(*this); registerInputFormatTSKV(*this); registerOutputFormatTSKV(*this); - registerOutputFormatProtobuf(*this); registerInputFormatProcessorNative(*this); registerOutputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/ProtobufRowOutputStream.cpp b/dbms/src/Formats/ProtobufRowOutputStream.cpp deleted file mode 100644 index dfa43a1c7e8..00000000000 --- a/dbms/src/Formats/ProtobufRowOutputStream.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include - -#include "config_formats.h" -#if USE_PROTOBUF - -#include "ProtobufRowOutputStream.h" - -#include -#include -#include -#include -#include - - -namespace DB -{ -ProtobufRowOutputStream::ProtobufRowOutputStream(WriteBuffer & out, const Block & header, const FormatSchemaInfo & format_schema) - : data_types(header.getDataTypes()), writer(out, ProtobufSchemas::instance().getMessageTypeForFormatSchema(format_schema), header.getNames()) -{ - value_indices.resize(header.columns()); -} - -void ProtobufRowOutputStream::write(const Block & block, size_t row_num) -{ - writer.startMessage(); - std::fill(value_indices.begin(), value_indices.end(), 0); - size_t column_index; - while (writer.writeField(column_index)) - data_types[column_index]->serializeProtobuf( - *block.getByPosition(column_index).column, row_num, writer, value_indices[column_index]); - writer.endMessage(); -} - - -void registerOutputFormatProtobuf(FormatFactory & factory) -{ - factory.registerOutputFormat( - "Protobuf", [](WriteBuffer & buf, const Block & header, const Context & context, const FormatSettings &) - { - return std::make_shared( - std::make_shared(buf, header, FormatSchemaInfo(context, "Protobuf")), header); - }); -} - -} - -#else - -namespace DB -{ - class FormatFactory; - void registerOutputFormatProtobuf(FormatFactory &) {} -} - -#endif diff --git a/dbms/src/Formats/ProtobufRowOutputStream.h b/dbms/src/Formats/ProtobufRowOutputStream.h deleted file mode 100644 index 2bc1ebb32c9..00000000000 --- a/dbms/src/Formats/ProtobufRowOutputStream.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace google -{ -namespace protobuf -{ - class Message; -} -} - - -namespace DB -{ -class Block; -class FormatSchemaInfo; - -/** Stream designed to serialize data in the google protobuf format. - * Each row is written as a separated message. - * These messages are delimited according to documentation - * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/util/delimited_message_util.h - * Serializing in the protobuf format requires the 'format_schema' setting to be set, e.g. - * SELECT * from table FORMAT Protobuf SETTINGS format_schema = 'schema:Message' - * where schema is the name of "schema.proto" file specifying protobuf schema. - */ -class ProtobufRowOutputStream : public IRowOutputStream -{ -public: - ProtobufRowOutputStream(WriteBuffer & out, const Block & header, const FormatSchemaInfo & format_schema); - - void write(const Block & block, size_t row_num) override; - std::string getContentType() const override { return "application/octet-stream"; } - -private: - DataTypes data_types; - ProtobufWriter writer; - std::vector value_indices; -}; - -} diff --git a/dbms/src/Processors/Formats/Impl/ProtobufBlockOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.cpp similarity index 56% rename from dbms/src/Processors/Formats/Impl/ProtobufBlockOutputFormat.cpp rename to dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.cpp index 03c8ef1b2ac..50f79dda993 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufBlockOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.cpp @@ -3,7 +3,7 @@ #include "config_formats.h" #if USE_PROTOBUF -#include +#include #include #include @@ -22,32 +22,26 @@ namespace ErrorCodes } -ProtobufBlockOutputFormat::ProtobufBlockOutputFormat( +ProtobufRowOutputFormat::ProtobufRowOutputFormat( WriteBuffer & out_, const Block & header, const FormatSchemaInfo & format_schema) - : IOutputFormat(header, out_) + : IRowOutputFormat(header, out_) , data_types(header.getDataTypes()) , writer(out, ProtobufSchemas::instance().getMessageTypeForFormatSchema(format_schema), header.getNames()) { value_indices.resize(header.columns()); } -void ProtobufBlockOutputFormat::consume(Chunk chunk) +void ProtobufRowOutputFormat::write(const Columns & columns, size_t row_num) { - auto & columns = chunk.getColumns(); - auto num_rows = chunk.getNumRows(); - - for (UInt64 row_num = 0; row_num < num_rows; ++row_num) - { - writer.startMessage(); - std::fill(value_indices.begin(), value_indices.end(), 0); - size_t column_index; - while (writer.writeField(column_index)) - data_types[column_index]->serializeProtobuf( - *columns[column_index], row_num, writer, value_indices[column_index]); - writer.endMessage(); - } + writer.startMessage(); + std::fill(value_indices.begin(), value_indices.end(), 0); + size_t column_index; + while (writer.writeField(column_index)) + data_types[column_index]->serializeProtobuf( + *columns[column_index], row_num, writer, value_indices[column_index]); + writer.endMessage(); } @@ -56,7 +50,7 @@ void registerOutputFormatProcessorProtobuf(FormatFactory & factory) factory.registerOutputFormatProcessor( "Protobuf", [](WriteBuffer & buf, const Block & header, const Context & context, const FormatSettings &) { - return std::make_shared(buf, header, FormatSchemaInfo(context, "Protobuf")); + return std::make_shared(buf, header, FormatSchemaInfo(context, "Protobuf")); }); } diff --git a/dbms/src/Processors/Formats/Impl/ProtobufBlockOutputFormat.h b/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h similarity index 80% rename from dbms/src/Processors/Formats/Impl/ProtobufBlockOutputFormat.h rename to dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h index 9cc5c7af68e..bdc6f5e2492 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufBlockOutputFormat.h +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace google @@ -29,18 +29,17 @@ namespace DB * SELECT * from table FORMAT Protobuf SETTINGS format_schema = 'schema:Message' * where schema is the name of "schema.proto" file specifying protobuf schema. */ -class ProtobufBlockOutputFormat : public IOutputFormat +class ProtobufRowOutputFormat : public IRowOutputFormat { public: - ProtobufBlockOutputFormat( + ProtobufRowOutputFormat( WriteBuffer & out_, const Block & header, const FormatSchemaInfo & format_schema); - String getName() const override { return "ProtobufBlockOutputFormat"; } - - void consume(Chunk) override; + String getName() const override { return "ProtobufRowOutputFormat"; } + void write(const Columns & columns, size_t row_num) override; std::string getContentType() const override { return "application/octet-stream"; } private: From e5d67cbe616ebd5cc6cfac1b417ac47f79b531ef Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:34:20 +0300 Subject: [PATCH 052/105] Remove ProtobufRowOutputStream. --- dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h b/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h index bdc6f5e2492..b6ca906ab83 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowOutputFormat.h @@ -40,6 +40,7 @@ public: String getName() const override { return "ProtobufRowOutputFormat"; } void write(const Columns & columns, size_t row_num) override; + void writeField(const IColumn &, const IDataType &, size_t) override {} std::string getContentType() const override { return "application/octet-stream"; } private: From afb3c20778eaab63e6a8240061ca187fa588f3ac Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:37:33 +0300 Subject: [PATCH 053/105] Remove CSVRowOutputStream. --- dbms/src/Formats/CSVRowOutputStream.cpp | 134 ------------------------ dbms/src/Formats/CSVRowOutputStream.h | 56 ---------- dbms/src/Formats/FormatFactory.cpp | 2 - 3 files changed, 192 deletions(-) delete mode 100644 dbms/src/Formats/CSVRowOutputStream.cpp delete mode 100644 dbms/src/Formats/CSVRowOutputStream.h diff --git a/dbms/src/Formats/CSVRowOutputStream.cpp b/dbms/src/Formats/CSVRowOutputStream.cpp deleted file mode 100644 index 94ed300eaf8..00000000000 --- a/dbms/src/Formats/CSVRowOutputStream.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include - -#include - - -namespace DB -{ - - -CSVRowOutputStream::CSVRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_, const FormatSettings & format_settings) - : ostr(ostr_), sample(sample_), with_names(with_names_), format_settings(format_settings) -{ - size_t columns = sample.columns(); - data_types.resize(columns); - for (size_t i = 0; i < columns; ++i) - data_types[i] = sample.safeGetByPosition(i).type; -} - - -void CSVRowOutputStream::flush() -{ - ostr.next(); -} - - -void CSVRowOutputStream::writePrefix() -{ - size_t columns = sample.columns(); - - if (with_names) - { - for (size_t i = 0; i < columns; ++i) - { - writeCSVString(sample.safeGetByPosition(i).name, ostr); - writeChar(i == columns - 1 ? '\n' : format_settings.csv.delimiter, ostr); - } - } -} - - -void CSVRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - type.serializeAsTextCSV(column, row_num, ostr, format_settings); -} - - -void CSVRowOutputStream::writeFieldDelimiter() -{ - writeChar(format_settings.csv.delimiter, ostr); -} - - -void CSVRowOutputStream::writeRowEndDelimiter() -{ - writeChar('\n', ostr); -} - - -void CSVRowOutputStream::writeSuffix() -{ - writeTotals(); - writeExtremes(); -} - - -void CSVRowOutputStream::writeTotals() -{ - if (totals) - { - size_t columns = totals.columns(); - - writeChar('\n', ostr); - writeRowStartDelimiter(); - - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeFieldDelimiter(); - writeField(*totals.getByPosition(j).column.get(), *totals.getByPosition(j).type.get(), 0); - } - - writeRowEndDelimiter(); - } -} - - -void CSVRowOutputStream::writeExtremes() -{ - if (extremes) - { - size_t rows = extremes.rows(); - size_t columns = extremes.columns(); - - writeChar('\n', ostr); - - for (size_t i = 0; i < rows; ++i) - { - if (i != 0) - writeRowBetweenDelimiter(); - - writeRowStartDelimiter(); - - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeFieldDelimiter(); - writeField(*extremes.getByPosition(j).column.get(), *extremes.getByPosition(j).type.get(), i); - } - - writeRowEndDelimiter(); - } - } -} - - -void registerOutputFormatCSV(FormatFactory & factory) -{ - for (bool with_names : {false, true}) - { - factory.registerOutputFormat(with_names ? "CSVWithNames" : "CSV", [=]( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & format_settings) - { - return std::make_shared( - std::make_shared(buf, sample, with_names, format_settings), sample); - }); - } -} - -} diff --git a/dbms/src/Formats/CSVRowOutputStream.h b/dbms/src/Formats/CSVRowOutputStream.h deleted file mode 100644 index ab4bb3a503b..00000000000 --- a/dbms/src/Formats/CSVRowOutputStream.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace DB -{ - -class WriteBuffer; - - -/** The stream for outputting data in csv format. - * Does not conform with https://tools.ietf.org/html/rfc4180 because it uses LF, not CR LF. - */ -class CSVRowOutputStream : public IRowOutputStream -{ -public: - /** with_names - output in the first line a header with column names - * with_types - output in the next line header with the names of the types - */ - CSVRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_, const FormatSettings & format_settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeFieldDelimiter() override; - void writeRowEndDelimiter() override; - void writePrefix() override; - void writeSuffix() override; - - void flush() override; - - void setTotals(const Block & totals_) override { totals = totals_; } - void setExtremes(const Block & extremes_) override { extremes = extremes_; } - - /// https://www.iana.org/assignments/media-types/text/csv - String getContentType() const override - { - return String("text/csv; charset=UTF-8; header=") + (with_names ? "present" : "absent"); - } - -protected: - void writeTotals(); - void writeExtremes(); - - WriteBuffer & ostr; - const Block sample; - bool with_names; - const FormatSettings format_settings; - DataTypes data_types; - Block totals; - Block extremes; -}; - -} - diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 5ef86844b67..ff9607249c4 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -204,7 +204,6 @@ void registerOutputFormatTabSeparated(FormatFactory & factory); void registerInputFormatValues(FormatFactory & factory); void registerOutputFormatValues(FormatFactory & factory); void registerInputFormatCSV(FormatFactory & factory); -void registerOutputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); void registerOutputFormatTSKV(FormatFactory & factory); @@ -257,7 +256,6 @@ FormatFactory::FormatFactory() registerInputFormatValues(*this); registerOutputFormatValues(*this); registerInputFormatCSV(*this); - registerOutputFormatCSV(*this); registerInputFormatTSKV(*this); registerOutputFormatTSKV(*this); From f809de0949edd9eaf94c371e519ad3851cd08a61 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:48:50 +0300 Subject: [PATCH 054/105] Remove TabSeparatedRowOutputStream and TSKVRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 4 - dbms/src/Formats/TSKVRowOutputStream.cpp | 56 ------ dbms/src/Formats/TSKVRowOutputStream.h | 27 --- .../Formats/TabSeparatedRowOutputStream.cpp | 179 ------------------ .../src/Formats/TabSeparatedRowOutputStream.h | 51 ----- .../Formats/tests/block_row_transforms.cpp | 7 +- .../Formats/tests/tab_separated_streams.cpp | 10 +- 7 files changed, 10 insertions(+), 324 deletions(-) delete mode 100644 dbms/src/Formats/TSKVRowOutputStream.cpp delete mode 100644 dbms/src/Formats/TSKVRowOutputStream.h delete mode 100644 dbms/src/Formats/TabSeparatedRowOutputStream.cpp delete mode 100644 dbms/src/Formats/TabSeparatedRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index ff9607249c4..c0ca5ffacd0 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -200,12 +200,10 @@ void FormatFactory::registerOutputFormatProcessor(const String & name, OutputPro void registerInputFormatNative(FormatFactory & factory); void registerOutputFormatNative(FormatFactory & factory); void registerInputFormatTabSeparated(FormatFactory & factory); -void registerOutputFormatTabSeparated(FormatFactory & factory); void registerInputFormatValues(FormatFactory & factory); void registerOutputFormatValues(FormatFactory & factory); void registerInputFormatCSV(FormatFactory & factory); void registerInputFormatTSKV(FormatFactory & factory); -void registerOutputFormatTSKV(FormatFactory & factory); void registerInputFormatProcessorNative(FormatFactory & factory); void registerOutputFormatProcessorNative(FormatFactory & factory); @@ -252,12 +250,10 @@ FormatFactory::FormatFactory() registerInputFormatNative(*this); registerOutputFormatNative(*this); registerInputFormatTabSeparated(*this); - registerOutputFormatTabSeparated(*this); registerInputFormatValues(*this); registerOutputFormatValues(*this); registerInputFormatCSV(*this); registerInputFormatTSKV(*this); - registerOutputFormatTSKV(*this); registerInputFormatProcessorNative(*this); registerOutputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/TSKVRowOutputStream.cpp b/dbms/src/Formats/TSKVRowOutputStream.cpp deleted file mode 100644 index edf952b45e3..00000000000 --- a/dbms/src/Formats/TSKVRowOutputStream.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include - - - -namespace DB -{ - -TSKVRowOutputStream::TSKVRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & format_settings_) - : TabSeparatedRowOutputStream(ostr_, sample_, false, false, format_settings_) -{ - NamesAndTypesList columns(sample_.getNamesAndTypesList()); - fields.assign(columns.begin(), columns.end()); - - for (auto & field : fields) - { - WriteBufferFromOwnString wb; - writeAnyEscapedString<'='>(field.name.data(), field.name.data() + field.name.size(), wb); - writeCString("=", wb); - field.name = wb.str(); - } -} - - -void TSKVRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - writeString(fields[field_number].name, ostr); - type.serializeAsTextEscaped(column, row_num, ostr, format_settings); - ++field_number; -} - - -void TSKVRowOutputStream::writeRowEndDelimiter() -{ - writeChar('\n', ostr); - field_number = 0; -} - - -void registerOutputFormatTSKV(FormatFactory & factory) -{ - factory.registerOutputFormat("TSKV", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/TSKVRowOutputStream.h b/dbms/src/Formats/TSKVRowOutputStream.h deleted file mode 100644 index 3a2ee8b8291..00000000000 --- a/dbms/src/Formats/TSKVRowOutputStream.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - - -namespace DB -{ - -/** The stream for outputting data in the TSKV format. - * TSKV is similar to TabSeparated, but before every value, its name and equal sign are specified: name=value. - * This format is very inefficient. - */ -class TSKVRowOutputStream : public TabSeparatedRowOutputStream -{ -public: - TSKVRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & format_settings); - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeRowEndDelimiter() override; - -protected: - NamesAndTypes fields; - size_t field_number = 0; -}; - -} - diff --git a/dbms/src/Formats/TabSeparatedRowOutputStream.cpp b/dbms/src/Formats/TabSeparatedRowOutputStream.cpp deleted file mode 100644 index dca1207dd24..00000000000 --- a/dbms/src/Formats/TabSeparatedRowOutputStream.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include -#include - -#include - - -namespace DB -{ - -TabSeparatedRowOutputStream::TabSeparatedRowOutputStream( - WriteBuffer & ostr_, const Block & sample_, bool with_names_, bool with_types_, const FormatSettings & format_settings) - : ostr(ostr_), sample(sample_), with_names(with_names_), with_types(with_types_), format_settings(format_settings) -{ -} - - -void TabSeparatedRowOutputStream::flush() -{ - ostr.next(); -} - - -void TabSeparatedRowOutputStream::writePrefix() -{ - size_t columns = sample.columns(); - - if (with_names) - { - for (size_t i = 0; i < columns; ++i) - { - writeEscapedString(sample.safeGetByPosition(i).name, ostr); - writeChar(i == columns - 1 ? '\n' : '\t', ostr); - } - } - - if (with_types) - { - for (size_t i = 0; i < columns; ++i) - { - writeEscapedString(sample.safeGetByPosition(i).type->getName(), ostr); - writeChar(i == columns - 1 ? '\n' : '\t', ostr); - } - } -} - - -void TabSeparatedRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - type.serializeAsTextEscaped(column, row_num, ostr, format_settings); -} - - -void TabSeparatedRowOutputStream::writeFieldDelimiter() -{ - writeChar('\t', ostr); -} - - -void TabSeparatedRowOutputStream::writeRowEndDelimiter() -{ - writeChar('\n', ostr); -} - - -void TabSeparatedRowOutputStream::writeSuffix() -{ - writeTotals(); - writeExtremes(); -} - - -void TabSeparatedRowOutputStream::writeTotals() -{ - if (totals) - { - size_t columns = totals.columns(); - - writeChar('\n', ostr); - writeRowStartDelimiter(); - - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeFieldDelimiter(); - writeField(*totals.getByPosition(j).column.get(), *totals.getByPosition(j).type.get(), 0); - } - - writeRowEndDelimiter(); - } -} - - -void TabSeparatedRowOutputStream::writeExtremes() -{ - if (extremes) - { - size_t rows = extremes.rows(); - size_t columns = extremes.columns(); - - writeChar('\n', ostr); - - for (size_t i = 0; i < rows; ++i) - { - if (i != 0) - writeRowBetweenDelimiter(); - - writeRowStartDelimiter(); - - for (size_t j = 0; j < columns; ++j) - { - if (j != 0) - writeFieldDelimiter(); - writeField(*extremes.getByPosition(j).column.get(), *extremes.getByPosition(j).type.get(), i); - } - - writeRowEndDelimiter(); - } - } -} - - -void registerOutputFormatTabSeparated(FormatFactory & factory) -{ - for (auto name : {"TabSeparated", "TSV"}) - { - factory.registerOutputFormat(name, []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, false, false, settings), sample); - }); - } - - for (auto name : {"TabSeparatedRaw", "TSVRaw"}) - { - factory.registerOutputFormat(name, []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, false, false, settings), sample); - }); - } - - for (auto name : {"TabSeparatedWithNames", "TSVWithNames"}) - { - factory.registerOutputFormat(name, []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, true, false, settings), sample); - }); - } - - for (auto name : {"TabSeparatedWithNamesAndTypes", "TSVWithNamesAndTypes"}) - { - factory.registerOutputFormat(name, []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, true, true, settings), sample); - }); - } -} - -} diff --git a/dbms/src/Formats/TabSeparatedRowOutputStream.h b/dbms/src/Formats/TabSeparatedRowOutputStream.h deleted file mode 100644 index 31d03a4a7e7..00000000000 --- a/dbms/src/Formats/TabSeparatedRowOutputStream.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace DB -{ - -class WriteBuffer; - -/** A stream for outputting data in tsv format. - */ -class TabSeparatedRowOutputStream : public IRowOutputStream -{ -public: - /** with_names - output in the first line a header with column names - * with_types - output the next line header with the names of the types - */ - TabSeparatedRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_, bool with_types_, const FormatSettings & format_settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeFieldDelimiter() override; - void writeRowEndDelimiter() override; - void writePrefix() override; - void writeSuffix() override; - - void flush() override; - - void setTotals(const Block & totals_) override { totals = totals_; } - void setExtremes(const Block & extremes_) override { extremes = extremes_; } - - /// https://www.iana.org/assignments/media-types/text/tab-separated-values - String getContentType() const override { return "text/tab-separated-values; charset=UTF-8"; } - -protected: - void writeTotals(); - void writeExtremes(); - - WriteBuffer & ostr; - const Block sample; - bool with_names; - bool with_types; - const FormatSettings format_settings; - Block totals; - Block extremes; -}; - -} - diff --git a/dbms/src/Formats/tests/block_row_transforms.cpp b/dbms/src/Formats/tests/block_row_transforms.cpp index 9d38a37f833..092b30405d2 100644 --- a/dbms/src/Formats/tests/block_row_transforms.cpp +++ b/dbms/src/Formats/tests/block_row_transforms.cpp @@ -18,6 +18,8 @@ #include #include +#include +#include int main(int, char **) @@ -46,10 +48,9 @@ try RowInputStreamPtr row_input = std::make_shared(in_buf, sample, false, false, format_settings); BlockInputStreamFromRowInputStream block_input(row_input, sample, DEFAULT_INSERT_BLOCK_SIZE, 0, []{}, format_settings); - RowOutputStreamPtr row_output = std::make_shared(out_buf, sample, false, false, format_settings); - BlockOutputStreamFromRowOutputStream block_output(row_output, sample); + BlockOutputStreamPtr block_output = std::make_shared(std::make_shared(out_buf, sample, false, false, format_settings), sample); - copyData(block_input, block_output); + copyData(block_input, *block_output); } catch (const DB::Exception & e) { diff --git a/dbms/src/Formats/tests/tab_separated_streams.cpp b/dbms/src/Formats/tests/tab_separated_streams.cpp index 11895699c3b..64fd5fac35d 100644 --- a/dbms/src/Formats/tests/tab_separated_streams.cpp +++ b/dbms/src/Formats/tests/tab_separated_streams.cpp @@ -15,6 +15,8 @@ #include #include +#include +#include using namespace DB; @@ -40,12 +42,12 @@ try FormatSettings format_settings; RowInputStreamPtr row_input = std::make_shared(in_buf, sample, false, false, format_settings); - RowOutputStreamPtr row_output = std::make_shared(out_buf, sample, false, false, format_settings); - BlockInputStreamFromRowInputStream block_input(row_input, sample, DEFAULT_INSERT_BLOCK_SIZE, 0, []{}, format_settings); - BlockOutputStreamFromRowOutputStream block_output(row_output, sample); - copyData(block_input, block_output); + BlockOutputStreamPtr block_output = std::make_shared( + std::make_shared(out_buf, sample, false, false, format_settings), sample); + + copyData(block_input, *block_output); return 0; } catch (...) From 6ab2e194105dfb64811865785cc149a6bdbdda75 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:51:33 +0300 Subject: [PATCH 055/105] Remove TSKVRowInputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/TSKVRowInputStream.cpp | 211 ------------------------ dbms/src/Formats/TSKVRowInputStream.h | 48 ------ 3 files changed, 261 deletions(-) delete mode 100644 dbms/src/Formats/TSKVRowInputStream.cpp delete mode 100644 dbms/src/Formats/TSKVRowInputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index c0ca5ffacd0..65b0c283327 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -203,7 +203,6 @@ void registerInputFormatTabSeparated(FormatFactory & factory); void registerInputFormatValues(FormatFactory & factory); void registerOutputFormatValues(FormatFactory & factory); void registerInputFormatCSV(FormatFactory & factory); -void registerInputFormatTSKV(FormatFactory & factory); void registerInputFormatProcessorNative(FormatFactory & factory); void registerOutputFormatProcessorNative(FormatFactory & factory); @@ -253,7 +252,6 @@ FormatFactory::FormatFactory() registerInputFormatValues(*this); registerOutputFormatValues(*this); registerInputFormatCSV(*this); - registerInputFormatTSKV(*this); registerInputFormatProcessorNative(*this); registerOutputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/TSKVRowInputStream.cpp b/dbms/src/Formats/TSKVRowInputStream.cpp deleted file mode 100644 index d86ee22bc4b..00000000000 --- a/dbms/src/Formats/TSKVRowInputStream.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include -#include - - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int INCORRECT_DATA; - extern const int CANNOT_PARSE_ESCAPE_SEQUENCE; - extern const int CANNOT_READ_ALL_DATA; - extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; -} - - -TSKVRowInputStream::TSKVRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSettings & format_settings) - : istr(istr_), header(header_), format_settings(format_settings), name_map(header.columns()) -{ - /// In this format, we assume that column name cannot contain BOM, - /// so BOM at beginning of stream cannot be confused with name of field, and it is safe to skip it. - skipBOMIfExists(istr); - - size_t num_columns = header.columns(); - for (size_t i = 0; i < num_columns; ++i) - name_map[header.safeGetByPosition(i).name] = i; /// NOTE You could place names more cache-locally. -} - - -/** Read the field name in the `tskv` format. - * Return true if the field is followed by an equal sign, - * otherwise (field with no value) return false. - * The reference to the field name will be written to `ref`. - * A temporary `tmp` buffer can also be used to copy the field name to it. - * When reading, skips the name and the equal sign after it. - */ -static bool readName(ReadBuffer & buf, StringRef & ref, String & tmp) -{ - tmp.clear(); - - while (!buf.eof()) - { - const char * next_pos = find_first_symbols<'\t', '\n', '\\', '='>(buf.position(), buf.buffer().end()); - - if (next_pos == buf.buffer().end()) - { - tmp.append(buf.position(), next_pos - buf.position()); - buf.next(); - continue; - } - - /// Came to the end of the name. - if (*next_pos != '\\') - { - bool have_value = *next_pos == '='; - if (tmp.empty()) - { - /// No need to copy data, you can refer directly to the `buf`. - ref = StringRef(buf.position(), next_pos - buf.position()); - buf.position() += next_pos + have_value - buf.position(); - } - else - { - /// Copy the data to a temporary string and return a reference to it. - tmp.append(buf.position(), next_pos - buf.position()); - buf.position() += next_pos + have_value - buf.position(); - ref = StringRef(tmp); - } - return have_value; - } - /// The name has an escape sequence. - else - { - tmp.append(buf.position(), next_pos - buf.position()); - buf.position() += next_pos + 1 - buf.position(); - if (buf.eof()) - throw Exception("Cannot parse escape sequence", ErrorCodes::CANNOT_PARSE_ESCAPE_SEQUENCE); - - tmp.push_back(parseEscapeSequence(*buf.position())); - ++buf.position(); - continue; - } - } - - throw Exception("Unexpected end of stream while reading key name from TSKV format", ErrorCodes::CANNOT_READ_ALL_DATA); -} - - -bool TSKVRowInputStream::read(MutableColumns & columns, RowReadExtension & ext) -{ - if (istr.eof()) - return false; - - size_t num_columns = columns.size(); - - /// Set of columns for which the values were read. The rest will be filled with default values. - read_columns.assign(num_columns, false); - - if (unlikely(*istr.position() == '\n')) - { - /// An empty string. It is permissible, but it is unclear why. - ++istr.position(); - } - else - { - while (true) - { - StringRef name_ref; - bool has_value = readName(istr, name_ref, name_buf); - ssize_t index = -1; - - if (has_value) - { - /// NOTE Optimization is possible by caching the order of fields (which is almost always the same) - /// and quickly checking for the next expected field, instead of searching the hash table. - - auto it = name_map.find(name_ref); - if (name_map.end() == it) - { - if (!format_settings.skip_unknown_fields) - throw Exception("Unknown field found while parsing TSKV format: " + name_ref.toString(), ErrorCodes::INCORRECT_DATA); - - /// If the key is not found, skip the value. - NullSink sink; - readEscapedStringInto(sink, istr); - } - else - { - index = it->getSecond(); - - if (read_columns[index]) - throw Exception("Duplicate field found while parsing TSKV format: " + name_ref.toString(), ErrorCodes::INCORRECT_DATA); - - read_columns[index] = true; - - header.getByPosition(index).type->deserializeAsTextEscaped(*columns[index], istr, format_settings); - } - } - else - { - /// The only thing that can go without value is `tskv` fragment that is ignored. - if (!(name_ref.size == 4 && 0 == memcmp(name_ref.data, "tskv", 4))) - throw Exception("Found field without value while parsing TSKV format: " + name_ref.toString(), ErrorCodes::INCORRECT_DATA); - } - - if (istr.eof()) - { - throw Exception("Unexpected end of stream after field in TSKV format: " + name_ref.toString(), ErrorCodes::CANNOT_READ_ALL_DATA); - } - else if (*istr.position() == '\t') - { - ++istr.position(); - continue; - } - else if (*istr.position() == '\n') - { - ++istr.position(); - break; - } - else - { - /// Possibly a garbage was written into column, remove it - if (index >= 0) - { - columns[index]->popBack(1); - read_columns[index] = false; - } - - throw Exception("Found garbage after field in TSKV format: " + name_ref.toString(), ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED); - } - } - } - - /// Fill in the not met columns with default values. - for (size_t i = 0; i < num_columns; ++i) - if (!read_columns[i]) - header.getByPosition(i).type->insertDefaultInto(*columns[i]); - - /// return info about defaults set - ext.read_columns = read_columns; - - return true; -} - - -void TSKVRowInputStream::syncAfterError() -{ - skipToUnescapedNextLineOrEOF(istr); -} - - -void registerInputFormatTSKV(FormatFactory & factory) -{ - factory.registerInputFormat("TSKV", []( - ReadBuffer & buf, - const Block & sample, - const Context &, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, settings), - sample, max_block_size, rows_portion_size, callback, settings); - }); -} - -} diff --git a/dbms/src/Formats/TSKVRowInputStream.h b/dbms/src/Formats/TSKVRowInputStream.h deleted file mode 100644 index ada2ba3ed66..00000000000 --- a/dbms/src/Formats/TSKVRowInputStream.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include - - -namespace DB -{ - -class ReadBuffer; - - -/** Stream for reading data in TSKV format. - * TSKV is a very inefficient data format. - * Similar to TSV, but each field is written as key=value. - * Fields can be listed in any order (including, in different lines there may be different order), - * and some fields may be missing. - * An equal sign can be escaped in the field name. - * Also, as an additional element there may be a useless tskv fragment - it needs to be ignored. - */ -class TSKVRowInputStream : public IRowInputStream -{ -public: - TSKVRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSettings & format_settings); - - bool read(MutableColumns & columns, RowReadExtension &) override; - bool allowSyncAfterError() const override { return true; } - void syncAfterError() override; - -private: - ReadBuffer & istr; - Block header; - - const FormatSettings format_settings; - - /// Buffer for the read from the stream the field name. Used when you have to copy it. - String name_buf; - - /// Hash table matching `field name -> position in the block`. NOTE You can use perfect hash map. - using NameMap = HashMap; - NameMap name_map; - - std::vector read_columns; -}; - -} From ab914010e15d1e06f5d87310b6b5532f60910465 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:56:16 +0300 Subject: [PATCH 056/105] Remove TSKVRowInputStream. --- dbms/src/IO/tests/write_buffer_aio.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/src/IO/tests/write_buffer_aio.cpp b/dbms/src/IO/tests/write_buffer_aio.cpp index 5794e277848..9274e5abee5 100644 --- a/dbms/src/IO/tests/write_buffer_aio.cpp +++ b/dbms/src/IO/tests/write_buffer_aio.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace { From 422b593570a02644c76e636469515e0ceb7fcf49 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:56:52 +0300 Subject: [PATCH 057/105] Remove TSKVRowInputStream. --- dbms/src/Formats/tests/tab_separated_streams.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/src/Formats/tests/tab_separated_streams.cpp b/dbms/src/Formats/tests/tab_separated_streams.cpp index 64fd5fac35d..e3bc551f6da 100644 --- a/dbms/src/Formats/tests/tab_separated_streams.cpp +++ b/dbms/src/Formats/tests/tab_separated_streams.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include From c336c514fbc9a76eece3dddd48a30d75f476ff8d Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:58:52 +0300 Subject: [PATCH 058/105] Remove TSKVRowInputStream. --- dbms/programs/odbc-bridge/MainHandler.cpp | 1 - dbms/src/Formats/tests/block_row_transforms.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/dbms/programs/odbc-bridge/MainHandler.cpp b/dbms/programs/odbc-bridge/MainHandler.cpp index cb5dfa70c9c..162e93dc3db 100644 --- a/dbms/programs/odbc-bridge/MainHandler.cpp +++ b/dbms/programs/odbc-bridge/MainHandler.cpp @@ -5,7 +5,6 @@ #include #include #include "ODBCBlockInputStream.h" -#include #include #include #include diff --git a/dbms/src/Formats/tests/block_row_transforms.cpp b/dbms/src/Formats/tests/block_row_transforms.cpp index 092b30405d2..c580f9af392 100644 --- a/dbms/src/Formats/tests/block_row_transforms.cpp +++ b/dbms/src/Formats/tests/block_row_transforms.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include From f820fff7942747675536e7e63b4d52a984118456 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 19:59:50 +0300 Subject: [PATCH 059/105] Remove TSKVRowInputStream. --- dbms/src/Formats/tests/tab_separated_streams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Formats/tests/tab_separated_streams.cpp b/dbms/src/Formats/tests/tab_separated_streams.cpp index e3bc551f6da..bb5e657229d 100644 --- a/dbms/src/Formats/tests/tab_separated_streams.cpp +++ b/dbms/src/Formats/tests/tab_separated_streams.cpp @@ -44,7 +44,7 @@ try BlockInputStreamFromRowInputStream block_input(row_input, sample, DEFAULT_INSERT_BLOCK_SIZE, 0, []{}, format_settings); BlockOutputStreamPtr block_output = std::make_shared( - std::make_shared(out_buf, sample, false, false, format_settings), sample); + std::make_shared(out_buf, sample, false, false, format_settings)); copyData(block_input, *block_output); return 0; From e6b3f3f03acb6ff430be82ffe8ac77c520fc3b5f Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 20:00:38 +0300 Subject: [PATCH 060/105] Remove TSKVRowInputStream. --- dbms/src/Formats/tests/block_row_transforms.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Formats/tests/block_row_transforms.cpp b/dbms/src/Formats/tests/block_row_transforms.cpp index c580f9af392..b2fe876fb2a 100644 --- a/dbms/src/Formats/tests/block_row_transforms.cpp +++ b/dbms/src/Formats/tests/block_row_transforms.cpp @@ -47,7 +47,7 @@ try RowInputStreamPtr row_input = std::make_shared(in_buf, sample, false, false, format_settings); BlockInputStreamFromRowInputStream block_input(row_input, sample, DEFAULT_INSERT_BLOCK_SIZE, 0, []{}, format_settings); - BlockOutputStreamPtr block_output = std::make_shared(std::make_shared(out_buf, sample, false, false, format_settings), sample); + BlockOutputStreamPtr block_output = std::make_shared(std::make_shared(out_buf, sample, false, false, format_settings)); copyData(block_input, *block_output); } From 1f6a16b03a92cdf5d531e805a4d62bcb16565b17 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 20:16:58 +0300 Subject: [PATCH 061/105] Remove ValuesRowInputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - .../Formats/TabSeparatedRawRowOutputStream.h | 25 --- dbms/src/Formats/ValuesRowInputStream.cpp | 168 ------------------ dbms/src/Formats/ValuesRowInputStream.h | 35 ---- .../Formats/Impl/ValuesRowInputFormat.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 11 +- 6 files changed, 6 insertions(+), 237 deletions(-) delete mode 100644 dbms/src/Formats/TabSeparatedRawRowOutputStream.h delete mode 100644 dbms/src/Formats/ValuesRowInputStream.cpp delete mode 100644 dbms/src/Formats/ValuesRowInputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 65b0c283327..c38767a3055 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -200,7 +200,6 @@ void FormatFactory::registerOutputFormatProcessor(const String & name, OutputPro void registerInputFormatNative(FormatFactory & factory); void registerOutputFormatNative(FormatFactory & factory); void registerInputFormatTabSeparated(FormatFactory & factory); -void registerInputFormatValues(FormatFactory & factory); void registerOutputFormatValues(FormatFactory & factory); void registerInputFormatCSV(FormatFactory & factory); @@ -249,7 +248,6 @@ FormatFactory::FormatFactory() registerInputFormatNative(*this); registerOutputFormatNative(*this); registerInputFormatTabSeparated(*this); - registerInputFormatValues(*this); registerOutputFormatValues(*this); registerInputFormatCSV(*this); diff --git a/dbms/src/Formats/TabSeparatedRawRowOutputStream.h b/dbms/src/Formats/TabSeparatedRawRowOutputStream.h deleted file mode 100644 index 86eaa2bbb58..00000000000 --- a/dbms/src/Formats/TabSeparatedRawRowOutputStream.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -namespace DB -{ -struct FormatSettings; - -/** A stream for outputting data in tsv format, but without escaping individual values. - * (That is, the output is irreversible.) - */ -class TabSeparatedRawRowOutputStream : public TabSeparatedRowOutputStream -{ -public: - TabSeparatedRawRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_, bool with_types_, const FormatSettings & format_settings_) - : TabSeparatedRowOutputStream(ostr_, sample_, with_names_, with_types_, format_settings_) {} - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override - { - type.serializeAsText(column, row_num, ostr, format_settings); - } -}; - -} - diff --git a/dbms/src/Formats/ValuesRowInputStream.cpp b/dbms/src/Formats/ValuesRowInputStream.cpp deleted file mode 100644 index 33799a95549..00000000000 --- a/dbms/src/Formats/ValuesRowInputStream.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; - extern const int CANNOT_PARSE_QUOTED_STRING; - extern const int CANNOT_PARSE_NUMBER; - extern const int CANNOT_PARSE_DATE; - extern const int CANNOT_PARSE_DATETIME; - extern const int CANNOT_READ_ARRAY_FROM_TEXT; - extern const int CANNOT_PARSE_DATE; - extern const int SYNTAX_ERROR; - extern const int VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE; -} - - -ValuesRowInputStream::ValuesRowInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_, const FormatSettings & format_settings) - : istr(istr_), header(header_), context(std::make_unique(context_)), format_settings(format_settings) -{ - /// In this format, BOM at beginning of stream cannot be confused with value, so it is safe to skip it. - skipBOMIfExists(istr); -} - - -bool ValuesRowInputStream::read(MutableColumns & columns, RowReadExtension &) -{ - size_t num_columns = columns.size(); - - skipWhitespaceIfAny(istr); - - if (istr.eof() || *istr.position() == ';') - return false; - - /** Typically, this is the usual format for streaming parsing. - * But as an exception, it also supports processing arbitrary expressions instead of values. - * This is very inefficient. But if there are no expressions, then there is no overhead. - */ - ParserExpression parser; - - assertChar('(', istr); - - for (size_t i = 0; i < num_columns; ++i) - { - skipWhitespaceIfAny(istr); - - char * prev_istr_position = istr.position(); - size_t prev_istr_bytes = istr.count() - istr.offset(); - - bool rollback_on_exception = false; - try - { - header.getByPosition(i).type->deserializeAsTextQuoted(*columns[i], istr, format_settings); - rollback_on_exception = true; - skipWhitespaceIfAny(istr); - - if (i != num_columns - 1) - assertChar(',', istr); - else - assertChar(')', istr); - } - catch (const Exception & e) - { - if (!format_settings.values.interpret_expressions) - throw; - - /** The normal streaming parser could not parse the value. - * Let's try to parse it with a SQL parser as a constant expression. - * This is an exceptional case. - */ - if (e.code() == ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED - || e.code() == ErrorCodes::CANNOT_PARSE_QUOTED_STRING - || e.code() == ErrorCodes::CANNOT_PARSE_NUMBER - || e.code() == ErrorCodes::CANNOT_PARSE_DATE - || e.code() == ErrorCodes::CANNOT_PARSE_DATETIME - || e.code() == ErrorCodes::CANNOT_READ_ARRAY_FROM_TEXT) - { - /// TODO Case when the expression does not fit entirely in the buffer. - - /// If the beginning of the value is no longer in the buffer. - if (istr.count() - istr.offset() != prev_istr_bytes) - throw; - - if (rollback_on_exception) - columns[i]->popBack(1); - - const IDataType & type = *header.getByPosition(i).type; - - Expected expected; - - Tokens tokens(prev_istr_position, istr.buffer().end()); - TokenIterator token_iterator(tokens); - - ASTPtr ast; - if (!parser.parse(token_iterator, ast, expected)) - throw Exception("Cannot parse expression of type " + type.getName() + " here: " - + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)), - ErrorCodes::SYNTAX_ERROR); - - istr.position() = const_cast(token_iterator->begin); - - std::pair value_raw = evaluateConstantExpression(ast, *context); - Field value = convertFieldToType(value_raw.first, type, value_raw.second.get()); - - /// Check that we are indeed allowed to insert a NULL. - if (value.isNull()) - { - if (!type.isNullable()) - throw Exception{"Expression returns value " + applyVisitor(FieldVisitorToString(), value) - + ", that is out of range of type " + type.getName() - + ", at: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)), - ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE}; - } - - columns[i]->insert(value); - - skipWhitespaceIfAny(istr); - - if (i != num_columns - 1) - assertChar(',', istr); - else - assertChar(')', istr); - } - else - throw; - } - } - - skipWhitespaceIfAny(istr); - if (!istr.eof() && *istr.position() == ',') - ++istr.position(); - - return true; -} - - -void registerInputFormatValues(FormatFactory & factory) -{ - factory.registerInputFormat("Values", []( - ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, context, settings), - sample, max_block_size, rows_portion_size, callback, settings); - }); -} - -} diff --git a/dbms/src/Formats/ValuesRowInputStream.h b/dbms/src/Formats/ValuesRowInputStream.h deleted file mode 100644 index 372619d4e27..00000000000 --- a/dbms/src/Formats/ValuesRowInputStream.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace DB -{ - -class Context; -class ReadBuffer; - - -/** Stream to read data in VALUES format (as in INSERT query). - */ -class ValuesRowInputStream : public IRowInputStream -{ -public: - /** Data is parsed using fast, streaming parser. - * If interpret_expressions is true, it will, in addition, try to use SQL parser and interpreter - * in case when streaming parser could not parse field (this is very slow). - */ - ValuesRowInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_, const FormatSettings & format_settings); - - bool read(MutableColumns & columns, RowReadExtension &) override; - -private: - ReadBuffer & istr; - Block header; - std::unique_ptr context; /// pimpl - const FormatSettings format_settings; -}; - -} diff --git a/dbms/src/Processors/Formats/Impl/ValuesRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/ValuesRowInputFormat.cpp index 7b0287596ad..337085198a3 100644 --- a/dbms/src/Processors/Formats/Impl/ValuesRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ValuesRowInputFormat.cpp @@ -159,7 +159,7 @@ void registerInputFormatProcessorValues(FormatFactory & factory) IRowInputFormat::Params params, const FormatSettings & settings) { - return std::make_shared(buf, sample, params, context, settings); + return std::make_shared(buf, sample, std::move(params), context, settings); }); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index b32470f9f77..dfc59654629 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -2488,17 +2488,16 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, const Context ReadBufferFromMemory right_paren_buf(")", 1); ConcatReadBuffer buf({&left_paren_buf, &fields_buf, &right_paren_buf}); - ValuesRowInputStream input_stream(buf, partition_key_sample, context, format_settings); - MutableColumns columns = partition_key_sample.cloneEmptyColumns(); + auto input_stream = FormatFactory::instance().getInput("Values", buf, partition_key_sample, context, context.getSettingsRef().max_block_size); - RowReadExtension unused; - if (!input_stream.read(columns, unused)) + auto block = input_stream->read(); + if (!block || !block.rows()) throw Exception( "Could not parse partition value: `" + partition_ast.fields_str.toString() + "`", ErrorCodes::INVALID_PARTITION_VALUE); for (size_t i = 0; i < fields_count; ++i) - columns[i]->get(0, partition_row[i]); + block.getByPosition(i).column->get(0, partition_row[i]); } MergeTreePartition partition(std::move(partition_row)); From 6234cb865a828b267ddb0141a1bd093e1c8fc042 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 20:19:10 +0300 Subject: [PATCH 062/105] Remove ValuesRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/ValuesRowOutputStream.cpp | 63 ---------------------- dbms/src/Formats/ValuesRowOutputStream.h | 33 ------------ 3 files changed, 98 deletions(-) delete mode 100644 dbms/src/Formats/ValuesRowOutputStream.cpp delete mode 100644 dbms/src/Formats/ValuesRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index c38767a3055..4e71f6042fb 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -200,7 +200,6 @@ void FormatFactory::registerOutputFormatProcessor(const String & name, OutputPro void registerInputFormatNative(FormatFactory & factory); void registerOutputFormatNative(FormatFactory & factory); void registerInputFormatTabSeparated(FormatFactory & factory); -void registerOutputFormatValues(FormatFactory & factory); void registerInputFormatCSV(FormatFactory & factory); void registerInputFormatProcessorNative(FormatFactory & factory); @@ -248,7 +247,6 @@ FormatFactory::FormatFactory() registerInputFormatNative(*this); registerOutputFormatNative(*this); registerInputFormatTabSeparated(*this); - registerOutputFormatValues(*this); registerInputFormatCSV(*this); registerInputFormatProcessorNative(*this); diff --git a/dbms/src/Formats/ValuesRowOutputStream.cpp b/dbms/src/Formats/ValuesRowOutputStream.cpp deleted file mode 100644 index eacc7e31eba..00000000000 --- a/dbms/src/Formats/ValuesRowOutputStream.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include - -#include -#include -#include - - -namespace DB -{ - - -ValuesRowOutputStream::ValuesRowOutputStream(WriteBuffer & ostr_, const FormatSettings & format_settings) - : ostr(ostr_), format_settings(format_settings) -{ -} - -void ValuesRowOutputStream::flush() -{ - ostr.next(); -} - -void ValuesRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - type.serializeAsTextQuoted(column, row_num, ostr, format_settings); -} - -void ValuesRowOutputStream::writeFieldDelimiter() -{ - writeChar(',', ostr); -} - -void ValuesRowOutputStream::writeRowStartDelimiter() -{ - writeChar('(', ostr); -} - -void ValuesRowOutputStream::writeRowEndDelimiter() -{ - writeChar(')', ostr); -} - -void ValuesRowOutputStream::writeRowBetweenDelimiter() -{ - writeCString(",", ostr); -} - - -void registerOutputFormatValues(FormatFactory & factory) -{ - factory.registerOutputFormat("Values", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/ValuesRowOutputStream.h b/dbms/src/Formats/ValuesRowOutputStream.h deleted file mode 100644 index 55cbad2acb1..00000000000 --- a/dbms/src/Formats/ValuesRowOutputStream.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include - - -namespace DB -{ - -class WriteBuffer; - - -/** A stream for outputting data in the VALUES format (as in the INSERT request). - */ -class ValuesRowOutputStream : public IRowOutputStream -{ -public: - ValuesRowOutputStream(WriteBuffer & ostr_, const FormatSettings & format_settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeFieldDelimiter() override; - void writeRowStartDelimiter() override; - void writeRowEndDelimiter() override; - void writeRowBetweenDelimiter() override; - void flush() override; - -private: - WriteBuffer & ostr; - const FormatSettings format_settings; -}; - -} - From 6e3274ef98b43b4ea9f3f4ccfd367cba018e58aa Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 20:37:24 +0300 Subject: [PATCH 063/105] Remove VerticalRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/VerticalRowOutputStream.cpp | 184 ------------------- dbms/src/Formats/VerticalRowOutputStream.h | 55 ------ 3 files changed, 241 deletions(-) delete mode 100644 dbms/src/Formats/VerticalRowOutputStream.cpp delete mode 100644 dbms/src/Formats/VerticalRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 4e71f6042fb..ea38b62e71e 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -223,7 +223,6 @@ void registerOutputFormatProcessorProtobuf(FormatFactory & factory); /// Output only (presentational) formats. -void registerOutputFormatVertical(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); @@ -270,7 +269,6 @@ FormatFactory::FormatFactory() registerOutputFormatProcessorParquet(*this); - registerOutputFormatVertical(*this); registerOutputFormatXML(*this); registerOutputFormatNull(*this); diff --git a/dbms/src/Formats/VerticalRowOutputStream.cpp b/dbms/src/Formats/VerticalRowOutputStream.cpp deleted file mode 100644 index 6a994cf9303..00000000000 --- a/dbms/src/Formats/VerticalRowOutputStream.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -VerticalRowOutputStream::VerticalRowOutputStream( - WriteBuffer & ostr_, const Block & sample_, const FormatSettings & format_settings) - : ostr(ostr_), sample(sample_), format_settings(format_settings) -{ - size_t columns = sample.columns(); - - using Widths = std::vector; - Widths name_widths(columns); - size_t max_name_width = 0; - - String serialized_value; - - for (size_t i = 0; i < columns; ++i) - { - /// Note that number of code points is just a rough approximation of visible string width. - const String & name = sample.getByPosition(i).name; - - name_widths[i] = UTF8::computeWidth(reinterpret_cast(name.data()), name.size()); - - if (name_widths[i] > max_name_width) - max_name_width = name_widths[i]; - } - - names_and_paddings.resize(columns); - for (size_t i = 0; i < columns; ++i) - { - WriteBufferFromString out(names_and_paddings[i]); - writeString(sample.getByPosition(i).name, out); - writeCString(": ", out); - } - - for (size_t i = 0; i < columns; ++i) - { - size_t new_size = max_name_width - name_widths[i] + names_and_paddings[i].size(); - names_and_paddings[i].resize(new_size, ' '); - } -} - - -void VerticalRowOutputStream::flush() -{ - ostr.next(); -} - - -void VerticalRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - if (row_number > format_settings.pretty.max_rows) - return; - - writeString(names_and_paddings[field_number], ostr); - writeValue(column, type, row_num); - writeChar('\n', ostr); - - ++field_number; -} - - -void VerticalRowOutputStream::writeValue(const IColumn & column, const IDataType & type, size_t row_num) const -{ - type.serializeAsText(column, row_num, ostr, format_settings); -} - - -void VerticalRowOutputStream::writeRowStartDelimiter() -{ - ++row_number; - - if (row_number > format_settings.pretty.max_rows) - return; - - writeCString("Row ", ostr); - writeIntText(row_number, ostr); - writeCString(":\n", ostr); - - size_t width = log10(row_number + 1) + 1 + strlen("Row :"); - for (size_t i = 0; i < width; ++i) - writeCString("─", ostr); - writeChar('\n', ostr); -} - - -void VerticalRowOutputStream::writeRowBetweenDelimiter() -{ - if (row_number > format_settings.pretty.max_rows) - return; - - writeCString("\n", ostr); - field_number = 0; -} - - -void VerticalRowOutputStream::writeSuffix() -{ - if (row_number > format_settings.pretty.max_rows) - { - writeCString("Showed first ", ostr); - writeIntText(format_settings.pretty.max_rows, ostr); - writeCString(".\n", ostr); - } - - if (totals || extremes) - { - writeCString("\n", ostr); - writeTotals(); - writeExtremes(); - } -} - - -void VerticalRowOutputStream::writeSpecialRow(const Block & block, size_t row_num, const char * title) -{ - writeCString("\n", ostr); - - row_number = 0; - field_number = 0; - - size_t columns = block.columns(); - - writeCString(title, ostr); - writeCString(":\n", ostr); - - size_t width = strlen(title) + 1; - for (size_t i = 0; i < width; ++i) - writeCString("─", ostr); - writeChar('\n', ostr); - - for (size_t i = 0; i < columns; ++i) - { - if (i != 0) - writeFieldDelimiter(); - - auto & col = block.getByPosition(i); - writeField(*col.column, *col.type, row_num); - } -} - - -void VerticalRowOutputStream::writeTotals() -{ - if (totals) - { - writeSpecialRow(totals, 0, "Totals"); - } -} - - -void VerticalRowOutputStream::writeExtremes() -{ - if (extremes) - { - writeSpecialRow(extremes, 0, "Min"); - writeSpecialRow(extremes, 1, "Max"); - } -} - - -void registerOutputFormatVertical(FormatFactory & factory) -{ - factory.registerOutputFormat("Vertical", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/VerticalRowOutputStream.h b/dbms/src/Formats/VerticalRowOutputStream.h deleted file mode 100644 index 0d9d1122b77..00000000000 --- a/dbms/src/Formats/VerticalRowOutputStream.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace DB -{ - -class WriteBuffer; -class Context; - - -/** Stream to output data in format "each value in separate row". - * Usable to show few rows with many columns. - */ -class VerticalRowOutputStream : public IRowOutputStream -{ -public: - VerticalRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & format_settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeRowStartDelimiter() override; - void writeRowBetweenDelimiter() override; - void writeSuffix() override; - - void flush() override; - - void setTotals(const Block & totals_) override { totals = totals_; } - void setExtremes(const Block & extremes_) override { extremes = extremes_; } - -protected: - virtual void writeValue(const IColumn & column, const IDataType & type, size_t row_num) const; - - void writeTotals(); - void writeExtremes(); - /// For totals and extremes. - void writeSpecialRow(const Block & block, size_t row_num, const char * title); - - WriteBuffer & ostr; - const Block sample; - const FormatSettings format_settings; - size_t field_number = 0; - size_t row_number = 0; - - using NamesAndPaddings = std::vector; - NamesAndPaddings names_and_paddings; - - Block totals; - Block extremes; -}; - -} - From a92f0866009270b0698e306a617563f05f7374fa Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 2 Aug 2019 20:39:24 +0300 Subject: [PATCH 064/105] Remove XMLRowOutputStream. --- dbms/src/Formats/FormatFactory.cpp | 2 - dbms/src/Formats/XMLRowOutputStream.cpp | 240 ------------------------ dbms/src/Formats/XMLRowOutputStream.h | 74 -------- 3 files changed, 316 deletions(-) delete mode 100644 dbms/src/Formats/XMLRowOutputStream.cpp delete mode 100644 dbms/src/Formats/XMLRowOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index ea38b62e71e..2d05ff3da43 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -223,7 +223,6 @@ void registerOutputFormatProcessorProtobuf(FormatFactory & factory); /// Output only (presentational) formats. -void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); void registerOutputFormatProcessorPretty(FormatFactory & factory); @@ -269,7 +268,6 @@ FormatFactory::FormatFactory() registerOutputFormatProcessorParquet(*this); - registerOutputFormatXML(*this); registerOutputFormatNull(*this); registerOutputFormatProcessorPretty(*this); diff --git a/dbms/src/Formats/XMLRowOutputStream.cpp b/dbms/src/Formats/XMLRowOutputStream.cpp deleted file mode 100644 index 9b4a33a6263..00000000000 --- a/dbms/src/Formats/XMLRowOutputStream.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include -#include -#include -#include - - -namespace DB -{ - -XMLRowOutputStream::XMLRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & format_settings) - : dst_ostr(ostr_), format_settings(format_settings) -{ - NamesAndTypesList columns(sample_.getNamesAndTypesList()); - fields.assign(columns.begin(), columns.end()); - field_tag_names.resize(sample_.columns()); - - bool need_validate_utf8 = false; - for (size_t i = 0; i < sample_.columns(); ++i) - { - if (!sample_.getByPosition(i).type->textCanContainOnlyValidUTF8()) - need_validate_utf8 = true; - - /// As element names, we will use the column name if it has a valid form, or "field", otherwise. - /// The condition below is more strict than the XML standard requires. - bool is_column_name_suitable = true; - const char * begin = fields[i].name.data(); - const char * end = begin + fields[i].name.size(); - for (const char * pos = begin; pos != end; ++pos) - { - char c = *pos; - if (!(isAlphaASCII(c) - || (pos != begin && isNumericASCII(c)) - || c == '_' - || c == '-' - || c == '.')) - { - is_column_name_suitable = false; - break; - } - } - - field_tag_names[i] = is_column_name_suitable - ? fields[i].name - : "field"; - } - - if (need_validate_utf8) - { - validating_ostr = std::make_unique(dst_ostr); - ostr = validating_ostr.get(); - } - else - ostr = &dst_ostr; -} - - -void XMLRowOutputStream::writePrefix() -{ - writeCString("\n", *ostr); - writeCString("\n", *ostr); - writeCString("\t\n", *ostr); - writeCString("\t\t\n", *ostr); - - for (size_t i = 0; i < fields.size(); ++i) - { - writeCString("\t\t\t\n", *ostr); - - writeCString("\t\t\t\t", *ostr); - writeXMLString(fields[i].name, *ostr); - writeCString("\n", *ostr); - writeCString("\t\t\t\t", *ostr); - writeXMLString(fields[i].type->getName(), *ostr); - writeCString("\n", *ostr); - - writeCString("\t\t\t\n", *ostr); - } - - writeCString("\t\t\n", *ostr); - writeCString("\t\n", *ostr); - writeCString("\t\n", *ostr); -} - - -void XMLRowOutputStream::writeField(const IColumn & column, const IDataType & type, size_t row_num) -{ - writeCString("\t\t\t<", *ostr); - writeString(field_tag_names[field_number], *ostr); - writeCString(">", *ostr); - type.serializeAsTextXML(column, row_num, *ostr, format_settings); - writeCString("\n", *ostr); - ++field_number; -} - - -void XMLRowOutputStream::writeRowStartDelimiter() -{ - writeCString("\t\t\n", *ostr); -} - - -void XMLRowOutputStream::writeRowEndDelimiter() -{ - writeCString("\t\t\n", *ostr); - field_number = 0; - ++row_count; -} - - -void XMLRowOutputStream::writeSuffix() -{ - writeCString("\t\n", *ostr); - - writeTotals(); - writeExtremes(); - - writeCString("\t", *ostr); - writeIntText(row_count, *ostr); - writeCString("\n", *ostr); - - writeRowsBeforeLimitAtLeast(); - - if (format_settings.write_statistics) - writeStatistics(); - - writeCString("\n", *ostr); - ostr->next(); -} - -void XMLRowOutputStream::writeRowsBeforeLimitAtLeast() -{ - if (applied_limit) - { - writeCString("\t", *ostr); - writeIntText(rows_before_limit, *ostr); - writeCString("\n", *ostr); - } -} - -void XMLRowOutputStream::writeTotals() -{ - if (totals) - { - writeCString("\t\n", *ostr); - - size_t totals_columns = totals.columns(); - for (size_t i = 0; i < totals_columns; ++i) - { - const ColumnWithTypeAndName & column = totals.safeGetByPosition(i); - - writeCString("\t\t<", *ostr); - writeString(field_tag_names[i], *ostr); - writeCString(">", *ostr); - column.type->serializeAsTextXML(*column.column.get(), 0, *ostr, format_settings); - writeCString("\n", *ostr); - } - - writeCString("\t\n", *ostr); - } -} - - -static void writeExtremesElement( - const char * title, const Block & extremes, size_t row_num, const Names & field_tag_names, WriteBuffer & ostr, const FormatSettings & format_settings) -{ - writeCString("\t\t<", ostr); - writeCString(title, ostr); - writeCString(">\n", ostr); - - size_t extremes_columns = extremes.columns(); - for (size_t i = 0; i < extremes_columns; ++i) - { - const ColumnWithTypeAndName & column = extremes.safeGetByPosition(i); - - writeCString("\t\t\t<", ostr); - writeString(field_tag_names[i], ostr); - writeCString(">", ostr); - column.type->serializeAsTextXML(*column.column.get(), row_num, ostr, format_settings); - writeCString("\n", ostr); - } - - writeCString("\t\t\n", ostr); -} - -void XMLRowOutputStream::writeExtremes() -{ - if (extremes) - { - writeCString("\t\n", *ostr); - writeExtremesElement("min", extremes, 0, field_tag_names, *ostr, format_settings); - writeExtremesElement("max", extremes, 1, field_tag_names, *ostr, format_settings); - writeCString("\t\n", *ostr); - } -} - - -void XMLRowOutputStream::onProgress(const Progress & value) -{ - progress.incrementPiecewiseAtomically(value); -} - - -void XMLRowOutputStream::writeStatistics() -{ - writeCString("\t\n", *ostr); - writeCString("\t\t", *ostr); - writeText(watch.elapsedSeconds(), *ostr); - writeCString("\n", *ostr); - writeCString("\t\t", *ostr); - writeText(progress.read_rows.load(), *ostr); - writeCString("\n", *ostr); - writeCString("\t\t", *ostr); - writeText(progress.read_bytes.load(), *ostr); - writeCString("\n", *ostr); - writeCString("\t\n", *ostr); -} - - -void registerOutputFormatXML(FormatFactory & factory) -{ - factory.registerOutputFormat("XML", []( - WriteBuffer & buf, - const Block & sample, - const Context &, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, settings), sample); - }); -} - -} diff --git a/dbms/src/Formats/XMLRowOutputStream.h b/dbms/src/Formats/XMLRowOutputStream.h deleted file mode 100644 index 6a77cfcbeb8..00000000000 --- a/dbms/src/Formats/XMLRowOutputStream.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -/** A stream for outputting data in XML format. - */ -class XMLRowOutputStream : public IRowOutputStream -{ -public: - XMLRowOutputStream(WriteBuffer & ostr_, const Block & sample_, const FormatSettings & format_settings); - - void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; - void writeRowStartDelimiter() override; - void writeRowEndDelimiter() override; - void writePrefix() override; - void writeSuffix() override; - - void flush() override - { - ostr->next(); - - if (validating_ostr) - dst_ostr.next(); - } - - void setRowsBeforeLimit(size_t rows_before_limit_) override - { - applied_limit = true; - rows_before_limit = rows_before_limit_; - } - - void setTotals(const Block & totals_) override { totals = totals_; } - void setExtremes(const Block & extremes_) override { extremes = extremes_; } - - void onProgress(const Progress & value) override; - - String getContentType() const override { return "application/xml; charset=UTF-8"; } - -protected: - - void writeRowsBeforeLimitAtLeast(); - virtual void writeTotals(); - virtual void writeExtremes(); - void writeStatistics(); - - WriteBuffer & dst_ostr; - std::unique_ptr validating_ostr; /// Validates UTF-8 sequences, replaces bad sequences with replacement character. - WriteBuffer * ostr; - - size_t field_number = 0; - size_t row_count = 0; - bool applied_limit = false; - size_t rows_before_limit = 0; - NamesAndTypes fields; - Names field_tag_names; - Block totals; - Block extremes; - - Progress progress; - Stopwatch watch; - const FormatSettings format_settings; -}; - -} - From f2be163fb0aed22523b4eefd7c03eec5a5886cf1 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Sat, 3 Aug 2019 16:51:56 +0300 Subject: [PATCH 065/105] Do not check empty columns in header. --- dbms/src/Core/Block.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dbms/src/Core/Block.cpp b/dbms/src/Core/Block.cpp index 9f8b66b1778..5a1f9753c13 100644 --- a/dbms/src/Core/Block.cpp +++ b/dbms/src/Core/Block.cpp @@ -475,6 +475,9 @@ static ReturnType checkBlockStructure(const Block & lhs, const Block & rhs, cons return on_error("Block structure mismatch in " + context_description + " stream: different types:\n" + lhs.dumpStructure() + "\n" + rhs.dumpStructure(), ErrorCodes::BLOCKS_HAVE_DIFFERENT_STRUCTURE); + if (!actual.column || !expected.column) + continue; + if (actual.column->getName() != expected.column->getName()) return on_error("Block structure mismatch in " + context_description + " stream: different columns:\n" + lhs.dumpStructure() + "\n" + rhs.dumpStructure(), ErrorCodes::BLOCKS_HAVE_DIFFERENT_STRUCTURE); From 64c42930e694d8fa29fe4508ae4554cc58b63e02 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sun, 4 Aug 2019 06:36:57 +0300 Subject: [PATCH 066/105] Using Danila Kutenin variant to make fastops working --- contrib/fastops | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fastops b/contrib/fastops index d2c85c5d654..88752a5e03c 160000 --- a/contrib/fastops +++ b/contrib/fastops @@ -1 +1 @@ -Subproject commit d2c85c5d6549cfd648a7f31ef7b14341881ff8ae +Subproject commit 88752a5e03cf34639a4a37a4b41d8b463fffd2b5 From fa9b27eec2f9acce1d6b90118479f93ed97fc095 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Sun, 4 Aug 2019 13:06:42 +0300 Subject: [PATCH 067/105] Update FormatsFactory. --- dbms/src/Formats/FormatFactory.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index 2d05ff3da43..82fd22393d1 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -92,18 +92,18 @@ BlockInputStreamPtr FormatFactory::getInput( BlockOutputStreamPtr FormatFactory::getOutput(const String & name, WriteBuffer & buf, const Block & sample, const Context & context) const { -// if (name == "PrettyCompactMonoBlock") -// { -// /// TODO: rewrite -// auto format = getOutputFormat("PrettyCompact", buf, sample, context); -// auto res = std::make_shared( -// std::make_shared(format), -// sample, context.getSettingsRef().output_format_pretty_max_rows, 0); -// -// res->disableFlush(); -// -// return std::make_shared(res, sample); -// } + if (name == "PrettyCompactMonoBlock") + { + /// TODO: rewrite + auto format = getOutputFormat("PrettyCompact", buf, sample, context); + auto res = std::make_shared( + std::make_shared(format), + sample, context.getSettingsRef().output_format_pretty_max_rows, 0); + + res->disableFlush(); + + return std::make_shared(res, sample); + } if (!getCreators(name).output_processor_creator) return getOutput(name, buf, sample, context); From 511f3050a6c68346869c430d85a5a50f269db877 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Sun, 4 Aug 2019 13:19:51 +0300 Subject: [PATCH 068/105] Update CSVRowInputFormat. --- .../Formats/Impl/CSVRowInputFormat.cpp | 84 +++++++++++++------ .../Formats/Impl/CSVRowInputFormat.h | 7 ++ 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp index 5936ab0a369..701878ff57b 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace DB @@ -27,6 +28,7 @@ CSVRowInputFormat::CSVRowInputFormat( data_types.resize(num_columns); column_indexes_by_names.reserve(num_columns); + column_idx_to_nullable_column_idx.resize(num_columns); for (size_t i = 0; i < num_columns; ++i) { @@ -34,6 +36,16 @@ CSVRowInputFormat::CSVRowInputFormat( data_types[i] = column_info.type; column_indexes_by_names.emplace(column_info.name, i); + + /// If input_format_null_as_default=1 we need ColumnNullable of type DataTypeNullable(nested_type) + /// to parse value as nullable before inserting it in corresponding column of not-nullable type. + /// Constructing temporary column for each row is slow, so we prepare it here + if (format_settings.csv.null_as_default && !column_info.type->isNullable() && column_info.type->canBeInsideNullable()) + { + column_idx_to_nullable_column_idx[i] = nullable_columns.size(); + nullable_types.emplace_back(std::make_shared(column_info.type)); + nullable_columns.emplace_back(nullable_types.back()->createColumn()); + } } } @@ -217,33 +229,12 @@ bool CSVRowInputFormat::readRow(MutableColumns & columns, RowReadExtension & ext if (table_column) { - const auto & type = data_types[*table_column]; - const bool at_delimiter = *in.position() == delimiter; - const bool at_last_column_line_end = is_last_file_column - && (*in.position() == '\n' || *in.position() == '\r' - || in.eof()); - - if (format_settings.csv.empty_as_default - && (at_delimiter || at_last_column_line_end)) - { - /// Treat empty unquoted column value as default value, if - /// specified in the settings. Tuple columns might seem - /// problematic, because they are never quoted but still contain - /// commas, which might be also used as delimiters. However, - /// they do not contain empty unquoted fields, so this check - /// works for tuples as well. - read_columns[*table_column] = false; + skipWhitespacesAndTabs(in); + read_columns[*table_column] = readField(*columns[*table_column], data_types[*table_column], + is_last_file_column, *table_column); + if (!read_columns[*table_column]) have_default_columns = true; - } - else - { - /// Read the column normally. - read_columns[*table_column] = true; - skipWhitespacesAndTabs(in); - type->deserializeAsTextCSV(*columns[*table_column], in, - format_settings); - skipWhitespacesAndTabs(in); - } + skipWhitespacesAndTabs(in); } else { @@ -383,7 +374,7 @@ bool OPTIMIZE(1) CSVRowInputFormat::parseRowAndPrintDiagnosticInfo(MutableColumn { skipWhitespacesAndTabs(in); prev_position = in.position(); - current_column_type->deserializeAsTextCSV(*columns[table_column], in, format_settings); + readField(*columns[table_column], current_column_type, is_last_file_column, table_column); curr_position = in.position(); skipWhitespacesAndTabs(in); } @@ -523,6 +514,45 @@ void CSVRowInputFormat::updateDiagnosticInfo() pos_of_current_row = in.position(); } +bool CSVRowInputFormat::readField(IColumn & column, const DataTypePtr & type, bool is_last_file_column, size_t column_idx) +{ + const bool at_delimiter = *in.position() == format_settings.csv.delimiter; + const bool at_last_column_line_end = is_last_file_column + && (*in.position() == '\n' || *in.position() == '\r' + || in.eof()); + + if (format_settings.csv.empty_as_default + && (at_delimiter || at_last_column_line_end)) + { + /// Treat empty unquoted column value as default value, if + /// specified in the settings. Tuple columns might seem + /// problematic, because they are never quoted but still contain + /// commas, which might be also used as delimiters. However, + /// they do not contain empty unquoted fields, so this check + /// works for tuples as well. + return false; + } + else if (column_idx_to_nullable_column_idx[column_idx]) + { + /// If value is null but type is not nullable then use default value instead. + const size_t nullable_idx = *column_idx_to_nullable_column_idx[column_idx]; + auto & tmp_col = *nullable_columns[nullable_idx]; + nullable_types[nullable_idx]->deserializeAsTextCSV(tmp_col, in, format_settings); + Field value = tmp_col[0]; + tmp_col.popBack(1); /// do not store copy of values in memory + if (value.isNull()) + return false; + column.insert(value); + return true; + } + else + { + /// Read the column normally. + type->deserializeAsTextCSV(column, in, format_settings); + return true; + } +} + void registerInputFormatProcessorCSV(FormatFactory & factory) { diff --git a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h index b7e29157e0f..6935325f01f 100644 --- a/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h +++ b/dbms/src/Processors/Formats/Impl/CSVRowInputFormat.h @@ -65,10 +65,17 @@ private: char * pos_of_current_row = nullptr; char * pos_of_prev_row = nullptr; + /// For setting input_format_null_as_default + DataTypes nullable_types; + MutableColumns nullable_columns; + OptionalIndexes column_idx_to_nullable_column_idx; + void updateDiagnosticInfo(); bool parseRowAndPrintDiagnosticInfo(MutableColumns & columns, WriteBuffer & out, size_t max_length_of_column_name, size_t max_length_of_data_type_name); + + bool readField(IColumn & column, const DataTypePtr & type, bool is_last_file_column, size_t column_idx); }; } From 98e6dbdd8775fcc1f4ee014e0a4fef11ef1fd4c5 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sun, 4 Aug 2019 13:58:43 +0300 Subject: [PATCH 069/105] Fixed CMake --- contrib/fastops-cmake/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/fastops-cmake/CMakeLists.txt b/contrib/fastops-cmake/CMakeLists.txt index 2d85d111526..0269d5603c2 100644 --- a/contrib/fastops-cmake/CMakeLists.txt +++ b/contrib/fastops-cmake/CMakeLists.txt @@ -3,9 +3,8 @@ set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/fastops) set(SRCS "") if(HAVE_AVX) - set (SRCS ${SRCS} ${LIBRARY_DIR}/fastops/avx/ops_avx.cpp ${LIBRARY_DIR}/fastops/core/FastIntrinsics.cpp) + set (SRCS ${SRCS} ${LIBRARY_DIR}/fastops/avx/ops_avx.cpp) set_source_files_properties(${LIBRARY_DIR}/fastops/avx/ops_avx.cpp PROPERTIES COMPILE_FLAGS "-mavx -DNO_AVX2") - set_source_files_properties(${LIBRARY_DIR}/fastops/core/FastIntrinsics.cpp PROPERTIES COMPILE_FLAGS "-mavx -DNO_AVX2") endif() if(HAVE_AVX2) From abc63f8a06ea91175e30544e806d6d0f0f101409 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Sun, 4 Aug 2019 15:43:11 +0300 Subject: [PATCH 070/105] Merged with master. --- dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp | 2 +- dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp | 3 +-- dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp | 2 +- dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp index 87cad3022fb..42ef04b64b1 100644 --- a/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/CapnProtoRowInputFormat.cpp @@ -1,9 +1,9 @@ #include "config_formats.h" +#include // Y_IGNORE #if USE_CAPNP #include #include -#include // Y_IGNORE #include #include #include // Y_IGNORE diff --git a/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp b/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp index 597c6cb4af1..e5f08c8d645 100644 --- a/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ParquetBlockInputFormat.cpp @@ -1,8 +1,7 @@ #include "config_formats.h" - -#if USE_PARQUET #include +#if USE_PARQUET #include #include #include diff --git a/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp index 5b546e863de..3a3540ede7e 100644 --- a/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ParquetBlockOutputFormat.cpp @@ -1,7 +1,7 @@ #include "config_formats.h" +#include #if USE_PARQUET -# include // TODO: clean includes # include diff --git a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp index d67bad4320c..4f535308b8f 100644 --- a/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/ProtobufRowInputFormat.cpp @@ -1,11 +1,11 @@ #include "config_formats.h" -#if USE_PROTOBUF +#include +#if USE_PROTOBUF #include #include #include #include -#include namespace DB From cddbd6db3cdffd4cd7cb0a2edb48b1d1ab6aeaa1 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Sun, 4 Aug 2019 16:19:57 +0300 Subject: [PATCH 071/105] Merged with master. --- dbms/src/Formats/CapnProtoRowInputStream.cpp | 332 ------------ dbms/src/Formats/ParquetBlockInputStream.cpp | 494 ------------------ dbms/src/Formats/ParquetBlockOutputStream.cpp | 450 ---------------- dbms/src/Formats/ProtobufRowInputStream.cpp | 94 ---- 4 files changed, 1370 deletions(-) delete mode 100644 dbms/src/Formats/CapnProtoRowInputStream.cpp delete mode 100644 dbms/src/Formats/ParquetBlockInputStream.cpp delete mode 100644 dbms/src/Formats/ParquetBlockOutputStream.cpp delete mode 100644 dbms/src/Formats/ProtobufRowInputStream.cpp diff --git a/dbms/src/Formats/CapnProtoRowInputStream.cpp b/dbms/src/Formats/CapnProtoRowInputStream.cpp deleted file mode 100644 index 89d652ebb12..00000000000 --- a/dbms/src/Formats/CapnProtoRowInputStream.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include "CapnProtoRowInputStream.h" - -#if USE_CAPNP -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int BAD_TYPE_OF_FIELD; - extern const int BAD_ARGUMENTS; - extern const int THERE_IS_NO_COLUMN; - extern const int LOGICAL_ERROR; -} - -CapnProtoRowInputStream::NestedField split(const Block & header, size_t i) -{ - CapnProtoRowInputStream::NestedField field = {{}, i}; - - // Remove leading dot in field definition, e.g. ".msg" -> "msg" - String name(header.safeGetByPosition(i).name); - if (name.size() > 0 && name[0] == '.') - name.erase(0, 1); - - boost::split(field.tokens, name, boost::is_any_of("._")); - return field; -} - - -Field convertNodeToField(capnp::DynamicValue::Reader value) -{ - switch (value.getType()) - { - case capnp::DynamicValue::UNKNOWN: - throw Exception("Unknown field type", ErrorCodes::BAD_TYPE_OF_FIELD); - case capnp::DynamicValue::VOID: - return Field(); - case capnp::DynamicValue::BOOL: - return value.as() ? 1u : 0u; - case capnp::DynamicValue::INT: - return value.as(); - case capnp::DynamicValue::UINT: - return value.as(); - case capnp::DynamicValue::FLOAT: - return value.as(); - case capnp::DynamicValue::TEXT: - { - auto arr = value.as(); - return String(arr.begin(), arr.size()); - } - case capnp::DynamicValue::DATA: - { - auto arr = value.as().asChars(); - return String(arr.begin(), arr.size()); - } - case capnp::DynamicValue::LIST: - { - auto listValue = value.as(); - Array res(listValue.size()); - for (auto i : kj::indices(listValue)) - res[i] = convertNodeToField(listValue[i]); - - return res; - } - case capnp::DynamicValue::ENUM: - return value.as().getRaw(); - case capnp::DynamicValue::STRUCT: - { - auto structValue = value.as(); - const auto & fields = structValue.getSchema().getFields(); - - Field field = Tuple(TupleBackend(fields.size())); - TupleBackend & tuple = get(field).toUnderType(); - for (auto i : kj::indices(fields)) - tuple[i] = convertNodeToField(structValue.get(fields[i])); - - return field; - } - case capnp::DynamicValue::CAPABILITY: - throw Exception("CAPABILITY type not supported", ErrorCodes::BAD_TYPE_OF_FIELD); - case capnp::DynamicValue::ANY_POINTER: - throw Exception("ANY_POINTER type not supported", ErrorCodes::BAD_TYPE_OF_FIELD); - } - return Field(); -} - -capnp::StructSchema::Field getFieldOrThrow(capnp::StructSchema node, const std::string & field) -{ - KJ_IF_MAYBE(child, node.findFieldByName(field)) - return *child; - else - throw Exception("Field " + field + " doesn't exist in schema " + node.getShortDisplayName().cStr(), ErrorCodes::THERE_IS_NO_COLUMN); -} - - -void CapnProtoRowInputStream::createActions(const NestedFieldList & sorted_fields, capnp::StructSchema reader) -{ - /// Columns in a table can map to fields in Cap'n'Proto or to structs. - - /// Store common parents and their tokens in order to backtrack. - std::vector parents; - std::vector parent_tokens; - - capnp::StructSchema cur_reader = reader; - - for (const auto & field : sorted_fields) - { - if (field.tokens.empty()) - throw Exception("Logical error in CapnProtoRowInputStream", ErrorCodes::LOGICAL_ERROR); - - // Backtrack to common parent - while (field.tokens.size() < parent_tokens.size() + 1 - || !std::equal(parent_tokens.begin(), parent_tokens.end(), field.tokens.begin())) - { - actions.push_back({Action::POP}); - parents.pop_back(); - parent_tokens.pop_back(); - - if (parents.empty()) - { - cur_reader = reader; - break; - } - else - cur_reader = parents.back().getType().asStruct(); - } - - // Go forward - while (parent_tokens.size() + 1 < field.tokens.size()) - { - const auto & token = field.tokens[parents.size()]; - auto node = getFieldOrThrow(cur_reader, token); - if (node.getType().isStruct()) - { - // Descend to field structure - parents.emplace_back(node); - parent_tokens.emplace_back(token); - cur_reader = node.getType().asStruct(); - actions.push_back({Action::PUSH, node}); - } - else if (node.getType().isList()) - { - break; // Collect list - } - else - throw Exception("Field " + token + " is neither Struct nor List", ErrorCodes::BAD_TYPE_OF_FIELD); - } - - // Read field from the structure - auto node = getFieldOrThrow(cur_reader, field.tokens[parents.size()]); - if (node.getType().isList() && actions.size() > 0 && actions.back().field == node) - { - // The field list here flattens Nested elements into multiple arrays - // In order to map Nested types in Cap'nProto back, they need to be collected - // Since the field names are sorted, the order of field positions must be preserved - // For example, if the fields are { b @0 :Text, a @1 :Text }, the `a` would come first - // even though it's position is second. - auto & columns = actions.back().columns; - auto it = std::upper_bound(columns.cbegin(), columns.cend(), field.pos); - columns.insert(it, field.pos); - } - else - { - actions.push_back({Action::READ, node, {field.pos}}); - } - } -} - -CapnProtoRowInputStream::CapnProtoRowInputStream(ReadBuffer & istr_, const Block & header_, const FormatSchemaInfo& info) - : istr(istr_), header(header_), parser(std::make_shared()) -{ - // Parse the schema and fetch the root object - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - auto schema = parser->impl.parseDiskFile(info.schemaPath(), info.absoluteSchemaPath(), {}); -#pragma GCC diagnostic pop - - root = schema.getNested(info.messageName()).asStruct(); - - /** - * The schema typically consists of fields in various nested structures. - * Here we gather the list of fields and sort them in a way so that fields in the same structure are adjacent, - * and the nesting level doesn't decrease to make traversal easier. - */ - NestedFieldList list; - size_t num_columns = header.columns(); - for (size_t i = 0; i < num_columns; ++i) - list.push_back(split(header, i)); - - // Order list first by value of strings then by length of string vector. - std::sort(list.begin(), list.end(), [](const NestedField & a, const NestedField & b) { return a.tokens < b.tokens; }); - createActions(list, root); -} - -kj::Array CapnProtoRowInputStream::readMessage() -{ - uint32_t segment_count; - istr.readStrict(reinterpret_cast(&segment_count), sizeof(uint32_t)); - - // one for segmentCount and one because segmentCount starts from 0 - const auto prefix_size = (2 + segment_count) * sizeof(uint32_t); - const auto words_prefix_size = (segment_count + 1) / 2 + 1; - auto prefix = kj::heapArray(words_prefix_size); - auto prefix_chars = prefix.asChars(); - ::memcpy(prefix_chars.begin(), &segment_count, sizeof(uint32_t)); - - // read size of each segment - for (size_t i = 0; i <= segment_count; ++i) - istr.readStrict(prefix_chars.begin() + ((i + 1) * sizeof(uint32_t)), sizeof(uint32_t)); - - // calculate size of message - const auto expected_words = capnp::expectedSizeInWordsFromPrefix(prefix); - const auto expected_bytes = expected_words * sizeof(capnp::word); - const auto data_size = expected_bytes - prefix_size; - auto msg = kj::heapArray(expected_words); - auto msg_chars = msg.asChars(); - - // read full message - ::memcpy(msg_chars.begin(), prefix_chars.begin(), prefix_size); - istr.readStrict(msg_chars.begin() + prefix_size, data_size); - - return msg; -} - -bool CapnProtoRowInputStream::read(MutableColumns & columns, RowReadExtension &) -{ - if (istr.eof()) - return false; - - auto array = readMessage(); - -#if CAPNP_VERSION >= 8000 - capnp::UnalignedFlatArrayMessageReader msg(array); -#else - capnp::FlatArrayMessageReader msg(array); -#endif - std::vector stack; - stack.push_back(msg.getRoot(root)); - - for (auto action : actions) - { - switch (action.type) - { - case Action::READ: - { - Field value = convertNodeToField(stack.back().get(action.field)); - if (action.columns.size() > 1) - { - // Nested columns must be flattened into several arrays - // e.g. Array(Tuple(x ..., y ...)) -> Array(x ...), Array(y ...) - const Array & collected = DB::get(value); - size_t size = collected.size(); - // The flattened array contains an array of a part of the nested tuple - Array flattened(size); - for (size_t column_index = 0; column_index < action.columns.size(); ++column_index) - { - // Populate array with a single tuple elements - for (size_t off = 0; off < size; ++off) - { - const TupleBackend & tuple = DB::get(collected[off]).toUnderType(); - flattened[off] = tuple[column_index]; - } - auto & col = columns[action.columns[column_index]]; - col->insert(flattened); - } - } - else - { - auto & col = columns[action.columns[0]]; - col->insert(value); - } - - break; - } - case Action::POP: - stack.pop_back(); - break; - case Action::PUSH: - stack.push_back(stack.back().get(action.field).as()); - break; - } - } - - return true; -} - -void registerInputFormatCapnProto(FormatFactory & factory) -{ - factory.registerInputFormat( - "CapnProto", - [](ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, FormatSchemaInfo(context, "CapnProto")), - sample, - max_block_size, - rows_portion_size, - callback, - settings); - }); -} - -} - -#else - -namespace DB -{ - class FormatFactory; - void registerInputFormatCapnProto(FormatFactory &) {} -} - -#endif // USE_CAPNP diff --git a/dbms/src/Formats/ParquetBlockInputStream.cpp b/dbms/src/Formats/ParquetBlockInputStream.cpp deleted file mode 100644 index e75d5e1d455..00000000000 --- a/dbms/src/Formats/ParquetBlockInputStream.cpp +++ /dev/null @@ -1,494 +0,0 @@ -#include "ParquetBlockInputStream.h" - -#if USE_PARQUET -# include -# include -# include -// TODO: clear includes -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -namespace DB -{ -namespace ErrorCodes -{ - extern const int UNKNOWN_TYPE; - extern const int VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE; - extern const int CANNOT_READ_ALL_DATA; - extern const int EMPTY_DATA_PASSED; - extern const int SIZES_OF_COLUMNS_DOESNT_MATCH; - extern const int CANNOT_CONVERT_TYPE; - extern const int CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN; - extern const int THERE_IS_NO_COLUMN; -} - -ParquetBlockInputStream::ParquetBlockInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_) - : istr{istr_}, header{header_}, context{context_} -{ -} - -Block ParquetBlockInputStream::getHeader() const -{ - return header; -} - -/// Inserts numeric data right into internal column data to reduce an overhead -template > -void fillColumnWithNumericData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - std::shared_ptr chunk = arrow_column->data()->chunk(chunk_i); - /// buffers[0] is a null bitmap and buffers[1] are actual values - std::shared_ptr buffer = chunk->data()->buffers[1]; - - const auto * raw_data = reinterpret_cast(buffer->data()); - column_data.insert_assume_reserved(raw_data, raw_data + chunk->length()); - } -} - -/// Inserts chars and offsets right into internal column data to reduce an overhead. -/// Internal offsets are shifted by one to the right in comparison with Arrow ones. So the last offset should map to the end of all chars. -/// Also internal strings are null terminated. -void fillColumnWithStringData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - PaddedPODArray & column_chars_t = static_cast(*internal_column).getChars(); - PaddedPODArray & column_offsets = static_cast(*internal_column).getOffsets(); - - size_t chars_t_size = 0; - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::BinaryArray & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - const size_t chunk_length = chunk.length(); - - chars_t_size += chunk.value_offset(chunk_length - 1) + chunk.value_length(chunk_length - 1); - chars_t_size += chunk_length; /// additional space for null bytes - } - - column_chars_t.reserve(chars_t_size); - column_offsets.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::BinaryArray & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - std::shared_ptr buffer = chunk.value_data(); - const size_t chunk_length = chunk.length(); - - for (size_t offset_i = 0; offset_i != chunk_length; ++offset_i) - { - if (!chunk.IsNull(offset_i) && buffer) - { - const UInt8 * raw_data = buffer->data() + chunk.value_offset(offset_i); - column_chars_t.insert_assume_reserved(raw_data, raw_data + chunk.value_length(offset_i)); - } - column_chars_t.emplace_back('\0'); - - column_offsets.emplace_back(column_chars_t.size()); - } - } -} - -void fillColumnWithBooleanData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast &>(*internal_column).getData(); - column_data.resize(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::BooleanArray & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - /// buffers[0] is a null bitmap and buffers[1] are actual values - std::shared_ptr buffer = chunk.data()->buffers[1]; - - for (size_t bool_i = 0; bool_i != static_cast(chunk.length()); ++bool_i) - column_data[bool_i] = chunk.Value(bool_i); - } -} - -/// Arrow stores Parquet::DATE in Int32, while ClickHouse stores Date in UInt16. Therefore, it should be checked before saving -void fillColumnWithDate32Data(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - PaddedPODArray & column_data = static_cast &>(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - arrow::Date32Array & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - UInt32 days_num = static_cast(chunk.Value(value_i)); - if (days_num > DATE_LUT_MAX_DAY_NUM) - { - // TODO: will it rollback correctly? - throw Exception{"Input value " + std::to_string(days_num) + " of a column \"" + arrow_column->name() - + "\" is greater than " - "max allowed Date value, which is " - + std::to_string(DATE_LUT_MAX_DAY_NUM), - ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE}; - } - - column_data.emplace_back(days_num); - } - } -} - -/// Arrow stores Parquet::DATETIME in Int64, while ClickHouse stores DateTime in UInt32. Therefore, it should be checked before saving -void fillColumnWithDate64Data(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast &>(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - auto & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - auto timestamp = static_cast(chunk.Value(value_i) / 1000); // Always? in ms - column_data.emplace_back(timestamp); - } - } -} - -void fillColumnWithTimestampData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column_data = static_cast &>(*internal_column).getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - auto & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - const auto & type = static_cast(*chunk.type()); - - UInt32 divide = 1; - const auto unit = type.unit(); - switch (unit) - { - case arrow::TimeUnit::SECOND: - divide = 1; - break; - case arrow::TimeUnit::MILLI: - divide = 1000; - break; - case arrow::TimeUnit::MICRO: - divide = 1000000; - break; - case arrow::TimeUnit::NANO: - divide = 1000000000; - break; - } - - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - auto timestamp = static_cast(chunk.Value(value_i) / divide); // ms! TODO: check other 's' 'ns' ... - column_data.emplace_back(timestamp); - } - } -} - -void fillColumnWithDecimalData(std::shared_ptr & arrow_column, MutableColumnPtr & internal_column) -{ - auto & column = static_cast &>(*internal_column); - auto & column_data = column.getData(); - column_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0, num_chunks = static_cast(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i) - { - auto & chunk = static_cast(*(arrow_column->data()->chunk(chunk_i))); - for (size_t value_i = 0, length = static_cast(chunk.length()); value_i < length; ++value_i) - { - column_data.emplace_back( - chunk.IsNull(value_i) ? Decimal128(0) : *reinterpret_cast(chunk.Value(value_i))); // TODO: copy column - } - } -} - -/// Creates a null bytemap from arrow's null bitmap -void fillByteMapFromArrowColumn(std::shared_ptr & arrow_column, MutableColumnPtr & bytemap) -{ - PaddedPODArray & bytemap_data = static_cast &>(*bytemap).getData(); - bytemap_data.reserve(arrow_column->length()); - - for (size_t chunk_i = 0; chunk_i != static_cast(arrow_column->data()->num_chunks()); ++chunk_i) - { - std::shared_ptr chunk = arrow_column->data()->chunk(chunk_i); - - for (size_t value_i = 0; value_i != static_cast(chunk->length()); ++value_i) - bytemap_data.emplace_back(chunk->IsNull(value_i)); - } -} - -# define FOR_ARROW_NUMERIC_TYPES(M) \ - M(arrow::Type::UINT8, UInt8) \ - M(arrow::Type::INT8, Int8) \ - M(arrow::Type::UINT16, UInt16) \ - M(arrow::Type::INT16, Int16) \ - M(arrow::Type::UINT32, UInt32) \ - M(arrow::Type::INT32, Int32) \ - M(arrow::Type::UINT64, UInt64) \ - M(arrow::Type::INT64, Int64) \ - M(arrow::Type::FLOAT, Float32) \ - M(arrow::Type::DOUBLE, Float64) -//M(arrow::Type::HALF_FLOAT, Float32) // TODO - - -using NameToColumnPtr = std::unordered_map>; - - -Block ParquetBlockInputStream::readImpl() -{ - static const std::unordered_map> arrow_type_to_internal_type = { - //{arrow::Type::DECIMAL, std::make_shared()}, - {arrow::Type::UINT8, std::make_shared()}, - {arrow::Type::INT8, std::make_shared()}, - {arrow::Type::UINT16, std::make_shared()}, - {arrow::Type::INT16, std::make_shared()}, - {arrow::Type::UINT32, std::make_shared()}, - {arrow::Type::INT32, std::make_shared()}, - {arrow::Type::UINT64, std::make_shared()}, - {arrow::Type::INT64, std::make_shared()}, - {arrow::Type::HALF_FLOAT, std::make_shared()}, - {arrow::Type::FLOAT, std::make_shared()}, - {arrow::Type::DOUBLE, std::make_shared()}, - - {arrow::Type::BOOL, std::make_shared()}, - //{arrow::Type::DATE32, std::make_shared()}, - {arrow::Type::DATE32, std::make_shared()}, - //{arrow::Type::DATE32, std::make_shared()}, - {arrow::Type::DATE64, std::make_shared()}, - {arrow::Type::TIMESTAMP, std::make_shared()}, - //{arrow::Type::TIME32, std::make_shared()}, - - - {arrow::Type::STRING, std::make_shared()}, - {arrow::Type::BINARY, std::make_shared()}, - //{arrow::Type::FIXED_SIZE_BINARY, std::make_shared()}, - //{arrow::Type::UUID, std::make_shared()}, - - - // TODO: add other types that are convertable to internal ones: - // 0. ENUM? - // 1. UUID -> String - // 2. JSON -> String - // Full list of types: contrib/arrow/cpp/src/arrow/type.h - }; - - - Block res; - - if (!istr.eof()) - { - /* - First we load whole stream into string (its very bad and limiting .parquet file size to half? of RAM) - Then producing blocks for every row_group (dont load big .parquet files with one row_group - it can eat x10+ RAM from .parquet file size) - */ - - if (row_group_current < row_group_total) - throw Exception{"Got new data, but data from previous chunks not readed " + std::to_string(row_group_current) + "/" - + std::to_string(row_group_total), - ErrorCodes::CANNOT_READ_ALL_DATA}; - - file_data.clear(); - { - WriteBufferFromString file_buffer(file_data); - copyData(istr, file_buffer); - } - - buffer = std::make_unique(file_data); - // TODO: maybe use parquet::RandomAccessSource? - auto reader = parquet::ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(*buffer)); - file_reader = std::make_unique(::arrow::default_memory_pool(), std::move(reader)); - row_group_total = file_reader->num_row_groups(); - row_group_current = 0; - } - if (row_group_current >= row_group_total) - return res; - - // TODO: also catch a ParquetException thrown by filereader? - //arrow::Status read_status = filereader.ReadTable(&table); - std::shared_ptr table; - arrow::Status read_status = file_reader->ReadRowGroup(row_group_current, &table); - - if (!read_status.ok()) - throw Exception{"Error while reading parquet data: " + read_status.ToString(), ErrorCodes::CANNOT_READ_ALL_DATA}; - - if (0 == table->num_rows()) - throw Exception{"Empty table in input data", ErrorCodes::EMPTY_DATA_PASSED}; - - if (header.columns() > static_cast(table->num_columns())) - // TODO: What if some columns were not presented? Insert NULLs? What if a column is not nullable? - throw Exception{"Number of columns is less than the table has", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH}; - - ++row_group_current; - - NameToColumnPtr name_to_column_ptr; - for (size_t i = 0, num_columns = static_cast(table->num_columns()); i < num_columns; ++i) - { - std::shared_ptr arrow_column = table->column(i); - name_to_column_ptr[arrow_column->name()] = arrow_column; - } - - for (size_t column_i = 0, columns = header.columns(); column_i < columns; ++column_i) - { - ColumnWithTypeAndName header_column = header.getByPosition(column_i); - - if (name_to_column_ptr.find(header_column.name) == name_to_column_ptr.end()) - // TODO: What if some columns were not presented? Insert NULLs? What if a column is not nullable? - throw Exception{"Column \"" + header_column.name + "\" is not presented in input data", ErrorCodes::THERE_IS_NO_COLUMN}; - - std::shared_ptr arrow_column = name_to_column_ptr[header_column.name]; - arrow::Type::type arrow_type = arrow_column->type()->id(); - - // TODO: check if a column is const? - if (!header_column.type->isNullable() && arrow_column->null_count()) - { - throw Exception{"Can not insert NULL data into non-nullable column \"" + header_column.name + "\"", - ErrorCodes::CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN}; - } - - const bool target_column_is_nullable = header_column.type->isNullable() || arrow_column->null_count(); - - DataTypePtr internal_nested_type; - - if (arrow_type == arrow::Type::DECIMAL) - { - const auto decimal_type = static_cast(arrow_column->type().get()); - internal_nested_type = std::make_shared>(decimal_type->precision(), decimal_type->scale()); - } - else if (arrow_type_to_internal_type.find(arrow_type) != arrow_type_to_internal_type.end()) - { - internal_nested_type = arrow_type_to_internal_type.at(arrow_type); - } - else - { - throw Exception{"The type \"" + arrow_column->type()->name() + "\" of an input column \"" + arrow_column->name() - + "\" is not supported for conversion from a Parquet data format", - ErrorCodes::CANNOT_CONVERT_TYPE}; - } - - const DataTypePtr internal_type = target_column_is_nullable ? makeNullable(internal_nested_type) : internal_nested_type; - const std::string internal_nested_type_name = internal_nested_type->getName(); - - const DataTypePtr column_nested_type = header_column.type->isNullable() - ? static_cast(header_column.type.get())->getNestedType() - : header_column.type; - - const DataTypePtr column_type = header_column.type; - - const std::string column_nested_type_name = column_nested_type->getName(); - - ColumnWithTypeAndName column; - column.name = header_column.name; - column.type = internal_type; - - /// Data - MutableColumnPtr read_column = internal_nested_type->createColumn(); - switch (arrow_type) - { - case arrow::Type::STRING: - case arrow::Type::BINARY: - //case arrow::Type::FIXED_SIZE_BINARY: - fillColumnWithStringData(arrow_column, read_column); - break; - case arrow::Type::BOOL: - fillColumnWithBooleanData(arrow_column, read_column); - break; - case arrow::Type::DATE32: - fillColumnWithDate32Data(arrow_column, read_column); - break; - case arrow::Type::DATE64: - fillColumnWithDate64Data(arrow_column, read_column); - break; - case arrow::Type::TIMESTAMP: - fillColumnWithTimestampData(arrow_column, read_column); - break; - case arrow::Type::DECIMAL: - //fillColumnWithNumericData>(arrow_column, read_column); // Have problems with trash values under NULL, but faster - fillColumnWithDecimalData(arrow_column, read_column /*, internal_nested_type*/); - break; -# define DISPATCH(ARROW_NUMERIC_TYPE, CPP_NUMERIC_TYPE) \ - case ARROW_NUMERIC_TYPE: \ - fillColumnWithNumericData(arrow_column, read_column); \ - break; - - FOR_ARROW_NUMERIC_TYPES(DISPATCH) -# undef DISPATCH - // TODO: support TIMESTAMP_MICROS and TIMESTAMP_MILLIS with truncated micro- and milliseconds? - // TODO: read JSON as a string? - // TODO: read UUID as a string? - default: - throw Exception{"Unsupported parquet type \"" + arrow_column->type()->name() + "\" of an input column \"" - + arrow_column->name() + "\"", - ErrorCodes::UNKNOWN_TYPE}; - } - - if (column.type->isNullable()) - { - MutableColumnPtr null_bytemap = DataTypeUInt8().createColumn(); - fillByteMapFromArrowColumn(arrow_column, null_bytemap); - column.column = ColumnNullable::create(std::move(read_column), std::move(null_bytemap)); - } - else - { - column.column = std::move(read_column); - } - - column.column = castColumn(column, column_type, context); - column.type = column_type; - - res.insert(std::move(column)); - } - - return res; -} - -void registerInputFormatParquet(FormatFactory & factory) -{ - factory.registerInputFormat( - "Parquet", - [](ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 /* max_block_size */, - UInt64 /* rows_portion_size */, - FormatFactory::ReadCallback /* callback */, - const FormatSettings & /* settings */) { return std::make_shared(buf, sample, context); }); -} - -} - -#else - -namespace DB -{ -class FormatFactory; -void registerInputFormatParquet(FormatFactory &) -{ -} -} - -#endif diff --git a/dbms/src/Formats/ParquetBlockOutputStream.cpp b/dbms/src/Formats/ParquetBlockOutputStream.cpp deleted file mode 100644 index b0d4cd7818c..00000000000 --- a/dbms/src/Formats/ParquetBlockOutputStream.cpp +++ /dev/null @@ -1,450 +0,0 @@ -#include "ParquetBlockOutputStream.h" - -#if USE_PARQUET -// TODO: clean includes -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -namespace DB -{ -namespace ErrorCodes -{ - extern const int UNKNOWN_EXCEPTION; - extern const int UNKNOWN_TYPE; -} - -ParquetBlockOutputStream::ParquetBlockOutputStream(WriteBuffer & ostr, const Block & header, const FormatSettings & format_settings) : ostr{ostr}, header{header}, format_settings{format_settings} -{ -} - -void ParquetBlockOutputStream::flush() -{ - ostr.next(); -} - -void checkStatus(arrow::Status & status, const std::string & column_name) -{ - if (!status.ok()) - throw Exception{"Error with a parquet column \"" + column_name + "\": " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; -} - -template -void fillArrowArrayWithNumericColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - const PaddedPODArray & internal_data = static_cast &>(*write_column).getData(); - ArrowBuilderType builder; - arrow::Status status; - - const UInt8 * arrow_null_bytemap_raw_ptr = nullptr; - PaddedPODArray arrow_null_bytemap; - if (null_bytemap) - { - /// Invert values since Arrow interprets 1 as a non-null value, while CH as a null - arrow_null_bytemap.reserve(null_bytemap->size()); - for (size_t i = 0, size = null_bytemap->size(); i < size; ++i) - arrow_null_bytemap.emplace_back(1 ^ (*null_bytemap)[i]); - - arrow_null_bytemap_raw_ptr = arrow_null_bytemap.data(); - } - - status = builder.AppendValues(internal_data.data(), internal_data.size(), arrow_null_bytemap_raw_ptr); - checkStatus(status, write_column->getName()); - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -template -void fillArrowArrayWithStringColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - const auto & internal_column = static_cast(*write_column); - arrow::StringBuilder builder; - arrow::Status status; - - for (size_t string_i = 0, size = internal_column.size(); string_i < size; ++string_i) - { - if (null_bytemap && (*null_bytemap)[string_i]) - { - status = builder.AppendNull(); - } - else - { - StringRef string_ref = internal_column.getDataAt(string_i); - status = builder.Append(string_ref.data, string_ref.size); - } - - checkStatus(status, write_column->getName()); - } - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -void fillArrowArrayWithDateColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - const PaddedPODArray & internal_data = static_cast &>(*write_column).getData(); - //arrow::Date32Builder date_builder; - arrow::UInt16Builder builder; - arrow::Status status; - - for (size_t value_i = 0, size = internal_data.size(); value_i < size; ++value_i) - { - if (null_bytemap && (*null_bytemap)[value_i]) - status = builder.AppendNull(); - else - /// Implicitly converts UInt16 to Int32 - status = builder.Append(internal_data[value_i]); - checkStatus(status, write_column->getName()); - } - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -void fillArrowArrayWithDateTimeColumnData( - ColumnPtr write_column, std::shared_ptr & arrow_array, const PaddedPODArray * null_bytemap) -{ - auto & internal_data = static_cast &>(*write_column).getData(); - //arrow::Date64Builder builder; - arrow::UInt32Builder builder; - arrow::Status status; - - for (size_t value_i = 0, size = internal_data.size(); value_i < size; ++value_i) - { - if (null_bytemap && (*null_bytemap)[value_i]) - status = builder.AppendNull(); - else - /// Implicitly converts UInt16 to Int32 - //status = date_builder.Append(static_cast(internal_data[value_i]) * 1000); // now ms. TODO check other units - status = builder.Append(internal_data[value_i]); - - checkStatus(status, write_column->getName()); - } - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -} - -template -void fillArrowArrayWithDecimalColumnData( - ColumnPtr write_column, - std::shared_ptr & arrow_array, - const PaddedPODArray * null_bytemap, - const DataType * decimal_type) -{ - const auto & column = static_cast(*write_column); - arrow::DecimalBuilder builder(arrow::decimal(decimal_type->getPrecision(), decimal_type->getScale())); - arrow::Status status; - - for (size_t value_i = 0, size = column.size(); value_i < size; ++value_i) - { - if (null_bytemap && (*null_bytemap)[value_i]) - status = builder.AppendNull(); - else - status = builder.Append( - arrow::Decimal128(reinterpret_cast(&column.getElement(value_i).value))); // TODO: try copy column - - checkStatus(status, write_column->getName()); - } - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); - -/* TODO column copy - const auto & internal_data = static_cast(*write_column).getData(); - //ArrowBuilderType numeric_builder; - arrow::DecimalBuilder builder(arrow::decimal(decimal_type->getPrecision(), decimal_type->getScale())); - arrow::Status status; - - const uint8_t * arrow_null_bytemap_raw_ptr = nullptr; - PaddedPODArray arrow_null_bytemap; - if (null_bytemap) - { - /// Invert values since Arrow interprets 1 as a non-null value, while CH as a null - arrow_null_bytemap.reserve(null_bytemap->size()); - for (size_t i = 0, size = null_bytemap->size(); i < size; ++i) - arrow_null_bytemap.emplace_back(1 ^ (*null_bytemap)[i]); - - arrow_null_bytemap_raw_ptr = arrow_null_bytemap.data(); - } - - status = builder.AppendValues(reinterpret_cast(internal_data.data()), internal_data.size(), arrow_null_bytemap_raw_ptr); - checkStatus(status, write_column->getName()); - - status = builder.Finish(&arrow_array); - checkStatus(status, write_column->getName()); -*/ -} - -# define FOR_INTERNAL_NUMERIC_TYPES(M) \ - M(UInt8, arrow::UInt8Builder) \ - M(Int8, arrow::Int8Builder) \ - M(UInt16, arrow::UInt16Builder) \ - M(Int16, arrow::Int16Builder) \ - M(UInt32, arrow::UInt32Builder) \ - M(Int32, arrow::Int32Builder) \ - M(UInt64, arrow::UInt64Builder) \ - M(Int64, arrow::Int64Builder) \ - M(Float32, arrow::FloatBuilder) \ - M(Float64, arrow::DoubleBuilder) - -const std::unordered_map> internal_type_to_arrow_type = { - {"UInt8", arrow::uint8()}, - {"Int8", arrow::int8()}, - {"UInt16", arrow::uint16()}, - {"Int16", arrow::int16()}, - {"UInt32", arrow::uint32()}, - {"Int32", arrow::int32()}, - {"UInt64", arrow::uint64()}, - {"Int64", arrow::int64()}, - {"Float32", arrow::float32()}, - {"Float64", arrow::float64()}, - - //{"Date", arrow::date64()}, - //{"Date", arrow::date32()}, - {"Date", arrow::uint16()}, // CHECK - //{"DateTime", arrow::date64()}, // BUG! saves as date32 - {"DateTime", arrow::uint32()}, - - // TODO: ClickHouse can actually store non-utf8 strings! - {"String", arrow::utf8()}, - {"FixedString", arrow::utf8()}, -}; - -const PaddedPODArray * extractNullBytemapPtr(ColumnPtr column) -{ - ColumnPtr null_column = static_cast(*column).getNullMapColumnPtr(); - const PaddedPODArray & null_bytemap = static_cast &>(*null_column).getData(); - return &null_bytemap; -} - - -class OstreamOutputStream : public parquet::OutputStream -{ -public: - explicit OstreamOutputStream(WriteBuffer & ostr_) : ostr(ostr_) {} - virtual ~OstreamOutputStream() {} - virtual void Close() {} - virtual int64_t Tell() { return total_length; } - virtual void Write(const uint8_t * data, int64_t length) - { - ostr.write(reinterpret_cast(data), length); - total_length += length; - } - -private: - WriteBuffer & ostr; - int64_t total_length = 0; - - PARQUET_DISALLOW_COPY_AND_ASSIGN(OstreamOutputStream); -}; - - -void ParquetBlockOutputStream::write(const Block & block) -{ - block.checkNumberOfRows(); - - const size_t columns_num = block.columns(); - - /// For arrow::Schema and arrow::Table creation - std::vector> arrow_fields; - std::vector> arrow_arrays; - arrow_fields.reserve(columns_num); - arrow_arrays.reserve(columns_num); - - for (size_t column_i = 0; column_i < columns_num; ++column_i) - { - // TODO: constructed every iteration - const ColumnWithTypeAndName & column = block.safeGetByPosition(column_i); - - const bool is_column_nullable = column.type->isNullable(); - const auto & column_nested_type - = is_column_nullable ? static_cast(column.type.get())->getNestedType() : column.type; - const std::string column_nested_type_name = column_nested_type->getFamilyName(); - - if (isDecimal(column_nested_type)) - { - const auto add_decimal_field = [&](const auto & types) -> bool { - using Types = std::decay_t; - using ToDataType = typename Types::LeftType; - - if constexpr ( - std::is_same_v< - ToDataType, - DataTypeDecimal< - Decimal32>> || std::is_same_v> || std::is_same_v>) - { - const auto & decimal_type = static_cast(column_nested_type.get()); - arrow_fields.emplace_back(std::make_shared( - column.name, arrow::decimal(decimal_type->getPrecision(), decimal_type->getScale()), is_column_nullable)); - } - - return false; - }; - callOnIndexAndDataType(column_nested_type->getTypeId(), add_decimal_field); - } - else - { - if (internal_type_to_arrow_type.find(column_nested_type_name) == internal_type_to_arrow_type.end()) - { - throw Exception{"The type \"" + column_nested_type_name + "\" of a column \"" + column.name - + "\"" - " is not supported for conversion into a Parquet data format", - ErrorCodes::UNKNOWN_TYPE}; - } - - arrow_fields.emplace_back(std::make_shared(column.name, internal_type_to_arrow_type.at(column_nested_type_name), is_column_nullable)); - } - - std::shared_ptr arrow_array; - - ColumnPtr nested_column - = is_column_nullable ? static_cast(*column.column).getNestedColumnPtr() : column.column; - const PaddedPODArray * null_bytemap = is_column_nullable ? extractNullBytemapPtr(column.column) : nullptr; - - if ("String" == column_nested_type_name) - { - fillArrowArrayWithStringColumnData(nested_column, arrow_array, null_bytemap); - } - else if ("FixedString" == column_nested_type_name) - { - fillArrowArrayWithStringColumnData(nested_column, arrow_array, null_bytemap); - } - else if ("Date" == column_nested_type_name) - { - fillArrowArrayWithDateColumnData(nested_column, arrow_array, null_bytemap); - } - else if ("DateTime" == column_nested_type_name) - { - fillArrowArrayWithDateTimeColumnData(nested_column, arrow_array, null_bytemap); - } - - else if (isDecimal(column_nested_type)) - { - auto fill_decimal = [&](const auto & types) -> bool - { - using Types = std::decay_t; - using ToDataType = typename Types::LeftType; - if constexpr ( - std::is_same_v< - ToDataType, - DataTypeDecimal< - Decimal32>> || std::is_same_v> || std::is_same_v>) - { - const auto & decimal_type = static_cast(column_nested_type.get()); - fillArrowArrayWithDecimalColumnData(nested_column, arrow_array, null_bytemap, decimal_type); - } - return false; - }; - callOnIndexAndDataType(column_nested_type->getTypeId(), fill_decimal); - } -# define DISPATCH(CPP_NUMERIC_TYPE, ARROW_BUILDER_TYPE) \ - else if (#CPP_NUMERIC_TYPE == column_nested_type_name) \ - { \ - fillArrowArrayWithNumericColumnData(nested_column, arrow_array, null_bytemap); \ - } - - FOR_INTERNAL_NUMERIC_TYPES(DISPATCH) -# undef DISPATCH - else - { - throw Exception{"Internal type \"" + column_nested_type_name + "\" of a column \"" + column.name - + "\"" - " is not supported for conversion into a Parquet data format", - ErrorCodes::UNKNOWN_TYPE}; - } - - - arrow_arrays.emplace_back(std::move(arrow_array)); - } - - std::shared_ptr arrow_schema = std::make_shared(std::move(arrow_fields)); - - std::shared_ptr arrow_table = arrow::Table::Make(arrow_schema, arrow_arrays); - - auto sink = std::make_shared(ostr); - - if (!file_writer) - { - - parquet::WriterProperties::Builder builder; -#if USE_SNAPPY - builder.compression(parquet::Compression::SNAPPY); -#endif - auto props = builder.build(); - auto status = parquet::arrow::FileWriter::Open( - *arrow_table->schema(), - arrow::default_memory_pool(), - sink, - props, /*parquet::default_writer_properties(),*/ - parquet::arrow::default_arrow_writer_properties(), - &file_writer); - if (!status.ok()) - throw Exception{"Error while opening a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; - } - - // TODO: calculate row_group_size depending on a number of rows and table size - auto status = file_writer->WriteTable(*arrow_table, format_settings.parquet.row_group_size); - - if (!status.ok()) - throw Exception{"Error while writing a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; -} - -void ParquetBlockOutputStream::writeSuffix() -{ - if (file_writer) - { - auto status = file_writer->Close(); - if (!status.ok()) - throw Exception{"Error while closing a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION}; - } -} - - -void registerOutputFormatParquet(FormatFactory & factory) -{ - factory.registerOutputFormat( - "Parquet", [](WriteBuffer & buf, const Block & sample, const Context & /*context*/, const FormatSettings & format_settings) - { - BlockOutputStreamPtr impl = std::make_shared(buf, sample, format_settings); - auto res = std::make_shared(impl, impl->getHeader(), format_settings.parquet.row_group_size, 0); - res->disableFlush(); - return res; - }); -} - -} - - -#else - -namespace DB -{ -class FormatFactory; -void registerOutputFormatParquet(FormatFactory &) -{ -} -} - - -#endif diff --git a/dbms/src/Formats/ProtobufRowInputStream.cpp b/dbms/src/Formats/ProtobufRowInputStream.cpp deleted file mode 100644 index 8dcff7bda36..00000000000 --- a/dbms/src/Formats/ProtobufRowInputStream.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "ProtobufRowInputStream.h" - -#if USE_PROTOBUF -#include -#include -#include -#include -#include - - -namespace DB -{ - -ProtobufRowInputStream::ProtobufRowInputStream(ReadBuffer & in_, const Block & header, const FormatSchemaInfo & format_schema) - : data_types(header.getDataTypes()), reader(in_, ProtobufSchemas::instance().getMessageTypeForFormatSchema(format_schema), header.getNames()) -{ -} - -ProtobufRowInputStream::~ProtobufRowInputStream() = default; - -bool ProtobufRowInputStream::read(MutableColumns & columns, RowReadExtension & extra) -{ - if (!reader.startMessage()) - return false; // EOF reached, no more messages. - - // Set of columns for which the values were read. The rest will be filled with default values. - auto & read_columns = extra.read_columns; - read_columns.assign(columns.size(), false); - - // Read values from this message and put them to the columns while it's possible. - size_t column_index; - while (reader.readColumnIndex(column_index)) - { - bool allow_add_row = !static_cast(read_columns[column_index]); - do - { - bool row_added; - data_types[column_index]->deserializeProtobuf(*columns[column_index], reader, allow_add_row, row_added); - if (row_added) - { - read_columns[column_index] = true; - allow_add_row = false; - } - } while (reader.canReadMoreValues()); - } - - // Fill non-visited columns with the default values. - for (column_index = 0; column_index < read_columns.size(); ++column_index) - if (!read_columns[column_index]) - data_types[column_index]->insertDefaultInto(*columns[column_index]); - - reader.endMessage(); - return true; -} - -bool ProtobufRowInputStream::allowSyncAfterError() const -{ - return true; -} - -void ProtobufRowInputStream::syncAfterError() -{ - reader.endMessage(true); -} - - -void registerInputFormatProtobuf(FormatFactory & factory) -{ - factory.registerInputFormat("Protobuf", []( - ReadBuffer & buf, - const Block & sample, - const Context & context, - UInt64 max_block_size, - UInt64 rows_portion_size, - FormatFactory::ReadCallback callback, - const FormatSettings & settings) - { - return std::make_shared( - std::make_shared(buf, sample, FormatSchemaInfo(context, "Protobuf")), - sample, max_block_size, rows_portion_size, callback, settings); - }); -} - -} - -#else - -namespace DB -{ -class FormatFactory; -void registerInputFormatProtobuf(FormatFactory &) {} -} - -#endif From 39b8141418543d873d6e2fd279de8a283a438982 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Mon, 5 Aug 2019 01:48:04 +0800 Subject: [PATCH 072/105] Fix recursive materialized view --- .../PushingToViewsBlockOutputStream.cpp | 2 ++ ...00975_recursive_materialized_view.reference | 4 ++++ .../00975_recursive_materialized_view.sql | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00975_recursive_materialized_view.reference create mode 100644 dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql diff --git a/dbms/src/DataStreams/PushingToViewsBlockOutputStream.cpp b/dbms/src/DataStreams/PushingToViewsBlockOutputStream.cpp index 1b369f79c63..7a71384c8dd 100644 --- a/dbms/src/DataStreams/PushingToViewsBlockOutputStream.cpp +++ b/dbms/src/DataStreams/PushingToViewsBlockOutputStream.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -192,6 +193,7 @@ void PushingToViewsBlockOutputStream::process(const Block & block, size_t view_n /// and two-level aggregation is triggered). in = std::make_shared( in, context.getSettingsRef().min_insert_block_size_rows, context.getSettingsRef().min_insert_block_size_bytes); + in = std::make_shared(context, in, view.out->getHeader(), ConvertingBlockInputStream::MatchColumnsMode::Position); in->readPrefix(); diff --git a/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.reference b/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.reference new file mode 100644 index 00000000000..c0a74072125 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.reference @@ -0,0 +1,4 @@ +2 +3 +3 +4 diff --git a/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql b/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql new file mode 100644 index 00000000000..1056644a1f4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql @@ -0,0 +1,18 @@ +DROP TABLE IF EXISTS test.src; +DROP TABLE IF EXISTS test.dst1; +DROP TABLE IF EXISTS test.dst2; + +USE test; + +CREATE TABLE src (x UInt8) ENGINE Memory; +CREATE TABLE dst1 (x UInt8) ENGINE Memory; +CREATE MATERIALIZED VIEW src_to_dst1 TO dst1 AS SELECT x + 1 as x FROM src; +CREATE MATERIALIZED VIEW dst2 ENGINE Memory AS SELECT x + 1 as x FROM dst1; + +INSERT INTO src VALUES (1), (2); +SELECT * FROM dst1 ORDER BY x; +SELECT * FROM dst2 ORDER BY x; + +DROP TABLE src; +DROP TABLE dst1; +DROP TABLE dst2; From 1e6972b38ee8efecefac45e0702c9d881dcbcf71 Mon Sep 17 00:00:00 2001 From: VDimir Date: Mon, 5 Aug 2019 02:24:16 +0300 Subject: [PATCH 073/105] Added optional message argument in throwIf (#5772) --- dbms/src/Functions/throwIf.cpp | 51 ++++++++++++++----- .../0_stateless/00602_throw_if.reference | 1 + .../queries/0_stateless/00602_throw_if.sh | 8 +-- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/dbms/src/Functions/throwIf.cpp b/dbms/src/Functions/throwIf.cpp index 15584aa26a7..16d7d553e87 100644 --- a/dbms/src/Functions/throwIf.cpp +++ b/dbms/src/Functions/throwIf.cpp @@ -1,9 +1,11 @@ #include #include #include +#include #include #include #include +#include namespace DB @@ -13,6 +15,7 @@ namespace ErrorCodes { extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int FUNCTION_THROW_IF_VALUE_IS_NON_ZERO; } @@ -32,6 +35,7 @@ public: return name; } + bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 1; @@ -39,9 +43,21 @@ public: DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { - if (!isNativeNumber(arguments.front())) + const size_t number_of_arguments = arguments.size(); + + if (number_of_arguments < 1 || number_of_arguments > 2) + throw Exception{"Number of arguments for function " + getName() + " doesn't match: passed " + + toString(number_of_arguments) + ", should be 1 or 2", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + + if (!isNativeNumber(arguments[0])) throw Exception{"Argument for function " + getName() + " must be number", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + if (number_of_arguments > 1 && !isString(arguments[1])) + throw Exception{"Illegal type " + arguments[1]->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + + return std::make_shared(); } @@ -49,29 +65,38 @@ public: void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override { + std::optional custom_message; + if (arguments.size() == 2) { + auto * msg_column = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); + if (!msg_column) + throw Exception{"Second argument for function " + getName() + " must be constant String", ErrorCodes::ILLEGAL_COLUMN}; + custom_message = msg_column->getValue(); + } + const auto in = block.getByPosition(arguments.front()).column.get(); - if ( !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result) - && !execute(block, in, result)) + if ( !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message) + && !execute(block, in, result, custom_message)) throw Exception{"Illegal column " + in->getName() + " of first argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN}; } template - bool execute(Block & block, const IColumn * in_untyped, const size_t result) + bool execute(Block & block, const IColumn * in_untyped, const size_t result, const std::optional & message) { if (const auto in = checkAndGetColumn>(in_untyped)) { const auto & in_data = in->getData(); if (!memoryIsZero(in_data.data(), in_data.size() * sizeof(in_data[0]))) - throw Exception("Value passed to 'throwIf' function is non zero", ErrorCodes::FUNCTION_THROW_IF_VALUE_IS_NON_ZERO); + throw Exception{message.value_or("Value passed to '" + getName() + "' function is non zero"), + ErrorCodes::FUNCTION_THROW_IF_VALUE_IS_NON_ZERO}; /// We return non constant to avoid constant folding. block.getByPosition(result).column = ColumnUInt8::create(in_data.size(), 0); diff --git a/dbms/tests/queries/0_stateless/00602_throw_if.reference b/dbms/tests/queries/0_stateless/00602_throw_if.reference index d0752a77fc7..ad5aaee89a8 100644 --- a/dbms/tests/queries/0_stateless/00602_throw_if.reference +++ b/dbms/tests/queries/0_stateless/00602_throw_if.reference @@ -1,2 +1,3 @@ 1 +1 1000000 diff --git a/dbms/tests/queries/0_stateless/00602_throw_if.sh b/dbms/tests/queries/0_stateless/00602_throw_if.sh index 8dae5033978..3c790d900d3 100755 --- a/dbms/tests/queries/0_stateless/00602_throw_if.sh +++ b/dbms/tests/queries/0_stateless/00602_throw_if.sh @@ -3,7 +3,9 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) . $CURDIR/../shell_config.sh -exception_pattern="Value passed to 'throwIf' function is non zero" +default_exception_message="Value passed to 'throwIf' function is non zero" +custom_exception_message="Number equals 1000000" -${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT throwIf(number = 1000000) FROM system.numbers" 2>&1 | grep -cF "$exception_pattern" -${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT sum(x = 0) FROM (SELECT throwIf(number = 1000000) AS x FROM numbers(1000000))" 2>&1 +${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT throwIf(number = 1000000) FROM system.numbers" 2>&1 | grep -cF "$default_exception_message" +${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT throwIf(number = 1000000, '$custom_exception_message') FROM system.numbers" 2>&1 | grep -cF "$custom_exception_message" +${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT sum(x = 0) FROM (SELECT throwIf(number = 1000000) AS x FROM numbers(1000000))" 2>&1 \ No newline at end of file From e994f45b6cd414eefdb65f7a630168821c95a3e6 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Mon, 5 Aug 2019 11:30:30 +0800 Subject: [PATCH 074/105] update --- .../0_stateless/00148_summing_merge_tree_aggregate_function.sql | 2 +- .../queries/0_stateless/00975_recursive_materialized_view.sql | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00148_summing_merge_tree_aggregate_function.sql b/dbms/tests/queries/0_stateless/00148_summing_merge_tree_aggregate_function.sql index da67212fca7..eab6b9da465 100644 --- a/dbms/tests/queries/0_stateless/00148_summing_merge_tree_aggregate_function.sql +++ b/dbms/tests/queries/0_stateless/00148_summing_merge_tree_aggregate_function.sql @@ -137,7 +137,7 @@ create table summing_merge_tree_null ( ) engine=Null; create materialized view summing_merge_tree_aggregate_function ( - d materialized today(), + d Date, k UInt64, c UInt64, u AggregateFunction(uniq, UInt64) diff --git a/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql b/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql index 1056644a1f4..21bf0381cd4 100644 --- a/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql +++ b/dbms/tests/queries/0_stateless/00975_recursive_materialized_view.sql @@ -14,5 +14,6 @@ SELECT * FROM dst1 ORDER BY x; SELECT * FROM dst2 ORDER BY x; DROP TABLE src; +DROP TABLE src_to_dst1; DROP TABLE dst1; DROP TABLE dst2; From 259364a4f87a90bcc98ca51c31c7bf63201d53a8 Mon Sep 17 00:00:00 2001 From: VDimir Date: Mon, 5 Aug 2019 09:38:52 +0300 Subject: [PATCH 075/105] Minor fixes in throwIf implementation --- dbms/src/Functions/throwIf.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dbms/src/Functions/throwIf.cpp b/dbms/src/Functions/throwIf.cpp index 16d7d553e87..dc4ac4950e8 100644 --- a/dbms/src/Functions/throwIf.cpp +++ b/dbms/src/Functions/throwIf.cpp @@ -38,7 +38,7 @@ public: bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { - return 1; + return 0; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override @@ -62,11 +62,13 @@ public: } bool useDefaultImplementationForConstants() const override { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; } void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override { std::optional custom_message; - if (arguments.size() == 2) { + if (arguments.size() == 2) + { auto * msg_column = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!msg_column) throw Exception{"Second argument for function " + getName() + " must be constant String", ErrorCodes::ILLEGAL_COLUMN}; From bd8c9733e30119c7f0f43034a167561c86891d78 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 5 Aug 2019 12:35:46 +0300 Subject: [PATCH 076/105] Update MySQLOutputFormat. --- dbms/src/Processors/Formats/IOutputFormat.h | 4 +- .../Formats/Impl/MySQLOutputFormat.cpp | 42 +++++++++++-------- .../Formats/Impl/MySQLOutputFormat.h | 4 ++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/dbms/src/Processors/Formats/IOutputFormat.h b/dbms/src/Processors/Formats/IOutputFormat.h index 3242ab9da9a..53e5b9e2158 100644 --- a/dbms/src/Processors/Formats/IOutputFormat.h +++ b/dbms/src/Processors/Formats/IOutputFormat.h @@ -64,8 +64,8 @@ public: void write(const Block & block) { consume(Chunk(block.getColumns(), block.rows())); } - void doWritePrefix() {} - void doWriteSuffix() { finalize(); } + virtual void doWritePrefix() {} + virtual void doWriteSuffix() { finalize(); } void setTotals(const Block & totals) { consumeTotals(Chunk(totals.getColumns(), totals.rows())); } void setExtremes(const Block & extremes) { consumeExtremes(Chunk(extremes.getColumns(), extremes.rows())); } diff --git a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp index 0487d6334b1..2e48d0643e9 100644 --- a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp +++ b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.cpp @@ -23,32 +23,40 @@ MySQLOutputFormat::MySQLOutputFormat(WriteBuffer & out_, const Block & header, c packet_sender.max_packet_size = context.mysql.max_packet_size; } -void MySQLOutputFormat::consume(Chunk chunk) +void MySQLOutputFormat::initialize() { + if (initialized) + return; + + initialized = true; auto & header = getPort(PortKind::Main).getHeader(); - if (!initialized) + + if (header.columns()) { - initialized = true; - if (header.columns()) + packet_sender.sendPacket(LengthEncodedNumber(header.columns())); + + for (const ColumnWithTypeAndName & column : header.getColumnsWithTypeAndName()) { + ColumnDefinition column_definition(column.name, CharacterSet::binary, 0, ColumnType::MYSQL_TYPE_STRING, + 0, 0); + packet_sender.sendPacket(column_definition); + } - packet_sender.sendPacket(LengthEncodedNumber(header.columns())); - - for (const ColumnWithTypeAndName & column : header.getColumnsWithTypeAndName()) - { - ColumnDefinition column_definition(column.name, CharacterSet::binary, 0, ColumnType::MYSQL_TYPE_STRING, - 0, 0); - packet_sender.sendPacket(column_definition); - } - - if (!(context.mysql.client_capabilities & Capability::CLIENT_DEPRECATE_EOF)) - { - packet_sender.sendPacket(EOF_Packet(0, 0)); - } + if (!(context.mysql.client_capabilities & Capability::CLIENT_DEPRECATE_EOF)) + { + packet_sender.sendPacket(EOF_Packet(0, 0)); } } +} + + +void MySQLOutputFormat::consume(Chunk chunk) +{ + initialize(); + + auto & header = getPort(PortKind::Main).getHeader(); size_t rows = chunk.getNumRows(); auto & columns = chunk.getColumns(); diff --git a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h index b9457a6369d..e6b319f659a 100644 --- a/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h +++ b/dbms/src/Processors/Formats/Impl/MySQLOutputFormat.h @@ -26,6 +26,10 @@ public: void consume(Chunk) override; void finalize() override; void flush() override; + void doWritePrefix() override { initialize(); } + + void initialize(); + private: bool initialized = false; From 0e09b7cc33c2f1464519ff3010de58d11c8937c4 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Mon, 5 Aug 2019 18:50:42 +0800 Subject: [PATCH 077/105] continue translate domain data type --- docs/zh/data_types/domains/ipv4.md | 15 ++++++------ docs/zh/data_types/domains/ipv6.md | 15 ++++++------ docs/zh/data_types/domains/overview.md | 32 +++++++++++++------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/zh/data_types/domains/ipv4.md b/docs/zh/data_types/domains/ipv4.md index 1dd2cb03794..4adf13409fe 120000 --- a/docs/zh/data_types/domains/ipv4.md +++ b/docs/zh/data_types/domains/ipv4.md @@ -1,7 +1,6 @@ ## IPv4 -`IPv4` 是基于 `UInt32` 的domain类型,用来存储IPv4地址。它使用紧凑的存储方式,提供用户友好的输入输出格式, -自动检查列类型。 +`IPv4`是与`UInt32`类型保持二进制兼容的Domain类型,其用于存储IPv4地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。 ### 基本使用 @@ -18,13 +17,13 @@ DESCRIBE TABLE hits; └──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ ``` -您也可以使用IPv4 domain作主键: +同时您也可以使用`IPv4`类型的列作为主键: ``` sql CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY from; ``` -`IPv4` domain支持定制化的IPv4地址字符串格式: +在写入与查询时,`IPv4`类型能够识别可读性更加友好的输入输出格式: ``` sql INSERT INTO hits (url, from) VALUES ('https://wikipedia.org', '116.253.40.133')('https://clickhouse.yandex', '183.247.232.58')('https://clickhouse.yandex/docs/en/', '116.106.34.242'); @@ -40,7 +39,7 @@ SELECT * FROM hits; └────────────────────────────────────┴────────────────┘ ``` -数据值以紧凑的二进制格式存储: +同时它提供更为紧凑的二进制存储格式: ``` sql SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; @@ -52,7 +51,7 @@ SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; └──────────────────┴───────────┘ ``` -Domain不可隐式转换为除`UInt32`以外的类型。如果要将IPv4值转换为字符串,则必须使用`IPv4NumToString()`函数显示的进行此操作。 +不可隐式转换为除`UInt32`以外的其他类型类型。如果要将`IPv4`类型的值转换成字符串,你可以使用`IPv4NumToString()`显示的进行转换: ``` sql SELECT toTypeName(s), IPv4NumToString(from) as s FROM hits LIMIT 1; @@ -64,7 +63,7 @@ SELECT toTypeName(s), IPv4NumToString(from) as s FROM hits LIMIT 1; └───────────────────────────────────┴────────────────┘ ``` -或转换为 `UInt32` 类型: +或可以使用`CAST`将它转换为`UInt32`类型: ``` sql SELECT toTypeName(i), CAST(from as UInt32) as i FROM hits LIMIT 1; @@ -76,4 +75,4 @@ SELECT toTypeName(i), CAST(from as UInt32) as i FROM hits LIMIT 1; └──────────────────────────────────┴────────────┘ ``` -[Original article](https://clickhouse.yandex/docs/en/data_types/domains/ipv4) +[来源文章](https://clickhouse.yandex/docs/en/data_types/domains/ipv4) diff --git a/docs/zh/data_types/domains/ipv6.md b/docs/zh/data_types/domains/ipv6.md index 13c6809e4a9..1209350990f 120000 --- a/docs/zh/data_types/domains/ipv6.md +++ b/docs/zh/data_types/domains/ipv6.md @@ -1,6 +1,6 @@ ## IPv6 -`IPv6` 是基于`FixedString(16)` 类型的domain类型,用来存储IPv6地址值。它使用紧凑的存储方式,提供用户友好的输入输出格式, 自动检查列类型。 +`IPv6`是与`FixedString(16)`类型保持二进制兼容的Domain类型,其用于存储IPv6地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。 ### 基本用法 @@ -17,13 +17,13 @@ DESCRIBE TABLE hits; └──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ ``` -您也可以使用 `IPv6`domain做主键: +同时您也可以使用`IPv6`类型的列作为主键: ``` sql CREATE TABLE hits (url String, from IPv6) ENGINE = MergeTree() ORDER BY from; ``` -`IPv6` domain支持定制化的IPv6地址字符串格式: +在写入与查询时,`IPv6`类型能够识别可读性更加友好的输入输出格式: ``` sql INSERT INTO hits (url, from) VALUES ('https://wikipedia.org', '2a02:aa08:e000:3100::2')('https://clickhouse.yandex', '2001:44c8:129:2632:33:0:252:2')('https://clickhouse.yandex/docs/en/', '2a02:e980:1e::1'); @@ -39,7 +39,7 @@ SELECT * FROM hits; └────────────────────────────────────┴───────────────────────────────┘ ``` -它以紧凑的二进制格式存储数值: +同时它提供更为紧凑的二进制存储格式: ``` sql SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; @@ -50,7 +50,8 @@ SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; │ IPv6 │ 200144C8012926320033000002520002 │ └──────────────────┴──────────────────────────────────┘ ``` -Domain不可隐式转换为除`FixedString(16)`以外的类型。如果要将`IPv6`值转换为字符串,则必须使用`IPv6NumToString()`函数显示地进行此操作: + +不可隐式转换为除`FixedString(16)`以外的其他类型类型。如果要将`IPv6`类型的值转换成字符串,你可以使用`IPv6NumToString()`显示的进行转换: ``` sql SELECT toTypeName(s), IPv6NumToString(from) as s FROM hits LIMIT 1; @@ -62,7 +63,7 @@ SELECT toTypeName(s), IPv6NumToString(from) as s FROM hits LIMIT 1; └───────────────────────────────────┴───────────────────────────────┘ ``` -或转换为 `FixedString(16)`类型: +或使用`CAST`将其转换为`FixedString(16)`: ``` sql SELECT toTypeName(i), CAST(from as FixedString(16)) as i FROM hits LIMIT 1; @@ -74,4 +75,4 @@ SELECT toTypeName(i), CAST(from as FixedString(16)) as i FROM hits LIMIT 1; └───────────────────────────────────────────┴─────────┘ ``` -[Original article](https://clickhouse.yandex/docs/en/data_types/domains/ipv6) +[来源文章](https://clickhouse.yandex/docs/en/data_types/domains/ipv6) diff --git a/docs/zh/data_types/domains/overview.md b/docs/zh/data_types/domains/overview.md index 25fc5d3850a..b4db116e75b 120000 --- a/docs/zh/data_types/domains/overview.md +++ b/docs/zh/data_types/domains/overview.md @@ -1,26 +1,26 @@ # Domains -Domains是特殊用途的类型,它在现有的基础类型之上添加了一些额外的特性,能够让线上和磁盘上的表格式保持不变。目前,ClickHouse暂不支持自定义的domains. +Domain类型是特定实现的类型,它总是与某个现存的基础类型保持二进制兼容的同时添加一些额外的特性,以能够在维持磁盘数据不变的情况下使用这些额外的特性。目前ClickHouse暂不支持自定义domain类型。 -您可以在任何地方使用domains,相应的基础类型的使用方式如下: +如果你可以在一个地方使用与Domain类型二进制兼容的基础类型,那么在相同的地方您也可以使用Domain类型,例如: -* 构建一列domain类型的数据 -* 从/向domain列读/写数据 -* 作为索引,如果基础类型能够被作为索引的话 -* 以domain列的值作为参数调用函数 -* 等等. +* 使用Domain类型作为表中列的类型 +* 对Domain类型的列进行读/写数据 +* 如果与Domain二进制兼容的基础类型可以作为索引,那么Domain类型也可以作为索引 +* 将Domain类型作为参数传递给函数使用 +* 其他 ### Domains的额外特性 -* 在使用`SHOW CREATE TABLE` 或 `DESCRIBE TABLE`时,明确地显示列类型名称 -* 使用 `INSERT INTO domain_table(domain_column) VALUES(...)`实现人性化格式输入 -* 使用`SELECT domain_column FROM domain_table`实现人性化格式输出 -* 使用 `INSERT INTO domain_table FORMAT CSV ...`实现外部源数据的人性化格式载入 +* 在执行SHOW CREATE TABLE 或 DESCRIBE TABLE时,其对应的列总是展示为Domain类型的名称 +* 在INSERT INTO domain_table(domain_column) VALUES(...)中输入数据总是以更人性化的格式进行输入 +* 在SELECT domain_column FROM domain_table中数据总是以更人性化的格式输出 +* 在INSERT INTO domain_table FORMAT CSV ...中,实现外部源数据以更人性化的格式载入 -### 缺陷 +### Domains类型的限制 -* 无法通过 `ALTER TABLE`将基础类型的索引转换为domain类型的索引. -* 当从其他列或表插入数据时,无法将string类型的值隐式地转换为domain类型的值. -* 无法对存储为domain类型的值添加约束. +* 无法通过`ALTER TABLE`将基础类型的索引转换为Domain类型的索引。 +* 当从其他列或表插入数据时,无法将string类型的值隐式地转换为Domain类型的值。 +* 无法对存储为Domain类型的值添加约束。 -[Original article](https://clickhouse.yandex/docs/en/data_types/domains/overview) +[来源文章](https://clickhouse.yandex/docs/en/data_types/domains/overview) From ef7d19e1433f18420f724c5418be87fa2330a160 Mon Sep 17 00:00:00 2001 From: chertus Date: Mon, 5 Aug 2019 17:03:14 +0300 Subject: [PATCH 078/105] better JOIN exception messages #5565 --- dbms/src/Common/ErrorCodes.cpp | 2 +- dbms/src/Interpreters/Join.cpp | 7 ++++--- dbms/src/Interpreters/SetVariants.cpp | 1 - dbms/src/Storages/StorageJoin.cpp | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index 56598aa2e89..cd4601e5b3d 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -127,7 +127,7 @@ namespace ErrorCodes extern const int INCORRECT_DATA = 117; extern const int ENGINE_REQUIRED = 119; extern const int CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE = 120; - extern const int UNKNOWN_SET_DATA_VARIANT = 121; + extern const int UNSUPPORTED_JOIN_KEYS = 121; extern const int INCOMPATIBLE_COLUMNS = 122; extern const int UNKNOWN_TYPE_OF_AST_NODE = 123; extern const int INCORRECT_ELEMENT_OF_SET = 124; diff --git a/dbms/src/Interpreters/Join.cpp b/dbms/src/Interpreters/Join.cpp index ccd5e76161b..9f1a69fba70 100644 --- a/dbms/src/Interpreters/Join.cpp +++ b/dbms/src/Interpreters/Join.cpp @@ -26,7 +26,7 @@ namespace DB namespace ErrorCodes { - extern const int UNKNOWN_SET_DATA_VARIANT; + extern const int UNSUPPORTED_JOIN_KEYS; extern const int LOGICAL_ERROR; extern const int SET_SIZE_LIMIT_EXCEEDED; extern const int TYPE_MISMATCH; @@ -770,7 +770,7 @@ IColumn::Filter switchJoinRightColumns( #undef M default: - throw Exception("Unknown JOIN keys variant.", ErrorCodes::UNKNOWN_SET_DATA_VARIANT); + throw Exception("Unsupported JOIN keys. Type: " + toString(static_cast(type)), ErrorCodes::UNSUPPORTED_JOIN_KEYS); } } @@ -1350,7 +1350,8 @@ private: APPLY_FOR_JOIN_VARIANTS(M) #undef M default: - throw Exception("Unknown JOIN keys variant.", ErrorCodes::UNKNOWN_SET_DATA_VARIANT); + throw Exception("Unsupported JOIN keys. Type: " + toString(static_cast(parent.type)), + ErrorCodes::UNSUPPORTED_JOIN_KEYS); } __builtin_unreachable(); diff --git a/dbms/src/Interpreters/SetVariants.cpp b/dbms/src/Interpreters/SetVariants.cpp index 8b5e8fbc984..281304f886e 100644 --- a/dbms/src/Interpreters/SetVariants.cpp +++ b/dbms/src/Interpreters/SetVariants.cpp @@ -8,7 +8,6 @@ namespace DB namespace ErrorCodes { - extern const int UNKNOWN_SET_DATA_VARIANT; extern const int LOGICAL_ERROR; } diff --git a/dbms/src/Storages/StorageJoin.cpp b/dbms/src/Storages/StorageJoin.cpp index 8a38c6fa8ff..3c90917b0f6 100644 --- a/dbms/src/Storages/StorageJoin.cpp +++ b/dbms/src/Storages/StorageJoin.cpp @@ -18,7 +18,7 @@ namespace DB namespace ErrorCodes { - extern const int UNKNOWN_SET_DATA_VARIANT; + extern const int UNSUPPORTED_JOIN_KEYS; extern const int NO_SUCH_COLUMN_IN_TABLE; extern const int INCOMPATIBLE_TYPE_OF_JOIN; extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; @@ -285,7 +285,8 @@ private: #undef M default: - throw Exception("Unknown JOIN keys variant for limited use", ErrorCodes::UNKNOWN_SET_DATA_VARIANT); + throw Exception("Unsupported JOIN keys in StorageJoin. Type: " + toString(static_cast(parent.type)), + ErrorCodes::UNSUPPORTED_JOIN_KEYS); } if (!rows_added) From a7db4255926d984572370193cf36096950758b2c Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Mon, 5 Aug 2019 22:15:15 +0800 Subject: [PATCH 079/105] Optimize Count() Cond. Follow up https://github.com/yandex/ClickHouse/pull/6028 --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 34 +++++++++++++------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 13f9458b835..e60bdc94a58 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -982,6 +982,18 @@ void ExpressionAnalyzer::getAggregateInfo(Names & key_names, AggregateDescriptio aggregates = aggregate_descriptions; } +struct ColumnExt +{ + size_t compressed_size; + size_t type_size; + size_t uncompressed_size; + String name; + bool operator<(const ColumnExt & that) const + { + return std::tie(compressed_size, type_size, uncompressed_size) < std::tie(that.compressed_size, that.type_size, that.uncompressed_size); + } +}; + void ExpressionAnalyzer::collectUsedColumns() { /** Calculate which columns are required to execute the expression. @@ -1040,23 +1052,23 @@ void ExpressionAnalyzer::collectUsedColumns() /// You need to read at least one column to find the number of rows. if (select_query && required.empty()) { - /// We will find a column with minimum compressed size. Because it is the column that is cheapest to read. - size_t min_data_compressed = 0; - String min_column_name; + /// We will find a column with minimum . + /// Because it is the column that is cheapest to read. + std::vector columns; if (storage) { auto column_sizes = storage->getColumnSizes(); - for (auto & [column_name, column_size] : column_sizes) + for (auto & source_column : source_columns) { - if (min_data_compressed == 0 || min_data_compressed > column_size.data_compressed) - { - min_data_compressed = column_size.data_compressed; - min_column_name = column_name; - } + auto c = column_sizes.find(source_column.name); + if (c == column_sizes.end()) + continue; + size_t type_size = source_column.type->haveMaximumSizeOfValue() ? source_column.type->getMaximumSizeOfValueInMemory() : 100; + columns.emplace_back(ColumnExt{c->second.data_compressed, type_size, c->second.data_uncompressed, source_column.name}); } } - if (min_data_compressed > 0) - required.insert(min_column_name); + if (columns.size()) + required.insert(std::min_element(columns.begin(), columns.end())->name); else /// If we have no information about columns sizes, choose a column of minimum size of its data type. required.insert(ExpressionActions::getSmallestColumn(source_columns)); From 50c39e8b863d6538d56cccc3dde1f0f917e0b90e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 5 Aug 2019 18:23:32 +0300 Subject: [PATCH 080/105] Added more checks in CAST function. --- dbms/src/Functions/FunctionsConversion.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index a83ae586d80..b0fcc0103d6 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -1632,6 +1632,7 @@ private: using ToDataType = DataTypeDecimal; TypeIndex type_index = from_type->getTypeId(); + UInt32 precision = to_type->getPrecision(); UInt32 scale = to_type->getScale(); WhichDataType which(type_index); @@ -1645,9 +1646,9 @@ private: throw Exception{"Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported", ErrorCodes::CANNOT_CONVERT_TYPE}; - return [type_index, scale] (Block & block, const ColumnNumbers & arguments, const size_t result, size_t input_rows_count) + return [type_index, precision, scale] (Block & block, const ColumnNumbers & arguments, const size_t result, size_t input_rows_count) { - callOnIndexAndDataType(type_index, [&](const auto & types) -> bool + auto res = callOnIndexAndDataType(type_index, [&](const auto & types) -> bool { using Types = std::decay_t; using LeftDataType = typename Types::LeftType; @@ -1656,6 +1657,14 @@ private: ConvertImpl::execute(block, arguments, result, input_rows_count, scale); return true; }); + + /// Additionally check if callOnIndexAndDataType wasn't called at all. + if (!res) + { + auto to = DataTypeDecimal(precision, scale); + throw Exception{"Conversion from " + std::string(getTypeName(type_index)) + " to " + to.getName() + + " is not supported", ErrorCodes::CANNOT_CONVERT_TYPE}; + } }; } @@ -2022,6 +2031,11 @@ private: const auto & tmp_res = tmp_block.getByPosition(tmp_res_index); + /// May happen in fuzzy tests. For debug purpose. + if (!tmp_res.column) + throw Exception("Couldn't convert " + block.getByPosition(arguments[0]).type->getName() + " to " + + nested_type->getName() + " in " + " prepareRemoveNullable wrapper.", ErrorCodes::LOGICAL_ERROR); + res.column = wrapInNullable(tmp_res.column, Block({block.getByPosition(arguments[0]), tmp_res}), {0}, 1, input_rows_count); }; } From 95532f2d31a766323ba2453f2982604955304794 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 5 Aug 2019 19:04:47 +0300 Subject: [PATCH 081/105] Fixed minor discrepancies --- dbms/src/Functions/GeoUtils.cpp | 4 ++-- dbms/src/Storages/System/StorageSystemDetachedParts.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Functions/GeoUtils.cpp b/dbms/src/Functions/GeoUtils.cpp index c055e3afa73..2c45b6d2cfc 100644 --- a/dbms/src/Functions/GeoUtils.cpp +++ b/dbms/src/Functions/GeoUtils.cpp @@ -62,7 +62,7 @@ inline Encoded encodeCoordinate(Float64 coord, Float64 min, Float64 max, UInt8 b Encoded result; result.fill(0); - for (int i = 0; i < bits; ++i) + for (size_t i = 0; i < bits; ++i) { Float64 mid = (max + min) / 2; if (coord >= mid) @@ -83,7 +83,7 @@ inline Encoded encodeCoordinate(Float64 coord, Float64 min, Float64 max, UInt8 b inline Float64 decodeCoordinate(const Encoded & coord, Float64 min, Float64 max, UInt8 bits) { Float64 mid = (max + min) / 2; - for (int i = 0; i < bits; ++i) + for (size_t i = 0; i < bits; ++i) { const auto c = coord[i]; if (c == 1) diff --git a/dbms/src/Storages/System/StorageSystemDetachedParts.cpp b/dbms/src/Storages/System/StorageSystemDetachedParts.cpp index 9ae6f7b607a..dbad9d8b604 100644 --- a/dbms/src/Storages/System/StorageSystemDetachedParts.cpp +++ b/dbms/src/Storages/System/StorageSystemDetachedParts.cpp @@ -59,7 +59,7 @@ protected: const auto parts = info.data->getDetachedParts(); for (auto & p : parts) { - int i = 0; + size_t i = 0; columns[i++]->insert(info.database); columns[i++]->insert(info.table); columns[i++]->insert(p.partition_id); From a19d05d6dfff3464edd344e616e815eaa65a2629 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 5 Aug 2019 19:05:37 +0300 Subject: [PATCH 082/105] Fixed minor discrepancies --- dbms/programs/server/MySQLHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/programs/server/MySQLHandler.cpp b/dbms/programs/server/MySQLHandler.cpp index c71e0554fb5..adf35501ee4 100644 --- a/dbms/programs/server/MySQLHandler.cpp +++ b/dbms/programs/server/MySQLHandler.cpp @@ -299,7 +299,7 @@ void MySQLHandler::authenticate(const HandshakeResponse & handshake_response, co } password.resize(plaintext_size); - for (int i = 0; i < plaintext_size; i++) + for (int i = 0; i < plaintext_size; ++i) { password[i] = plaintext[i] ^ static_cast(scramble[i % scramble.size()]); } From d5fd3c0a8a8091eb85dfc4c63c6819b4a5864d8f Mon Sep 17 00:00:00 2001 From: Vxider Date: Tue, 6 Aug 2019 00:25:26 +0800 Subject: [PATCH 083/105] build fix --- dbms/programs/server/Server.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index d97fe4aff2c..aff54b5e992 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -611,7 +611,7 @@ int Server::main(const std::vector & /*args*/) return socket_address; }; - auto socket_bind_listen = [&](auto & socket, const std::string & host, UInt16 port, [[maybe_unused]] bool secure = 0) + auto socket_bind_listen = [&](auto & socket, const std::string & host, [[maybe_unused]] UInt16 port, [[maybe_unused]] bool secure = 0) { auto address = make_socket_address(host, port); #if !defined(POCO_CLICKHOUSE_PATCH) || POCO_VERSION < 0x01090100 @@ -681,7 +681,7 @@ int Server::main(const std::vector & /*args*/) }); /// HTTPS - create_server("https_port", [&](UInt16 port) + create_server("https_port", [&]([[maybe_unused]]UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -718,7 +718,7 @@ int Server::main(const std::vector & /*args*/) }); /// TCP with SSL - create_server("tcp_port_secure", [&](UInt16 port) + create_server ("tcp_port_secure", [&]([[maybe_unused]]UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -753,7 +753,7 @@ int Server::main(const std::vector & /*args*/) LOG_INFO(log, "Listening for replica communication (interserver) http://" + address.toString()); }); - create_server("interserver_https_port", [&](UInt16 port) + create_server("interserver_https_port", [&]([[maybe_unused]]UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -773,7 +773,7 @@ int Server::main(const std::vector & /*args*/) #endif }); - create_server("mysql_port", [&](UInt16 port) + create_server("mysql_port", [&]([[maybe_unused]]UInt16 port) { #if USE_POCO_NETSSL Poco::Net::ServerSocket socket; From 03092d570492abf28fe28caec82b8fea60d6f59f Mon Sep 17 00:00:00 2001 From: Vxider Date: Tue, 6 Aug 2019 00:53:11 +0800 Subject: [PATCH 084/105] build fix --- dbms/programs/server/Server.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index aff54b5e992..3f96562b656 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -681,7 +681,7 @@ int Server::main(const std::vector & /*args*/) }); /// HTTPS - create_server("https_port", [&]([[maybe_unused]]UInt16 port) + create_server("https_port", [&]([[maybe_unused]] UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -718,7 +718,7 @@ int Server::main(const std::vector & /*args*/) }); /// TCP with SSL - create_server ("tcp_port_secure", [&]([[maybe_unused]]UInt16 port) + create_server ("tcp_port_secure", [&]([[maybe_unused]] UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -753,7 +753,7 @@ int Server::main(const std::vector & /*args*/) LOG_INFO(log, "Listening for replica communication (interserver) http://" + address.toString()); }); - create_server("interserver_https_port", [&]([[maybe_unused]]UInt16 port) + create_server("interserver_https_port", [&]([[maybe_unused]] UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -773,7 +773,7 @@ int Server::main(const std::vector & /*args*/) #endif }); - create_server("mysql_port", [&]([[maybe_unused]]UInt16 port) + create_server("mysql_port", [&]([[maybe_unused]] UInt16 port) { #if USE_POCO_NETSSL Poco::Net::ServerSocket socket; From 8ff4c38751f06c9e82b3833e62802318a60d8a13 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 5 Aug 2019 22:24:51 +0300 Subject: [PATCH 085/105] Added option to generate changelog from a list of PRs --- utils/make_changelog.py | 73 +++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/utils/make_changelog.py b/utils/make_changelog.py index f14015f4cb8..271525a1413 100755 --- a/utils/make_changelog.py +++ b/utils/make_changelog.py @@ -131,6 +131,24 @@ def find_pull_requests(commits, token, max_retries, retry_timeout): return not_found_commits, pull_requests +# Find pull requests by list of numbers +def find_pull_requests_by_num(pull_requests_nums, token, max_retries, retry_timeout): + pull_requests = {} + + for pr in pull_requests_nums: + item = github_api_get_json('repos/{}/pulls/{}'.format(repo, pr), token, max_retries, retry_timeout) + + number = item['number'] + if number not in pull_requests: + pull_requests[number] = { + 'title': item['title'], + 'description': item['body'], + 'user': item['user']['login'], + } + + return pull_requests + + # Get users for all unknown commits and pull requests. def get_users_info(pull_requests, commits_info, token, max_retries, retry_timeout): @@ -305,10 +323,12 @@ def save_state(state_file, state): f.write(json.dumps(state, indent=4, separators=(',', ': '))) -def make_changelog(new_tag, prev_tag, repo, repo_folder, state_file, token, max_retries, retry_timeout): +def make_changelog(new_tag, prev_tag, pull_requests_nums, repo, repo_folder, state_file, token, max_retries, retry_timeout): - base_sha = get_merge_base(new_tag, prev_tag, repo_folder) - logging.info('Base sha: %s', base_sha) + base_sha = None + if new_tag and prev_tag: + base_sha = get_merge_base(new_tag, prev_tag, repo_folder) + logging.info('Base sha: %s', base_sha) # Step 1. Get commits from merge_base to new_tag HEAD. # Result is a list of commits + map with commits info (author, message) @@ -349,24 +369,27 @@ def make_changelog(new_tag, prev_tag, repo, repo_folder, state_file, token, max_ users = state['users'] is_users_loaded = True - state['base_sha'] = base_sha - state['new_tag'] = new_tag - state['prev_tag'] = prev_tag + if base_sha: + state['base_sha'] = base_sha + state['new_tag'] = new_tag + state['prev_tag'] = prev_tag - if not is_commits_loaded: - logging.info('Getting commits using github api.') - commits = get_commits_from_branch(repo, new_tag, base_sha, commits_info, 100, token, max_retries, retry_timeout) - state['commits'] = commits - state['commits_info'] = commits_info + if not is_commits_loaded: + logging.info('Getting commits using github api.') + commits = get_commits_from_branch(repo, new_tag, base_sha, commits_info, 100, token, max_retries, retry_timeout) + state['commits'] = commits + state['commits_info'] = commits_info - logging.info('Found %d commits from %s to %s.\n', len(commits), new_tag, base_sha) - save_state(state_file, state) + logging.info('Found %d commits from %s to %s.\n', len(commits), new_tag, base_sha) + save_state(state_file, state) - if not is_pull_requests_loaded: - logging.info('Searching for pull requests using github api.') - unknown_commits, pull_requests = find_pull_requests(commits, token, max_retries, retry_timeout) - state['unknown_commits'] = unknown_commits - state['pull_requests'] = pull_requests + if not is_pull_requests_loaded: + logging.info('Searching for pull requests using github api.') + unknown_commits, pull_requests = find_pull_requests(commits, token, max_retries, retry_timeout) + state['unknown_commits'] = unknown_commits + state['pull_requests'] = pull_requests + else: + pull_requests = find_pull_requests_by_num(pull_requests_nums.split(','), token, max_retries, retry_timeout) logging.info('Found %d pull requests and %d unknown commits.\n', len(pull_requests), len(unknown_commits)) save_state(state_file, state) @@ -393,8 +416,9 @@ def make_changelog(new_tag, prev_tag, repo, repo_folder, state_file, token, max_ if __name__ == '__main__': parser = argparse.ArgumentParser(description='Make changelog.') - parser.add_argument('prev_release_tag', help='Git tag from previous release.') - parser.add_argument('new_release_tag', help='Git tag for new release.') + parser.add_argument('prev_release_tag', nargs='?', help='Git tag from previous release.') + parser.add_argument('new_release_tag', nargs='?', help='Git tag for new release.') + parser.add_argument('--pull-requests', help='Process the specified list of pull-request numbers (comma separated) instead of commits between tags.') parser.add_argument('--token', help='Github token. Use it to increase github api query limit.') parser.add_argument('--directory', help='ClickHouse repo directory. Script dir by default.') parser.add_argument('--state', help='File to dump inner states result.', default='changelog_state.json') @@ -412,9 +436,16 @@ if __name__ == '__main__': repo = args.repo max_retry = args.max_retry retry_timeout = args.retry_timeout + pull_requests = args.pull_requests + + if (not prev_release_tag or not new_release_tag) and not pull_requests: + raise Exception('Either release tags or --pull-requests must be specified') + + if prev_release_tag and new_release_tag and pull_requests: + raise Exception('Either release tags or --pull-requests must be specified') logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') repo_folder = os.path.expanduser(repo_folder) - make_changelog(new_release_tag, prev_release_tag, repo, repo_folder, state_file, token, max_retry, retry_timeout) + make_changelog(new_release_tag, prev_release_tag, pull_requests, repo, repo_folder, state_file, token, max_retry, retry_timeout) From 5f9b09e430ac8c554bba1fc6b03ee4b3ad76d322 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 5 Aug 2019 22:38:03 +0300 Subject: [PATCH 086/105] Added changelog for 19.11.4 --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f2282e8f37..b7d1f4103ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +## ClickHouse release 19.11.4.24, 2019-08-01 + +### Bug Fix +* Fix bug with writing secondary indices marks with adaptive granularity. ... [#6126](https://github.com/yandex/ClickHouse/pull/6126) ([alesapin](https://github.com/alesapin)) +* Fix `WITH ROLLUP` and `WITH CUBE` modifiers of `GROUP BY` with two-level aggregation. ... [#6225](https://github.com/yandex/ClickHouse/pull/6225) ([Anton Popov](https://github.com/CurtizJ)) +* Fixed hang in `JSONExtractRaw` function. Fixed [#6195](https://github.com/yandex/ClickHouse/issues/6195) [#6198](https://github.com/yandex/ClickHouse/pull/6198) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Fix segfault in ExternalLoader::reloadOutdated(). [#6082](https://github.com/yandex/ClickHouse/pull/6082) ([Vitaly Baranov](https://github.com/vitlibar)) +* Fixed the case when server may close listening sockets but not shutdown and continue serving remaining queries. You may end up with two running clickhouse-server processes. Sometimes, the server may return an error `bad_function_call` for remaining queries. [#6231](https://github.com/yandex/ClickHouse/pull/6231) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Fixed useless and incorrect condition on update field for initial loading of external dictionaries via ODBC, MySQL, ClickHouse and HTTP. This fixes [#6069](https://github.com/yandex/ClickHouse/issues/6069) [#6083](https://github.com/yandex/ClickHouse/pull/6083) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Fixed irrelevant exception in cast of `LowCardinality(Nullable)` to not-Nullable column in case if it doesn't contain Nulls (e.g. in query like `SELECT CAST(CAST('Hello' AS LowCardinality(Nullable(String))) AS String)`. [#6094](https://github.com/yandex/ClickHouse/issues/6094) [#6119](https://github.com/yandex/ClickHouse/pull/6119) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) +* Fix non-deterministic result of "uniq" aggregate function in extreme rare cases. The bug was present in all ClickHouse versions. [#6058](https://github.com/yandex/ClickHouse/pull/6058) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Segfault when we set a little bit too high CIDR on the function `IPv6CIDRToRange`. [#6068](https://github.com/yandex/ClickHouse/pull/6068) ([Guillaume Tassery](https://github.com/YiuRULE)) +* Fixed small memory leak when server throw many exceptions from many different contexts. [#6144](https://github.com/yandex/ClickHouse/pull/6144) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Fix the situation when consumer got paused before subscription and not resumed afterwards. [#6075](https://github.com/yandex/ClickHouse/pull/6075) ([Ivan](https://github.com/abyss7)) Note that Kafka is broken in this version. +* Clearing the Kafka data buffer from the previous read operation that was completed with an error [#6026](https://github.com/yandex/ClickHouse/pull/6026) ([Nikolay](https://github.com/bopohaa)) Note that Kafka is broken in this version. +* Since `StorageMergeTree::background_task_handle` is initialized in `startup()` the `MergeTreeBlockOutputStream::write()` may try to use it before initialization. Just check if it is initialized. [#6080](https://github.com/yandex/ClickHouse/pull/6080) ([Ivan](https://github.com/abyss7)) + +### Build/Testing/Packaging Improvement +* Added official `rpm` packages. [#5740](https://github.com/yandex/ClickHouse/pull/5740) ([proller](https://github.com/proller)) ([alesapin](https://github.com/alesapin)) +* Add an ability to build `.rpm` and `.tgz` packages with `packager` script. [#5769](https://github.com/yandex/ClickHouse/pull/5769) ([alesapin](https://github.com/alesapin)) +* Fixes for "Arcadia" build system. [#6223](https://github.com/yandex/ClickHouse/pull/6223) ([proller](https://github.com/proller)) + +### Backward Incompatible Change +* `Kafka` is broken in this version. + + ## ClickHouse release 19.11.3.11, 2019-07-18 ### New Feature @@ -35,6 +61,7 @@ * clickhouse-copier: Fix use-after free on shutdown [#5752](https://github.com/yandex/ClickHouse/pull/5752) ([proller](https://github.com/proller)) * Updated `simdjson`. Fixed the issue that some invalid JSONs with zero bytes successfully parse. [#5938](https://github.com/yandex/ClickHouse/pull/5938) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Fix shutdown of SystemLogs [#5802](https://github.com/yandex/ClickHouse/pull/5802) ([Anton Popov](https://github.com/CurtizJ)) +* Fix hanging when condition in invalidate_query depends on a dictionary. [#6011](https://github.com/yandex/ClickHouse/pull/6011) ([Vitaly Baranov](https://github.com/vitlibar)) ### Improvement * Allow unresolvable addresses in cluster configuration. They will be considered unavailable and tried to resolve at every connection attempt. This is especially useful for Kubernetes. This fixes [#5714](https://github.com/yandex/ClickHouse/issues/5714) [#5924](https://github.com/yandex/ClickHouse/pull/5924) ([alexey-milovidov](https://github.com/alexey-milovidov)) @@ -55,13 +82,12 @@ * Inverting ngramSearch to be more intuitive [#5807](https://github.com/yandex/ClickHouse/pull/5807) ([Danila Kutenin](https://github.com/danlark1)) * Add user parsing in HDFS engine builder [#5946](https://github.com/yandex/ClickHouse/pull/5946) ([akonyaev90](https://github.com/akonyaev90)) * Update default value of `max_ast_elements parameter` [#5933](https://github.com/yandex/ClickHouse/pull/5933) ([Artem Konovalov](https://github.com/izebit)) +* Added a notion of obsolete settings. The obsolete setting `allow_experimental_low_cardinality_type` can be used with no effect. [0f15c01c6802f7ce1a1494c12c846be8c98944cd](https://github.com/yandex/ClickHouse/commit/0f15c01c6802f7ce1a1494c12c846be8c98944cd) [Alexey Milovidov](https://github.com/alexey-milovidov) ### Performance Improvement * Increase number of streams to SELECT from Merge table for more uniform distribution of threads. Added setting `max_streams_multiplier_for_merge_tables`. This fixes [#5797](https://github.com/yandex/ClickHouse/issues/5797) [#5915](https://github.com/yandex/ClickHouse/pull/5915) ([alexey-milovidov](https://github.com/alexey-milovidov)) ### Build/Testing/Packaging Improvement -* Added official `rpm` packages. [#5740](https://github.com/yandex/ClickHouse/pull/5740) ([proller](https://github.com/proller)) ([alesapin](https://github.com/alesapin)) -* Add an ability to build `.rpm` and `.tgz` packages with `packager` script. [#5769](https://github.com/yandex/ClickHouse/pull/5769) ([alesapin](https://github.com/alesapin)) * Add a backward compatibility test for client-server interaction with different versions of clickhouse. [#5868](https://github.com/yandex/ClickHouse/pull/5868) ([alesapin](https://github.com/alesapin)) * Test coverage information in every commit and pull request. [#5896](https://github.com/yandex/ClickHouse/pull/5896) ([alesapin](https://github.com/alesapin)) * Cooperate with address sanitizer to support our custom allocators (`Arena` and `ArenaWithFreeLists`) for better debugging of "use-after-free" errors. [#5728](https://github.com/yandex/ClickHouse/pull/5728) ([akuzm](https://github.com/akuzm)) From 73d7f0c497ee964afa9819a993123fd92a32f725 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 5 Aug 2019 22:38:58 +0300 Subject: [PATCH 087/105] Added changelog for 19.11.4 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d1f4103ae..bf221c1e002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ ## ClickHouse release 19.11.4.24, 2019-08-01 ### Bug Fix -* Fix bug with writing secondary indices marks with adaptive granularity. ... [#6126](https://github.com/yandex/ClickHouse/pull/6126) ([alesapin](https://github.com/alesapin)) -* Fix `WITH ROLLUP` and `WITH CUBE` modifiers of `GROUP BY` with two-level aggregation. ... [#6225](https://github.com/yandex/ClickHouse/pull/6225) ([Anton Popov](https://github.com/CurtizJ)) +* Fix bug with writing secondary indices marks with adaptive granularity. [#6126](https://github.com/yandex/ClickHouse/pull/6126) ([alesapin](https://github.com/alesapin)) +* Fix `WITH ROLLUP` and `WITH CUBE` modifiers of `GROUP BY` with two-level aggregation. [#6225](https://github.com/yandex/ClickHouse/pull/6225) ([Anton Popov](https://github.com/CurtizJ)) * Fixed hang in `JSONExtractRaw` function. Fixed [#6195](https://github.com/yandex/ClickHouse/issues/6195) [#6198](https://github.com/yandex/ClickHouse/pull/6198) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Fix segfault in ExternalLoader::reloadOutdated(). [#6082](https://github.com/yandex/ClickHouse/pull/6082) ([Vitaly Baranov](https://github.com/vitlibar)) * Fixed the case when server may close listening sockets but not shutdown and continue serving remaining queries. You may end up with two running clickhouse-server processes. Sometimes, the server may return an error `bad_function_call` for remaining queries. [#6231](https://github.com/yandex/ClickHouse/pull/6231) ([alexey-milovidov](https://github.com/alexey-milovidov)) From eadb6ef1a4afa9fb0cd8c8b76ea1dc424996948c Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 5 Aug 2019 22:48:23 +0300 Subject: [PATCH 088/105] Suppress PVS-Studio warning --- dbms/src/Common/Dwarf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Common/Dwarf.cpp b/dbms/src/Common/Dwarf.cpp index 798eb08cc52..9d4a2f05632 100644 --- a/dbms/src/Common/Dwarf.cpp +++ b/dbms/src/Common/Dwarf.cpp @@ -707,7 +707,7 @@ void Dwarf::LineNumberVM::init() lineRange_ = read(header); opcodeBase_ = read(header); SAFE_CHECK(opcodeBase_ != 0, "invalid opcode base"); - standardOpcodeLengths_ = reinterpret_cast(header.data()); + standardOpcodeLengths_ = reinterpret_cast(header.data()); //-V506 header.remove_prefix(opcodeBase_ - 1); // We don't want to use heap, so we don't keep an unbounded amount of state. From 9950c9442b32cd5da0b5f83ee93d582c7e31de2a Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Tue, 6 Aug 2019 09:34:49 +0800 Subject: [PATCH 089/105] Update --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index e60bdc94a58..fdc8226a42a 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -982,18 +982,6 @@ void ExpressionAnalyzer::getAggregateInfo(Names & key_names, AggregateDescriptio aggregates = aggregate_descriptions; } -struct ColumnExt -{ - size_t compressed_size; - size_t type_size; - size_t uncompressed_size; - String name; - bool operator<(const ColumnExt & that) const - { - return std::tie(compressed_size, type_size, uncompressed_size) < std::tie(that.compressed_size, that.type_size, that.uncompressed_size); - } -}; - void ExpressionAnalyzer::collectUsedColumns() { /** Calculate which columns are required to execute the expression. @@ -1054,7 +1042,19 @@ void ExpressionAnalyzer::collectUsedColumns() { /// We will find a column with minimum . /// Because it is the column that is cheapest to read. - std::vector columns; + struct ColumnSizeTuple + { + size_t compressed_size; + size_t type_size; + size_t uncompressed_size; + String name; + bool operator<(const ColumnSizeTuple & that) const + { + return std::tie(compressed_size, type_size, uncompressed_size) + < std::tie(that.compressed_size, that.type_size, that.uncompressed_size); + } + }; + std::vector columns; if (storage) { auto column_sizes = storage->getColumnSizes(); @@ -1064,7 +1064,7 @@ void ExpressionAnalyzer::collectUsedColumns() if (c == column_sizes.end()) continue; size_t type_size = source_column.type->haveMaximumSizeOfValue() ? source_column.type->getMaximumSizeOfValueInMemory() : 100; - columns.emplace_back(ColumnExt{c->second.data_compressed, type_size, c->second.data_uncompressed, source_column.name}); + columns.emplace_back(ColumnSizeTuple{c->second.data_compressed, type_size, c->second.data_uncompressed, source_column.name}); } } if (columns.size()) From bcc23fc839363de165f3115a8267763a6e892d66 Mon Sep 17 00:00:00 2001 From: alesapin Date: Tue, 6 Aug 2019 11:21:31 +0300 Subject: [PATCH 090/105] Add changelog 19.11.5 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf221c1e002..8685079d3c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## ClickHouse release 19.11.5.28, 2019-08-05 + +### Bug fix +* Fixed the possibility of hanging queries when server is overloaded. [#6301](https://github.com/yandex/ClickHouse/pull/6301) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Fix FPE in yandexConsistentHash function. This fixes [#6304](https://github.com/yandex/ClickHouse/issues/6304). [#6126](https://github.com/yandex/ClickHouse/pull/6126) ([alexey-milovidov](https://github.com/alexey-milovidov)) +* Fixed bug in conversion of `LowCardinality` types in `AggregateFunctionFactory`. This fixes [#6257](https://github.com/yandex/ClickHouse/issues/6304). [#6281](https://github.com/yandex/ClickHouse/pull/6281) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) +* Fix parsing of `bool` settings from `true` and `false` strings. [#6278](https://github.com/yandex/ClickHouse/pull/6278) ([alesapin](https://github.com/alesapin)) +* Fix rare bug with incompatible stream headers in queries to `Distributed` table over `MergeTree` table when part of `WHERE` moves to `PREWHERE`. [#6236](https://github.com/yandex/ClickHouse/pull/6236) ([alesapin](https://github.com/alesapin)) +* Fixed overflow in integer division of signed type to unsigned type. This fixes [#6214](https://github.com/yandex/ClickHouse/issues/6214). [#6233](https://github.com/yandex/ClickHouse/pull/6233) ([alexey-milovidov](https://github.com/alexey-milovidov)) + +### Backward Incompatible Change +* `Kafka` still broken. + ## ClickHouse release 19.11.4.24, 2019-08-01 ### Bug Fix From fe3216cf335942ddab58e4524422193d6ed2a825 Mon Sep 17 00:00:00 2001 From: alesapin Date: Tue, 6 Aug 2019 11:23:54 +0300 Subject: [PATCH 091/105] Add changelog 19.11.5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8685079d3c1..f10e8da9d7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### Bug fix * Fixed the possibility of hanging queries when server is overloaded. [#6301](https://github.com/yandex/ClickHouse/pull/6301) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Fix FPE in yandexConsistentHash function. This fixes [#6304](https://github.com/yandex/ClickHouse/issues/6304). [#6126](https://github.com/yandex/ClickHouse/pull/6126) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Fixed bug in conversion of `LowCardinality` types in `AggregateFunctionFactory`. This fixes [#6257](https://github.com/yandex/ClickHouse/issues/6304). [#6281](https://github.com/yandex/ClickHouse/pull/6281) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) +* Fixed bug in conversion of `LowCardinality` types in `AggregateFunctionFactory`. This fixes [#6257](https://github.com/yandex/ClickHouse/issues/6257). [#6281](https://github.com/yandex/ClickHouse/pull/6281) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) * Fix parsing of `bool` settings from `true` and `false` strings. [#6278](https://github.com/yandex/ClickHouse/pull/6278) ([alesapin](https://github.com/alesapin)) * Fix rare bug with incompatible stream headers in queries to `Distributed` table over `MergeTree` table when part of `WHERE` moves to `PREWHERE`. [#6236](https://github.com/yandex/ClickHouse/pull/6236) ([alesapin](https://github.com/alesapin)) * Fixed overflow in integer division of signed type to unsigned type. This fixes [#6214](https://github.com/yandex/ClickHouse/issues/6214). [#6233](https://github.com/yandex/ClickHouse/pull/6233) ([alexey-milovidov](https://github.com/alexey-milovidov)) From c7ff51ab7bb56b426f9a13ab5effffbb3a3f8ec6 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 6 Aug 2019 13:30:24 +0300 Subject: [PATCH 092/105] Removed russian changelog --- CHANGELOG_RU.md | 2074 ----------------------------------------------- 1 file changed, 2074 deletions(-) delete mode 100644 CHANGELOG_RU.md diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md deleted file mode 100644 index e3e9fbdafbf..00000000000 --- a/CHANGELOG_RU.md +++ /dev/null @@ -1,2074 +0,0 @@ -## ClickHouse release 19.9.4.1, 2019-07-05 - -### Исправления ошибок -* Исправлен segmentation fault в кодеке сжатия Delta в колонках с величинами размером меньше 32 бит. Ошибка могла приводить к повреждениям памяти. [#5786](https://github.com/yandex/ClickHouse/pull/5786) ([alesapin](https://github.com/alesapin)) -* Исправлена ошибка в проверке кусков в LowCardinality колонках. [#5832](https://github.com/yandex/ClickHouse/pull/5832) ([alesapin](https://github.com/alesapin)) -* Исправлен segmentation fault при слиянии кусков с истекшим TTL в случае, когда в блоке присутствуют столбцы, не входящие в структуру таблицы. [#5819](https://github.com/yandex/ClickHouse/pull/5819) ([Anton Popov](https://github.com/CurtizJ)) -* Исправлена существовавшая возможность ухода в бесконечное ожидание на низко-приоритетных запросах. [#5842](https://github.com/yandex/ClickHouse/pull/5842) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка определения таймзоны по умолчанию (UCT вместо UTC). [#5828](https://github.com/yandex/ClickHouse/pull/5828) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка в распределенных запросах вида DROP/ALTER/TRUNCATE/OPTIMIZE ON CLUSTER. [#5757](https://github.com/yandex/ClickHouse/pull/5757) ([alesapin](https://github.com/alesapin)) -* Исправлена ошибка, которая при распределенных запросах могла привести к тому, что некоторые запросы не появлялись в query_log сразу после SYSTEM FLUSH LOGS запроса. [#5685](https://github.com/yandex/ClickHouse/pull/5685) ([Anton Popov](https://github.com/CurtizJ)) -* Добавлена отсутствовавшая поддержка константных аргументов для функции `evalMLModel`. [#5820](https://github.com/yandex/ClickHouse/pull/5820) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -## ClickHouse release 19.7.6.1, 2019-07-05 - -### Исправления ошибок -* Исправлена просадка производительности в методе JOIN в некоторых видах запросов. [#5192](https://github.com/yandex/ClickHouse/pull/5192) ([Winter Zhang](https://github.com/zhang2014)) - -## ClickHouse release 19.9.2.4, 2019-06-24 - -### Новые возможности -* Выводить информацию о "замороженных" кусках в таблице `system.parts`. [#5471](https://github.com/yandex/ClickHouse/pull/5471) ([proller](https://github.com/proller)) -* clickhouse-client спрашивает клиентский пароль на старте, если не указан в аргументах [#5092](https://github.com/yandex/ClickHouse/pull/5092) ([proller](https://github.com/proller)) -* Реализованы функции `dictGet` и `dictGetOrDefault` для Decimal-ов. [#5394](https://github.com/yandex/ClickHouse/pull/5394) ([Artem Zuikov](https://github.com/4ertus2)) - -### Улучшения -* Debian init: добавлен таймаут остановки [#5522](https://github.com/yandex/ClickHouse/pull/5522) ([proller](https://github.com/proller)) -* Добавлены setting-и для обхода запрета на создание LowCardinality-колонок от неподходящих типов данных [#5448](https://github.com/yandex/ClickHouse/pull/5448) ([Olga Khvostikova](https://github.com/stavrolia)) -* Функции регрессии возвращают веса модели (когда используются не в качестве состояния для функции `evalMLMethod`). [#5411](https://github.com/yandex/ClickHouse/pull/5411) ([Quid37](https://github.com/Quid37)) -* Переименованы и улучшены функции регрессии. [#5492](https://github.com/yandex/ClickHouse/pull/5492) ([Quid37](https://github.com/Quid37)) -* Улучшения в интерфейсе поиска подстрок. [#5586](https://github.com/yandex/ClickHouse/pull/5586) ([Danila Kutenin](https://github.com/danlark1)) - -### Исправления ошибок -* Исправлена потенциальная потеря данных в Kafka [#5445](https://github.com/yandex/ClickHouse/pull/5445) ([Ivan](https://github.com/abyss7)) -* Исправлен потенциальный бесконечный цикл в формате `PrettySpace` вызванном с нулем колонок [#5560](https://github.com/yandex/ClickHouse/pull/5560) ([Olga Khvostikova](https://github.com/stavrolia)) -* Исправлено переполнение UInt32 в линейной регрессии. Поддержаны неконстантные аргументы в ML моделях. [#5516](https://github.com/yandex/ClickHouse/pull/5516) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлено ошибочкное исключение по `ALTER TABLE ... DROP INDEX IF EXISTS ...` когда индекс не существует [#5524](https://github.com/yandex/ClickHouse/pull/5524) ([Gleb Novikov](https://github.com/NanoBjorn)) -* Исправлено падение в функции `bitmapHasAny` в скалярных подзапросах [#5528](https://github.com/yandex/ClickHouse/pull/5528) ([Zhichang Yu](https://github.com/yuzhichang)) -* Исправлена ошибка обновления DNS в пуле репликации, когда данные не обновлялись после очистки DNS-кеша. [#5534](https://github.com/yandex/ClickHouse/pull/5534) ([alesapin](https://github.com/alesapin)) -* Исправлен `ALTER ... MODIFY TTL` в ReplicatedMergeTree. [#5539](https://github.com/yandex/ClickHouse/pull/5539) ([Anton Popov](https://github.com/CurtizJ)) -* Исправлен INSERT в Distributed таблицу с MATERIALIZED колонками [#5429](https://github.com/yandex/ClickHouse/pull/5429) ([Azat Khuzhin](https://github.com/azat)) -* Исправлена ошибка аллокации памяти при очистке табилц с движком Join [#5437](https://github.com/yandex/ClickHouse/pull/5437) ([TCeason](https://github.com/TCeason)) -* Исправление таймзон. [#5443](https://github.com/yandex/ClickHouse/pull/5443) ([Ivan](https://github.com/abyss7)) -* Исправлена ошибка в алгоритме MultiVolnitsky приводящая в редких случаях к неверным результатам функции `multiSearchAny`. [#5588](https://github.com/yandex/ClickHouse/pull/5588) ([Danila Kutenin](https://github.com/danlark1)) -* Исправлена ошибка, при которой часть настроек не прокидывалась для HTTP запросов. [#5455](https://github.com/yandex/ClickHouse/pull/5455) ([Danila Kutenin](https://github.com/danlark1)) -* Исправлена ошибка когда куски данных удалялись из файловой системы и оставались в Zookeeper-е. [#5520](https://github.com/yandex/ClickHouse/pull/5520) ([alesapin](https://github.com/alesapin)) -* Убрана отладочная информация из MySQL-протокола [#5478](https://github.com/yandex/ClickHouse/pull/5478) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Пропуск ZNONODE в процессе выполнения DDL запросов [#5489](https://github.com/yandex/ClickHouse/pull/5489) ([Azat Khuzhin](https://github.com/azat)) -* Исправлена ошибка `UNION ALL` с разными типами возвращаемых результатов из подзапросов. [#5503](https://github.com/yandex/ClickHouse/pull/5503) ([Artem Zuikov](https://github.com/4ertus2)) -* Кидаем исплючение вместо падения в случае неправильного целочисленного типа в фукнциях `dictGetT`. [#5446](https://github.com/yandex/ClickHouse/pull/5446) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлены неверные значения element_count и load_factor в таблице `system.dictionaries` для хэш-словаря. [#5440](https://github.com/yandex/ClickHouse/pull/5440) ([Azat Khuzhin](https://github.com/azat)) - -### Улучшения сборки, тестирования и пакетирования -* Исправлена сборка с выключенной компрессией `Brotli` (cmake переменная `ENABLE_BROTLI=OFF`). [#5521](https://github.com/yandex/ClickHouse/pull/5521) ([Anton Yuzhaninov](https://github.com/citrin)) -* Исправлено включение roaring.h [#5523](https://github.com/yandex/ClickHouse/pull/5523) ([Orivej Desh](https://github.com/orivej)) -* Исправлены предупреждения gcc9 в hyperscan. [#5546](https://github.com/yandex/ClickHouse/pull/5546) ([Danila Kutenin](https://github.com/danlark1)) -* Исправлены предупреждения в сборке с gcc-9. [#5498](https://github.com/yandex/ClickHouse/pull/5498) ([Danila Kutenin](https://github.com/danlark1)) -* Исправлена линковка с lld [#5477](https://github.com/yandex/ClickHouse/pull/5477) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Убраны ненужные специализации шаблонов в коде словарей [#5452](https://github.com/yandex/ClickHouse/pull/5452) ([Artem Zuikov](https://github.com/4ertus2)) -* Улучшения в тестах производительности. [#5497](https://github.com/yandex/ClickHouse/pull/5497) ([Olga Khvostikova](https://github.com/stavrolia)) -* Исправления для параллельного запуска тестов. [#5506](https://github.com/yandex/ClickHouse/pull/5506) ([proller](https://github.com/proller)) -* Docker использует конфиг из clickhouse-test [#5531](https://github.com/yandex/ClickHouse/pull/5531) ([proller](https://github.com/proller)) -* Исправлена сборка под FreeBSD [#5447](https://github.com/yandex/ClickHouse/pull/5447) ([proller](https://github.com/proller)) -* Обновление boost до 1.70 [#5570](https://github.com/yandex/ClickHouse/pull/5570) ([proller](https://github.com/proller)) -* Исправлена сборка clickhouse как сабмодуля [#5574](https://github.com/yandex/ClickHouse/pull/5574) ([proller](https://github.com/proller)) -* Улучшение теста производительности функций JSONExtract [#5444](https://github.com/yandex/ClickHouse/pull/5444) ([Vitaly Baranov](https://github.com/vitlibar)) - -## ClickHouse release 19.8.3.8, 2019-06-11 - -### Новые возможности -* Добавлены функции для работы с JSON. [#4686](https://github.com/yandex/ClickHouse/pull/4686) ([hcz](https://github.com/hczhcz)) [#5124](https://github.com/yandex/ClickHouse/pull/5124). ([Vitaly Baranov](https://github.com/vitlibar)) -* Добавлена функция `basename`, аналогичная функции `basename` в различных языках программирования (`os.path.basename` в python, `basename` в PHP, и т.д.). Работает с UNIX и Windows подобными путями. [#5136](https://github.com/yandex/ClickHouse/pull/5136) ([Guillaume Tassery](https://github.com/YiuRULE)) -* Добавлена возможность указать смещение в секции LIMIT BY с помощью синтаксиса `LIMIT n, m BY` или `LIMIT m OFFSET n BY`. [#5138](https://github.com/yandex/ClickHouse/pull/5138) ([Anton Popov](https://github.com/CurtizJ)) -* Добавлен новый тип данных `SimpleAggregateFunction`, который позволяет создавать столбцы с легковесной агрегацией в AggregatingMergeTree. Он может использоваться только с простыми функциями, такими как `any`,` anyLast`, `sum`,` min`, `max`. - [#4629](https://github.com/yandex/ClickHouse/pull/4629) ([Boris Granveaud](https://github.com/bgranvea)) -* Добавлена поддержка неконстантных аргументов в функции `ngramDistance` [#5198](https://github.com/yandex/ClickHouse/pull/5198) ([Danila Kutenin](https://github.com/danlark1)) -* Добавлены функции `skewPop`, `skewSamp`, `kurtPop` и `kurtSamp`, которые вычисляют для последовательности коэффициент асимметрии, выборочный коэффициент асимметрии, коэффициент эксцесса и выборочный коэффициент эксцесса соответсвенно. [#5200](https://github.com/yandex/ClickHouse/pull/5200) ([hcz](https://github.com/hczhcz)) -* Добавлена поддержка операции `RENAME` для движка `MaterializedView`. [#5209](https://github.com/yandex/ClickHouse/pull/5209) ([Guillaume Tassery](https://github.com/YiuRULE)) -* Сервер, позволяющий подключаться к ClickHouse через клиент MySQL. [#4715](https://github.com/yandex/ClickHouse/pull/4715) ([Yuriy Baranov](https://github.com/yurriy)) -* Добавлены функции `toDecimal*OrZero` и `toDecimal*OrNull`. [#5291](https://github.com/yandex/ClickHouse/pull/5291) ([Artem Zuikov](https://github.com/4ertus2)) -* Добавлена поддержка Decimal в функциях: `quantile`, `quantiles`, `median`, `quantileExactWeighted`, `quantilesExactWeighted`, `medianExactWeighted`. [#5304](https://github.com/yandex/ClickHouse/pull/5304) ([Artem Zuikov](https://github.com/4ertus2)) -* Добавлена функция `toValidUTF8`, которая заменяет все некорректные символы в кодировке UTF-8 на заменяющий символ � (U+FFFD). [#5322](https://github.com/yandex/ClickHouse/pull/5322) ([Danila Kutenin](https://github.com/danlark1)) -* Добавлена функция `format`, которая выполняет подстановку в константный шаблон (упрощенный шаблон форматирования, используемый в Python) строк, переданных в аргументах функции. [#5330](https://github.com/yandex/ClickHouse/pull/5330) ([Danila Kutenin](https://github.com/danlark1)) -* Добавлена системная таблица `system.detached_parts`, содержащая информацию о кусках из директории `detached` для таблиц семейства `MergeTree`. [#5353](https://github.com/yandex/ClickHouse/pull/5353) ([akuzm](https://github.com/akuzm)) -* Добавлена функция `ngramSearch` для вычисления несимметричной разности между `needle` и `haystack`. [#5418](https://github.com/yandex/ClickHouse/pull/5418)[#5422](https://github.com/yandex/ClickHouse/pull/5422) ([Danila Kutenin](https://github.com/danlark1)) -* Реализованы основные методы машинного обучения (стохастическая линейная регрессия и логистическая регрессия) в виде агрегатных функций. Для вычисления весов могут использоваться различные методы (градиентный спуск, градиентный спуск с накоплением импульса, метод Нестерова). Также поддерживаются mini-batches произвольного размера. [#4943](https://github.com/yandex/ClickHouse/pull/4943) ([Quid37](https://github.com/Quid37)) -* Добавлены функции `geohashEncode` и `geohashDecode`. [#5003](https://github.com/yandex/ClickHouse/pull/5003) ([Vasily Nemkov](https://github.com/Enmk)) -* Добавлена агрегатная функция `timeSeriesGroupSum`, которая агрегирует временные ряды в которых не совпадают моменты. Функция использует линейную интерполяцию между двумя значениями времени, а затем суммирует значения для одного и того же момента. Добавлена агрегатная функция `timeSeriesGroupRateSum`, которая вычисляет производные по timestamp для рядов, а затем суммирует полученные производные для всех рядов для одного значения timestamp. [#4542](https://github.com/yandex/ClickHouse/pull/4542) ([Yangkuan Liu](https://github.com/LiuYangkuan)) -* Добавлены функции `IPv4CIDRtoIPv4Range` and `IPv6CIDRtoIPv6Range`, которые вычисляют диапазон подсети, используя CIDR. [#5095](https://github.com/yandex/ClickHouse/pull/5095) ([Guillaume Tassery](https://github.com/YiuRULE)) -* Добавлен заголовок X-ClickHouse-Summary при отправке HTTP запроса с включенной настройкой `send_progress_in_http_headers`. Он содержит инфорцию о X-ClickHouse-Progress, а также информацию о том сколько строк и байт было записано в таблицу и подобное. [#5116](https://github.com/yandex/ClickHouse/pull/5116) ([Guillaume Tassery](https://github.com/YiuRULE)) - -### Улучшения -* Добавлена настройка `max_parts_in_total` (по умолчанию: 100 000) для таблиц семейства MergeTree, предотвращающая неправильное задание ключа партиционирования #5166. [#5171](https://github.com/yandex/ClickHouse/pull/5171) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* `clickhouse-obfuscator`: теперь seed вычисляется для столбцов путем комбинирования начального seed и имени колонки, а не ее позиции. Это необходимо для того, чтобы оставить таблицы пригодными для JOIN-ов при преобразовании датасетов с несколькими таблицами. [#5178](https://github.com/yandex/ClickHouse/pull/5178) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлены функции `JSONExtractRaw`, `JSONExtractKeyAndValues`. Функции вида `jsonExtract` переименованы в `JSONExtract`. Теперь, в случае ошибки эти функции возвращают соответсвующие типу значения, а не `NULL`. Теперь возвращаемый тип передается в функцию `JSONExtract` последним параметром. Если недоступны иструкции AVX2, то JSON функции выполняются с использованием бибилиотеки RapidJSON. Обновлена библиотека Simdjson. [#5235](https://github.com/yandex/ClickHouse/pull/5235) ([Vitaly Baranov](https://github.com/vitlibar)) -* Теперь функции `if` and `multiIf` не зависят от условных `Nullable` типов. [#5238](https://github.com/yandex/ClickHouse/pull/5238) ([Jian Wu](https://github.com/janplus)) -* Оператор `IN` теперь возвращает `Null` для значений равных `Null` (аналогично функции `Equal`). [#5152](https://github.com/yandex/ClickHouse/pull/5152) ([Jian Wu](https://github.com/janplus)) -* Добавлена проверка ограничения по времени выполенения запроса через каждые (flush_interval / poll_timeout) строк при чтении из движка Kafka. Это позволяет чаще прерывать чтение из движка Kafka и чаще проверять ограничение по времени на более высоком уровне конвеера выполнения запроса. [#5249](https://github.com/yandex/ClickHouse/pull/5249) ([Ivan](https://github.com/abyss7)) -* Теперь библиотека rdkafka линкуется c bundled библиотекой SASL. Это позволяет использовать SASL SCRAM аутентификацию. [#5253](https://github.com/yandex/ClickHouse/pull/5253) ([Ivan](https://github.com/abyss7)) -* clickhouse-server: более информативные сообщения об ошибках прослушивания. [#5268](https://github.com/yandex/ClickHouse/pull/5268) ([proller](https://github.com/proller)) -* clickhouse-copier: добавлена поддержка словарей в функциях в секции ``. [#5270](https://github.com/yandex/ClickHouse/pull/5270) ([proller](https://github.com/proller)) -* Добавлена настройка `kafka_commit_every_batch` для регулирования чтения данных из движка Kafka. Позволяет установить вид чтения: после каждого полученного пакета сообщений или после того как блок записан в таблицу. [#5308](https://github.com/yandex/ClickHouse/pull/5308) ([Ivan](https://github.com/abyss7)) -* Добавлена поддержка беззнаковых целых типов отличных от UInt32 в функциях `windowFunnel`, `sequenceMatch`. [#5339](https://github.com/yandex/ClickHouse/pull/5339) [#5320](https://github.com/yandex/ClickHouse/pull/5320) ([sundyli](https://github.com/sundy-li)) -* В движке Merge виртуальный столбец с названием `_table` (содержащий название таблицы) теперь недоступен, если он присутствует в таблицах-источниках. [#5325](https://github.com/yandex/ClickHouse/pull/5325) ([Ivan](https://github.com/abyss7)) -* Более понятные сообщения об ошибках, если чексуммы не совпадают вероятнее всего из-за ошибок на аппаратном уровне. [#5355](https://github.com/yandex/ClickHouse/pull/5355) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Для движка `Merge` добавлена проверка на то, что таблицы-источники поддерживают семплирование. [#5366](https://github.com/yandex/ClickHouse/pull/5366) ([Ivan](https://github.com/abyss7)) -* Теперь после использования MySQL в качестве внешнего словаря закрывается соединение. [#5395](https://github.com/yandex/ClickHouse/pull/5395) ([Clément Rodriguez](https://github.com/clemrodriguez)) -* Улучшения в протоколе MySQL Wire. Формат переименован из `MySQL` to `MySQLWire`. Теперь SSL недоступно, если не удалось создать SSL контекст. [#5419](https://github.com/yandex/ClickHouse/pull/5419) ([Yuriy Baranov](https://github.com/yurriy)) -* clickhouse-client: теперь можно запустить клиент, если файл истории недоступен. [#5431](https://github.com/yandex/ClickHouse/pull/5431) ([proller](https://github.com/proller)) -* Теперь учитываются настройки запроса при асинхронных вставках в таблицу типа Distributed. [#4936](https://github.com/yandex/ClickHouse/pull/4936) ([TCeason](https://github.com/TCeason)) -* Переименованы функции `leastSqr` в `simpleLinearRegression`, `LinearRegression` в `linearRegression`, `LogisticRegression` в `logisticRegression`. [#5391](https://github.com/yandex/ClickHouse/pull/5391) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) - -### Улучшения производительности -* Паралелльная обработка кусков в запросах `ALTER ... MODIFY`. [#4639](https://github.com/yandex/ClickHouse/pull/4639) ([Ivan Kush](https://github.com/IvanKush)) -* Оптимизации в обработке регулярных выражений. [#5193](https://github.com/yandex/ClickHouse/pull/5193) [#5191](https://github.com/yandex/ClickHouse/pull/5191) ([Danila Kutenin](https://github.com/danlark1)) -* Теперь столбец правой таблицы, который используется только в секции `JOIN ON` не добавляется в результат. [#5260](https://github.com/yandex/ClickHouse/pull/5260) ([Artem Zuikov](https://github.com/4ertus2)) -* Теперь чтение из буфера движка Kafka приостанавливается после первого пустого ответа. Это позволяет не вызывать несколько раз метод `ReadBuffer::next()` для пустого результата. [#5283](https://github.com/yandex/ClickHouse/pull/5283) ([Ivan](https://github.com/abyss7)) -* Оптимизация функции `concat` для нескольких аргументов. [#5357](https://github.com/yandex/ClickHouse/pull/5357) ([Danila Kutenin](https://github.com/danlark1)) -* Оптимизация запросов. Прокидывание выражения оператора `IN` при конвертации `commа/cross join` в `inner`. [#5396](https://github.com/yandex/ClickHouse/pull/5396) ([Artem Zuikov](https://github.com/4ertus2)) -* Улучшение реализации LZ4 для более быстрого разжатия данных. [#5070](https://github.com/yandex/ClickHouse/pull/5070) ([Danila Kutenin](https://github.com/danlark1)) -* Реализована MSD-сортировка, а также на ее основе частичная сортировка. [#5129](https://github.com/yandex/ClickHouse/pull/5129) ([Evgenii Pravda](https://github.com/kvinty)) - -### Исправления ошибок -* Исправлено прокидывание необходимых для чтения столбцов в join. [#5192](https://github.com/yandex/ClickHouse/pull/5192) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлено неправильное поведение команды `sudo service clickhouse-server forcerestart` в случае, если сервер запущен при помощи systemd. [#5204](https://github.com/yandex/ClickHouse/pull/5204) ([proller](https://github.com/proller)) -* Исправлены коды ошибок при передаче кусков (раньше даже при ошибках возвращался код 200). [#5216](https://github.com/yandex/ClickHouse/pull/5216) ([proller](https://github.com/proller)) -* Исправлено использование типа SimpleAggregateFunction со строками длиннее чем `MAX_SMALL_STRING_SIZE` [#5311](https://github.com/yandex/ClickHouse/pull/5311) ([Azat Khuzhin](https://github.com/azat)) -* Исправлена ошибка конвертации типа `Decimal` в `Nullable(Decimal)` в секции IN. Добавлена возможность конвертации между различными типами Decimal (including different scales). [#5350](https://github.com/yandex/ClickHouse/pull/5350) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено затирание регистров FPU в библиотеке simdjson, которое приводило к неправильным вычислениям в агрегатных функциях `uniqHLL` и `uniqCombined`, а также математических функциях, таких как `log`. [#5354](https://github.com/yandex/ClickHouse/pull/5354) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены обработка константных и неконстантных аргументов одновременно в JSON функциях. [#5435](https://github.com/yandex/ClickHouse/pull/5435) ([Vitaly Baranov](https://github.com/vitlibar)) -* Исправлен возвращаемый тип в функции `quantileExact` с типом `Decimal`. [#5304](https://github.com/yandex/ClickHouse/pull/5304) ([Artem Zuikov](https://github.com/4ertus2)) - -### Улучшения сборки, тестирования и пакетирования -* Исправлены срабатывания address-санитайзера, показывающие потенциальную ошибку use-after-free.[#5139](https://github.com/yandex/ClickHouse/pull/5139) [#5143](https://github.com/yandex/ClickHouse/pull/5143) [#5393](https://github.com/yandex/ClickHouse/pull/5393) ([Ivan](https://github.com/abyss7)) -* Тесты производительности перемещены в одну директорию. [#5158](https://github.com/yandex/ClickHouse/pull/5158) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены некоторые тесты производительности. [#5255](https://github.com/yandex/ClickHouse/pull/5255) ([alesapin](https://github.com/alesapin)) -* Добавлена утилита, позволяющая вычислять чексуммы, полученные в результате возможных инверсий битов. Она помогает отлаживать аппаратные ошибки. [#5334](https://github.com/yandex/ClickHouse/pull/5334) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Улучшение скрипта для запуска интеграционных тестов. [#5340](https://github.com/yandex/ClickHouse/pull/5340)[#5360](https://github.com/yandex/ClickHouse/pull/5360) ([filimonov](https://github.com/filimonov)) -* Добавлена инструкция о том, как писать тесты производительности. [#5408](https://github.com/yandex/ClickHouse/pull/5408) ([alesapin](https://github.com/alesapin)) -* Добавлена возможность делать подстановки в запросах create, fill и drop в тестах производительности. [#5367](https://github.com/yandex/ClickHouse/pull/5367) ([Olga Khvostikova](https://github.com/stavrolia)) - -## ClickHouse release 19.7.5.27, 2019-06-09 - -### Новые возможности -* Добавлены функции для битмапов `bitmapHasAny` и `bitmapHasAll` (аналогично функциям `hasAny` и `hasAll` для массивов). [#5279](https://github.com/yandex/ClickHouse/pull/5279) ([Sergi Vladykin](https://github.com/svladykin)) - -### Исправления ошибок -* Исправлен segfault при использовании `minmax` индекса со значениями `Null`. [#5246](https://github.com/yandex/ClickHouse/pull/5246) ([Nikita Vasilev](https://github.com/nikvas0)) -* Исправлена ошибка 'Not found column', возникавшая в некоторых распределенных запросах. [#5407](https://github.com/yandex/ClickHouse/pull/5407) ([Constantin S. Pan](https://github.com/kvap)) -* Исправлена ошибка "Column '0' already exists" в запросах `SELECT .. PREWHERE` со столбцами с указанным `DEFAULT` [#5397](https://github.com/yandex/ClickHouse/pull/5397) ([proller](https://github.com/proller)) -* Исправлен запрос `ALTER MODIFY TTL` для таблиц типа `ReplicatedMergeTree`. [#5539](https://github.com/yandex/ClickHouse/pull/5539/commits) ([Anton Popov](https://github.com/CurtizJ)) -* Теперь сервер не падает, если подписчики Kafka не смогли запуститься. [#5285](https://github.com/yandex/ClickHouse/pull/5285) ([Ivan](https://github.com/abyss7)) -* Исправлены bitmap функции. [#5359](https://github.com/yandex/ClickHouse/pull/5359) ([Andy Yang](https://github.com/andyyzh)) -* Исправлено значение `element_count` в таблице `system.dictionaries` для словарей типа hashed (теперь не подсчитываются дубликаты). [#5440](https://github.com/yandex/ClickHouse/pull/5440) ([Azat Khuzhin](https://github.com/azat)) -* Для определения имени таймзоны теперь используется переменная среды TZ. В некоторых случаях это помогает правильно определять таймзону по умолчанию. [#5443](https://github.com/yandex/ClickHouse/pull/5443) ([Ivan](https://github.com/abyss7)) -* Убрано неявное преобразование целых типов в функциях `dictGetT`, т.к. оно работало неправильно. Вместо этого теперь бросается исключение. [#5446](https://github.com/yandex/ClickHouse/pull/5446) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлены настройки во внешних данных HTTP запроса. [#5455](https://github.com/yandex/ClickHouse/pull/5455) ([Danila Kutenin](https://github.com/danlark1)) -* Исправлена ошибка, приводящая к тому, что куски удалялись только из файловой системы, но не из Zookeeper. [#5520](https://github.com/yandex/ClickHouse/pull/5520) ([alesapin](https://github.com/alesapin)) -* Исправлен segfault в функции `bitmapHasAny`. [#5528](https://github.com/yandex/ClickHouse/pull/5528) ([Zhichang Yu](https://github.com/yuzhichang)) -* Исправлена ошибка, приводящая к тому, что при репликации не вычислялся заново адрес хоста, даже если DNS кеш был сброшен. [#5534](https://github.com/yandex/ClickHouse/pull/5534) ([alesapin](https://github.com/alesapin)) -* Исправлен запрос `DROP INDEX IF EXISTS`. Теперь запрос `ALTER TABLE ... DROP INDEX IF EXISTS ...` не выкидывает исключение. [#5524](https://github.com/yandex/ClickHouse/pull/5524) ([Gleb Novikov](https://github.com/NanoBjorn)) -* Исправлен тип результируещего столбца в запросе `UNION ALL`. Раньше могли быть случаи, когда тип и данные столбца были несогласованы. [#5503](https://github.com/yandex/ClickHouse/pull/5503) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлена ошибка, вследствие которой поток `DDLWorker`-а мог быть остановлен, если одна нода удалила `znode` из очереди задач, а другая уже получила ее, но не успела выполнить. [#5489](https://github.com/yandex/ClickHouse/pull/5489) ([Azat Khuzhin](https://github.com/azat)) -* Исправлена вставка в Distributed таблицы с материализованныси столбцами. [#5429](https://github.com/yandex/ClickHouse/pull/5429) ([Azat Khuzhin](https://github.com/azat)) - - -## ClickHouse release 19.7.3.9, 2019-05-30 - -### Новые возможности -* Добавлена возможность ограничить значения конфигурационных параметров, - которые может задать пользователь. Эти ограничения устанавливаются в профиле -настроек пользователя. [#4931](https://github.com/yandex/ClickHouse/pull/4931) -([Vitaly Baranov](https://github.com/vitlibar)) -* Добавлен вариант функции `groupUniqArray` с дополнительным параметром - `max_size`, который ограничивает размер результирующего массива, аналогично -функции `groupArray(max_size)(x)`. -[#5026](https://github.com/yandex/ClickHouse/pull/5026) ([Guillaume -Tassery](https://github.com/YiuRULE)) -* Для входных файлов формата TSVWithNames и CSVWithNames появилась возможность - определить порядок колонок в файле исходя из его заголовка. Это поведение -управляется конфигурационным параметром `input_format_with_names_use_header`. -[#5081](https://github.com/yandex/ClickHouse/pull/5081) -([Alexander](https://github.com/Akazz)) - -### Исправления ошибок -* Падение в процессе слияния при использовании uncompressed_cache и JOIN - (#5197). [#5133](https://github.com/yandex/ClickHouse/pull/5133) ([Danila -Kutenin](https://github.com/danlark1)) -* Segmentation fault на запросе к системным таблицам (#5066). - [#5127](https://github.com/yandex/ClickHouse/pull/5127) -([Ivan](https://github.com/abyss7)) -* Потеря загружаемых данных при больших потоках загрузки через KafkaEngine - (#4736). [#5080](https://github.com/yandex/ClickHouse/pull/5080) -([Ivan](https://github.com/abyss7)) -* Исправлен очень редкий data race condition который мог произойти при выполнении запроса с UNION ALL включающего минимум два SELECT из таблиц system.columns, system.tables, system.parts, system.parts_tables или таблиц семейства Merge и одновременно выполняющихся запросов ALTER столбцов соответствующих таблиц. [#5189](https://github.com/yandex/ClickHouse/pull/5189) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Улучшения производительности -* Используется поразрядная сортировка числовых колонок для `ORDER BY` без - `LIMIT`. [#5106](https://github.com/yandex/ClickHouse/pull/5106), -[#4439](https://github.com/yandex/ClickHouse/pull/4439) ([Evgenii -Pravda](https://github.com/kvinty), -[alexey-milovidov](https://github.com/alexey-milovidov) - -### Документация -* Документация для некоторых табличных движков переведена на китайский. - [#5107](https://github.com/yandex/ClickHouse/pull/5107), -[#5094](https://github.com/yandex/ClickHouse/pull/5094), -[#5087](https://github.com/yandex/ClickHouse/pull/5087) -([张风啸](https://github.com/AlexZFX), -[#5068](https://github.com/yandex/ClickHouse/pull/5068) ([never -lee](https://github.com/neverlee)) - -### Улучшения сборки, тестирования и пакетирования -* Правильно отображаются символы в кодировке UTF-8 в `clickhouse-test`. - [#5084](https://github.com/yandex/ClickHouse/pull/5084) -([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлен параметр командной строки для `clickhouse-client`, позволяющий - всегда загружать данные подсказок. -[#5102](https://github.com/yandex/ClickHouse/pull/5102) -([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены некоторые предупреждения PVS-Studio. - [#5082](https://github.com/yandex/ClickHouse/pull/5082) -([alexey-milovidov](https://github.com/alexey-milovidov)) -* Обновлена библиотека LZ4. - [#5040](https://github.com/yandex/ClickHouse/pull/5040) ([Danila -Kutenin](https://github.com/danlark1)) -* В зависимости сборки добавлен gperf для поддержки готовящегося PR #5030. - [#5110](https://github.com/yandex/ClickHouse/pull/5110) -([proller](https://github.com/proller)) - - -## ClickHouse release 19.6.3.18, 2019-06-13 - -### Исправления ошибок -* Исправлено прокидывание условий оператора IN для запросов с табличными функциями `mysql` and `odbc` и соответсвующими движками таблиц. [#5313](https://github.com/yandex/ClickHouse/pull/5313) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен deadlock в Zookeeper. [#5297](https://github.com/yandex/ClickHouse/pull/5297) ([github1youlc](https://github.com/github1youlc)) -* Для формата CSV добавлена возможность указывать значения типа Decimal в кавычках. [#5284](https://github.com/yandex/ClickHouse/pull/5284) ([Artem Zuikov](https://github.com/4ertus2) -* Убрана возможность преобразований из float Inf/NaN в Decimal (теперь бросается исключение). [#5282](https://github.com/yandex/ClickHouse/pull/5282) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлен data race в запросе `RENAME`. [#5247](https://github.com/yandex/ClickHouse/pull/5247) ([Winter Zhang](https://github.com/zhang2014)) -* Отключен LFAlloc. Использование LFAlloc могло приводить к ошибкам MAP_FAILED при использовании UncompressedCache и в результате к падению запросов на высоконагруженных серверах. [cfdba93](https://github.com/yandex/ClickHouse/commit/cfdba938ce22f16efeec504f7f90206a515b1280)([Danila Kutenin](https://github.com/danlark1)) - - -## ClickHouse release 19.6.2.11, 2019-05-13 - -### Новые возможности -* TTL выражения, позволяющие настроить время жизни и автоматическую очистку данных в таблице или в отдельных её столбцах. [#4212](https://github.com/yandex/ClickHouse/pull/4212) ([Anton Popov](https://github.com/CurtizJ)) -* Добавлена поддержка алгоритма сжатия `brotli` в HTTP ответах (`Accept-Encoding: br`). Для тела POST запросов, эта возможность уже существовала. [#4388](https://github.com/yandex/ClickHouse/pull/4388) ([Mikhail](https://github.com/fandyushin)) -* Добавлена функция `isValidUTF8` для проверки, содержит ли строка валидные данные в кодировке UTF-8. [#4934](https://github.com/yandex/ClickHouse/pull/4934) ([Danila Kutenin](https://github.com/danlark1)) -* Добавлены новое правило балансировки (`load_balancing`) `first_or_random` по которому запросы посылаются на первый заданый хост и если он недоступен - на случайные хосты шарда. Полезно для топологий с кросс-репликацией. [#5012](https://github.com/yandex/ClickHouse/pull/5012) ([nvartolomei](https://github.com/nvartolomei)) - -### Экспериментальные возможности -* Добавлена настройка `index_granularity_bytes` (адаптивная гранулярность индекса) для таблиц семейства MergeTree* . [#4826](https://github.com/yandex/ClickHouse/pull/4826) ([alesapin](https://github.com/alesapin)) - -### Улучшения -* Добавлена поддержка для не константных и отрицательных значений аргументов смещения и длины для функции `substringUTF8`. [#4989](https://github.com/yandex/ClickHouse/pull/4989) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Отключение push-down в правую таблицы в left join, левую таблицу в right join, и в обе таблицы в full join. Это исправляет неправильные JOIN результаты в некоторых случаях. [#4846](https://github.com/yandex/ClickHouse/pull/4846) ([Ivan](https://github.com/abyss7)) -* `clickhouse-copier`: Автоматическая загрузка конфигурации задачи в zookeeper из `--task-file` опции [#4876](https://github.com/yandex/ClickHouse/pull/4876) ([proller](https://github.com/proller)) -* Добавлены подсказки с учётом опечаток для имён движков таблиц и табличных функций. [#4891](https://github.com/yandex/ClickHouse/pull/4891) ([Danila Kutenin](https://github.com/danlark1)) -* Поддержка выражений `select *` и `select tablename.*` для множественных join без подзапросов [#4898](https://github.com/yandex/ClickHouse/pull/4898) ([Artem Zuikov](https://github.com/4ertus2)) -* Сообщения об ошибках об отсутствующих столбцах стали более понятными. [#4915](https://github.com/yandex/ClickHouse/pull/4915) ([Artem Zuikov](https://github.com/4ertus2)) - -### Улучшение производительности -* Существенное ускорение ASOF JOIN [#4924](https://github.com/yandex/ClickHouse/pull/4924) ([Martijn Bakker](https://github.com/Gladdy)) - -### Обратно несовместимые изменения -* HTTP заголовок `Query-Id` переименован в `X-ClickHouse-Query-Id` для соответствия. [#4972](https://github.com/yandex/ClickHouse/pull/4972) ([Mikhail](https://github.com/fandyushin)) - -### Исправления ошибок -* Исправлены возможные разыменования нулевого указателя в `clickhouse-copier`. [#4900](https://github.com/yandex/ClickHouse/pull/4900) ([proller](https://github.com/proller)) -* Исправлены ошибки в запросах с JOIN + ARRAY JOIN [#4938](https://github.com/yandex/ClickHouse/pull/4938) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено зависание на старте сервера если внешний словарь зависит от другого словаря через использование таблицы из БД с движком `Dictionary`. [#4962](https://github.com/yandex/ClickHouse/pull/4962) ([Vitaly Baranov](https://github.com/vitlibar)) -* При использовании `distributed_product_mode = 'local'` корректно работает использование столбцов локальных таблиц в where/having/order by/... через табличные алиасы. Выкидывает исключение если таблица не имеет алиас. Доступ к столбцам без алиасов пока не возможен. [#4986](https://github.com/yandex/ClickHouse/pull/4986) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлен потенциально некорректный результат для `SELECT DISTINCT` с `JOIN` [#5001](https://github.com/yandex/ClickHouse/pull/5001) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлен очень редкий data race condition который мог произойти при выполнении запроса с UNION ALL включающего минимум два SELECT из таблиц system.columns, system.tables, system.parts, system.parts_tables или таблиц семейства Merge и одновременно выполняющихся запросов ALTER столбцов соответствующих таблиц. [#5189](https://github.com/yandex/ClickHouse/pull/5189) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Улучшения сборки/тестирования/пакетирования -* Исправлена неработоспособность тестов, если `clickhouse-server` запущен на удалённом хосте [#4713](https://github.com/yandex/ClickHouse/pull/4713) ([Vasily Nemkov](https://github.com/Enmk)) -* `clickhouse-test`: Отключена раскраска результата, если команда запускается не в терминале. [#4937](https://github.com/yandex/ClickHouse/pull/4937) ([alesapin](https://github.com/alesapin)) -* `clickhouse-test`: Возможность использования не только базы данных test [#5008](https://github.com/yandex/ClickHouse/pull/5008) ([proller](https://github.com/proller)) -* Исправлены ошибки при запуске тестов под UBSan [#5037](https://github.com/yandex/ClickHouse/pull/5037) ([Vitaly Baranov](https://github.com/vitlibar)) -* Добавлен аллокатор Yandex LFAlloc для аллоцирования MarkCache и UncompressedCache данных разными способами для более надежного отлавливания проездов по памяти [#4995](https://github.com/yandex/ClickHouse/pull/4995) ([Danila Kutenin](https://github.com/danlark1)) -* Утилита для упрощения бэкпортирования изменений в старые релизы и составления changelogs. [#4949](https://github.com/yandex/ClickHouse/pull/4949) ([Ivan](https://github.com/abyss7)) - - -## ClickHouse release 19.5.4.22, 2019-05-13 - -### Исправления ошибок -* Исправлены возможные падения в bitmap* функциях [#5220](https://github.com/yandex/ClickHouse/pull/5220) [#5228](https://github.com/yandex/ClickHouse/pull/5228) ([Andy Yang](https://github.com/andyyzh)) -* Исправлен очень редкий data race condition который мог произойти при выполнении запроса с UNION ALL включающего минимум два SELECT из таблиц system.columns, system.tables, system.parts, system.parts_tables или таблиц семейства Merge и одновременно выполняющихся запросов ALTER столбцов соответствующих таблиц. [#5189](https://github.com/yandex/ClickHouse/pull/5189) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка `Set for IN is not created yet in case of using single LowCardinality column in the left part of IN`. Эта ошибка возникала когда LowCardinality столбец была частью primary key. #5031 [#5154](https://github.com/yandex/ClickHouse/pull/5154) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправление функции retention: только первое соответствующее условие добавлялось в состояние данных. Сейчас все условия которые удовлетворяют в строке данных добавляются в состояние. [#5119](https://github.com/yandex/ClickHouse/pull/5119) ([小路](https://github.com/nicelulu)) - - -## ClickHouse release 19.5.3.8, 2019-04-18 - -### Исправления ошибок -* Исправлен тип настройки `max_partitions_per_insert_block` с булевого на UInt64. [#5028](https://github.com/yandex/ClickHouse/pull/5028) ([Mohammad Hossein Sekhavat](https://github.com/mhsekhavat)) - -## ClickHouse release 19.5.2.6, 2019-04-15 - -### Новые возможности - -* Добавлены функции для работы с несколькими регулярными выражениями с помощью библиотеки [Hyperscan](https://github.com/intel/hyperscan). (`multiMatchAny`, `multiMatchAnyIndex`, `multiFuzzyMatchAny`, `multiFuzzyMatchAnyIndex`). [#4780](https://github.com/yandex/ClickHouse/pull/4780), [#4841](https://github.com/yandex/ClickHouse/pull/4841) ([Danila Kutenin](https://github.com/danlark1)) -* Добавлена функция `multiSearchFirstPosition`. [#4780](https://github.com/yandex/ClickHouse/pull/4780) ([Danila Kutenin](https://github.com/danlark1)) -* Реализована возможность указания построчного ограничения доступа к таблицам. [#4792](https://github.com/yandex/ClickHouse/pull/4792) ([Ivan](https://github.com/abyss7)) -* Добавлен новый тип вторичного индекса на базе фильтра Блума (используется в функциях `equal`, `in` и `like`). [#4499](https://github.com/yandex/ClickHouse/pull/4499) ([Nikita Vasilev](https://github.com/nikvas0)) -* Добавлен `ASOF JOIN` которые позволяет джойнить строки по наиболее близкому известному значению. [#4774](https://github.com/yandex/ClickHouse/pull/4774) [#4867](https://github.com/yandex/ClickHouse/pull/4867) [#4863](https://github.com/yandex/ClickHouse/pull/4863) [#4875](https://github.com/yandex/ClickHouse/pull/4875) ([Martijn Bakker](https://github.com/Gladdy), [Artem Zuikov](https://github.com/4ertus2)) -* Теперь запрос `COMMA JOIN` переписывается `CROSS JOIN`. И затем оба переписываются в `INNER JOIN`, если это возможно. [#4661](https://github.com/yandex/ClickHouse/pull/4661) ([Artem Zuikov](https://github.com/4ertus2)) - -### Улучшения - -* Функции `topK` и `topKWeighted` теперь поддерживают произвольный `loadFactor` (исправляет issue [#4252](https://github.com/yandex/ClickHouse/issues/4252)). [#4634](https://github.com/yandex/ClickHouse/pull/4634) ([Kirill Danshin](https://github.com/kirillDanshin)) -* Добавлена возможность использования настройки `parallel_replicas_count > 1` для таблиц без семплирования (ранее настройка просто игнорировалась). [#4637](https://github.com/yandex/ClickHouse/pull/4637) ([Alexey Elymanov](https://github.com/digitalist)) -* Поддержан запрос `CREATE OR REPLACE VIEW`. Позволяет создать `VIEW` или изменить запрос в одном выражении. [#4654](https://github.com/yandex/ClickHouse/pull/4654) ([Boris Granveaud](https://github.com/bgranvea)) -* Движок таблиц `Buffer` теперь поддерживает `PREWHERE`. [#4671](https://github.com/yandex/ClickHouse/pull/4671) ([Yangkuan Liu](https://github.com/LiuYangkuan)) -* Теперь реплицируемые таблицы могу стартовать в `readonly` режиме даже при отсутствии zookeeper. [#4691](https://github.com/yandex/ClickHouse/pull/4691) ([alesapin](https://github.com/alesapin)) -* Исправлено мигание прогресс-бара в clickhouse-client. Проблема была наиболее заметна при использовании `FORMAT Null` в потоковых запросах. [#4811](https://github.com/yandex/ClickHouse/pull/4811) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена возможность отключения функций, использующих библиотеку `hyperscan`, для пользователей, чтобы ограничить возможное неконтролируемое потребление ресурсов. [#4816](https://github.com/yandex/ClickHouse/pull/4816) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлено логирование номера версии во все исключения. [#4824](https://github.com/yandex/ClickHouse/pull/4824) ([proller](https://github.com/proller)) -* Добавлено ограничение на размер строк и количество параметров в функции `multiMatch`. Теперь они принимают строки умещающиеся в `unsigned int`. [#4834](https://github.com/yandex/ClickHouse/pull/4834) ([Danila Kutenin](https://github.com/danlark1)) -* Улучшено использование памяти и обработка ошибок в Hyperscan. [#4866](https://github.com/yandex/ClickHouse/pull/4866) ([Danila Kutenin](https://github.com/danlark1)) -* Теперь системная таблица `system.graphite_detentions` заполняется из конфигурационного файла для таблиц семейства `*GraphiteMergeTree`. [#4584](https://github.com/yandex/ClickHouse/pull/4584) ([Mikhail f. Shiryaev](https://github.com/Felixoid)) -* Функция `trigramDistance` переименована в функцию `ngramDistance`. Добавлено несколько функций с `CaseInsensitive` и `UTF`. [#4602](https://github.com/yandex/ClickHouse/pull/4602) ([Danila Kutenin](https://github.com/danlark1)) -* Улучшено вычисление вторичных индексов. [#4640](https://github.com/yandex/ClickHouse/pull/4640) ([Nikita Vasilev](https://github.com/nikvas0)) -* Теперь обычные колонки, а также колонки `DEFAULT`, `MATERIALIZED` и `ALIAS` хранятся в одном списке (исправляет issue [#2867](https://github.com/yandex/ClickHouse/issues/2867)). [#4707](https://github.com/yandex/ClickHouse/pull/4707) ([Alex Zatelepin](https://github.com/ztlpn)) - -### Исправления ошибок - -* В случае невозможности выделить память вместо вызова `std::terminate` бросается исключение `std::bad_alloc`. [#4665](https://github.com/yandex/ClickHouse/pull/4665) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены ошибки чтения capnproto из буфера. Иногда файлы не загружались по HTTP. [#4674](https://github.com/yandex/ClickHouse/pull/4674) ([Vladislav](https://github.com/smirnov-vs)) -* Исправлена ошибка `Unknown log entry type: 0` после запроса `OPTIMIZE TABLE FINAL`. [#4683](https://github.com/yandex/ClickHouse/pull/4683) ([Amos Bird](https://github.com/amosbird)) -* При передаче неправильных аргументов в `hasAny` и `hasAll` могла происходить ошибка сегментирования. [#4698](https://github.com/yandex/ClickHouse/pull/4698) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен дедлок, который мог происходить при запросе `DROP DATABASE dictionary`. [#4701](https://github.com/yandex/ClickHouse/pull/4701) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено неопределенное поведение в функциях `median` и `quantile`. [#4702](https://github.com/yandex/ClickHouse/pull/4702) ([hcz](https://github.com/hczhcz)) -* Исправлено определение уровня сжатия при указании настройки `network_compression_method` в нижнем регистре. Было сломано в v19.1. [#4706](https://github.com/yandex/ClickHouse/pull/4706) ([proller](https://github.com/proller)) -* Настройка `UTC` больше не игнорируется (исправляет issue [#4658](https://github.com/yandex/ClickHouse/issues/4658)). [#4718](https://github.com/yandex/ClickHouse/pull/4718) ([proller](https://github.com/proller)) -* Исправлено поведение функции `histogram` с `Distributed` таблицами. [#4741](https://github.com/yandex/ClickHouse/pull/4741) ([olegkv](https://github.com/olegkv)) -* Исправлено срабатывание thread-санитайзера с ошибкой `destroy of a locked mutex`. [#4742](https://github.com/yandex/ClickHouse/pull/4742) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено срабатывание thread-санитайзера при завершении сервера, вызванное гонкой при использовании системных логов. Также исправлена потенциальная ошибка use-after-free при завершении сервера в котором был включен `part_log`. [#4758](https://github.com/yandex/ClickHouse/pull/4758) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена перепроверка кусков в `ReplicatedMergeTreeAlterThread` при появлении ошибок. [#4772](https://github.com/yandex/ClickHouse/pull/4772) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена работа арифметических операций с промежуточными состояниями агрегатных функций для константных аргументов (таких как результаты подзапросов). [#4776](https://github.com/yandex/ClickHouse/pull/4776) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Теперь имена колонок всегда экранируются в файлах с метаинформацией. В противном случае было невозможно создать таблицу с колонкой с именем `index`. [#4782](https://github.com/yandex/ClickHouse/pull/4782) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено падение в запросе `ALTER ... MODIFY ORDER BY` к `Distributed` таблице. [#4790](https://github.com/yandex/ClickHouse/pull/4790) ([TCeason](https://github.com/TCeason)) -* Исправлена ошибка сегментирования при запросах с `JOIN ON` и включенной настройкой `enable_optimize_predicate_expression`. [#4794](https://github.com/yandex/ClickHouse/pull/4794) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлено добавление лишней строки после чтения protobuf-сообщения из таблицы с движком `Kafka`. [#4808](https://github.com/yandex/ClickHouse/pull/4808) ([Vitaly Baranov](https://github.com/vitlibar)) -* Исправлено падение при запросе с `JOIN ON` с не `nullable` и nullable колонкой. Также исправлено поведение при появлении `NULLs` среди ключей справа в`ANY JOIN` + `join_use_nulls`. [#4815](https://github.com/yandex/ClickHouse/pull/4815) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлена ошибка сегментирования в `clickhouse-copier`. [#4835](https://github.com/yandex/ClickHouse/pull/4835) ([proller](https://github.com/proller)) -* Исправлена гонка при `SELECT` запросе из `system.tables` если таблица была конкурентно переименована или к ней был применен `ALTER` запрос. [#4836](https://github.com/yandex/ClickHouse/pull/4836) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена гонка при скачивании куска, который уже является устаревшим. [#4839](https://github.com/yandex/ClickHouse/pull/4839) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена редкая гонка при `RENAME` запросах к таблицам семейства MergeTree. [#4844](https://github.com/yandex/ClickHouse/pull/4844) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка сегментирования в функции `arrayIntersect`. Ошибка возникала при вызове функции с константными и не константными аргументами. [#4847](https://github.com/yandex/ClickHouse/pull/4847) ([Lixiang Qian](https://github.com/fancyqlx)) -* Исправлена редкая ошибка при чтении из колонки типа `Array(LowCardinality)`, которая возникала, если в колонке содержалось большее количество подряд идущих пустых массивов. [#4850](https://github.com/yandex/ClickHouse/pull/4850) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлено паление в запроса с `FULL/RIGHT JOIN` когда объединение происходило по nullable и не nullable колонке. [#4855](https://github.com/yandex/ClickHouse/pull/4855) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлена ошибка `No message received`, возникавшая при скачивании кусков между репликами. [#4856](https://github.com/yandex/ClickHouse/pull/4856) ([alesapin](https://github.com/alesapin)) -* Исправлена ошибка в функции `arrayIntersect` приводившая к неправильным результатам в случае нескольких повторяющихся значений в массиве. [#4871](https://github.com/yandex/ClickHouse/pull/4871) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена гонка при конкурентных `ALTER COLUMN` запросах, которая могла приводить к падению сервера (исправляет issue [#3421](https://github.com/yandex/ClickHouse/issues/3421)). [#4592](https://github.com/yandex/ClickHouse/pull/4592) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлен некорректный результат в `FULL/RIGHT JOIN` запросах с константной колонкой. [#4723](https://github.com/yandex/ClickHouse/pull/4723) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено появление дубликатов в `GLOBAL JOIN` со звездочкой. [#4705](https://github.com/yandex/ClickHouse/pull/4705) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено определение параметров кодеков в запросах `ALTER MODIFY`, если тип колонки не был указан. [#4883](https://github.com/yandex/ClickHouse/pull/4883) ([alesapin](https://github.com/alesapin)) -* Функции `cutQueryStringAndFragment()` и `queryStringAndFragment()` теперь работают корректно, когда `URL` содержит фрагмент, но не содержит запроса. [#4894](https://github.com/yandex/ClickHouse/pull/4894) ([Vitaly Baranov](https://github.com/vitlibar)) -* Исправлена редкая ошибка, возникавшая при установке настройки `min_bytes_to_use_direct_io` больше нуля. Она возникла при необходимости сдвинутся в файле, который уже прочитан до конца. [#4897](https://github.com/yandex/ClickHouse/pull/4897) ([alesapin](https://github.com/alesapin)) -* Исправлено неправильное определение типов аргументов для агрегатных функций с `LowCardinality` аргументами (исправляет [#4919](https://github.com/yandex/ClickHouse/issues/4919)). [#4922](https://github.com/yandex/ClickHouse/pull/4922) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена неверная квалификация имён в `GLOBAL JOIN`. [#4969](https://github.com/yandex/ClickHouse/pull/4969) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлен результат функции `toISOWeek` для 1970 года. [#4988](https://github.com/yandex/ClickHouse/pull/4988) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено дублирование `DROP`, `TRUNCATE` и `OPTIMIZE` запросов, когда они выполнялись `ON CLUSTER` для семейства таблиц `ReplicatedMergeTree*`. [#4991](https://github.com/yandex/ClickHouse/pull/4991) ([alesapin](https://github.com/alesapin)) - -### Обратно несовместимые изменения - -* Настройка `insert_sample_with_metadata` переименована в `input_format_defaults_for_omitted_fields`. [#4771](https://github.com/yandex/ClickHouse/pull/4771) ([Artem Zuikov](https://github.com/4ertus2)) -* Добавлена настройка `max_partitions_per_insert_block` (со значением по умолчанию 100). Если вставляемый блок содержит большое количество партиций, то бросается исключение. Лимит можно убрать выставив настройку в 0 (не рекомендуется). [#4845](https://github.com/yandex/ClickHouse/pull/4845) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Функции мультипоиска были переименованы (`multiPosition` в `multiSearchAllPositions`, `multiSearch` в `multiSearchAny`, `firstMatch` в `multiSearchFirstIndex`). [#4780](https://github.com/yandex/ClickHouse/pull/4780) ([Danila Kutenin](https://github.com/danlark1)) - -### Улучшение производительности - -* Оптимизирован поиска с помощью алгоритма Volnitsky с помощью инлайнинга. Это дает около 5-10% улучшения производительности поиска для запросов ищущих множество слов или много одинаковых биграмм. [#4862](https://github.com/yandex/ClickHouse/pull/4862) ([Danila Kutenin](https://github.com/danlark1)) -* Исправлено снижение производительности при выставлении настройки `use_uncompressed_cache` больше нуля для запросов, данные которых целиком лежат в кеше. [#4913](https://github.com/yandex/ClickHouse/pull/4913) ([alesapin](https://github.com/alesapin)) - - -### Улучшения сборки/тестирования/пакетирования - -* Более строгие настройки для debug-сборок: более гранулярные маппинги памяти и использование ASLR; добавлена защита памяти для кеша засечек и индекса. Это позволяет найти больше ошибок порчи памяти, которые не обнаруживают address-санитайзер и thread-санитайзер. [#4632](https://github.com/yandex/ClickHouse/pull/4632) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлены настройки `ENABLE_PROTOBUF`, `ENABLE_PARQUET` и `ENABLE_BROTLI` которые позволяют отключить соответствующие компоненты. [#4669](https://github.com/yandex/ClickHouse/pull/4669) ([Silviu Caragea](https://github.com/silviucpp)) -* Теперь при зависании запросов во время работы тестов будет показан список запросов и стек-трейсы всех потоков. [#4675](https://github.com/yandex/ClickHouse/pull/4675) ([alesapin](https://github.com/alesapin)) -* Добавлены ретраи при ошибке `Connection loss` в `clickhouse-test`. [#4682](https://github.com/yandex/ClickHouse/pull/4682) ([alesapin](https://github.com/alesapin)) -* Добавлена возможность сборки под FreeBSD в `packager`-скрипт. [#4712](https://github.com/yandex/ClickHouse/pull/4712) [#4748](https://github.com/yandex/ClickHouse/pull/4748) ([alesapin](https://github.com/alesapin)) -* Теперь при установке предлагается установить пароль для пользователя `'default'`. [#4725](https://github.com/yandex/ClickHouse/pull/4725) ([proller](https://github.com/proller)) -* Убраны предупреждения из библиотеки `rdkafka` при сборке. [#4740](https://github.com/yandex/ClickHouse/pull/4740) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена возможность сборки без поддержки ssl. [#4750](https://github.com/yandex/ClickHouse/pull/4750) ([proller](https://github.com/proller)) -* Добавлена возможность запускать докер-образ с clickhouse-server из под любого пользователя. [#4753](https://github.com/yandex/ClickHouse/pull/4753) ([Mikhail f. Shiryaev](https://github.com/Felixoid)) -* Boost обновлен до 1.69. [#4793](https://github.com/yandex/ClickHouse/pull/4793) ([proller](https://github.com/proller)) -* Отключено использование `mremap` при сборке с thread-санитайзером, что приводило к ложным срабатываниям. Исправлены ошибки thread-санитайзера в stateful-тестах. [#4859](https://github.com/yandex/ClickHouse/pull/4859) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлен тест проверяющий использование схемы форматов для HTTP-интерфейса. [#4864](https://github.com/yandex/ClickHouse/pull/4864) ([Vitaly Baranov](https://github.com/vitlibar)) - -## ClickHouse release 19.4.4.33, 2019-04-17 - -### Исправление ошибок -* В случае невозможности выделить память вместо вызова `std::terminate` бросается исключение `std::bad_alloc`. [#4665](https://github.com/yandex/ClickHouse/pull/4665) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены ошибки чтения capnproto из буфера. Иногда файлы не загружались по HTTP. [#4674](https://github.com/yandex/ClickHouse/pull/4674) ([Vladislav](https://github.com/smirnov-vs)) -* Исправлена ошибка `Unknown log entry type: 0` после запроса `OPTIMIZE TABLE FINAL`. [#4683](https://github.com/yandex/ClickHouse/pull/4683) ([Amos Bird](https://github.com/amosbird)) -* При передаче неправильных аргументов в `hasAny` и `hasAll` могла происходить ошибка сегментирования. [#4698](https://github.com/yandex/ClickHouse/pull/4698) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен дедлок, который мог происходить при запросе `DROP DATABASE dictionary`. [#4701](https://github.com/yandex/ClickHouse/pull/4701) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено неопределенное поведение в функциях `median` и `quantile`. [#4702](https://github.com/yandex/ClickHouse/pull/4702) ([hcz](https://github.com/hczhcz)) -* Исправлено определение уровня сжатия при указании настройки `network_compression_method` в нижнем регистре. Было сломано в v19.1. [#4706](https://github.com/yandex/ClickHouse/pull/4706) ([proller](https://github.com/proller)) -* Настройка `UTC` больше не игнорируется (исправляет issue [#4658](https://github.com/yandex/ClickHouse/issues/4658)). [#4718](https://github.com/yandex/ClickHouse/pull/4718) ([proller](https://github.com/proller)) -* Исправлено поведение функции `histogram` с `Distributed` таблицами. [#4741](https://github.com/yandex/ClickHouse/pull/4741) ([olegkv](https://github.com/olegkv)) -* Исправлено срабатывание thread-санитайзера с ошибкой `destroy of a locked mutex`. [#4742](https://github.com/yandex/ClickHouse/pull/4742) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено срабатывание thread-санитайзера при завершении сервера, вызванное гонкой при использовании системных логов. Также исправлена потенциальная ошибка use-after-free при завершении сервера в котором был включен `part_log`. [#4758](https://github.com/yandex/ClickHouse/pull/4758) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена перепроверка кусков в `ReplicatedMergeTreeAlterThread` при появлении ошибок. [#4772](https://github.com/yandex/ClickHouse/pull/4772) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена работа арифметических операций с промежуточными состояниями агрегатных функций для константных аргументов (таких как результаты подзапросов). [#4776](https://github.com/yandex/ClickHouse/pull/4776) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Теперь имена колонок всегда экранируются в файлах с метаинформацией. В противном случае было невозможно создать таблицу с колонкой с именем `index`. [#4782](https://github.com/yandex/ClickHouse/pull/4782) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено падение в запросе `ALTER ... MODIFY ORDER BY` к `Distributed` таблице. [#4790](https://github.com/yandex/ClickHouse/pull/4790) ([TCeason](https://github.com/TCeason)) -* Исправлена ошибка сегментирования при запросах с `JOIN ON` и включенной настройкой `enable_optimize_predicate_expression`. [#4794](https://github.com/yandex/ClickHouse/pull/4794) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлено добавление лишней строки после чтения protobuf-сообщения из таблицы с движком `Kafka`. [#4808](https://github.com/yandex/ClickHouse/pull/4808) ([Vitaly Baranov](https://github.com/vitlibar)) -* Исправлена ошибка сегментирования в `clickhouse-copier`. [#4835](https://github.com/yandex/ClickHouse/pull/4835) ([proller](https://github.com/proller)) -* Исправлена гонка при `SELECT` запросе из `system.tables` если таблица была конкурентно переименована или к ней был применен `ALTER` запрос. [#4836](https://github.com/yandex/ClickHouse/pull/4836) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена гонка при скачивании куска, который уже является устаревшим. [#4839](https://github.com/yandex/ClickHouse/pull/4839) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена редкая гонка при `RENAME` запросах к таблицам семейства MergeTree. [#4844](https://github.com/yandex/ClickHouse/pull/4844) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка сегментирования в функции `arrayIntersect`. Ошибка возникала при вызове функции с константными и не константными аргументами. [#4847](https://github.com/yandex/ClickHouse/pull/4847) ([Lixiang Qian](https://github.com/fancyqlx)) -* Исправлена редкая ошибка при чтении из колонки типа `Array(LowCardinality)`, которая возникала, если в колонке содержалось большее количество подряд идущих пустых массивов. [#4850](https://github.com/yandex/ClickHouse/pull/4850) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена ошибка `No message received`, возникавшая при скачивании кусков между репликами. [#4856](https://github.com/yandex/ClickHouse/pull/4856) ([alesapin](https://github.com/alesapin)) -* Исправлена ошибка в функции `arrayIntersect` приводившая к неправильным результатам в случае нескольких повторяющихся значений в массиве. [#4871](https://github.com/yandex/ClickHouse/pull/4871) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена гонка при конкурентных `ALTER COLUMN` запросах, которая могла приводить к падению сервера (исправляет issue [#3421](https://github.com/yandex/ClickHouse/issues/3421)). [#4592](https://github.com/yandex/ClickHouse/pull/4592) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлено определение параметров кодеков в запросах `ALTER MODIFY`, если тип колонки не был указан. [#4883](https://github.com/yandex/ClickHouse/pull/4883) ([alesapin](https://github.com/alesapin)) -* Функции `cutQueryStringAndFragment()` и `queryStringAndFragment()` теперь работают корректно, когда `URL` содержит фрагмент, но не содержит запроса. [#4894](https://github.com/yandex/ClickHouse/pull/4894) ([Vitaly Baranov](https://github.com/vitlibar)) -* Исправлена редкая ошибка, возникавшая при установке настройки `min_bytes_to_use_direct_io` больше нуля. Она возникла при необходимости сдвинутся в файле, который уже прочитан до конца. [#4897](https://github.com/yandex/ClickHouse/pull/4897) ([alesapin](https://github.com/alesapin)) -* Исправлено неправильное определение типов аргументов для агрегатных функций с `LowCardinality` аргументами (исправляет [#4919](https://github.com/yandex/ClickHouse/issues/4919)). [#4922](https://github.com/yandex/ClickHouse/pull/4922) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлен результат функции `toISOWeek` для 1970 года. [#4988](https://github.com/yandex/ClickHouse/pull/4988) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено дублирование `DROP`, `TRUNCATE` и `OPTIMIZE` запросов, когда они выполнялись `ON CLUSTER` для семейства таблиц `ReplicatedMergeTree*`. [#4991](https://github.com/yandex/ClickHouse/pull/4991) ([alesapin](https://github.com/alesapin)) - -### Улучшения - -* Теперь обычные колонки, а также колонки `DEFAULT`, `MATERIALIZED` и `ALIAS` хранятся в одном списке (исправляет issue [#2867](https://github.com/yandex/ClickHouse/issues/2867)). [#4707](https://github.com/yandex/ClickHouse/pull/4707) ([Alex Zatelepin](https://github.com/ztlpn)) - -## ClickHouse release 19.4.3.11, 2019-04-02 - -### Исправление ошибок - -* Исправлено паление в запроса с `FULL/RIGHT JOIN` когда объединение происходило по nullable и не nullable колонке. [#4855](https://github.com/yandex/ClickHouse/pull/4855) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлена ошибка сегментирования в `clickhouse-copier`. [#4835](https://github.com/yandex/ClickHouse/pull/4835) ([proller](https://github.com/proller)) - -### Улучшения сборки/тестирования/пакетирования - -* Добавлена возможность запускать докер-образ с clickhouse-server из под любого пользователя. [#4753](https://github.com/yandex/ClickHouse/pull/4753) ([Mikhail f. Shiryaev](https://github.com/Felixoid)) - -## ClickHouse release 19.4.2.7, 2019-03-30 - -### Исправление ошибок -* Исправлена редкая ошибка при чтении из колонки типа `Array(LowCardinality)`, которая возникала, если в колонке содержалось большее количество подряд идущих пустых массивов. [#4850](https://github.com/yandex/ClickHouse/pull/4850) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) - -## ClickHouse release 19.4.1.3, 2019-03-19 - -### Исправление ошибок -* Исправлено поведение удаленных запросов, которые одновременно содержали `LIMIT BY` и `LIMIT`. Раньше для таких запросов `LIMIT` мог быть выполнен до `LIMIT BY`, что приводило к перефильтрации. [#4708](https://github.com/yandex/ClickHouse/pull/4708) ([Constantin S. Pan](https://github.com/kvap)) - -## ClickHouse release 19.4.0.49, 2019-03-09 - -### Новые возможности -* Добавлена полная поддержка формата `Protobuf` (чтение и запись, вложенные структуры данных). [#4174](https://github.com/yandex/ClickHouse/pull/4174) [#4493](https://github.com/yandex/ClickHouse/pull/4493) ([Vitaly Baranov](https://github.com/vitlibar)) -* Добавлены функции для работы с битовыми масками с использованием библиотеки Roaring Bitmaps. [#4207](https://github.com/yandex/ClickHouse/pull/4207) ([Andy Yang](https://github.com/andyyzh)) [#4568](https://github.com/yandex/ClickHouse/pull/4568) ([Vitaly Baranov](https://github.com/vitlibar)) -* Поддержка формата `Parquet` [#4448](https://github.com/yandex/ClickHouse/pull/4448) ([proller](https://github.com/proller)) -* Вычисление расстояния между строками с помощью подсчёта N-грам - для приближённого сравнения строк. Алгоритм похож на q-gram metrics в языке R. [#4466](https://github.com/yandex/ClickHouse/pull/4466) ([Danila Kutenin](https://github.com/danlark1)) -* Движок таблиц GraphiteMergeTree поддерживает отдельные шаблоны для правил агрегации и для правил времени хранения. [#4426](https://github.com/yandex/ClickHouse/pull/4426) ([Mikhail f. Shiryaev](https://github.com/Felixoid)) -* Добавлены настройки `max_execution_speed` и `max_execution_speed_bytes` для того, чтобы ограничить потребление ресурсов запросами. Добавлена настройка `min_execution_speed_bytes` в дополнение к `min_execution_speed`. [#4430](https://github.com/yandex/ClickHouse/pull/4430) ([Winter Zhang](https://github.com/zhang2014)) -* Добавлена функция `flatten` - конвертация многомерных массивов в плоский массив. [#4555](https://github.com/yandex/ClickHouse/pull/4555) [#4409](https://github.com/yandex/ClickHouse/pull/4409) ([alexey-milovidov](https://github.com/alexey-milovidov), [kzon](https://github.com/kzon)) -* Добавлены функции `arrayEnumerateDenseRanked` и `arrayEnumerateUniqRanked` (похожа на `arrayEnumerateUniq` но позволяет указать глубину, на которую следует смотреть в многомерные массивы). [#4475](https://github.com/yandex/ClickHouse/pull/4475) ([proller](https://github.com/proller)) [#4601](https://github.com/yandex/ClickHouse/pull/4601) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена поддержка множества JOIN в одном запросе без подзапросов, с некоторыми ограничениями: без звёздочки и без алиасов сложных выражений в ON/WHERE/GROUP BY/... [#4462](https://github.com/yandex/ClickHouse/pull/4462) ([Artem Zuikov](https://github.com/4ertus2)) - -### Исправления ошибок -* Этот релиз также содержит все исправления из 19.3 и 19.1. -* Исправлена ошибка во вторичных индексах (экспериментальная возможность): порядок гранул при INSERT был неверным. [#4407](https://github.com/yandex/ClickHouse/pull/4407) ([Nikita Vasilev](https://github.com/nikvas0)) -* Исправлена работа вторичного индекса (экспериментальная возможность) типа `set` для столбцов типа `Nullable` и `LowCardinality`. Ранее их использование вызывало ошибку `Data type must be deserialized with multiple streams` при запросе SELECT. [#4594](https://github.com/yandex/ClickHouse/pull/4594) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Правильное запоминание времени последнего обновления при полной перезагрузке словарей типа `executable`. [#4551](https://github.com/yandex/ClickHouse/pull/4551) ([Tema Novikov](https://github.com/temoon)) -* Исправлена неработоспособность прогресс-бара, возникшая в версии 19.3 [#4627](https://github.com/yandex/ClickHouse/pull/4627) ([filimonov](https://github.com/filimonov)) -* Исправлены неправильные значения MemoryTracker, если кусок памяти был уменьшен в размере, в очень редких случаях. [#4619](https://github.com/yandex/ClickHouse/pull/4619) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено undefined behaviour в ThreadPool [#4612](https://github.com/yandex/ClickHouse/pull/4612) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено очень редкое падение с сообщением `mutex lock failed: Invalid argument`, которое могло произойти, если таблица типа MergeTree удалялась одновременно с SELECT. [#4608](https://github.com/yandex/ClickHouse/pull/4608) ([Alex Zatelepin](https://github.com/ztlpn)) -* Совместимость ODBC драйвера с типом данных `LowCardinality` [#4381](https://github.com/yandex/ClickHouse/pull/4381) ([proller](https://github.com/proller)) -* Исправление ошибки `AIOcontextPool: Found io_event with unknown id 0` под ОС FreeBSD [#4438](https://github.com/yandex/ClickHouse/pull/4438) ([urgordeadbeef](https://github.com/urgordeadbeef)) -* Таблица `system.part_log` создавалась независимо от того, была ли она объявлена в конфигурации. [#4483](https://github.com/yandex/ClickHouse/pull/4483) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено undefined behaviour в функции `dictIsIn` для словарей типа `cache`. [#4515](https://github.com/yandex/ClickHouse/pull/4515) ([alesapin](https://github.com/alesapin)) -* Исправлен deadlock в случае, если запрос SELECT блокирует одну и ту же таблицу несколько раз (например - из разных потоков, либо при выполнении разных подзапросов) и одновременно с этим производится DDL запрос. [#4535](https://github.com/yandex/ClickHouse/pull/4535) ([Alex Zatelepin](https://github.com/ztlpn)) -* Настройка `compile_expressions` выключена по-умолчанию до тех пор, пока мы не зафиксируем исходники используемой библиотеки `LLVM` и не будем проверять её под `ASan` (сейчас библиотека LLVM берётся из системы). [#4579](https://github.com/yandex/ClickHouse/pull/4579) ([alesapin](https://github.com/alesapin)) -* Исправлено падение по `std::terminate`, если `invalidate_query` для внешних словарей с источником `clickhouse` вернул неправильный результат (пустой; более чем одну строку; более чем один столбец). Исправлена ошибка, из-за которой запрос `invalidate_query` производился каждые пять секунд, независимо от указанного `lifetime`. [#4583](https://github.com/yandex/ClickHouse/pull/4583) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен deadlock в случае, если запрос `invalidate_query` для внешнего словаря с источником `clickhouse` использовал таблицу `system.dictionaries` или базу данных типа `Dictionary` (редкий случай). [#4599](https://github.com/yandex/ClickHouse/pull/4599) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена работа CROSS JOIN с пустым WHERE [#4598](https://github.com/yandex/ClickHouse/pull/4598) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлен segfault в функции `replicate` с константным аргументом. [#4603](https://github.com/yandex/ClickHouse/pull/4603) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена работа predicate pushdown (настройка `enable_optimize_predicate_expression`) с лямбда-функциями. [#4408](https://github.com/yandex/ClickHouse/pull/4408) ([Winter Zhang](https://github.com/zhang2014)) -* Множественные исправления для множества JOIN в одном запросе. [#4595](https://github.com/yandex/ClickHouse/pull/4595) ([Artem Zuikov](https://github.com/4ertus2)) - -### Улучшения -* Поддержка алиасов в секции JOIN ON для правой таблицы [#4412](https://github.com/yandex/ClickHouse/pull/4412) ([Artem Zuikov](https://github.com/4ertus2)) -* Используются правильные алиасы в случае множественных JOIN с подзапросами. [#4474](https://github.com/yandex/ClickHouse/pull/4474) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлена логика работы predicate pushdown (настройка `enable_optimize_predicate_expression`) для JOIN. [#4387](https://github.com/yandex/ClickHouse/pull/4387) ([Ivan](https://github.com/abyss7)) - -### Улучшения производительности -* Улучшена эвристика оптимизации "перенос в PREWHERE". [#4405](https://github.com/yandex/ClickHouse/pull/4405) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Используются настоящие lookup таблицы вместо хэш-таблиц в случае 8 и 16 битных ключей. Интерфейс хэш-таблиц обобщён, чтобы поддерживать этот случай. [#4536](https://github.com/yandex/ClickHouse/pull/4536) ([Amos Bird](https://github.com/amosbird)) -* Улучшена производительность сравнения строк. [#4564](https://github.com/yandex/ClickHouse/pull/4564) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Очередь DDL операций (для запросов ON CLUSTER) очищается в отдельном потоке, чтобы не замедлять основную работу. [#4502](https://github.com/yandex/ClickHouse/pull/4502) ([Alex Zatelepin](https://github.com/ztlpn)) -* Даже если настройка `min_bytes_to_use_direct_io` выставлена в 1, не каждый файл открывался в режиме O_DIRECT, потому что размер файлов иногда недооценивался на размер одного сжатого блока. [#4526](https://github.com/yandex/ClickHouse/pull/4526) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Улучшения сборки/тестирования/пакетирования -* Добавлена поддержка компилятора clang-9 [#4604](https://github.com/yandex/ClickHouse/pull/4604) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены неправильные `__asm__` инструкции [#4621](https://github.com/yandex/ClickHouse/pull/4621) ([Konstantin Podshumok](https://github.com/podshumok)) -* Добавлена поддержка задания настроек выполнения запросов для `clickhouse-performance-test` из командной строки. [#4437](https://github.com/yandex/ClickHouse/pull/4437) ([alesapin](https://github.com/alesapin)) -* Тесты словарей перенесены в интеграционные тесты. [#4477](https://github.com/yandex/ClickHouse/pull/4477) ([alesapin](https://github.com/alesapin)) -* В набор автоматизированных тестов производительности добавлены запросы, находящиеся в разделе "benchmark" на официальном сайте. [#4496](https://github.com/yandex/ClickHouse/pull/4496) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправления сборки в случае использования внешних библиотек lz4 и xxhash. [#4495](https://github.com/yandex/ClickHouse/pull/4495) ([Orivej Desh](https://github.com/orivej)) -* Исправлен undefined behaviour, если функция `quantileTiming` была вызвана с отрицательным или нецелым аргументом (обнаружено с помощью fuzz test под undefined behaviour sanitizer). [#4506](https://github.com/yandex/ClickHouse/pull/4506) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены опечатки в коде. [#4531](https://github.com/yandex/ClickHouse/pull/4531) ([sdk2](https://github.com/sdk2)) -* Исправлена сборка под Mac. [#4371](https://github.com/yandex/ClickHouse/pull/4371) ([Vitaly Baranov](https://github.com/vitlibar)) -* Исправлена сборка под FreeBSD и для некоторых необычных конфигурациях сборки. [#4444](https://github.com/yandex/ClickHouse/pull/4444) ([proller](https://github.com/proller)) - - -## ClickHouse release 19.3.7, 2019-03-12 - -### Исправления ошибок - -* Исправлена ошибка в #3920. Ошибка проявлялась в виде случайных повреждений кэша (сообщения `Unknown codec family code`, `Cannot seek through file`) и segfault. Ошибка впервые возникла в 19.1 и присутствует во всех версиях до 19.1.10 и 19.3.6. [#4623](https://github.com/yandex/ClickHouse/pull/4623) ([alexey-milovidov](https://github.com/alexey-milovidov)) - - -## ClickHouse release 19.3.6, 2019-03-02 - -### Исправления ошибок - -* Если в пуле потоков было более 1000 потоков, то при выходе из потока, вызывается `std::terminate`. [Azat Khuzhin](https://github.com/azat) [#4485](https://github.com/yandex/ClickHouse/pull/4485) [#4505](https://github.com/yandex/ClickHouse/pull/4505) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Теперь возможно создавать таблицы `ReplicatedMergeTree*` с комментариями столбцов без указания DEFAULT, а также с CODEC но без COMMENT и DEFAULT. Исправлено сравнение CODEC друг с другом. [#4523](https://github.com/yandex/ClickHouse/pull/4523) ([alesapin](https://github.com/alesapin)) -* Исправлено падение при JOIN по массивам и кортежам. [#4552](https://github.com/yandex/ClickHouse/pull/4552) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено падение `clickhouse-copier` с сообщением `ThreadStatus not created`. [#4540](https://github.com/yandex/ClickHouse/pull/4540) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено зависание сервера при завершении работы в случае использования распределённых DDL. [#4472](https://github.com/yandex/ClickHouse/pull/4472) ([Alex Zatelepin](https://github.com/ztlpn)) -* В сообщениях об ошибке при парсинге текстовых форматов, выдавались неправильные номера столбцов, в случае, если номер больше 10. [#4484](https://github.com/yandex/ClickHouse/pull/4484) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Улучшения сборки/тестирования/пакетирования - -* Исправлена сборка с включенным AVX. [#4527](https://github.com/yandex/ClickHouse/pull/4527) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена поддержка расширенных метрик выполнения запроса в случае, если ClickHouse был собран на системе с новым ядром Linux, а запускается на системе с существенно более старым ядром. [#4541](https://github.com/yandex/ClickHouse/pull/4541) ([nvartolomei](https://github.com/nvartolomei)) -* Продолжение работы в случае невозможности применить настройку `core_dump.size_limit` с выводом предупреждения. [#4473](https://github.com/yandex/ClickHouse/pull/4473) ([proller](https://github.com/proller)) -* Удалено `inline` для `void readBinary(...)` в `Field.cpp`. [#4530](https://github.com/yandex/ClickHouse/pull/4530) ([hcz](https://github.com/hczhcz)) - - -## ClickHouse release 19.3.5, 2019-02-21 - -### Исправления ошибок: - -* Исправлена ошибка обработки длинных http-запросов на вставку на стороне сервера. [#4454](https://github.com/yandex/ClickHouse/pull/4454) ([alesapin](https://github.com/alesapin)) -* Исправлена обратная несовместимость со старыми версиями, появившаяся из-за некорректной реализации настройки `send_logs_level`. [#4445](https://github.com/yandex/ClickHouse/pull/4445) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена обратная несовместимость табличной функции `remote`, появившаяся из-за добавления комментариев колонок. [#4446](https://github.com/yandex/ClickHouse/pull/4446) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -## ClickHouse release 19.3.4, 2019-02-16 - -### Улучшения: - -* При выполнении запроса `ATTACH TABLE` при проверке ограничений на используемую память теперь не учитывается память, занимаемая индексом таблицы. Это позволяет избежать ситуации, когда невозможно сделать `ATTACH TABLE` после соответствующего `DETACH TABLE`. [#4396](https://github.com/yandex/ClickHouse/pull/4396) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Немного увеличены ограничения на максимальный размер строки и массива, полученные от ZooKeeper. Это позволяет продолжать работу после увеличения настройки ZooKeeper `CLIENT_JVMFLAGS=-Djute.maxbuffer=...`. [#4398](https://github.com/yandex/ClickHouse/pull/4398) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Теперь реплику, отключенную на длительный период, можно восстановить, даже если в её очереди скопилось огромное число записей. [#4399](https://github.com/yandex/ClickHouse/pull/4399) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Для вторичных индексов типа `set` добавлен обязательный параметр (максимальное число хранимых значений). [#4386](https://github.com/yandex/ClickHouse/pull/4386) ([Nikita Vasilev](https://github.com/nikvas0)) - -### Исправления ошибок: - -* Исправлен неверный результат запроса с модификатором `WITH ROLLUP` при группировке по единственному столбцу типа `LowCardinality`. [#4384](https://github.com/yandex/ClickHouse/pull/4384) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Исправлена ошибка во вторичном индексе типа `set` (гранулы, в которых было больше, чем `max_rows` строк, игнорировались). [#4386](https://github.com/yandex/ClickHouse/pull/4386) ([Nikita Vasilev](https://github.com/nikvas0)) -* Исправлена подстановка alias-ов в запросах с подзапросом, содержащим этот же alias ([#4110](https://github.com/yandex/ClickHouse/issues/4110)). [#4351](https://github.com/yandex/ClickHouse/pull/4351) ([Artem Zuikov](https://github.com/4ertus2)) - -### Улучшения сборки/тестирования/пакетирования: - -* Множество исправлений для сборки под FreeBSD. [#4397](https://github.com/yandex/ClickHouse/pull/4397) ([proller](https://github.com/proller)) -* Возможность запускать `clickhouse-server` для stateless тестов из docker-образа. [#4347](https://github.com/yandex/ClickHouse/pull/4347) ([Vasily Nemkov](https://github.com/Enmk)) - -## ClickHouse release 19.3.3, 2019-02-13 - -### Новые возможности: - -* Добавлен запрос `KILL MUTATION`, который позволяет удалять мутации, которые по какой-то причине не могут выполниться. В таблицу `system.mutations` для облегчения диагностики добавлены столбцы `latest_failed_part`, `latest_fail_time`, `latest_fail_reason`. [#4287](https://github.com/yandex/ClickHouse/pull/4287) ([Alex Zatelepin](https://github.com/ztlpn)) -* Добавлена агрегатная функция `entropy`, которая вычисляет энтропию Шеннона. [#4238](https://github.com/yandex/ClickHouse/pull/4238) ([Quid37](https://github.com/Quid37)) -* Добавлена обобщённая реализация функции `arrayWithConstant`. [#4322](https://github.com/yandex/ClickHouse/pull/4322) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлен оператор сравнения `NOT BETWEEN`. [#4228](https://github.com/yandex/ClickHouse/pull/4228) ([Dmitry Naumov](https://github.com/nezed)) -* Добавлена функция `sumMapFiltered` - вариант `sumMap`, позволяющий указать набор ключей, по которым будет производиться суммирование. [#4129](https://github.com/yandex/ClickHouse/pull/4129) ([Léo Ercolanelli](https://github.com/ercolanelli-leo)) -* Добавлена функция `sumMapWithOverflow`. [#4151](https://github.com/yandex/ClickHouse/pull/4151) ([Léo Ercolanelli](https://github.com/ercolanelli-leo)) -* Добавлена поддержка `Nullable` типов в табличной функции `mysql`. [#4198](https://github.com/yandex/ClickHouse/pull/4198) ([Emmanuel Donin de Rosière](https://github.com/edonin)) -* Добавлена поддержка произвольных константных выражений в секции `LIMIT`. [#4246](https://github.com/yandex/ClickHouse/pull/4246) ([k3box](https://github.com/k3box)) -* Добавлена агрегатная функция `topKWeighted` - вариант `topK`, позволяющий задавать (целый неотрицательный) вес добавляемого значения. [#4245](https://github.com/yandex/ClickHouse/pull/4245) ([Andrew Golman](https://github.com/andrewgolman)) -* Движок `Join` теперь поддерживает настройку `join_any_take_last_row`, которая позволяет перезаписывать значения для существующих ключей. [#3973](https://github.com/yandex/ClickHouse/pull/3973) ([Amos Bird](https://github.com/amosbird)) -* Добавлена функция `toStartOfInterval`. [#4304](https://github.com/yandex/ClickHouse/pull/4304) ([Vitaly Baranov](https://github.com/vitlibar)) -* Добавлена функция `toStartOfTenMinutes`. [#4298](https://github.com/yandex/ClickHouse/pull/4298) ([Vitaly Baranov](https://github.com/vitlibar)) -* Добавлен формат `RowBinaryWithNamesAndTypes`. [#4200](https://github.com/yandex/ClickHouse/pull/4200) ([Oleg V. Kozlyuk](https://github.com/DarkWanderer)) -* Добавлены типы `IPv4` и `IPv6`. Более эффективная реализация функций `IPv*`. [#3669](https://github.com/yandex/ClickHouse/pull/3669) ([Vasily Nemkov](https://github.com/Enmk)) -* Добавлен выходной формат `Protobuf`. [#4005](https://github.com/yandex/ClickHouse/pull/4005) [#4158](https://github.com/yandex/ClickHouse/pull/4158) ([Vitaly Baranov](https://github.com/vitlibar)) -* В HTTP-интерфейсе добавлена поддержка алгоритма сжатия brotli для вставляемых данных. [#4235](https://github.com/yandex/ClickHouse/pull/4235) ([Mikhail](https://github.com/fandyushin)) -* Клиент командной строки теперь подсказывает правильное имя, если пользователь опечатался в названии функции. [#4239](https://github.com/yandex/ClickHouse/pull/4239) ([Danila Kutenin](https://github.com/danlark1)) -* В HTTP-ответ сервера добавлен заголовок `Query-Id`. [#4231](https://github.com/yandex/ClickHouse/pull/4231) ([Mikhail](https://github.com/fandyushin)) - -### Экспериментальные возможности: - -* Добавлена поддержка вторичных индексов типа `minmax` и `set` для таблиц семейства MergeTree (позволяют быстро пропускать целые блоки данных). [#4143](https://github.com/yandex/ClickHouse/pull/4143) ([Nikita Vasilev](https://github.com/nikvas0)) -* Добавлена поддержка преобразования `CROSS JOIN` в `INNER JOIN`, если это возможно. [#4221](https://github.com/yandex/ClickHouse/pull/4221) [#4266](https://github.com/yandex/ClickHouse/pull/4266) ([Artem Zuikov](https://github.com/4ertus2)) - -### Исправления ошибок: - -* Исправлена ошибка `Not found column` для случая дублирующихся столбцов в секции `JOIN ON`. [#4279](https://github.com/yandex/ClickHouse/pull/4279) ([Artem Zuikov](https://github.com/4ertus2)) -* Команда `START REPLICATED SENDS` теперь действительно включает посылку кусков данных при репликации. [#4229](https://github.com/yandex/ClickHouse/pull/4229) ([nvartolomei](https://github.com/nvartolomei)) -* Исправлена агрегация столбцов типа `Array(LowCardinality)`. [#4055](https://github.com/yandex/ClickHouse/pull/4055) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Исправлена ошибка, приводившая к тому, что при исполнении запроса `INSERT ... SELECT ... FROM file(...)` терялась первая строчка файла, если он был в формате `CSVWithNames` или `TSVWIthNames`. [#4297](https://github.com/yandex/ClickHouse/pull/4297) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено падение при перезагрузке внешнего словаря, если словарь недоступен. Ошибка возникла в 19.1.6. [#4188](https://github.com/yandex/ClickHouse/pull/4188) ([proller](https://github.com/proller)) -* Исправлен неверный результат `ALL JOIN`, если в правой таблице присутствуют дубликаты ключа join. [#4184](https://github.com/yandex/ClickHouse/pull/4184) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено падение сервера при включённой опции `use_uncompressed_cache`, а также исключение о неправильном размере разжатых данных. [#4186](https://github.com/yandex/ClickHouse/pull/4186) ([alesapin](https://github.com/alesapin)) -* Исправлена ошибка, приводящая к неправильному результату сравнения больших (не помещающихся в Int16) дат при включённой настройке `compile_expressions`. [#4341](https://github.com/yandex/ClickHouse/pull/4341) ([alesapin](https://github.com/alesapin)) -* Исправлен бесконечный цикл при запросе из табличной функции `numbers(0)`. [#4280](https://github.com/yandex/ClickHouse/pull/4280) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Временно отключён pushdown предикатов в подзапрос, если он содержит `ORDER BY`. [#3890](https://github.com/yandex/ClickHouse/pull/3890) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлена ошибка `Illegal instruction` при использовании функций для работы с base64 на старых CPU. Ошибка проявлялась только, если ClickHouse был скомпилирован с gcc-8. [#4275](https://github.com/yandex/ClickHouse/pull/4275) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка `No message received` при запросах к PostgreSQL через ODBC-драйвер и TLS-соединение, исправлен segfault при использовании MySQL через ODBC-драйвер. [#4170](https://github.com/yandex/ClickHouse/pull/4170) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен неверный результат при использовании значений типа `Date` или `DateTime` в ветвях условного оператора (функции `if`). Функция `if` теперь работает для произвольного типа значений в ветвях. [#4243](https://github.com/yandex/ClickHouse/pull/4243) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Словари с источником из локального ClickHouse теперь исполняются локально, а не используя TCP-соединение. [#4166](https://github.com/yandex/ClickHouse/pull/4166) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено зависание запросов к таблице с движком `File` после того, как `SELECT` из этой таблицы завершился с ошибкой `No such file or directory`. [#4161](https://github.com/yandex/ClickHouse/pull/4161) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, из-за которой при запросе к таблице `system.tables` могло возникать исключение `table doesn't exist`. [#4313](https://github.com/yandex/ClickHouse/pull/4313) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, приводившая к падению `clickhouse-client` в интерактивном режиме, если успеть выйти из него во время загрузки подсказок командной строки. [#4317](https://github.com/yandex/ClickHouse/pull/4317) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, приводившая к неверным результатам исполнения мутаций, содержащих оператор `IN`. [#4099](https://github.com/yandex/ClickHouse/pull/4099) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлена ошибка, из-за которой, если была создана база данных с движком `Dictionary`, все словари загружались при старте сервера, а словари с источником из локального ClickHouse не могли загрузиться. [#4255](https://github.com/yandex/ClickHouse/pull/4255) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено повторное создание таблиц с системными логами (`system.query_log`, `system.part_log`) при остановке сервера. [#4254](https://github.com/yandex/ClickHouse/pull/4254) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен вывод типа возвращаемого значения, а также использование блокировок в функции `joinGet`. [#4153](https://github.com/yandex/ClickHouse/pull/4153) ([Amos Bird](https://github.com/amosbird)) -* Исправлено падение сервера при использовании настройки `allow_experimental_multiple_joins_emulation`. [52de2c](https://github.com/yandex/ClickHouse/commit/52de2cd927f7b5257dd67e175f0a5560a48840d0) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлено некорректное сравнение значений типа `Date` и `DateTime`. [#4237](https://github.com/yandex/ClickHouse/pull/4237) ([valexey](https://github.com/valexey)) -* Исправлена ошибка, проявлявшаяся при fuzz-тестировании с undefined behaviour-санитайзером: добавлена проверка типов параметров для семейства функций `quantile*Weighted`. [#4145](https://github.com/yandex/ClickHouse/pull/4145) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена редкая ошибка, из-за которой при удалении старых кусков данных может возникать ошибка `File not found`. [#4378](https://github.com/yandex/ClickHouse/pull/4378) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена установка пакета при отсутствующем файле /etc/clickhouse-server/config.xml. [#4343](https://github.com/yandex/ClickHouse/pull/4343) ([proller](https://github.com/proller)) - -### Улучшения сборки/тестирования/пакетирования: - -* При установке Debian-пакета символическая ссылка /etc/clickhouse-server/preprocessed теперь создаётся, учитывая пути, прописанные в конфигурационном файле. [#4205](https://github.com/yandex/ClickHouse/pull/4205) ([proller](https://github.com/proller)) -* Исправления сборки под FreeBSD. [#4225](https://github.com/yandex/ClickHouse/pull/4225) ([proller](https://github.com/proller)) -* Добавлена возможность создавать, заполнять и удалять таблицы в тестах производительности. [#4220](https://github.com/yandex/ClickHouse/pull/4220) ([alesapin](https://github.com/alesapin)) -* Добавлен скрипт для поиска дублирующихся include-директив в исходных файлах. [#4326](https://github.com/yandex/ClickHouse/pull/4326) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* В тестах производительности добавлена возможность запускать запросы по номеру. [#4264](https://github.com/yandex/ClickHouse/pull/4264) ([alesapin](https://github.com/alesapin)) -* Пакет с debug-символами добавлен в список рекомендованных для основного пакета. [#4274](https://github.com/yandex/ClickHouse/pull/4274) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Рефакторинг утилиты performance-test. Улучшено логирование и обработка сигналов. [#4171](https://github.com/yandex/ClickHouse/pull/4171) ([alesapin](https://github.com/alesapin)) -* Задокументирован анонимизированный датасет Яндекс.Метрики. [#4164](https://github.com/yandex/ClickHouse/pull/4164) ([alesapin](https://github.com/alesapin)) -* Добавлен инструмент для конвертирования кусков данных таблиц, созданных с использованием старого синтаксиса с помесячным партиционированием, в новый формат. [#4195](https://github.com/yandex/ClickHouse/pull/4195) ([Alex Zatelepin](https://github.com/ztlpn)) -* Добавлена документация для двух датасетов, загруженных в s3. [#4144](https://github.com/yandex/ClickHouse/pull/4144) ([alesapin](https://github.com/alesapin)) -* Добавлен инструмент, собирающий changelog из описаний pull request-ов. [#4169](https://github.com/yandex/ClickHouse/pull/4169) [#4173](https://github.com/yandex/ClickHouse/pull/4173) ([KochetovNicolai](https://github.com/KochetovNicolai)) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Добавлен puppet-модуль для Clickhouse. [#4182](https://github.com/yandex/ClickHouse/pull/4182) ([Maxim Fedotov](https://github.com/MaxFedotov)) -* Добавлена документация для нескольких недокументированных функций. [#4168](https://github.com/yandex/ClickHouse/pull/4168) ([Winter Zhang](https://github.com/zhang2014)) -* Исправления сборки под ARM. [#4210](https://github.com/yandex/ClickHouse/pull/4210)[#4306](https://github.com/yandex/ClickHouse/pull/4306) [#4291](https://github.com/yandex/ClickHouse/pull/4291) ([proller](https://github.com/proller)) ([proller](https://github.com/proller)) -* Добавлена возможность запускать тесты словарей из `ctest`. [#4189](https://github.com/yandex/ClickHouse/pull/4189) ([proller](https://github.com/proller)) -* Теперь директорией с SSL-сертификатами по умолчанию является `/etc/ssl`. [#4167](https://github.com/yandex/ClickHouse/pull/4167) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена проверка доступности SSE и AVX-инструкций на старте. [#4234](https://github.com/yandex/ClickHouse/pull/4234) ([Igr](https://github.com/igron99)) -* Init-скрипт теперь дожидается, пока сервер запустится. [#4281](https://github.com/yandex/ClickHouse/pull/4281) ([proller](https://github.com/proller)) - -### Обратно несовместимые изменения: - -* Удалена настройка `allow_experimental_low_cardinality_type`. Семейство типов данных `LowCardinality` готово для использования в production. [#4323](https://github.com/yandex/ClickHouse/pull/4323) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Размер кэша засечек и кэша разжатых блоков теперь уменьшается в зависимости от доступного объёма памяти. [#4240](https://github.com/yandex/ClickHouse/pull/4240) ([Lopatin Konstantin](https://github.com/k-lopatin)) -* Для запроса `CREATE TABLE` добавлено ключевое слово `INDEX`. Имя столбца `index` теперь надо оборачивать в двойные или обратные кавычки: `` `index` ``. [#4143](https://github.com/yandex/ClickHouse/pull/4143) ([Nikita Vasilev](https://github.com/nikvas0)) -* Функция `sumMap` теперь возвращает тип с большей областью значений вместо переполнения. Если необходимо старое поведение, следует использовать добавленную функцию `sumMapWithOverflow`. [#4151](https://github.com/yandex/ClickHouse/pull/4151) ([Léo Ercolanelli](https://github.com/ercolanelli-leo)) - -### Улучшения производительности: - -* Для запросов без секции `LIMIT` вместо `std::sort` теперь используется `pdqsort`. [#4236](https://github.com/yandex/ClickHouse/pull/4236) ([Evgenii Pravda](https://github.com/kvinty)) -* Теперь сервер переиспользует потоки для выполнения запросов из глобального пула потоков. В краевых случаях это влияет на производительность. [#4150](https://github.com/yandex/ClickHouse/pull/4150) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Улучшения: - -* Теперь, если в нативном протоколе послать запрос `INSERT INTO tbl VALUES (....` (с данными в запросе), отдельно посылать разобранные данные для вставки не нужно. [#4301](https://github.com/yandex/ClickHouse/pull/4301) ([alesapin](https://github.com/alesapin)) -* Добавлена поддержка AIO для FreeBSD. [#4305](https://github.com/yandex/ClickHouse/pull/4305) ([urgordeadbeef](https://github.com/urgordeadbeef)) -* Запрос `SELECT * FROM a JOIN b USING a, b` теперь возвращает столбцы `a` и `b` только из левой таблицы. [#4141](https://github.com/yandex/ClickHouse/pull/4141) ([Artem Zuikov](https://github.com/4ertus2)) -* Добавлена опция командной строки `-C` для клиента, которая работает так же, как и опция `-c`. [#4232](https://github.com/yandex/ClickHouse/pull/4232) ([syominsergey](https://github.com/syominsergey)) -* Если для опции `--password` клиента командной строки не указано значение, пароль запрашивается из стандартного входа. [#4230](https://github.com/yandex/ClickHouse/pull/4230) ([BSD_Conqueror](https://github.com/bsd-conqueror)) -* Добавлена подсветка метасимволов в строковых литералах, содержащих выражения для оператора `LIKE` и регулярные выражения. [#4327](https://github.com/yandex/ClickHouse/pull/4327) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена отмена HTTP-запроса, если сокет клиента отваливается. [#4213](https://github.com/yandex/ClickHouse/pull/4213) ([nvartolomei](https://github.com/nvartolomei)) -* Теперь сервер время от времени посылает пакеты Progress для поддержания соединения. [#4215](https://github.com/yandex/ClickHouse/pull/4215) ([Ivan](https://github.com/abyss7)) -* Немного улучшено сообщение о причине, почему запрос OPTIMIZE не может быть исполнен (если включена настройка `optimize_throw_if_noop`). [#4294](https://github.com/yandex/ClickHouse/pull/4294) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена поддержка опции `--version` для `clickhouse-server`. [#4251](https://github.com/yandex/ClickHouse/pull/4251) ([Lopatin Konstantin](https://github.com/k-lopatin)) -* Добавлена поддержка опции `--help/-h` для `clickhouse-server`. [#4233](https://github.com/yandex/ClickHouse/pull/4233) ([Yuriy Baranov](https://github.com/yurriy)) -* Добавлена поддержка скалярных подзапросов, возвращающих состояние агрегатной функции. [#4348](https://github.com/yandex/ClickHouse/pull/4348) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Уменьшено время ожидания завершения сервера и завершения запросов `ALTER`. [#4372](https://github.com/yandex/ClickHouse/pull/4372) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлена информация о значении настройки `replicated_can_become_leader` в таблицу `system.replicas`. Добавлено логирование в случае, если реплика не собирается стать лидером. [#4379](https://github.com/yandex/ClickHouse/pull/4379) ([Alex Zatelepin](https://github.com/ztlpn)) - -## ClickHouse release 19.1.14, 2019-03-14 - -* Исправлена ошибка `Column ... queried more than once`, которая могла произойти в случае включенной настройки `asterisk_left_columns_only` в случае использования `GLOBAL JOIN` а также `SELECT *` (редкий случай). Эта ошибка изначально отсутствует в версиях 19.3 и более новых. [6bac7d8d](https://github.com/yandex/ClickHouse/pull/4692/commits/6bac7d8d11a9b0d6de0b32b53c47eb2f6f8e7062) ([Artem Zuikov](https://github.com/4ertus2)) - -## ClickHouse release 19.1.13, 2019-03-12 - -Этот релиз содержит такие же исправления ошибок, как и 19.3.7. - -## ClickHouse release 19.1.10, 2019-03-03 - -Этот релиз содержит такие же исправления ошибок, как и 19.3.6. - -## ClickHouse release 19.1.9, 2019-02-21 - -### Исправления ошибок: - -* Исправлена обратная несовместимость со старыми версиями, появившаяся из-за некорректной реализации настройки `send_logs_level`. [#4445](https://github.com/yandex/ClickHouse/pull/4445) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена обратная несовместимость табличной функции `remote`, появившаяся из-за добавления комментариев колонок. [#4446](https://github.com/yandex/ClickHouse/pull/4446) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -## ClickHouse release 19.1.8, 2019-02-16 - -### Исправления ошибок: - -* Исправлена установка пакета при отсутствующем файле /etc/clickhouse-server/config.xml. [#4343](https://github.com/yandex/ClickHouse/pull/4343) ([proller](https://github.com/proller)) - -## ClickHouse release 19.1.7, 2019-02-15 - -### Исправления ошибок: - -* Исправлен вывод типа возвращаемого значения, а также использование блокировок в функции `joinGet`. [#4153](https://github.com/yandex/ClickHouse/pull/4153) ([Amos Bird](https://github.com/amosbird)) -* Исправлено повторное создание таблиц с системными логами (`system.query_log`, `system.part_log`) при остановке сервера. [#4254](https://github.com/yandex/ClickHouse/pull/4254) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, из-за которой, если была создана база данных с движком `Dictionary`, все словари загружались при старте сервера, а словари с источником из локального ClickHouse не могли загрузиться. [#4255](https://github.com/yandex/ClickHouse/pull/4255) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, приводившая к неверным результатам исполнения мутаций, содержащих оператор `IN`. [#4099](https://github.com/yandex/ClickHouse/pull/4099) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлена ошибка, приводившая к падению `clickhouse-client` в интерактивном режиме, если успеть выйти из него во время загрузки подсказок командной строки. [#4317](https://github.com/yandex/ClickHouse/pull/4317) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, из-за которой при запросе к таблице `system.tables` могло возникать исключение `table doesn't exist`. [#4313](https://github.com/yandex/ClickHouse/pull/4313) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено зависание запросов к таблице с движком `File` после того, как `SELECT` из этой таблицы завершился с ошибкой `No such file or directory`. [#4161](https://github.com/yandex/ClickHouse/pull/4161) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Словари с источником из локального ClickHouse теперь исполняются локально, а не используя TCP-соединение. [#4166](https://github.com/yandex/ClickHouse/pull/4166) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка `No message received` при запросах к PostgreSQL через ODBC-драйвер и TLS-соединение, исправлен segfault при использовании MySQL через ODBC-драйвер. [#4170](https://github.com/yandex/ClickHouse/pull/4170) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Временно отключён pushdown предикатов в подзапрос, если он содержит `ORDER BY`. [#3890](https://github.com/yandex/ClickHouse/pull/3890) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлен бесконечный цикл при запросе из табличной функции `numbers(0)`. [#4280](https://github.com/yandex/ClickHouse/pull/4280) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, приводящая к неправильному результату сравнения больших (не помещающихся в Int16) дат при включённой настройке `compile_expressions`. [#4341](https://github.com/yandex/ClickHouse/pull/4341) ([alesapin](https://github.com/alesapin)) -* Исправлено падение сервера при включённой опции `uncompressed_cache`, а также исключение о неправильном размере разжатых данных. [#4186](https://github.com/yandex/ClickHouse/pull/4186) ([alesapin](https://github.com/alesapin)) -* Исправлен неверный результат `ALL JOIN`, если в правой таблице присутствуют дубликаты ключа join. [#4184](https://github.com/yandex/ClickHouse/pull/4184) ([Artem Zuikov](https://github.com/4ertus2)) -* Исправлена ошибка, приводившая к тому, что при исполнении запроса `INSERT ... SELECT ... FROM file(...)` терялась первая строчка файла, если он был в формате `CSVWithNames` или `TSVWIthNames`. [#4297](https://github.com/yandex/ClickHouse/pull/4297) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена агрегация столбцов типа `Array(LowCardinality)`. [#4055](https://github.com/yandex/ClickHouse/pull/4055) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* При установке Debian-пакета символическая ссылка /etc/clickhouse-server/preprocessed теперь создаётся, учитывая пути, прописанные в конфигурационном файле. [#4205](https://github.com/yandex/ClickHouse/pull/4205) ([proller](https://github.com/proller)) -* Исправлена ошибка, проявлявшаяся при fuzz-тестировании с undefined behaviour-санитайзером: добавлена проверка типов параметров для семейства функций `quantile*Weighted`. [#4145](https://github.com/yandex/ClickHouse/pull/4145) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Команда `START REPLICATED SENDS` теперь действительно включает посылку кусков данных при репликации. [#4229](https://github.com/yandex/ClickHouse/pull/4229) ([nvartolomei](https://github.com/nvartolomei)) -* Исправлена ошибка `Not found column` для случая дублирующихся столбцов в секции `JOIN ON`. [#4279](https://github.com/yandex/ClickHouse/pull/4279) ([Artem Zuikov](https://github.com/4ertus2)) -* Теперь директорией с SSL-сертификатами по умолчанию является `/etc/ssl`. [#4167](https://github.com/yandex/ClickHouse/pull/4167) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено падение при перезагрузке внешнего словаря, если словарь недоступен. Ошибка возникла в 19.1.6. [#4188](https://github.com/yandex/ClickHouse/pull/4188) ([proller](https://github.com/proller)) -* Исправлено некорректное сравнение значений типа `Date` и `DateTime`. [#4237](https://github.com/yandex/ClickHouse/pull/4237) ([valexey](https://github.com/valexey)) -* Исправлен неверный результат при использовании значений типа `Date` или `DateTime` в ветвях условного оператора (функции `if`). Функция `if` теперь работает для произвольного типа значений в ветвях. [#4243](https://github.com/yandex/ClickHouse/pull/4243) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -## ClickHouse release 19.1.6, 2019-01-24 - -### Новые возможности: - -* Задание формата сжатия для отдельных столбцов. [#3899](https://github.com/yandex/ClickHouse/pull/3899) [#4111](https://github.com/yandex/ClickHouse/pull/4111) ([alesapin](https://github.com/alesapin), [Winter Zhang](https://github.com/zhang2014), [Anatoly](https://github.com/Sindbag)) -* Формат сжатия `Delta`. [#4052](https://github.com/yandex/ClickHouse/pull/4052) ([alesapin](https://github.com/alesapin)) -* Изменение формата сжатия запросом `ALTER`. [#4054](https://github.com/yandex/ClickHouse/pull/4054) ([alesapin](https://github.com/alesapin)) -* Добавлены функции `left`, `right`, `trim`, `ltrim`, `rtrim`, `timestampadd`, `timestampsub` для совместимости со стандартом SQL. [#3826](https://github.com/yandex/ClickHouse/pull/3826) ([Ivan Blinkov](https://github.com/blinkov)) -* Поддержка записи в движок `HDFS` и табличную функцию `hdfs`. [#4084](https://github.com/yandex/ClickHouse/pull/4084) ([alesapin](https://github.com/alesapin)) -* Добавлены функции поиска набора константных строк в тексте: `multiPosition`, `multiSearch` ,`firstMatch` также с суффиксами `-UTF8`, `-CaseInsensitive`, и `-CaseInsensitiveUTF8`. [#4053](https://github.com/yandex/ClickHouse/pull/4053) ([Danila Kutenin](https://github.com/danlark1)) -* Пропуск неиспользуемых шардов в случае, если запрос `SELECT` содержит фильтрацию по ключу шардирования (настройка `optimize_skip_unused_shards`). [#3851](https://github.com/yandex/ClickHouse/pull/3851) ([Gleb Kanterov](https://github.com/kanterov), [Ivan](https://github.com/abyss7)) -* Пропуск строк в случае ошибки парсинга для движка `Kafka` (настройка `kafka_skip_broken_messages`). [#4094](https://github.com/yandex/ClickHouse/pull/4094) ([Ivan](https://github.com/abyss7)) -* Поддержка применения мультиклассовых моделей `CatBoost`. Функция `modelEvaluate` возвращает кортеж в случае использования мультиклассовой модели. `libcatboostmodel.so` should be built with [#607](https://github.com/catboost/catboost/pull/607). [#3959](https://github.com/yandex/ClickHouse/pull/3959) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Добавлены функции `filesystemAvailable`, `filesystemFree`, `filesystemCapacity`. [#4097](https://github.com/yandex/ClickHouse/pull/4097) ([Boris Granveaud](https://github.com/bgranvea)) -* Добавлены функции хеширования `xxHash64` и `xxHash32`. [#3905](https://github.com/yandex/ClickHouse/pull/3905) ([filimonov](https://github.com/filimonov)) -* Добавлена функция хеширования `gccMurmurHash` (GCC flavoured Murmur hash), использующая те же hash seed, что и [gcc](https://github.com/gcc-mirror/gcc/blob/41d6b10e96a1de98e90a7c0378437c3255814b16/libstdc%2B%2B-v3/include/bits/functional_hash.h#L191) [#4000](https://github.com/yandex/ClickHouse/pull/4000) ([sundyli](https://github.com/sundy-li)) -* Добавлены функции хеширования `javaHash`, `hiveHash`. [#3811](https://github.com/yandex/ClickHouse/pull/3811) ([shangshujie365](https://github.com/shangshujie365)) -* Добавлена функция `remoteSecure`. Функция работает аналогично `remote`, но использует безопасное соединение. [#4088](https://github.com/yandex/ClickHouse/pull/4088) ([proller](https://github.com/proller)) - - -### Экспериментальные возможности: - -* Эмуляция запросов с несколькими секциями `JOIN` (настройка `allow_experimental_multiple_joins_emulation`). [#3946](https://github.com/yandex/ClickHouse/pull/3946) ([Artem Zuikov](https://github.com/4ertus2)) - -### Исправления ошибок: - -* Ограничен размер кеша скомпилированных выражений в случае, если не указана настройка `compiled_expression_cache_size` для экономии потребляемой памяти. [#4041](https://github.com/yandex/ClickHouse/pull/4041) ([alesapin](https://github.com/alesapin)) -* Исправлена проблема зависания потоков, выполняющих запрос `ALTER` для таблиц семейства `Replicated`, а также потоков, обновляющих конфигурацию из ZooKeeper. [#2947](https://github.com/yandex/ClickHouse/issues/2947) [#3891](https://github.com/yandex/ClickHouse/issues/3891) [#3934](https://github.com/yandex/ClickHouse/pull/3934) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлен race condition в случае выполнения распределенной задачи запроса `ALTER`. Race condition приводил к состоянию, когда более чем одна реплика пыталась выполнить задачу, в результате чего все такие реплики, кроме одной, падали с ошибкой обращения к ZooKeeper. [#3904](https://github.com/yandex/ClickHouse/pull/3904) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлена проблема обновления настройки `from_zk`. Настройка, указанная в файле конфигурации, не обновлялась в случае, если запрос к ZooKeeper падал по timeout. [#2947](https://github.com/yandex/ClickHouse/issues/2947) [#3947](https://github.com/yandex/ClickHouse/pull/3947) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлена ошибка в вычислении сетевого префикса при указании IPv4 маски подсети. [#3945](https://github.com/yandex/ClickHouse/pull/3945) ([alesapin](https://github.com/alesapin)) -* Исправлено падение (`std::terminate`) в редком сценарии, когда новый поток не мог быть создан из-за нехватки ресурсов. [#3956](https://github.com/yandex/ClickHouse/pull/3956) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено падение табличной функции `remote` в случае, когда не удавалось получить структуру таблицы из-за ограничений пользователя. [#4009](https://github.com/yandex/ClickHouse/pull/4009) ([alesapin](https://github.com/alesapin)) -* Исправлена утечка сетевых сокетов. Сокеты создавались в пуле и никогда не закрывались. При создании потока, создавались новые сокеты в случае, если все доступные использовались. [#4017](https://github.com/yandex/ClickHouse/pull/4017) ([Alex Zatelepin](https://github.com/ztlpn)) -* Исправлена проблема закрывания `/proc/self/fd` раньше, чем все файловые дескрипторы были прочитаны из `/proc` после создания процесса `odbc-bridge`. [#4120](https://github.com/yandex/ClickHouse/pull/4120) ([alesapin](https://github.com/alesapin)) -* Исправлен баг в монотонном преобразовании String в UInt в случае использования String в первичном ключе. [#3870](https://github.com/yandex/ClickHouse/pull/3870) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлен баг в вычислении монотонности функции преобразования типа целых значений. [#3921](https://github.com/yandex/ClickHouse/pull/3921) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлено падение в функциях `arrayEnumerateUniq`, `arrayEnumerateDense` при передаче невалидных аргументов. [#3909](https://github.com/yandex/ClickHouse/pull/3909) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен undefined behavior в StorageMerge. [#3910](https://github.com/yandex/ClickHouse/pull/3910) ([Amos Bird](https://github.com/amosbird)) -* Исправлено падение в функциях `addDays`, `subtractDays`. [#3913](https://github.com/yandex/ClickHouse/pull/3913) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена проблема, в результате которой функции `round`, `floor`, `trunc`, `ceil` могли возвращать неверный результат для отрицательных целочисленных аргументов с большим значением. [#3914](https://github.com/yandex/ClickHouse/pull/3914) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена проблема, в результате которой 'kill query sync' приводил к падению сервера. [#3916](https://github.com/yandex/ClickHouse/pull/3916) ([muVulDeePecker](https://github.com/fancyqlx)) -* Исправлен баг, приводящий к большой задержке в случае пустой очереди репликации. [#3928](https://github.com/yandex/ClickHouse/pull/3928) [#3932](https://github.com/yandex/ClickHouse/pull/3932) ([alesapin](https://github.com/alesapin)) -* Исправлено избыточное использование памяти в случае вставки в таблицу с `LowCardinality` в первичном ключе. [#3955](https://github.com/yandex/ClickHouse/pull/3955) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Исправлена сериализация пустых массивов типа `LowCardinality` для формата `Native`. [#3907](https://github.com/yandex/ClickHouse/issues/3907) [#4011](https://github.com/yandex/ClickHouse/pull/4011) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Исправлен неверный результат в случае использования distinct для числового столбца `LowCardinality`. [#3895](https://github.com/yandex/ClickHouse/issues/3895) [#4012](https://github.com/yandex/ClickHouse/pull/4012) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Исправлена компиляция вычисления агрегатных функций для ключа `LowCardinality` (для случая, когда включена настройка `compile`). [#3886](https://github.com/yandex/ClickHouse/pull/3886) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Исправлена передача пользователя и пароля для запросов с реплик. [#3957](https://github.com/yandex/ClickHouse/pull/3957) ([alesapin](https://github.com/alesapin)) ([小路](https://github.com/nicelulu)) -* Исправлен очень редкий race condition возникающий при перечислении таблиц из базы данных типа `Dictionary` во время перезагрузки словарей. [#3970](https://github.com/yandex/ClickHouse/pull/3970) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлен неверный результат в случае использования HAVING с ROLLUP или CUBE. [#3756](https://github.com/yandex/ClickHouse/issues/3756) [#3837](https://github.com/yandex/ClickHouse/pull/3837) ([Sam Chou](https://github.com/reflection)) -* Исправлена проблема с алиасами столбцов для запросов с `JOIN ON` над распределенными таблицами. [#3980](https://github.com/yandex/ClickHouse/pull/3980) ([Winter Zhang](https://github.com/zhang2014)) -* Исправлена ошибка в реализации функции `quantileTDigest` (нашел Artem Vakhrushev). Эта ошибка никогда не происходит в ClickHouse и актуальна только для тех, кто использует кодовую базу ClickHouse напрямую в качестве библиотеки. [#3935](https://github.com/yandex/ClickHouse/pull/3935) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Улучшения: - -* Добавлена поддержка `IF NOT EXISTS` в выражении `ALTER TABLE ADD COLUMN`, `IF EXISTS` в выражении `DROP/MODIFY/CLEAR/COMMENT COLUMN`. [#3900](https://github.com/yandex/ClickHouse/pull/3900) ([Boris Granveaud](https://github.com/bgranvea)) -* Функция `parseDateTimeBestEffort` теперь поддерживает форматы `DD.MM.YYYY`, `DD.MM.YY`, `DD-MM-YYYY`, `DD-Mon-YYYY`, `DD/Month/YYYY` и аналогичные. [#3922](https://github.com/yandex/ClickHouse/pull/3922) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* `CapnProtoInputStream` теперь поддерживает jagged структуры. [#4063](https://github.com/yandex/ClickHouse/pull/4063) ([Odin Hultgren Van Der Horst](https://github.com/Miniwoffer)) -* Улучшение usability: добавлена проверка, что сервер запущен от пользователя, совпадающего с владельцем директории данных. Запрещен запуск от пользователя root в случае, если root не владеет директорией с данными. [#3785](https://github.com/yandex/ClickHouse/pull/3785) ([sergey-v-galtsev](https://github.com/sergey-v-galtsev)) -* Улучшена логика проверки столбцов, необходимых для JOIN, на стадии анализа запроса. [#3930](https://github.com/yandex/ClickHouse/pull/3930) ([Artem Zuikov](https://github.com/4ertus2)) -* Уменьшено число поддерживаемых соединений в случае большого числа распределенных таблиц. [#3726](https://github.com/yandex/ClickHouse/pull/3726) ([Winter Zhang](https://github.com/zhang2014)) -* Добавлена поддержка строки с totals для запроса с `WITH TOTALS` через ODBC драйвер. [#3836](https://github.com/yandex/ClickHouse/pull/3836) ([Maksim Koritckiy](https://github.com/nightweb)) -* Поддержано использование `Enum` в качестве чисел в функции `if`. [#3875](https://github.com/yandex/ClickHouse/pull/3875) ([Ivan](https://github.com/abyss7)) -* Добавлена настройка `low_cardinality_allow_in_native_format`. Если она выключена, то тип `LowCadrinality` не используется в формате `Native`. [#3879](https://github.com/yandex/ClickHouse/pull/3879) ([KochetovNicolai](https://github.com/KochetovNicolai)) -* Удалены некоторые избыточные объекты из кеша скомпилированных выражений для уменьшения потребления памяти. [#4042](https://github.com/yandex/ClickHouse/pull/4042) ([alesapin](https://github.com/alesapin)) -* Добавлена проверка того, что в запрос `SET send_logs_level = 'value'` передается верное значение. [#3873](https://github.com/yandex/ClickHouse/pull/3873) ([Sabyanin Maxim](https://github.com/s-mx)) -* Добавлена проверка типов для функций преобразования типов. [#3896](https://github.com/yandex/ClickHouse/pull/3896) ([Winter Zhang](https://github.com/zhang2014)) - -### Улучшения производительности: - -* Добавлена настройка `use_minimalistic_part_header_in_zookeeper` для движка MergeTree. Если настройка включена, Replicated таблицы будут хранить метаданные куска в компактном виде (в соответствующем znode для этого куска). Это может значительно уменьшить размер для ZooKeeper snapshot (особенно для таблиц с большим числом столбцов). После включения данной настройки будет невозможно сделать откат к версии, которая эту настройку не поддерживает. [#3960](https://github.com/yandex/ClickHouse/pull/3960) ([Alex Zatelepin](https://github.com/ztlpn)) -* Добавлена реализация функций `sequenceMatch` и `sequenceCount` на основе конечного автомата в случае, если последовательность событий не содержит условия на время. [#4004](https://github.com/yandex/ClickHouse/pull/4004) ([Léo Ercolanelli](https://github.com/ercolanelli-leo)) -* Улучшена производительность сериализации целых чисел. [#3968](https://github.com/yandex/ClickHouse/pull/3968) ([Amos Bird](https://github.com/amosbird)) -* Добавлен zero left padding для PODArray. Теперь элемент с индексом -1 является валидным нулевым значением. Эта особенность используется для удаления условного выражения при вычислении оффсетов массивов. [#3920](https://github.com/yandex/ClickHouse/pull/3920) ([Amos Bird](https://github.com/amosbird)) -* Откат версии `jemalloc`, приводящей к деградации производительности. [#4018](https://github.com/yandex/ClickHouse/pull/4018) ([alexey-milovidov](https://github.com/alexey-milovidov)) - -### Обратно несовместимые изменения: - -* Удалена недокументированная возможность `ALTER MODIFY PRIMARY KEY`, замененная выражением `ALTER MODIFY ORDER BY`. [#3887](https://github.com/yandex/ClickHouse/pull/3887) ([Alex Zatelepin](https://github.com/ztlpn)) -* Удалена функция `shardByHash`. [#3833](https://github.com/yandex/ClickHouse/pull/3833) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Запрещено использование скалярных подзапросов с результатом, имеющим тип `AggregateFunction`. [#3865](https://github.com/yandex/ClickHouse/pull/3865) ([Ivan](https://github.com/abyss7)) - -### Улучшения сборки/тестирования/пакетирования: - -* Добавлена поддержка сборки под PowerPC (`ppc64le`). [#4132](https://github.com/yandex/ClickHouse/pull/4132) ([Danila Kutenin](https://github.com/danlark1)) -* Функциональные stateful тесты запускаются на публично доступных данных. [#3969](https://github.com/yandex/ClickHouse/pull/3969) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлена ошибка, при которой сервер не мог запуститься с сообщением `bash: /usr/bin/clickhouse-extract-from-config: Operation not permitted` при использовании Docker или systemd-nspawn. [#4136](https://github.com/yandex/ClickHouse/pull/4136) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Обновлена библиотека `rdkafka` до версии v1.0.0-RC5. Использована cppkafka на замену интерфейса языка C. [#4025](https://github.com/yandex/ClickHouse/pull/4025) ([Ivan](https://github.com/abyss7)) -* Обновлена библиотека `mariadb-client`. Исправлена проблема, обнаруженная с использованием UBSan. [#3924](https://github.com/yandex/ClickHouse/pull/3924) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправления для сборок с UBSan. [#3926](https://github.com/yandex/ClickHouse/pull/3926) [#3021](https://github.com/yandex/ClickHouse/pull/3021) [#3948](https://github.com/yandex/ClickHouse/pull/3948) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлены покоммитные запуски тестов с UBSan сборкой. -* Добавлены покоммитные запуски тестов со статическим анализатором PVS-Studio. -* Исправлены проблемы, найденные с использованием PVS-Studio. [#4013](https://github.com/yandex/ClickHouse/pull/4013) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправлены проблемы совместимости glibc. [#4100](https://github.com/yandex/ClickHouse/pull/4100) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Docker образы перемещены на Ubuntu 18.10, добавлена совместимость с glibc >= 2.28 [#3965](https://github.com/yandex/ClickHouse/pull/3965) ([alesapin](https://github.com/alesapin)) -* Добавлена переменная окружения `CLICKHOUSE_DO_NOT_CHOWN`, позволяющая не делать shown директории для Docker образа сервера. [#3967](https://github.com/yandex/ClickHouse/pull/3967) ([alesapin](https://github.com/alesapin)) -* Включены большинство предупреждений из `-Weverything` для clang. Включено `-Wpedantic`. [#3986](https://github.com/yandex/ClickHouse/pull/3986) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Добавлены некоторые предупреждения, специфичные только для clang 8. [#3993](https://github.com/yandex/ClickHouse/pull/3993) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* При использовании динамической линковки используется `libLLVM` вместо библиотеки `LLVM`. [#3989](https://github.com/yandex/ClickHouse/pull/3989) ([Orivej Desh](https://github.com/orivej)) -* Добавлены переменные окружения для параметров `TSan`, `UBSan`, `ASan` в тестовом Docker образе. [#4072](https://github.com/yandex/ClickHouse/pull/4072) ([alesapin](https://github.com/alesapin)) -* Debian пакет `clickhouse-server` будет рекомендовать пакет `libcap2-bin` для того, чтобы использовать утилиту `setcap` для настроек. Данный пакет опционален. [#4093](https://github.com/yandex/ClickHouse/pull/4093) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Уменьшено время сборки, убраны ненужные включения заголовочных файлов. [#3898](https://github.com/yandex/ClickHouse/pull/3898) ([proller](https://github.com/proller)) -* Добавлены тесты производительности для функций хеширования. [#3918](https://github.com/yandex/ClickHouse/pull/3918) ([filimonov](https://github.com/filimonov)) -* Исправлены циклические зависимости библиотек. [#3958](https://github.com/yandex/ClickHouse/pull/3958) ([proller](https://github.com/proller)) -* Улучшена компиляция при малом объеме памяти. [#4030](https://github.com/yandex/ClickHouse/pull/4030) ([proller](https://github.com/proller)) -* Добавлен тестовый скрипт для воспроизведения деградации производительности в `jemalloc`. [#4036](https://github.com/yandex/ClickHouse/pull/4036) ([alexey-milovidov](https://github.com/alexey-milovidov)) -* Исправления опечаток в комментариях и строковых литералах. [#4122](https://github.com/yandex/ClickHouse/pull/4122) ([maiha](https://github.com/maiha)) -* Исправления опечаток в комментариях. [#4089](https://github.com/yandex/ClickHouse/pull/4089) ([Evgenii Pravda](https://github.com/kvinty)) - -## ClickHouse release 18.16.1, 2018-12-21 - -### Исправления ошибок: - -* Исправлена проблема, приводившая к невозможности обновить словари с источником ODBC. [#3825](https://github.com/yandex/ClickHouse/issues/3825), [#3829](https://github.com/yandex/ClickHouse/issues/3829) -* JIT-компиляция агрегатных функций теперь работает с LowCardinality столбцами. [#3838](https://github.com/yandex/ClickHouse/issues/3838) - -### Улучшения: - -* Добавлена настройка `low_cardinality_allow_in_native_format` (по умолчанию включена). Если её выключить, столбцы LowCardinality в Native формате будут преобразовываться в соответствующий обычный тип при SELECT и из этого типа при INSERT. [#3879](https://github.com/yandex/ClickHouse/pull/3879) - -### Улучшения сборки: -* Исправления сборки под macOS и ARM. - -## ClickHouse release 18.16.0, 2018-12-14 - -### Новые возможности: - -* Вычисление `DEFAULT` выражений для отсутствующих полей при загрузке данных в полуструктурированных форматах (`JSONEachRow`, `TSKV`) (требуется включить настройку запроса `insert_sample_with_metadata`). [#3555](https://github.com/yandex/ClickHouse/pull/3555) -* Для запроса `ALTER TABLE` добавлено действие `MODIFY ORDER BY` для изменения ключа сортировки при одновременном добавлении или удалении столбца таблицы. Это полезно для таблиц семейства `MergeTree`, выполняющих дополнительную работу при слияниях, согласно этому ключу сортировки, как например, `SummingMergeTree`, `AggregatingMergeTree` и т. п. [#3581](https://github.com/yandex/ClickHouse/pull/3581) [#3755](https://github.com/yandex/ClickHouse/pull/3755) -* Для таблиц семейства `MergeTree` появилась возможность указать различный ключ сортировки (`ORDER BY`) и индекс (`PRIMARY KEY`). Ключ сортировки может быть длиннее, чем индекс. [#3581](https://github.com/yandex/ClickHouse/pull/3581) -* Добавлена табличная функция `hdfs` и движок таблиц `HDFS` для импорта и экспорта данных в HDFS. [chenxing-xc](https://github.com/yandex/ClickHouse/pull/3617) -* Добавлены функции для работы с base64: `base64Encode`, `base64Decode`, `tryBase64Decode`. [Alexander Krasheninnikov](https://github.com/yandex/ClickHouse/pull/3350) -* Для агрегатной функции `uniqCombined` появилась возможность настраивать точность работы с помощью параметра (выбирать количество ячеек HyperLogLog). [#3406](https://github.com/yandex/ClickHouse/pull/3406) -* Добавлена таблица `system.contributors`, содержащая имена всех, кто делал коммиты в ClickHouse. [#3452](https://github.com/yandex/ClickHouse/pull/3452) -* Добавлена возможность не указывать партицию для запроса `ALTER TABLE ... FREEZE` для бэкапа сразу всех партиций. [#3514](https://github.com/yandex/ClickHouse/pull/3514) -* Добавлены функции `dictGet`, `dictGetOrDefault` без указания типа возвращаемого значения. Тип определяется автоматически из описания словаря. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3564) -* Возможность указания комментария для столбца в описании таблицы и изменения его с помощью `ALTER`. [#3377](https://github.com/yandex/ClickHouse/pull/3377) -* Возможность чтения из таблицы типа `Join` в случае простых ключей. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3728) -* Возможность указания настроек `join_use_nulls`, `max_rows_in_join`, `max_bytes_in_join`, `join_overflow_mode` при создании таблицы типа `Join`. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3728) -* Добавлена функция `joinGet`, позволяющая использовать таблицы типа `Join` как словарь. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3728) -* Добавлены столбцы `partition_key`, `sorting_key`, `primary_key`, `sampling_key` в таблицу `system.tables`, позволяющие получить информацию о ключах таблицы. [#3609](https://github.com/yandex/ClickHouse/pull/3609) -* Добавлены столбцы `is_in_partition_key`, `is_in_sorting_key`, `is_in_primary_key`, `is_in_sampling_key` в таблицу `system.columns`. [#3609](https://github.com/yandex/ClickHouse/pull/3609) -* Добавлены столбцы `min_time`, `max_time` в таблицу `system.parts`. Эти столбцы заполняются, если ключ партиционирования является выражением от столбцов типа `DateTime`. [Emmanuel Donin de Rosière](https://github.com/yandex/ClickHouse/pull/3800) - -### Исправления ошибок: - -* Исправления и улучшения производительности для типа данных `LowCardinality`. `GROUP BY` по `LowCardinality(Nullable(...))`. Получение `extremes` значений. Выполнение функций высшего порядка. `LEFT ARRAY JOIN`. Распределённый `GROUP BY`. Функции, возвращающие `Array`. Выполнение `ORDER BY`. Запись в `Distributed` таблицы (nicelulu). Обратная совместимость для запросов `INSERT` от старых клиентов, реализующих `Native` протокол. Поддержка `LowCardinality` для `JOIN`. Производительность при работе в один поток. [#3823](https://github.com/yandex/ClickHouse/pull/3823) [#3803](https://github.com/yandex/ClickHouse/pull/3803) [#3799](https://github.com/yandex/ClickHouse/pull/3799) [#3769](https://github.com/yandex/ClickHouse/pull/3769) [#3744](https://github.com/yandex/ClickHouse/pull/3744) [#3681](https://github.com/yandex/ClickHouse/pull/3681) [#3651](https://github.com/yandex/ClickHouse/pull/3651) [#3649](https://github.com/yandex/ClickHouse/pull/3649) [#3641](https://github.com/yandex/ClickHouse/pull/3641) [#3632](https://github.com/yandex/ClickHouse/pull/3632) [#3568](https://github.com/yandex/ClickHouse/pull/3568) [#3523](https://github.com/yandex/ClickHouse/pull/3523) [#3518](https://github.com/yandex/ClickHouse/pull/3518) -* Исправлена работа настройки `select_sequential_consistency`. Ранее, при включенной настройке, после начала записи в новую партицию, мог возвращаться неполный результат. [#2863](https://github.com/yandex/ClickHouse/pull/2863) -* Корректное указание базы данных при выполнении DDL запросов `ON CLUSTER`, а также при выполнении `ALTER UPDATE/DELETE`. [#3772](https://github.com/yandex/ClickHouse/pull/3772) [#3460](https://github.com/yandex/ClickHouse/pull/3460) -* Корректное указание базы данных для подзапросов внутри VIEW. [#3521](https://github.com/yandex/ClickHouse/pull/3521) -* Исправлена работа `PREWHERE` с `FINAL` для `VersionedCollapsingMergeTree`. [7167bfd7](https://github.com/yandex/ClickHouse/commit/7167bfd7b365538f7a91c4307ad77e552ab4e8c1) -* Возможность с помощью запроса `KILL QUERY` отмены запросов, которые ещё не начали выполняться из-за ожидания блокировки таблицы. [#3517](https://github.com/yandex/ClickHouse/pull/3517) -* Исправлены расчёты с датой и временем в случае, если стрелки часов были переведены назад в полночь (это происходит в Иране, а также было Москве с 1981 по 1983 год). Ранее это приводило к тому, что стрелки часов переводились на сутки раньше, чем нужно, а также приводило к некорректному форматированию даты-с-временем в текстовом виде. [#3819](https://github.com/yandex/ClickHouse/pull/3819) -* Исправлена работа некоторых случаев `VIEW` и подзапросов без указания базы данных. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3521) -* Исправлен race condition при одновременном чтении из `MATERIALIZED VIEW` и удалением `MATERIALIZED VIEW` из-за отсутствия блокировки внутренней таблицы `MATERIALIZED VIEW`. [#3404](https://github.com/yandex/ClickHouse/pull/3404) [#3694](https://github.com/yandex/ClickHouse/pull/3694) -* Исправлена ошибка `Lock handler cannot be nullptr.` [#3689](https://github.com/yandex/ClickHouse/pull/3689) -* Исправления выполнения запросов при включенной настройке `compile_expressions` (включена по-умолчанию) - убрана свёртка недетерминированных константных выражений, как например, функции `now`. [#3457](https://github.com/yandex/ClickHouse/pull/3457) -* Исправлено падение при указании неконстантного аргумента scale в функциях `toDecimal32/64/128`. -* Исправлена ошибка при попытке вставки в формате `Values` массива с `NULL` элементами в столбец типа `Array` без `Nullable` (в случае `input_format_values_interpret_expressions` = 1). [#3487](https://github.com/yandex/ClickHouse/pull/3487) [#3503](https://github.com/yandex/ClickHouse/pull/3503) -* Исправлено непрерывное логгирование ошибок в `DDLWorker`, если ZooKeeper недоступен. [8f50c620](https://github.com/yandex/ClickHouse/commit/8f50c620334988b28018213ec0092fe6423847e2) -* Исправлен тип возвращаемого значения для функций `quantile*` от аргументов типа `Date` и `DateTime`. [#3580](https://github.com/yandex/ClickHouse/pull/3580) -* Исправлена работа секции `WITH`, если она задаёт простой алиас без выражений. [#3570](https://github.com/yandex/ClickHouse/pull/3570) -* Исправлена обработка запросов с именованными подзапросами и квалифицированными именами столбцов при включенной настройке `enable_optimize_predicate_expression`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3588) -* Исправлена ошибка `Attempt to attach to nullptr thread group` при работе материализованных представлений. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3623) -* Исправлено падение при передаче некоторых некорректных аргументов в функцию `arrayReverse`. [73e3a7b6](https://github.com/yandex/ClickHouse/commit/73e3a7b662161d6005e7727d8a711b930386b871) -* Исправлен buffer overflow в функции `extractURLParameter`. Увеличена производительность. Добавлена корректная обработка строк, содержащих нулевые байты. [141e9799](https://github.com/yandex/ClickHouse/commit/141e9799e49201d84ea8e951d1bed4fb6d3dacb5) -* Исправлен buffer overflow в функциях `lowerUTF8`, `upperUTF8`. Удалена возможность выполнения этих функций над аргументами типа `FixedString`. [#3662](https://github.com/yandex/ClickHouse/pull/3662) -* Исправлен редкий race condition при удалении таблиц типа `MergeTree`. [#3680](https://github.com/yandex/ClickHouse/pull/3680) -* Исправлен race condition при чтении из таблиц типа `Buffer` и одновременном `ALTER` либо `DROP` таблиц назначения. [#3719](https://github.com/yandex/ClickHouse/pull/3719) -* Исправлен segfault в случае превышения ограничения `max_temporary_non_const_columns`. [#3788](https://github.com/yandex/ClickHouse/pull/3788) - -### Улучшения: - -* Обработанные конфигурационные файлы записываются сервером не в `/etc/clickhouse-server/` директорию, а в директорию `preprocessed_configs` внутри `path`. Это позволяет оставить директорию `/etc/clickhouse-server/` недоступной для записи пользователем `clickhouse`, что повышает безопасность. [#2443](https://github.com/yandex/ClickHouse/pull/2443) -* Настройка `min_merge_bytes_to_use_direct_io` выставлена по-умолчанию в 10 GiB. Слияния, образующие крупные куски таблиц семейства MergeTree, будут производиться в режиме `O_DIRECT`, что исключает вымывание кэша. [#3504](https://github.com/yandex/ClickHouse/pull/3504) -* Ускорен запуск сервера в случае наличия очень большого количества таблиц. [#3398](https://github.com/yandex/ClickHouse/pull/3398) -* Добавлен пул соединений и HTTP `Keep-Alive` для соединения между репликами. [#3594](https://github.com/yandex/ClickHouse/pull/3594) -* В случае ошибки синтаксиса запроса, в `HTTP` интерфейсе возвращается код `400 Bad Request` (ранее возвращался код 500). [31bc680a](https://github.com/yandex/ClickHouse/commit/31bc680ac5f4bb1d0360a8ba4696fa84bb47d6ab) -* Для настройки `join_default_strictness` выбрано значение по-умолчанию `ALL` для совместимости. [120e2cbe](https://github.com/yandex/ClickHouse/commit/120e2cbe2ff4fbad626c28042d9b28781c805afe) -* Убрано логгирование в `stderr` из библиотеки `re2` в случае некорректных или сложных регулярных выражений. [#3723](https://github.com/yandex/ClickHouse/pull/3723) -* Для движка таблиц `Kafka`: проверка наличия подписок перед началом чтения из Kafka; настройка таблицы kafka_max_block_size. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3396) -* Функции `cityHash64`, `farmHash64`, `metroHash64`, `sipHash64`, `halfMD5`, `murmurHash2_32`, `murmurHash2_64`, `murmurHash3_32`, `murmurHash3_64` теперь работают для произвольного количества аргументов, а также для аргументов-кортежей. [#3451](https://github.com/yandex/ClickHouse/pull/3451) [#3519](https://github.com/yandex/ClickHouse/pull/3519) -* Функция `arrayReverse` теперь работает с любыми типами массивов. [73e3a7b6](https://github.com/yandex/ClickHouse/commit/73e3a7b662161d6005e7727d8a711b930386b871) -* Добавлен опциональный параметр - размер слота для функции `timeSlots`. [Kirill Shvakov](https://github.com/yandex/ClickHouse/pull/3724) -* Для `FULL` и `RIGHT JOIN` учитывается настройка `max_block_size` для потока неприсоединённых данных из правой таблицы. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3699) -* В `clickhouse-benchmark` и `clickhouse-performance-test` добавлен параметр командной строки `--secure` для включения TLS. [#3688](https://github.com/yandex/ClickHouse/pull/3688) [#3690](https://github.com/yandex/ClickHouse/pull/3690) -* Преобразование типов в случае, если структура таблицы типа `Buffer` не соответствует структуре таблицы назначения. [Vitaly Baranov](https://github.com/yandex/ClickHouse/pull/3603) -* Добавлена настройка `tcp_keep_alive_timeout` для включения keep-alive пакетов после неактивности в течение указанного интервала времени. [#3441](https://github.com/yandex/ClickHouse/pull/3441) -* Убрано излишнее квотирование значений ключа партиции в таблице `system.parts`, если он состоит из одного столбца. [#3652](https://github.com/yandex/ClickHouse/pull/3652) -* Функция деления с остатком работает для типов данных `Date` и `DateTime`. [#3385](https://github.com/yandex/ClickHouse/pull/3385) -* Добавлены синонимы функций `POWER`, `LN`, `LCASE`, `UCASE`, `REPLACE`, `LOCATE`, `SUBSTR`, `MID`. [#3774](https://github.com/yandex/ClickHouse/pull/3774) [#3763](https://github.com/yandex/ClickHouse/pull/3763) Некоторые имена функций сделаны регистронезависимыми для совместимости со стандартом SQL. Добавлен синтаксический сахар `SUBSTRING(expr FROM start FOR length)` для совместимости с SQL. [#3804](https://github.com/yandex/ClickHouse/pull/3804) -* Добавлена возможность фиксации (`mlock`) страниц памяти, соответствующих исполняемому коду `clickhouse-server` для предотвращения вытеснения их из памяти. Возможность выключена по-умолчанию. [#3553](https://github.com/yandex/ClickHouse/pull/3553) -* Увеличена производительность чтения с `O_DIRECT` (с включенной опцией `min_bytes_to_use_direct_io`). [#3405](https://github.com/yandex/ClickHouse/pull/3405) -* Улучшена производительность работы функции `dictGet...OrDefault` в случае константного аргумента-ключа и неконстантного аргумента-default. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3563) -* В функции `firstSignificantSubdomain` добавлена обработка доменов `gov`, `mil`, `edu`. [Igor Hatarist](https://github.com/yandex/ClickHouse/pull/3601) Увеличена производительность работы. [#3628](https://github.com/yandex/ClickHouse/pull/3628) -* Возможность указания произвольных переменных окружения для запуска `clickhouse-server` посредством `SYS-V init.d`-скрипта с помощью указания `CLICKHOUSE_PROGRAM_ENV` в `/etc/default/clickhouse`. -[Pavlo Bashynskyi](https://github.com/yandex/ClickHouse/pull/3612) -* Правильный код возврата init-скрипта clickhouse-server. [#3516](https://github.com/yandex/ClickHouse/pull/3516) -* В таблицу `system.metrics` добавлена метрика `VersionInteger`, а в `system.build_options` добавлена строчка `VERSION_INTEGER`, содержащая версию ClickHouse в числовом представлении, вида `18016000`. [#3644](https://github.com/yandex/ClickHouse/pull/3644) -* Удалена возможность сравнения типа `Date` с числом, чтобы избежать потенциальных ошибок вида `date = 2018-12-17`, где ошибочно не указаны кавычки вокруг даты. [#3687](https://github.com/yandex/ClickHouse/pull/3687) -* Исправлено поведение функций с состоянием типа `rowNumberInAllBlocks` - раньше они выдавали число на единицу больше вследствие их запуска во время анализа запроса. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3729) -* При невозможности удалить файл `force_restore_data`, выводится сообщение об ошибке. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3794) - -### Улучшение сборки: - -* Обновлена библиотека `jemalloc`, что исправляет потенциальную утечку памяти. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3557) -* Для debug сборок включено по-умолчанию профилирование `jemalloc`. [2cc82f5c](https://github.com/yandex/ClickHouse/commit/2cc82f5cbe266421cd4c1165286c2c47e5ffcb15) -* Добавлена возможность запуска интеграционных тестов, при наличии установленным в системе лишь `Docker`. [#3650](https://github.com/yandex/ClickHouse/pull/3650) -* Добавлен fuzz тест выражений в SELECT запросах. [#3442](https://github.com/yandex/ClickHouse/pull/3442) -* Добавлен покоммитный стресс-тест, выполняющий функциональные тесты параллельно и в произвольном порядке, позволяющий обнаружить больше race conditions. [#3438](https://github.com/yandex/ClickHouse/pull/3438) -* Улучшение способа запуска clickhouse-server в Docker образе. [Elghazal Ahmed](https://github.com/yandex/ClickHouse/pull/3663) -* Для Docker образа добавлена поддержка инициализации базы данных с помощью файлов в директории `/docker-entrypoint-initdb.d`. [Konstantin Lebedev](https://github.com/yandex/ClickHouse/pull/3695) -* Исправления для сборки под ARM. [#3709](https://github.com/yandex/ClickHouse/pull/3709) - -### Обратно несовместимые изменения: - -* Удалена возможность сравнения типа `Date` с числом, необходимо вместо `toDate('2018-12-18') = 17883`, использовать явное приведение типов `= toDate(17883)` [#3687](https://github.com/yandex/ClickHouse/pull/3687) - -## ClickHouse release 18.14.19, 2018-12-19 - -### Исправления ошибок: - -* Исправлена проблема, приводившая к невозможности обновить словари с источником ODBC. [#3825](https://github.com/yandex/ClickHouse/issues/3825), [#3829](https://github.com/yandex/ClickHouse/issues/3829) -* Исправлен segfault в случае превышения ограничения `max_temporary_non_const_columns`. [#3788](https://github.com/yandex/ClickHouse/pull/3788) -* Корректное указание базы данных при выполнении DDL запросов `ON CLUSTER`. [#3460](https://github.com/yandex/ClickHouse/pull/3460) - -### Улучшения сборки: -* Исправления сборки под ARM. - -## ClickHouse release 18.14.18, 2018-12-04 - -### Исправления ошибок: -* Исправлена ошибка в функции `dictGet...` для словарей типа `range`, если один из аргументов константный, а другой - нет. [#3751](https://github.com/yandex/ClickHouse/pull/3751) -* Исправлена ошибка, приводящая к выводу сообщений `netlink: '...': attribute type 1 has an invalid length` в логе ядра Linux, проявляющаяся на достаточно новых ядрах Linux. [#3749](https://github.com/yandex/ClickHouse/pull/3749) -* Исправлен segfault при выполнении функции `empty` от аргумента типа `FixedString`. [Daniel, Dao Quang Minh](https://github.com/yandex/ClickHouse/pull/3703) -* Исправлена избыточная аллокация памяти при большом значении настройки `max_query_size` (кусок памяти размера `max_query_size` выделялся сразу). [#3720](https://github.com/yandex/ClickHouse/pull/3720) - -### Улучшения процесса сборки ClickHouse: -* Исправлена сборка с использованием библиотек LLVM/Clang версии 7 из пакетов ОС (эти библиотеки используются для динамической компиляции запросов). [#3582](https://github.com/yandex/ClickHouse/pull/3582) - -## ClickHouse release 18.14.17, 2018-11-30 - -### Исправления ошибок: -* Исправлена ситуация, при которой ODBC Bridge продолжал работу после завершения работы сервера ClickHouse. Теперь ODBC Bridge всегда завершает работу вместе с сервером. [#3642](https://github.com/yandex/ClickHouse/pull/3642) -* Исправлена синхронная вставка в `Distributed` таблицу в случае явного указания неполного списка столбцов или списка столбцов в измененном порядке. [#3673](https://github.com/yandex/ClickHouse/pull/3673) -* Исправлен редкий race condition, который мог привести к падению сервера при удалении MergeTree-таблиц. [#3680](https://github.com/yandex/ClickHouse/pull/3680) -* Исправлен deadlock при выполнении запроса, возникающий если создание новых потоков выполнения невозможно из-за ошибки `Resource temporarily unavailable`. [#3643](https://github.com/yandex/ClickHouse/pull/3643) -* Исправлена ошибка парсинга `ENGINE` при создании таблицы с синтаксисом `AS table` в случае, когда `AS table` указывался после `ENGINE`, что приводило к игнорированию указанного движка. [#3692](https://github.com/yandex/ClickHouse/pull/3692) - -## ClickHouse release 18.14.15, 2018-11-21 - -### Исправления ошибок: -* При чтении столбцов типа `Array(String)`, размер требуемого куска памяти оценивался слишком большим, что приводило к исключению "Memory limit exceeded" при выполнении запроса. Ошибка появилась в версии 18.12.13. [#3589](https://github.com/yandex/ClickHouse/issues/3589) - -## ClickHouse release 18.14.14, 2018-11-20 - -### Исправления ошибок: -* Исправлена работа запросов `ON CLUSTER` в случае, когда в конфигурации кластера включено шифрование (флаг ``). [#3599](https://github.com/yandex/ClickHouse/pull/3599) - -### Улучшения процесса сборки ClickHouse: -* Исправлены проблемы сборки (llvm-7 из системы, macos) [#3582](https://github.com/yandex/ClickHouse/pull/3582) - -## ClickHouse release 18.14.13, 2018-11-08 - -### Исправления ошибок: -* Исправлена ошибка `Block structure mismatch in MergingSorted stream`. [#3162](https://github.com/yandex/ClickHouse/issues/3162) -* Исправлена работа запросов `ON CLUSTER` в случае, когда в конфигурации кластера включено шифрование (флаг ``). [#3465](https://github.com/yandex/ClickHouse/pull/3465) -* Исправлена ошибка при использовании `SAMPLE`, `PREWHERE` и столбцов-алиасов. [#3543](https://github.com/yandex/ClickHouse/pull/3543) -* Исправлена редкая ошибка `unknown compression method` при использовании настройки `min_bytes_to_use_direct_io`. [3544](https://github.com/yandex/ClickHouse/pull/3544) - -### Улучшения производительности: -* Исправлена деградация производительности запросов с `GROUP BY` столбцов типа Int16, Date на процессорах AMD EPYC. [Игорь Лапко](https://github.com/yandex/ClickHouse/pull/3512) -* Исправлена деградация производительности при обработке длинных строк. [#3530](https://github.com/yandex/ClickHouse/pull/3530) - -### Улучшения процесса сборки ClickHouse: -* Доработки для упрощения сборки в Arcadia. [#3475](https://github.com/yandex/ClickHouse/pull/3475), [#3535](https://github.com/yandex/ClickHouse/pull/3535) - -## ClickHouse release 18.14.12, 2018-11-02 - -### Исправления ошибок: - -* Исправлена ошибка при join-запросе двух неименованных подзапросов. [#3505](https://github.com/yandex/ClickHouse/pull/3505) -* Исправлена генерация пустой `WHERE`-части при запросах к внешним базам. [hotid](https://github.com/yandex/ClickHouse/pull/3477) -* Исправлена ошибка использования неправильной настройки таймаута в ODBC-словарях. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3511) - -## ClickHouse release 18.14.11, 2018-10-29 - -### Исправления ошибок: - -* Исправлена ошибка `Block structure mismatch in UNION stream: different number of columns` в запросах с LIMIT. [#2156](https://github.com/yandex/ClickHouse/issues/2156) -* Исправлены ошибки при слиянии данных в таблицах, содержащих массивы внутри Nested структур. [#3397](https://github.com/yandex/ClickHouse/pull/3397) -* Исправлен неправильный результат запросов при выключенной настройке `merge_tree_uniform_read_distribution` (включена по умолчанию). [#3429](https://github.com/yandex/ClickHouse/pull/3429) -* Исправлена ошибка при вставке в Distributed таблицу в формате Native. [#3411](https://github.com/yandex/ClickHouse/issues/3411) - -## ClickHouse release 18.14.10, 2018-10-23 - -* Настройка `compile_expressions` (JIT компиляция выражений) выключена по умолчанию. [#3410](https://github.com/yandex/ClickHouse/pull/3410) -* Настройка `enable_optimize_predicate_expression` выключена по умолчанию. - -## ClickHouse release 18.14.9, 2018-10-16 - -### Новые возможности: - -* Модификатор `WITH CUBE` для `GROUP BY` (также доступен синтаксис: `GROUP BY CUBE(...)`). [#3172](https://github.com/yandex/ClickHouse/pull/3172) -* Добавлена функция `formatDateTime`. [Alexandr Krasheninnikov](https://github.com/yandex/ClickHouse/pull/2770) -* Добавлен движок таблиц `JDBC` и табличная функция `jdbc` (для работы требуется установка clickhouse-jdbc-bridge). [Alexandr Krasheninnikov](https://github.com/yandex/ClickHouse/pull/3210) -* Добавлены функции для работы с ISO номером недели: `toISOWeek`, `toISOYear`, `toStartOfISOYear`, а также `toDayOfYear`. [#3146](https://github.com/yandex/ClickHouse/pull/3146) -* Добавлена возможность использования столбцов типа `Nullable` для таблиц типа `MySQL`, `ODBC`. [#3362](https://github.com/yandex/ClickHouse/pull/3362) -* Возможность чтения вложенных структур данных как вложенных объектов в формате `JSONEachRow`. Добавлена настройка `input_format_import_nested_json`. [Veloman Yunkan](https://github.com/yandex/ClickHouse/pull/3144) -* Возможность параллельной обработки многих `MATERIALIZED VIEW` при вставке данных. Настройка `parallel_view_processing`. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3208) -* Добавлен запрос `SYSTEM FLUSH LOGS` (форсированный сброс логов в системные таблицы, такие как например, `query_log`) [#3321](https://github.com/yandex/ClickHouse/pull/3321) -* Возможность использования предопределённых макросов `database` и `table` в объявлении `Replicated` таблиц. [#3251](https://github.com/yandex/ClickHouse/pull/3251) -* Добавлена возможность чтения значения типа `Decimal` в инженерной нотации (с указанием десятичной экспоненты). [#3153](https://github.com/yandex/ClickHouse/pull/3153) - -### Экспериментальные возможности: - -* Оптимизация GROUP BY для типов данных `LowCardinality` [#3138](https://github.com/yandex/ClickHouse/pull/3138) -* Оптимизации вычисления выражений для типов данных `LowCardinality` [#3200](https://github.com/yandex/ClickHouse/pull/3200) - -### Улучшения: - -* Существенно уменьшено потребление памяти для запросов с `ORDER BY` и `LIMIT`. Настройка `max_bytes_before_remerge_sort`. [#3205](https://github.com/yandex/ClickHouse/pull/3205) -* При отсутствии указания типа `JOIN` (`LEFT`, `INNER`, ...), подразумевается `INNER JOIN`. [#3147](https://github.com/yandex/ClickHouse/pull/3147) -* Корректная работа квалифицированных звёздочек в запросах с `JOIN`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3202) -* Движок таблиц `ODBC` корректно выбирает способ квотирования идентификаторов в SQL диалекте удалённой СУБД. [Alexandr Krasheninnikov](https://github.com/yandex/ClickHouse/pull/3210) -* Настройка `compile_expressions` (JIT компиляция выражений) включена по-умолчанию. -* Исправлено поведение при одновременном DROP DATABASE/TABLE IF EXISTS и CREATE DATABASE/TABLE IF NOT EXISTS. Ранее запрос `CREATE DATABASE ... IF NOT EXISTS` мог выдавать сообщение об ошибке вида "File ... already exists", а запросы `CREATE TABLE ... IF NOT EXISTS` и `DROP TABLE IF EXISTS` могли выдавать сообщение `Table ... is creating or attaching right now`. [#3101](https://github.com/yandex/ClickHouse/pull/3101) -* Выражения LIKE и IN с константной правой частью пробрасываются на удалённый сервер при запросах из таблиц типа MySQL и ODBC. [#3182](https://github.com/yandex/ClickHouse/pull/3182) -* Сравнения с константными выражениями в секции WHERE пробрасываются на удалённый сервер при запросах из таблиц типа MySQL и ODBC. Ранее пробрасывались только сравнения с константами. [#3182](https://github.com/yandex/ClickHouse/pull/3182) -* Корректное вычисление ширины строк в терминале для `Pretty` форматов, в том числе для строк с иероглифами. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3257). -* Возможность указания `ON CLUSTER` для запросов `ALTER UPDATE`. -* Увеличена производительность чтения данных в формате `JSONEachRow`. [#3332](https://github.com/yandex/ClickHouse/pull/3332) -* Добавлены синонимы функций `LENGTH`, `CHARACTER_LENGTH` для совместимости. Функция `CONCAT` стала регистронезависимой. [#3306](https://github.com/yandex/ClickHouse/pull/3306) -* Добавлен синоним `TIMESTAMP` для типа `DateTime`. [#3390](https://github.com/yandex/ClickHouse/pull/3390) -* В логах сервера всегда присутствует место для query_id, даже если строчка лога не относится к запросу. Это сделано для более простого парсинга текстовых логов сервера сторонними инструментами. -* Логгирование потребления памяти запросом при превышении очередной отметки целого числа гигабайт. [#3205](https://github.com/yandex/ClickHouse/pull/3205) -* Добавлен режим совместимости для случая, когда клиентская библиотека, работающая по Native протоколу, по ошибке отправляет меньшее количество столбцов, чем сервер ожидает для запроса INSERT. Такой сценарий был возможен при использовании библиотеки clickhouse-cpp. Ранее этот сценарий приводил к падению сервера. [#3171](https://github.com/yandex/ClickHouse/pull/3171) -* В `clickhouse-copier`, в задаваемом пользователем выражении WHERE, появилась возможность использовать алиас `partition_key` (для дополнительной фильтрации по партициям исходной таблицы). Это полезно, если схема партиционирования изменяется при копировании, но изменяется незначительно. [#3166](https://github.com/yandex/ClickHouse/pull/3166) -* Рабочий поток движка `Kafka` перенесён в фоновый пул потоков для того, чтобы автоматически уменьшать скорость чтения данных при большой нагрузке. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3215). -* Поддержка чтения значений типа `Tuple` и `Nested` структур как `struct` в формате `Cap'n'Proto` [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3216). -* В список доменов верхнего уровня для функции `firstSignificantSubdomain` добавлен домен `biz` [decaseal](https://github.com/yandex/ClickHouse/pull/3219). -* В конфигурации внешних словарей, пустое значение `null_value` интерпретируется, как значение типа данных по-умоланию. [#3330](https://github.com/yandex/ClickHouse/pull/3330) -* Поддержка функций `intDiv`, `intDivOrZero` для `Decimal`. [b48402e8](https://github.com/yandex/ClickHouse/commit/b48402e8712e2b9b151e0eef8193811d433a1264) -* Поддержка типов `Date`, `DateTime`, `UUID`, `Decimal` в качестве ключа для агрегатной функции `sumMap`. [#3281](https://github.com/yandex/ClickHouse/pull/3281) -* Поддержка типа данных `Decimal` во внешних словарях. [#3324](https://github.com/yandex/ClickHouse/pull/3324) -* Поддержка типа данных `Decimal` в таблицах типа `SummingMergeTree`. [#3348](https://github.com/yandex/ClickHouse/pull/3348) -* Добавлена специализация для `UUID` в функции `if`. [#3366](https://github.com/yandex/ClickHouse/pull/3366) -* Уменьшено количество системных вызовов `open`, `close` при чтении из таблиц семейства `MergeTree` [#3283](https://github.com/yandex/ClickHouse/pull/3283). -* Возможность выполнения запроса `TRUNCATE TABLE` на любой реплике (запрос пробрасывается на реплику-лидера). [Kirill Shvakov](https://github.com/yandex/ClickHouse/pull/3375) - -### Исправление ошибок: - -* Исправлена ошибка в работе таблиц типа `Dictionary` для словарей типа `range_hashed`. Ошибка возникла в версии 18.12.17. [#1702](https://github.com/yandex/ClickHouse/pull/1702) -* Исправлена ошибка при загрузке словарей типа `range_hashed` (сообщение `Unsupported type Nullable(...)`). Ошибка возникла в версии 18.12.17. [#3362](https://github.com/yandex/ClickHouse/pull/3362) -* Исправлена некорректная работа функции `pointInPolygon` из-за накопления погрешности при вычислениях для полигонов с большим количеством близко расположенных вершин. [#3331](https://github.com/yandex/ClickHouse/pull/3331) [#3341](https://github.com/yandex/ClickHouse/pull/3341) -* Если после слияния кусков данных, у результирующего куска чексумма отличается от результата того же слияния на другой реплике, то результат слияния удаляется, и вместо этого кусок скачивается с другой реплики (это правильное поведение). Но после скачивания куска, он не мог добавиться в рабочий набор из-за ошибки, что кусок уже существует (так как кусок после слияния удалялся не сразу, а с задержкой). Это приводило к циклическим попыткам скачивания одних и тех же данных. [#3194](https://github.com/yandex/ClickHouse/pull/3194) -* Исправлен некорректный учёт общего потребления оперативной памяти запросами (что приводило к неправильной работе настройки `max_memory_usage_for_all_queries` и неправильному значению метрики `MemoryTracking`). Ошибка возникла в версии 18.12.13. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3344) -* Исправлена работоспособность запросов `CREATE TABLE ... ON CLUSTER ... AS SELECT ...` Ошибка возникла в версии 18.12.13. [#3247](https://github.com/yandex/ClickHouse/pull/3247) -* Исправлена лишняя подготовка структуры данных для `JOIN` на сервере-инициаторе запроса, если `JOIN` выполняется только на удалённых серверах. [#3340](https://github.com/yandex/ClickHouse/pull/3340) -* Исправлены ошибки в движке `Kafka`: неработоспособность после исключения при начале чтения данных; блокировка при завершении [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3215). -* Для таблиц `Kafka` не передавался опциональный параметр `schema` (схема формата `Cap'n'Proto`). [Vojtech Splichal](https://github.com/yandex/ClickHouse/pull/3150) -* Если ансамбль серверов ZooKeeper содержит серверы, которые принимают соединение, но сразу же разрывают его вместо ответа на рукопожатие, то ClickHouse выбирает для соединения другой сервер. Ранее в этом случае возникала ошибка `Cannot read all data. Bytes read: 0. Bytes expected: 4.` и сервер не мог стартовать. [8218cf3a](https://github.com/yandex/ClickHouse/commit/8218cf3a5f39a43401953769d6d12a0bb8d29da9) -* Если ансамбль серверов ZooKeeper содержит серверы, для которых DNS запрос возвращает ошибку, то такие серверы пропускаются. [17b8e209](https://github.com/yandex/ClickHouse/commit/17b8e209221061325ad7ba0539f03c6e65f87f29) -* Исправлено преобразование типов между `Date` и `DateTime` при вставке данных в формате `VALUES` (в случае, когда `input_format_values_interpret_expressions = 1`). Ранее преобразование производилось между числовым значением количества дней с начала unix эпохи и unix timestamp, что приводило к неожиданным результатам. [#3229](https://github.com/yandex/ClickHouse/pull/3229) -* Исправление преобразования типов между `Decimal` и целыми числами. [#3211](https://github.com/yandex/ClickHouse/pull/3211) -* Исправлены ошибки в работе настройки `enable_optimize_predicate_expression`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3231) -* Исправлена ошибка парсинга формата CSV с числами с плавающей запятой, если используется разделитель CSV не по-умолчанию, такой как например, `;` [#3155](https://github.com/yandex/ClickHouse/pull/3155). -* Исправлена функция `arrayCumSumNonNegative` (она не накапливает отрицательные значения, если аккумулятор становится меньше нуля). [Aleksey Studnev](https://github.com/yandex/ClickHouse/pull/3163) -* Исправлена работа `Merge` таблицы поверх `Distributed` таблиц при использовании `PREWHERE`. [#3165](https://github.com/yandex/ClickHouse/pull/3165) -* Исправления ошибок в запросе `ALTER UPDATE`. -* Исправления ошибок в табличной функции `odbc`, которые возникли в версии 18.12. [#3197](https://github.com/yandex/ClickHouse/pull/3197) -* Исправлена работа агрегатных функций с комбинаторами `StateArray`. [#3188](https://github.com/yandex/ClickHouse/pull/3188) -* Исправлено падение при делении значения типа `Decimal` на ноль. [69dd6609](https://github.com/yandex/ClickHouse/commit/69dd6609193beb4e7acd3e6ad216eca0ccfb8179) -* Исправлен вывод типов для операций с использованием аргументов типа `Decimal` и целых чисел. [#3224](https://github.com/yandex/ClickHouse/pull/3224) -* Исправлен segfault при `GROUP BY` по `Decimal128`. [3359ba06](https://github.com/yandex/ClickHouse/commit/3359ba06c39fcd05bfdb87d6c64154819621e13a) -* Настройка `log_query_threads` (логгирование информации о каждом потоке исполнения запроса) теперь имеет эффект только если настройка `log_queries` (логгирование информации о запросах) выставлена в 1. Так как настройка `log_query_threads` включена по-умолчанию, ранее информация о потоках логгировалась даже если логгирование запросов выключено. [#3241](https://github.com/yandex/ClickHouse/pull/3241) -* Исправлена ошибка в распределённой работе агрегатной функции quantiles (сообщение об ошибке вида `Not found column quantile...`). [292a8855](https://github.com/yandex/ClickHouse/commit/292a885533b8e3b41ce8993867069d14cbd5a664) -* Исправлена проблема совместимости при одновременной работе на кластере серверов версии 18.12.17 и более старых, приводящая к тому, что при распределённых запросах с GROUP BY по ключам одновременно фиксированной и не фиксированной длины, при условии, что количество данных в процессе агрегации большое, могли возвращаться не до конца агрегированные данные (одни и те же ключи агрегации в двух разных строках). [#3254](https://github.com/yandex/ClickHouse/pull/3254) -* Исправлена обработка подстановок в `clickhouse-performance-test`, если запрос содержит только часть из объявленных в тесте подстановок. [#3263](https://github.com/yandex/ClickHouse/pull/3263) -* Исправлена ошибка при использовании `FINAL` совместно с `PREWHERE`. [#3298](https://github.com/yandex/ClickHouse/pull/3298) -* Исправлена ошибка при использовании `PREWHERE` над столбцами, добавленными при `ALTER`. [#3298](https://github.com/yandex/ClickHouse/pull/3298) -* Добавлена проверка отсутствия `arrayJoin` для `DEFAULT`, `MATERIALIZED` выражений. Ранее наличие `arrayJoin` приводило к ошибке при вставке данных. [#3337](https://github.com/yandex/ClickHouse/pull/3337) -* Добавлена проверка отсутствия `arrayJoin` в секции `PREWHERE`. Ранее это приводило к сообщениям вида `Size ... doesn't match` или `Unknown compression method` при выполнении запросов. [#3357](https://github.com/yandex/ClickHouse/pull/3357) -* Исправлен segfault, который мог возникать в редких случаях после оптимизации - замены цепочек AND из равенства выражения константам на соответствующее выражение IN. [liuyimin-bytedance](https://github.com/yandex/ClickHouse/pull/3339). -* Мелкие исправления `clickhouse-benchmark`: ранее информация о клиенте не передавалась на сервер; более корректный подсчёт числа выполненных запросов при завершении работы и для ограничения числа итераций. [#3351](https://github.com/yandex/ClickHouse/pull/3351) [#3352](https://github.com/yandex/ClickHouse/pull/3352) - -### Обратно несовместимые изменения: - -* Удалена настройка `allow_experimental_decimal_type`. Тип данных `Decimal` доступен для использования по-умолчанию. [#3329](https://github.com/yandex/ClickHouse/pull/3329) - - -## ClickHouse release 18.12.17, 2018-09-16 - -### Новые возможности: - -* `invalidate_query` (возможность задать запрос для проверки необходимости обновления внешнего словаря) реализована для источника `clickhouse`. [#3126](https://github.com/yandex/ClickHouse/pull/3126) -* Добавлена возможность использования типов данных `UInt*`, `Int*`, `DateTime` (наравне с типом `Date`) в качестве ключа внешнего словаря типа `range_hashed`, определяющего границы диапазонов. Возможность использования `NULL` в качестве обозначения открытого диапазона. [Vasily Nemkov](https://github.com/yandex/ClickHouse/pull/3123) -* Для типа `Decimal` добавлена поддержка агрегатных функций `var*`, `stddev*`. [#3129](https://github.com/yandex/ClickHouse/pull/3129) -* Для типа `Decimal` добавлена поддержка математических функций (`exp`, `sin` и т. п.) [#3129](https://github.com/yandex/ClickHouse/pull/3129) -* В таблицу `system.part_log` добавлен столбец `partition_id`. [#3089](https://github.com/yandex/ClickHouse/pull/3089) - -### Исправление ошибок: - -* Исправлена работа `Merge` таблицы поверх `Distributed` таблиц. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3159) -* Исправлена несовместимость (лишняя зависимость от версии `glibc`), приводящая к невозможности запуска ClickHouse на `Ubuntu Precise` и более старых. Несовместимость возникла в версии 18.12.13. [#3130](https://github.com/yandex/ClickHouse/pull/3130) -* Исправлены ошибки в работе настройки `enable_optimize_predicate_expression`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3107) -* Исправлено незначительное нарушение обратной совместимости, проявляющееся при одновременной работе на кластере реплик версий до 18.12.13 и создании новой реплики таблицы на сервере более новой версии (выдаётся сообщение `Can not clone replica, because the ... updated to new ClickHouse version`, что полностью логично, но не должно было происходить). [#3122](https://github.com/yandex/ClickHouse/pull/3122) - -### Обратно несовместимые изменения: - -* Настройка `enable_optimize_predicate_expression` включена по-умолчанию, что конечно очень оптимистично. При возникновении ошибок анализа запроса, связанных с поиском имён столбцов, следует выставить `enable_optimize_predicate_expression` в 0. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3107) - - -## ClickHouse release 18.12.14, 2018-09-13 - -### Новые возможности: - -* Добавлена поддержка запросов `ALTER UPDATE`. [#3035](https://github.com/yandex/ClickHouse/pull/3035) -* Добавлена настройка `allow_ddl`, упраляющая доступом пользователя к DDL-запросам. [#3104](https://github.com/yandex/ClickHouse/pull/3104) -* Добавлена настройка `min_merge_bytes_to_use_direct_io` для движков семейства `MergeTree`, позволяющая задать порог на суммарный размер слияния после которого работа с файлами кусков будет происходить с O_DIRECT. [#3117](https://github.com/yandex/ClickHouse/pull/3117) -* В системную таблицу `system.merges` добавлен столбец `partition_id`. [#3099](https://github.com/yandex/ClickHouse/pull/3099) - -### Улучшения - -* Если в процессе мутации кусок остался неизменённым, он не будет скачан репликами. [#3103](https://github.com/yandex/ClickHouse/pull/3103) -* При работе с `clickhouse-client` добавлено автодополнение для имён настроек. [#3106](https://github.com/yandex/ClickHouse/pull/3106) - -### Исправление ошибок - -* Добавлена проверка размеров массивов, которые являются элементами полей типа `Nested`, при вставке. [#3118](https://github.com/yandex/ClickHouse/pull/3118) -* Исправлена ошибка обновления внешних словарей с источником `ODBC` и форматом хранения `hashed`. Ошибка возникла в версии 18.12.13. -* Исправлено падение при создании временной таблицы таблицы из запроса с условием `IN`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3098) -* Исправлена ошибка в работе агрегатных функций для массивов, элементами которых может быть `NULL`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3097) - - -## ClickHouse release 18.12.13, 2018-09-10 - -### Новые возможности: - -* Добавлен тип данных `DECIMAL(digits, scale)` (`Decimal32(scale)`, `Decimal64(scale)`, `Decimal128(scale)`). Возможность доступна под настройкой `allow_experimental_decimal_type`. [#2846](https://github.com/yandex/ClickHouse/pull/2846) [#2970](https://github.com/yandex/ClickHouse/pull/2970) [#3008](https://github.com/yandex/ClickHouse/pull/3008) [#3047](https://github.com/yandex/ClickHouse/pull/3047) -* Модификатор `WITH ROLLUP` для `GROUP BY` (также доступен синтаксис: `GROUP BY ROLLUP(...)`). [#2948](https://github.com/yandex/ClickHouse/pull/2948) -* В запросах с JOIN, звёздочка раскрывается в список столбцов всех таблиц, в соответствии со стандартом SQL. Вернуть старое поведение можно, выставив настройку (уровня пользователя) `asterisk_left_columns_only` в значение 1. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2787) -* Добавлена поддержка JOIN с табличной функцией. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2907) -* Автодополнение по нажатию Tab в clickhouse-client. [Sergey Shcherbin](https://github.com/yandex/ClickHouse/pull/2447) -* Нажатие Ctrl+C в clickhouse-client очищает запрос, если он был введён. [#2877](https://github.com/yandex/ClickHouse/pull/2877) -* Добавлена настройка `join_default_strictness` (значения `''`, `'any'`, `'all'`). Её использование позволяет не указывать `ANY` или `ALL` для `JOIN`. [#2982](https://github.com/yandex/ClickHouse/pull/2982) -* В каждой строчке лога сервера, относящейся к обработке запроса, выводится идентификатор запроса. [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* Возможность получения логов выполнения запроса в clickhouse-client (настройка `send_logs_level`). При распределённой обработке запроса, логи отправляются каскадно со всех серверов. [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* В таблицах `system.query_log` и `system.processes` (`SHOW PROCESSLIST`) появилась информация о всех изменённых настройках при выполнении запроса (вложенная структура данных `Settings`). Добавлена настройка `log_query_settings`. [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* В таблицах `system.query_log` и `system.processes` появилась информация о номерах потоков, участвующих в исполнении запроса (столбец `thread_numbers`). [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* Добавлены счётчики `ProfileEvents`, измеряющие время, потраченное на чтение и запись по сети; чтение и запись на диск; количество сетевых ошибок; время потраченное на ожидании при ограничении сетевой полосы. [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* Добавлены счётчики `ProfileEvents`, содержащие системные метрики из rusage (позволяющие получить информацию об использовании CPU в userspace и ядре, page faults, context switches) а также метрики taskstats (позволяющие получить информацию о времени ожидания IO, CPU, а также количество прочитанных и записанных данных с учётом и без учёта page cache). [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* Счётчики `ProfileEvents` учитываются не только глобально, но и на каждый запрос, а также на каждый поток выполнения запроса, что позволяет детально профилировать потребление ресурсов отдельными запросами. [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* Добавлена таблица `system.query_thread_log`, содержащая информацию о каждом потоке выполнения запроса. Добавлена настройка `log_query_threads`. [#2482](https://github.com/yandex/ClickHouse/pull/2482) -* В таблицах `system.metrics` и `system.events` появилась встроенная документация. [#3016](https://github.com/yandex/ClickHouse/pull/3016) -* Добавлена функция `arrayEnumerateDense`. [Amos Bird](https://github.com/yandex/ClickHouse/pull/2975) -* Добавлены функции `arrayCumSumNonNegative` и `arrayDifference`. [Aleksey Studnev](https://github.com/yandex/ClickHouse/pull/2942) -* Добавлена агрегатная функция `retention`. [Sundy Li](https://github.com/yandex/ClickHouse/pull/2887) -* Возможность сложения (слияния) состояний агрегатных функций с помощью оператора плюс, а также умножения состояний агрегатных функций на целую неотрицательную константу. [#3062](https://github.com/yandex/ClickHouse/pull/3062) [#3034](https://github.com/yandex/ClickHouse/pull/3034) -* В таблицах семейства MergeTree добавлен виртуальный столбец `_partition_id`. [#3089](https://github.com/yandex/ClickHouse/pull/3089) - -### Экспериментальные возможности: - -* Добавлен тип данных `LowCardinality(T)`. Тип данных автоматически создаёт локальный словарь значений и позволяет обрабатывать данные без распаковки словаря. [#2830](https://github.com/yandex/ClickHouse/pull/2830) -* Добавлен кэш JIT-скомпилированных функций, а также счётчик числа использований перед компиляцией. Возможность JIT-компиляции выражений включается настройкой `compile_expressions`. [#2990](https://github.com/yandex/ClickHouse/pull/2990) [#3077](https://github.com/yandex/ClickHouse/pull/3077) - -### Улучшения: - -* Исправлена проблема неограниченного накопления лога репликации в случае наличия заброшенных реплик. Добавлен режим эффективного восстановления реплик после длительного отставания. -* Увеличена производительность при выполнении `GROUP BY` в случае, если есть несколько полей агрегации, одно из которых строковое, а другие - фиксированной длины. -* Увеличена производительность при использовании `PREWHERE` и при неявном переносе выражений в `PREWHERE`. -* Увеличена производительность парсинга текстовых форматов (`CSV`, `TSV`). [Amos Bird](https://github.com/yandex/ClickHouse/pull/2977) [#2980](https://github.com/yandex/ClickHouse/pull/2980) -* Увеличена производительность чтения строк и массивов в бинарных форматах. [Amos Bird](https://github.com/yandex/ClickHouse/pull/2955) -* Увеличена производительность и уменьшено потребление памяти в запросах к таблицам `system.tables` и `system.columns` в случае наличия очень большого количества таблиц на одном сервере. [#2953](https://github.com/yandex/ClickHouse/pull/2953) -* Исправлена проблема низкой производительности в случае наличия большого потока запросов, для которых возвращается ошибка (в `perf top` видна функция `_dl_addr`, при этом сервер использует мало CPU). [#2938](https://github.com/yandex/ClickHouse/pull/2938) -* Прокидывание условий внутрь View (при включенной настройке `enable_optimize_predicate_expression`) [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2907) -* Доработки недостающей функциональности для типа данных `UUID`. [#3074](https://github.com/yandex/ClickHouse/pull/3074) [#2985](https://github.com/yandex/ClickHouse/pull/2985) -* Тип данных `UUID` поддержан в словарях The-Alchemist. [#2822](https://github.com/yandex/ClickHouse/pull/2822) -* Функция `visitParamExtractRaw` корректно работает с вложенными структурами. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2974) -* При использовании настройки `input_format_skip_unknown_fields` корректно работает пропуск значений-объектов в формате `JSONEachRow`. [BlahGeek](https://github.com/yandex/ClickHouse/pull/2958) -* Для выражения `CASE` с условиями, появилась возможность не указывать `ELSE`, что эквивалентно `ELSE NULL`. [#2920](https://github.com/yandex/ClickHouse/pull/2920) -* Возможность конфигурирования operation timeout при работе с ZooKeeper. [urykhy](https://github.com/yandex/ClickHouse/pull/2971) -* Возможность указания смещения для `LIMIT n, m` в виде `LIMIT n OFFSET m`. [#2840](https://github.com/yandex/ClickHouse/pull/2840) -* Возможность использования синтаксиса `SELECT TOP n` в качестве альтернативы для `LIMIT`. [#2840](https://github.com/yandex/ClickHouse/pull/2840) -* Увеличен размер очереди записи в системные таблицы, что позволяет уменьшить количество ситуаций `SystemLog queue is full`. -* В агрегатной функции `windowFunnel` добавлена поддержка событий, подходящих под несколько условий. [Amos Bird](https://github.com/yandex/ClickHouse/pull/2801) -* Возможность использования дублирующихся столбцов в секции `USING` для `JOIN`. [#3006](https://github.com/yandex/ClickHouse/pull/3006) -* Для форматов `Pretty` введено ограничение выравнивания столбцов по ширине. Настройка `output_format_pretty_max_column_pad_width`. В случае более широкого значения, оно всё ещё будет выведено целиком, но остальные ячейки таблицы не будут излишне широкими. [#3003](https://github.com/yandex/ClickHouse/pull/3003) -* В табличной функции `odbc` добавлена возможность указания имени базы данных/схемы. [Amos Bird](https://github.com/yandex/ClickHouse/pull/2885) -* Добавлена возможность использования имени пользователя, заданного в конфигурационном файле `clickhouse-client`. [Vladimir Kozbin](https://github.com/yandex/ClickHouse/pull/2909) -* Счётчик `ZooKeeperExceptions` разделён на три счётчика `ZooKeeperUserExceptions`, `ZooKeeperHardwareExceptions`, `ZooKeeperOtherExceptions`. -* Запросы `ALTER DELETE` работают для материализованных представлений. -* Добавлена рандомизация во времени периодического запуска cleanup thread для таблиц типа `ReplicatedMergeTree`, чтобы избежать периодических всплесков нагрузки в случае очень большого количества таблиц типа `ReplicatedMergeTree`. -* Поддержка запроса `ATTACH TABLE ... ON CLUSTER`. [#3025](https://github.com/yandex/ClickHouse/pull/3025) - -### Исправление ошибок: - -* Исправлена ошибка в работе таблиц типа `Dictionary` (кидается исключение `Size of offsets doesn't match size of column` или `Unknown compression method`). Ошибка появилась в версии 18.10.3. [#2913](https://github.com/yandex/ClickHouse/issues/2913) -* Исправлена ошибка при мерже данных таблиц типа `CollapsingMergeTree`, если один из кусков данных пустой (такие куски, в свою очередь, образуются при слиянии или при `ALTER DELETE` в случае удаления всех данных), и для слияния был выбран алгоритм `vertical`. [#3049](https://github.com/yandex/ClickHouse/pull/3049) -* Исправлен race condition при `DROP` или `TRUNCATE` таблиц типа `Memory` при одновременном `SELECT`, который мог приводить к падениям сервера. Ошибка появилась в версии 1.1.54388. [#3038](https://github.com/yandex/ClickHouse/pull/3038) -* Исправлена возможность потери данных при вставке в `Replicated` таблицы в случае получения ошибки `Session expired` (потеря данных может быть обнаружена по метрике `ReplicatedDataLoss`). Ошибка возникла в версии 1.1.54378. [#2939](https://github.com/yandex/ClickHouse/pull/2939) [#2949](https://github.com/yandex/ClickHouse/pull/2949) [#2964](https://github.com/yandex/ClickHouse/pull/2964) -* Исправлен segfault при `JOIN ... ON`. [#3000](https://github.com/yandex/ClickHouse/pull/3000) -* Исправлена ошибка поиска имён столбцов в случае, если выражение `WHERE` состоит целиком из квалифицированного имени столбца, как например `WHERE table.column`. [#2994](https://github.com/yandex/ClickHouse/pull/2994) -* Исправлена ошибка вида "Not found column" при выполнении распределённых запросов в случае, если с удалённого сервера запрашивается единственный столбец, представляющий собой выражение IN с подзапросом. [#3087](https://github.com/yandex/ClickHouse/pull/3087) -* Исправлена ошибка `Block structure mismatch in UNION stream: different number of columns`, возникающая при распределённых запросах, если один из шардов локальный, а другой - нет, и если при этом срабатывает оптимизация переноса в `PREWHERE`. [#2226](https://github.com/yandex/ClickHouse/pull/2226) [#3037](https://github.com/yandex/ClickHouse/pull/3037) [#3055](https://github.com/yandex/ClickHouse/pull/3055) [#3065](https://github.com/yandex/ClickHouse/pull/3065) [#3073](https://github.com/yandex/ClickHouse/pull/3073) [#3090](https://github.com/yandex/ClickHouse/pull/3090) [#3093](https://github.com/yandex/ClickHouse/pull/3093) -* Исправлена работа функции `pointInPolygon` для некоторого случая невыпуклых полигонов. [#2910](https://github.com/yandex/ClickHouse/pull/2910) -* Исправлен некорректный результат при сравнении `nan` с целыми числами. [#3024](https://github.com/yandex/ClickHouse/pull/3024) -* Исправлена ошибка в библиотеке `zlib-ng`, которая могла приводить к segfault в редких случаях. [#2854](https://github.com/yandex/ClickHouse/pull/2854) -* Исправлена утечка памяти при вставке в таблицу со столбцами типа `AggregateFunction`, если состояние агрегатной функции нетривиальное (выделяет память отдельно), и если в одном запросе на вставку получается несколько маленьких блоков. [#3084](https://github.com/yandex/ClickHouse/pull/3084) -* Исправлен race condition при одновременном создании и удалении одной и той же таблицы типа `Buffer` или `MergeTree`. -* Исправлена возможность segfault при сравнении кортежей из некоторых нетривиальных типов, таких как, например, кортежей. [#2989](https://github.com/yandex/ClickHouse/pull/2989) -* Исправлена возможность segfault при выполнении некоторых запросов `ON CLUSTER`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2960) -* Исправлена ошибка в функции `arrayDistinct` в случае `Nullable` элементов массивов. [#2845](https://github.com/yandex/ClickHouse/pull/2845) [#2937](https://github.com/yandex/ClickHouse/pull/2937) -* Возможность `enable_optimize_predicate_expression` корректно поддерживает случаи с `SELECT *`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2929) -* Исправлена возможность segfault при переинициализации сессии с ZooKeeper. [#2917](https://github.com/yandex/ClickHouse/pull/2917) -* Исправлена возможность блокировки при взаимодействии с ZooKeeper. -* Исправлен некорректный код суммирования вложенных структур данных в `SummingMergeTree`. -* При выделении памяти для состояний агрегатных функций, корректно учитывается выравнивание, что позволяет использовать при реализации состояний агрегатных функций операции, для которых выравнивание является необходимым. [chenxing-xc](https://github.com/yandex/ClickHouse/pull/2808) - -### Исправления безопасности: - -* Безопасная работа с ODBC источниками данных. Взаимодействие с ODBC драйверами выполняется через отдельный процесс `clickhouse-odbc-bridge`. Ошибки в сторонних ODBC драйверах теперь не приводят к проблемам со стабильностью сервера или уязвимостям. [#2828](https://github.com/yandex/ClickHouse/pull/2828) [#2879](https://github.com/yandex/ClickHouse/pull/2879) [#2886](https://github.com/yandex/ClickHouse/pull/2886) [#2893](https://github.com/yandex/ClickHouse/pull/2893) [#2921](https://github.com/yandex/ClickHouse/pull/2921) -* Исправлена некорректная валидация пути к файлу в табличной функции `catBoostPool`. [#2894](https://github.com/yandex/ClickHouse/pull/2894) -* Содержимое системных таблиц (`tables`, `databases`, `parts`, `columns`, `parts_columns`, `merges`, `mutations`, `replicas`, `replication_queue`) фильтруется согласно конфигурации доступа к базам данных для пользователя (`allow_databases`) [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2856) - -### Обратно несовместимые изменения: - -* В запросах с JOIN, звёздочка раскрывается в список столбцов всех таблиц, в соответствии со стандартом SQL. Вернуть старое поведение можно, выставив настройку (уровня пользователя) `asterisk_left_columns_only` в значение 1. - -### Изменения сборки: - -* Добавлен покоммитный запуск большинства интеграционных тестов. -* Добавлен покоммитный запуск проверки стиля кода. -* Корректный выбор реализации `memcpy` при сборке на CentOS7 / Fedora. [Etienne Champetier](https://github.com/yandex/ClickHouse/pull/2912) -* При сборке с помощью clang добавлены некоторые warnings из `-Weverything` в дополнение к обычным `-Wall -Wextra -Werror`. [#2957](https://github.com/yandex/ClickHouse/pull/2957) -* При debug сборке используется debug вариант `jemalloc`. -* Абстрагирован интерфейс библиотеки для взаимодействия с ZooKeeper. [#2950](https://github.com/yandex/ClickHouse/pull/2950) - - -## ClickHouse release 18.10.3, 2018-08-13 - -### Новые возможности: -* Возможность использования HTTPS для репликации. [#2760](https://github.com/yandex/ClickHouse/pull/2760) -* Добавлены функции `murmurHash2_64`, `murmurHash3_32`, `murmurHash3_64`, `murmurHash3_128` в дополнение к имеющемуся `murmurHash2_32`. [#2791](https://github.com/yandex/ClickHouse/pull/2791) -* Поддержка Nullable типов в ODBC драйвере ClickHouse (формат вывода `ODBCDriver2`) [#2834](https://github.com/yandex/ClickHouse/pull/2834) -* Поддержка `UUID` в ключевых столбцах. - -### Улучшения: -* Удаление кластеров без перезагрузки сервера при их удалении из конфигурационных файлов. [#2777](https://github.com/yandex/ClickHouse/pull/2777) -* Удаление внешних словарей без перезагрузки сервера при их удалении из конфигурационных файлов. [#2779](https://github.com/yandex/ClickHouse/pull/2779) -* Добавлена поддержка `SETTINGS` для движка таблиц `Kafka`. [Alexander Marshalov](https://github.com/yandex/ClickHouse/pull/2781) -* Доработки для типа данных `UUID` (не полностью) Šimon Podlipský. [#2618](https://github.com/yandex/ClickHouse/pull/2618) -* Поддежка пустых кусков после мержей в движках `SummingMergeTree`, `CollapsingMergeTree` and `VersionedCollapsingMergeTree`. [#2815](https://github.com/yandex/ClickHouse/pull/2815) -* Удаление старых записей о полностью выполнившихся мутациях (`ALTER DELETE`) [#2784](https://github.com/yandex/ClickHouse/pull/2784) -* Добавлена таблица `system.merge_tree_settings`. [Kirill Shvakov](https://github.com/yandex/ClickHouse/pull/2841) -* В таблицу `system.tables` добавлены столбцы зависимостей: `dependencies_database` и `dependencies_table`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2851) -* Добавлена опция конфига `max_partition_size_to_drop`. [#2782](https://github.com/yandex/ClickHouse/pull/2782) -* Добавлена настройка `output_format_json_escape_forward_slashes`. [Alexander Bocharov](https://github.com/yandex/ClickHouse/pull/2812) -* Добавлена настройка `max_fetch_partition_retries_count`. [#2831](https://github.com/yandex/ClickHouse/pull/2831) -* Добавлена настройка `prefer_localhost_replica`, позволяющая отключить предпочтение локальной реплики и хождение на локальную реплику без межпроцессного взаимодействия. [#2832](https://github.com/yandex/ClickHouse/pull/2832) -* Агрегатная функция `quantileExact` возвращает `nan` в случае агрегации по пустому множеству `Float32`/`Float64` типов. [Sundy Li](https://github.com/yandex/ClickHouse/pull/2855) - -### Исправление ошибок: -* Убрано излишнее экранирование параметров connection string для ODBC, котрое приводило к невозможности соединения. Ошибка возникла в версии 18.6.0. -* Исправлена логика обработки команд на `REPLACE PARTITION` в очереди репликации. Неправильная логика могла приводить к тому, что при наличии двух `REPLACE` одной и той же партиции, один из них оставался в очереди репликации и не мог выполниться. [#2814](https://github.com/yandex/ClickHouse/pull/2814) -* Исправлена ошибка при мерже, если все куски были пустыми (такие куски, в свою очередь, образуются при слиянии или при `ALTER DELETE` в случае удаления всех данных). Ошибка появилась в версии 18.1.0. [#2930](https://github.com/yandex/ClickHouse/pull/2930) -* Исправлена ошибка при параллельной записи в таблицы типа `Set` или `Join`. [Amos Bird](https://github.com/yandex/ClickHouse/pull/2823) -* Исправлена ошибка `Block structure mismatch in UNION stream: different number of columns`, возникающая при запросах с `UNION ALL` внутри подзапроса, в случае, если один из `SELECT` запросов содержит дублирующиеся имена столбцов. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2094) -* Исправлена утечка памяти в случае исключения при соединении с MySQL сервером. -* Исправлен некорректный код возврата clickhouse-client в случае ошибочного запроса -* Исправлен некорректная работа materialized views, содержащих DISTINCT. [#2795](https://github.com/yandex/ClickHouse/issues/2795) - -### Обратно несовместимые изменения -* Убрана поддержка запросов CHECK TABLE для Distributed таблиц. - -### Изменения сборки: -* Заменен аллокатор, теперь используется `jemalloc` вместо `tcmalloc`. На некоторых сценариях ускорение достигает 20%. В то же время, существуют запросы, замедлившиеся до 20%. Потребление памяти на некоторых сценариях примерно на 10% меньше и более стабильно. При высококонкурентной нагрузке, потребление CPU в userspace и в system незначительно вырастает. [#2773](https://github.com/yandex/ClickHouse/pull/2773) -* Использование libressl из submodule. [#1983](https://github.com/yandex/ClickHouse/pull/1983) [#2807](https://github.com/yandex/ClickHouse/pull/2807) -* Использование unixodbc из submodule. [#2789](https://github.com/yandex/ClickHouse/pull/2789) -* Использование mariadb-connector-c из submodule. [#2785](https://github.com/yandex/ClickHouse/pull/2785) -* В репозиторий добавлены файлы функциональных тестов, рассчитывающих на наличие тестовых данных (пока без самих тестовых данных). - - -## ClickHouse release 18.6.0, 2018-08-02 - -### Новые возможности: -* Добавлена поддержка ON выражений для JOIN ON синтаксиса: -`JOIN ON Expr([table.]column, ...) = Expr([table.]column, ...) [AND Expr([table.]column, ...) = Expr([table.]column, ...) ...]` -Выражение должно представлять из себя цепочку равенств, объединенных оператором AND. Каждая часть равенства может являться произвольным выражением над столбцами одной из таблиц. Поддержана возможность использования fully qualified имен столбцов (`table.name`, `database.table.name`, `table_alias.name`, `subquery_alias.name`) для правой таблицы. [#2742](https://github.com/yandex/ClickHouse/pull/2742) -* Добавлена возможность включить HTTPS для репликации. [#2760](https://github.com/yandex/ClickHouse/pull/2760) - -### Улучшения: -* Сервер передаёт на клиент также patch-компонент своей версии. Данные о patch компоненте версии добавлены в `system.processes` и `query_log`. [#2646](https://github.com/yandex/ClickHouse/pull/2646) - - -## ClickHouse release 18.5.1, 2018-07-31 - -### Новые возможности: -* Добавлена функция хеширования `murmurHash2_32`. [#2756](https://github.com/yandex/ClickHouse/pull/2756). - -### Улучшения: -* Добавлена возможность указывать значения в конфигурационных файлах из переменных окружения с помощью атрибута `from_env`. [#2741](https://github.com/yandex/ClickHouse/pull/2741). -* Добавлены регистронезависимые версии функций `coalesce`, `ifNull`, `nullIf`. [#2752](https://github.com/yandex/ClickHouse/pull/2752). - -### Исправление ошибок: -* Исправлена возможная ошибка при старте реплики. [#2759](https://github.com/yandex/ClickHouse/pull/2759). - - -## ClickHouse release 18.4.0, 2018-07-28 - -### Новые возможности: -* Добавлены системные таблицы `formats`, `data_type_families`, `aggregate_function_combinators`, `table_functions`, `table_engines`, `collations` [#2721](https://github.com/yandex/ClickHouse/pull/2721). -* Добавлена возможность использования табличной функции вместо таблицы в качестве аргумента табличной функции `remote` и `cluster` [#2708](https://github.com/yandex/ClickHouse/pull/2708). -* Поддержка `HTTP Basic` аутентификации в протоколе репликации [#2727](https://github.com/yandex/ClickHouse/pull/2727). -* В функции `has` добавлена возможность поиска в массиве значений типа `Enum` по числовому значению [Maxim Khrisanfov](https://github.com/yandex/ClickHouse/pull/2699). -* Поддержка добавления произвольных разделителей сообщений в процессе чтения из `Kafka` [Amos Bird](https://github.com/yandex/ClickHouse/pull/2701). - -### Улучшения: -* Запрос `ALTER TABLE t DELETE WHERE` не перезаписывает куски данных, которые не были затронуты условием WHERE [#2694](https://github.com/yandex/ClickHouse/pull/2694). -* Настройка `use_minimalistic_checksums_in_zookeeper` таблиц семейства `ReplicatedMergeTree` включена по-умолчанию. Эта настройка была добавлена в версии 1.1.54378, 2018-04-16. Установка версий, более старых, чем 1.1.54378, становится невозможной. -* Поддерживается запуск запросов `KILL` и `OPTIMIZE` с указанием `ON CLUSTER` [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2689). - -### Исправление ошибок: -* Исправлена ошибка `Column ... is not under aggregate function and not in GROUP BY` в случае агрегации по выражению с оператором IN. Ошибка появилась в версии 18.1.0. ([bbdd780b](https://github.com/yandex/ClickHouse/commit/bbdd780be0be06a0f336775941cdd536878dd2c2)) -* Исправлена ошибка в агрегатной функции `windowFunnel` [Winter Zhang](https://github.com/yandex/ClickHouse/pull/2735). -* Исправлена ошибка в агрегатной функции `anyHeavy` ([a2101df2](https://github.com/yandex/ClickHouse/commit/a2101df25a6a0fba99aa71f8793d762af2b801ee)) -* Исправлено падение сервера при использовании функции `countArray()`. - -### Обратно несовместимые изменения: - -* Список параметров для таблиц `Kafka` был изменён с `Kafka(kafka_broker_list, kafka_topic_list, kafka_group_name, kafka_format[, kafka_schema, kafka_num_consumers])` на `Kafka(kafka_broker_list, kafka_topic_list, kafka_group_name, kafka_format[, kafka_row_delimiter, kafka_schema, kafka_num_consumers])`. Если вы использовали параметры `kafka_schema` или `kafka_num_consumers`, вам необходимо вручную отредактировать файлы с метаданными `path/metadata/database/table.sql`, добавив параметр `kafka_row_delimiter` со значением `''` в соответствующее место. - - -## ClickHouse release 18.1.0, 2018-07-23 - -### Новые возможности: -* Поддержка запроса `ALTER TABLE t DELETE WHERE` для нереплицированных MergeTree-таблиц ([#2634](https://github.com/yandex/ClickHouse/pull/2634)). -* Поддержка произвольных типов для семейства агрегатных функций `uniq*` ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). -* Поддержка произвольных типов в операторах сравнения ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). -* Возможность в `users.xml` указывать маску подсети в формате `10.0.0.1/255.255.255.0`. Это необходимо для использования "дырявых" масок IPv6 сетей ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). -* Добавлена функция `arrayDistinct` ([#2670](https://github.com/yandex/ClickHouse/pull/2670)). -* Движок SummingMergeTree теперь может работать со столбцами типа AggregateFunction ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2566)). - -### Улучшения: -* Изменена схема версионирования релизов. Теперь первый компонент содержит год релиза (A.D.; по московскому времени; из номера вычитается 2000), второй - номер крупных изменений (увеличивается для большинства релизов), третий - патч-версия. Релизы по-прежнему обратно совместимы, если другое не указано в changelog. -* Ускорено преобразование чисел с плавающей точкой в строку ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2664)). -* Теперь, если при вставке из-за ошибок парсинга пропущено некоторое количество строк (такое возможно про включённых настройках `input_allow_errors_num`, `input_allow_errors_ratio`), это количество пишется в лог сервера ([Leonardo Cecchi](https://github.com/yandex/ClickHouse/pull/2669)). - -### Исправление ошибок: -* Исправлена работа команды TRUNCATE для временных таблиц ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2624)). -* Исправлен редкий deadlock в клиентской библиотеке ZooKeeper, который возникал при сетевой ошибке во время вычитывания ответа ([c315200](https://github.com/yandex/ClickHouse/commit/c315200e64b87e44bdf740707fc857d1fdf7e947)). -* Исправлена ошибка при CAST в Nullable типы ([#1322](https://github.com/yandex/ClickHouse/issues/1322)). -* Исправлен неправильный результат функции `maxIntersection()` в случае совпадения границ отрезков ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2657)). -* Исправлено неверное преобразование цепочки OR-выражений в аргументе функции ([chenxing-xc](https://github.com/yandex/ClickHouse/pull/2663)). -* Исправлена деградация производительности запросов, содержащих выражение `IN (подзапрос)` внутри другого подзапроса ([#2571](https://github.com/yandex/ClickHouse/issues/2571)). -* Исправлена несовместимость серверов разных версий при распределённых запросах, использующих функцию `CAST` не в верхнем регистре ([fe8c4d6](https://github.com/yandex/ClickHouse/commit/fe8c4d64e434cacd4ceef34faa9005129f2190a5)). -* Добавлено недостающее квотирование идентификаторов при запросах к внешним СУБД ([#2635](https://github.com/yandex/ClickHouse/issues/2635)). - -### Обратно несовместимые изменения: -* Не работает преобразование строки, содержащей число ноль, в DateTime. Пример: `SELECT toDateTime('0')`. По той же причине не работает `DateTime DEFAULT '0'` в таблицах, а также `0` в словарях. Решение: заменить `0` на `0000-00-00 00:00:00`. - - -## ClickHouse release 1.1.54394, 2018-07-12 - -### Новые возможности: -* Добавлена агрегатная функция `histogram` ([Михаил Сурин](https://github.com/yandex/ClickHouse/pull/2521)). -* Возможность использования `OPTIMIZE TABLE ... FINAL` без указания партиции для `ReplicatedMergeTree` ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2600)). - -### Исправление ошибок: -* Исправлена ошибка - выставление слишком маленького таймаута у сокетов (одна секунда) для чтения и записи при отправке и скачивании реплицируемых данных, что приводило к невозможности скачать куски достаточно большого размера при наличии некоторой нагрузки на сеть или диск (попытки скачивания кусков циклически повторяются). Ошибка возникла в версии 1.1.54388. -* Исправлена работа при использовании chroot в ZooKeeper, в случае вставки дублирующихся блоков данных в таблицу. -* Исправлена работа функции `has` для случая массива с Nullable элементами ([#2115](https://github.com/yandex/ClickHouse/issues/2521)). -* Исправлена работа таблицы `system.tables` при её использовании в распределённых запросах; столбцы `metadata_modification_time` и `engine_full` сделаны невиртуальными; исправлена ошибка в случае, если из таблицы были запрошены только эти столбцы. -* Исправлена работа пустой таблицы типа `TinyLog` после вставки в неё пустого блока данных ([#2563](https://github.com/yandex/ClickHouse/issues/2563)). -* Таблица `system.zookeeper` работает в случае, если значение узла в ZooKeeper равно NULL. - - -## ClickHouse release 1.1.54390, 2018-07-06 - -### Новые возможности: -* Возможность отправки запроса в формате `multipart/form-data` (в поле `query`), что полезно, если при этом также отправляются внешние данные для обработки запроса ([Ольга Хвостикова](https://github.com/yandex/ClickHouse/pull/2490)). -* Добавлена возможность включить или отключить обработку одинарных или двойных кавычек при чтении данных в формате CSV. Это задаётся настройками `format_csv_allow_single_quotes` и `format_csv_allow_double_quotes` ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2574)) -* Возможность использования `OPTIMIZE TABLE ... FINAL` без указания партиции для не реплицированных вариантов`MergeTree` ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2599)). - -### Улучшения: -* Увеличена производительность, уменьшено потребление памяти, добавлен корректный учёт потребления памяти, при использовании оператора IN в случае, когда для его работы может использоваться индекс таблицы ([#2584](https://github.com/yandex/ClickHouse/pull/2584)). -* Убраны избыточные проверки чексумм при добавлении куска. Это важно в случае большого количества реплик, так как в этом случае суммарное количество проверок было равно N^2. -* Добавлена поддержка аргументов типа `Array(Tuple(...))` для функции `arrayEnumerateUniq` ([#2573](https://github.com/yandex/ClickHouse/pull/2573)). -* Добавлена поддержка `Nullable` для функции `runningDifference`. ([#2594](https://github.com/yandex/ClickHouse/pull/2594)) -* Увеличена производительность анализа запроса в случае очень большого количества выражений ([#2572](https://github.com/yandex/ClickHouse/pull/2572)). -* Более быстрый выбор кусков для слияния в таблицах типа `ReplicatedMergeTree`. Более быстрое восстановление сессии с ZooKeeper. ([#2597](https://github.com/yandex/ClickHouse/pull/2597)). -* Файл `format_version.txt` для таблиц семейства `MergeTree` создаётся заново при его отсутствии, что имеет смысл в случае запуска ClickHouse после копирования структуры директорий без файлов ([Ciprian Hacman](https://github.com/yandex/ClickHouse/pull/2593)). - -### Исправление ошибок: -* Исправлена ошибка при работе с ZooKeeper, которая могла приводить к невозможности восстановления сессии и readonly состояниям таблиц до перезапуска сервера. -* Исправлена ошибка при работе с ZooKeeper, которая могла приводить к неудалению старых узлов при разрыве сессии. -* Исправлена ошибка в функции `quantileTDigest` для Float аргументов (ошибка появилась в версии 1.1.54388) ([Михаил Сурин](https://github.com/yandex/ClickHouse/pull/2553)). -* Исправлена ошибка работы индекса таблиц типа MergeTree, если в условии, столбец первичного ключа расположен внутри функции преобразования типов между знаковым и беззнаковым целым одного размера ([#2603](https://github.com/yandex/ClickHouse/pull/2603)). -* Исправлен segfault, если в конфигурационном файле нет `macros`, но они используются ([#2570](https://github.com/yandex/ClickHouse/pull/2570)). -* Исправлено переключение на базу данных по-умолчанию при переподключении клиента ([#2583](https://github.com/yandex/ClickHouse/pull/2583)). -* Исправлена ошибка в случае отключенной настройки `use_index_for_in_with_subqueries`. - -### Исправления безопасности: -* При соединениях с MySQL удалена возможность отправки файлов (`LOAD DATA LOCAL INFILE`). - - -## ClickHouse release 1.1.54388, 2018-06-28 - -### Новые возможности: -* Добавлена поддержка запроса `ALTER TABLE t DELETE WHERE` для реплицированных таблиц и таблица `system.mutations`. -* Добавлена поддержка запроса `ALTER TABLE t [REPLACE|ATTACH] PARTITION` для *MergeTree-таблиц. -* Добавлена поддержка запроса `TRUNCATE TABLE` ([Winter Zhang](https://github.com/yandex/ClickHouse/pull/2260)) -* Добавлено несколько новых `SYSTEM`-запросов для реплицированных таблиц (`RESTART REPLICAS`, `SYNC REPLICA`, `[STOP|START] [MERGES|FETCHES|REPLICATED SENDS|REPLICATION QUEUES]`). -* Добавлена возможность записи в таблицу с движком MySQL и соответствующую табличную функцию ([sundy-li](https://github.com/yandex/ClickHouse/pull/2294)). -* Добавлена табличная функция `url()` и движок таблиц `URL` ([Александр Сапин](https://github.com/yandex/ClickHouse/pull/2501)). -* Добавлена агрегатная функция `windowFunnel` ([sundy-li](https://github.com/yandex/ClickHouse/pull/2352)). -* Добавлены функции `startsWith` и `endsWith` для строк ([Вадим Плахтинский](https://github.com/yandex/ClickHouse/pull/2429)). -* В табличной функции `numbers()` добавлена возможность указывать offset ([Winter Zhang](https://github.com/yandex/ClickHouse/pull/2535)). -* Добавлена возможность интерактивного ввода пароля в `clickhouse-client`. -* Добавлена возможность отправки логов сервера в syslog ([Александр Крашенинников](https://github.com/yandex/ClickHouse/pull/2459)). -* Добавлена поддержка логирования в словарях с источником shared library ([Александр Сапин](https://github.com/yandex/ClickHouse/pull/2472)). -* Добавлена поддержка произвольного разделителя в формате CSV ([Иван Жуков](https://github.com/yandex/ClickHouse/pull/2263)) -* Добавлена настройка `date_time_input_format`. Если переключить эту настройку в значение `'best_effort'`, значения DateTime будут читаться в широком диапазоне форматов. -* Добавлена утилита `clickhouse-obfuscator` для обфускации данных. Пример использования: публикация данных, используемых в тестах производительности. - -### Экспериментальные возможности: -* Добавлена возможность вычислять аргументы функции `and` только там, где они нужны ([Анастасия Царькова](https://github.com/yandex/ClickHouse/pull/2272)) -* Добавлена возможность JIT-компиляции в нативный код некоторых выражений ([pyos](https://github.com/yandex/ClickHouse/pull/2277)). - -### Исправление ошибок: -* Исправлено появление дублей в запросе с `DISTINCT` и `ORDER BY`. -* Запросы с `ARRAY JOIN` и `arrayFilter` раньше возвращали некорректный результат. -* Исправлена ошибка при чтении столбца-массива из Nested-структуры ([#2066](https://github.com/yandex/ClickHouse/issues/2066)). -* Исправлена ошибка при анализе запросов с секцией HAVING вида `HAVING tuple IN (...)`. -* Исправлена ошибка при анализе запросов с рекурсивными алиасами. -* Исправлена ошибка при чтении из ReplacingMergeTree с условием в PREWHERE, фильтрующим все строки ([#2525](https://github.com/yandex/ClickHouse/issues/2525)). -* Настройки профиля пользователя не применялись при использовании сессий в HTTP-интерфейсе. -* Исправлено применение настроек из параметров командной строки в программе clickhouse-local. -* Клиентская библиотека ZooKeeper теперь использует таймаут сессии, полученный от сервера. -* Исправлена ошибка в клиентской библиотеке ZooKeeper, из-за которой ожидание ответа от сервера могло длиться дольше таймаута. -* Исправлено отсечение ненужных кусков при запросе с условием на столбцы ключа партиционирования ([#2342](https://github.com/yandex/ClickHouse/issues/2342)). -* После `CLEAR COLUMN IN PARTITION` в соответствующей партиции теперь возможны слияния ([#2315](https://github.com/yandex/ClickHouse/issues/2315)). -* Исправлено соответствие типов в табличной функции ODBC ([sundy-li](https://github.com/yandex/ClickHouse/pull/2268)). -* Исправлено некорректное сравнение типов `DateTime` с таймзоной и без неё ([Александр Бочаров](https://github.com/yandex/ClickHouse/pull/2400)). -* Исправлен синтаксический разбор и форматирование оператора `CAST`. -* Исправлена вставка в материализованное представление в случае, если движок таблицы представления - Distributed ([Babacar Diassé](https://github.com/yandex/ClickHouse/pull/2411)). -* Исправлен race condition при записи данных из движка `Kafka` в материализованные представления ([Yangkuan Liu](https://github.com/yandex/ClickHouse/pull/2448)). -* Исправлена SSRF в табличной функции remote(). -* Исправлен выход из `clickhouse-client` в multiline-режиме ([#2510](https://github.com/yandex/ClickHouse/issues/2510)). - -### Улучшения: -* Фоновые задачи в реплицированных таблицах теперь выполняются не в отдельных потоках, а в пуле потоков ([Silviu Caragea](https://github.com/yandex/ClickHouse/pull/1722)) -* Улучшена производительность разжатия LZ4. -* Ускорен анализ запроса с большим числом JOIN-ов и подзапросов. -* DNS-кэш теперь автоматически обновляется при большом числе сетевых ошибок. -* Вставка в таблицу теперь не происходит, если вставка в одно из её материализованных представлений невозможна из-за того, что в нём много кусков. -* Исправлено несоответствие в значениях счётчиков событий `Query`, `SelectQuery`, `InsertQuery`. -* Разрешены выражения вида `tuple IN (SELECT tuple)`, если типы кортежей совпадают. -* Сервер с реплицированными таблицами теперь может стартовать, даже если не сконфигурирован ZooKeeper. -* При расчёте количества доступных ядер CPU теперь учитываются ограничения cgroups ([Atri Sharma](https://github.com/yandex/ClickHouse/pull/2325)). -* Добавлен chown директорий конфигов в конфигурационном файле systemd ([Михаил Ширяев](https://github.com/yandex/ClickHouse/pull/2421)). - -### Изменения сборки: -* Добавлена возможность сборки компилятором gcc8. -* Добавлена возможность сборки llvm из submodule. -* Используемая версия библиотеки librdkafka обновлена до v0.11.4. -* Добавлена возможность использования библиотеки libcpuid из системы, используемая версия библиотеки обновлена до 0.4.0. -* Исправлена сборка с использованием библиотеки vectorclass ([Babacar Diassé](https://github.com/yandex/ClickHouse/pull/2274)). -* Cmake теперь по умолчанию генерирует файлы для ninja (как при использовании `-G Ninja`). -* Добавлена возможность использования библиотеки libtinfo вместо libtermcap ([Георгий Кондратьев](https://github.com/yandex/ClickHouse/pull/2519)). -* Исправлен конфликт заголовочных файлов в Fedora Rawhide ([#2520](https://github.com/yandex/ClickHouse/issues/2520)). - -### Обратно несовместимые изменения: -* Убран escaping в форматах `Vertical` и `Pretty*`, удалён формат `VerticalRaw`. -* Если в распределённых запросах одновременно участвуют серверы версии 1.1.54388 или новее и более старые, то при использовании выражения `cast(x, 'Type')`, записанного без указания `AS`, если слово `cast` указано не в верхнем регистре, возникает ошибка вида `Not found column cast(0, 'UInt8') in block`. Решение: обновить сервер на всём кластере. - - -## ClickHouse release 1.1.54385, 2018-06-01 -### Исправление ошибок: -* Исправлена ошибка, которая в некоторых случаях приводила к блокировке операций с ZooKeeper. - -## ClickHouse release 1.1.54383, 2018-05-22 -### Исправление ошибок: -* Исправлена деградация скорости выполнения очереди репликации при большом количестве реплик - -## ClickHouse release 1.1.54381, 2018-05-14 - -### Исправление ошибок: -* Исправлена ошибка, приводящая к "утеканию" метаданных в ZooKeeper при потере соединения с сервером ZooKeeper. - -## ClickHouse release 1.1.54380, 2018-04-21 - -### Новые возможности: -* Добавлена табличная функция `file(path, format, structure)`. Пример, читающий байты из `/dev/urandom`: `ln -s /dev/urandom /var/lib/clickhouse/user_files/random` `clickhouse-client -q "SELECT * FROM file('random', 'RowBinary', 'd UInt8') LIMIT 10"`. - -### Улучшения: -* Добавлена возможность оборачивать подзапросы скобками `()` для повышения читаемости запросов. Например: `(SELECT 1) UNION ALL (SELECT 1)`. -* Простые запросы `SELECT` из таблицы `system.processes` не учитываются в ограничении `max_concurrent_queries`. - -### Исправление ошибок: -* Исправлена неправильная работа оператора `IN` в `MATERIALIZED VIEW`. -* Исправлена неправильная работа индекса по ключу партиционирования в выражениях типа `partition_key_column IN (...)`. -* Исправлена невозможность выполнить `OPTIMIZE` запрос на лидирующей реплике после выполнения `RENAME` таблицы. -* Исправлены ошибки авторизации возникающие при выполнении запросов `OPTIMIZE` и `ALTER` на нелидирующей реплике. -* Исправлены зависания запросов `KILL QUERY`. -* Исправлена ошибка в клиентской библиотеке ZooKeeper, которая при использовании непустого префикса `chroot` в конфигурации приводила к потере watch'ей, остановке очереди distributed DDL запросов и замедлению репликации. - -### Обратно несовместимые изменения: -* Убрана поддержка выражений типа `(a, b) IN (SELECT (a, b))` (можно использовать эквивалентные выражение `(a, b) IN (SELECT a, b)`). Раньше такие запросы могли приводить к недетерминированной фильтрации в `WHERE`. - - -## ClickHouse release 1.1.54378, 2018-04-16 - -### Новые возможности: - -* Возможность изменения уровня логгирования без перезагрузки сервера. -* Добавлен запрос `SHOW CREATE DATABASE`. -* Возможность передать `query_id` в `clickhouse-client` (elBroom). -* Добавлена настройка `max_network_bandwidth_for_all_users`. -* Добавлена поддержка `ALTER TABLE ... PARTITION ... ` для `MATERIALIZED VIEW`. -* Добавлена информация о размере кусков данных в несжатом виде в системные таблицы. -* Поддержка межсерверного шифрования для distributed таблиц (`1` в конфигурации реплики в ``). -* Добавлена настройка уровня таблицы семейства `ReplicatedMergeTree` для уменьшения объема данных, хранимых в zookeeper: `use_minimalistic_checksums_in_zookeeper = 1` -* Возможность настройки приглашения `clickhouse-client`. По-умолчанию добавлен вывод имени сервера в приглашение. Возможность изменить отображаемое имя сервера. Отправка его в HTTP заголовке `X-ClickHouse-Display-Name` (Kirill Shvakov). -* Возможность указания нескольких `topics` через запятую для движка `Kafka` (Tobias Adamson) -* При остановке запроса по причине `KILL QUERY` или `replace_running_query`, клиент получает исключение `Query was cancelled` вместо неполного результата. - -### Улучшения: - -* Запросы вида `ALTER TABLE ... DROP/DETACH PARTITION` выполняются впереди очереди репликации. -* Возможность использовать `SELECT ... FINAL` и `OPTIMIZE ... FINAL` даже в случае, если данные в таблице представлены одним куском. -* Пересоздание таблицы `query_log` налету в случае если было произведено её удаление вручную (Kirill Shvakov). -* Ускорение функции `lengthUTF8` (zhang2014). -* Улучшена производительность синхронной вставки в `Distributed` таблицы (`insert_distributed_sync = 1`) в случае очень большого количества шардов. -* Сервер принимает настройки `send_timeout` и `receive_timeout` от клиента и применяет их на своей стороне для соединения с клиентом (в переставленном порядке: `send_timeout` у сокета на стороне сервера выставляется в значение `receive_timeout` принятое от клиента, и наоборот). -* Более надёжное восстановление после сбоев при асинхронной вставке в `Distributed` таблицы. -* Возвращаемый тип функции `countEqual` изменён с `UInt32` на `UInt64` (谢磊) - -### Исправление ошибок: - -* Исправлена ошибка c `IN` где левая часть выражения `Nullable`. -* Исправлен неправильный результат при использовании кортежей с `IN` в случае, если часть компоненнтов кортежа есть в индексе таблицы. -* Исправлена работа ограничения `max_execution_time` с распределенными запросами. -* Исправлены ошибки при вычислении размеров составных столбцов в таблице `system.columns`. -* Исправлена ошибка при создании временной таблицы `CREATE TEMPORARY TABLE IF NOT EXISTS` -* Исправлены ошибки в `StorageKafka` (#2075) -* Исправлены падения сервера от некорректных аргументов некоторых аггрегатных функций. -* Исправлена ошибка, из-за которой запрос `DETACH DATABASE` мог не приводить к остановке фоновых задач таблицы типа `ReplicatedMergeTree`. -* Исправлена проблема с появлением `Too many parts` в агрегирующих материализованных представлениях (#2084). -* Исправлена рекурсивная обработка подстановок в конфиге, если после одной подстановки, требуется другая подстановка на том же уровне. -* Исправлена ошибка с неправильным синтаксисом в файле с метаданными при создании `VIEW`, использующих запрос с `UNION ALL`. -* Исправлена работа `SummingMergeTree` в случае суммирования вложенных структур данных с составным ключом. -* Исправлена возможность возникновения race condition при выборе лидера таблиц `ReplicatedMergeTree`. - -### Изменения сборки: - -* Поддержка `ninja` вместо `make` при сборке. `ninja` используется по-умолчанию при сборке релизов. -* Переименованы пакеты `clickhouse-server-base` в `clickhouse-common-static`; `clickhouse-server-common` в `clickhouse-server`; `clickhouse-common-dbg` в `clickhouse-common-static-dbg`. Для установки используйте `clickhouse-server clickhouse-client`. Для совместимости, пакеты со старыми именами продолжают загружаться в репозиторий. - -### Обратно несовместимые изменения: - -* Удалена специальная интерпретация выражения IN, если слева указан массив. Ранее выражение вида `arr IN (set)` воспринималось как "хотя бы один элемент `arr` принадлежит множеству `set`". Для получения такого же поведения в новой версии, напишите `arrayExists(x -> x IN (set), arr)`. -* Отключено ошибочное использование опции сокета `SO_REUSEPORT` (которая по ошибке включена по-умолчанию в библиотеке Poco). Стоит обратить внимание, что на Linux системах теперь не имеет смысла указывать одновременно адреса `::` и `0.0.0.0` для listen - следует использовать лишь адрес `::`, который (с настройками ядра по-умолчанию) позволяет слушать соединения как по IPv4 так и по IPv6. Также вы можете вернуть поведение старых версий, указав в конфиге `1`. - - -## ClickHouse release 1.1.54370, 2018-03-16 - -### Новые возможности: - -* Добавлена системная таблица `system.macros` и автоматическое обновление макросов при изменении конфигурационного файла. -* Добавлен запрос `SYSTEM RELOAD CONFIG`. -* Добавлена агрегатная функция `maxIntersections(left_col, right_col)`, возвращающая максимальное количество одновременно пересекающихся интервалов `[left; right]`. Функция `maxIntersectionsPosition(left, right)` возвращает начало такого "максимального" интервала. ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2012)). - -### Улучшения: - -* При вставке данных в `Replicated`-таблицу делается меньше обращений к `ZooKeeper` (также из лога `ZooKeeper` исчезло большинство user-level ошибок). -* Добавлена возможность создавать алиасы для множеств. Пример: `WITH (1, 2, 3) AS set SELECT number IN set FROM system.numbers LIMIT 10`. - -### Исправление ошибок: - -* Исправлена ошибка `Illegal PREWHERE` при чтении из Merge-таблицы над `Distributed`-таблицами. -* Добавлены исправления, позволяющие запускать clickhouse-server в IPv4-only docker-контейнерах. -* Исправлен race condition при чтении из системной таблицы `system.parts_columns` -* Убрана двойная буферизация при синхронной вставке в `Distributed`-таблицу, которая могла приводить к timeout-ам соединений. -* Исправлена ошибка, вызывающая чрезмерно долгое ожидание недоступной реплики перед началом выполнения `SELECT`. -* Исправлено некорректное отображение дат в таблице `system.parts`. -* Исправлена ошибка, приводящая к невозможности вставить данные в `Replicated`-таблицу, если в конфигурации кластера `ZooKeeper` задан непустой `chroot`. -* Исправлен алгоритм вертикального мержа при пустом ключе `ORDER BY` таблицы. -* Возвращена возможность использовать словари в запросах к удаленным таблицам, даже если этих словарей нет на сервере-инициаторе. Данная функциональность была потеряна в версии 1.1.54362. -* Восстановлено поведение, при котором в запросах типа `SELECT * FROM remote('server2', default.table) WHERE col IN (SELECT col2 FROM default.table)` в правой части `IN` должна использоваться удаленная таблица `default.table`, а не локальная. данное поведение было нарушено в версии 1.1.54358. -* Устранено ненужное Error-level логирование `Not found column ... in block`. - - -## Релиз ClickHouse 1.1.54362, 2018-03-11 - -### Новые возможности: - -* Агрегация без `GROUP BY` по пустому множеству (как например, `SELECT count(*) FROM table WHERE 0`) теперь возвращает результат из одной строки с нулевыми значениями агрегатных функций, в соответствии со стандартом SQL. Вы можете вернуть старое поведение (возвращать пустой результат), выставив настройку `empty_result_for_aggregation_by_empty_set` в значение 1. -* Добавлено приведение типов при `UNION ALL`. Допустимо использование столбцов с разными алиасами в соответствующих позициях `SELECT` в `UNION ALL`, что соответствует стандарту SQL. -* Поддержка произвольных выражений в секции `LIMIT BY`. Ранее было возможно лишь использование столбцов - результата `SELECT`. -* Использование индекса таблиц семейства `MergeTree` при наличии условия `IN` на кортеж от выражений от столбцов первичного ключа. Пример `WHERE (UserID, EventDate) IN ((123, '2000-01-01'), ...)` (Anastasiya Tsarkova). -* Добавлен инструмент `clickhouse-copier` для межкластерного копирования и перешардирования данных (бета). -* Добавлены функции консистентного хэширования `yandexConsistentHash`, `jumpConsistentHash`, `sumburConsistentHash`. Их можно использовать в качестве ключа шардирования для того, чтобы уменьшить объём сетевого трафика при последующих перешардированиях. -* Добавлены функции `arrayAny`, `arrayAll`, `hasAny`, `hasAll`, `arrayIntersect`, `arrayResize`. -* Добавлена функция `arrayCumSum` (Javi Santana). -* Добавлена функция `parseDateTimeBestEffort`, `parseDateTimeBestEffortOrZero`, `parseDateTimeBestEffortOrNull`, позволяющая прочитать DateTime из строки, содержащей текст в широком множестве возможных форматов. -* Возможность частичной перезагрузки данных внешних словарей при их обновлении (загрузка лишь записей со значением заданного поля большим, чем при предыдущей загрузке) (Arsen Hakobyan). -* Добавлена табличная функция `cluster`. Пример: `cluster(cluster_name, db, table)`. Табличная функция `remote` может принимать имя кластера в качестве первого аргумента, если оно указано в виде идентификатора. -* Возможность использования табличных функций `remote`, `cluster` в `INSERT` запросах. -* Добавлены виртуальные столбцы `create_table_query`, `engine_full` в таблице `system.tables`. Столбец `metadata_modification_time` сделан виртуальным. -* Добавлены столбцы `data_path`, `metadata_path` в таблицы `system.tables` и` system.databases`, а также столбец `path` в таблицы `system.parts` и `system.parts_columns`. -* Добавлена дополнительная информация о слияниях в таблице `system.part_log`. -* Возможность использования произвольного ключа партиционирования для таблицы `system.query_log` (Kirill Shvakov). -* Запрос `SHOW TABLES` теперь показывает также и временные таблицы. Добавлены временные таблицы и столбец `is_temporary` в таблице `system.tables` (zhang2014). -* Добавлен запрос `DROP TEMPORARY TABLE`, `EXISTS TEMPORARY TABLE` (zhang2014). -* Поддержка `SHOW CREATE TABLE` для временных таблиц (zhang2014). -* Добавлен конфигурационный параметр `system_profile` для настроек, используемых внутренними процессами. -* Поддержка загрузки `object_id` в качестве атрибута в словарях с источником `MongoDB` (Павел Литвиненко). -* Возможность читать `null` как значение по-умолчанию при загрузке данных для внешнего словаря с источником `MongoDB` (Павел Литвиненко). -* Возможность чтения значения типа `DateTime` в формате `Values` из unix timestamp без одинарных кавычек. -* Поддержан failover в табличной функции `remote` для случая, когда на части реплик отсутствует запрошенная таблица. -* Возможность переопределять параметры конфигурации в параметрах командной строки при запуске `clickhouse-server`, пример: `clickhouse-server -- --logger.level=information`. -* Реализована функция `empty` от аргумента типа `FixedString`: функция возвращает 1, если строка состоит полностью из нулевых байт (zhang2014). -* Добавлен конфигурационный параметр `listen_try`, позволяющий слушать хотя бы один из listen адресов и не завершать работу, если некоторые адреса не удаётся слушать (полезно для систем с выключенной поддержкой IPv4 или IPv6). -* Добавлен движок таблиц `VersionedCollapsingMergeTree`. -* Поддержка строк и произвольных числовых типов для источника словарей `library`. -* Возможность использования таблиц семейства `MergeTree` без первичного ключа (для этого необходимо указать `ORDER BY tuple()`). -* Добавлена возможность выполнить преобразование (`CAST`) `Nullable` типа в не `Nullable` тип, если аргумент не является `NULL`. -* Возможность выполнения `RENAME TABLE` для `VIEW`. -* Добавлена функция `throwIf`. -* Добавлена настройка `odbc_default_field_size`, позволяющая расширить максимальный размер значения, загружаемого из ODBC источника (по-умолчанию - 1024). -* В таблицу `system.processes` и в `SHOW PROCESSLIST` добавлены столбцы `is_cancelled` и `peak_memory_usage`. - -### Улучшения: - -* Ограничения на результат и квоты на результат теперь не применяются к промежуточным данным для запросов `INSERT SELECT` и для подзапросов в `SELECT`. -* Уменьшено количество ложных срабатываний при проверке состояния `Replicated` таблиц при запуске сервера, приводивших к необходимости выставления флага `force_restore_data`. -* Добавлена настройка `allow_distributed_ddl`. -* Запрещено использование недетерминированных функций в выражениях для ключей таблиц семейства `MergeTree`. -* Файлы с подстановками из `config.d` директорий загружаются в алфавитном порядке. -* Увеличена производительность функции `arrayElement` в случае константного многомерного массива с пустым массивом в качестве одного из элементов. Пример: `[[1], []][x]`. -* Увеличена скорость запуска сервера при использовании конфигурационных файлов с очень большими подстановками (например, очень большими списками IP-сетей). -* При выполнении запроса, табличные функции выполняются один раз. Ранее табличные функции `remote`, `mysql` дважды делали одинаковый запрос на получение структуры таблицы с удалённого сервера. -* Используется генератор документации `MkDocs`. -* При попытке удалить столбец таблицы, от которого зависят `DEFAULT`/`MATERIALIZED` выражения других столбцов, кидается исключение (zhang2014). -* Добавлена возможность парсинга пустой строки в текстовых форматах как числа 0 для `Float` типов данных. Эта возможность присутствовала раньше, но была потеряна в релизе 1.1.54342. -* Значения типа `Enum` можно использовать в функциях `min`, `max`, `sum` и некоторых других - в этих случаях используются соответствующие числовые значения. Эта возможность присутствовала ранее, но была потеряна в релизе 1.1.54337. -* Добавлено ограничение `max_expanded_ast_elements` действующее на размер AST после рекурсивного раскрытия алиасов. - -### Исправление ошибок: - -* Исправлены случаи ошибочного удаления ненужных столбцов из подзапросов, а также отсутствие удаления ненужных столбцов из подзапросов, содержащих `UNION ALL`. -* Исправлена ошибка в слияниях для таблиц типа `ReplacingMergeTree`. -* Исправлена работа синхронного режима вставки в `Distributed` таблицы (`insert_distributed_sync = 1`). -* Исправлены segfault при некоторых случаях использования `FULL` и `RIGHT JOIN` с дублирующимися столбцами в подзапросах. -* Исправлены segfault, которые могут возникать при использовании функциональности `replace_running_query` и `KILL QUERY`. -* Исправлен порядок столбцов `source` и `last_exception` в таблице `system.dictionaries`. -* Исправлена ошибка - запрос `DROP DATABASE` не удалял файл с метаданными. -* Исправлен запрос `DROP DATABASE` для базы данных типа `Dictionary`. -* Исправлена неоправданно низкая точность работы функций `uniqHLL12` и `uniqCombined` для кардинальностей больше 100 млн. элементов (Alex Bocharov). -* Исправлено вычисление неявных значений по-умолчанию при необходимости одновременного вычисления явных выражений по-умолчанию в запросах `INSERT` (zhang2014). -* Исправлен редкий случай, в котором запрос к таблице типа `MergeTree` мог не завершаться (chenxing-xc). -* Исправлено падение при выполнении запроса `CHECK` для `Distributed` таблиц, если все шарды локальные (chenxing.xc). -* Исправлена незначительная регрессия производительности при работе функций, использующих регулярные выражения. -* Исправлена регрессия производительности при создании многомерных массивов от сложных выражений. -* Исправлена ошибка, из-за которой в `.sql` файл с метаданными может записываться лишняя секция `FORMAT`. -* Исправлена ошибка, приводящая к тому, что ограничение `max_table_size_to_drop` действует при попытке удаления `MATERIALIZED VIEW`, смотрящего на явно указанную таблицу. -* Исправлена несовместимость со старыми клиентами (на старые клиенты могли отправляться данные с типом `DateTime('timezone')`, который они не понимают). -* Исправлена ошибка при чтении столбцов-элементов `Nested` структур, которые были добавлены с помощью `ALTER`, но являются пустыми для старых партиций, когда условия на такие столбцы переносятся в `PREWHERE`. -* Исправлена ошибка при фильтрации таблиц по условию на виртуальных столбец `_table` в запросах к таблицам типа `Merge`. -* Исправлена ошибка при использовании `ALIAS` столбцов в `Distributed` таблицах. -* Исправлена ошибка, приводящая к невозможности динамической компиляции запросов с агрегатными функциями из семейства `quantile`. -* Исправлен race condition в конвейере выполнения запроса, который мог проявляться в очень редких случаях при использовании `Merge` таблиц над большим количеством таблиц, а также при использовании `GLOBAL` подзапросов. -* Исправлено падение при передаче массивов разных размеров в функцию `arrayReduce` при использовании агрегатных функций от нескольких аргументов. -* Запрещено использование запросов с `UNION ALL` в `MATERIALIZED VIEW`. -* Исправлена ошибка, которая может возникать при инициализации системной таблицы `part_log` при старте сервера (по-умолчанию `part_log` выключен). - -### Обратно несовместимые изменения: - -* Удалена настройка `distributed_ddl_allow_replicated_alter`. Соответствующее поведение включено по-умолчанию. -* Удалена настройка `strict_insert_defaults`. Если вы использовали эту функциональность, напишите на `clickhouse-feedback@yandex-team.com`. -* Удалён движок таблиц `UnsortedMergeTree`. - -## Релиз ClickHouse 1.1.54343, 2018-02-05 - -* Добавлена возможность использовать макросы при задании имени кластера в распределенных DLL запросах и создании Distributed-таблиц: `CREATE TABLE distr ON CLUSTER '{cluster}' (...) ENGINE = Distributed('{cluster}', 'db', 'table')`. -* Теперь при вычислении запросов вида `SELECT ... FROM table WHERE expr IN (subquery)` используется индекс таблицы `table`. -* Улучшена обработка дубликатов при вставке в Replicated-таблицы, теперь они не приводят к излишнему замедлению выполнения очереди репликации. - -## Релиз ClickHouse 1.1.54342, 2018-01-22 - -Релиз содержит исправление к предыдущему релизу 1.1.54337: -* Исправлена регрессия в версии 1.1.54337: если пользователь по-умолчанию имеет readonly доступ, то сервер отказывался стартовать с сообщением `Cannot create database in readonly mode`. -* Исправлена регрессия в версии 1.1.54337: на системах под управлением systemd, логи по ошибке всегда записываются в syslog; watchdog скрипт по ошибке использует init.d. -* Исправлена регрессия в версии 1.1.54337: неправильная конфигурация по-умоланию в Docker образе. -* Исправлена недетерминированная работа GraphiteMergeTree (в логах видно по сообщениям `Data after merge is not byte-identical to data on another replicas`). -* Исправлена ошибка, в связи с которой запрос OPTIMIZE к Replicated таблицам мог приводить к неконсистентным мержам (в логах видно по сообщениям `Part ... intersects previous part`). -* Таблицы типа Buffer теперь работают при наличии MATERIALIZED столбцов в таблице назначения (by zhang2014). -* Исправлена одна из ошибок в реализации NULL. - -## Релиз ClickHouse 1.1.54337, 2018-01-18 - -### Новые возможности: - -* Добавлена поддержка хранения многомерных массивов и кортежей (тип данных `Tuple`) в таблицах. -* Поддержка табличных функций для запросов `DESCRIBE` и `INSERT`. Поддержка подзапроса в запросе `DESCRIBE`. Примеры: `DESC TABLE remote('host', default.hits)`; `DESC TABLE (SELECT 1)`; `INSERT INTO TABLE FUNCTION remote('host', default.hits)`. Возможность писать `INSERT INTO TABLE` вместо `INSERT INTO`. -* Улучшена поддержка часовых поясов. В типе `DateTime` может быть указана таймзона, которая используется для парсинга и отображения данных в текстовом виде. Пример: `DateTime('Europe/Moscow')`. При указании таймзоны в функциях работы с `DateTime`, тип возвращаемого значения будет запоминать таймзону, для того, чтобы значение отображалось ожидаемым образом. -* Добавлены функции `toTimeZone`, `timeDiff`, `toQuarter`, `toRelativeQuarterNum`. В функцию `toRelativeHour`/`Minute`/`Second` можно передать аргумент типа `Date`. Имя функции `now` воспринимается без учёта регистра. -* Добавлена функция `toStartOfFifteenMinutes` (Kirill Shvakov). -* Добавлена программа `clickhouse format` для переформатирования запросов. -* Добавлен конфигурационный параметр `format_schema_path` (Marek Vavruša). Он используется для задания схемы для формата `Cap'n'Proto`. Файлы со схемой могут использоваться только из указанной директории. -* Добавлена поддержка `incl` и `conf.d` подстановок для конфигурации словарей и моделей (Pavel Yakunin). -* В таблице `system.settings` появилось описание большинства настроек (Kirill Shvakov). -* Добавлена таблица `system.parts_columns`, содержащая информацию о размерах столбцов в каждом куске данных `MergeTree` таблиц. -* Добавлена таблица `system.models`, содержащая информацию о загруженных моделях `CatBoost`. -* Добавлены табличные функции `mysql` и `odbc` и соответствующие движки таблиц `MySQL`, `ODBC` для обращения к удалённым базам данных. Функциональность в состоянии "бета". -* Для функции `groupArray` разрешено использование аргументов типа `AggregateFunction` (можно создать массив из состояний агрегатных функций). -* Удалены ограничения на использование разных комбинаций комбинаторов агрегатных функций. Для примера, вы можете использовать как функцию `avgForEachIf`, так и `avgIfForEach`, которые имеют разный смысл. -* Комбинатор агрегатных функций `-ForEach` расширен для случая агрегатных функций с более чем одним аргументом. -* Добавлена поддержка агрегатных функций от `Nullable` аргументов, для случаев, когда функция всегда возвращает не `Nullable` результат (реализовано с участием Silviu Caragea). Пример: `groupArray`, `groupUniqArray`, `topK`. -* Добавлен параметр командной строки `max_client_network_bandwidth` для `clickhouse-client` (Kirill Shvakov). -* Пользователям с доступом `readonly = 2` разрешено работать с временными таблицами (CREATE, DROP, INSERT...) (Kirill Shvakov). -* Добавлена возможность указания количества consumers для `Kafka`. Расширена возможность конфигурации движка `Kafka` (Marek Vavruša). -* Добавлены функции `intExp2`, `intExp10`. -* Добавлена агрегатная функция `sumKahan`. -* Добавлены функции to*Number*OrNull, где *Number* - числовой тип. -* Добавлена поддержка секции `WITH` для запроса `INSERT SELECT` (автор: zhang2014). -* Добавлены настройки `http_connection_timeout`, `http_send_timeout`, `http_receive_timeout`. Настройки используются, в том числе, при скачивании кусков для репликации. Изменение этих настроек позволяет сделать более быстрый failover в случае перегруженной сети. -* Добавлена поддержка `ALTER` для таблиц типа `Null` (Anastasiya Tsarkova). -* Функция `reinterpretAsString` расширена на все типы данных, значения которых хранятся в памяти непрерывно. -* Для программы `clickhouse-local` добавлена опция `--silent` для подавления вывода информации о выполнении запроса в stderr. -* Добавлена поддержка чтения `Date` в текстовом виде в формате, где месяц и день месяца могут быть указаны одной цифрой вместо двух (Amos Bird). - -### Увеличение производительности: - -* Увеличена производительность агрегатных функций `min`, `max`, `any`, `anyLast`, `anyHeavy`, `argMin`, `argMax` от строковых аргументов. -* Увеличена производительность функций `isInfinite`, `isFinite`, `isNaN`, `roundToExp2`. -* Увеличена производительность форматирования в текстовом виде и парсинга из текста значений типа `Date` и `DateTime`. -* Увеличена производительность и точность парсинга чисел с плавающей запятой. -* Уменьшено потребление памяти при `JOIN`, если левая и правая часть содержали столбцы с одинаковым именем, не входящие в `USING`. -* Увеличена производительность агрегатных функций `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, `corr` за счёт уменьшения стойкости к вычислительной погрешности. Старые версии функций добавлены под именами `varSampStable`, `varPopStable`, `stddevSampStable`, `stddevPopStable`, `covarSampStable`, `covarPopStable`, `corrStable`. - -### Исправления ошибок: - -* Исправлена работа дедупликации блоков после `DROP` или `DETATH PARTITION`. Раньше удаление партиции и вставка тех же самых данных заново не работала, так как вставленные заново блоки считались дубликатами. -* Исправлена ошибка, в связи с которой может неправильно обрабатываться `WHERE` для запросов на создание `MATERIALIZED VIEW` с указанием `POPULATE`. -* Исправлена ошибка в работе параметра `root_path` в конфигурации `zookeeper_servers`. -* Исправлен неожиданный результат при передаче аргумента типа `Date` в функцию `toStartOfDay`. -* Исправлена работа функции `addMonths`, `subtractMonths`, арифметика с `INTERVAL n MONTH`, если в результате получается предыдущий год. -* Добавлена недостающая поддержка типа данных `UUID` для `DISTINCT`, `JOIN`, в агрегатных функциях `uniq` и во внешних словарях (Иванов Евгений). Поддержка `UUID` всё ещё остаётся не полной. -* Исправлено поведение `SummingMergeTree` для строк, в которых все значения после суммирования равны нулю. -* Многочисленные доработки для движка таблиц `Kafka` (Marek Vavruša). -* Исправлена некорректная работа движка таблиц `Join` (Amos Bird). -* Исправлена работа аллокатора под FreeBSD и OS X. -* Функция `extractAll` теперь может доставать пустые вхождения. -* Исправлена ошибка, не позволяющая подключить при сборке `libressl` вместо `openssl`. -* Исправлена работа `CREATE TABLE AS SELECT` из временной таблицы. -* Исправлена неатомарность обновления очереди репликации. Эта проблема могла приводить к рассинхронизации реплик и чинилась при перезапуске. -* Исправлено переполнение в функциях `gcd`, `lcm`, `modulo` (оператор `%`) (Maks Skorokhod). -* Файлы `-preprocessed` теперь создаются после изменения `umask` (`umask` может быть задан в конфигурационном файле). -* Исправлена ошибка фоновой проверки кусков (`MergeTreePartChecker`) при использовании партиционирования по произвольному ключу. -* Исправлен парсинг кортежей (значений типа `Tuple`) в текстовых форматах. -* Исправлены сообщения о неподходящих типах аргументов для функций `multiIf`, `array` и некоторых других. -* Переработана поддержка `Nullable` типов. Исправлены ошибки, которые могут приводить к падению сервера. Исправлено подавляющее большинство других ошибок, связанных с поддержкой `NULL`: неправильное приведение типов при INSERT SELECT, недостаточная поддержка Nullable в HAVING и в PREWHERE, режим `join_use_nulls`, Nullable типы в операторе `OR` и т. п. -* Исправлена работа с внутренними свойствами типов данных, что позволило исправить проблемы следующего вида: ошибочное суммирование полей типа `Enum` в `SummingMergeTree`; значения типа `Enum` ошибочно выводятся с выравниванием по правому краю в таблицах в `Pretty` форматах, и т. п. -* Более строгие проверки для допустимых комбинаций составных столбцов - это позволило исправить ошибок, которые могли приводить к падениям. -* Исправлено переполнение при задании очень большого значения параметра для типа `FixedString`. -* Исправлена работа агрегатной функции `topK` для generic случая. -* Добавлена отсутствующая проверка на совпадение размеров массивов для n-арных вариантов агрегатных функций с комбинатором `-Array`. -* Исправлена работа `--pager` для `clickhouse-client` (автор: ks1322). -* Исправлена точность работы функции `exp10`. -* Исправлено поведение функции `visitParamExtract` согласно документации. -* Исправлено падение при объявлении некорректных типов данных. -* Исправлена работа `DISTINCT` при условии, что все столбцы константные. -* Исправлено форматирование запроса в случае наличия функции `tupleElement` со сложным константным выражением в качестве номера элемента. -* Исправлена работа `Dictionary` таблиц для словарей типа `range_hashed`. -* Исправлена ошибка, приводящая к появлению лишних строк при `FULL` и `RIGHT JOIN` (Amos Bird). -* Исправлено падение сервера в случае создания и удаления временных файлов в `config.d` директориях в момент перечитывания конфигурации. -* Исправлена работа запроса `SYSTEM DROP DNS CACHE`: ранее сброс DNS кэша не приводил к повторному резолвингу имён хостов кластера. -* Исправлено поведение `MATERIALIZED VIEW` после `DETACH TABLE` таблицы, на которую он смотрит (Marek Vavruša). - -### Улучшения сборки: - -* Для сборки используется `pbuilder`. Сборка максимально независима от окружения на сборочной машине. -* Для разных версий систем выкладывается один и тот же пакет, который совместим с широким диапазоном Linux систем. -* Добавлен пакет `clickhouse-test`, который может быть использован для запуска функциональных тестов. -* Добавлена выкладка в репозиторий архива с исходниками. Этот архив может быть использован для воспроизведения сборки без использования GitHub. -* Добавлена частичная интеграция с Travis CI. В связи с ограничениями на время сборки в Travis, запускается только ограниченный набор тестов на Debug сборке. -* Добавлена поддержка `Cap'n'Proto` в сборку по-умолчанию. -* Документация переведена с `Restructured Text` на `Markdown`. -* Добавлена поддержка `systemd` (Vladimir Smirnov). В связи с несовместимостью с некоторыми образами, она выключена по-умолчанию и может быть включена вручную. -* Для динамической компиляции запросов, `clang` и `lld` встроены внутрь `clickhouse`. Они также могут быть вызваны с помощью `clickhouse clang` и `clickhouse lld`. -* Удалено использование расширений GNU из кода и включена опция `-Wextra`. При сборке с помощью `clang` по-умолчанию используется `libc++` вместо `libstdc++`. -* Выделены библиотеки `clickhouse_parsers` и `clickhouse_common_io` для более быстрой сборки утилит. - -### Обратно несовместимые изменения: - -* Формат засечек (marks) для таблиц типа `Log`, содержащих `Nullable` столбцы, изменён обратно-несовместимым образом. В случае наличия таких таблиц, вы можете преобразовать их в `TinyLog` до запуска новой версии сервера. Для этого в соответствующем таблице файле `.sql` в директории `metadata`, замените `ENGINE = Log` на `ENGINE = TinyLog`. Если в таблице нет `Nullable` столбцов или тип таблицы не `Log`, то ничего делать не нужно. -* Удалена настройка `experimental_allow_extended_storage_definition_syntax`. Соответствующая функциональность включена по-умолчанию. -* Функция `runningIncome` переименована в `runningDifferenceStartingWithFirstValue` во избежание путаницы. -* Удалена возможность написания `FROM ARRAY JOIN arr` без указания таблицы после FROM (Amos Bird). -* Удалён формат `BlockTabSeparated`, использовавшийся лишь для демонстрационных целей. -* Изменён формат состояния агрегатных функций `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, `corr`. Если вы использовали эти состояния для хранения в таблицах (тип данных `AggregateFunction` от этих функций или материализованные представления, хранящие эти состояния), напишите на clickhouse-feedback@yandex-team.com. -* В предыдущих версиях существовала недокументированная возможность: в типе данных AggregateFunction можно было не указывать параметры для агрегатной функции, которая зависит от параметров. Пример: `AggregateFunction(quantiles, UInt64)` вместо `AggregateFunction(quantiles(0.5, 0.9), UInt64)`. Эта возможность потеряна. Не смотря на то, что возможность не документирована, мы собираемся вернуть её в ближайших релизах. -* Значения типа данных Enum не могут быть переданы в агрегатные функции min/max. Возможность будет возвращена обратно в следующем релизе. - -### На что обратить внимание при обновлении: -* При обновлении кластера, на время, когда на одних репликах работает новая версия сервера, а на других - старая, репликация будет приостановлена и в логе появятся сообщения вида `unknown parameter 'shard'`. Репликация продолжится после обновления всех реплик кластера. -* Если на серверах кластера работают разные версии ClickHouse, то возможен неправильный результат распределённых запросов, использующих функции `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, `corr`. Необходимо обновить все серверы кластера. - -## Релиз ClickHouse 1.1.54327, 2017-12-21 - -Релиз содержит исправление к предыдущему релизу 1.1.54318: -* Исправлена проблема с возможным race condition при репликации, которая может приводить к потере данных. Проблеме подвержены версии 1.1.54310 и 1.1.54318. Если вы их используете и у вас есть Replicated таблицы, то обновление обязательно. Понять, что эта проблема существует, можно по сообщениям в логе Warning вида `Part ... from own log doesn't exist.` Даже если таких сообщений нет, проблема всё-равно актуальна. - -## Релиз ClickHouse 1.1.54318, 2017-11-30 - -Релиз содержит изменения к предыдущему релизу 1.1.54310 с исправлением следующих багов: -* Исправлено некорректное удаление строк при слияниях в движке SummingMergeTree -* Исправлена утечка памяти в нереплицированных MergeTree-движках -* Исправлена деградация производительности при частых вставках в MergeTree-движках -* Исправлена проблема, приводящая к остановке выполнения очереди репликации -* Исправлено ротирование и архивация логов сервера - -## Релиз ClickHouse 1.1.54310, 2017-11-01 - -### Новые возможности: -* Произвольный ключ партиционирования для таблиц семейства MergeTree. -* Движок таблиц [Kafka](https://clickhouse.yandex/docs/en/operations/table_engines/kafka/). -* Возможность загружать модели [CatBoost](https://catboost.yandex/) и применять их к данным, хранящимся в ClickHouse. -* Поддержка часовых поясов с нецелым смещением от UTC. -* Поддержка операций с временными интервалами. -* Диапазон значений типов Date и DateTime расширен до 2105 года. -* Запрос `CREATE MATERIALIZED VIEW x TO y` (позволяет указать существующую таблицу для хранения данных материализованного представления). -* Запрос `ATTACH TABLE` без аргументов. -* Логика обработки Nested-столбцов в SummingMergeTree, заканчивающихся на -Map, вынесена в агрегатную функцию sumMap. Такие столбцы теперь можно задавать явно. -* Максимальный размер IP trie-словаря увеличен до 128М записей. -* Функция getSizeOfEnumType. -* Агрегатная функция sumWithOverflow. -* Поддержка входного формата Cap’n Proto. -* Возможность задавать уровень сжатия при использовании алгоритма zstd. - -### Обратно несовместимые изменения: -* Запрещено создание временных таблиц с движком, отличным от Memory. -* Запрещено явное создание таблиц с движком View и MaterializedView. -* При создании таблицы теперь проверяется, что ключ сэмплирования входит в первичный ключ. - -### Исправления ошибок: -* Исправлено зависание при синхронной вставке в Distributed таблицу. -* Исправлена неатомарность при добавлении/удалении кусков в реплицированных таблицах. -* Данные, вставляемые в материализованное представление, теперь не подвергаются излишней дедупликации. -* Запрос в Distributed таблицу, для которого локальная реплика отстаёт, а удалённые недоступны, теперь не падает. -* Для создания временных таблиц теперь не требуется прав доступа к БД `default`. -* Исправлено падение при указании типа Array без аргументов. -* Исправлено зависание при недостатке места на диске в разделе с логами. -* Исправлено переполнение в функции toRelativeWeekNum для первой недели Unix-эпохи. - -### Улучшения сборки: -* Несколько сторонних библиотек (в частности, Poco) обновлены и переведены на git submodules. - -## Релиз ClickHouse 1.1.54304, 2017-10-19 -### Новые возможности: -* Добавлена поддержка TLS в нативном протоколе (включается заданием `tcp_ssl_port` в `config.xml`) - -### Исправления ошибок: -* `ALTER` для реплицированных таблиц теперь пытается начать выполнение как можно быстрее -* Исправлены падения при чтении данных с настройкой `preferred_block_size_bytes=0` -* Исправлено падение `clickhouse-client` при нажатии `Page Down` -* Корректная интепретация некоторых сложных запросов с `GLOBAL IN` и `UNION ALL` -* Операция `FREEZE PARTITION` теперь работает всегда атомарно -* Исправлено зависание пустых POST-запросов (теперь возвращается код 411) -* Исправлены ошибки при интепретации выражений типа `CAST(1 AS Nullable(UInt8))` -* Исправлена ошибка при чтении колонок типа `Array(Nullable(String))` из `MergeTree` таблиц -* Исправлено падение при парсинге запросов типа `SELECT dummy AS dummy, dummy AS b` -* Корректное обновление пользователей при невалидном `users.xml` -* Корректная обработка случаев, когда executable-словарь возвращает ненулевой код ответа - -## Релиз ClickHouse 1.1.54292, 2017-09-20 - -### Новые возможности: -* Добавлена функция `pointInPolygon` для работы с координатами на плоскости. -* Добавлена агрегатная функция `sumMap`, обеспечивающая суммирование массивов аналогично `SummingMergeTree`. -* Добавлена функция `trunc`. Увеличена производительность функций округления `round`, `floor`, `ceil`, `roundToExp2`. Исправлена логика работы функций округления. Изменена логика работы функции `roundToExp2` для дробных и отрицательных чисел. -* Ослаблена зависимость исполняемого файла ClickHouse от версии libc. Один и тот же исполняемый файл ClickHouse может запускаться и работать на широком множестве Linux систем. Замечание: зависимость всё ещё присутствует при использовании скомпилированных запросов (настройка `compile = 1`, по-умолчанию не используется). -* Уменьшено время динамической компиляции запросов. - -### Исправления ошибок: -* Исправлена ошибка, которая могла приводить к сообщениям `part ... intersects previous part` и нарушению консистентности реплик. -* Исправлена ошибка, приводящая к блокировке при завершении работы сервера, если в это время ZooKeeper недоступен. -* Удалено избыточное логгирование при восстановлении реплик. -* Исправлена ошибка в реализации UNION ALL. -* Исправлена ошибка в функции concat, возникающая в случае, если первый столбец блока имеет тип Array. -* Исправлено отображение прогресса в таблице system.merges. - -## Релиз ClickHouse 1.1.54289, 2017-09-13 - -### Новые возможности: -* Запросы `SYSTEM` для административных действий с сервером: `SYSTEM RELOAD DICTIONARY`, `SYSTEM RELOAD DICTIONARIES`, `SYSTEM DROP DNS CACHE`, `SYSTEM SHUTDOWN`, `SYSTEM KILL`. -* Добавлены функции для работы с массивами: `concat`, `arraySlice`, `arrayPushBack`, `arrayPushFront`, `arrayPopBack`, `arrayPopFront`. -* Добавлены параметры `root` и `identity` для конфигурации ZooKeeper. Это позволяет изолировать разных пользователей одного ZooKeeper кластера. -* Добавлены агрегатные функции `groupBitAnd`, `groupBitOr`, `groupBitXor` (для совместимости доступны также под именами `BIT_AND`, `BIT_OR`, `BIT_XOR`). -* Возможность загрузки внешних словарей из MySQL с указанием сокета на файловой системе. -* Возможность загрузки внешних словарей из MySQL через SSL соединение (параметры `ssl_cert`, `ssl_key`, `ssl_ca`). -* Добавлена настройка `max_network_bandwidth_for_user` для ограничения общего потребления сети для всех запросов одного пользователя. -* Поддержка `DROP TABLE` для временных таблиц. -* Поддержка чтения значений типа `DateTime` в формате unix timestamp из форматов `CSV` и `JSONEachRow`. -* Включено по-умолчанию отключение отстающих реплик при распределённых запросах (по-умолчанию порог равен 5 минутам). -* Используются FIFO блокировки при ALTER: выполнение ALTER не будет неограниченно блокироваться при непрерывно выполняющихся запросах. -* Возможность задать `umask` в конфигурационном файле. -* Увеличена производительность запросов с `DISTINCT`. - -### Исправления ошибок: -* Более оптимальная процедура удаления старых нод в ZooKeeper. Ранее в случае очень частых вставок, старые ноды могли не успевать удаляться, что приводило, в том числе, к очень долгому завершению сервера. -* Исправлена рандомизация при выборе хостов для соединения с ZooKeeper. -* Исправлено отключение отстающей реплики при распределённых запросах, если реплика является localhost. -* Исправлена ошибка, в связи с которой кусок данных таблицы типа `ReplicatedMergeTree` мог становиться битым после выполнения `ALTER MODIFY` элемента `Nested` структуры. -* Исправлена ошибка приводящая к возможному зависанию SELECT запросов. -* Доработки распределённых DDL запросов. -* Исправлен запрос `CREATE TABLE ... AS `. -* Исправлен дедлок при запросе `ALTER ... CLEAR COLUMN IN PARTITION` для `Buffer` таблиц. -* Исправлено использование неправильного значения по-умолчанию для `Enum`-ов (0 вместо минимального) при использовании форматов `JSONEachRow` и `TSKV`. -* Исправлено появление zombie процессов при работе со словарём с источником `executable`. -* Исправлен segfault при запросе HEAD. - -### Улучшения процесса разработки и сборки ClickHouse: -* Возможность сборки с помощью `pbuilder`. -* Возможность сборки с использованием `libc++` вместо `libstdc++` под Linux. -* Добавлены инструкции для использования статических анализаторов кода `Coverity`, `clang-tidy`, `cppcheck`. - -### На что обратить внимание при обновлении: -* Увеличено значение по-умолчанию для настройки MergeTree `max_bytes_to_merge_at_max_space_in_pool` (максимальный суммарный размер кусков в байтах для мержа) со 100 GiB до 150 GiB. Это может привести к запуску больших мержей после обновления сервера, что может вызвать повышенную нагрузку на дисковую подсистему. Если же на серверах, где это происходит, количество свободного места менее чем в два раза больше суммарного объёма выполняющихся мержей, то в связи с этим перестанут выполняться какие-либо другие мержи, включая мержи мелких кусков. Это приведёт к тому, что INSERT-ы будут отклоняться с сообщением "Merges are processing significantly slower than inserts". Для наблюдения, используйте запрос `SELECT * FROM system.merges`. Вы также можете смотреть на метрику `DiskSpaceReservedForMerge` в таблице `system.metrics` или в Graphite. Для исправления этой ситуации можно ничего не делать, так как она нормализуется сама после завершения больших мержей. Если же вас это не устраивает, вы можете вернуть настройку `max_bytes_to_merge_at_max_space_in_pool` в старое значение, прописав в config.xml в секции `` `107374182400` и перезапустить сервер. - -## Релиз ClickHouse 1.1.54284, 2017-08-29 - -* Релиз содержит изменения к предыдущему релизу 1.1.54282, которые исправляют утечку записей о кусках в ZooKeeper - -## Релиз ClickHouse 1.1.54282, 2017-08-23 - -Релиз содержит исправления к предыдущему релизу 1.1.54276: -* Исправлена ошибка `DB::Exception: Assertion violation: !_path.empty()` при вставке в Distributed таблицу. -* Исправлен парсинг при вставке в формате RowBinary, если входные данные начинаются с ';'. -* Исправлена ошибка при рантайм-компиляции некоторых агрегатных функций (например, `groupArray()`). - -## Релиз ClickHouse 1.1.54276, 2017-08-16 - -### Новые возможности: -* Добавлена опциональная секция WITH запроса SELECT. Пример запроса: `WITH 1+1 AS a SELECT a, a*a` -* Добавлена возможность синхронной вставки в Distributed таблицу: выдается Ok только после того как все данные записались на все шарды. Активируется настройкой insert_distributed_sync=1 -* Добавлен тип данных UUID для работы с 16-байтовыми идентификаторами -* Добавлены алиасы типов CHAR, FLOAT и т.д. для совместимости с Tableau -* Добавлены функции toYYYYMM, toYYYYMMDD, toYYYYMMDDhhmmss для перевода времени в числа -* Добавлена возможность использовать IP адреса (совместно с hostname) для идентификации сервера при работе с кластерными DDL запросами -* Добавлена поддержка неконстантных аргументов и отрицательных смещений в функции `substring(str, pos, len)` -* Добавлен параметр max_size для агрегатной функции `groupArray(max_size)(column)`, и оптимизирована её производительность - -### Основные изменения: -* Улучшение безопасности: все файлы сервера создаются с правами 0640 (можно поменять, через параметр в конфиге). -* Улучшены сообщения об ошибках в случае синтаксически неверных запросов -* Значительно уменьшен расход оперативной памяти и улучшена производительность слияний больших MergeTree-кусков данных -* Значительно увеличена производительность слияний данных для движка ReplacingMergeTree -* Улучшена производительность асинхронных вставок из Distributed таблицы за счет объединения нескольких исходных вставок. Функциональность включается настройкой distributed_directory_monitor_batch_inserts=1. - -### Обратно несовместимые изменения: -* Изменился бинарный формат агрегатных состояний функции `groupArray(array_column)` для массивов - -### Полный список изменений: -* Добавлена настройка `output_format_json_quote_denormals`, включающая вывод nan и inf значений в формате JSON -* Более оптимальное выделение потоков при чтении из Distributed таблиц -* Разрешено задавать настройки в режиме readonly, если их значение не изменяется -* Добавлена возможность считывать нецелые гранулы движка MergeTree для выполнения ограничений на размер блока, задаваемый настройкой preferred_block_size_bytes - для уменьшения потребления оперативной памяти и увеличения кэш-локальности при обработке запросов из таблиц со столбцами большого размера -* Эффективное использование индекса, содержащего выражения типа `toStartOfHour(x)`, для условий вида `toStartOfHour(x) op сonstexpr` -* Добавлены новые настройки для MergeTree движков (секция merge_tree в config.xml): - - replicated_deduplication_window_seconds позволяет задать интервал дедупликации вставок в Replicated-таблицы в секундах - - cleanup_delay_period - периодичность запуска очистки неактуальных данных - - replicated_can_become_leader - запретить реплике становиться лидером (и назначать мержи) -* Ускорена очистка неактуальных данных из ZooKeeper -* Множественные улучшения и исправления работы кластерных DDL запросов. В частности, добавлена настройка distributed_ddl_task_timeout, ограничивающая время ожидания ответов серверов кластера. Если запрос не успел выполниться на всех нодах в установленное время, ответ будет содержать timeout ошибку и дальнейшее выполнение этого запроса будет происходить в асинхронном режиме -* Улучшено отображение стэктрейсов в логах сервера -* Добавлен метод сжатия none -* Возможность использования нескольких секций dictionaries_config в config.xml -* Возможность подключения к MySQL через сокет на файловой системе -* В таблицу system.parts добавлен столбец с информацией о размере marks в байтах - -### Исправления багов: -* Исправлена некорректная работа Distributed таблиц, использующих Merge таблицы, при SELECT с условием на поле _table -* Исправлен редкий race condition в ReplicatedMergeTree при проверке кусков данных -* Исправлено возможное зависание процедуры leader election при старте сервера -* Исправлено игнорирование настройки max_replica_delay_for_distributed_queries при использовании локальной реплики в качестве источника данных -* Исправлено некорректное поведение `ALTER TABLE CLEAR COLUMN IN PARTITION` при попытке очистить несуществующую колонку -* Исправлено исключение в функции multiIf при использовании пустых массивов или строк -* Исправлено чрезмерное выделение памяти при десериализации формата Native -* Исправлено некорректное автообновление Trie словарей -* Исправлено исключение при выполнении запросов с GROUP BY из Merge-таблицы при использовании SAMPLE -* Исправлено падение GROUP BY при использовании настройки distributed_aggregation_memory_efficient=1 -* Добавлена возможность указывать database.table в правой части IN и JOIN -* Исправлено использование слишком большого количества потоков при параллельной агрегации -* Исправлена работа функции if с аргументами FixedString -* Исправлена некорректная работа SELECT из Distributed-таблицы для шардов с весом 0 -* Исправлено падение запроса `CREATE VIEW IF EXISTS` -* Исправлено некорректное поведение при input_format_skip_unknown_fields=1 в случае отрицательных чисел -* Исправлен бесконечный цикл в функции `dictGetHierarchy()` в случае некоторых некорректных данных словаря -* Исправлены ошибки типа `Syntax error: unexpected (...)` при выполнении распределенных запросов с подзапросами в секции IN или JOIN, в случае использования совместно с Merge таблицами -* Исправлена неправильная интерпретация SELECT запроса из таблиц типа Dictionary -* Исправлена ошибка "Cannot mremap" при использовании множеств в секциях IN, JOIN, содержащих более 2 млрд. элементов -* Исправлен failover для словарей с источником MySQL - -### Улучшения процесса разработки и сборки ClickHouse: -* Добавлена возмозможность сборки в Arcadia -* Добавлена возможность сборки с помощью gcc 7 -* Ускорена параллельная сборка с помощью ccache+distcc - - -## Релиз ClickHouse 1.1.54245, 2017-07-04 - -### Новые возможности: -* Распределённые DDL (например, `CREATE TABLE ON CLUSTER`) -* Реплицируемый запрос `ALTER TABLE CLEAR COLUMN IN PARTITION` -* Движок таблиц Dictionary (доступ к данным словаря в виде таблицы) -* Движок баз данных Dictionary (в такой базе автоматически доступны Dictionary-таблицы для всех подключённых внешних словарей) -* Возможность проверки необходимости обновления словаря путём отправки запроса в источник -* Qualified имена столбцов -* Квотирование идентификаторов двойными кавычками -* Сессии в HTTP интерфейсе -* Запрос OPTIMIZE для Replicated таблицы теперь можно выполнять не только на лидере - -### Обратно несовместимые изменения: -* Убрана команда SET GLOBAL - -### Мелкие изменения: -* Теперь после получения сигнала в лог печатается полный стектрейс -* Ослаблена проверка на количество повреждённых/лишних кусков при старте (было слишком много ложных срабатываний) - -### Исправления багов: -* Исправлено залипание плохого соединения при вставке в Distributed таблицу -* GLOBAL IN теперь работает при запросе из таблицы Merge, смотрящей в Distributed -* Теперь правильно определяется количество ядер на виртуалках Google Compute Engine -* Исправления в работе executable источника кэшируемых внешних словарей -* Исправлены сравнения строк, содержащих нулевые символы -* Исправлено сравнение полей первичного ключа типа Float32 с константами -* Раньше неправильная оценка размера поля могла приводить к слишком большим аллокациям -* Исправлено падение при запросе Nullable столбца, добавленного в таблицу ALTER-ом -* Исправлено падение при сортировке по Nullable столбцу, если количество строк меньше LIMIT -* Исправлен ORDER BY подзапроса, состоящего только из константных значений -* Раньше Replicated таблица могла остаться в невалидном состоянии после неудавшегося DROP TABLE -* Алиасы для скалярных подзапросов с пустым результатом теперь не теряются -* Теперь запрос, в котором использовалась компиляция, не завершается ошибкой, если .so файл повреждается From ecb25067a5c50f95b00ff7418b00d6457ccc045f Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Tue, 6 Aug 2019 13:32:07 +0300 Subject: [PATCH 093/105] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f10e8da9d7b..f9c461e63e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Fixed the possibility of hanging queries when server is overloaded. [#6301](https://github.com/yandex/ClickHouse/pull/6301) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Fix FPE in yandexConsistentHash function. This fixes [#6304](https://github.com/yandex/ClickHouse/issues/6304). [#6126](https://github.com/yandex/ClickHouse/pull/6126) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Fixed bug in conversion of `LowCardinality` types in `AggregateFunctionFactory`. This fixes [#6257](https://github.com/yandex/ClickHouse/issues/6257). [#6281](https://github.com/yandex/ClickHouse/pull/6281) ([Nikolai Kochetov](https://github.com/KochetovNicolai)) -* Fix parsing of `bool` settings from `true` and `false` strings. [#6278](https://github.com/yandex/ClickHouse/pull/6278) ([alesapin](https://github.com/alesapin)) +* Fix parsing of `bool` settings from `true` and `false` strings in configuration files. [#6278](https://github.com/yandex/ClickHouse/pull/6278) ([alesapin](https://github.com/alesapin)) * Fix rare bug with incompatible stream headers in queries to `Distributed` table over `MergeTree` table when part of `WHERE` moves to `PREWHERE`. [#6236](https://github.com/yandex/ClickHouse/pull/6236) ([alesapin](https://github.com/alesapin)) * Fixed overflow in integer division of signed type to unsigned type. This fixes [#6214](https://github.com/yandex/ClickHouse/issues/6214). [#6233](https://github.com/yandex/ClickHouse/pull/6233) ([alexey-milovidov](https://github.com/alexey-milovidov)) From ffb053aa5f16022acb327695634c3dfeaa7ca144 Mon Sep 17 00:00:00 2001 From: chertus Date: Tue, 6 Aug 2019 14:15:48 +0300 Subject: [PATCH 094/105] add test for crash described in #5859 --- .../00980_full_join_crash_fancyqlx.reference | 5 +++++ .../00980_full_join_crash_fancyqlx.sql | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.reference create mode 100644 dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.sql diff --git a/dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.reference b/dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.reference new file mode 100644 index 00000000000..5399cf08165 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.reference @@ -0,0 +1,5 @@ +1 2019-01-01 a +1 2019-01-01 \N +1 2019-01-01 \N +2 2019-01-01 b +3 2019-01-01 c diff --git a/dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.sql b/dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.sql new file mode 100644 index 00000000000..2514b6ded1b --- /dev/null +++ b/dbms/tests/queries/0_stateless/00980_full_join_crash_fancyqlx.sql @@ -0,0 +1,15 @@ +drop table if exists test_join; + +create table test_join (date Date, id Int32, name Nullable(String)) engine = MergeTree partition by date order by id; + +insert into test_join values ('2019-01-01', 1, 'a'); +insert into test_join values ('2019-01-01', 2, 'b'); +insert into test_join values ('2019-01-01', 3, 'c'); +insert into test_join values ('2019-01-01', 1, null); + +SELECT id, date, name FROM (SELECT id, date, name FROM test_join GROUP BY id, name, date) +FULL OUTER JOIN (SELECT id, date, name FROM test_join GROUP BY id, name, date) +USING (id, name, date) +ORDER BY id, name; + +drop table test_join; From 19e11d6300741a6d222394c0118e126bb3101bc2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 6 Aug 2019 16:19:08 +0300 Subject: [PATCH 095/105] Updated changelog in docs --- docs/fa/changelog.md | 2 +- docs/ru/changelog.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/fa/changelog.md b/docs/fa/changelog.md index b84693cec46..699cc9e7b7c 120000 --- a/docs/fa/changelog.md +++ b/docs/fa/changelog.md @@ -1 +1 @@ -../../CHANGELOG_RU.md \ No newline at end of file +../../CHANGELOG.md \ No newline at end of file diff --git a/docs/ru/changelog.md b/docs/ru/changelog.md index b84693cec46..699cc9e7b7c 120000 --- a/docs/ru/changelog.md +++ b/docs/ru/changelog.md @@ -1 +1 @@ -../../CHANGELOG_RU.md \ No newline at end of file +../../CHANGELOG.md \ No newline at end of file From 4d780d99f4d62de22a60591b8204a8e750006279 Mon Sep 17 00:00:00 2001 From: Vxider Date: Tue, 6 Aug 2019 22:03:41 +0800 Subject: [PATCH 096/105] build fix --- dbms/programs/server/Server.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index 3f96562b656..c2f7ca5f9b6 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -611,7 +611,7 @@ int Server::main(const std::vector & /*args*/) return socket_address; }; - auto socket_bind_listen = [&](auto & socket, const std::string & host, [[maybe_unused]] UInt16 port, [[maybe_unused]] bool secure = 0) + auto socket_bind_listen = [&](auto & socket, const std::string & host, UInt16 port, [[maybe_unused]] bool secure = 0) { auto address = make_socket_address(host, port); #if !defined(POCO_CLICKHOUSE_PATCH) || POCO_VERSION < 0x01090100 @@ -681,7 +681,7 @@ int Server::main(const std::vector & /*args*/) }); /// HTTPS - create_server("https_port", [&]([[maybe_unused]] UInt16 port) + create_server("https_port", [&](UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -696,6 +696,7 @@ int Server::main(const std::vector & /*args*/) LOG_INFO(log, "Listening https://" + address.toString()); #else + UNUSED(port); throw Exception{"HTTPS protocol is disabled because Poco library was built without NetSSL support.", ErrorCodes::SUPPORT_IS_DISABLED}; #endif @@ -718,7 +719,7 @@ int Server::main(const std::vector & /*args*/) }); /// TCP with SSL - create_server ("tcp_port_secure", [&]([[maybe_unused]] UInt16 port) + create_server ("tcp_port_secure", [&](UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -732,6 +733,7 @@ int Server::main(const std::vector & /*args*/) new Poco::Net::TCPServerParams)); LOG_INFO(log, "Listening for connections with secure native protocol (tcp_secure): " + address.toString()); #else + UNUSED(port); throw Exception{"SSL support for TCP protocol is disabled because Poco library was built without NetSSL support.", ErrorCodes::SUPPORT_IS_DISABLED}; #endif @@ -753,7 +755,7 @@ int Server::main(const std::vector & /*args*/) LOG_INFO(log, "Listening for replica communication (interserver) http://" + address.toString()); }); - create_server("interserver_https_port", [&]([[maybe_unused]] UInt16 port) + create_server("interserver_https_port", [&](UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; @@ -768,12 +770,13 @@ int Server::main(const std::vector & /*args*/) LOG_INFO(log, "Listening for secure replica communication (interserver) https://" + address.toString()); #else + UNUSED(port); throw Exception{"SSL support for TCP protocol is disabled because Poco library was built without NetSSL support.", ErrorCodes::SUPPORT_IS_DISABLED}; #endif }); - create_server("mysql_port", [&]([[maybe_unused]] UInt16 port) + create_server("mysql_port", [&](UInt16 port) { #if USE_POCO_NETSSL Poco::Net::ServerSocket socket; @@ -788,6 +791,7 @@ int Server::main(const std::vector & /*args*/) LOG_INFO(log, "Listening for MySQL compatibility protocol: " + address.toString()); #else + UNUSED(port); throw Exception{"SSL support for MySQL protocol is disabled because Poco library was built without NetSSL support.", ErrorCodes::SUPPORT_IS_DISABLED}; #endif From 42287c0b7252c968618fa7df6ed5521fc637b8d7 Mon Sep 17 00:00:00 2001 From: Vxider Date: Tue, 6 Aug 2019 22:04:51 +0800 Subject: [PATCH 097/105] format code --- dbms/programs/server/Server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index c2f7ca5f9b6..c2fbce603d4 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -719,7 +719,7 @@ int Server::main(const std::vector & /*args*/) }); /// TCP with SSL - create_server ("tcp_port_secure", [&](UInt16 port) + create_server("tcp_port_secure", [&](UInt16 port) { #if USE_POCO_NETSSL Poco::Net::SecureServerSocket socket; From 511bf370298a1c65659aaf2733243c8e1fe63f3d Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Tue, 6 Aug 2019 17:26:51 +0300 Subject: [PATCH 098/105] Update 00602_throw_if.sh --- dbms/tests/queries/0_stateless/00602_throw_if.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00602_throw_if.sh b/dbms/tests/queries/0_stateless/00602_throw_if.sh index 3c790d900d3..69039891bd2 100755 --- a/dbms/tests/queries/0_stateless/00602_throw_if.sh +++ b/dbms/tests/queries/0_stateless/00602_throw_if.sh @@ -8,4 +8,4 @@ custom_exception_message="Number equals 1000000" ${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT throwIf(number = 1000000) FROM system.numbers" 2>&1 | grep -cF "$default_exception_message" ${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT throwIf(number = 1000000, '$custom_exception_message') FROM system.numbers" 2>&1 | grep -cF "$custom_exception_message" -${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT sum(x = 0) FROM (SELECT throwIf(number = 1000000) AS x FROM numbers(1000000))" 2>&1 \ No newline at end of file +${CLICKHOUSE_CLIENT} --server_logs_file /dev/null --query="SELECT sum(x = 0) FROM (SELECT throwIf(number = 1000000) AS x FROM numbers(1000000))" 2>&1 From 8bf1af35367916edb5d30fec8a887a4efc40ccf0 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 6 Aug 2019 17:36:16 +0300 Subject: [PATCH 099/105] Removed trash symlinks #6338 --- docs/zh/data_types/domains/ipv4.md | 78 -------------------------- docs/zh/data_types/domains/ipv6.md | 78 -------------------------- docs/zh/data_types/domains/overview.md | 26 --------- 3 files changed, 182 deletions(-) delete mode 120000 docs/zh/data_types/domains/ipv4.md delete mode 120000 docs/zh/data_types/domains/ipv6.md delete mode 120000 docs/zh/data_types/domains/overview.md diff --git a/docs/zh/data_types/domains/ipv4.md b/docs/zh/data_types/domains/ipv4.md deleted file mode 120000 index 4adf13409fe..00000000000 --- a/docs/zh/data_types/domains/ipv4.md +++ /dev/null @@ -1,78 +0,0 @@ -## IPv4 - -`IPv4`是与`UInt32`类型保持二进制兼容的Domain类型,其用于存储IPv4地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。 - -### 基本使用 - -``` sql -CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY url; - -DESCRIBE TABLE hits; -``` - -``` -┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┐ -│ url │ String │ │ │ │ │ -│ from │ IPv4 │ │ │ │ │ -└──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ -``` - -同时您也可以使用`IPv4`类型的列作为主键: - -``` sql -CREATE TABLE hits (url String, from IPv4) ENGINE = MergeTree() ORDER BY from; -``` - -在写入与查询时,`IPv4`类型能够识别可读性更加友好的输入输出格式: - -``` sql -INSERT INTO hits (url, from) VALUES ('https://wikipedia.org', '116.253.40.133')('https://clickhouse.yandex', '183.247.232.58')('https://clickhouse.yandex/docs/en/', '116.106.34.242'); - -SELECT * FROM hits; -``` - -``` -┌─url────────────────────────────────┬───────────from─┐ -│ https://clickhouse.yandex/docs/en/ │ 116.106.34.242 │ -│ https://wikipedia.org │ 116.253.40.133 │ -│ https://clickhouse.yandex │ 183.247.232.58 │ -└────────────────────────────────────┴────────────────┘ -``` - -同时它提供更为紧凑的二进制存储格式: - -``` sql -SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; -``` - -``` -┌─toTypeName(from)─┬─hex(from)─┐ -│ IPv4 │ B7F7E83A │ -└──────────────────┴───────────┘ -``` - -不可隐式转换为除`UInt32`以外的其他类型类型。如果要将`IPv4`类型的值转换成字符串,你可以使用`IPv4NumToString()`显示的进行转换: - -``` sql -SELECT toTypeName(s), IPv4NumToString(from) as s FROM hits LIMIT 1; -``` - -``` -┌─toTypeName(IPv4NumToString(from))─┬─s──────────────┐ -│ String │ 183.247.232.58 │ -└───────────────────────────────────┴────────────────┘ -``` - -或可以使用`CAST`将它转换为`UInt32`类型: - -``` sql -SELECT toTypeName(i), CAST(from as UInt32) as i FROM hits LIMIT 1; -``` - -``` -┌─toTypeName(CAST(from, 'UInt32'))─┬──────────i─┐ -│ UInt32 │ 3086477370 │ -└──────────────────────────────────┴────────────┘ -``` - -[来源文章](https://clickhouse.yandex/docs/en/data_types/domains/ipv4) diff --git a/docs/zh/data_types/domains/ipv6.md b/docs/zh/data_types/domains/ipv6.md deleted file mode 120000 index 1209350990f..00000000000 --- a/docs/zh/data_types/domains/ipv6.md +++ /dev/null @@ -1,78 +0,0 @@ -## IPv6 - -`IPv6`是与`FixedString(16)`类型保持二进制兼容的Domain类型,其用于存储IPv6地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。 - -### 基本用法 - -``` sql -CREATE TABLE hits (url String, from IPv6) ENGINE = MergeTree() ORDER BY url; - -DESCRIBE TABLE hits; -``` - -``` -┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┐ -│ url │ String │ │ │ │ │ -│ from │ IPv6 │ │ │ │ │ -└──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┘ -``` - -同时您也可以使用`IPv6`类型的列作为主键: - -``` sql -CREATE TABLE hits (url String, from IPv6) ENGINE = MergeTree() ORDER BY from; -``` - -在写入与查询时,`IPv6`类型能够识别可读性更加友好的输入输出格式: - -``` sql -INSERT INTO hits (url, from) VALUES ('https://wikipedia.org', '2a02:aa08:e000:3100::2')('https://clickhouse.yandex', '2001:44c8:129:2632:33:0:252:2')('https://clickhouse.yandex/docs/en/', '2a02:e980:1e::1'); - -SELECT * FROM hits; -``` - -``` -┌─url────────────────────────────────┬─from──────────────────────────┐ -│ https://clickhouse.yandex │ 2001:44c8:129:2632:33:0:252:2 │ -│ https://clickhouse.yandex/docs/en/ │ 2a02:e980:1e::1 │ -│ https://wikipedia.org │ 2a02:aa08:e000:3100::2 │ -└────────────────────────────────────┴───────────────────────────────┘ -``` - -同时它提供更为紧凑的二进制存储格式: - -``` sql -SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; -``` - -``` -┌─toTypeName(from)─┬─hex(from)────────────────────────┐ -│ IPv6 │ 200144C8012926320033000002520002 │ -└──────────────────┴──────────────────────────────────┘ -``` - -不可隐式转换为除`FixedString(16)`以外的其他类型类型。如果要将`IPv6`类型的值转换成字符串,你可以使用`IPv6NumToString()`显示的进行转换: - -``` sql -SELECT toTypeName(s), IPv6NumToString(from) as s FROM hits LIMIT 1; -``` - -``` -┌─toTypeName(IPv6NumToString(from))─┬─s─────────────────────────────┐ -│ String │ 2001:44c8:129:2632:33:0:252:2 │ -└───────────────────────────────────┴───────────────────────────────┘ -``` - -或使用`CAST`将其转换为`FixedString(16)`: - -``` sql -SELECT toTypeName(i), CAST(from as FixedString(16)) as i FROM hits LIMIT 1; -``` - -``` -┌─toTypeName(CAST(from, 'FixedString(16)'))─┬─i───────┐ -│ FixedString(16) │ ��� │ -└───────────────────────────────────────────┴─────────┘ -``` - -[来源文章](https://clickhouse.yandex/docs/en/data_types/domains/ipv6) diff --git a/docs/zh/data_types/domains/overview.md b/docs/zh/data_types/domains/overview.md deleted file mode 120000 index b4db116e75b..00000000000 --- a/docs/zh/data_types/domains/overview.md +++ /dev/null @@ -1,26 +0,0 @@ -# Domains - -Domain类型是特定实现的类型,它总是与某个现存的基础类型保持二进制兼容的同时添加一些额外的特性,以能够在维持磁盘数据不变的情况下使用这些额外的特性。目前ClickHouse暂不支持自定义domain类型。 - -如果你可以在一个地方使用与Domain类型二进制兼容的基础类型,那么在相同的地方您也可以使用Domain类型,例如: - -* 使用Domain类型作为表中列的类型 -* 对Domain类型的列进行读/写数据 -* 如果与Domain二进制兼容的基础类型可以作为索引,那么Domain类型也可以作为索引 -* 将Domain类型作为参数传递给函数使用 -* 其他 - -### Domains的额外特性 - -* 在执行SHOW CREATE TABLE 或 DESCRIBE TABLE时,其对应的列总是展示为Domain类型的名称 -* 在INSERT INTO domain_table(domain_column) VALUES(...)中输入数据总是以更人性化的格式进行输入 -* 在SELECT domain_column FROM domain_table中数据总是以更人性化的格式输出 -* 在INSERT INTO domain_table FORMAT CSV ...中,实现外部源数据以更人性化的格式载入 - -### Domains类型的限制 - -* 无法通过`ALTER TABLE`将基础类型的索引转换为Domain类型的索引。 -* 当从其他列或表插入数据时,无法将string类型的值隐式地转换为Domain类型的值。 -* 无法对存储为Domain类型的值添加约束。 - -[来源文章](https://clickhouse.yandex/docs/en/data_types/domains/overview) From fcb04828301d13f578d01ee8c813c3c07929e521 Mon Sep 17 00:00:00 2001 From: Vasily Nemkov Date: Mon, 15 Jul 2019 15:51:08 +0300 Subject: [PATCH 100/105] Implement geohashesInBox function. #6127 --- dbms/src/Functions/GeoUtils.cpp | 142 +++++++++++++-- dbms/src/Functions/GeoUtils.h | 25 ++- dbms/src/Functions/geohashesInBox.cpp | 169 ++++++++++++++++++ dbms/src/Functions/registerFunctionsGeo.cpp | 2 + .../00972_geohashesInBox.reference | 40 +++++ .../0_stateless/00972_geohashesInBox.sql | 63 +++++++ docs/en/query_language/functions/geo.md | 32 ++++ 7 files changed, 460 insertions(+), 13 deletions(-) create mode 100644 dbms/src/Functions/geohashesInBox.cpp create mode 100644 dbms/tests/queries/0_stateless/00972_geohashesInBox.reference create mode 100644 dbms/tests/queries/0_stateless/00972_geohashesInBox.sql diff --git a/dbms/src/Functions/GeoUtils.cpp b/dbms/src/Functions/GeoUtils.cpp index 2c45b6d2cfc..5134343dae0 100644 --- a/dbms/src/Functions/GeoUtils.cpp +++ b/dbms/src/Functions/GeoUtils.cpp @@ -36,6 +36,10 @@ const UInt8 geohash_base32_decode_lookup_table[256] = { const size_t BITS_PER_SYMBOL = 5; const size_t MAX_PRECISION = 12; const size_t MAX_BITS = MAX_PRECISION * BITS_PER_SYMBOL * 1.5; +const Float64 LON_MIN = -180; +const Float64 LON_MAX = 180; +const Float64 LAT_MIN = -90; +const Float64 LAT_MAX = 90; using Encoded = std::array; @@ -64,7 +68,7 @@ inline Encoded encodeCoordinate(Float64 coord, Float64 min, Float64 max, UInt8 b for (size_t i = 0; i < bits; ++i) { - Float64 mid = (max + min) / 2; + const Float64 mid = (max + min) / 2; if (coord >= mid) { result[i] = 1; @@ -148,7 +152,7 @@ inline void base32Encode(const Encoded & binary, UInt8 precision, char * out) { extern const char geohash_base32_encode_lookup_table[32]; - for (UInt8 i = 0; i < precision * BITS_PER_SYMBOL; i += 5) + for (UInt8 i = 0; i < precision * BITS_PER_SYMBOL; i += BITS_PER_SYMBOL) { UInt8 v = binary[i]; v <<= 1; @@ -187,24 +191,38 @@ inline Encoded base32Decode(const char * encoded_string, size_t encoded_length) return result; } +inline Float64 getMaxSpan(CoordType type) +{ + if (type == LONGITUDE) + { + return LON_MAX - LON_MIN; + } + + return LAT_MAX - LAT_MIN; } -namespace DB +inline Float64 getSpan(UInt8 precision, CoordType type) { + const auto bits = singleCoordBitsPrecision(precision, type); + // since every bit of precision divides span by 2, divide max span by 2^bits. + return ldexp(getMaxSpan(type), -1 * bits); +} -namespace GeoUtils -{ - -size_t geohashEncode(Float64 longitude, Float64 latitude, UInt8 precision, char *& out) +inline UInt8 geohashPrecision(UInt8 precision) { if (precision == 0 || precision > MAX_PRECISION) { precision = MAX_PRECISION; } + return precision; +} + +inline size_t geohashEncodeImpl(Float64 longitude, Float64 latitude, UInt8 precision, char * out) +{ const Encoded combined = merge( - encodeCoordinate(longitude, -180, 180, singleCoordBitsPrecision(precision, LONGITUDE)), - encodeCoordinate(latitude, -90, 90, singleCoordBitsPrecision(precision, LATITUDE)), + encodeCoordinate(longitude, LON_MIN, LON_MAX, singleCoordBitsPrecision(precision, LONGITUDE)), + encodeCoordinate(latitude, LAT_MIN, LAT_MAX, singleCoordBitsPrecision(precision, LATITUDE)), precision); base32Encode(combined, precision, out); @@ -212,9 +230,28 @@ size_t geohashEncode(Float64 longitude, Float64 latitude, UInt8 precision, char return precision; } +} + +namespace DB +{ + +namespace ErrorCodes +{ +extern const int ARGUMENT_OUT_OF_BOUND; +} + +namespace GeoUtils +{ + +size_t geohashEncode(Float64 longitude, Float64 latitude, UInt8 precision, char * out) +{ + precision = geohashPrecision(precision); + return geohashEncodeImpl(longitude, latitude, precision, out); +} + void geohashDecode(const char * encoded_string, size_t encoded_len, Float64 * longitude, Float64 * latitude) { - const UInt8 precision = std::min(encoded_len, MAX_PRECISION); + const UInt8 precision = std::min(encoded_len, static_cast(MAX_PRECISION)); if (precision == 0) { return; @@ -223,8 +260,89 @@ void geohashDecode(const char * encoded_string, size_t encoded_len, Float64 * lo Encoded lat_encoded, lon_encoded; std::tie(lon_encoded, lat_encoded) = split(base32Decode(encoded_string, precision), precision); - *longitude = decodeCoordinate(lon_encoded, -180, 180, singleCoordBitsPrecision(precision, LONGITUDE)); - *latitude = decodeCoordinate(lat_encoded, -90, 90, singleCoordBitsPrecision(precision, LATITUDE)); + *longitude = decodeCoordinate(lon_encoded, LON_MIN, LON_MAX, singleCoordBitsPrecision(precision, LONGITUDE)); + *latitude = decodeCoordinate(lat_encoded, LAT_MIN, LAT_MAX, singleCoordBitsPrecision(precision, LATITUDE)); +} + +GeohashesInBoxPreparedArgs geohashesInBoxPrepare(const Float64 longitude_min, + const Float64 latitude_min, + const Float64 longitude_max, + const Float64 latitude_max, + UInt8 precision) +{ + precision = geohashPrecision(precision); + + if (longitude_max < longitude_min || latitude_max < latitude_min) + { + return {}; + } + + const auto lon_step = getSpan(precision, LONGITUDE); + const auto lat_step = getSpan(precision, LATITUDE); + + // align max to the right(or up) border of geohash grid cell to ensure that cell is in result. + Float64 lon_min = floor(longitude_min / lon_step) * lon_step; + Float64 lat_min = floor(latitude_min / lat_step) * lat_step; + Float64 lon_max = ceil(longitude_max / lon_step) * lon_step; + Float64 lat_max = ceil(latitude_max / lat_step) * lat_step; + + const auto lon_span = lon_max - lon_min; + const auto lat_span = lat_max - lat_min; + // in case of a very small (or zero) span, produce at least 1 item. + const auto items_count = std::max(size_t{1}, static_cast(ceil(lon_span/lon_step * lat_span/lat_step))); + + return GeohashesInBoxPreparedArgs{ + items_count, + precision, + lon_min, + lat_min, + lon_max, + lat_max, + lon_step, + lat_step + }; +} + +UInt64 geohashesInBox(const GeohashesInBoxPreparedArgs & args, char * out) +{ + if (args.items_count == 0 + || args.precision == 0 + || args.precision > MAX_PRECISION + || args.latitude_min > args.latitude_max + || args.longitude_min > args.longitude_max + || args.longitude_step <= 0 + || args.latitude_step <= 0) + { + return 0; + } + + UInt64 items = 0; + for (auto lon = args.longitude_min; lon < args.longitude_max; lon += args.longitude_step) + { + for (auto lat = args.latitude_min; lat < args.latitude_max; lat += args.latitude_step) + { + assert(items <= args.items_count); + + size_t l = geohashEncodeImpl(lon, lat, args.precision, out); + out += l; + *out = '\0'; + ++out; + + ++items; + } + } + + if (items == 0 && args.items_count != 0) + { + size_t l = geohashEncodeImpl(args.longitude_min, args.latitude_min, args.precision, out); + out += l; + *out = '\0'; + ++out; + + ++items; + } + + return items; } } diff --git a/dbms/src/Functions/GeoUtils.h b/dbms/src/Functions/GeoUtils.h index b3a283ee2e6..9c5ebf98b16 100644 --- a/dbms/src/Functions/GeoUtils.h +++ b/dbms/src/Functions/GeoUtils.h @@ -706,10 +706,33 @@ std::string serialize(Polygon && polygon) return result; } -size_t geohashEncode(Float64 longitude, Float64 latitude, UInt8 precision, char *& out); +size_t geohashEncode(Float64 longitude, Float64 latitude, UInt8 precision, char * out); void geohashDecode(const char * encoded_string, size_t encoded_len, Float64 * longitude, Float64 * latitude); +std::vector> geohashCoverBox(Float64 longitude_min, Float64 latitude_min, Float64 longitude_max, Float64 latitude_max, UInt8 precision, UInt32 max_items = 0); + +struct GeohashesInBoxPreparedArgs +{ + UInt64 items_count = 0; + UInt8 precision = 0; + + Float64 longitude_min = 0.0; + Float64 latitude_min = 0.0; + Float64 longitude_max = 0.0; + Float64 latitude_max = 0.0; + + Float64 longitude_step = 0.0; + Float64 latitude_step = 0.0; +}; + +GeohashesInBoxPreparedArgs geohashesInBoxPrepare(const Float64 longitude_min, + const Float64 latitude_min, + Float64 longitude_max, + Float64 latitude_max, + UInt8 precision); + +UInt64 geohashesInBox(const GeohashesInBoxPreparedArgs & estimation, char * out); } /// GeoUtils diff --git a/dbms/src/Functions/geohashesInBox.cpp b/dbms/src/Functions/geohashesInBox.cpp new file mode 100644 index 00000000000..09e36e01e77 --- /dev/null +++ b/dbms/src/Functions/geohashesInBox.cpp @@ -0,0 +1,169 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace DB +{ + +namespace ErrorCodes +{ +extern const int LOGICAL_ERROR; +extern const int ILLEGAL_TYPE_OF_ARGUMENT; +extern const int TOO_LARGE_ARRAY_SIZE; +} + +class FunctionGeohashesInBox : public IFunction +{ +public: + static constexpr auto name = "geohashesInBox"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override { return name; } + + size_t getNumberOfArguments() const override { return 5; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + validateArgumentType(*this, arguments, 0, isFloat, "float"); + validateArgumentType(*this, arguments, 1, isFloat, "float"); + validateArgumentType(*this, arguments, 2, isFloat, "float"); + validateArgumentType(*this, arguments, 3, isFloat, "float"); + validateArgumentType(*this, arguments, 4, isUInt8, "integer"); + + if (!(arguments[0]->equals(*arguments[1]) && + arguments[0]->equals(*arguments[2]) && + arguments[0]->equals(*arguments[3]))) + { + throw Exception("Illegal type of argument of " + getName() + + " all coordinate arguments must have the same type, instead they are:" + + arguments[0]->getName() + ", " + + arguments[1]->getName() + ", " + + arguments[2]->getName() + ", " + + arguments[3]->getName() + ".", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + return std::make_shared(std::make_shared()); + } + + bool useDefaultImplementationForConstants() const override { return true; } + + template + void execute(const IColumn * lon_min_column, + const IColumn * lat_min_column, + const IColumn * lon_max_column, + const IColumn * lat_max_column, + const IColumn * precision_column, + ColumnPtr & result) + { + static constexpr size_t max_array_size = 10'000'000; + + const auto * lon_min = checkAndGetColumn>(lon_min_column); + const auto * lat_min = checkAndGetColumn>(lat_min_column); + const auto * lon_max = checkAndGetColumn>(lon_max_column); + const auto * lat_max = checkAndGetColumn>(lat_max_column); + auto * precision = checkAndGetColumn>(precision_column); + if (precision == nullptr) + { + precision = checkAndGetColumnConstData>(precision_column); + } + + if (!lon_min || !lat_min || !lon_max || !lat_max || !precision) + { + throw Exception("Unsupported argument types for function " + getName() + " : " + + lon_min_column->getName() + ", " + + lat_min_column->getName() + ", " + + lon_max_column->getName() + ", " + + lat_max_column->getName() + ".", + ErrorCodes::LOGICAL_ERROR); + } + + const size_t total_rows = lat_min->size(); + + auto col_res = ColumnArray::create(ColumnString::create()); + ColumnString & res_strings = typeid_cast(col_res->getData()); + ColumnArray::Offsets & res_offsets = col_res->getOffsets(); + ColumnString::Chars & res_strings_chars = res_strings.getChars(); + ColumnString::Offsets & res_strings_offsets = res_strings.getOffsets(); + + for (size_t row = 0; row < total_rows; ++row) + { + const Float64 lon_min_value = lon_min->getElement(row); + const Float64 lat_min_value = lat_min->getElement(row); + const Float64 lon_max_value = lon_max->getElement(row); + const Float64 lat_max_value = lat_max->getElement(row); + + const auto prepared_args = GeoUtils::geohashesInBoxPrepare( + lon_min_value, lat_min_value, lon_max_value, lat_max_value, + precision->getElement(row % precision->size())); + if (prepared_args.items_count > max_array_size) + { + throw Exception(getName() + " would produce " + std::to_string(prepared_args.items_count) + + " array elements, which is bigger than the allowed maximum of " + std::to_string(max_array_size), + ErrorCodes::TOO_LARGE_ARRAY_SIZE); + } + + res_strings_offsets.reserve(res_strings_offsets.size() + prepared_args.items_count); + res_strings_chars.resize(res_strings_chars.size() + prepared_args.items_count * (prepared_args.precision + 1)); + const auto starting_offset = res_strings_offsets.empty() ? 0 : res_strings_offsets.back(); + char * out = reinterpret_cast(res_strings_chars.data() + starting_offset); + + // Actually write geohashes into preallocated buffer. + GeoUtils::geohashesInBox(prepared_args, out); + + for (UInt8 i = 1; i <= prepared_args.items_count ; ++i) + { + res_strings_offsets.push_back(starting_offset + (prepared_args.precision + 1) * i); + } + res_offsets.push_back((res_offsets.empty() ? 0 : res_offsets.back()) + prepared_args.items_count); + } + if (!res_strings_offsets.empty() && res_strings_offsets.back() != res_strings_chars.size()) + { + throw Exception("String column size mismatch (internal logical error)", ErrorCodes::LOGICAL_ERROR); + } + + if (!res_offsets.empty() && res_offsets.back() != res_strings.size()) + { + throw Exception("Arrary column size mismatch (internal logical error)" + + std::to_string(res_offsets.back()) + " != " + std::to_string(res_strings.size()), + ErrorCodes::LOGICAL_ERROR); + } + + result = std::move(col_res); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override + { + const IColumn * lon_min = block.getByPosition(arguments[0]).column.get(); + const IColumn * lat_min = block.getByPosition(arguments[1]).column.get(); + const IColumn * lon_max = block.getByPosition(arguments[2]).column.get(); + const IColumn * lat_max = block.getByPosition(arguments[3]).column.get(); + const IColumn * prec = block.getByPosition(arguments[4]).column.get(); + ColumnPtr & res = block.getByPosition(result).column; + + if (checkColumn>(lon_min)) + { + execute(lon_min, lat_min, lon_max, lat_max, prec, res); + } + else + { + execute(lon_min, lat_min, lon_max, lat_max, prec, res); + } + } +}; + +void registerFunctionGeohashesInBox(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/dbms/src/Functions/registerFunctionsGeo.cpp b/dbms/src/Functions/registerFunctionsGeo.cpp index 0f436811874..adc025aafe3 100644 --- a/dbms/src/Functions/registerFunctionsGeo.cpp +++ b/dbms/src/Functions/registerFunctionsGeo.cpp @@ -10,6 +10,7 @@ void registerFunctionPointInEllipses(FunctionFactory & factory); void registerFunctionPointInPolygon(FunctionFactory & factory); void registerFunctionGeohashEncode(FunctionFactory & factory); void registerFunctionGeohashDecode(FunctionFactory & factory); +void registerFunctionGeohashesInBox(FunctionFactory & factory); #if USE_H3 void registerFunctionGeoToH3(FunctionFactory &); @@ -22,6 +23,7 @@ void registerFunctionsGeo(FunctionFactory & factory) registerFunctionPointInPolygon(factory); registerFunctionGeohashEncode(factory); registerFunctionGeohashDecode(factory); + registerFunctionGeohashesInBox(factory); #if USE_H3 registerFunctionGeoToH3(factory); diff --git a/dbms/tests/queries/0_stateless/00972_geohashesInBox.reference b/dbms/tests/queries/0_stateless/00972_geohashesInBox.reference new file mode 100644 index 00000000000..e6844fa8394 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00972_geohashesInBox.reference @@ -0,0 +1,40 @@ +center +['7zz','ebp','kpb','s00'] +['7zzzm','7zzzq','7zzzr','7zzzt','7zzzv','7zzzw','7zzzx','7zzzy','7zzzz','ebpbj','ebpbm','ebpbn','ebpbp','ebpbq','ebpbr','ebpbt','ebpbw','ebpbx','kpbp2','kpbp3','kpbp6','kpbp8','kpbp9','kpbpb','kpbpc','kpbpd','kpbpf','s0000','s0001','s0002','s0003','s0004','s0006','s0008','s0009','s000d'] +['7zzzz','ebpbp','kpbpb','s0000'] +north pole +['bpb'] +['gzz'] +['upb'] +['zzz'] +south pole +['000'] +['5bp'] +['h00'] +['pbp'] +wrap point around equator +['rzz'] +['xbp'] +['2pb'] +['800'] +arbitrary values in all 4 quarters +['w1muy4','w1muy5','w1muy6','w1muy7','w1muyh','w1muyk'] +['thym0','thym1','thym2','thym3','thym4','thym6','thym8','thym9','thymd'] +['6gkzx5','6gkzx7','6gkzxh','6gkzxj','6gkzxk','6gkzxm'] +['h927mu','h927mv','h927my','h927qh','h927qj','h927qn'] +small range always produces array of length 1 +zooming +['s7'] +['s7w'] +['s7w1','s7w3','s7w4','s7w5','s7w6','s7w7','s7w9','s7wc','s7wd','s7we','s7wf','s7wg','s7wh','s7wj','s7wk','s7wm','s7wn','s7wp','s7wq','s7wr','s7ws','s7wt','s7wu','s7wv','s7ww','s7wx','s7wy','s7wz'] +['s7w1z','s7w3b','s7w3c','s7w3f','s7w3g','s7w3u','s7w4p','s7w4r','s7w4x','s7w4z','s7w5p','s7w60','s7w61','s7w62','s7w63','s7w64','s7w65','s7w66','s7w67','s7w68','s7w69','s7w6b','s7w6c','s7w6d','s7w6e','s7w6f','s7w6g','s7w6h','s7w6k','s7w6s','s7w6u','s7w70','s7w71','s7w74','s7w75','s7w7h'] +['s7w1z0','s7w1z1','s7w1z2','s7w1z3','s7w1z4','s7w1z5','s7w1z6','s7w1z7','s7w1z8','s7w1z9','s7w1zb','s7w1zc','s7w1zd','s7w1ze','s7w1zf','s7w1zg','s7w1zh','s7w1zj','s7w1zk','s7w1zm','s7w1zn','s7w1zp','s7w1zq','s7w1zr','s7w1zs','s7w1zt','s7w1zu','s7w1zv','s7w1zw','s7w1zx','s7w1zy','s7w1zz','s7w3b0','s7w3b1','s7w3b2','s7w3b3','s7w3b4','s7w3b5','s7w3b6','s7w3b7','s7w3b8','s7w3b9','s7w3bd','s7w3be','s7w3bh','s7w3bj','s7w3bk','s7w3bm','s7w3bn','s7w3bp','s7w3bq','s7w3br','s7w3bs','s7w3bt','s7w3bw','s7w3bx','s7w4p0','s7w4p1','s7w4p2','s7w4p3','s7w4p4','s7w4p5','s7w4p6','s7w4p7','s7w4p8','s7w4p9','s7w4pb','s7w4pc','s7w4pd','s7w4pe','s7w4pf','s7w4pg','s7w4ph','s7w4pk','s7w4ps','s7w4pu','s7w600','s7w601','s7w602','s7w603','s7w604','s7w605','s7w606','s7w607','s7w608','s7w609','s7w60d','s7w60e','s7w60h','s7w60k','s7w60s'] +['s7w1z0g','s7w1z0u','s7w1z0v','s7w1z0y','s7w1z0z','s7w1z15','s7w1z17','s7w1z1e','s7w1z1g','s7w1z1h','s7w1z1j','s7w1z1k','s7w1z1m','s7w1z1n','s7w1z1p','s7w1z1q','s7w1z1r','s7w1z1s','s7w1z1t','s7w1z1u','s7w1z1v','s7w1z1w','s7w1z1x','s7w1z1y','s7w1z1z','s7w1z2b','s7w1z2c','s7w1z2f','s7w1z30','s7w1z31','s7w1z32','s7w1z33','s7w1z34','s7w1z36','s7w1z38','s7w1z39','s7w1z3b','s7w1z3c','s7w1z3d','s7w1z3f','s7w1z45','s7w1z47','s7w1z4e','s7w1z4h','s7w1z4j','s7w1z4k','s7w1z4m','s7w1z4n','s7w1z4p','s7w1z4q','s7w1z4r','s7w1z4s','s7w1z4t','s7w1z4w','s7w1z4x','s7w1z60','s7w1z61','s7w1z62','s7w1z63','s7w1z64','s7w1z66','s7w1z68','s7w1z69','s7w1z6d'] +['s7w1z0gs','s7w1z0gt','s7w1z0gu','s7w1z0gv','s7w1z0gw','s7w1z0gx','s7w1z0gy','s7w1z0gz','s7w1z0uh','s7w1z0uj','s7w1z0uk','s7w1z0um','s7w1z0un','s7w1z0up','s7w1z0uq','s7w1z0ur','s7w1z158','s7w1z159','s7w1z15b','s7w1z15c','s7w1z15d','s7w1z15f','s7w1z1h0','s7w1z1h1','s7w1z1h2','s7w1z1h3','s7w1z1h4','s7w1z1h6'] +['s7w1z0gs3','s7w1z0gs6','s7w1z0gs7','s7w1z0gs9','s7w1z0gsc','s7w1z0gsd','s7w1z0gse','s7w1z0gsf','s7w1z0gsg','s7w1z0gsk','s7w1z0gss','s7w1z0gsu','s7w1z0gt1','s7w1z0gt4','s7w1z0gt5','s7w1z0gth'] +['s7w1z0gs3y','s7w1z0gs3z','s7w1z0gs6n','s7w1z0gs6p','s7w1z0gs9b','s7w1z0gsd0'] +['s7w1z0gs3y0','s7w1z0gs3y1','s7w1z0gs3y2','s7w1z0gs3y3'] +['s7w1z0gs3y0z','s7w1z0gs3y1p','s7w1z0gs3y1r','s7w1z0gs3y1x','s7w1z0gs3y2b','s7w1z0gs3y2c','s7w1z0gs3y2f','s7w1z0gs3y2g','s7w1z0gs3y2u','s7w1z0gs3y2v','s7w1z0gs3y30','s7w1z0gs3y31','s7w1z0gs3y32','s7w1z0gs3y33','s7w1z0gs3y34','s7w1z0gs3y35','s7w1z0gs3y36','s7w1z0gs3y37','s7w1z0gs3y38','s7w1z0gs3y39','s7w1z0gs3y3d','s7w1z0gs3y3e','s7w1z0gs3y3h','s7w1z0gs3y3j','s7w1z0gs3y3k','s7w1z0gs3y3m','s7w1z0gs3y3s','s7w1z0gs3y3t'] +['s7w1z0gs3y0z','s7w1z0gs3y1p','s7w1z0gs3y1r','s7w1z0gs3y1x','s7w1z0gs3y2b','s7w1z0gs3y2c','s7w1z0gs3y2f','s7w1z0gs3y2g','s7w1z0gs3y2u','s7w1z0gs3y2v','s7w1z0gs3y30','s7w1z0gs3y31','s7w1z0gs3y32','s7w1z0gs3y33','s7w1z0gs3y34','s7w1z0gs3y35','s7w1z0gs3y36','s7w1z0gs3y37','s7w1z0gs3y38','s7w1z0gs3y39','s7w1z0gs3y3d','s7w1z0gs3y3e','s7w1z0gs3y3h','s7w1z0gs3y3j','s7w1z0gs3y3k','s7w1z0gs3y3m','s7w1z0gs3y3s','s7w1z0gs3y3t'] +['s7w1z0gs3y0z','s7w1z0gs3y1p','s7w1z0gs3y1r','s7w1z0gs3y1x','s7w1z0gs3y2b','s7w1z0gs3y2c','s7w1z0gs3y2f','s7w1z0gs3y2g','s7w1z0gs3y2u','s7w1z0gs3y2v','s7w1z0gs3y30','s7w1z0gs3y31','s7w1z0gs3y32','s7w1z0gs3y33','s7w1z0gs3y34','s7w1z0gs3y35','s7w1z0gs3y36','s7w1z0gs3y37','s7w1z0gs3y38','s7w1z0gs3y39','s7w1z0gs3y3d','s7w1z0gs3y3e','s7w1z0gs3y3h','s7w1z0gs3y3j','s7w1z0gs3y3k','s7w1z0gs3y3m','s7w1z0gs3y3s','s7w1z0gs3y3t'] +errors diff --git a/dbms/tests/queries/0_stateless/00972_geohashesInBox.sql b/dbms/tests/queries/0_stateless/00972_geohashesInBox.sql new file mode 100644 index 00000000000..f382bf234ac --- /dev/null +++ b/dbms/tests/queries/0_stateless/00972_geohashesInBox.sql @@ -0,0 +1,63 @@ +-- test data acquired with: https://github.com/sunng87/node-geohash +-- geohash.bboxes(minlat, minlon, maxlat, maxlon, precision) +-- as +-- geohashesInBox(minlon, minlat, maxlon, maxlat, precision) +-- except for the cases when JS-version produces result outside of given region, +-- typically at wrap points: poles, 0-latitude and 0-longitude. + +select 'center'; +SELECT arraySort(geohashesInBox(-1.0, -1.0, 1.0, 1.0, 3)); +SELECT arraySort(geohashesInBox(-0.1, -0.1, 0.1, 0.1, 5)); +SELECT arraySort(geohashesInBox(-0.01, -0.01, 0.01, 0.01, 5)); + +select 'north pole'; +SELECT arraySort(geohashesInBox(-180.0, 89.0, -179.0, 90.0, 3)); +SELECT arraySort(geohashesInBox(-1.0, 89.0, 0.0, 90.0, 3)); +SELECT arraySort(geohashesInBox(0.0, 89.0, 1.0, 90.0, 3)); +SELECT arraySort(geohashesInBox(179.0, 89.0, 180.0, 90.0, 3)); + +select 'south pole'; +SELECT arraySort(geohashesInBox(-180.0, -90.0, -179.0, -89.0, 3)); +SELECT arraySort(geohashesInBox(-1.0, -90.0, 0.0, -89.0, 3)); +SELECT arraySort(geohashesInBox(0.0, -90.0, 1.0, -89.0, 3)); +SELECT arraySort(geohashesInBox(179.0, -90.0, 180.0, -89.0, 3)); + +select 'wrap point around equator'; +SELECT arraySort(geohashesInBox(179.0, -1.0, 180.0, 0.0, 3)); +SELECT arraySort(geohashesInBox(179.0, 0.0, 180.0, 1.0, 3)); +SELECT arraySort(geohashesInBox(-180.0, -1.0, -179.0, 0.0, 3)); +SELECT arraySort(geohashesInBox(-180.0, 0.0, -179.0, 1.0, 3)); + +select 'arbitrary values in all 4 quarters'; +SELECT arraySort(geohashesInBox(98.36, 7.88, 98.37, 7.89, 6)); +SELECT arraySort(geohashesInBox(53.8, 27.6, 53.9, 27.7, 5)); +SELECT arraySort(geohashesInBox(-49.26, -25.38, -49.25, -25.37, 6)); +SELECT arraySort(geohashesInBox(23.11, -82.37, 23.12, -82.36, 6)); + +select 'small range always produces array of length 1'; +SELECT lon/5 - 180 as lon1, lat/5 - 90 as lat1, lon1 as lon2, lat1 as lat2, geohashesInBox(lon1, lat1, lon2, lat2, 1) as g FROM (SELECT arrayJoin(range(360*5)) as lon, arrayJoin(range(180*5)) as lat) WHERE length(g) != 1; +SELECT lon/5 - 40 as lon1, lat/5 - 20 as lat1, lon1 as lon2, lat1 as lat2, geohashesInBox(lon1, lat1, lon2, lat2, 12) as g FROM (SELECT arrayJoin(range(80*5)) as lon, arrayJoin(range(10*5)) as lat) WHERE length(g) != 1; +SELECT lon/5 - 40 as lon1, lat/5 - 20 as lat1, lon1 + 0.0000000001 as lon2, lat1 + 0.0000000001 as lat2, geohashesInBox(lon1, lat1, lon2, lat2, 1) as g FROM (SELECT arrayJoin(range(80*5)) as lon, arrayJoin(range(10*5)) as lat) WHERE length(g) != 1; + +select 'zooming'; +SELECT arraySort(geohashesInBox(20.0, 20.0, 21.0, 21.0, 2)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 21.0, 21.0, 3)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 21.0, 21.0, 4)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.25, 20.25, 5)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.0625, 20.0625, 6)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.01, 20.01, 7)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.001, 20.001, 8)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.0001, 20.0001, 9)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.00001, 20.00001, 10)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.000001, 20.000001, 11)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.000001, 20.000001, 12)); + + -- precision greater than 12 is truncated to 12, so these two calls would produce same result as above +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.000001, 20.000001, 13)); +SELECT arraySort(geohashesInBox(20.0, 20.0, 20.000001, 20.000001, 14)); + +select 'errors'; +SELECT geohashesInBox(); -- { serverError 42 } -- not enough arguments +SELECT geohashesInBox(1, 2, 3, 4, 5); -- { serverError 43 } -- wrong types of arguments +SELECT geohashesInBox(toFloat32(1.0), 2.0, 3.0, 4.0, 5); -- { serverError 43 } -- all lats and longs should be of the same type +SELECT geohashesInBox(24.48, 40.56, 24.785, 40.81, 12); -- { serverError 128 } -- to many elements in array diff --git a/docs/en/query_language/functions/geo.md b/docs/en/query_language/functions/geo.md index 2c84a4516ba..d05345da29e 100644 --- a/docs/en/query_language/functions/geo.md +++ b/docs/en/query_language/functions/geo.md @@ -183,4 +183,36 @@ SELECT geoToH3(37.79506683, 55.71290588, 15) as h3Index └────────────────────┘ ``` +## geohashesInBox + +Returns an array of geohash-encoded strings of given precision that fall inside and intersect boundaries of given box, basically a 2D grid flattened into array. + +**Input values** + +- longitude_min - min longitude, floating value in range `[-180°, 180°]` +- latitude_min - min latitude, floating value in range `[-90°, 90°]` +- longitude_max - max longitude, floating value in range `[-180°, 180°]` +- latitude_max - max latitude, floating value in range `[-90°, 90°]` +- precision - geohash precision, `UInt8` in range `[1, 12]` + +Please note that all coordinate parameters should be of the same type: either `Float32` or `Float64`. + +**Returned values** + +- array of precision-long strings of geohash-boxes covering provided area, you should not rely on order of items. +- [] - empty array if *min* values of *latitude* and *longitude* aren't less than corresponding *max* values. + +Please note that function will throw an exception if resulting array is over 10'000'000 items long. + +**Example** + +``` +SELECT geohashesInBox(24.48, 40.56, 24.785, 40.81, 4) AS thasos +``` +``` +┌─thasos──────────────────────────────────────┐ +│ ['sx1q','sx1r','sx32','sx1w','sx1x','sx38'] │ +└─────────────────────────────────────────────┘ +``` + [Original article](https://clickhouse.yandex/docs/en/query_language/functions/geo/) From 9cd9c694496d5ae793718c9577ec8bb3a5fedc77 Mon Sep 17 00:00:00 2001 From: Vasily Nemkov Date: Tue, 6 Aug 2019 17:57:17 +0300 Subject: [PATCH 101/105] geohashesInbox(lon_min, lat_min, lon_max, lat_max, precision) function (#6127) --- dbms/src/DataTypes/IDataType.h | 1 - dbms/src/Functions/GeoUtils.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dbms/src/DataTypes/IDataType.h b/dbms/src/DataTypes/IDataType.h index e5020fe19de..359874c5660 100644 --- a/dbms/src/DataTypes/IDataType.h +++ b/dbms/src/DataTypes/IDataType.h @@ -602,7 +602,6 @@ inline bool isStringOrFixedString(const T & data_type) return WhichDataType(data_type).isStringOrFixedString(); } - inline bool isNotDecimalButComparableToDecimal(const DataTypePtr & data_type) { WhichDataType which(data_type); diff --git a/dbms/src/Functions/GeoUtils.cpp b/dbms/src/Functions/GeoUtils.cpp index 5134343dae0..d08216ad5c6 100644 --- a/dbms/src/Functions/GeoUtils.cpp +++ b/dbms/src/Functions/GeoUtils.cpp @@ -1,6 +1,8 @@ #include #include +#include + namespace { From 224ed0ca670ccc00921caa7f513b84bb0c28f9d9 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov Date: Tue, 6 Aug 2019 17:59:19 +0300 Subject: [PATCH 102/105] Revert wrong merge commit. This reverts commit 9cd9c694496d5ae793718c9577ec8bb3a5fedc77. --- dbms/src/DataTypes/IDataType.h | 1 + dbms/src/Functions/GeoUtils.cpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dbms/src/DataTypes/IDataType.h b/dbms/src/DataTypes/IDataType.h index 359874c5660..e5020fe19de 100644 --- a/dbms/src/DataTypes/IDataType.h +++ b/dbms/src/DataTypes/IDataType.h @@ -602,6 +602,7 @@ inline bool isStringOrFixedString(const T & data_type) return WhichDataType(data_type).isStringOrFixedString(); } + inline bool isNotDecimalButComparableToDecimal(const DataTypePtr & data_type) { WhichDataType which(data_type); diff --git a/dbms/src/Functions/GeoUtils.cpp b/dbms/src/Functions/GeoUtils.cpp index d08216ad5c6..5134343dae0 100644 --- a/dbms/src/Functions/GeoUtils.cpp +++ b/dbms/src/Functions/GeoUtils.cpp @@ -1,8 +1,6 @@ #include #include -#include - namespace { From 4982f3e9f9763fd31269b60500b2a1eca52674f5 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov Date: Wed, 7 Aug 2019 16:52:15 +0300 Subject: [PATCH 103/105] Add links to hits_100m dataset. --- docs/en/getting_started/example_datasets/metrica.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/getting_started/example_datasets/metrica.md b/docs/en/getting_started/example_datasets/metrica.md index c26332ad563..75741ba0b54 100644 --- a/docs/en/getting_started/example_datasets/metrica.md +++ b/docs/en/getting_started/example_datasets/metrica.md @@ -1,5 +1,5 @@ # Anonymized Yandex.Metrica Data -Dataset consists of two tables containing anonymized data about hits (`hits_v1`) and visits (`visits_v1`) of Yandex.Metrica. Each of the tables can be downloaded as a compressed `tsv.xz` file or as prepared partitions. +Dataset consists of two tables containing anonymized data about hits (`hits_v1`) and visits (`visits_v1`) of Yandex.Metrica. Each of the tables can be downloaded as a compressed `tsv.xz` file or as prepared partitions. In addition to that, an extended version of the `hits` table containing 100 million rows is available as TSV at `https://clickhouse-datasets.s3.yandex.net/hits/tsv/hits_100m_obfuscated_v1.tsv.xz` and as prepared partitions at `https://clickhouse-datasets.s3.yandex.net/hits/partitions/hits_100m_obfuscated_v1.tar.xz`. ## Obtaining Tables from Prepared Partitions **Download and import hits:** From da6ca3f8c749133dc76b213fc8bfa6284e193c4e Mon Sep 17 00:00:00 2001 From: BayoNet Date: Wed, 7 Aug 2019 19:02:56 +0300 Subject: [PATCH 104/105] DOCAPI-7413: T64 codec docs (#6347) --- docs/en/operations/table_engines/mergetree.md | 6 +- docs/en/query_language/create.md | 76 ++++++++++--------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/docs/en/operations/table_engines/mergetree.md b/docs/en/operations/table_engines/mergetree.md index 2c2141a0a87..2a099a8947d 100644 --- a/docs/en/operations/table_engines/mergetree.md +++ b/docs/en/operations/table_engines/mergetree.md @@ -81,9 +81,9 @@ For descriptions of request parameters, see the [request description](../../quer - `merge_with_ttl_timeout` — Minimum delay in seconds before repeating a merge with TTL. Default value: 86400 (1 day). -**Example of setting the sections ** +**Example of setting the sections** -``` +```sql ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate, intHash32(UserID)) SAMPLE BY intHash32(UserID) SETTINGS index_granularity=8192 ``` @@ -125,7 +125,7 @@ The `MergeTree` engine is configured in the same way as in the example above for ## Data Storage -A table consists of data *parts* sorted by primary key. +A table consists of data parts sorted by primary key. When data is inserted in a table, separate data parts are created and each of them is lexicographically sorted by primary key. For example, if the primary key is `(CounterID, Date)`, the data in the part is sorted by `CounterID`, and within each `CounterID`, it is ordered by `Date`. diff --git a/docs/en/query_language/create.md b/docs/en/query_language/create.md index bd2228efa94..81d7982eb00 100644 --- a/docs/en/query_language/create.md +++ b/docs/en/query_language/create.md @@ -109,25 +109,7 @@ Defines storage time for values. Can be specified only for MergeTree-family tabl ## Column Compression Codecs -Besides default data compression, defined in [server settings](../operations/server_settings/settings.md#compression), per-column specification is also available. - -Supported compression algorithms: - -- `NONE` — No compression. -- `LZ4` — Lossless [data compression algorithm](https://github.com/lz4/lz4) used by default. Applies LZ4 fast compression. -- `LZ4HC[(level)]` — LZ4 CH (high compression) algorithm with configurable level. Default level: 9. If you set `level <= 0`, the default level is applied. Possible levels: [1, 12]. Recommended levels are in range: [4, 9]. -- `ZSTD[(level)]` — [ZSTD compression algorithm](https://en.wikipedia.org/wiki/Zstandard) with configurable `level`. Possible levels: [1, 22]. Default value: 1. -- `Delta(delta_bytes)` — compression approach, when raw values are replaced with the difference of two neighbour values. Up to `delta_bytes` are used for storing delta value, so `delta_bytes` is a maximum size of raw values. -Possible `delta_bytes` values: 1, 2, 4, 8. Default value for `delta_bytes` is `sizeof(type)`, if it is equals to 1, 2, 4, 8. Otherwise it equals 1. -- `DoubleDelta` — Compresses values down to 1 bit (in the best case), using deltas calculation. Best compression rates are achieved on monotonic sequences with constant stride, for example, time series data. Can be used with any fixed-width type. Implements the algorithm used in Gorilla TSDB, extending it to support 64 bit types. Uses 1 extra bit for 32 byte deltas: 5 bit prefix instead of 4 bit prefix. For additional information, see the "Compressing time stamps" section of the [Gorilla: A Fast, Scalable, In-Memory Time Series Database](http://www.vldb.org/pvldb/vol8/p1816-teller.pdf) document. -- `Gorilla` — Compresses values down to 1 bit (in the best case). The codec is efficient when storing series of floating point values that change slowly, because the best compression rate is achieved when neighbouring values are binary equal. Implements the algorithm used in Gorilla TSDB, extending it to support 64 bit types. For additional information, see the "Compressing values" section of the [Gorilla: A Fast, Scalable, In-Memory Time Series Database](http://www.vldb.org/pvldb/vol8/p1816-teller.pdf) document. - -High compression levels useful for asymmetric scenarios, like compress once, decompress a lot of times. Greater levels stands for better compression and higher CPU usage. - -!!!warning - You cannot decompress ClickHouse database files with external utilities, for example, `lz4`. Use the special utility [clickhouse-compressor](https://github.com/yandex/ClickHouse/tree/master/dbms/programs/compressor). - -Syntax example: +By default, ClickHouse applies to columns the compression method, defined in [server settings](../operations/server_settings/settings.md#compression). Also, you can define compression method for each individual column in the `CREATE TABLE` query. ``` CREATE TABLE codec_example @@ -136,28 +118,48 @@ CREATE TABLE codec_example ts DateTime CODEC(LZ4HC), float_value Float32 CODEC(NONE), double_value Float64 CODEC(LZ4HC(9)) -) -ENGINE = MergeTree -PARTITION BY tuple() -ORDER BY dt -``` - -Codecs can be combined in a pipeline. Default table codec is not included into pipeline (if it should be applied to a column, you have to specify it explicitly in pipeline). Example below shows an optimization approach for storing timeseries metrics. -Usually, values for particular metric, stored in `path` does not differ significantly from point to point. Using delta-encoding allows to reduce disk space usage significantly. - -``` -CREATE TABLE timeseries_example -( - dt Date, - ts DateTime, - path String, value Float32 CODEC(Delta, ZSTD) ) -ENGINE = MergeTree -PARTITION BY dt -ORDER BY (path, ts) +ENGINE = +... ``` +If a codec is specified, the default codec doesn't apply. Codecs can be combined in a pipeline, for example, `CODEC(Delta, ZSTD)`. To select the best codecs combination for you project, pass benchmarks, similar to described in the Altinity [New Encodings to Improve ClickHouse Efficiency](https://www.altinity.com/blog/2019/7/new-encodings-to-improve-clickhouse) article. + +!!!warning + You cannot decompress ClickHouse database files with external utilities, for example, `lz4`. Use the special utility, [clickhouse-compressor](https://github.com/yandex/ClickHouse/tree/master/dbms/programs/compressor). + +Compression is supported for the table engines: + +- [*MergeTree](../operations/table_engines/mergetree.md) family +- [*Log](../operations/table_engines/log_family.md) family +- [Set](../operations/table_engines/set.md) +- [Join](../operations/table_engines/join.md) + +ClickHouse supports common purpose codecs and specialized codecs. + +### Specialized codecs {#create-query-specialized-codecs} + +These codecs are designed to make compression more effective using specifities of the data. Some of this codecs don't compress data by itself, but they prepare data to be compressed better by common purpose codecs. + +Specialized codecs: + +- `Delta(delta_bytes)` — Compression approach, when raw values are replaced with the difference of two neighbor values. Up to `delta_bytes` are used for storing delta value, so `delta_bytes` is a maximum size of raw values. Possible `delta_bytes` values: 1, 2, 4, 8. Default value for `delta_bytes` is `sizeof(type)`, if it is equals to 1, 2, 4, 8. Otherwise it equals 1. +- `DoubleDelta` — Compresses values down to 1 bit (in the best case), using deltas calculation. Best compression rates are achieved on monotonic sequences with constant stride, for example, time series data. Can be used with any fixed-width type. Implements the algorithm used in Gorilla TSDB, extending it to support 64 bit types. Uses 1 extra bit for 32 byte deltas: 5 bit prefix instead of 4 bit prefix. For additional information, see the "Compressing time stamps" section of the [Gorilla: A Fast, Scalable, In-Memory Time Series Database](http://www.vldb.org/pvldb/vol8/p1816-teller.pdf) document. +- `Gorilla` — Compresses values down to 1 bit (in the best case). The codec is efficient when storing series of floating point values that change slowly, because the best compression rate is achieved when neighboring values are binary equal. Implements the algorithm used in Gorilla TSDB, extending it to support 64 bit types. For additional information, see the "Compressing values" section of the [Gorilla: A Fast, Scalable, In-Memory Time Series Database](http://www.vldb.org/pvldb/vol8/p1816-teller.pdf) document. +- `T64` — Compression approach that crops unused high bits of values in integer data types (including `Enum`, `Date` and `DateTime`). At each step of its algorithm, codec takes a block of 64 values, puts them into 64x64 bit matrix, transposes it, crops the unused bits of values and returns the rest as a sequence. Unused bits are the bits, that don't differ between maximum and minimum values in the whole data part for which the compression is used. + +### Common purpose codecs {#create-query-common-purpose-codecs} + +Codecs: + +- `NONE` — No compression. +- `LZ4` — Lossless [data compression algorithm](https://github.com/lz4/lz4) used by default. Applies LZ4 fast compression. +- `LZ4HC[(level)]` — LZ4 CH (high compression) algorithm with configurable level. Default level: 9. If you set `level <= 0`, the default level is applied. Possible levels: [1, 12]. Recommended levels are in range: [4, 9]. +- `ZSTD[(level)]` — [ZSTD compression algorithm](https://en.wikipedia.org/wiki/Zstandard) with configurable `level`. Possible levels: [1, 22]. Default level: 1. + +High compression levels useful for asymmetric scenarios, like compress once, decompress a lot of times. Greater levels stands for better compression and higher CPU usage. + ## Temporary Tables ClickHouse supports temporary tables which have the following characteristics: From 1bf6e034e8157966ac039c7932f8d677f2f3779f Mon Sep 17 00:00:00 2001 From: Ivan <5627721+abyss7@users.noreply.github.com> Date: Wed, 7 Aug 2019 19:10:14 +0300 Subject: [PATCH 105/105] Fix infinite loop when reading Kafka messages (#6354) * Do not pause/resume consumer at all * Fix kafka tests * Try to ensure the subscription * Set timeout for kafka tests and return 'while True' * Update cluster.py * When doing a raw select from kafka, ignore client errors. They may rise due to 'Local: Timed out' while subscribing. --- dbms/src/Storages/IStorage.cpp | 7 +- dbms/src/Storages/IStorage.h | 2 +- .../Kafka/ReadBufferFromKafkaConsumer.cpp | 32 +++++--- dbms/src/Storages/StorageValues.cpp | 2 +- .../integration/test_storage_kafka/test.py | 76 +++++++++++-------- 5 files changed, 73 insertions(+), 46 deletions(-) diff --git a/dbms/src/Storages/IStorage.cpp b/dbms/src/Storages/IStorage.cpp index 687ca970311..1504df4f68d 100644 --- a/dbms/src/Storages/IStorage.cpp +++ b/dbms/src/Storages/IStorage.cpp @@ -145,9 +145,12 @@ namespace } } -void IStorage::check(const Names & column_names) const +void IStorage::check(const Names & column_names, bool include_virtuals) const { - const NamesAndTypesList & available_columns = getColumns().getAllPhysical(); + NamesAndTypesList available_columns = getColumns().getAllPhysical(); + if (include_virtuals) + available_columns.splice(available_columns.end(), getColumns().getVirtuals()); + const String list_of_columns = listOfColumns(available_columns); if (column_names.empty()) diff --git a/dbms/src/Storages/IStorage.h b/dbms/src/Storages/IStorage.h index 7d259f289ee..3f38dc08b83 100644 --- a/dbms/src/Storages/IStorage.h +++ b/dbms/src/Storages/IStorage.h @@ -116,7 +116,7 @@ public: /// thread-unsafe part. lockStructure must be acquired /// Verify that all the requested names are in the table and are set correctly: /// list of names is not empty and the names do not repeat. - void check(const Names & column_names) const; + void check(const Names & column_names, bool include_virtuals = false) const; /// Check that all the requested names are in the table and have the correct types. void check(const NamesAndTypesList & columns) const; diff --git a/dbms/src/Storages/Kafka/ReadBufferFromKafkaConsumer.cpp b/dbms/src/Storages/Kafka/ReadBufferFromKafkaConsumer.cpp index db3de302dd8..01fd09db7e3 100644 --- a/dbms/src/Storages/Kafka/ReadBufferFromKafkaConsumer.cpp +++ b/dbms/src/Storages/Kafka/ReadBufferFromKafkaConsumer.cpp @@ -56,32 +56,42 @@ void ReadBufferFromKafkaConsumer::commit() void ReadBufferFromKafkaConsumer::subscribe(const Names & topics) { { - String message = "Subscribed to topics:"; + String message = "Already subscribed to topics:"; for (const auto & topic : consumer->get_subscription()) message += " " + topic; LOG_TRACE(log, message); } { - String message = "Assigned to topics:"; + String message = "Already assigned to topics:"; for (const auto & toppar : consumer->get_assignment()) message += " " + toppar.get_topic(); LOG_TRACE(log, message); } - consumer->resume(); - // While we wait for an assignment after subscribtion, we'll poll zero messages anyway. // If we're doing a manual select then it's better to get something after a wait, then immediate nothing. - if (consumer->get_subscription().empty()) + // But due to the nature of async pause/resume/subscribe we can't guarantee any persistent state: + // see https://github.com/edenhill/librdkafka/issues/2455 + while (consumer->get_subscription().empty()) { - consumer->pause(); // don't accidentally read any messages - consumer->subscribe(topics); - consumer->poll(5s); - consumer->resume(); + stalled = false; - // FIXME: if we failed to receive "subscribe" response while polling and destroy consumer now, then we may hang up. - // see https://github.com/edenhill/librdkafka/issues/2077 + try + { + consumer->subscribe(topics); + if (nextImpl()) + break; + + // FIXME: if we failed to receive "subscribe" response while polling and destroy consumer now, then we may hang up. + // see https://github.com/edenhill/librdkafka/issues/2077 + } + catch (cppkafka::HandleException & e) + { + if (e.get_error() == RD_KAFKA_RESP_ERR__TIMED_OUT) + continue; + throw; + } } stalled = false; diff --git a/dbms/src/Storages/StorageValues.cpp b/dbms/src/Storages/StorageValues.cpp index d289a4d6579..79d1641f6c2 100644 --- a/dbms/src/Storages/StorageValues.cpp +++ b/dbms/src/Storages/StorageValues.cpp @@ -21,7 +21,7 @@ BlockInputStreams StorageValues::read( size_t /*max_block_size*/, unsigned /*num_streams*/) { - check(column_names); + check(column_names, true); return BlockInputStreams(1, std::make_shared(res_block)); } diff --git a/dbms/tests/integration/test_storage_kafka/test.py b/dbms/tests/integration/test_storage_kafka/test.py index 9be725d33b7..f066dc34a7f 100644 --- a/dbms/tests/integration/test_storage_kafka/test.py +++ b/dbms/tests/integration/test_storage_kafka/test.py @@ -122,6 +122,7 @@ def kafka_setup_teardown(): # Tests +@pytest.mark.timeout(60) def test_kafka_settings_old_syntax(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value UInt64) @@ -136,14 +137,15 @@ def test_kafka_settings_old_syntax(kafka_cluster): kafka_produce('old', messages) result = '' - for i in range(50): - result += instance.query('SELECT * FROM test.kafka') + while True: + result += instance.query('SELECT * FROM test.kafka', ignore_error=True) if kafka_check_result(result): break - time.sleep(0.5) + kafka_check_result(result, True) -@pytest.mark.skip(reason="fails for some reason") + +@pytest.mark.timeout(60) def test_kafka_settings_new_syntax(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value UInt64) @@ -171,14 +173,15 @@ def test_kafka_settings_new_syntax(kafka_cluster): kafka_produce('new', messages) result = '' - for i in range(50): - result += instance.query('SELECT * FROM test.kafka') + while True: + result += instance.query('SELECT * FROM test.kafka', ignore_error=True) if kafka_check_result(result): break - time.sleep(0.5) + kafka_check_result(result, True) +@pytest.mark.timeout(60) def test_kafka_csv_with_delimiter(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value UInt64) @@ -196,14 +199,15 @@ def test_kafka_csv_with_delimiter(kafka_cluster): kafka_produce('csv', messages) result = '' - for i in range(50): - result += instance.query('SELECT * FROM test.kafka') + while True: + result += instance.query('SELECT * FROM test.kafka', ignore_error=True) if kafka_check_result(result): break - time.sleep(0.5) + kafka_check_result(result, True) +@pytest.mark.timeout(60) def test_kafka_tsv_with_delimiter(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value UInt64) @@ -221,14 +225,15 @@ def test_kafka_tsv_with_delimiter(kafka_cluster): kafka_produce('tsv', messages) result = '' - for i in range(50): - result += instance.query('SELECT * FROM test.kafka') + while True: + result += instance.query('SELECT * FROM test.kafka', ignore_error=True) if kafka_check_result(result): break - time.sleep(0.5) + kafka_check_result(result, True) +@pytest.mark.timeout(60) def test_kafka_json_without_delimiter(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value UInt64) @@ -250,14 +255,15 @@ def test_kafka_json_without_delimiter(kafka_cluster): kafka_produce('json', [messages]) result = '' - for i in range(50): - result += instance.query('SELECT * FROM test.kafka') + while True: + result += instance.query('SELECT * FROM test.kafka', ignore_error=True) if kafka_check_result(result): break - time.sleep(0.5) + kafka_check_result(result, True) +@pytest.mark.timeout(60) def test_kafka_protobuf(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value String) @@ -274,14 +280,15 @@ def test_kafka_protobuf(kafka_cluster): kafka_produce_protobuf_messages('pb', 21, 29) result = '' - for i in range(50): - result += instance.query('SELECT * FROM test.kafka') + while True: + result += instance.query('SELECT * FROM test.kafka', ignore_error=True) if kafka_check_result(result): break - time.sleep(0.5) + kafka_check_result(result, True) +@pytest.mark.timeout(60) def test_kafka_materialized_view(kafka_cluster): instance.query(''' DROP TABLE IF EXISTS test.view; @@ -305,19 +312,20 @@ def test_kafka_materialized_view(kafka_cluster): messages.append(json.dumps({'key': i, 'value': i})) kafka_produce('mv', messages) - for i in range(50): + while True: result = instance.query('SELECT * FROM test.view') if kafka_check_result(result): break - time.sleep(0.5) - kafka_check_result(result, True) instance.query(''' DROP TABLE test.consumer; DROP TABLE test.view; ''') -@pytest.mark.skip(reason="Hungs") + kafka_check_result(result, True) + + +@pytest.mark.timeout(300) def test_kafka_flush_on_big_message(kafka_cluster): # Create batchs of messages of size ~100Kb kafka_messages = 1000 @@ -354,15 +362,20 @@ def test_kafka_flush_on_big_message(kafka_cluster): except kafka.errors.GroupCoordinatorNotAvailableError: continue - for i in range(50): + while True: result = instance.query('SELECT count() FROM test.view') if int(result) == kafka_messages*batch_messages: break - time.sleep(0.5) + + instance.query(''' + DROP TABLE test.consumer; + DROP TABLE test.view; + ''') assert int(result) == kafka_messages*batch_messages, 'ClickHouse lost some messages: {}'.format(result) +@pytest.mark.timeout(60) def test_kafka_virtual_columns(kafka_cluster): instance.query(''' CREATE TABLE test.kafka (key UInt64, value UInt64) @@ -384,14 +397,15 @@ def test_kafka_virtual_columns(kafka_cluster): kafka_produce('virt1', [messages]) result = '' - for i in range(50): - result += instance.query('SELECT _key, key, _topic, value, _offset FROM test.kafka') + while True: + result += instance.query('SELECT _key, key, _topic, value, _offset FROM test.kafka', ignore_error=True) if kafka_check_result(result, False, 'test_kafka_virtual1.reference'): break - time.sleep(0.5) + kafka_check_result(result, True, 'test_kafka_virtual1.reference') +@pytest.mark.timeout(60) def test_kafka_virtual_columns_with_materialized_view(kafka_cluster): instance.query(''' DROP TABLE IF EXISTS test.view; @@ -415,18 +429,18 @@ def test_kafka_virtual_columns_with_materialized_view(kafka_cluster): messages.append(json.dumps({'key': i, 'value': i})) kafka_produce('virt2', messages) - for i in range(50): + while True: result = instance.query('SELECT kafka_key, key, topic, value, offset FROM test.view') if kafka_check_result(result, False, 'test_kafka_virtual2.reference'): break - time.sleep(0.5) - kafka_check_result(result, True, 'test_kafka_virtual2.reference') instance.query(''' DROP TABLE test.consumer; DROP TABLE test.view; ''') + kafka_check_result(result, True, 'test_kafka_virtual2.reference') + if __name__ == '__main__': cluster.start()