From 0f20952f2ce98329ed64c567484272905bcfc6d9 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Sat, 10 Feb 2018 17:21:54 +0800 Subject: [PATCH 001/244] ISSUES-1885 UTF8 countCodePoints use simd --- dbms/src/Common/UTF8Helpers.h | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/dbms/src/Common/UTF8Helpers.h b/dbms/src/Common/UTF8Helpers.h index 1ce31426e85..ba1685c89f3 100644 --- a/dbms/src/Common/UTF8Helpers.h +++ b/dbms/src/Common/UTF8Helpers.h @@ -3,6 +3,9 @@ #include #include +#if __SSE2__ +#include +#endif namespace DB { @@ -49,9 +52,37 @@ inline size_t seqLength(const UInt8 first_octet) inline size_t countCodePoints(const UInt8 * data, size_t size) { size_t res = 0; + const auto end = data + size; - /// TODO SIMD implementation looks quite simple. - for (auto end = data + size; data < end; ++data) /// Skip UTF-8 continuation bytes. +#if __SSE2__ + const auto bytes_sse = sizeof(__m128i); + const auto src_end_sse = (data + size) - (size % bytes_sse); + + const auto upper_bound = _mm_set1_epi8(0x7F + 1); + const auto lower_bound = _mm_set1_epi8(0xC0 - 1); + + for (; data < src_end_sse;) + { + UInt8 mem_res[16] = {0}; + auto sse_res = _mm_set1_epi8(0); + + for (int i = 0; i < 0XFF && data < src_end_sse; ++i, data += bytes_sse) + { + const auto chars = _mm_loadu_si128(reinterpret_cast(data)); + sse_res = _mm_add_epi8(sse_res, + _mm_or_si128(_mm_cmplt_epi8(chars, upper_bound), + _mm_cmpgt_epi8(chars, lower_bound))); + } + + _mm_store_si128(reinterpret_cast<__m128i *>(mem_res), sse_res); + + for (auto count : mem_res) + res += count; + } + +#endif + + for (; data < end; ++data) /// Skip UTF-8 continuation bytes. res += (*data <= 0x7F || *data >= 0xC0); return res; From 73077e02459fb1a6da866aa785c21c4fba2d5d01 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Sun, 11 Feb 2018 22:38:51 +0800 Subject: [PATCH 002/244] ISSUES-1885 fix failed test --- dbms/src/Common/UTF8Helpers.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/dbms/src/Common/UTF8Helpers.h b/dbms/src/Common/UTF8Helpers.h index ba1685c89f3..c2f57b8107a 100644 --- a/dbms/src/Common/UTF8Helpers.h +++ b/dbms/src/Common/UTF8Helpers.h @@ -2,6 +2,7 @@ #include #include +#include #if __SSE2__ #include @@ -58,23 +59,27 @@ inline size_t countCodePoints(const UInt8 * data, size_t size) const auto bytes_sse = sizeof(__m128i); const auto src_end_sse = (data + size) - (size % bytes_sse); + const auto fill_sse = _mm_set1_epi8(0xFF); const auto upper_bound = _mm_set1_epi8(0x7F + 1); const auto lower_bound = _mm_set1_epi8(0xC0 - 1); for (; data < src_end_sse;) { - UInt8 mem_res[16] = {0}; + UInt16 mem_res[8] = {0}; auto sse_res = _mm_set1_epi8(0); - for (int i = 0; i < 0XFF && data < src_end_sse; ++i, data += bytes_sse) + for (int i = 0, limit = 0xFF; i < limit && data < src_end_sse; ++i, data += bytes_sse) { const auto chars = _mm_loadu_si128(reinterpret_cast(data)); - sse_res = _mm_add_epi8(sse_res, - _mm_or_si128(_mm_cmplt_epi8(chars, upper_bound), - _mm_cmpgt_epi8(chars, lower_bound))); + + const auto chars_cmpgt_res = _mm_or_si128(_mm_cmplt_epi8(chars, upper_bound), + _mm_cmpgt_epi8(chars, lower_bound)); + + sse_res = _mm_add_epi8(sse_res, _mm_add_epi8(_mm_xor_si128(chars_cmpgt_res, fill_sse), _mm_set1_epi8(1))); } - _mm_store_si128(reinterpret_cast<__m128i *>(mem_res), sse_res); + auto horizontal_add = _mm_sad_epu8(sse_res, _mm_set1_epi8(0)); + _mm_store_si128(reinterpret_cast<__m128i *>(mem_res), horizontal_add); for (auto count : mem_res) res += count; From 5f9292ac30056d23425399b451df9f24a14f09f1 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Mon, 12 Feb 2018 15:27:51 +0800 Subject: [PATCH 003/244] ISSUES-1885 resolve some opinions --- dbms/src/Common/UTF8Helpers.h | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/dbms/src/Common/UTF8Helpers.h b/dbms/src/Common/UTF8Helpers.h index c2f57b8107a..71ce6e4af51 100644 --- a/dbms/src/Common/UTF8Helpers.h +++ b/dbms/src/Common/UTF8Helpers.h @@ -2,12 +2,15 @@ #include #include -#include #if __SSE2__ #include #endif +#if __SSE4_1__ +#include +#endif + namespace DB { @@ -55,34 +58,39 @@ inline size_t countCodePoints(const UInt8 * data, size_t size) size_t res = 0; const auto end = data + size; -#if __SSE2__ +#if __SSE2__ && __SSE4_1__ const auto bytes_sse = sizeof(__m128i); const auto src_end_sse = (data + size) - (size % bytes_sse); - const auto fill_sse = _mm_set1_epi8(0xFF); - const auto upper_bound = _mm_set1_epi8(0x7F + 1); - const auto lower_bound = _mm_set1_epi8(0xC0 - 1); + const auto one_sse = _mm_set1_epi8(1); + const auto zero_sse = _mm_set1_epi8(0); + + const auto align_sse = _mm_set1_epi8(0xFF - 0xC0); + const auto upper_bound = _mm_set1_epi8(0x7F + (0xFF - 0xC0) + 1); for (; data < src_end_sse;) { - UInt16 mem_res[8] = {0}; auto sse_res = _mm_set1_epi8(0); for (int i = 0, limit = 0xFF; i < limit && data < src_end_sse; ++i, data += bytes_sse) { const auto chars = _mm_loadu_si128(reinterpret_cast(data)); - const auto chars_cmpgt_res = _mm_or_si128(_mm_cmplt_epi8(chars, upper_bound), - _mm_cmpgt_epi8(chars, lower_bound)); + ///Align to zero for the solve two case + const auto align_res = _mm_add_epi8(chars, align_sse); + ///Because _mm_cmmpgt_epid8 return 0xFF if true + const auto choose_res = _mm_blendv_epi8(zero_sse, one_sse, _mm_cmpgt_epi8(align_res, upper_bound)); - sse_res = _mm_add_epi8(sse_res, _mm_add_epi8(_mm_xor_si128(chars_cmpgt_res, fill_sse), _mm_set1_epi8(1))); + sse_res = _mm_add_epi8(sse_res, choose_res); } - auto horizontal_add = _mm_sad_epu8(sse_res, _mm_set1_epi8(0)); + UInt16 mem_res[8] = {0}; + auto horizontal_add = _mm_sad_epu8(sse_res, zero_sse); _mm_store_si128(reinterpret_cast<__m128i *>(mem_res), horizontal_add); - for (auto count : mem_res) - res += count; + /// Hack,Because only bytes MSB to LSB + res += mem_res[0]; + res += mem_res[4]; } #endif From acb5b99195171b104c5a04c918e3b12f23517dd1 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Mon, 12 Feb 2018 16:05:10 +0800 Subject: [PATCH 004/244] ISSUES-1885 fix align bound --- dbms/src/Common/UTF8Helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Common/UTF8Helpers.h b/dbms/src/Common/UTF8Helpers.h index 71ce6e4af51..c1aa9930eaa 100644 --- a/dbms/src/Common/UTF8Helpers.h +++ b/dbms/src/Common/UTF8Helpers.h @@ -65,8 +65,8 @@ inline size_t countCodePoints(const UInt8 * data, size_t size) const auto one_sse = _mm_set1_epi8(1); const auto zero_sse = _mm_set1_epi8(0); - const auto align_sse = _mm_set1_epi8(0xFF - 0xC0); - const auto upper_bound = _mm_set1_epi8(0x7F + (0xFF - 0xC0) + 1); + const auto align_sse = _mm_set1_epi8(0xFF - 0xC0 + 1); + const auto upper_bound = _mm_set1_epi8(0x7F + (0xFF - 0xC0 + 1) + 1); for (; data < src_end_sse;) { From 0d8730c687f2ebaa67a3a2b3bd0ca0faaf2e82ec Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Tue, 13 Feb 2018 13:46:16 +0800 Subject: [PATCH 005/244] ISSUES-1885 fix signed problem --- dbms/src/Common/UTF8Helpers.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dbms/src/Common/UTF8Helpers.h b/dbms/src/Common/UTF8Helpers.h index c1aa9930eaa..698ff369684 100644 --- a/dbms/src/Common/UTF8Helpers.h +++ b/dbms/src/Common/UTF8Helpers.h @@ -63,10 +63,10 @@ inline size_t countCodePoints(const UInt8 * data, size_t size) const auto src_end_sse = (data + size) - (size % bytes_sse); const auto one_sse = _mm_set1_epi8(1); - const auto zero_sse = _mm_set1_epi8(0); + const auto zero_sse = _mm_setzero_si128(); - const auto align_sse = _mm_set1_epi8(0xFF - 0xC0 + 1); - const auto upper_bound = _mm_set1_epi8(0x7F + (0xFF - 0xC0 + 1) + 1); + const auto align_sse = _mm_set1_epi8(0x40); + const auto upper_bound = _mm_set1_epi8(0xBF); for (; data < src_end_sse;) { @@ -77,11 +77,12 @@ inline size_t countCodePoints(const UInt8 * data, size_t size) const auto chars = _mm_loadu_si128(reinterpret_cast(data)); ///Align to zero for the solve two case - const auto align_res = _mm_add_epi8(chars, align_sse); - ///Because _mm_cmmpgt_epid8 return 0xFF if true - const auto choose_res = _mm_blendv_epi8(zero_sse, one_sse, _mm_cmpgt_epi8(align_res, upper_bound)); + const auto align_res = _mm_adds_epu8(chars, align_sse); + const auto less_than_and_equals = _mm_cmpeq_epi8(_mm_min_epu8(align_res, upper_bound), align_res); + ///Because _mm_cmpeq_epi8 return 0xFF if true + const auto choose_res = _mm_blendv_epi8(zero_sse, one_sse, less_than_and_equals); - sse_res = _mm_add_epi8(sse_res, choose_res); + sse_res = _mm_adds_epu8(sse_res, choose_res); } UInt16 mem_res[8] = {0}; From 6033096fd1d6aabd4fe6dafd1c8c52c1a16ae2e0 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Tue, 13 Feb 2018 16:12:20 +0800 Subject: [PATCH 006/244] ISSUES-1885 add performance test --- .../functions_length/functions_length.xml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 dbms/tests/performance/functions_length/functions_length.xml diff --git a/dbms/tests/performance/functions_length/functions_length.xml b/dbms/tests/performance/functions_length/functions_length.xml new file mode 100644 index 00000000000..d285cd2422f --- /dev/null +++ b/dbms/tests/performance/functions_length/functions_length.xml @@ -0,0 +1,38 @@ + + functions_length + once + + + + 10000 + + + 5000 + 20000 + + + + + + + + + + string + + materialize('') + materialize('Hello, world') + toString(number) + reinterpretAsString(number) + materialize('中文测试字符串') + materialize('https://github.com/yandex/ClickHouse/pull/1882') + materialize('https://zh.wikipedia.org/wiki/%E4%B8%AD%E6%97%A5%E9%9F%93%E7%B5%B1%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97%E6%93%B4%E5%B1%95%E5%8D%80F') + concat('中文测试字符串 ', toString(number), ' Привет, мир!') + concat(concat('中文测试字符串 ', toString(number), ' Привет, мир!') AS x, x, x, x, x, x, x, x, x, x) + convertCharset(concat(reinterpretAsString(rand64(1)), reinterpretAsString(rand64(2)), reinterpretAsString(rand64(3)), reinterpretAsString(rand64(4)), reinterpretAsString(rand64(5)), reinterpretAsString(rand64(6)), reinterpretAsString(rand64(7)), reinterpretAsString(rand64(8)), reinterpretAsString(rand64(9)), reinterpretAsString(rand64(10))), 'UTF-16', 'UTF-8') + + + + + SELECT count() FROM system.numbers WHERE NOT ignore(lengthUTF8({string})) + From eeae014a42affed560781499625c6ed6f705cb99 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Wed, 14 Feb 2018 08:11:12 +0800 Subject: [PATCH 007/244] ISSUES-1885 use movemask & popcnt --- dbms/src/Common/UTF8Helpers.h | 36 +++++++---------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/dbms/src/Common/UTF8Helpers.h b/dbms/src/Common/UTF8Helpers.h index 698ff369684..0237b6f036c 100644 --- a/dbms/src/Common/UTF8Helpers.h +++ b/dbms/src/Common/UTF8Helpers.h @@ -7,10 +7,6 @@ #include #endif -#if __SSE4_1__ -#include -#endif - namespace DB { @@ -58,40 +54,22 @@ inline size_t countCodePoints(const UInt8 * data, size_t size) size_t res = 0; const auto end = data + size; -#if __SSE2__ && __SSE4_1__ +#if __SSE2__ const auto bytes_sse = sizeof(__m128i); const auto src_end_sse = (data + size) - (size % bytes_sse); - const auto one_sse = _mm_set1_epi8(1); - const auto zero_sse = _mm_setzero_si128(); - const auto align_sse = _mm_set1_epi8(0x40); const auto upper_bound = _mm_set1_epi8(0xBF); - for (; data < src_end_sse;) + for (; data < src_end_sse; data += bytes_sse) { - auto sse_res = _mm_set1_epi8(0); + const auto chars = _mm_loadu_si128(reinterpret_cast(data)); - for (int i = 0, limit = 0xFF; i < limit && data < src_end_sse; ++i, data += bytes_sse) - { - const auto chars = _mm_loadu_si128(reinterpret_cast(data)); + ///Align to zero for the solve two case + const auto align_res = _mm_adds_epu8(chars, align_sse); + const auto less_than_and_equals = _mm_cmpeq_epi8(_mm_min_epu8(align_res, upper_bound), align_res); - ///Align to zero for the solve two case - const auto align_res = _mm_adds_epu8(chars, align_sse); - const auto less_than_and_equals = _mm_cmpeq_epi8(_mm_min_epu8(align_res, upper_bound), align_res); - ///Because _mm_cmpeq_epi8 return 0xFF if true - const auto choose_res = _mm_blendv_epi8(zero_sse, one_sse, less_than_and_equals); - - sse_res = _mm_adds_epu8(sse_res, choose_res); - } - - UInt16 mem_res[8] = {0}; - auto horizontal_add = _mm_sad_epu8(sse_res, zero_sse); - _mm_store_si128(reinterpret_cast<__m128i *>(mem_res), horizontal_add); - - /// Hack,Because only bytes MSB to LSB - res += mem_res[0]; - res += mem_res[4]; + res += __builtin_popcount(_mm_movemask_epi8(less_than_and_equals)); } #endif From 0b26189fabfa5e3fce522c53fb0895031360a3be Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Sat, 24 Feb 2018 14:06:53 +0200 Subject: [PATCH 008/244] prototype: show server group name in client --- dbms/src/Client/Connection.cpp | 12 ++++++++++++ dbms/src/Client/Connection.h | 2 ++ dbms/src/Core/Defines.h | 1 + dbms/src/Server/Client.cpp | 5 ++++- dbms/src/Server/TCPHandler.cpp | 4 ++++ dbms/src/Server/config.xml | 2 +- 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/dbms/src/Client/Connection.cpp b/dbms/src/Client/Connection.cpp index 3c6c8d75d0e..9b57c1b39b2 100644 --- a/dbms/src/Client/Connection.cpp +++ b/dbms/src/Client/Connection.cpp @@ -148,6 +148,10 @@ void Connection::receiveHello() { readStringBinary(server_timezone, *in); } + if (server_revision >= DBMS_MIN_REVISION_WITH_SERVER_GROUP_NAME) + { + readStringBinary(server_group_name, *in); + } } else if (packet_type == Protocol::Server::Exception) receiveException()->rethrow(); @@ -203,6 +207,14 @@ const String & Connection::getServerTimezone() return server_timezone; } +const String & Connection::getServerGroupname() +{ + if (!connected) + connect(); + + return server_group_name; +} + void Connection::forceConnected() { if (!connected) diff --git a/dbms/src/Client/Connection.h b/dbms/src/Client/Connection.h index c9b401c91ee..06f8e94e29c 100644 --- a/dbms/src/Client/Connection.h +++ b/dbms/src/Client/Connection.h @@ -134,6 +134,7 @@ public: void getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision); const String & getServerTimezone(); + const String & getServerGroupname(); /// For log and exception messages. const String & getDescription() const; @@ -213,6 +214,7 @@ private: UInt64 server_version_minor = 0; UInt64 server_revision = 0; String server_timezone; + String server_group_name; std::unique_ptr socket; std::shared_ptr in; diff --git a/dbms/src/Core/Defines.h b/dbms/src/Core/Defines.h index 8b69d83d69e..180d2a0dc2b 100644 --- a/dbms/src/Core/Defines.h +++ b/dbms/src/Core/Defines.h @@ -60,6 +60,7 @@ #define DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO 54060 #define DBMS_MIN_REVISION_WITH_TABLES_STATUS 54226 #define DBMS_MIN_REVISION_WITH_TIME_ZONE_PARAMETER_IN_DATETIME_DATA_TYPE 54337 +#define DBMS_MIN_REVISION_WITH_SERVER_GROUP_NAME 54355 /// Version of ClickHouse TCP protocol. Set to git tag with latest protocol change. #define DBMS_TCP_PROTOCOL_VERSION 54226 diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 238be504aac..1189dd4d6bc 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -153,6 +153,7 @@ private: /// If the last query resulted in exception. bool got_exception = false; String server_version; + String server_group_name; Stopwatch watch; @@ -425,6 +426,7 @@ private: connection->getServerVersion(server_name, server_version_major, server_version_minor, server_revision); server_version = toString(server_version_major) + "." + toString(server_version_minor) + "." + toString(server_revision); + server_group_name = connection->getServerGroupname(); if (is_interactive) { std::cout << "Connected to " << server_name @@ -450,7 +452,8 @@ private: { String query; String prev_query; - while (char * line_ = readline(query.empty() ? ":) " : ":-] ")) + String prompt = server_group_name.length() ? "[" + server_group_name + "] :) " : ":) "; + while (char * line_ = readline(query.empty() ? prompt.c_str() : ":-] ")) { String line = line_; free(line_); diff --git a/dbms/src/Server/TCPHandler.cpp b/dbms/src/Server/TCPHandler.cpp index 7dadeef966b..70d16d6a16b 100644 --- a/dbms/src/Server/TCPHandler.cpp +++ b/dbms/src/Server/TCPHandler.cpp @@ -508,6 +508,10 @@ void TCPHandler::sendHello() { writeStringBinary(DateLUT::instance().getTimeZone(), *out); } + if (client_revision >= DBMS_MIN_REVISION_WITH_SERVER_GROUP_NAME) + { + writeStringBinary(server.config().getString("group_name"), *out); + } out->next(); } diff --git a/dbms/src/Server/config.xml b/dbms/src/Server/config.xml index e0b4ea563ac..3fe4f580f40 100644 --- a/dbms/src/Server/config.xml +++ b/dbms/src/Server/config.xml @@ -8,7 +8,7 @@ 10 - + staging 8123 9000 From 2216f9e0cccbed113744d475c13087ade37ff2c9 Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Sat, 24 Feb 2018 14:36:19 +0200 Subject: [PATCH 009/244] fix function name --- dbms/src/Client/Connection.cpp | 2 +- dbms/src/Client/Connection.h | 2 +- dbms/src/Server/Client.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Client/Connection.cpp b/dbms/src/Client/Connection.cpp index 9b57c1b39b2..4e5ee88c782 100644 --- a/dbms/src/Client/Connection.cpp +++ b/dbms/src/Client/Connection.cpp @@ -207,7 +207,7 @@ const String & Connection::getServerTimezone() return server_timezone; } -const String & Connection::getServerGroupname() +const String & Connection::getServerGroupName() { if (!connected) connect(); diff --git a/dbms/src/Client/Connection.h b/dbms/src/Client/Connection.h index 06f8e94e29c..0caf6ead9f2 100644 --- a/dbms/src/Client/Connection.h +++ b/dbms/src/Client/Connection.h @@ -134,7 +134,7 @@ public: void getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision); const String & getServerTimezone(); - const String & getServerGroupname(); + const String & getServerGroupName(); /// For log and exception messages. const String & getDescription() const; diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 1189dd4d6bc..f644da2f3ea 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -426,7 +426,7 @@ private: connection->getServerVersion(server_name, server_version_major, server_version_minor, server_revision); server_version = toString(server_version_major) + "." + toString(server_version_minor) + "." + toString(server_revision); - server_group_name = connection->getServerGroupname(); + server_group_name = connection->getServerGroupName(); if (is_interactive) { std::cout << "Connected to " << server_name From d3b6aafa097c3c772531ea30b07bd9348bf43856 Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 26 Feb 2018 08:49:17 +0200 Subject: [PATCH 010/244] Rename group_name to display_name --- dbms/src/Client/Connection.cpp | 8 ++++---- dbms/src/Client/Connection.h | 4 ++-- dbms/src/Core/Defines.h | 2 +- dbms/src/Server/Client.cpp | 6 +++--- dbms/src/Server/TCPHandler.cpp | 5 +++-- dbms/src/Server/config.xml | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/dbms/src/Client/Connection.cpp b/dbms/src/Client/Connection.cpp index 4e5ee88c782..0960ac8e77d 100644 --- a/dbms/src/Client/Connection.cpp +++ b/dbms/src/Client/Connection.cpp @@ -148,9 +148,9 @@ void Connection::receiveHello() { readStringBinary(server_timezone, *in); } - if (server_revision >= DBMS_MIN_REVISION_WITH_SERVER_GROUP_NAME) + if (server_revision >= DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME) { - readStringBinary(server_group_name, *in); + readStringBinary(server_display_name, *in); } } else if (packet_type == Protocol::Server::Exception) @@ -207,12 +207,12 @@ const String & Connection::getServerTimezone() return server_timezone; } -const String & Connection::getServerGroupName() +const String & Connection::getServerDisplayName() { if (!connected) connect(); - return server_group_name; + return server_display_name; } void Connection::forceConnected() diff --git a/dbms/src/Client/Connection.h b/dbms/src/Client/Connection.h index 0caf6ead9f2..cac188f12c8 100644 --- a/dbms/src/Client/Connection.h +++ b/dbms/src/Client/Connection.h @@ -134,7 +134,7 @@ public: void getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision); const String & getServerTimezone(); - const String & getServerGroupName(); + const String & getServerDisplayName(); /// For log and exception messages. const String & getDescription() const; @@ -214,7 +214,7 @@ private: UInt64 server_version_minor = 0; UInt64 server_revision = 0; String server_timezone; - String server_group_name; + String server_display_name; std::unique_ptr socket; std::shared_ptr in; diff --git a/dbms/src/Core/Defines.h b/dbms/src/Core/Defines.h index 180d2a0dc2b..1cc14a62155 100644 --- a/dbms/src/Core/Defines.h +++ b/dbms/src/Core/Defines.h @@ -60,7 +60,7 @@ #define DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO 54060 #define DBMS_MIN_REVISION_WITH_TABLES_STATUS 54226 #define DBMS_MIN_REVISION_WITH_TIME_ZONE_PARAMETER_IN_DATETIME_DATA_TYPE 54337 -#define DBMS_MIN_REVISION_WITH_SERVER_GROUP_NAME 54355 +#define DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME 54355 /// Version of ClickHouse TCP protocol. Set to git tag with latest protocol change. #define DBMS_TCP_PROTOCOL_VERSION 54226 diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index f644da2f3ea..4760c8d4874 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -153,7 +153,7 @@ private: /// If the last query resulted in exception. bool got_exception = false; String server_version; - String server_group_name; + String server_display_name; Stopwatch watch; @@ -426,7 +426,7 @@ private: connection->getServerVersion(server_name, server_version_major, server_version_minor, server_revision); server_version = toString(server_version_major) + "." + toString(server_version_minor) + "." + toString(server_revision); - server_group_name = connection->getServerGroupName(); + server_display_name = connection->getServerDisplayName(); if (is_interactive) { std::cout << "Connected to " << server_name @@ -452,7 +452,7 @@ private: { String query; String prev_query; - String prompt = server_group_name.length() ? "[" + server_group_name + "] :) " : ":) "; + String prompt = server_display_name.length() ? "[" + server_display_name + "] :) " : ":) "; while (char * line_ = readline(query.empty() ? prompt.c_str() : ":-] ")) { String line = line_; diff --git a/dbms/src/Server/TCPHandler.cpp b/dbms/src/Server/TCPHandler.cpp index 70d16d6a16b..e6ac7b5d5d6 100644 --- a/dbms/src/Server/TCPHandler.cpp +++ b/dbms/src/Server/TCPHandler.cpp @@ -31,6 +31,7 @@ #include "TCPHandler.h" #include +#include namespace DB @@ -508,9 +509,9 @@ void TCPHandler::sendHello() { writeStringBinary(DateLUT::instance().getTimeZone(), *out); } - if (client_revision >= DBMS_MIN_REVISION_WITH_SERVER_GROUP_NAME) + if (client_revision >= DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME) { - writeStringBinary(server.config().getString("group_name"), *out); + writeStringBinary(server.config().getString("display_name", getFQDNOrHostName()), *out); } out->next(); } diff --git a/dbms/src/Server/config.xml b/dbms/src/Server/config.xml index 3fe4f580f40..4c1afb53639 100644 --- a/dbms/src/Server/config.xml +++ b/dbms/src/Server/config.xml @@ -8,7 +8,7 @@ 10 - staging + 8123 9000 From f15b55f9295b6422ece51bad2c0e0fccf4e5fd6e Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 26 Feb 2018 15:24:06 +0200 Subject: [PATCH 011/244] prototype: custom prompt --- dbms/src/Server/Client.cpp | 59 ++++++++++++++++++++++++++- dbms/src/Server/clickhouse-client.xml | 4 ++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 4760c8d4874..989a83a0030 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include @@ -138,6 +140,8 @@ private: String current_profile; + String prompt_by_server_display_name = "%display_name% :)"; + /// Path to a file containing command history. String history_file; @@ -335,6 +339,18 @@ private: } } + Strings keys; + config().keys("prompt_by_server_display_name", keys); + + for (const String & key : keys) + { + if (server_display_name.find(key) != std::string::npos) + { + prompt_by_server_display_name = config().getString("prompt_by_server_display_name." + key); + break; + } + } + if (is_interactive) { if (print_time_to_stderr) @@ -447,13 +463,52 @@ private: return select(1, &fds, 0, 0, &timeout) == 1; } + const String prompt() const + { + std::map colors = { + { "red", "31" }, + { "green", "32" }, + { "yellow", "33" }, + { "blue", "34" }, + { "magenta", "35" }, + { "cyan", "36" }, + }; + + String pattern = prompt_by_server_display_name; + + for (const auto & pair: colors) + { + String name = static_cast(pair.first); + String code = static_cast(pair.second); + + boost::replace_all(pattern, "[" + name + "]", "\33[1;" + code + "m"); + boost::replace_all(pattern, "[/" + name + "]", "\033[0m"); + } + + std::map environment = { + {"host", config().getString("host", "localhost")}, + {"display_name", server_display_name}, + {"user", config().getString("user", "default")}, + {"database", config().getString("database", "default")}, + }; + + for (const auto & pair: environment) + { + String key = static_cast(pair.first); + String value = static_cast(pair.second); + + boost::replace_all(pattern, "%" + key + "%", value); + } + + return pattern; + } void loop() { String query; String prev_query; - String prompt = server_display_name.length() ? "[" + server_display_name + "] :) " : ":) "; - while (char * line_ = readline(query.empty() ? prompt.c_str() : ":-] ")) + + while (char * line_ = readline(query.empty() ? prompt().c_str() : ":-] ")) { String line = line_; free(line_); diff --git a/dbms/src/Server/clickhouse-client.xml b/dbms/src/Server/clickhouse-client.xml index c19606c518b..e5ec8318e94 100644 --- a/dbms/src/Server/clickhouse-client.xml +++ b/dbms/src/Server/clickhouse-client.xml @@ -13,4 +13,8 @@ + + %display_name% [green]:)[/green] + %display_name% [red]:)[/red] + From 213caffddeda54f92392a058a36df10816a1d42d Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 26 Feb 2018 15:48:07 +0200 Subject: [PATCH 012/244] add default section to client config --- dbms/src/Server/Client.cpp | 4 +++- dbms/src/Server/clickhouse-client.xml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 989a83a0030..229167763e9 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -140,7 +140,7 @@ private: String current_profile; - String prompt_by_server_display_name = "%display_name% :)"; + String prompt_by_server_display_name; /// Path to a file containing command history. String history_file; @@ -342,6 +342,8 @@ private: Strings keys; config().keys("prompt_by_server_display_name", keys); + prompt_by_server_display_name = config().getString("prompt_by_server_display_name.default", "%display_name% :)"); + for (const String & key : keys) { if (server_display_name.find(key) != std::string::npos) diff --git a/dbms/src/Server/clickhouse-client.xml b/dbms/src/Server/clickhouse-client.xml index e5ec8318e94..6b569f02bc6 100644 --- a/dbms/src/Server/clickhouse-client.xml +++ b/dbms/src/Server/clickhouse-client.xml @@ -14,6 +14,7 @@ + %display_name% :) %display_name% [green]:)[/green] %display_name% [red]:)[/red] From 390ce9428b2754a956e2e288f87d7755aa3c856a Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Tue, 27 Feb 2018 09:47:15 +0200 Subject: [PATCH 013/244] add background colors --- dbms/src/Server/Client.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 229167763e9..a13dd195eff 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -468,12 +468,43 @@ private: const String prompt() const { std::map colors = { + /* Foreground */ + { "black", "30" }, { "red", "31" }, { "green", "32" }, { "yellow", "33" }, { "blue", "34" }, { "magenta", "35" }, { "cyan", "36" }, + { "white", "97" }, + + { "light gray", "37" }, + { "dark gray", "90" }, + { "light red", "91" }, + { "light green", "92" }, + { "light yellow", "93" }, + { "light blue", "94" }, + { "light magenta", "95" }, + { "light cyan", "96" }, + + /* Background*/ + { "background black", "40" }, + { "background red", "41" }, + { "background green", "42" }, + { "background yellow", "43" }, + { "background blue", "44" }, + { "background magenta", "45" }, + { "background cyan", "46" }, + { "background white", "107" }, + + { "background light gray", "47" }, + { "background dark gray", "100" }, + { "background light red", "101" }, + { "background light green", "102" }, + { "background light yellow", "103" }, + { "background light blue", "104" }, + { "background light magenta", "105" }, + { "background light cyan", "106" }, }; String pattern = prompt_by_server_display_name; @@ -489,6 +520,7 @@ private: std::map environment = { {"host", config().getString("host", "localhost")}, + {"port", config().getString("port", "9000")}, {"display_name", server_display_name}, {"user", config().getString("user", "default")}, {"database", config().getString("database", "default")}, From 053b3f21a02a9ca35e2ec05b56961bbcb6d605fc Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Tue, 27 Feb 2018 09:57:18 +0200 Subject: [PATCH 014/244] move 'colors' from function body --- dbms/src/Server/Client.cpp | 78 +++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index a13dd195eff..741d2effd98 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -103,7 +103,45 @@ private: "учшеж", "йгшеж", "дщпщгеж", "q", "й", "\\q", "\\Q", "\\й", "\\Й", ":q", "Жй" }; + std::map colors = { + /* Foreground */ + { "black", "30" }, + { "red", "31" }, + { "green", "32" }, + { "yellow", "33" }, + { "blue", "34" }, + { "magenta", "35" }, + { "cyan", "36" }, + { "white", "97" }, + { "light gray", "37" }, + { "dark gray", "90" }, + { "light red", "91" }, + { "light green", "92" }, + { "light yellow", "93" }, + { "light blue", "94" }, + { "light magenta", "95" }, + { "light cyan", "96" }, + + /* Background*/ + { "background black", "40" }, + { "background red", "41" }, + { "background green", "42" }, + { "background yellow", "43" }, + { "background blue", "44" }, + { "background magenta", "45" }, + { "background cyan", "46" }, + { "background white", "107" }, + + { "background light gray", "47" }, + { "background dark gray", "100" }, + { "background light red", "101" }, + { "background light green", "102" }, + { "background light yellow", "103" }, + { "background light blue", "104" }, + { "background light magenta", "105" }, + { "background light cyan", "106" }, + }; bool is_interactive = true; /// Use either readline interface or batch mode. bool need_render_progress = true; /// Render query execution progress. bool echo_queries = false; /// Print queries before execution in batch mode. @@ -467,46 +505,6 @@ private: const String prompt() const { - std::map colors = { - /* Foreground */ - { "black", "30" }, - { "red", "31" }, - { "green", "32" }, - { "yellow", "33" }, - { "blue", "34" }, - { "magenta", "35" }, - { "cyan", "36" }, - { "white", "97" }, - - { "light gray", "37" }, - { "dark gray", "90" }, - { "light red", "91" }, - { "light green", "92" }, - { "light yellow", "93" }, - { "light blue", "94" }, - { "light magenta", "95" }, - { "light cyan", "96" }, - - /* Background*/ - { "background black", "40" }, - { "background red", "41" }, - { "background green", "42" }, - { "background yellow", "43" }, - { "background blue", "44" }, - { "background magenta", "45" }, - { "background cyan", "46" }, - { "background white", "107" }, - - { "background light gray", "47" }, - { "background dark gray", "100" }, - { "background light red", "101" }, - { "background light green", "102" }, - { "background light yellow", "103" }, - { "background light blue", "104" }, - { "background light magenta", "105" }, - { "background light cyan", "106" }, - }; - String pattern = prompt_by_server_display_name; for (const auto & pair: colors) From bba059145299d7015ad1087282f79d86d44fdc9d Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 5 Mar 2018 12:20:23 +0200 Subject: [PATCH 015/244] add X-ClickHouse-Display-Name header to HTTPHandler --- dbms/src/Server/Client.cpp | 13 +++++-------- dbms/src/Server/HTTPHandler.cpp | 5 +++-- dbms/src/Server/HTTPHandler.h | 1 + 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 741d2effd98..bf08072a20d 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -507,10 +507,10 @@ private: { String pattern = prompt_by_server_display_name; - for (const auto & pair: colors) + for (const auto & [key, value]: colors) { - String name = static_cast(pair.first); - String code = static_cast(pair.second); + String name = static_cast(key); + String code = static_cast(value); boost::replace_all(pattern, "[" + name + "]", "\33[1;" + code + "m"); boost::replace_all(pattern, "[/" + name + "]", "\033[0m"); @@ -524,12 +524,9 @@ private: {"database", config().getString("database", "default")}, }; - for (const auto & pair: environment) + for (const auto & [key, value]: environment) { - String key = static_cast(pair.first); - String value = static_cast(pair.second); - - boost::replace_all(pattern, "%" + key + "%", value); + boost::replace_all(pattern, "%" + static_cast(key) + "%", static_cast(value)); } return pattern; diff --git a/dbms/src/Server/HTTPHandler.cpp b/dbms/src/Server/HTTPHandler.cpp index 555d4b5f3ba..3d99257f70a 100644 --- a/dbms/src/Server/HTTPHandler.cpp +++ b/dbms/src/Server/HTTPHandler.cpp @@ -12,7 +12,7 @@ #include #include #include - +#include #include #include #include @@ -198,6 +198,7 @@ HTTPHandler::HTTPHandler(IServer & server_) : server(server_) , log(&Logger::get("HTTPHandler")) { + display_name = server.config().getString("display_name", getFQDNOrHostName()); } @@ -631,7 +632,7 @@ void HTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Ne try { response.setContentType("text/plain; charset=UTF-8"); - + response.set("X-ClickHouse-Display-Name", display_name); /// For keep-alive to work. if (request.getVersion() == Poco::Net::HTTPServerRequest::HTTP_1_1) response.setChunkedTransferEncoding(true); diff --git a/dbms/src/Server/HTTPHandler.h b/dbms/src/Server/HTTPHandler.h index b0b7164852e..255da56c8d9 100644 --- a/dbms/src/Server/HTTPHandler.h +++ b/dbms/src/Server/HTTPHandler.h @@ -54,6 +54,7 @@ private: IServer & server; Poco::Logger * log; + String display_name; CurrentMetrics::Increment metric_increment{CurrentMetrics::HTTPConnection}; From 3c09dacb5f1e049ffdaaddd624d18252a72e198a Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 5 Mar 2018 14:05:48 +0200 Subject: [PATCH 016/244] fix test --- dbms/tests/queries/0_stateless/00501_http_head.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00501_http_head.sh b/dbms/tests/queries/0_stateless/00501_http_head.sh index c15b8679fab..7fb675e5b8a 100755 --- a/dbms/tests/queries/0_stateless/00501_http_head.sh +++ b/dbms/tests/queries/0_stateless/00501_http_head.sh @@ -7,7 +7,7 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) . $CURDIR/../shell_config.sh ( ${CLICKHOUSE_CURL} -s --head "${CLICKHOUSE_URL}?query=SELECT%201"; - ${CLICKHOUSE_CURL} -s --head "${CLICKHOUSE_URL}?query=select+*+from+system.numbers+limit+1000000" ) | grep -v "Date:" + ${CLICKHOUSE_CURL} -s --head "${CLICKHOUSE_URL}?query=select+*+from+system.numbers+limit+1000000" ) | grep -v "Date:" | grep -v "X-ClickHouse-Display-Name:" if [[ `${CLICKHOUSE_CURL} -sS -X POST -I "${CLICKHOUSE_URL}?query=SELECT+1" | grep -c '411 Length Required'` -ne 1 ]]; then echo FAIL From 5e55a605f09d593b59d32a5fd354c0a21eba17fe Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 5 Mar 2018 14:18:53 +0200 Subject: [PATCH 017/244] add bold font --- dbms/src/Server/Client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index bf08072a20d..e47c4b5b5ce 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -104,6 +104,7 @@ private: "q", "й", "\\q", "\\Q", "\\й", "\\Й", ":q", "Жй" }; std::map colors = { + { "bold", "1" }, /* Foreground */ { "black", "30" }, { "red", "31" }, From 27a9ce8dd74a64dcfcd4a90805cd7d752f985cbf Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 5 Mar 2018 16:47:10 +0200 Subject: [PATCH 018/244] Display host if display name is empty --- dbms/src/Server/Client.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index e47c4b5b5ce..a7394fa7c7a 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -484,6 +484,12 @@ private: server_version = toString(server_version_major) + "." + toString(server_version_minor) + "." + toString(server_revision); server_display_name = connection->getServerDisplayName(); + + if (server_display_name.length() == 0) + { + server_display_name = config().getString("host", "localhost"); + } + if (is_interactive) { std::cout << "Connected to " << server_name From 950a7f83cfdfd675558f6607e413278f214a1896 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 7 Mar 2018 23:54:36 +0300 Subject: [PATCH 019/244] Update Defines.h --- dbms/src/Core/Defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Core/Defines.h b/dbms/src/Core/Defines.h index 1cc14a62155..f860bd8c71c 100644 --- a/dbms/src/Core/Defines.h +++ b/dbms/src/Core/Defines.h @@ -60,7 +60,7 @@ #define DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO 54060 #define DBMS_MIN_REVISION_WITH_TABLES_STATUS 54226 #define DBMS_MIN_REVISION_WITH_TIME_ZONE_PARAMETER_IN_DATETIME_DATA_TYPE 54337 -#define DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME 54355 +#define DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME 54358 /// Version of ClickHouse TCP protocol. Set to git tag with latest protocol change. #define DBMS_TCP_PROTOCOL_VERSION 54226 From fdcc88b5a28464b46333b84ffbbd70e9c18dc3a3 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 7 Mar 2018 23:56:15 +0300 Subject: [PATCH 020/244] Update Client.cpp --- dbms/src/Server/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index a7394fa7c7a..fff59cd6e4e 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -124,7 +124,7 @@ private: { "light magenta", "95" }, { "light cyan", "96" }, - /* Background*/ + /* Background */ { "background black", "40" }, { "background red", "41" }, { "background green", "42" }, From 052079b73a49852765e5a03d482f14d9b18775a2 Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Thu, 8 Mar 2018 09:36:58 +0200 Subject: [PATCH 021/244] Use standard markup '{}' like macros. Add coments. --- dbms/src/Server/Client.cpp | 9 +++------ dbms/src/Server/HTTPHandler.cpp | 4 ++-- dbms/src/Server/HTTPHandler.h | 4 +++- dbms/src/Server/TCPHandler.cpp | 3 +-- dbms/src/Server/TCPHandler.h | 6 +++++- dbms/src/Server/clickhouse-client.xml | 15 ++++++++++++--- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index a7394fa7c7a..82e15d9d302 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -381,7 +381,7 @@ private: Strings keys; config().keys("prompt_by_server_display_name", keys); - prompt_by_server_display_name = config().getString("prompt_by_server_display_name.default", "%display_name% :)"); + prompt_by_server_display_name = config().getString("prompt_by_server_display_name.default", "{display_name} :) "); for (const String & key : keys) { @@ -514,11 +514,8 @@ private: { String pattern = prompt_by_server_display_name; - for (const auto & [key, value]: colors) + for (const auto & [name, code]: colors) { - String name = static_cast(key); - String code = static_cast(value); - boost::replace_all(pattern, "[" + name + "]", "\33[1;" + code + "m"); boost::replace_all(pattern, "[/" + name + "]", "\033[0m"); } @@ -533,7 +530,7 @@ private: for (const auto & [key, value]: environment) { - boost::replace_all(pattern, "%" + static_cast(key) + "%", static_cast(value)); + boost::replace_all(pattern, "{" + key + "}", value); } return pattern; diff --git a/dbms/src/Server/HTTPHandler.cpp b/dbms/src/Server/HTTPHandler.cpp index 3d99257f70a..539573fc8fb 100644 --- a/dbms/src/Server/HTTPHandler.cpp +++ b/dbms/src/Server/HTTPHandler.cpp @@ -198,7 +198,7 @@ HTTPHandler::HTTPHandler(IServer & server_) : server(server_) , log(&Logger::get("HTTPHandler")) { - display_name = server.config().getString("display_name", getFQDNOrHostName()); + server_display_name = server.config().getString("display_name", getFQDNOrHostName()); } @@ -632,7 +632,7 @@ void HTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Ne try { response.setContentType("text/plain; charset=UTF-8"); - response.set("X-ClickHouse-Display-Name", display_name); + response.set("X-ClickHouse-Server-Display-Name", server_display_name); /// For keep-alive to work. if (request.getVersion() == Poco::Net::HTTPServerRequest::HTTP_1_1) response.setChunkedTransferEncoding(true); diff --git a/dbms/src/Server/HTTPHandler.h b/dbms/src/Server/HTTPHandler.h index 255da56c8d9..72606afa827 100644 --- a/dbms/src/Server/HTTPHandler.h +++ b/dbms/src/Server/HTTPHandler.h @@ -54,7 +54,9 @@ private: IServer & server; Poco::Logger * log; - String display_name; + + /// It is the name of the server that will be sent in an http-header X-ClickHouse-Server-Display-Name. + String server_display_name; CurrentMetrics::Increment metric_increment{CurrentMetrics::HTTPConnection}; diff --git a/dbms/src/Server/TCPHandler.cpp b/dbms/src/Server/TCPHandler.cpp index e6ac7b5d5d6..729916738c3 100644 --- a/dbms/src/Server/TCPHandler.cpp +++ b/dbms/src/Server/TCPHandler.cpp @@ -31,7 +31,6 @@ #include "TCPHandler.h" #include -#include namespace DB @@ -511,7 +510,7 @@ void TCPHandler::sendHello() } if (client_revision >= DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME) { - writeStringBinary(server.config().getString("display_name", getFQDNOrHostName()), *out); + writeStringBinary(server_display_name, *out); } out->next(); } diff --git a/dbms/src/Server/TCPHandler.h b/dbms/src/Server/TCPHandler.h index 444d8eb4990..f53850ee487 100644 --- a/dbms/src/Server/TCPHandler.h +++ b/dbms/src/Server/TCPHandler.h @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -81,6 +82,7 @@ public: , connection_context(server.context()) , query_context(server.context()) { + server_display_name = server.config().getString("display_name", getFQDNOrHostName()); } void run(); @@ -111,7 +113,9 @@ private: QueryState state; CurrentMetrics::Increment metric_increment{CurrentMetrics::TCPConnection}; - + + /// It is the name of the server that will be sent to the client. + String server_display_name; void runImpl(); diff --git a/dbms/src/Server/clickhouse-client.xml b/dbms/src/Server/clickhouse-client.xml index 6b569f02bc6..ecd19d6c623 100644 --- a/dbms/src/Server/clickhouse-client.xml +++ b/dbms/src/Server/clickhouse-client.xml @@ -13,9 +13,18 @@ + - %display_name% :) - %display_name% [green]:)[/green] - %display_name% [red]:)[/red] + {display_name} :) + {display_name} [green]:)[/green + {display_name} [red]:)[/red] From 8c4a7b774efc7e352347c0415c20e4774b5508b0 Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Thu, 8 Mar 2018 10:55:27 +0200 Subject: [PATCH 022/244] Removed BB-Style macros for colors. Preparing prompt pattern once and replace current database in the cycle only. --- dbms/src/Server/Client.cpp | 93 ++++++------------- dbms/src/Server/clickhouse-client.xml | 5 +- .../queries/0_stateless/00501_http_head.sh | 2 +- 3 files changed, 33 insertions(+), 67 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index f490b61b12a..959dfe9a199 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -103,46 +103,6 @@ private: "учшеж", "йгшеж", "дщпщгеж", "q", "й", "\\q", "\\Q", "\\й", "\\Й", ":q", "Жй" }; - std::map colors = { - { "bold", "1" }, - /* Foreground */ - { "black", "30" }, - { "red", "31" }, - { "green", "32" }, - { "yellow", "33" }, - { "blue", "34" }, - { "magenta", "35" }, - { "cyan", "36" }, - { "white", "97" }, - - { "light gray", "37" }, - { "dark gray", "90" }, - { "light red", "91" }, - { "light green", "92" }, - { "light yellow", "93" }, - { "light blue", "94" }, - { "light magenta", "95" }, - { "light cyan", "96" }, - - /* Background */ - { "background black", "40" }, - { "background red", "41" }, - { "background green", "42" }, - { "background yellow", "43" }, - { "background blue", "44" }, - { "background magenta", "45" }, - { "background cyan", "46" }, - { "background white", "107" }, - - { "background light gray", "47" }, - { "background dark gray", "100" }, - { "background light red", "101" }, - { "background light green", "102" }, - { "background light yellow", "103" }, - { "background light blue", "104" }, - { "background light magenta", "105" }, - { "background light cyan", "106" }, - }; bool is_interactive = true; /// Use either readline interface or batch mode. bool need_render_progress = true; /// Render query execution progress. bool echo_queries = false; /// Print queries before execution in batch mode. @@ -379,10 +339,11 @@ private: } Strings keys; - config().keys("prompt_by_server_display_name", keys); prompt_by_server_display_name = config().getString("prompt_by_server_display_name.default", "{display_name} :) "); + config().keys("prompt_by_server_display_name", keys); + for (const String & key : keys) { if (server_display_name.find(key) != std::string::npos) @@ -392,6 +353,30 @@ private: } } + std::map terminalCharacters = { + { "\\e[", "\e[" }, + { "\\33[", "\33[" }, + { "\\033[", "\033["}, + { "\\x1B[", "\x1B["}, + }; + + for (const auto & [key, value]: terminalCharacters) + { + boost::replace_all(prompt_by_server_display_name, key, value); + } + + std::map environment = { + {"host", config().getString("host", "localhost")}, + {"port", config().getString("port", "9000")}, + {"user", config().getString("user", "default")}, + {"display_name", server_display_name}, + }; + + for (const auto & [key, value]: environment) + { + boost::replace_all(prompt_by_server_display_name, "{" + key + "}", value); + } + if (is_interactive) { if (print_time_to_stderr) @@ -483,9 +468,8 @@ private: connection->getServerVersion(server_name, server_version_major, server_version_minor, server_revision); server_version = toString(server_version_major) + "." + toString(server_version_minor) + "." + toString(server_revision); - server_display_name = connection->getServerDisplayName(); - - if (server_display_name.length() == 0) + + if (server_display_name = connection->getServerDisplayName(); server_display_name.length() == 0) { server_display_name = config().getString("host", "localhost"); } @@ -513,26 +497,7 @@ private: const String prompt() const { String pattern = prompt_by_server_display_name; - - for (const auto & [name, code]: colors) - { - boost::replace_all(pattern, "[" + name + "]", "\33[1;" + code + "m"); - boost::replace_all(pattern, "[/" + name + "]", "\033[0m"); - } - - std::map environment = { - {"host", config().getString("host", "localhost")}, - {"port", config().getString("port", "9000")}, - {"display_name", server_display_name}, - {"user", config().getString("user", "default")}, - {"database", config().getString("database", "default")}, - }; - - for (const auto & [key, value]: environment) - { - boost::replace_all(pattern, "{" + key + "}", value); - } - + boost::replace_all(pattern, "{database}", config().getString("database", "default")); return pattern; } diff --git a/dbms/src/Server/clickhouse-client.xml b/dbms/src/Server/clickhouse-client.xml index ecd19d6c623..3cd05d7fec9 100644 --- a/dbms/src/Server/clickhouse-client.xml +++ b/dbms/src/Server/clickhouse-client.xml @@ -21,10 +21,11 @@ {user} {database} {display_name} + Terminal colors: https://misc.flogisoft.com/bash/tip_colors_and_formatting --> {display_name} :) - {display_name} [green]:)[/green - {display_name} [red]:)[/red] + {display_name} \e[1;32m:)\e[0m + {display_name} \e[1;31m:)\e[0m diff --git a/dbms/tests/queries/0_stateless/00501_http_head.sh b/dbms/tests/queries/0_stateless/00501_http_head.sh index 7fb675e5b8a..578e27da751 100755 --- a/dbms/tests/queries/0_stateless/00501_http_head.sh +++ b/dbms/tests/queries/0_stateless/00501_http_head.sh @@ -7,7 +7,7 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) . $CURDIR/../shell_config.sh ( ${CLICKHOUSE_CURL} -s --head "${CLICKHOUSE_URL}?query=SELECT%201"; - ${CLICKHOUSE_CURL} -s --head "${CLICKHOUSE_URL}?query=select+*+from+system.numbers+limit+1000000" ) | grep -v "Date:" | grep -v "X-ClickHouse-Display-Name:" + ${CLICKHOUSE_CURL} -s --head "${CLICKHOUSE_URL}?query=select+*+from+system.numbers+limit+1000000" ) | grep -v "Date:" | grep -v "X-ClickHouse-Server-Display-Name:" if [[ `${CLICKHOUSE_CURL} -sS -X POST -I "${CLICKHOUSE_URL}?query=SELECT+1" | grep -c '411 Length Required'` -ne 1 ]]; then echo FAIL From 8cb5733b4460f3101e5d9fcf0a4f25c7a376a06a Mon Sep 17 00:00:00 2001 From: Michael Furmur Date: Thu, 8 Mar 2018 15:23:28 +0200 Subject: [PATCH 023/244] add aggregate functions IntersectionsMax and IntersectionsMaxPos --- .../AggregateFunctionIntersectionsMax.cpp | 145 ++++++++++++++++++ .../AggregateFunctionIntersectionsMax.h | 132 ++++++++++++++++ .../registerAggregateFunctions.cpp | 2 + 3 files changed, 279 insertions(+) create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp new file mode 100644 index 00000000000..854737ceba4 --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp @@ -0,0 +1,145 @@ +#include +#include +#include + +#include +#include + +namespace DB +{ + +template +typename Intersections::PointsMap::iterator +Intersections::insert_point(const T &v) +{ + auto res = points.emplace(v,0); + auto &i = res.first; + if(!res.second) return i; + if(i==points.begin()) return i; + auto prev = i; + prev--; + i->second=prev->second; + return i; +} + +template +void Intersections::add(const T &start, const T &end, T weight) +{ + auto sp = insert_point(start); + auto ep = end ? insert_point(end) : points.end(); + do { + sp->second+=weight; + if(sp->second > max_weight) { + max_weight = sp->second; + max_weight_pos = sp->first; + } + } while(++sp != ep); +} + +template +void Intersections::merge(const Intersections &other) +{ + if(other.points.empty()) + return; + + typename PointsMap::const_iterator prev, i = other.points.begin(); + prev = i; + i++; + + while(i != other.points.end()) { + add(prev->first,i->first,prev->second); + prev = i; + i++; + } + + if(prev != other.points.end()) + add(prev->first,0,prev->second); +} + +template +void Intersections::serialize(WriteBuffer & buf) const +{ + writeBinary(points.size(),buf); + for(const auto &p: points) { + writeBinary(p.first,buf); + writeBinary(p.second,buf); + } +} + +template +void Intersections::deserialize(ReadBuffer & buf) +{ + std::size_t size; + T point; + T weight; + + readBinary(size, buf); + for (std::size_t i = 0; i < size; ++i) { + readBinary(point, buf); + readBinary(weight,buf); + points.emplace(point,weight); + } +} + +void AggregateFunctionIntersectionsMax::_add( + AggregateDataPtr place, + const IColumn & column_start, + const IColumn & column_end, + size_t row_num) const +{ + PointType start_time, end_time; + Field tmp_start_time_field, tmp_end_time_field; + + column_start.get(row_num,tmp_start_time_field); + if(tmp_start_time_field.isNull()) + return; + start_time = tmp_start_time_field.template get(); + if(0==start_time) + return; + + column_end.get(row_num,tmp_end_time_field); + if(tmp_end_time_field.isNull()) { + end_time = 0; + } else { + end_time = tmp_end_time_field.template get(); + if(0!=end_time) { + if(end_time==start_time) { + end_time = 0; + } else if(end_time < start_time) { + return; + } + } + } + + data(place).add(start_time,end_time); +} + +namespace +{ + +AggregateFunctionPtr createAggregateFunctionIntersectionsMax(const std::string & name, const DataTypes & argument_types, const Array & parameters) +{ + assertBinary(name, argument_types); + return std::make_shared(argument_types,parameters,false); +} + +AggregateFunctionPtr createAggregateFunctionIntersectionsMaxPos(const std::string & name, const DataTypes & argument_types, const Array & parameters) +{ + assertBinary(name, argument_types); + return std::make_shared(argument_types,parameters,true); +} + +} + +void registerAggregateFunctionIntersectionsMax(AggregateFunctionFactory & factory) +{ + factory.registerFunction("IntersectionsMax", + createAggregateFunctionIntersectionsMax, + AggregateFunctionFactory::CaseInsensitive); + factory.registerFunction("IntersectionsMaxPos", + createAggregateFunctionIntersectionsMaxPos, + AggregateFunctionFactory::CaseInsensitive); +} + +} + diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h new file mode 100644 index 00000000000..ca97986e678 --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h @@ -0,0 +1,132 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; +} + +template +class Intersections final +{ + + using PointsMap = std::map; + + PointsMap points; + T max_weight; + T max_weight_pos; + + typename PointsMap::iterator insert_point(const T &v); + public: + + Intersections() + : max_weight(0) + { } + + void add(const T &start, const T &end, T weight = 1); + void merge(const Intersections &other); + + void serialize(WriteBuffer & buf) const; + void deserialize(ReadBuffer & buf); + + T max() const { return max_weight; } + T max_pos() const { return max_weight_pos; } +}; + +class AggregateFunctionIntersectionsMax final + : public IAggregateFunctionDataHelper, AggregateFunctionIntersectionsMax> +{ + using PointType = UInt64; + + bool return_position; + void _add(AggregateDataPtr place, const IColumn & column_start, const IColumn & column_end, size_t row_num) const; + + public: + AggregateFunctionIntersectionsMax(const DataTypes & arguments, const Array & params, bool return_position) + : return_position(return_position) + { + if (!params.empty()) { + throw Exception( + "Aggregate function " + getName() + " does not allow paremeters.", + ErrorCodes::AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS); + } + + if (arguments.size() != 2) + throw Exception("Aggregate function " + getName() + " requires two arguments.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + if(!arguments[0]->isValueRepresentedByInteger()) + throw Exception { + getName() + ": first argument must be represented by integer", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT + }; + + if(!arguments[1]->isValueRepresentedByInteger()) + throw Exception { + getName() + ": second argument must be represented by integer", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT + }; + + if(!arguments[0]->equals(*arguments[1])) + throw Exception { + getName() + ": arguments must have the same type", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT + }; + } + + String getName() const override { return "IntersectionsMax"; } + + DataTypePtr getReturnType() const override + { + return std::make_shared(); + } + + void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena *) const override + { + _add(place,*columns[0],*columns[1],row_num); + } + + void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override + { + this->data(place).merge(data(rhs)); + } + + void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override + { + this->data(place).serialize(buf); + } + + void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override + { + this->data(place).deserialize(buf); + } + + void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override + { + auto &ret = static_cast(to).getData(); + ret.push_back(data(place).max()); + if(return_position) + ret.push_back(data(place).max_pos()); + } + + const char * getHeaderFilePath() const override { return __FILE__; } +}; + +} + diff --git a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp index 59bda8bb8b5..d054107c705 100644 --- a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp +++ b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp @@ -23,6 +23,7 @@ void registerAggregateFunctionsUniq(AggregateFunctionFactory &); void registerAggregateFunctionUniqUpTo(AggregateFunctionFactory &); void registerAggregateFunctionTopK(AggregateFunctionFactory &); void registerAggregateFunctionsBitwise(AggregateFunctionFactory &); +void registerAggregateFunctionIntersectionsMax(AggregateFunctionFactory &); void registerAggregateFunctionCombinatorIf(AggregateFunctionCombinatorFactory &); void registerAggregateFunctionCombinatorArray(AggregateFunctionCombinatorFactory &); @@ -53,6 +54,7 @@ void registerAggregateFunctions() registerAggregateFunctionUniqUpTo(factory); registerAggregateFunctionTopK(factory); registerAggregateFunctionsBitwise(factory); + registerAggregateFunctionIntersectionsMax(factory); } { From ab9553711a1839a2466be099620894e2fdcbcbb4 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Thu, 8 Mar 2018 20:35:42 +0300 Subject: [PATCH 024/244] Contents bag is fixed. --- docs/mkdocs_en.yml | 2 +- docs/mkdocs_ru.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 5d0723f0042..551ce240f3b 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -218,7 +218,7 @@ pages: - 'Internal dictionaries': 'dicts/internal_dicts.md' - 'Operation': - - 'Operation': 'operations/index.md' +# - 'Operation': 'operations/index.md' - 'Access rights': 'operations/access_rights.md' - 'Configuration files': 'operations/configuration_files.md' - 'Quotas': 'operations/quotas.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index df06d235c99..bc8b74a3d17 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -219,7 +219,7 @@ pages: - 'Встроенные словари': 'dicts/internal_dicts.md' - 'Эксплуатация': - - 'Эксплуатация': 'operations/index.md' +# - 'Эксплуатация': 'operations/index.md' - 'Права доступа': 'operations/access_rights.md' - 'Конфигурационные файлы': 'operations/configuration_files.md' - 'Квоты': 'operations/quotas.md' From 808bfef3453fe016a4f560867e4b4d31b38409ae Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 12 Mar 2018 15:23:15 +0200 Subject: [PATCH 025/244] inline prompt function --- dbms/src/Server/Client.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 959dfe9a199..53752f1d173 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -346,7 +346,7 @@ private: for (const String & key : keys) { - if (server_display_name.find(key) != std::string::npos) + if (key != "default" && server_display_name.find(key) != std::string::npos) { prompt_by_server_display_name = config().getString("prompt_by_server_display_name." + key); break; @@ -494,11 +494,9 @@ private: return select(1, &fds, 0, 0, &timeout) == 1; } - const String prompt() const + inline const String prompt() const { - String pattern = prompt_by_server_display_name; - boost::replace_all(pattern, "{database}", config().getString("database", "default")); - return pattern; + return boost::replace_all_copy(prompt_by_server_display_name, "{database}", config().getString("database", "default")); } void loop() From 2b3e897aa1b75b292c9f325322002038af4e34a5 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 12 Mar 2018 17:14:56 +0300 Subject: [PATCH 026/244] added SHOW CREATE DATABASE query [#CLICKHOUSE-3590] --- dbms/src/Databases/DatabaseOrdinary.cpp | 17 ++++++-- dbms/src/Databases/IDatabase.h | 3 +- dbms/src/Interpreters/InterpreterFactory.cpp | 6 ++- .../InterpreterShowCreateQuery.cpp | 2 +- .../Parsers/ParserTablePropertiesQuery.cpp | 39 +++++++++++++------ dbms/src/Parsers/TablePropertiesQueriesASTs.h | 22 +++++++++-- 6 files changed, 69 insertions(+), 20 deletions(-) diff --git a/dbms/src/Databases/DatabaseOrdinary.cpp b/dbms/src/Databases/DatabaseOrdinary.cpp index 0021f47c4c7..b0719649094 100644 --- a/dbms/src/Databases/DatabaseOrdinary.cpp +++ b/dbms/src/Databases/DatabaseOrdinary.cpp @@ -45,6 +45,12 @@ namespace detail { return base_path + (endsWith(base_path, "/") ? "" : "/") + escapeForFileName(table_name) + ".sql"; } + + String getDatabaseMetadataPath(const String & base_path) + { + return (endsWith(base_path, "/") ? base_path.substr(0, base_path.size() - 1) : base_path) + ".sql"; + } + } static void loadTable( @@ -332,16 +338,21 @@ void DatabaseOrdinary::removeTable( static ASTPtr getCreateQueryImpl(const String & path, const String & table_name) { - String table_metadata_path = detail::getTableMetadataPath(path, table_name); + String metadata_path; + + if (table_name.empty()) + metadata_path = detail::getDatabaseMetadataPath(path); + else + metadata_path = detail::getTableMetadataPath(path, table_name); String query; { - ReadBufferFromFile in(table_metadata_path, 4096); + ReadBufferFromFile in(metadata_path, 4096); readStringUntilEOF(query, in); } ParserCreateQuery parser; - return parseQuery(parser, query.data(), query.data() + query.size(), "in file " + table_metadata_path); + return parseQuery(parser, query.data(), query.data() + query.size(), "in file " + metadata_path); } diff --git a/dbms/src/Databases/IDatabase.h b/dbms/src/Databases/IDatabase.h index 74cbe0b2202..8d62c0e3d45 100644 --- a/dbms/src/Databases/IDatabase.h +++ b/dbms/src/Databases/IDatabase.h @@ -124,7 +124,8 @@ public: const Context & context, const String & name) = 0; - /// Get the CREATE TABLE query for the table. It can also provide information for detached tables for which there is metadata. + /// Get the CREATE TABLE query for the table or CREATE DATABASE query for database if name is empty. + /// It can also provide information for detached tables for which there is metadata. virtual ASTPtr getCreateQuery( const Context & context, const String & name) const = 0; diff --git a/dbms/src/Interpreters/InterpreterFactory.cpp b/dbms/src/Interpreters/InterpreterFactory.cpp index 9d30c586129..2e43efbb12e 100644 --- a/dbms/src/Interpreters/InterpreterFactory.cpp +++ b/dbms/src/Interpreters/InterpreterFactory.cpp @@ -107,7 +107,11 @@ std::unique_ptr InterpreterFactory::get(ASTPtr & query, Context & { return std::make_unique(query, context); } - else if (typeid_cast(query.get())) + else if (typeid_cast(query.get())) + { + return std::make_unique(query, context); + } + else if (typeid_cast(query.get())) { return std::make_unique(query, context); } diff --git a/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp b/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp index d4bd116bcf7..705b9bb4120 100644 --- a/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp @@ -39,7 +39,7 @@ Block InterpreterShowCreateQuery::getSampleBlock() BlockInputStreamPtr InterpreterShowCreateQuery::executeImpl() { - const ASTShowCreateQuery & ast = typeid_cast(*query_ptr); + const auto & ast = dynamic_cast(*query_ptr); if (ast.temporary && !ast.database.empty()) throw Exception("Temporary databases are not possible.", ErrorCodes::SYNTAX_ERROR); diff --git a/dbms/src/Parsers/ParserTablePropertiesQuery.cpp b/dbms/src/Parsers/ParserTablePropertiesQuery.cpp index 570597b0fa6..45e92f9e181 100644 --- a/dbms/src/Parsers/ParserTablePropertiesQuery.cpp +++ b/dbms/src/Parsers/ParserTablePropertiesQuery.cpp @@ -19,6 +19,7 @@ bool ParserTablePropertiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & ParserKeyword s_desc("DESC"); ParserKeyword s_show("SHOW"); ParserKeyword s_create("CREATE"); + ParserKeyword s_database("DATABASE"); ParserKeyword s_table("TABLE"); ParserToken s_dot(TokenType::Dot); ParserIdentifier name_p; @@ -27,6 +28,8 @@ bool ParserTablePropertiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & ASTPtr table; std::shared_ptr query; + bool parse_only_database_name = false; + if (s_exists.ignore(pos, expected)) { query = std::make_shared(); @@ -36,26 +39,40 @@ bool ParserTablePropertiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & if (!s_create.ignore(pos, expected)) return false; - query = std::make_shared(); + if (s_database.ignore(pos, expected)) + { + parse_only_database_name = true; + query = std::make_shared(); + } + else + query = std::make_shared(); } else { return false; } - if (s_temporary.ignore(pos, expected)) - query->temporary = true; - - s_table.ignore(pos, expected); - - if (!name_p.parse(pos, table, expected)) - return false; - - if (s_dot.ignore(pos, expected)) + if (parse_only_database_name) { - database = table; + if (!name_p.parse(pos, database, expected)) + return false; + } + else + { + if (s_temporary.ignore(pos, expected)) + query->temporary = true; + + s_table.ignore(pos, expected); + if (!name_p.parse(pos, table, expected)) return false; + + if (s_dot.ignore(pos, expected)) + { + database = table; + if (!name_p.parse(pos, table, expected)) + return false; + } } if (database) diff --git a/dbms/src/Parsers/TablePropertiesQueriesASTs.h b/dbms/src/Parsers/TablePropertiesQueriesASTs.h index 312b112f494..15a1d397fa4 100644 --- a/dbms/src/Parsers/TablePropertiesQueriesASTs.h +++ b/dbms/src/Parsers/TablePropertiesQueriesASTs.h @@ -12,12 +12,18 @@ struct ASTExistsQueryIDAndQueryNames static constexpr auto Query = "EXISTS TABLE"; }; -struct ASTShowCreateQueryIDAndQueryNames +struct ASTShowCreateTableQueryIDAndQueryNames { - static constexpr auto ID = "ShowCreateQuery"; + static constexpr auto ID = "ShowCreateTableQuery"; static constexpr auto Query = "SHOW CREATE TABLE"; }; +struct ASTShowCreateDatabaseQueryIDAndQueryNames +{ + static constexpr auto ID = "ShowCreateDatabaseQuery"; + static constexpr auto Query = "SHOW CREATE DATABASE"; +}; + struct ASTDescribeQueryExistsQueryIDAndQueryNames { static constexpr auto ID = "DescribeQuery"; @@ -25,7 +31,17 @@ struct ASTDescribeQueryExistsQueryIDAndQueryNames }; using ASTExistsQuery = ASTQueryWithTableAndOutputImpl; -using ASTShowCreateQuery = ASTQueryWithTableAndOutputImpl; +using ASTShowCreateTableQuery = ASTQueryWithTableAndOutputImpl; + +class ASTShowCreateDatabaseQuery : public ASTQueryWithTableAndOutputImpl +{ +protected: + void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override + { + settings.ostr << (settings.hilite ? hilite_keyword : "") << ASTShowCreateDatabaseQueryIDAndQueryNames::Query + << " " << (settings.hilite ? hilite_none : "") << backQuoteIfNeed(database); + } +}; class ASTDescribeQuery : public ASTQueryWithOutput { From 5a07569c2a57f95197dd8af42232bf08553cdae6 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 12 Mar 2018 18:21:17 +0300 Subject: [PATCH 027/244] added test [#CLICKHOUSE-3590] --- .../queries/0_stateless/00604_show_create_database.reference | 1 + dbms/tests/queries/0_stateless/00604_show_create_database.sql | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00604_show_create_database.reference create mode 100644 dbms/tests/queries/0_stateless/00604_show_create_database.sql diff --git a/dbms/tests/queries/0_stateless/00604_show_create_database.reference b/dbms/tests/queries/0_stateless/00604_show_create_database.reference new file mode 100644 index 00000000000..ab242ee47fd --- /dev/null +++ b/dbms/tests/queries/0_stateless/00604_show_create_database.reference @@ -0,0 +1 @@ +CREATE DATABASE test ENGINE = Ordinary diff --git a/dbms/tests/queries/0_stateless/00604_show_create_database.sql b/dbms/tests/queries/0_stateless/00604_show_create_database.sql new file mode 100644 index 00000000000..b5671b3a984 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00604_show_create_database.sql @@ -0,0 +1,2 @@ +create database if not exists test; +show create database test; From 4dd7f47ad52151494551498aadc9c13fd6dbf45b Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 12 Mar 2018 21:16:51 +0300 Subject: [PATCH 028/244] reload macros with config [#CLICKHOUSE-3591] --- dbms/src/Common/Macros.h | 2 ++ dbms/src/Interpreters/Context.cpp | 10 ++++++---- dbms/src/Interpreters/Context.h | 3 ++- dbms/src/Interpreters/DDLWorker.cpp | 2 +- dbms/src/Server/Server.cpp | 1 + dbms/src/Storages/StorageDistributed.cpp | 2 +- dbms/src/Storages/StorageReplicatedMergeTree.cpp | 4 ++-- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/dbms/src/Common/Macros.h b/dbms/src/Common/Macros.h index 0ebf52afd02..5b5435ca9e6 100644 --- a/dbms/src/Common/Macros.h +++ b/dbms/src/Common/Macros.h @@ -27,4 +27,6 @@ private: MacroMap macros; }; +using MacrosPtr = std::shared_ptr; + } diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 6fddcbc2f05..7a2358f36c0 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -130,7 +130,8 @@ struct ContextShared ConfigurationPtr users_config; /// Config with the users, profiles and quotas sections. InterserverIOHandler interserver_io_handler; /// Handler for interserver communication. BackgroundProcessingPoolPtr background_pool; /// The thread pool for the background work performed by the tables. - Macros macros; /// Substitutions extracted from config. + mutable std::mutex macros_mutex; + MacrosPtr macros; /// Substitutions extracted from config. std::unique_ptr compiler; /// Used for dynamic compilation of queries' parts if it necessary. std::shared_ptr ddl_worker; /// Process ddl commands from zk. /// Rules for selecting the compression settings, depending on the size of the part. @@ -1042,15 +1043,16 @@ void Context::setDefaultFormat(const String & name) default_format = name; } -const Macros & Context::getMacros() const +const MacrosPtr & Context::getMacros() const { + std::unique_lock lock(shared->macros_mutex); return shared->macros; } void Context::setMacros(Macros && macros) { - /// We assume that this assignment occurs once when the server starts. If this is not the case, you need to use a mutex. - shared->macros = macros; + std::unique_lock lock(shared->macros_mutex); + shared->macros = std::make_shared(std::move(macros)); } const Context & Context::getQueryContext() const diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index bab3be07add..4148b79923b 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -80,6 +80,7 @@ using Dependencies = std::vector; using TableAndCreateAST = std::pair; using TableAndCreateASTs = std::map; +using MacrosPtr = std::shared_ptr; /** A set of known objects that can be used in the query. * Consists of a shared part (always common to all sessions and queries) @@ -206,7 +207,7 @@ public: String getDefaultFormat() const; /// If default_format is not specified, some global default format is returned. void setDefaultFormat(const String & name); - const Macros & getMacros() const; + const MacrosPtr & getMacros() const; void setMacros(Macros && macros); Settings getSettings() const; diff --git a/dbms/src/Interpreters/DDLWorker.cpp b/dbms/src/Interpreters/DDLWorker.cpp index 1c60b6d766c..c0262358fe1 100644 --- a/dbms/src/Interpreters/DDLWorker.cpp +++ b/dbms/src/Interpreters/DDLWorker.cpp @@ -1131,7 +1131,7 @@ BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & cont } } - query->cluster = context.getMacros().expand(query->cluster); + query->cluster = context.getMacros()->expand(query->cluster); ClusterPtr cluster = context.getCluster(query->cluster); DDLWorker & ddl_worker = context.getDDLWorker(); diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index db20c194573..08153b00b1d 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -231,6 +231,7 @@ int Server::main(const std::vector & /*args*/) [&](ConfigurationPtr config) { global_context->setClustersConfig(config); + global_context->setMacros(Macros(*config, "macros")); }, /* already_loaded = */ true); diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index c1681e6fbea..f25b0ef6deb 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -144,7 +144,7 @@ StorageDistributed::StorageDistributed( : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, name(name_), remote_database(remote_database_), remote_table(remote_table_), - context(context_), cluster_name(context.getMacros().expand(cluster_name_)), has_sharding_key(sharding_key_), + context(context_), cluster_name(context.getMacros()->expand(cluster_name_)), has_sharding_key(sharding_key_), sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(name) + '/')) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index 9917b7e7a94..56b9b6443cd 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -190,8 +190,8 @@ StorageReplicatedMergeTree::StorageReplicatedMergeTree( : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, context(context_), current_zookeeper(context.getZooKeeper()), database_name(database_name_), table_name(name_), full_path(path_ + escapeForFileName(table_name) + '/'), - zookeeper_path(context.getMacros().expand(zookeeper_path_)), - replica_name(context.getMacros().expand(replica_name_)), + zookeeper_path(context.getMacros()->expand(zookeeper_path_)), + replica_name(context.getMacros()->expand(replica_name_)), data(database_name, table_name, full_path, columns_, materialized_columns_, alias_columns_, column_defaults_, From 8b09e5510267ef5a08a825abcb382dcfc2e2ce3f Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 12 Mar 2018 21:38:00 +0300 Subject: [PATCH 029/244] added system.macros table [#CLICKHOUSE-3591] --- dbms/src/Common/Macros.h | 3 +- .../Storages/System/StorageSystemMacros.cpp | 48 +++++++++++++++++++ .../src/Storages/System/StorageSystemMacros.h | 36 ++++++++++++++ .../Storages/System/attachSystemTables.cpp | 2 + 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 dbms/src/Storages/System/StorageSystemMacros.cpp create mode 100644 dbms/src/Storages/System/StorageSystemMacros.h diff --git a/dbms/src/Common/Macros.h b/dbms/src/Common/Macros.h index 5b5435ca9e6..316d526b5a7 100644 --- a/dbms/src/Common/Macros.h +++ b/dbms/src/Common/Macros.h @@ -21,9 +21,10 @@ public: */ String expand(const String & s, size_t level = 0) const; -private: using MacroMap = std::map; + const MacroMap getMacroMap() const { return macros; } +private: MacroMap macros; }; diff --git a/dbms/src/Storages/System/StorageSystemMacros.cpp b/dbms/src/Storages/System/StorageSystemMacros.cpp new file mode 100644 index 00000000000..37c3197fd60 --- /dev/null +++ b/dbms/src/Storages/System/StorageSystemMacros.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + + +namespace DB +{ + + +StorageSystemMacros::StorageSystemMacros(const std::string & name_) + : name(name_) +{ + columns = NamesAndTypesList{ + {"macro", std::make_shared()}, + {"substitution", std::make_shared()}, + }; +} + + +BlockInputStreams StorageSystemMacros::read( + const Names & column_names, + const SelectQueryInfo &, + const Context & context, + QueryProcessingStage::Enum & processed_stage, + const size_t /*max_block_size*/, + const unsigned /*num_streams*/) +{ + check(column_names); + processed_stage = QueryProcessingStage::FetchColumns; + + MutableColumns res_columns = getSampleBlock().cloneEmptyColumns(); + + auto macros = context.getMacros(); + + for (const auto & macro : macros->getMacroMap()) + { + res_columns[0]->insert(macro.first); + res_columns[1]->insert(macro.second); + } + + return BlockInputStreams(1, std::make_shared(getSampleBlock().cloneWithColumns(std::move(res_columns)))); +} + + +} diff --git a/dbms/src/Storages/System/StorageSystemMacros.h b/dbms/src/Storages/System/StorageSystemMacros.h new file mode 100644 index 00000000000..ec8af55a0d3 --- /dev/null +++ b/dbms/src/Storages/System/StorageSystemMacros.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + + +namespace DB +{ + +class Context; + + +/** Implements `databases` system table, which allows you to get information about all databases. + */ +class StorageSystemMacros : public ext::shared_ptr_helper, public IStorage +{ +public: + std::string getName() const override { return "SystemMacros"; } + std::string getTableName() const override { return name; } + + BlockInputStreams read( + const Names & column_names, + const SelectQueryInfo & query_info, + const Context & context, + QueryProcessingStage::Enum & processed_stage, + size_t max_block_size, + unsigned num_streams) override; + +private: + const std::string name; + +protected: + StorageSystemMacros(const std::string & name_); +}; + +} diff --git a/dbms/src/Storages/System/attachSystemTables.cpp b/dbms/src/Storages/System/attachSystemTables.cpp index cc49f047d9d..93d4809b3c7 100644 --- a/dbms/src/Storages/System/attachSystemTables.cpp +++ b/dbms/src/Storages/System/attachSystemTables.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,7 @@ void attachSystemTablesServer(IDatabase & system_database, bool has_zookeeper) system_database.attachTable("models", StorageSystemModels::create("models")); system_database.attachTable("clusters", StorageSystemClusters::create("clusters")); system_database.attachTable("graphite_retentions", StorageSystemGraphite::create("graphite_retentions")); + system_database.attachTable("macros", StorageSystemMacros::create("macros")); if (has_zookeeper) system_database.attachTable("zookeeper", StorageSystemZooKeeper::create("zookeeper")); From 71642b08809d8e6e29fc1e46d22a7e5829886116 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Tue, 6 Mar 2018 23:18:34 +0300 Subject: [PATCH 030/244] use ColumnsDescription everywhere [#CLICKHOUSE-3241] --- dbms/src/Analyzers/AnalyzeColumns.cpp | 4 +- dbms/src/Analyzers/ExecuteTableFunctions.cpp | 2 +- dbms/src/Common/ExternalTable.h | 4 +- dbms/src/Core/iostream_debug_helpers.cpp | 2 +- .../DataStreams/RemoteBlockInputStream.cpp | 2 +- dbms/src/Databases/DatabaseDictionary.cpp | 9 +- dbms/src/Databases/DatabaseDictionary.h | 5 +- dbms/src/Databases/DatabaseMemory.cpp | 5 +- dbms/src/Databases/DatabaseMemory.h | 5 +- dbms/src/Databases/DatabaseOrdinary.cpp | 7 +- dbms/src/Databases/DatabaseOrdinary.h | 5 +- dbms/src/Databases/DatabasesCommon.cpp | 4 +- dbms/src/Databases/IDatabase.h | 7 +- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 12 +- .../Interpreters/InterpreterAlterQuery.cpp | 2 +- .../Interpreters/InterpreterCreateQuery.cpp | 54 ++++---- .../src/Interpreters/InterpreterCreateQuery.h | 20 +-- .../Interpreters/InterpreterDescribeQuery.cpp | 6 +- .../Interpreters/InterpreterInsertQuery.cpp | 6 +- .../Interpreters/InterpreterSelectQuery.cpp | 10 +- dbms/src/Server/TCPHandler.cpp | 3 +- dbms/src/Storages/AlterCommands.cpp | 99 +++++++-------- dbms/src/Storages/AlterCommands.h | 12 +- dbms/src/Storages/ColumnsDescription.cpp | 63 +++++++--- dbms/src/Storages/ColumnsDescription.h | 45 +++++-- .../Storages/Distributed/DirectoryMonitor.cpp | 2 +- dbms/src/Storages/IStorage.h | 4 + dbms/src/Storages/ITableDeclaration.cpp | 115 ++++-------------- dbms/src/Storages/ITableDeclaration.h | 65 +--------- .../Storages/MergeTree/DataPartsExchange.cpp | 1 + .../MergeTree/MergeTreeBlockInputStream.cpp | 4 +- .../MergeTree/MergeTreeBlockReadUtils.cpp | 4 +- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 36 ++---- dbms/src/Storages/MergeTree/MergeTreeData.h | 21 ++-- .../MergeTree/MergeTreeDataMerger.cpp | 4 +- .../Storages/MergeTree/MergeTreeDataPart.cpp | 6 +- .../MergeTree/MergeTreeDataSelectExecutor.cpp | 4 +- .../MergeTree/MergeTreeDataSelectExecutor.h | 2 + .../MergeTree/MergeTreeDataWriter.cpp | 2 +- .../Storages/MergeTree/MergeTreeReadPool.cpp | 4 +- .../Storages/MergeTree/MergeTreeReader.cpp | 4 +- .../MergeTree/MergeTreeWhereOptimizer.cpp | 4 +- .../ReplicatedMergeTreeAlterThread.cpp | 44 +------ .../MergeTree/registerStorageMergeTree.cpp | 5 +- dbms/src/Storages/StorageBuffer.cpp | 15 +-- dbms/src/Storages/StorageBuffer.h | 5 +- dbms/src/Storages/StorageCatBoostPool.cpp | 11 +- dbms/src/Storages/StorageDictionary.cpp | 12 +- dbms/src/Storages/StorageDictionary.h | 6 +- dbms/src/Storages/StorageDistributed.cpp | 30 ++--- dbms/src/Storages/StorageDistributed.h | 16 +-- dbms/src/Storages/StorageFactory.cpp | 14 +-- dbms/src/Storages/StorageFactory.h | 12 +- dbms/src/Storages/StorageFile.cpp | 8 +- dbms/src/Storages/StorageFile.h | 12 +- dbms/src/Storages/StorageJoin.cpp | 22 +--- dbms/src/Storages/StorageJoin.h | 5 +- dbms/src/Storages/StorageKafka.cpp | 8 +- dbms/src/Storages/StorageKafka.h | 5 +- dbms/src/Storages/StorageLog.cpp | 18 ++- dbms/src/Storages/StorageLog.h | 5 +- dbms/src/Storages/StorageMaterializedView.cpp | 10 +- dbms/src/Storages/StorageMaterializedView.h | 6 +- dbms/src/Storages/StorageMemory.cpp | 12 +- dbms/src/Storages/StorageMemory.h | 13 +- dbms/src/Storages/StorageMerge.cpp | 16 +-- dbms/src/Storages/StorageMerge.h | 6 +- dbms/src/Storages/StorageMergeTree.cpp | 48 ++------ dbms/src/Storages/StorageMergeTree.h | 8 +- dbms/src/Storages/StorageMySQL.cpp | 6 +- dbms/src/Storages/StorageMySQL.h | 2 +- dbms/src/Storages/StorageNull.cpp | 9 +- dbms/src/Storages/StorageNull.h | 17 ++- dbms/src/Storages/StorageODBC.cpp | 6 +- dbms/src/Storages/StorageODBC.h | 2 +- .../Storages/StorageReplicatedMergeTree.cpp | 70 +++-------- .../src/Storages/StorageReplicatedMergeTree.h | 7 +- dbms/src/Storages/StorageSet.cpp | 25 ++-- dbms/src/Storages/StorageSet.h | 16 +-- dbms/src/Storages/StorageStripeLog.cpp | 8 +- dbms/src/Storages/StorageStripeLog.h | 5 +- dbms/src/Storages/StorageTinyLog.cpp | 12 +- dbms/src/Storages/StorageTinyLog.h | 5 +- dbms/src/Storages/StorageView.cpp | 4 +- dbms/src/Storages/StorageView.h | 2 +- .../StorageSystemAsynchronousMetrics.cpp | 2 +- .../System/StorageSystemBuildOptions.cpp | 2 +- .../Storages/System/StorageSystemClusters.cpp | 2 +- .../Storages/System/StorageSystemColumns.cpp | 8 +- .../System/StorageSystemDatabases.cpp | 2 +- .../System/StorageSystemDictionaries.cpp | 2 +- .../Storages/System/StorageSystemEvents.cpp | 2 +- .../System/StorageSystemFunctions.cpp | 2 +- .../Storages/System/StorageSystemGraphite.cpp | 2 +- .../Storages/System/StorageSystemMerges.cpp | 2 +- .../Storages/System/StorageSystemMetrics.cpp | 2 +- .../Storages/System/StorageSystemModels.cpp | 2 +- .../Storages/System/StorageSystemNumbers.cpp | 2 +- dbms/src/Storages/System/StorageSystemOne.cpp | 2 +- .../System/StorageSystemPartsBase.cpp | 10 +- .../System/StorageSystemPartsColumns.cpp | 6 +- .../System/StorageSystemProcesses.cpp | 2 +- .../Storages/System/StorageSystemReplicas.cpp | 2 +- .../System/StorageSystemReplicationQueue.cpp | 2 +- .../Storages/System/StorageSystemSettings.cpp | 2 +- .../Storages/System/StorageSystemTables.cpp | 2 +- .../System/StorageSystemZooKeeper.cpp | 2 +- dbms/src/Storages/tests/storage_log.cpp | 4 +- .../src/TableFunctions/TableFunctionMerge.cpp | 12 +- .../src/TableFunctions/TableFunctionMySQL.cpp | 2 +- dbms/src/TableFunctions/TableFunctionODBC.cpp | 3 +- .../getStructureOfRemoteTable.cpp | 2 +- 112 files changed, 478 insertions(+), 850 deletions(-) diff --git a/dbms/src/Analyzers/AnalyzeColumns.cpp b/dbms/src/Analyzers/AnalyzeColumns.cpp index 6367699ea8e..78568b080c6 100644 --- a/dbms/src/Analyzers/AnalyzeColumns.cpp +++ b/dbms/src/Analyzers/AnalyzeColumns.cpp @@ -173,7 +173,7 @@ ASTPtr createASTIdentifierForColumnInTable(const String & column, const CollectT void createASTsForAllColumnsInTable(const CollectTables::TableInfo & table, ASTs & res) { if (table.storage) - for (const auto & name : table.storage->getColumnNamesList()) + for (const auto & name : table.storage->columns.getNames()) res.emplace_back(createASTIdentifierForColumnInTable(name, table)); else for (size_t i = 0, size = table.structure_of_subquery.columns(); i < size; ++i) @@ -315,7 +315,7 @@ void processIdentifier( } else if (table->storage) { - info.data_type = table->storage->getDataTypeByName(column_name); + info.data_type = table->storage->getColumn(column_name).type; } else throw Exception("Logical error: no storage and no structure of subquery is specified for table", ErrorCodes::LOGICAL_ERROR); diff --git a/dbms/src/Analyzers/ExecuteTableFunctions.cpp b/dbms/src/Analyzers/ExecuteTableFunctions.cpp index fab9c6c3a3f..326c5df62ed 100644 --- a/dbms/src/Analyzers/ExecuteTableFunctions.cpp +++ b/dbms/src/Analyzers/ExecuteTableFunctions.cpp @@ -72,7 +72,7 @@ void ExecuteTableFunctions::dump(WriteBuffer & out) const { writeString(table.second->getName(), out); writeCString("\n\n", out); - writeString(table.second->getColumnsList().toString(), out); + writeString(table.second->columns.getList().toString(), out); writeCString("\n", out); } } diff --git a/dbms/src/Common/ExternalTable.h b/dbms/src/Common/ExternalTable.h index 624604d30a1..b5b0c522339 100644 --- a/dbms/src/Common/ExternalTable.h +++ b/dbms/src/Common/ExternalTable.h @@ -198,7 +198,9 @@ public: /// Create table NamesAndTypesList columns = sample_block.getNamesAndTypesList(); - StoragePtr storage = StorageMemory::create(data.second, columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}); + StoragePtr storage = StorageMemory::create( + data.second, + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); storage->startup(); context.addExternalTable(data.second, storage); BlockOutputStreamPtr output = storage->write(ASTPtr(), context.getSettingsRef()); diff --git a/dbms/src/Core/iostream_debug_helpers.cpp b/dbms/src/Core/iostream_debug_helpers.cpp index 3fbbb02a98f..822bbf58376 100644 --- a/dbms/src/Core/iostream_debug_helpers.cpp +++ b/dbms/src/Core/iostream_debug_helpers.cpp @@ -44,7 +44,7 @@ std::ostream & operator<<(std::ostream & stream, const IDataType & what) std::ostream & operator<<(std::ostream & stream, const IStorage & what) { stream << "IStorage(name = " << what.getName() << ", tableName = " << what.getTableName() << ") {" - << what.getColumnsList().toString() + << what.columns.getList().toString() << "}"; // isRemote supportsSampling supportsFinal supportsPrewhere return stream; diff --git a/dbms/src/DataStreams/RemoteBlockInputStream.cpp b/dbms/src/DataStreams/RemoteBlockInputStream.cpp index 7b63b36cadc..079cabe8dee 100644 --- a/dbms/src/DataStreams/RemoteBlockInputStream.cpp +++ b/dbms/src/DataStreams/RemoteBlockInputStream.cpp @@ -138,7 +138,7 @@ void RemoteBlockInputStream::sendExternalTables() { StoragePtr cur = table.second; QueryProcessingStage::Enum stage = QueryProcessingStage::Complete; - BlockInputStreams input = cur->read(cur->getColumnNamesList(), {}, context, + BlockInputStreams input = cur->read(cur->columns.getNames(), {}, context, stage, DEFAULT_BLOCK_SIZE, 1); if (input.size() == 0) res.push_back(std::make_pair(std::make_shared(cur->getSampleBlock()), table.first)); diff --git a/dbms/src/Databases/DatabaseDictionary.cpp b/dbms/src/Databases/DatabaseDictionary.cpp index 8a10535fd09..439fe8f4d79 100644 --- a/dbms/src/Databases/DatabaseDictionary.cpp +++ b/dbms/src/Databases/DatabaseDictionary.cpp @@ -42,7 +42,7 @@ Tables DatabaseDictionary::loadTables() const DictionaryStructure & dictionary_structure = dict_ptr->getStructure(); auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure); tables[name] = StorageDictionary::create(name, - columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, dictionary_structure, name); + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}, dictionary_structure, name); } } @@ -77,7 +77,7 @@ StoragePtr DatabaseDictionary::tryGetTable( const DictionaryStructure & dictionary_structure = dict_ptr->getStructure(); auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure); return StorageDictionary::create(table_name, - columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, dictionary_structure, table_name); + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}, dictionary_structure, table_name); } } } @@ -142,10 +142,7 @@ void DatabaseDictionary::renameTable( void DatabaseDictionary::alterTable( const Context &, const String &, - const NamesAndTypesList &, - const NamesAndTypesList &, - const NamesAndTypesList &, - const ColumnDefaults &, + const ColumnsDescription &, const ASTModifier &) { throw Exception("DatabaseDictionary: alterTable() is not supported", ErrorCodes::NOT_IMPLEMENTED); diff --git a/dbms/src/Databases/DatabaseDictionary.h b/dbms/src/Databases/DatabaseDictionary.h index 1308ea20a40..aba93faa5b1 100644 --- a/dbms/src/Databases/DatabaseDictionary.h +++ b/dbms/src/Databases/DatabaseDictionary.h @@ -79,10 +79,7 @@ public: void alterTable( const Context & context, const String & name, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, const ASTModifier & engine_modifier) override; time_t getTableMetadataModificationTime( diff --git a/dbms/src/Databases/DatabaseMemory.cpp b/dbms/src/Databases/DatabaseMemory.cpp index 66b23f07ca6..57089862863 100644 --- a/dbms/src/Databases/DatabaseMemory.cpp +++ b/dbms/src/Databases/DatabaseMemory.cpp @@ -105,10 +105,7 @@ void DatabaseMemory::renameTable( void DatabaseMemory::alterTable( const Context &, const String &, - const NamesAndTypesList &, - const NamesAndTypesList &, - const NamesAndTypesList &, - const ColumnDefaults &, + const ColumnsDescription &, const ASTModifier &) { throw Exception("DatabaseMemory: alterTable() is not supported", ErrorCodes::NOT_IMPLEMENTED); diff --git a/dbms/src/Databases/DatabaseMemory.h b/dbms/src/Databases/DatabaseMemory.h index be095ad3755..586dcfbe4da 100644 --- a/dbms/src/Databases/DatabaseMemory.h +++ b/dbms/src/Databases/DatabaseMemory.h @@ -70,10 +70,7 @@ public: void alterTable( const Context & context, const String & name, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, const ASTModifier & engine_modifier) override; time_t getTableMetadataModificationTime( diff --git a/dbms/src/Databases/DatabaseOrdinary.cpp b/dbms/src/Databases/DatabaseOrdinary.cpp index 0021f47c4c7..9dd705fbf9a 100644 --- a/dbms/src/Databases/DatabaseOrdinary.cpp +++ b/dbms/src/Databases/DatabaseOrdinary.cpp @@ -462,10 +462,7 @@ void DatabaseOrdinary::drop() void DatabaseOrdinary::alterTable( const Context & context, const String & name, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, const ASTModifier & storage_modifier) { /// Read the definition of the table and replace the necessary parts with new ones. @@ -486,7 +483,7 @@ void DatabaseOrdinary::alterTable( ASTCreateQuery & ast_create_query = typeid_cast(*ast); - ASTPtr new_columns = InterpreterCreateQuery::formatColumns(columns, materialized_columns, alias_columns, column_defaults); + ASTPtr new_columns = InterpreterCreateQuery::formatColumns(columns); ast_create_query.replace(ast_create_query.columns, new_columns); if (storage_modifier) diff --git a/dbms/src/Databases/DatabaseOrdinary.h b/dbms/src/Databases/DatabaseOrdinary.h index dbd44586c74..25e99114430 100644 --- a/dbms/src/Databases/DatabaseOrdinary.h +++ b/dbms/src/Databases/DatabaseOrdinary.h @@ -45,10 +45,7 @@ public: void alterTable( const Context & context, const String & name, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, const ASTModifier & engine_modifier) override; time_t getTableMetadataModificationTime( diff --git a/dbms/src/Databases/DatabasesCommon.cpp b/dbms/src/Databases/DatabasesCommon.cpp index 83a14145d58..66d05d11184 100644 --- a/dbms/src/Databases/DatabasesCommon.cpp +++ b/dbms/src/Databases/DatabasesCommon.cpp @@ -67,7 +67,7 @@ std::pair createTableFromDefinition( if (!ast_create_query.columns) throw Exception("Missing definition of columns.", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED); - InterpreterCreateQuery::ColumnsInfo columns_info = InterpreterCreateQuery::getColumnsInfo(*ast_create_query.columns, context); + ColumnsDescription columns = InterpreterCreateQuery::getColumnsDescription(*ast_create_query.columns, context); return { @@ -75,7 +75,7 @@ std::pair createTableFromDefinition( StorageFactory::instance().get( ast_create_query, database_data_path, ast_create_query.table, database_name, context, context.getGlobalContext(), - columns_info.columns, columns_info.materialized_columns, columns_info.alias_columns, columns_info.column_defaults, + columns, true, has_force_restore_data_flag) }; } diff --git a/dbms/src/Databases/IDatabase.h b/dbms/src/Databases/IDatabase.h index 74cbe0b2202..f7b8af632ca 100644 --- a/dbms/src/Databases/IDatabase.h +++ b/dbms/src/Databases/IDatabase.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -113,10 +113,7 @@ public: virtual void alterTable( const Context & context, const String & name, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, const ASTModifier & engine_modifier) = 0; /// Returns time of table's metadata change, 0 if there is no corresponding metadata file. diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index c3c663d59ad..fe85e154e92 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -190,7 +190,7 @@ ExpressionAnalyzer::ExpressionAnalyzer( } if (storage && source_columns.empty()) - source_columns = storage->getSampleBlock().getNamesAndTypesList(); + source_columns = storage->columns.getList(); else removeDuplicateColumns(source_columns); @@ -712,7 +712,7 @@ static std::shared_ptr interpretSubquery( /// get columns list for target table auto database_table = getDatabaseAndTableNameFromIdentifier(*table); const auto & storage = context.getTable(database_table.first, database_table.second); - const auto & columns = storage->getColumnsListNonMaterialized(); + const auto & columns = storage->columns.getListNonMaterialized(); select_expression_list->children.reserve(columns.size()); /// manually substitute column names in place of asterisk @@ -826,7 +826,9 @@ void ExpressionAnalyzer::addExternalStorage(ASTPtr & subquery_or_table_name_or_t Block sample = interpreter->getSampleBlock(); NamesAndTypesList columns = sample.getNamesAndTypesList(); - StoragePtr external_storage = StorageMemory::create(external_table_name, columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}); + StoragePtr external_storage = StorageMemory::create( + external_table_name, + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); external_storage->startup(); /** We replace the subquery with the name of the temporary table. @@ -1050,7 +1052,7 @@ void ExpressionAnalyzer::normalizeTreeImpl( if (storage) { /// If we select from a table, get only not MATERIALIZED, not ALIAS columns. - for (const auto & name_type : storage->getColumnsListNonMaterialized()) + for (const auto & name_type : storage->columns.getListNonMaterialized()) all_columns.emplace_back(std::make_shared(name_type.name)); } else @@ -1147,7 +1149,7 @@ void ExpressionAnalyzer::addAliasColumns() if (!storage) return; - source_columns.insert(std::end(source_columns), std::begin(storage->alias_columns), std::end(storage->alias_columns)); + source_columns.insert(std::end(source_columns), std::begin(storage->columns.aliases), std::end(storage->columns.aliases)); } diff --git a/dbms/src/Interpreters/InterpreterAlterQuery.cpp b/dbms/src/Interpreters/InterpreterAlterQuery.cpp index f990fd8570f..1fb3e1e80db 100644 --- a/dbms/src/Interpreters/InterpreterAlterQuery.cpp +++ b/dbms/src/Interpreters/InterpreterAlterQuery.cpp @@ -200,7 +200,7 @@ void InterpreterAlterQuery::PartitionCommands::validate(const IStorage * table) { String column_name = command.column_name.safeGet(); - if (!table->hasRealColumn(column_name)) + if (!table->columns.has(column_name)) { throw Exception("Wrong column name. Cannot find column " + column_name + " to clear it from partition", DB::ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 2b6d333d1f6..6033947b474 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -301,15 +301,11 @@ ASTPtr InterpreterCreateQuery::formatColumns(const NamesAndTypesList & columns) return columns_list; } -ASTPtr InterpreterCreateQuery::formatColumns( - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults) +ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) { auto columns_list = std::make_shared(); - for (const auto & column : boost::join(columns, boost::join(materialized_columns, alias_columns))) + for (const auto & column : boost::join(columns.ordinary, boost::join(columns.materialized, columns.aliases))) { const auto column_declaration = std::make_shared(); ASTPtr column_declaration_ptr{column_declaration}; @@ -324,8 +320,8 @@ ASTPtr InterpreterCreateQuery::formatColumns( column_declaration->type = parseQuery(storage_p, pos, end, "data type"); column_declaration->type->owned_string = type_name; - const auto it = column_defaults.find(column.name); - if (it != std::end(column_defaults)) + const auto it = columns.defaults.find(column.name); + if (it != std::end(columns.defaults)) { column_declaration->default_specifier = toString(it->second.type); column_declaration->default_expression = it->second.expression->clone(); @@ -338,49 +334,46 @@ ASTPtr InterpreterCreateQuery::formatColumns( } -InterpreterCreateQuery::ColumnsInfo InterpreterCreateQuery::getColumnsInfo(const ASTExpressionList & columns, const Context & context) +ColumnsDescription InterpreterCreateQuery::getColumnsDescription(const ASTExpressionList & columns, const Context & context) { - ColumnsInfo res; + ColumnsDescription res; auto && columns_and_defaults = parseColumns(columns, context); - res.materialized_columns = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Materialized); - res.alias_columns = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Alias); - res.columns = std::move(columns_and_defaults.first); - res.column_defaults = std::move(columns_and_defaults.second); + res.materialized = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Materialized); + res.aliases = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Alias); + res.ordinary = std::move(columns_and_defaults.first); + res.defaults = std::move(columns_and_defaults.second); - if (res.columns.size() + res.materialized_columns.size() == 0) + if (res.ordinary.size() + res.materialized.size() == 0) throw Exception{"Cannot CREATE table without physical columns", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED}; return res; } -InterpreterCreateQuery::ColumnsInfo InterpreterCreateQuery::setColumns( +ColumnsDescription InterpreterCreateQuery::setColumns( ASTCreateQuery & create, const Block & as_select_sample, const StoragePtr & as_storage) const { - ColumnsInfo res; + ColumnsDescription res; if (create.columns) { - res = getColumnsInfo(*create.columns, context); + res = getColumnsDescription(*create.columns, context); } else if (!create.as_table.empty()) { - res.columns = as_storage->getColumnsListNonMaterialized(); - res.materialized_columns = as_storage->materialized_columns; - res.alias_columns = as_storage->alias_columns; - res.column_defaults = as_storage->column_defaults; + res = as_storage->columns; } else if (create.select) { for (size_t i = 0; i < as_select_sample.columns(); ++i) - res.columns.emplace_back(as_select_sample.safeGetByPosition(i).name, as_select_sample.safeGetByPosition(i).type); + res.ordinary.emplace_back(as_select_sample.safeGetByPosition(i).name, as_select_sample.safeGetByPosition(i).type); } else throw Exception("Incorrect CREATE query: required list of column descriptions or AS section or SELECT.", ErrorCodes::INCORRECT_QUERY); /// Even if query has list of columns, canonicalize it (unfold Nested columns). - ASTPtr new_columns = formatColumns(res.columns, res.materialized_columns, res.alias_columns, res.column_defaults); + ASTPtr new_columns = formatColumns(res); if (create.columns) create.replace(create.columns, new_columns); else @@ -394,11 +387,11 @@ InterpreterCreateQuery::ColumnsInfo InterpreterCreateQuery::setColumns( throw Exception("Column " + backQuoteIfNeed(column_name_and_type.name) + " already exists", ErrorCodes::DUPLICATE_COLUMN); }; - for (const auto & elem : res.columns) + for (const auto & elem : res.ordinary) check_column_already_exists(elem); - for (const auto & elem : res.materialized_columns) + for (const auto & elem : res.materialized) check_column_already_exists(elem); - for (const auto & elem : res.alias_columns) + for (const auto & elem : res.aliases) check_column_already_exists(elem); return res; @@ -489,7 +482,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create) } /// Set and retrieve list of columns. - ColumnsInfo columns = setColumns(create, as_select_sample, as_storage); + ColumnsDescription columns = setColumns(create, as_select_sample, as_storage); /// Set the table engine if it was not specified explicitly. setEngine(create); @@ -530,10 +523,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create) database_name, context, context.getGlobalContext(), - columns.columns, - columns.materialized_columns, - columns.alias_columns, - columns.column_defaults, + columns, create.attach, false); diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.h b/dbms/src/Interpreters/InterpreterCreateQuery.h index b72b7eb7d09..8bec93a0fdc 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.h +++ b/dbms/src/Interpreters/InterpreterCreateQuery.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include class ThreadPool; @@ -27,11 +27,7 @@ public: /// List of columns and their types in AST. static ASTPtr formatColumns(const NamesAndTypesList & columns); - static ASTPtr formatColumns( - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults); + static ASTPtr formatColumns(const ColumnsDescription & columns); void setDatabaseLoadingThreadpool(ThreadPool & thread_pool_) { @@ -48,23 +44,15 @@ public: internal = internal_; } - struct ColumnsInfo - { - NamesAndTypesList columns; - NamesAndTypesList materialized_columns; - NamesAndTypesList alias_columns; - ColumnDefaults column_defaults; - }; - /// Obtain information about columns, their types and default values, for case when columns in CREATE query is specified explicitly. - static ColumnsInfo getColumnsInfo(const ASTExpressionList & columns, const Context & context); + static ColumnsDescription getColumnsDescription(const ASTExpressionList & columns, const Context & context); private: BlockIO createDatabase(ASTCreateQuery & create); BlockIO createTable(ASTCreateQuery & create); /// Calculate list of columns of table and return it. - ColumnsInfo setColumns(ASTCreateQuery & create, const Block & as_select_sample, const StoragePtr & as_storage) const; + ColumnsDescription setColumns(ASTCreateQuery & create, const Block & as_select_sample, const StoragePtr & as_storage) const; void setEngine(ASTCreateQuery & create) const; void checkAccess(const ASTCreateQuery & create); diff --git a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp index 65b0fea25f1..b0d7e4c0363 100644 --- a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp +++ b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp @@ -99,9 +99,9 @@ BlockInputStreamPtr InterpreterDescribeQuery::executeImpl() } auto table_lock = table->lockStructure(false, __PRETTY_FUNCTION__); - columns = table->getColumnsList(); - columns.insert(std::end(columns), std::begin(table->alias_columns), std::end(table->alias_columns)); - column_defaults = table->column_defaults; + columns = table->columns.getList(); + columns.insert(std::end(columns), std::begin(table->columns.aliases), std::end(table->columns.aliases)); + column_defaults = table->columns.defaults; } Block sample_block = getSampleBlock(); diff --git a/dbms/src/Interpreters/InterpreterInsertQuery.cpp b/dbms/src/Interpreters/InterpreterInsertQuery.cpp index 014c8d287ad..5f0b8201ac3 100644 --- a/dbms/src/Interpreters/InterpreterInsertQuery.cpp +++ b/dbms/src/Interpreters/InterpreterInsertQuery.cpp @@ -95,7 +95,7 @@ BlockIO InterpreterInsertQuery::execute() auto table_lock = table->lockStructure(true, __PRETTY_FUNCTION__); - NamesAndTypesList required_columns = table->getColumnsList(); + NamesAndTypesList required_columns = table->columns.getList(); /// We create a pipeline of several streams, into which we will write data. BlockOutputStreamPtr out; @@ -103,7 +103,7 @@ BlockIO InterpreterInsertQuery::execute() out = std::make_shared(query.database, query.table, table, context, query_ptr, query.no_destination); out = std::make_shared( - out, getSampleBlock(query, table), required_columns, table->column_defaults, context); + out, getSampleBlock(query, table), required_columns, table->columns.defaults, context); /// Do not squash blocks if it is a sync INSERT into Distributed if (!(context.getSettingsRef().insert_distributed_sync && table->getName() == "Distributed")) @@ -135,7 +135,7 @@ BlockIO InterpreterInsertQuery::execute() if (!allow_materialized) { Block in_header = res.in->getHeader(); - for (const auto & name_type : table->materialized_columns) + for (const auto & name_type : table->columns.materialized) if (in_header.has(name_type.name)) throw Exception("Cannot insert column " + name_type.name + ", because it is MATERIALIZED column.", ErrorCodes::ILLEGAL_COLUMN); } diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 1d5a442bb62..04e05e975ac 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -516,12 +516,12 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline /// Are ALIAS columns required for query execution? auto alias_columns_required = false; - if (storage && !storage->alias_columns.empty()) + if (storage && !storage->columns.aliases.empty()) { for (const auto & column : required_columns) { - const auto default_it = storage->column_defaults.find(column); - if (default_it != std::end(storage->column_defaults) && default_it->second.type == ColumnDefaultType::Alias) + const auto default_it = storage->columns.defaults.find(column); + if (default_it != std::end(storage->columns.defaults) && default_it->second.type == ColumnDefaultType::Alias) { alias_columns_required = true; break; @@ -535,8 +535,8 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline for (const auto & column : required_columns) { - const auto default_it = storage->column_defaults.find(column); - if (default_it != std::end(storage->column_defaults) && default_it->second.type == ColumnDefaultType::Alias) + const auto default_it = storage->columns.defaults.find(column); + if (default_it != std::end(storage->columns.defaults) && default_it->second.type == ColumnDefaultType::Alias) required_columns_expr_list->children.emplace_back(setAlias(default_it->second.expression->clone(), column)); else required_columns_expr_list->children.emplace_back(std::make_shared(column)); diff --git a/dbms/src/Server/TCPHandler.cpp b/dbms/src/Server/TCPHandler.cpp index 55f85c662dc..76a79d09722 100644 --- a/dbms/src/Server/TCPHandler.cpp +++ b/dbms/src/Server/TCPHandler.cpp @@ -630,7 +630,8 @@ bool TCPHandler::receiveData() if (!(storage = query_context.tryGetExternalTable(external_table_name))) { NamesAndTypesList columns = block.getNamesAndTypesList(); - storage = StorageMemory::create(external_table_name, columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}); + storage = StorageMemory::create(external_table_name, + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); storage->startup(); query_context.addExternalTable(external_table_name, storage); } diff --git a/dbms/src/Storages/AlterCommands.cpp b/dbms/src/Storages/AlterCommands.cpp index 8411dfe1bf6..defad6f5cba 100644 --- a/dbms/src/Storages/AlterCommands.cpp +++ b/dbms/src/Storages/AlterCommands.cpp @@ -21,9 +21,7 @@ namespace ErrorCodes } -void AlterCommand::apply( - NamesAndTypesList & columns, NamesAndTypesList & materialized_columns, NamesAndTypesList & alias_columns, - ColumnDefaults & column_defaults) const +void AlterCommand::apply(ColumnsDescription & columns_description) const { if (type == ADD_COLUMN) { @@ -33,9 +31,9 @@ void AlterCommand::apply( std::bind(namesEqual, std::cref(column_name), std::placeholders::_1)); }; - if (exists_in(columns) || - exists_in(materialized_columns) || - exists_in(alias_columns)) + if (exists_in(columns_description.ordinary) || + exists_in(columns_description.materialized) || + exists_in(columns_description.aliases)) { throw Exception{ "Cannot add column " + column_name + ": column with this name already exists", @@ -68,24 +66,24 @@ void AlterCommand::apply( }; if (default_type == ColumnDefaultType::Default) - add_column(columns); + add_column(columns_description.ordinary); else if (default_type == ColumnDefaultType::Materialized) - add_column(materialized_columns); + add_column(columns_description.materialized); else if (default_type == ColumnDefaultType::Alias) - add_column(alias_columns); + add_column(columns_description.aliases); else throw Exception{"Unknown ColumnDefaultType value", ErrorCodes::LOGICAL_ERROR}; if (default_expression) - column_defaults.emplace(column_name, ColumnDefault{default_type, default_expression}); + columns_description.defaults.emplace(column_name, ColumnDefault{default_type, default_expression}); /// Slow, because each time a list is copied - columns = Nested::flatten(columns); + columns_description.ordinary = Nested::flatten(columns_description.ordinary); } else if (type == DROP_COLUMN) { /// look for a column in list and remove it if present, also removing corresponding entry from column_defaults - const auto remove_column = [&column_defaults, this] (NamesAndTypesList & columns) + const auto remove_column = [&columns_description, this] (NamesAndTypesList & columns) { auto removed = false; NamesAndTypesList::iterator column_it; @@ -95,15 +93,15 @@ void AlterCommand::apply( { removed = true; column_it = columns.erase(column_it); - column_defaults.erase(column_name); + columns_description.defaults.erase(column_name); } return removed; }; - if (!remove_column(columns) && - !remove_column(materialized_columns) && - !remove_column(alias_columns)) + if (!remove_column(columns_description.ordinary) && + !remove_column(columns_description.materialized) && + !remove_column(columns_description.aliases)) { throw Exception("Wrong column name. Cannot find column " + column_name + " to drop", ErrorCodes::ILLEGAL_COLUMN); @@ -111,14 +109,15 @@ void AlterCommand::apply( } else if (type == MODIFY_COLUMN) { - const auto default_it = column_defaults.find(column_name); - const auto had_default_expr = default_it != std::end(column_defaults); + const auto default_it = columns_description.defaults.find(column_name); + const auto had_default_expr = default_it != std::end(columns_description.defaults); const auto old_default_type = had_default_expr ? default_it->second.type : ColumnDefaultType{}; /// target column list - auto & new_columns = default_type == ColumnDefaultType::Default ? - columns : default_type == ColumnDefaultType::Materialized ? - materialized_columns : alias_columns; + auto & new_columns = + default_type == ColumnDefaultType::Default ? columns_description.ordinary + : default_type == ColumnDefaultType::Materialized ? columns_description.materialized + : columns_description.aliases; /// find column or throw exception const auto find_column = [this] (NamesAndTypesList & columns) @@ -136,9 +135,10 @@ void AlterCommand::apply( if (default_type != old_default_type) { /// source column list - auto & old_columns = old_default_type == ColumnDefaultType::Default ? - columns : old_default_type == ColumnDefaultType::Materialized ? - materialized_columns : alias_columns; + auto & old_columns = + old_default_type == ColumnDefaultType::Default ? columns_description.ordinary + : old_default_type == ColumnDefaultType::Materialized ? columns_description.materialized + : columns_description.aliases; const auto old_column_it = find_column(old_columns); new_columns.emplace_back(*old_column_it); @@ -146,7 +146,7 @@ void AlterCommand::apply( /// do not forget to change the default type of old column if (had_default_expr) - column_defaults[column_name].type = default_type; + columns_description.defaults[column_name].type = default_type; } /// find column in one of three column lists @@ -155,13 +155,13 @@ void AlterCommand::apply( if (!default_expression && had_default_expr) /// new column has no default expression, remove it from column_defaults along with it's type - column_defaults.erase(column_name); + columns_description.defaults.erase(column_name); else if (default_expression && !had_default_expr) /// new column has a default expression while the old one had not, add it it column_defaults - column_defaults.emplace(column_name, ColumnDefault{default_type, default_expression}); + columns_description.defaults.emplace(column_name, ColumnDefault{default_type, default_expression}); else if (had_default_expr) /// both old and new columns have default expression, update it - column_defaults[column_name].expression = default_expression; + columns_description.defaults[column_name].expression = default_expression; } else if (type == MODIFY_PRIMARY_KEY) { @@ -173,30 +173,21 @@ void AlterCommand::apply( } -void AlterCommands::apply(NamesAndTypesList & columns, - NamesAndTypesList & materialized_columns, - NamesAndTypesList & alias_columns, - ColumnDefaults & column_defaults) const +void AlterCommands::apply(ColumnsDescription & columns_description) const { - auto new_columns = columns; - auto new_materialized_columns = materialized_columns; - auto new_alias_columns = alias_columns; - auto new_column_defaults = column_defaults; + auto new_columns_description = columns_description; for (const AlterCommand & command : *this) - command.apply(new_columns, new_materialized_columns, new_alias_columns, new_column_defaults); + command.apply(new_columns_description); - columns = std::move(new_columns); - materialized_columns = std::move(new_materialized_columns); - alias_columns = std::move(new_alias_columns); - column_defaults = std::move(new_column_defaults); + columns_description = std::move(new_columns_description); } void AlterCommands::validate(IStorage * table, const Context & context) { - auto columns = table->getColumnsList(); - columns.insert(std::end(columns), std::begin(table->alias_columns), std::end(table->alias_columns)); - auto defaults = table->column_defaults; + auto all_columns = table->columns.getList(); + all_columns.insert(std::end(all_columns), std::begin(table->columns.aliases), std::end(table->columns.aliases)); + auto defaults = table->columns.defaults; std::vector> defaulted_columns{}; @@ -208,12 +199,12 @@ void AlterCommands::validate(IStorage * table, const Context & context) if (command.type == AlterCommand::ADD_COLUMN || command.type == AlterCommand::MODIFY_COLUMN) { const auto & column_name = command.column_name; - const auto column_it = std::find_if(std::begin(columns), std::end(columns), + const auto column_it = std::find_if(std::begin(all_columns), std::end(all_columns), std::bind(AlterCommand::namesEqual, std::cref(command.column_name), std::placeholders::_1)); if (command.type == AlterCommand::ADD_COLUMN) { - if (std::end(columns) != column_it) + if (std::end(all_columns) != column_it) throw Exception{ "Cannot add column " + column_name + ": column with this name already exists", ErrorCodes::ILLEGAL_COLUMN}; @@ -221,17 +212,17 @@ void AlterCommands::validate(IStorage * table, const Context & context) else if (command.type == AlterCommand::MODIFY_COLUMN) { - if (std::end(columns) == column_it) + if (std::end(all_columns) == column_it) throw Exception{ "Wrong column name. Cannot find column " + column_name + " to modify", ErrorCodes::ILLEGAL_COLUMN}; - columns.erase(column_it); + all_columns.erase(column_it); defaults.erase(column_name); } /// we're creating dummy DataTypeUInt8 in order to prevent the NullPointerException in ExpressionActions - columns.emplace_back(column_name, command.data_type ? command.data_type : std::make_shared()); + all_columns.emplace_back(column_name, command.data_type ? command.data_type : std::make_shared()); if (command.default_expression) { @@ -265,7 +256,7 @@ void AlterCommands::validate(IStorage * table, const Context & context) for (const auto & default_column : defaults) { const auto & default_expression = default_column.second.expression; - const auto actions = ExpressionAnalyzer{default_expression, context, {}, columns}.getActions(true); + const auto actions = ExpressionAnalyzer{default_expression, context, {}, all_columns}.getActions(true); const auto required_columns = actions->getRequiredColumns(); if (required_columns.end() != std::find(required_columns.begin(), required_columns.end(), command.column_name)) @@ -275,12 +266,12 @@ void AlterCommands::validate(IStorage * table, const Context & context) } auto found = false; - for (auto it = std::begin(columns); it != std::end(columns);) + for (auto it = std::begin(all_columns); it != std::end(all_columns);) { if (AlterCommand::namesEqual(command.column_name, *it)) { found = true; - it = columns.erase(it); + it = all_columns.erase(it); } else ++it; @@ -305,7 +296,7 @@ void AlterCommands::validate(IStorage * table, const Context & context) for (const auto & col_def : defaults) { const auto & column_name = col_def.first; - const auto column_it = std::find_if(columns.begin(), columns.end(), [&] (const NameAndTypePair & name_type) + const auto column_it = std::find_if(all_columns.begin(), all_columns.end(), [&] (const NameAndTypePair & name_type) { return AlterCommand::namesEqual(column_name, name_type); }); const auto tmp_column_name = column_name + "_tmp"; @@ -321,7 +312,7 @@ void AlterCommands::validate(IStorage * table, const Context & context) defaulted_columns.emplace_back(NameAndTypePair{column_name, column_type_ptr}, nullptr); } - const auto actions = ExpressionAnalyzer{default_expr_list, context, {}, columns}.getActions(true); + const auto actions = ExpressionAnalyzer{default_expr_list, context, {}, all_columns}.getActions(true); const auto block = actions->getSampleBlock(); /// set deduced types, modify default expression if necessary diff --git a/dbms/src/Storages/AlterCommands.h b/dbms/src/Storages/AlterCommands.h index 543106254e6..44c44e8bfd0 100644 --- a/dbms/src/Storages/AlterCommands.h +++ b/dbms/src/Storages/AlterCommands.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace DB { @@ -43,10 +43,7 @@ struct AlterCommand return (name_with_dot == name_type.name.substr(0, name_without_dot.length() + 1) || name_without_dot == name_type.name); } - void apply(NamesAndTypesList & columns, - NamesAndTypesList & materialized_columns, - NamesAndTypesList & alias_columns, - ColumnDefaults & column_defaults) const; + void apply(ColumnsDescription & columns_description) const; AlterCommand() = default; AlterCommand(const Type type, const String & column_name, const DataTypePtr & data_type, @@ -63,10 +60,7 @@ class Context; class AlterCommands : public std::vector { public: - void apply(NamesAndTypesList & columns, - NamesAndTypesList & materialized_columns, - NamesAndTypesList & alias_columns, - ColumnDefaults & column_defaults) const; + void apply(ColumnsDescription & columns_description) const; void validate(IStorage * table, const Context & context); }; diff --git a/dbms/src/Storages/ColumnsDescription.cpp b/dbms/src/Storages/ColumnsDescription.cpp index c0bfabea727..b8fae53ed4e 100644 --- a/dbms/src/Storages/ColumnsDescription.cpp +++ b/dbms/src/Storages/ColumnsDescription.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,8 +8,13 @@ #include #include #include -#include #include +#include + +#include +#include + +#include namespace DB @@ -16,17 +22,47 @@ namespace DB namespace ErrorCodes { + extern const int NO_SUCH_COLUMN_IN_TABLE; extern const int CANNOT_PARSE_TEXT; } -template -String ColumnsDescription::toString() const +NamesAndTypesList ColumnsDescription::getList() const +{ + return ext::collection_cast(boost::join(ordinary, materialized)); +} + + +Names ColumnsDescription::getNames() const +{ + return ext::map(boost::join(ordinary, materialized), [] (const auto & it) { return it.name; }); +} + + +NameAndTypePair ColumnsDescription::get(const String & column_name) const +{ + for (auto & it : boost::join(ordinary, materialized)) + if (it.name == column_name) + return it; + throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE); +} + + +bool ColumnsDescription::has(const String & column_name) const +{ + for (auto & it : boost::join(ordinary, materialized)) + if (it.name == column_name) + return true; + return false; +} + + +String ColumnsDescription::toString() const { WriteBufferFromOwnString buf; writeString("columns format version: 1\n", buf); - writeText(columns.size() + materialized.size() + alias.size(), buf); + writeText(ordinary.size() + materialized.size() + aliases.size(), buf); writeString(" columns:\n", buf); const auto write_columns = [this, &buf] (const NamesAndTypesList & columns) @@ -53,16 +89,15 @@ String ColumnsDescription::toString() const } }; - write_columns(columns); + write_columns(ordinary); write_columns(materialized); - write_columns(alias); + write_columns(aliases); return buf.str(); } -template <> -ColumnsDescription ColumnsDescription::parse(const String & str) +ColumnsDescription ColumnsDescription::parse(const String & str) { ReadBufferFromString buf{str}; @@ -74,7 +109,7 @@ ColumnsDescription ColumnsDescription::parse(const String & str) ParserExpression expr_parser; const DataTypeFactory & data_type_factory = DataTypeFactory::instance(); - ColumnsDescription result{}; + ColumnsDescription result; for (size_t i = 0; i < count; ++i) { String column_name; @@ -88,7 +123,7 @@ ColumnsDescription ColumnsDescription::parse(const String & str) { assertChar('\n', buf); - result.columns.emplace_back(column_name, std::move(type)); + result.ordinary.emplace_back(column_name, std::move(type)); continue; } assertChar('\t', buf); @@ -107,11 +142,11 @@ ColumnsDescription ColumnsDescription::parse(const String & str) ASTPtr default_expr = parseQuery(expr_parser, begin, end, "default expression"); if (ColumnDefaultType::Default == default_type) - result.columns.emplace_back(column_name, std::move(type)); + result.ordinary.emplace_back(column_name, std::move(type)); else if (ColumnDefaultType::Materialized == default_type) result.materialized.emplace_back(column_name, std::move(type)); else if (ColumnDefaultType::Alias == default_type) - result.alias.emplace_back(column_name, std::move(type)); + result.aliases.emplace_back(column_name, std::move(type)); result.defaults.emplace(column_name, ColumnDefault{default_type, default_expr}); } @@ -121,8 +156,4 @@ ColumnsDescription ColumnsDescription::parse(const String & str) return result; } - -template struct ColumnsDescription; -template struct ColumnsDescription; - } diff --git a/dbms/src/Storages/ColumnsDescription.h b/dbms/src/Storages/ColumnsDescription.h index cce6232d33b..888f0864701 100644 --- a/dbms/src/Storages/ColumnsDescription.h +++ b/dbms/src/Storages/ColumnsDescription.h @@ -1,28 +1,53 @@ #pragma once -#include #include +#include +#include +#include namespace DB { - -template struct ColumnsDescription { - template - using by_value_or_cref = std::conditional_t; + NamesAndTypesList ordinary; + NamesAndTypesList materialized; + NamesAndTypesList aliases; + ColumnDefaults defaults; + + + bool operator==(const ColumnsDescription & other) const + { + return ordinary == other.ordinary + && materialized == other.materialized + && aliases == other.aliases + && defaults == other.defaults; + } + + bool operator!=(const ColumnsDescription & other) const { return !(*this == other); } + + /** Get a list of names and table column types, only non-virtual. + */ + NamesAndTypesList getList() const; + const NamesAndTypesList & getListNonMaterialized() const { return ordinary; } + + /** Get a list of column names. + */ + Names getNames() const; + + /** Get a description of any column by its name. + */ + NameAndTypePair get(const String & column_name) const; + + /** Is there a column with that name. + */ + bool has(const String & column_name) const; - by_value_or_cref columns; - by_value_or_cref materialized; - by_value_or_cref alias; - by_value_or_cref defaults; String toString() const; static ColumnsDescription parse(const String & str); }; - } diff --git a/dbms/src/Storages/Distributed/DirectoryMonitor.cpp b/dbms/src/Storages/Distributed/DirectoryMonitor.cpp index 66a4fc84434..6347510f7b1 100644 --- a/dbms/src/Storages/Distributed/DirectoryMonitor.cpp +++ b/dbms/src/Storages/Distributed/DirectoryMonitor.cpp @@ -468,7 +468,7 @@ bool StorageDistributedDirectoryMonitor::maybeMarkAsBroken(const std::string & f std::string StorageDistributedDirectoryMonitor::getLoggerName() const { - return storage.name + '.' + storage.getName() + ".DirectoryMonitor"; + return storage.table_name + '.' + storage.getName() + ".DirectoryMonitor"; } } diff --git a/dbms/src/Storages/IStorage.h b/dbms/src/Storages/IStorage.h index a2970b0de96..ef9fd8004ce 100644 --- a/dbms/src/Storages/IStorage.h +++ b/dbms/src/Storages/IStorage.h @@ -83,6 +83,10 @@ public: /// The main name of the table type (for example, StorageMergeTree). virtual std::string getName() const = 0; + /** The name of the table. + */ + virtual std::string getTableName() const = 0; + /** Returns true if the storage receives data from a remote server or servers. */ virtual bool isRemote() const { return false; } diff --git a/dbms/src/Storages/ITableDeclaration.cpp b/dbms/src/Storages/ITableDeclaration.cpp index da4cc920608..d4bbb4b501e 100644 --- a/dbms/src/Storages/ITableDeclaration.cpp +++ b/dbms/src/Storages/ITableDeclaration.cpp @@ -1,13 +1,12 @@ -#include +#include +#include + +#include #include #include -#include -#include -#include -#include -#include -#include -#include + +#include +#include namespace DB @@ -25,77 +24,14 @@ namespace ErrorCodes } -NamesAndTypesList ITableDeclaration::getColumnsList() const -{ - return ext::collection_cast(getColumnsListRange()); -} - - -ITableDeclaration::ColumnsListRange ITableDeclaration::getColumnsListRange() const -{ - return boost::join(getColumnsListImpl(), materialized_columns); -} - - -bool ITableDeclaration::hasRealColumn(const String & column_name) const -{ - for (auto & it : getColumnsListRange()) - if (it.name == column_name) - return true; - return false; -} - - -Names ITableDeclaration::getColumnNamesList() const -{ - return ext::map(getColumnsListRange(), [] (const auto & it) { return it.name; }); -} - - -NameAndTypePair ITableDeclaration::getRealColumn(const String & column_name) const -{ - for (auto & it : getColumnsListRange()) - if (it.name == column_name) - return it; - throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE); -} - -NameAndTypePair ITableDeclaration::getMaterializedColumn(const String & column_name) const -{ - for (auto & column : materialized_columns) - if (column.name == column_name) - return column; - - throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE); -} - -bool ITableDeclaration::hasMaterializedColumn(const String & column_name) const -{ - for (auto & column : materialized_columns) - if (column.name == column_name) - return true; - - return false; -} - bool ITableDeclaration::hasColumn(const String & column_name) const { - return hasRealColumn(column_name); /// By default, we assume that there are no virtual columns in the storage. + return columns.has(column_name); /// By default, we assume that there are no virtual columns in the storage. } NameAndTypePair ITableDeclaration::getColumn(const String & column_name) const { - return getRealColumn(column_name); /// By default, we assume that there are no virtual columns in the storage. -} - - -const DataTypePtr ITableDeclaration::getDataTypeByName(const String & column_name) const -{ - for (const auto & column : getColumnsListRange()) - if (column.name == column_name) - return column.type; - - throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE); + return columns.get(column_name); /// By default, we assume that there are no virtual columns in the storage. } @@ -103,7 +39,7 @@ Block ITableDeclaration::getSampleBlock() const { Block res; - for (const auto & col : getColumnsListRange()) + for (const auto & col : boost::join(columns.ordinary, columns.materialized)) res.insert({ col.type->createColumn(), col.type, col.name }); return res; @@ -114,7 +50,7 @@ Block ITableDeclaration::getSampleBlockNonMaterialized() const { Block res; - for (const auto & col : getColumnsListNonMaterialized()) + for (const auto & col : columns.ordinary) res.insert({ col.type->createColumn(), col.type, col.name }); return res; @@ -138,7 +74,7 @@ Block ITableDeclaration::getSampleBlockForColumns(const Names & column_names) co static std::string listOfColumns(const NamesAndTypesList & available_columns) { std::stringstream s; - for (NamesAndTypesList::const_iterator it = available_columns.begin(); it != available_columns.end(); ++it) + for (auto it = available_columns.begin(); it != available_columns.end(); ++it) { if (it != available_columns.begin()) s << ", "; @@ -175,7 +111,7 @@ static NamesAndTypesMap getColumnsMap(const Args &... args) void ITableDeclaration::check(const Names & column_names) const { - const NamesAndTypesList & available_columns = getColumnsList(); + const NamesAndTypesList & available_columns = columns.getList(); if (column_names.empty()) throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns), @@ -201,16 +137,16 @@ void ITableDeclaration::check(const Names & column_names) const } -void ITableDeclaration::check(const NamesAndTypesList & columns) const +void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const { - const NamesAndTypesList & available_columns = getColumnsList(); + const NamesAndTypesList & available_columns = columns.getList(); const auto columns_map = getColumnsMap(available_columns); using UniqueStrings = google::dense_hash_set; UniqueStrings unique_names; unique_names.set_empty_key(StringRef()); - for (const NameAndTypePair & column : columns) + for (const NameAndTypePair & column : provided_columns) { NamesAndTypesMap::const_iterator it = columns_map.find(column.name); if (columns_map.end() == it) @@ -229,11 +165,11 @@ void ITableDeclaration::check(const NamesAndTypesList & columns) const } -void ITableDeclaration::check(const NamesAndTypesList & columns, const Names & column_names) const +void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const Names & column_names) const { - const NamesAndTypesList & available_columns = getColumnsList(); + const NamesAndTypesList & available_columns = columns.getList(); const auto available_columns_map = getColumnsMap(available_columns); - const NamesAndTypesMap & provided_columns_map = getColumnsMap(columns); + const NamesAndTypesMap & provided_columns_map = getColumnsMap(provided_columns); if (column_names.empty()) throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns), @@ -268,7 +204,7 @@ void ITableDeclaration::check(const NamesAndTypesList & columns, const Names & c void ITableDeclaration::check(const Block & block, bool need_all) const { - const NamesAndTypesList & available_columns = getColumnsList(); + const NamesAndTypesList & available_columns = columns.getList(); const auto columns_map = getColumnsMap(available_columns); using NameSet = std::unordered_set; @@ -304,14 +240,11 @@ void ITableDeclaration::check(const Block & block, bool need_all) const } } -ITableDeclaration::ITableDeclaration(const NamesAndTypesList & columns, const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, const ColumnDefaults & column_defaults) - : columns{columns}, - materialized_columns{materialized_columns}, - alias_columns{alias_columns}, - column_defaults{column_defaults} + +ITableDeclaration::ITableDeclaration(ColumnsDescription columns_) + : columns{std::move(columns_)} { - if (columns.empty()) + if (columns.ordinary.empty()) throw Exception("Empty list of columns passed to storage constructor", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED); } diff --git a/dbms/src/Storages/ITableDeclaration.h b/dbms/src/Storages/ITableDeclaration.h index 841ebc6c753..4c4ea59e4b5 100644 --- a/dbms/src/Storages/ITableDeclaration.h +++ b/dbms/src/Storages/ITableDeclaration.h @@ -1,50 +1,17 @@ #pragma once -#include -#include -#include -#include -#include - -#include -#include +#include namespace DB { -class Context; - /** Description of the table. - * Do not thread safe. See IStorage::lockStructure (). + * Is not thread safe. See IStorage::lockStructure (). */ class ITableDeclaration { public: - /** The name of the table. - */ - virtual std::string getTableName() const = 0; - - /** Get a list of names and table column types, only non-virtual. - */ - NamesAndTypesList getColumnsList() const; - const NamesAndTypesList & getColumnsListNonMaterialized() const { return getColumnsListImpl(); } - - /** Get a list of column table names, only non-virtual. - */ - virtual Names getColumnNamesList() const; - - /** Get a description of the real (non-virtual) column by its name. - */ - virtual NameAndTypePair getRealColumn(const String & column_name) const; - - /** Is there a real (non-virtual) column with that name. - */ - virtual bool hasRealColumn(const String & column_name) const; - - NameAndTypePair getMaterializedColumn(const String & column_name) const; - bool hasMaterializedColumn(const String & column_name) const; - /** Get a description of any column by its name. */ virtual NameAndTypePair getColumn(const String & column_name) const; @@ -53,10 +20,6 @@ public: */ virtual bool hasColumn(const String & column_name) const; - const DataTypePtr getDataTypeByName(const String & column_name) const; - - /** The same, but in the form of a block-sample. - */ Block getSampleBlock() const; Block getSampleBlockNonMaterialized() const; Block getSampleBlockForColumns(const Names & column_names) const; @@ -81,29 +44,11 @@ public: void check(const Block & block, bool need_all = false) const; + ITableDeclaration() = default; + explicit ITableDeclaration(ColumnsDescription columns_); virtual ~ITableDeclaration() = default; - ITableDeclaration() = default; - ITableDeclaration( - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults); - - NamesAndTypesList columns; - NamesAndTypesList materialized_columns; - NamesAndTypesList alias_columns; - ColumnDefaults column_defaults; - -private: - virtual const NamesAndTypesList & getColumnsListImpl() const - { - return columns; - } - - using ColumnsListRange = boost::range::joined_range; - /// Returns a lazily joined range of table's ordinary and materialized columns, without unnecessary copying - ColumnsListRange getColumnsListRange() const; + ColumnsDescription columns; }; } diff --git a/dbms/src/Storages/MergeTree/DataPartsExchange.cpp b/dbms/src/Storages/MergeTree/DataPartsExchange.cpp index e2c884681d3..b2ff96e0fe3 100644 --- a/dbms/src/Storages/MergeTree/DataPartsExchange.cpp +++ b/dbms/src/Storages/MergeTree/DataPartsExchange.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp index e0a8dc94400..5a67714db64 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp @@ -141,8 +141,8 @@ try if (!column_names.empty()) storage.check(data_part->columns, column_names); - pre_columns = storage.getColumnsList().addTypes(pre_column_names); - columns = storage.getColumnsList().addTypes(column_names); + pre_columns = storage.columns.getList().addTypes(pre_column_names); + columns = storage.columns.getList().addTypes(column_names); } else { diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp b/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp index b0b09ae06eb..b6d8ff3cd5a 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp @@ -26,9 +26,9 @@ NameSet injectRequiredColumns(const MergeTreeData & storage, const MergeTreeData continue; } - const auto default_it = storage.column_defaults.find(column_name); + const auto default_it = storage.columns.defaults.find(column_name); /// columns has no explicit default expression - if (default_it == std::end(storage.column_defaults)) + if (default_it == std::end(storage.columns.defaults)) continue; /// collect identifiers required for evaluation diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 392c45a7cc7..7933a9454c7 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -80,10 +80,7 @@ namespace ErrorCodes MergeTreeData::MergeTreeData( const String & database_, const String & table_, - const String & full_path_, const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const String & full_path_, const ColumnsDescription & columns_, Context & context_, const ASTPtr & primary_expr_ast_, const ASTPtr & secondary_sort_expr_ast_, @@ -95,7 +92,7 @@ MergeTreeData::MergeTreeData( bool require_part_metadata_, bool attach, BrokenPartCallback broken_part_callback_) - : ITableDeclaration{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : ITableDeclaration{columns_}, context(context_), sampling_expression(sampling_expression_), index_granularity(settings_.index_granularity), @@ -113,7 +110,7 @@ MergeTreeData::MergeTreeData( data_parts_by_state_and_info(data_parts_indexes.get()) { /// NOTE: using the same columns list as is read when performing actual merges. - merging_params.check(getColumnsList()); + merging_params.check(columns.getList()); if (!primary_expr_ast) throw Exception("Primary key cannot be empty", ErrorCodes::BAD_ARGUMENTS); @@ -225,11 +222,11 @@ void MergeTreeData::initPrimaryKey() primary_sort_descr.clear(); addSortDescription(primary_sort_descr, primary_expr_ast); - primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumnsList()).getActions(false); + primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getList()).getActions(false); { ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumnsList()).getActions(true); + ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getList()).getActions(true); primary_key_sample = projected_expr->getSampleBlock(); } @@ -244,10 +241,10 @@ void MergeTreeData::initPrimaryKey() if (secondary_sort_expr_ast) { addSortDescription(sort_descr, secondary_sort_expr_ast); - secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumnsList()).getActions(false); + secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getList()).getActions(false); ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumnsList()).getActions(true); + ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getList()).getActions(true); auto secondary_key_sample = projected_expr->getSampleBlock(); checkKeyExpression(*secondary_sort_expr, secondary_key_sample, "Secondary"); @@ -260,7 +257,7 @@ void MergeTreeData::initPartitionKey() if (!partition_expr_ast || partition_expr_ast->children.empty()) return; - partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, getColumnsList()).getActions(false); + partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, columns.getList()).getActions(false); for (const ASTPtr & ast : partition_expr_ast->children) { String col_name = ast->getColumnName(); @@ -865,10 +862,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) { /// Check that needed transformations can be applied to the list of columns without considering type conversions. auto new_columns = columns; - auto new_materialized_columns = materialized_columns; - auto new_alias_columns = alias_columns; - auto new_column_defaults = column_defaults; - commands.apply(new_columns, new_materialized_columns, new_alias_columns, new_column_defaults); + commands.apply(new_columns); /// Set of columns that shouldn't be altered. NameSet columns_alter_forbidden; @@ -909,7 +903,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) columns_alter_forbidden.insert(merging_params.sign_column); std::map old_types; - for (const auto & column : columns) + for (const auto & column : columns.ordinary) old_types.emplace(column.name, column.type.get()); for (const AlterCommand & command : commands) @@ -937,11 +931,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) NameToNameMap unused_map; bool unused_bool; - /// augment plain columns with materialized columns for convert expression creation - new_columns.insert(std::end(new_columns), - std::begin(new_materialized_columns), std::end(new_materialized_columns)); - - createConvertExpression(nullptr, getColumnsList(), new_columns, unused_expression, unused_map, unused_bool); + createConvertExpression(nullptr, columns.getList(), new_columns.getList(), unused_expression, unused_map, unused_bool); } void MergeTreeData::createConvertExpression(const DataPartPtr & part, const NamesAndTypesList & old_columns, const NamesAndTypesList & new_columns, @@ -1845,7 +1835,7 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : getColumnsList()) + for (const auto & column : columns.getList()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; @@ -1878,7 +1868,7 @@ void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : columns) + for (const auto & column : columns.ordinary) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.h b/dbms/src/Storages/MergeTree/MergeTreeData.h index 519e7223d13..a32baf797ef 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.h +++ b/dbms/src/Storages/MergeTree/MergeTreeData.h @@ -4,7 +4,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -270,10 +271,8 @@ public: /// require_part_metadata - should checksums.txt and columns.txt exist in the part directory. /// attach - whether the existing table is attached or the new table is created. MergeTreeData(const String & database_, const String & table_, - const String & full_path_, const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const String & full_path_, + const ColumnsDescription & columns_, Context & context_, const ASTPtr & primary_expr_ast_, const ASTPtr & secondary_sort_expr_ast_, @@ -305,8 +304,6 @@ public: Int64 getMaxDataPartIndex(); - const NamesAndTypesList & getColumnsListImpl() const override { return columns; } - NameAndTypePair getColumn(const String & column_name) const override { if (column_name == "_part") @@ -316,12 +313,12 @@ public: if (column_name == "_sample_factor") return NameAndTypePair("_sample_factor", std::make_shared()); - return ITableDeclaration::getColumn(column_name); + return columns.get(column_name); } bool hasColumn(const String & column_name) const override { - return ITableDeclaration::hasColumn(column_name) + return columns.has(column_name) || column_name == "_part" || column_name == "_part_index" || column_name == "_sample_factor"; @@ -329,7 +326,7 @@ public: String getDatabaseName() const { return database_name; } - String getTableName() const override { return table_name; } + String getTableName() const { return table_name; } String getFullPath() const { return full_path; } @@ -431,9 +428,6 @@ public: const ASTPtr & new_primary_key, bool skip_sanity_checks); - /// Must be called with locked lockStructureForAlter(). - void setColumnsList(const NamesAndTypesList & new_columns) { columns = new_columns; } - /// Should be called if part data is suspected to be corrupted. void reportBrokenPart(const String & name) { @@ -507,6 +501,7 @@ public: /// For ATTACH/DETACH/DROP PARTITION. String getPartitionIDFromQuery(const ASTPtr & partition, const Context & context); + MergeTreeDataFormatVersion format_version; Context & context; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index cf9e6eef15c..4e3e9788aaa 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -536,8 +536,8 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataMerger::mergePartsToTemporaryPart for (const MergeTreeData::DataPartPtr & part : parts) part->accumulateColumnSizes(merged_column_to_size); - Names all_column_names = data.getColumnNamesList(); - NamesAndTypesList all_columns = data.getColumnsList(); + Names all_column_names = data.columns.getNames(); + NamesAndTypesList all_columns = data.columns.getList(); const SortDescription sort_desc = data.getSortDescription(); NamesAndTypesList gathering_columns, merging_columns; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index df273f2d6b5..9c0269c7437 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -418,7 +418,7 @@ UInt64 MergeTreeDataPart::getColumnMrkSize(const String & name) const */ String MergeTreeDataPart::getColumnNameWithMinumumCompressedSize() const { - const auto & columns = storage.getColumnsList(); + const auto & columns = storage.columns.getList(); const std::string * minimum_size_column = nullptr; UInt64 minimum_size = std::numeric_limits::max(); @@ -774,7 +774,7 @@ void MergeTreeDataPart::accumulateColumnSizes(ColumnToSize & column_to_size) con { std::shared_lock part_lock(columns_lock); - for (const NameAndTypePair & name_type : storage.columns) + for (const NameAndTypePair & name_type : storage.columns.getList()) { name_type.type->enumerateStreams([&](const IDataType::SubstreamPath & substream_path) { @@ -794,7 +794,7 @@ void MergeTreeDataPart::loadColumns(bool require) throw Exception("No columns.txt in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); /// If there is no file with a list of columns, write it down. - for (const NameAndTypePair & column : storage.getColumnsList()) + for (const NameAndTypePair & column : storage.columns.getList()) if (Poco::File(getFullPath() + escapeForFileName(column.name) + ".bin").exists()) columns.push_back(column); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp index fb7c1735ced..605091e6386 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp @@ -175,7 +175,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read( } } - NamesAndTypesList available_real_columns = data.getColumnsList(); + NamesAndTypesList available_real_columns = data.columns.getList(); NamesAndTypesList available_real_and_virtual_columns = available_real_columns; for (const auto & name : virt_column_names) @@ -857,7 +857,7 @@ void MergeTreeDataSelectExecutor::createPositiveSignCondition( arguments->children.push_back(sign); arguments->children.push_back(one); - out_expression = ExpressionAnalyzer(function, context, {}, data.getColumnsList()).getActions(false); + out_expression = ExpressionAnalyzer(function, context, {}, data.columns.getList()).getActions(false); out_column = function->getColumnName(); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h index fd0b0265ced..1b3caeeb259 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h +++ b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index fabbca3a473..f4db6b934ba 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -205,7 +205,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithPa /// either default lz4 or compression method with zero thresholds on absolute and relative part size. auto compression_settings = data.context.chooseCompressionSettings(0, 0); - NamesAndTypesList columns = data.getColumnsList().filter(block.getNames()); + NamesAndTypesList columns = data.columns.getList().filter(block.getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_settings); out.writePrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp index e95c576274c..c32aa71a731 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp @@ -238,8 +238,8 @@ std::vector MergeTreeReadPool::fillPerPartInfo( if (!required_column_names.empty()) data.check(part.data_part->columns, required_column_names); - per_part_pre_columns.push_back(data.getColumnsList().addTypes(required_pre_column_names)); - per_part_columns.push_back(data.getColumnsList().addTypes(required_column_names)); + per_part_pre_columns.push_back(data.columns.getList().addTypes(required_pre_column_names)); + per_part_columns.push_back(data.columns.getList().addTypes(required_column_names)); } else { diff --git a/dbms/src/Storages/MergeTree/MergeTreeReader.cpp b/dbms/src/Storages/MergeTree/MergeTreeReader.cpp index 63d763d5939..7bce149776a 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeReader.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeReader.cpp @@ -463,7 +463,7 @@ void MergeTreeReader::fillMissingColumns(Block & res, const Names & ordered_name if (!has_column) { should_sort = true; - if (storage.column_defaults.count(requested_column.name) != 0) + if (storage.columns.defaults.count(requested_column.name) != 0) { should_evaluate_defaults = true; continue; @@ -498,7 +498,7 @@ void MergeTreeReader::fillMissingColumns(Block & res, const Names & ordered_name /// evaluate defaulted columns if necessary if (should_evaluate_defaults) - evaluateMissingDefaults(res, columns, storage.column_defaults, storage.context); + evaluateMissingDefaults(res, columns, storage.columns.defaults, storage.context); /// sort columns to ensure consistent order among all blocks if (should_sort) diff --git a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp index cf7bc0d33f7..005ca750226 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp @@ -41,9 +41,9 @@ MergeTreeWhereOptimizer::MergeTreeWhereOptimizer( Logger * log) : primary_key_columns{ext::map(data.getPrimarySortDescription(), [] (const SortColumnDescription & col) { return col.column_name; })}, - table_columns{ext::map(data.getColumnsList(), + table_columns{ext::map(data.columns.getList(), [] (const NameAndTypePair & col) { return col.name; })}, - block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.getColumnsList())}, + block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.columns.getList())}, prepared_sets(query_info.sets), log{log} { diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp index ef7582c497c..c359a889bfb 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp @@ -56,12 +56,7 @@ void ReplicatedMergeTreeAlterThread::run() zkutil::Stat stat; const String columns_str = zookeeper->get(storage.zookeeper_path + "/columns", &stat, wakeup_event); - auto columns_desc = ColumnsDescription::parse(columns_str); - - auto & columns = columns_desc.columns; - auto & materialized_columns = columns_desc.materialized; - auto & alias_columns = columns_desc.alias; - auto & column_defaults = columns_desc.defaults; + auto columns_in_zk = ColumnsDescription::parse(columns_str); bool changed_version = (stat.version != storage.columns_version); @@ -92,42 +87,15 @@ void ReplicatedMergeTreeAlterThread::run() auto table_lock = storage.lockStructureForAlter(__PRETTY_FUNCTION__); - const auto columns_changed = columns != storage.data.getColumnsListNonMaterialized(); - const auto materialized_columns_changed = materialized_columns != storage.data.materialized_columns; - const auto alias_columns_changed = alias_columns != storage.data.alias_columns; - const auto column_defaults_changed = column_defaults != storage.data.column_defaults; - - if (columns_changed || materialized_columns_changed || alias_columns_changed || - column_defaults_changed) + if (columns_in_zk != storage.data.columns) { LOG_INFO(log, "Columns list changed in ZooKeeper. Applying changes locally."); storage.context.getDatabase(storage.database_name)->alterTable( - storage.context, storage.table_name, - columns, materialized_columns, alias_columns, column_defaults, {}); + storage.context, storage.table_name, columns_in_zk, {}); - if (columns_changed) - { - storage.data.setColumnsList(columns); - } - - if (materialized_columns_changed) - { - storage.materialized_columns = materialized_columns; - storage.data.materialized_columns = std::move(materialized_columns); - } - - if (alias_columns_changed) - { - storage.alias_columns = alias_columns; - storage.data.alias_columns = std::move(alias_columns); - } - - if (column_defaults_changed) - { - storage.column_defaults = column_defaults; - storage.data.column_defaults = std::move(column_defaults); - } + storage.columns = columns_in_zk; + storage.data.columns = std::move(columns_in_zk); /// Reinitialize primary key because primary key column types might have changed. storage.data.initPrimaryKey(); @@ -158,7 +126,7 @@ void ReplicatedMergeTreeAlterThread::run() if (!changed_version) parts = storage.data.getDataParts(); - const auto columns_plus_materialized = storage.data.getColumnsList(); + const auto columns_plus_materialized = storage.data.columns.getList(); for (const MergeTreeData::DataPartPtr & part : parts) { diff --git a/dbms/src/Storages/MergeTree/registerStorageMergeTree.cpp b/dbms/src/Storages/MergeTree/registerStorageMergeTree.cpp index 89787fca4f0..4cdff05c2e3 100644 --- a/dbms/src/Storages/MergeTree/registerStorageMergeTree.cpp +++ b/dbms/src/Storages/MergeTree/registerStorageMergeTree.cpp @@ -628,14 +628,13 @@ static StoragePtr create(const StorageFactory::Arguments & args) if (replicated) return StorageReplicatedMergeTree::create( zookeeper_path, replica_name, args.attach, args.data_path, args.database_name, args.table_name, - args.columns, args.materialized_columns, args.alias_columns, args.column_defaults, + args.columns, args.context, primary_expr_list, secondary_sorting_expr_list, date_column_name, partition_expr_list, sampling_expression, merging_params, storage_settings, args.has_force_restore_data_flag); else return StorageMergeTree::create( - args.data_path, args.database_name, args.table_name, - args.columns, args.materialized_columns, args.alias_columns, args.column_defaults, args.attach, + args.data_path, args.database_name, args.table_name, args.columns, args.attach, args.context, primary_expr_list, secondary_sorting_expr_list, date_column_name, partition_expr_list, sampling_expression, merging_params, storage_settings, args.has_force_restore_data_flag); diff --git a/dbms/src/Storages/StorageBuffer.cpp b/dbms/src/Storages/StorageBuffer.cpp index 6b9ec92ce75..c76a1edc81b 100644 --- a/dbms/src/Storages/StorageBuffer.cpp +++ b/dbms/src/Storages/StorageBuffer.cpp @@ -48,14 +48,11 @@ namespace ErrorCodes } -StorageBuffer::StorageBuffer(const std::string & name_, const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, +StorageBuffer::StorageBuffer(const std::string & name_, const ColumnsDescription & columns_, Context & context_, size_t num_shards_, const Thresholds & min_thresholds_, const Thresholds & max_thresholds_, const String & destination_database_, const String & destination_table_, bool allow_materialized_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, name(name_), context(context_), num_shards(num_shards_), buffers(num_shards_), min_thresholds(min_thresholds_), max_thresholds(max_thresholds_), @@ -598,11 +595,8 @@ void StorageBuffer::alter(const AlterCommands & params, const String & database_ /// So that no blocks of the old structure remain. optimize({} /*query*/, {} /*partition_id*/, false /*final*/, false /*deduplicate*/, context); - params.apply(columns, materialized_columns, alias_columns, column_defaults); - - context.getDatabase(database_name)->alterTable( - context, table_name, - columns, materialized_columns, alias_columns, column_defaults, {}); + params.apply(columns); + context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); } @@ -641,7 +635,6 @@ void registerStorageBuffer(StorageFactory & factory) return StorageBuffer::create( args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, args.context, num_buckets, StorageBuffer::Thresholds{min_time, min_rows, min_bytes}, diff --git a/dbms/src/Storages/StorageBuffer.h b/dbms/src/Storages/StorageBuffer.h index 9d9f72340c5..02c2ef9b09b 100644 --- a/dbms/src/Storages/StorageBuffer.h +++ b/dbms/src/Storages/StorageBuffer.h @@ -123,10 +123,7 @@ protected: /** num_shards - the level of internal parallelism (the number of independent buffers) * The buffer is flushed if all minimum thresholds or at least one of the maximum thresholds are exceeded. */ - StorageBuffer(const std::string & name_, const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + StorageBuffer(const std::string & name_, const ColumnsDescription & columns_, Context & context_, size_t num_shards_, const Thresholds & min_thresholds_, const Thresholds & max_thresholds_, const String & destination_database_, const String & destination_table_, bool allow_materialized_); diff --git a/dbms/src/Storages/StorageCatBoostPool.cpp b/dbms/src/Storages/StorageCatBoostPool.cpp index cbaf523e3bf..1a973f7dd75 100644 --- a/dbms/src/Storages/StorageCatBoostPool.cpp +++ b/dbms/src/Storages/StorageCatBoostPool.cpp @@ -220,7 +220,6 @@ void StorageCatBoostPool::parseColumnDescription() void StorageCatBoostPool::createSampleBlockAndColumns() { - columns.clear(); NamesAndTypesList cat_columns; NamesAndTypesList num_columns; sample_block.clear(); @@ -239,19 +238,19 @@ void StorageCatBoostPool::createSampleBlockAndColumns() else if (desc.column_type == DatasetColumnType::Num) num_columns.emplace_back(desc.column_name, type); else - materialized_columns.emplace_back(desc.column_name, type); + columns.materialized.emplace_back(desc.column_name, type); if (!desc.alias.empty()) { auto alias = std::make_shared(desc.column_name); - column_defaults[desc.alias] = {ColumnDefaultType::Alias, alias}; - alias_columns.emplace_back(desc.alias, type); + columns.defaults[desc.alias] = {ColumnDefaultType::Alias, alias}; + columns.aliases.emplace_back(desc.alias, type); } sample_block.insert(ColumnWithTypeAndName(type, desc.column_name)); } - columns.insert(columns.end(), num_columns.begin(), num_columns.end()); - columns.insert(columns.end(), cat_columns.begin(), cat_columns.end()); + columns.ordinary.insert(columns.ordinary.end(), num_columns.begin(), num_columns.end()); + columns.ordinary.insert(columns.ordinary.end(), cat_columns.begin(), cat_columns.end()); } BlockInputStreams StorageCatBoostPool::read(const Names & column_names, diff --git a/dbms/src/Storages/StorageDictionary.cpp b/dbms/src/Storages/StorageDictionary.cpp index 2bb69748c6d..954b8ae898b 100644 --- a/dbms/src/Storages/StorageDictionary.cpp +++ b/dbms/src/Storages/StorageDictionary.cpp @@ -24,13 +24,10 @@ namespace ErrorCodes StorageDictionary::StorageDictionary( const String & table_name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const DictionaryStructure & dictionary_structure_, const String & dictionary_name_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, table_name(table_name_), + : IStorage{columns_}, table_name(table_name_), dictionary_name(dictionary_name_), logger(&Poco::Logger::get("StorageDictionary")) { @@ -75,7 +72,7 @@ void StorageDictionary::checkNamesAndTypesCompatibleWithDictionary(const Diction auto dictionary_names_and_types = getNamesAndTypes(dictionary_structure); std::set namesAndTypesSet(dictionary_names_and_types.begin(), dictionary_names_and_types.end()); - for (auto & column : columns) + for (auto & column : columns.ordinary) { if (namesAndTypesSet.find(column) == namesAndTypesSet.end()) { @@ -105,8 +102,7 @@ void registerStorageDictionary(StorageFactory & factory) const DictionaryStructure & dictionary_structure = dictionary->getStructure(); return StorageDictionary::create( - args.table_name, args.columns, args.materialized_columns, args.alias_columns, - args.column_defaults, dictionary_structure, dictionary_name); + args.table_name, args.columns, dictionary_structure, dictionary_name); }); } diff --git a/dbms/src/Storages/StorageDictionary.h b/dbms/src/Storages/StorageDictionary.h index 0f21373f546..0320a514839 100644 --- a/dbms/src/Storages/StorageDictionary.h +++ b/dbms/src/Storages/StorageDictionary.h @@ -22,7 +22,6 @@ class StorageDictionary : public ext::shared_ptr_helper, publ public: std::string getName() const override { return "Dictionary"; } std::string getTableName() const override { return table_name; } - const NamesAndTypesList & getColumnsListImpl() const override { return columns; } BlockInputStreams read(const Names & column_names, const SelectQueryInfo & query_info, const Context & context, @@ -62,10 +61,7 @@ private: protected: StorageDictionary(const String & table_name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const DictionaryStructure & dictionary_structure_, const String & dictionary_name_); }; diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index c1681e6fbea..1b7c5fdf69a 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -130,24 +130,21 @@ StorageDistributed::~StorageDistributed() = default; StorageDistributed::StorageDistributed( - const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const std::string & table_name_, + const ColumnsDescription & columns_, const String & remote_database_, const String & remote_table_, const String & cluster_name_, const Context & context_, const ASTPtr & sharding_key_, const String & data_path_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, - name(name_), + : IStorage{columns_}, + table_name(table_name_), remote_database(remote_database_), remote_table(remote_table_), context(context_), cluster_name(context.getMacros().expand(cluster_name_)), has_sharding_key(sharding_key_), - sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns).getActions(false) : nullptr), + sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns.ordinary).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), - path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(name) + '/')) + path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(table_name) + '/')) { } @@ -161,7 +158,7 @@ StoragePtr StorageDistributed::createWithOwnCluster( const Context & context_) { auto res = ext::shared_ptr_helper::create( - name_, columns_, NamesAndTypesList(), NamesAndTypesList(), ColumnDefaults(), + name_, ColumnsDescription{columns_, NamesAndTypesList(), NamesAndTypesList(), ColumnDefaults()}, remote_database_, remote_table_, String{}, context_, ASTPtr(), String()); res->owned_cluster = owned_cluster_; @@ -236,11 +233,9 @@ void StorageDistributed::alter(const AlterCommands & params, const String & data throw Exception("Storage engine " + getName() + " doesn't support primary key.", ErrorCodes::NOT_IMPLEMENTED); auto lock = lockStructureForAlter(__PRETTY_FUNCTION__); - params.apply(columns, materialized_columns, alias_columns, column_defaults); + params.apply(columns); - context.getDatabase(database_name)->alterTable( - context, table_name, - columns, materialized_columns, alias_columns, column_defaults, {}); + context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); } @@ -291,13 +286,13 @@ NameAndTypePair StorageDistributed::getColumn(const String & column_name) const if (const auto & type = VirtualColumnFactory::tryGetType(column_name)) return { column_name, type }; - return getRealColumn(column_name); + return columns.get(column_name); } bool StorageDistributed::hasColumn(const String & column_name) const { - return VirtualColumnFactory::hasColumn(column_name) || IStorage::hasColumn(column_name); + return VirtualColumnFactory::hasColumn(column_name) || columns.has(column_name); } void StorageDistributed::createDirectoryMonitors() @@ -390,7 +385,7 @@ void registerStorageDistributed(StorageFactory & factory) /// Check that sharding_key exists in the table and has numeric type. if (sharding_key) { - auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns).getActions(true); + auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.ordinary).getActions(true); const Block & block = sharding_expr->getSampleBlock(); if (block.columns() != 1) @@ -405,7 +400,6 @@ void registerStorageDistributed(StorageFactory & factory) return StorageDistributed::create( args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, remote_database, remote_table, cluster_name, args.context, sharding_key, args.data_path); }); diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 6afb54ba007..22e24c3f9fb 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -34,20 +34,19 @@ public: ~StorageDistributed() override; static StoragePtr createWithOwnCluster( - const std::string & name_, /// The name of the table. - const NamesAndTypesList & columns_, /// List of columns. + const std::string & table_name_, + const NamesAndTypesList & columns_, const String & remote_database_, /// database on remote servers. const String & remote_table_, /// The name of the table on the remote servers. ClusterPtr & owned_cluster_, const Context & context_); std::string getName() const override { return "Distributed"; } - std::string getTableName() const override { return name; } + std::string getTableName() const override { return table_name; } bool supportsSampling() const override { return true; } bool supportsFinal() const override { return true; } bool supportsPrewhere() const override { return true; } - const NamesAndTypesList & getColumnsListImpl() const override { return columns; } NameAndTypePair getColumn(const String & column_name) const override; bool hasColumn(const String & column_name) const override; @@ -64,7 +63,7 @@ public: BlockOutputStreamPtr write(const ASTPtr & query, const Settings & settings) override; void drop() override {} - void rename(const String & /*new_path_to_db*/, const String & /*new_database_name*/, const String & new_table_name) override { name = new_table_name; } + void rename(const String & /*new_path_to_db*/, const String & /*new_database_name*/, const String & new_table_name) override { table_name = new_table_name; } /// in the sub-tables, you need to manually add and delete columns /// the structure of the sub-table is not checked void alter(const AlterCommands & params, const String & database_name, const String & table_name, const Context & context) override; @@ -95,7 +94,7 @@ public: ClusterPtr getCluster() const; - String name; + String table_name; String remote_database; String remote_table; @@ -132,10 +131,7 @@ public: protected: StorageDistributed( const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const String & remote_database_, const String & remote_table_, const String & cluster_name_, diff --git a/dbms/src/Storages/StorageFactory.cpp b/dbms/src/Storages/StorageFactory.cpp index 0bcc7166c1d..1b8970aba24 100644 --- a/dbms/src/Storages/StorageFactory.cpp +++ b/dbms/src/Storages/StorageFactory.cpp @@ -45,10 +45,7 @@ StoragePtr StorageFactory::get( const String & database_name, Context & local_context, Context & context, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, bool attach, bool has_force_restore_data_flag) const { @@ -67,9 +64,9 @@ StoragePtr StorageFactory::get( { /// Check for some special types, that are not allowed to be stored in tables. Example: NULL data type. /// Exception: any type is allowed in View, because plain (non-materialized) View does not store anything itself. - checkAllTypesAreAllowedInTable(columns); - checkAllTypesAreAllowedInTable(materialized_columns); - checkAllTypesAreAllowedInTable(alias_columns); + checkAllTypesAreAllowedInTable(columns.ordinary); + checkAllTypesAreAllowedInTable(columns.materialized); + checkAllTypesAreAllowedInTable(columns.aliases); if (query.is_materialized_view) { @@ -130,9 +127,6 @@ StoragePtr StorageFactory::get( .local_context = local_context, .context = context, .columns = columns, - .materialized_columns = materialized_columns, - .alias_columns = alias_columns, - .column_defaults = column_defaults, .attach = attach, .has_force_restore_data_flag = has_force_restore_data_flag }; diff --git a/dbms/src/Storages/StorageFactory.h b/dbms/src/Storages/StorageFactory.h index 1af131943ba..2acb9fb7c00 100644 --- a/dbms/src/Storages/StorageFactory.h +++ b/dbms/src/Storages/StorageFactory.h @@ -14,7 +14,7 @@ class ASTStorage; /** Allows to create a table by the name and parameters of the engine. - * In 'columns', 'materialized_columns', etc., Nested data structures must be flattened. + * In 'columns' Nested data structures must be flattened. * You should subsequently call IStorage::startup method to work with table. */ class StorageFactory : public ext::singleton @@ -31,10 +31,7 @@ public: const String & database_name; Context & local_context; Context & context; - const NamesAndTypesList & columns; - const NamesAndTypesList & materialized_columns; - const NamesAndTypesList & alias_columns; - const ColumnDefaults & column_defaults; + const ColumnsDescription & columns; bool attach; bool has_force_restore_data_flag; }; @@ -48,10 +45,7 @@ public: const String & database_name, Context & local_context, Context & context, - const NamesAndTypesList & columns, - const NamesAndTypesList & materialized_columns, - const NamesAndTypesList & alias_columns, - const ColumnDefaults & column_defaults, + const ColumnsDescription & columns, bool attach, bool has_force_restore_data_flag) const; diff --git a/dbms/src/Storages/StorageFile.cpp b/dbms/src/Storages/StorageFile.cpp index 78fb3990978..2f606d5cbcf 100644 --- a/dbms/src/Storages/StorageFile.cpp +++ b/dbms/src/Storages/StorageFile.cpp @@ -54,12 +54,9 @@ StorageFile::StorageFile( const std::string & db_dir_path, const std::string & table_name_, const std::string & format_name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, Context & context_) - : IStorage(columns_, materialized_columns_, alias_columns_, column_defaults_), + : IStorage(columns_), table_name(table_name_), format_name(format_name_), context_global(context_), table_fd(table_fd_) { if (table_fd < 0) /// Will use file @@ -311,7 +308,6 @@ void registerStorageFile(StorageFactory & factory) return StorageFile::create( source_path, source_fd, args.data_path, args.table_name, format_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, args.context); }); } diff --git a/dbms/src/Storages/StorageFile.h b/dbms/src/Storages/StorageFile.h index 8501415001c..4292ea6d7f9 100644 --- a/dbms/src/Storages/StorageFile.h +++ b/dbms/src/Storages/StorageFile.h @@ -31,11 +31,6 @@ public: return table_name; } - const NamesAndTypesList & getColumnsListImpl() const override - { - return columns; - } - BlockInputStreams read( const Names & column_names, const SelectQueryInfo & query_info, @@ -61,7 +56,7 @@ protected: /** there are three options (ordered by priority): - use specified file descriptor if (fd >= 0) - use specified table_path if it isn't empty - - create own tabale inside data/db/table/ + - create own table inside data/db/table/ */ StorageFile( const std::string & table_path_, @@ -69,10 +64,7 @@ protected: const std::string & db_dir_path, const std::string & table_name_, const std::string & format_name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, Context & context_); private: diff --git a/dbms/src/Storages/StorageJoin.cpp b/dbms/src/Storages/StorageJoin.cpp index 846c18d7055..c3dfc16c5d7 100644 --- a/dbms/src/Storages/StorageJoin.cpp +++ b/dbms/src/Storages/StorageJoin.cpp @@ -24,24 +24,12 @@ StorageJoin::StorageJoin( const String & name_, const Names & key_names_, ASTTableJoin::Kind kind_, ASTTableJoin::Strictness strictness_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_) - : StorageSetOrJoinBase{path_, name_, columns_, materialized_columns_, alias_columns_, column_defaults_}, + const ColumnsDescription & columns_) + : StorageSetOrJoinBase{path_, name_, columns_}, key_names(key_names_), kind(kind_), strictness(strictness_) { - /// Check that key exists in table definition. - const auto check_key_exists = [] (const NamesAndTypesList & columns, const String & key) - { - for (const auto & column : columns) - if (column.name == key) - return true; - return false; - }; - for (const auto & key : key_names) - if (!check_key_exists(columns, key) && !check_key_exists(materialized_columns, key)) + if (!columns.has(key)) throw Exception{ "Key column (" + key + ") does not exist in table declaration.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE}; @@ -58,7 +46,7 @@ void StorageJoin::assertCompatible(ASTTableJoin::Kind kind_, ASTTableJoin::Stric { /// NOTE Could be more loose. if (!(kind == kind_ && strictness == strictness_)) - throw Exception("Table " + name + " has incompatible type of JOIN.", ErrorCodes::INCOMPATIBLE_TYPE_OF_JOIN); + throw Exception("Table " + table_name + " has incompatible type of JOIN.", ErrorCodes::INCOMPATIBLE_TYPE_OF_JOIN); } @@ -123,7 +111,7 @@ void registerStorageJoin(StorageFactory & factory) return StorageJoin::create( args.data_path, args.table_name, key_names, kind, strictness, - args.columns, args.materialized_columns, args.alias_columns, args.column_defaults); + args.columns); }); } diff --git a/dbms/src/Storages/StorageJoin.h b/dbms/src/Storages/StorageJoin.h index 135236beddb..c005450e772 100644 --- a/dbms/src/Storages/StorageJoin.h +++ b/dbms/src/Storages/StorageJoin.h @@ -47,10 +47,7 @@ protected: const String & name_, const Names & key_names_, ASTTableJoin::Kind kind_, ASTTableJoin::Strictness strictness_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_); + const ColumnsDescription & columns_); }; } diff --git a/dbms/src/Storages/StorageKafka.cpp b/dbms/src/Storages/StorageKafka.cpp index c3b14a468ca..a822fe47a92 100644 --- a/dbms/src/Storages/StorageKafka.cpp +++ b/dbms/src/Storages/StorageKafka.cpp @@ -218,13 +218,10 @@ StorageKafka::StorageKafka( const std::string & table_name_, const std::string & database_name_, Context & context_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const String & brokers_, const String & group_, const Names & topics_, const String & format_name_, const String & schema_name_, size_t num_consumers_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, table_name(table_name_), database_name(database_name_), context(context_), topics(topics_), brokers(brokers_), group(group_), format_name(format_name_), schema_name(schema_name_), num_consumers(num_consumers_), log(&Logger::get("StorageKafka (" + table_name_ + ")")), @@ -591,7 +588,6 @@ void registerStorageKafka(StorageFactory & factory) return StorageKafka::create( args.table_name, args.database_name, args.context, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, brokers, group, topics, format, schema, num_consumers); }); } diff --git a/dbms/src/Storages/StorageKafka.h b/dbms/src/Storages/StorageKafka.h index 39df9c136a1..655b0bfe5e8 100644 --- a/dbms/src/Storages/StorageKafka.h +++ b/dbms/src/Storages/StorageKafka.h @@ -102,10 +102,7 @@ protected: const std::string & table_name_, const std::string & database_name_, Context & context_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const String & brokers_, const String & group_, const Names & topics_, const String & format_name_, const String & schema_name_, size_t num_consumers_); }; diff --git a/dbms/src/Storages/StorageLog.cpp b/dbms/src/Storages/StorageLog.cpp index 711d48621f0..27881d8b8fe 100644 --- a/dbms/src/Storages/StorageLog.cpp +++ b/dbms/src/Storages/StorageLog.cpp @@ -358,12 +358,9 @@ void LogBlockOutputStream::writeMarks(MarksForColumns && marks) StorageLog::StorageLog( const std::string & path_, const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, size_t max_compress_block_size_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, path(path_), name(name_), max_compress_block_size(max_compress_block_size_), file_checker(path + escapeForFileName(name) + '/' + "sizes.json") @@ -374,7 +371,7 @@ StorageLog::StorageLog( /// create files if they do not exist Poco::File(path + escapeForFileName(name) + '/').createDirectories(); - for (const auto & column : getColumnsList()) + for (const auto & column : columns.getList()) addFiles(column.name, *column.type); marks_file = Poco::File(path + escapeForFileName(name) + '/' + DBMS_STORAGE_LOG_MARKS_FILE_NAME); @@ -468,8 +465,8 @@ void StorageLog::rename(const String & new_path_to_db, const String & /*new_data const StorageLog::Marks & StorageLog::getMarksWithRealRowCount() const { - const String & column_name = columns.front().name; - const IDataType & column_type = *columns.front().type; + const String & column_name = columns.ordinary.front().name; + const IDataType & column_type = *columns.ordinary.front().type; String filename; /** We take marks from first column. @@ -502,7 +499,7 @@ BlockInputStreams StorageLog::read( processed_stage = QueryProcessingStage::FetchColumns; loadMarks(); - NamesAndTypesList columns = Nested::collect(getColumnsList().addTypes(column_names)); + NamesAndTypesList all_columns = Nested::collect(columns.getList().addTypes(column_names)); std::shared_lock lock(rwlock); @@ -526,7 +523,7 @@ BlockInputStreams StorageLog::read( res.emplace_back(std::make_shared( max_block_size, - columns, + all_columns, *this, mark_begin, rows_end - rows_begin, @@ -562,7 +559,6 @@ void registerStorageLog(StorageFactory & factory) return StorageLog::create( args.data_path, args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, args.context.getSettings().max_compress_block_size); }); } diff --git a/dbms/src/Storages/StorageLog.h b/dbms/src/Storages/StorageLog.h index 4f38f403138..b52a90ec563 100644 --- a/dbms/src/Storages/StorageLog.h +++ b/dbms/src/Storages/StorageLog.h @@ -52,10 +52,7 @@ protected: StorageLog( const std::string & path_, const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, size_t max_compress_block_size_); private: diff --git a/dbms/src/Storages/StorageMaterializedView.cpp b/dbms/src/Storages/StorageMaterializedView.cpp index 33eec0ad8f7..1146028830b 100644 --- a/dbms/src/Storages/StorageMaterializedView.cpp +++ b/dbms/src/Storages/StorageMaterializedView.cpp @@ -64,12 +64,9 @@ StorageMaterializedView::StorageMaterializedView( const String & database_name_, Context & local_context, const ASTCreateQuery & query, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, table_name(table_name_), + : IStorage{columns_}, table_name(table_name_), database_name(database_name_), global_context(local_context.getGlobalContext()) { if (!query.select) @@ -213,8 +210,7 @@ void registerStorageMaterializedView(StorageFactory & factory) /// Pass local_context here to convey setting for inner table return StorageMaterializedView::create( args.table_name, args.database_name, args.local_context, args.query, - args.columns, args.materialized_columns, args.alias_columns, args.column_defaults, - args.attach); + args.columns, args.attach); }); } diff --git a/dbms/src/Storages/StorageMaterializedView.h b/dbms/src/Storages/StorageMaterializedView.h index 4dd0980e874..82a5b0822b4 100644 --- a/dbms/src/Storages/StorageMaterializedView.h +++ b/dbms/src/Storages/StorageMaterializedView.h @@ -17,7 +17,6 @@ class StorageMaterializedView : public ext::shared_ptr_helperclone(); }; StoragePtr getTargetTable() const; @@ -62,10 +61,7 @@ protected: const String & database_name_, Context & local_context, const ASTCreateQuery & query, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach_); }; diff --git a/dbms/src/Storages/StorageMemory.cpp b/dbms/src/Storages/StorageMemory.cpp index 96af6a9a138..7b36796c324 100644 --- a/dbms/src/Storages/StorageMemory.cpp +++ b/dbms/src/Storages/StorageMemory.cpp @@ -74,14 +74,8 @@ private: }; -StorageMemory::StorageMemory( - const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, - name(name_) +StorageMemory::StorageMemory(String table_name_, ColumnsDescription columns_description_) + : IStorage{std::move(columns_description_)}, table_name(std::move(table_name_)) { } @@ -144,7 +138,7 @@ void registerStorageMemory(StorageFactory & factory) "Engine " + args.engine_name + " doesn't support any arguments (" + toString(args.engine_args.size()) + " given)", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - return StorageMemory::create(args.table_name, args.columns, args.materialized_columns, args.alias_columns, args.column_defaults); + return StorageMemory::create(args.table_name, args.columns); }); } diff --git a/dbms/src/Storages/StorageMemory.h b/dbms/src/Storages/StorageMemory.h index 956e4354727..454fdcc2823 100644 --- a/dbms/src/Storages/StorageMemory.h +++ b/dbms/src/Storages/StorageMemory.h @@ -24,7 +24,7 @@ friend class MemoryBlockOutputStream; public: std::string getName() const override { return "Memory"; } - std::string getTableName() const override { return name; } + std::string getTableName() const override { return table_name; } size_t getSize() const { return data.size(); } @@ -39,10 +39,10 @@ public: BlockOutputStreamPtr write(const ASTPtr & query, const Settings & settings) override; void drop() override; - void rename(const String & /*new_path_to_db*/, const String & /*new_database_name*/, const String & new_table_name) override { name = new_table_name; } + void rename(const String & /*new_path_to_db*/, const String & /*new_database_name*/, const String & new_table_name) override { table_name = new_table_name; } private: - String name; + String table_name; /// The data itself. `list` - so that when inserted to the end, the existing iterators are not invalidated. BlocksList data; @@ -50,12 +50,7 @@ private: std::mutex mutex; protected: - StorageMemory( - const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_); + StorageMemory(String table_name_, ColumnsDescription columns_description_); }; } diff --git a/dbms/src/Storages/StorageMerge.cpp b/dbms/src/Storages/StorageMerge.cpp index 7ceecc62a43..39fed81e538 100644 --- a/dbms/src/Storages/StorageMerge.cpp +++ b/dbms/src/Storages/StorageMerge.cpp @@ -37,14 +37,11 @@ namespace ErrorCodes StorageMerge::StorageMerge( const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const String & source_database_, const String & table_name_regexp_, const Context & context_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, name(name_), source_database(source_database_), table_name_regexp(table_name_regexp_), context(context_) { @@ -184,7 +181,7 @@ BlockInputStreams StorageMerge::read( /// If there are only virtual columns in query, you must request at least one other column. if (real_column_names.size() == 0) - real_column_names.push_back(ExpressionActions::getSmallestColumn(table->getColumnsList())); + real_column_names.push_back(ExpressionActions::getSmallestColumn(table->columns.getList())); /// Substitute virtual column for its value when querying tables. ASTPtr modified_query_ast = query->clone(); @@ -336,11 +333,9 @@ void StorageMerge::alter(const AlterCommands & params, const String & database_n throw Exception("Storage engine " + getName() + " doesn't support primary key.", ErrorCodes::NOT_IMPLEMENTED); auto lock = lockStructureForAlter(__PRETTY_FUNCTION__); - params.apply(columns, materialized_columns, alias_columns, column_defaults); - context.getDatabase(database_name)->alterTable( - context, table_name, - columns, materialized_columns, alias_columns, column_defaults, {}); + params.apply(columns); + context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); } @@ -367,7 +362,6 @@ void registerStorageMerge(StorageFactory & factory) return StorageMerge::create( args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, source_database, table_name_regexp, args.context); }); } diff --git a/dbms/src/Storages/StorageMerge.h b/dbms/src/Storages/StorageMerge.h index 9bef645c0e0..0c37e4e7fb4 100644 --- a/dbms/src/Storages/StorageMerge.h +++ b/dbms/src/Storages/StorageMerge.h @@ -26,7 +26,6 @@ public: bool supportsFinal() const override { return true; } bool supportsIndexForIn() const override { return true; } - const NamesAndTypesList & getColumnsListImpl() const override { return columns; } NameAndTypePair getColumn(const String & column_name) const override; bool hasColumn(const String & column_name) const override; @@ -60,10 +59,7 @@ private: protected: StorageMerge( const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, const String & source_database_, const String & table_name_regexp_, const Context & context_); diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index 8ee9f3c7c5b..71d8013e4db 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -35,10 +35,7 @@ StorageMergeTree::StorageMergeTree( const String & path_, const String & database_name_, const String & table_name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach, Context & context_, const ASTPtr & primary_expr_ast_, @@ -49,12 +46,11 @@ StorageMergeTree::StorageMergeTree( const MergeTreeData::MergingParams & merging_params_, const MergeTreeSettings & settings_, bool has_force_restore_data_flag) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, path(path_), database_name(database_name_), table_name(table_name_), full_path(path + escapeForFileName(table_name) + '/'), context(context_), background_pool(context_.getBackgroundPool()), data(database_name, table_name, full_path, columns_, - materialized_columns_, alias_columns_, column_defaults_, context_, primary_expr_ast_, secondary_sorting_expr_list_, date_column_name, partition_expr_ast_, sampling_expression_, merging_params_, settings_, false, attach), @@ -157,16 +153,9 @@ void StorageMergeTree::alter( data.checkAlter(params); - auto new_columns = data.getColumnsListNonMaterialized(); - auto new_materialized_columns = data.materialized_columns; - auto new_alias_columns = data.alias_columns; - auto new_column_defaults = data.column_defaults; + auto new_columns = data.columns; - params.apply(new_columns, new_materialized_columns, new_alias_columns, new_column_defaults); - - auto columns_for_parts = new_columns; - columns_for_parts.insert(std::end(columns_for_parts), - std::begin(new_materialized_columns), std::end(new_materialized_columns)); + params.apply(new_columns); std::vector transactions; @@ -187,6 +176,7 @@ void StorageMergeTree::alter( throw Exception("MODIFY PRIMARY KEY only supported for tables without sampling key", ErrorCodes::BAD_ARGUMENTS); auto parts = data.getDataParts({MergeTreeDataPartState::PreCommitted, MergeTreeDataPartState::Committed, MergeTreeDataPartState::Outdated}); + auto columns_for_parts = new_columns.getList(); for (const MergeTreeData::DataPartPtr & part : parts) { if (auto transaction = data.alterDataPart(part, columns_for_parts, new_primary_key_ast, false)) @@ -212,19 +202,10 @@ void StorageMergeTree::alter( }; } - context.getDatabase(database_name)->alterTable( - context, table_name, - new_columns, new_materialized_columns, new_alias_columns, new_column_defaults, - storage_modifier); + context.getDatabase(database_name)->alterTable(context, table_name, new_columns, storage_modifier); - materialized_columns = new_materialized_columns; - alias_columns = new_alias_columns; - column_defaults = new_column_defaults; - - data.setColumnsList(new_columns); - data.materialized_columns = std::move(new_materialized_columns); - data.alias_columns = std::move(new_alias_columns); - data.column_defaults = std::move(new_column_defaults); + columns = new_columns; + data.columns = std::move(new_columns); if (primary_key_is_modified) { @@ -438,17 +419,10 @@ void StorageMergeTree::clearColumnInPartition(const ASTPtr & partition, const Fi alter_command.type = AlterCommand::DROP_COLUMN; alter_command.column_name = get(column_name); - auto new_columns = data.getColumnsListNonMaterialized(); - auto new_materialized_columns = data.materialized_columns; - auto new_alias_columns = data.alias_columns; - auto new_column_defaults = data.column_defaults; - - alter_command.apply(new_columns, new_materialized_columns, new_alias_columns, new_column_defaults); - - auto columns_for_parts = new_columns; - columns_for_parts.insert(std::end(columns_for_parts), - std::begin(new_materialized_columns), std::end(new_materialized_columns)); + auto new_columns = data.columns; + alter_command.apply(new_columns); + auto columns_for_parts = new_columns.getList(); for (const auto & part : parts) { if (part->info.partition_id != partition_id) diff --git a/dbms/src/Storages/StorageMergeTree.h b/dbms/src/Storages/StorageMergeTree.h index e1121ec84d0..e2ad6177a82 100644 --- a/dbms/src/Storages/StorageMergeTree.h +++ b/dbms/src/Storages/StorageMergeTree.h @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -35,8 +36,6 @@ public: bool supportsFinal() const override { return data.supportsFinal(); } bool supportsPrewhere() const override { return data.supportsPrewhere(); } - const NamesAndTypesList & getColumnsListImpl() const override { return data.getColumnsListNonMaterialized(); } - NameAndTypePair getColumn(const String & column_name) const override { return data.getColumn(column_name); @@ -135,10 +134,7 @@ protected: const String & path_, const String & database_name_, const String & table_name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach, Context & context_, const ASTPtr & primary_expr_ast_, diff --git a/dbms/src/Storages/StorageMySQL.cpp b/dbms/src/Storages/StorageMySQL.cpp index f3f18518d83..28a367f17e0 100644 --- a/dbms/src/Storages/StorageMySQL.cpp +++ b/dbms/src/Storages/StorageMySQL.cpp @@ -23,8 +23,8 @@ StorageMySQL::StorageMySQL( mysqlxx::Pool && pool, const std::string & remote_database_name, const std::string & remote_table_name, - const NamesAndTypesList & columns_) - : IStorage{columns_, {}, {}, {}} + const ColumnsDescription & columns_) + : IStorage{columns_} , name(name) , remote_database_name(remote_database_name) , remote_table_name(remote_table_name) @@ -43,7 +43,7 @@ BlockInputStreams StorageMySQL::read( { check(column_names); processed_stage = QueryProcessingStage::FetchColumns; - String query = transformQueryForExternalDatabase(*query_info.query, columns, remote_database_name, remote_table_name, context); + String query = transformQueryForExternalDatabase(*query_info.query, columns.ordinary, remote_database_name, remote_table_name, context); Block sample_block; for (const String & name : column_names) diff --git a/dbms/src/Storages/StorageMySQL.h b/dbms/src/Storages/StorageMySQL.h index 9558605ff0e..9e2b233283e 100644 --- a/dbms/src/Storages/StorageMySQL.h +++ b/dbms/src/Storages/StorageMySQL.h @@ -24,7 +24,7 @@ public: mysqlxx::Pool && pool, const std::string & remote_database_name, const std::string & remote_table_name, - const NamesAndTypesList & columns_); + const ColumnsDescription & columns); std::string getName() const override { return "MySQL"; } std::string getTableName() const override { return name; } diff --git a/dbms/src/Storages/StorageNull.cpp b/dbms/src/Storages/StorageNull.cpp index 0cee00aa1b8..13232068ca9 100644 --- a/dbms/src/Storages/StorageNull.cpp +++ b/dbms/src/Storages/StorageNull.cpp @@ -25,8 +25,7 @@ void registerStorageNull(StorageFactory & factory) "Engine " + args.engine_name + " doesn't support any arguments (" + toString(args.engine_args.size()) + " given)", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - return StorageNull::create(args.table_name, - args.columns, args.materialized_columns, args.alias_columns, args.column_defaults); + return StorageNull::create(args.table_name, args.columns); }); } @@ -34,11 +33,9 @@ void StorageNull::alter(const AlterCommands & params, const String & database_na { auto lock = lockStructureForAlter(__PRETTY_FUNCTION__); - params.apply(columns, materialized_columns, alias_columns, column_defaults); + params.apply(columns); - context.getDatabase(database_name)->alterTable( - context, table_name, - columns, materialized_columns, alias_columns, column_defaults, {}); + context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); } } diff --git a/dbms/src/Storages/StorageNull.h b/dbms/src/Storages/StorageNull.h index ef3f0f6fcd1..cdde480a951 100644 --- a/dbms/src/Storages/StorageNull.h +++ b/dbms/src/Storages/StorageNull.h @@ -18,7 +18,7 @@ class StorageNull : public ext::shared_ptr_helper, public IStorage { public: std::string getName() const override { return "Null"; } - std::string getTableName() const override { return name; } + std::string getTableName() const override { return table_name; } BlockInputStreams read( const Names & column_names, @@ -38,22 +38,19 @@ public: void rename(const String & /*new_path_to_db*/, const String & /*new_database_name*/, const String & new_table_name) override { - name = new_table_name; + table_name = new_table_name; } void alter(const AlterCommands & params, const String & database_name, const String & table_name, const Context & context) override; private: - String name; + String table_name; protected: - StorageNull( - const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, name(name_) {} + StorageNull(String table_name_, ColumnsDescription columns_description_) + : IStorage{std::move(columns_description_)}, table_name(std::move(table_name_)) + { + } }; } diff --git a/dbms/src/Storages/StorageODBC.cpp b/dbms/src/Storages/StorageODBC.cpp index 67362bf2f90..7856ee9a231 100644 --- a/dbms/src/Storages/StorageODBC.cpp +++ b/dbms/src/Storages/StorageODBC.cpp @@ -21,8 +21,8 @@ StorageODBC::StorageODBC( const std::string & connection_string, const std::string & remote_database_name, const std::string & remote_table_name, - const NamesAndTypesList & columns_) - : IStorage{columns_, {}, {}, {}} + const ColumnsDescription & columns_) + : IStorage{columns_} , name(name) , remote_database_name(remote_database_name) , remote_table_name(remote_table_name) @@ -43,7 +43,7 @@ BlockInputStreams StorageODBC::read( { check(column_names); processed_stage = QueryProcessingStage::FetchColumns; - String query = transformQueryForExternalDatabase(*query_info.query, columns, remote_database_name, remote_table_name, context); + String query = transformQueryForExternalDatabase(*query_info.query, columns.ordinary, remote_database_name, remote_table_name, context); Block sample_block; for (const String & name : column_names) diff --git a/dbms/src/Storages/StorageODBC.h b/dbms/src/Storages/StorageODBC.h index f582c74a263..5632fe38282 100644 --- a/dbms/src/Storages/StorageODBC.h +++ b/dbms/src/Storages/StorageODBC.h @@ -30,7 +30,7 @@ public: const std::string & connection_string, const std::string & remote_database_name, const std::string & remote_table_name, - const NamesAndTypesList & columns_); + const ColumnsDescription & columns_); std::string getName() const override { return "ODBC"; } std::string getTableName() const override { return name; } diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index 9917b7e7a94..9f6553f6512 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -174,10 +174,7 @@ StorageReplicatedMergeTree::StorageReplicatedMergeTree( const String & replica_name_, bool attach, const String & path_, const String & database_name_, const String & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, Context & context_, const ASTPtr & primary_expr_ast_, const ASTPtr & secondary_sorting_expr_list_, @@ -187,14 +184,13 @@ StorageReplicatedMergeTree::StorageReplicatedMergeTree( const MergeTreeData::MergingParams & merging_params_, const MergeTreeSettings & settings_, bool has_force_restore_data_flag) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, context(context_), + : IStorage{columns_}, context(context_), current_zookeeper(context.getZooKeeper()), database_name(database_name_), table_name(name_), full_path(path_ + escapeForFileName(table_name) + '/'), zookeeper_path(context.getMacros().expand(zookeeper_path_)), replica_name(context.getMacros().expand(replica_name_)), data(database_name, table_name, full_path, columns_, - materialized_columns_, alias_columns_, column_defaults_, context_, primary_expr_ast_, secondary_sorting_expr_list_, date_column_name, partition_expr_ast_, sampling_expression_, merging_params_, settings_, true, attach, @@ -488,9 +484,7 @@ void StorageReplicatedMergeTree::createTableIfNotExists() acl, zkutil::CreateMode::Persistent)); ops.emplace_back(std::make_unique(zookeeper_path + "/metadata", metadata, acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/columns", ColumnsDescription{ - data.getColumnsListNonMaterialized(), data.materialized_columns, - data.alias_columns, data.column_defaults}.toString(), + ops.emplace_back(std::make_unique(zookeeper_path + "/columns", data.columns.toString(), acl, zkutil::CreateMode::Persistent)); ops.emplace_back(std::make_unique(zookeeper_path + "/log", "", acl, zkutil::CreateMode::Persistent)); @@ -524,39 +518,28 @@ void StorageReplicatedMergeTree::checkTableStructure(bool skip_sanity_checks, bo TableMetadata(data).check(metadata_str); zkutil::Stat stat; - auto columns_desc = ColumnsDescription::parse(zookeeper->get(zookeeper_path + "/columns", &stat)); + auto columns_from_zk = ColumnsDescription::parse(zookeeper->get(zookeeper_path + "/columns", &stat)); - auto & columns = columns_desc.columns; - auto & materialized_columns = columns_desc.materialized; - auto & alias_columns = columns_desc.alias; - auto & column_defaults = columns_desc.defaults; columns_version = stat.version; - if (columns != data.getColumnsListNonMaterialized() || - materialized_columns != data.materialized_columns || - alias_columns != data.alias_columns || - column_defaults != data.column_defaults) + if (columns_from_zk != data.columns) { if (allow_alter && (skip_sanity_checks || - data.getColumnsListNonMaterialized().sizeOfDifference(columns) + - data.materialized_columns.sizeOfDifference(materialized_columns) <= 2)) + data.columns.ordinary.sizeOfDifference(columns_from_zk.ordinary) + + data.columns.materialized.sizeOfDifference(columns_from_zk.materialized) <= 2)) { LOG_WARNING(log, "Table structure in ZooKeeper is a little different from local table structure. Assuming ALTER."); /// Without any locks, because table has not been created yet. - context.getDatabase(database_name)->alterTable( - context, table_name, - columns, materialized_columns, alias_columns, column_defaults, {}); + context.getDatabase(database_name)->alterTable(context, table_name, columns_from_zk, {}); - data.setColumnsList(columns); - data.materialized_columns = std::move(materialized_columns); - data.alias_columns = std::move(alias_columns); - data.column_defaults = std::move(column_defaults); + columns = columns_from_zk; + data.columns = std::move(columns_from_zk); } else { - throw Exception("Table structure in ZooKeeper is too much different from local table structure.", + throw Exception("Table structure in ZooKeeper is too different from local table structure", ErrorCodes::INCOMPATIBLE_COLUMNS); } } @@ -714,12 +697,7 @@ void StorageReplicatedMergeTree::createReplica() LOG_DEBUG(log, "Copied " << source_queue.size() << " queue entries"); } - zookeeper->create(replica_path + "/columns", ColumnsDescription{ - data.getColumnsListNonMaterialized(), - data.materialized_columns, - data.alias_columns, - data.column_defaults - }.toString(), zkutil::CreateMode::Persistent); + zookeeper->create(replica_path + "/columns", data.columns.toString(), zkutil::CreateMode::Persistent); } @@ -1529,19 +1507,12 @@ void StorageReplicatedMergeTree::executeClearColumnInPartition(const LogEntry & alter_command.type = AlterCommand::DROP_COLUMN; alter_command.column_name = entry.column_name; - auto new_columns = data.getColumnsListNonMaterialized(); - auto new_materialized_columns = data.materialized_columns; - auto new_alias_columns = data.alias_columns; - auto new_column_defaults = data.column_defaults; - - alter_command.apply(new_columns, new_materialized_columns, new_alias_columns, new_column_defaults); - - auto columns_for_parts = new_columns; - columns_for_parts.insert(std::end(columns_for_parts), - std::begin(new_materialized_columns), std::end(new_materialized_columns)); + auto new_columns = data.columns; + alter_command.apply(new_columns); size_t modified_parts = 0; auto parts = data.getDataParts(); + auto columns_for_parts = new_columns.getList(); for (const auto & part : parts) { if (!entry_part_info.contains(part->info)) @@ -2573,15 +2544,10 @@ void StorageReplicatedMergeTree::alter(const AlterCommands & params, if (param.type == AlterCommand::MODIFY_PRIMARY_KEY) throw Exception("Modification of primary key is not supported for replicated tables", ErrorCodes::NOT_IMPLEMENTED); - NamesAndTypesList new_columns = data.getColumnsListNonMaterialized(); - NamesAndTypesList new_materialized_columns = data.materialized_columns; - NamesAndTypesList new_alias_columns = data.alias_columns; - ColumnDefaults new_column_defaults = data.column_defaults; - params.apply(new_columns, new_materialized_columns, new_alias_columns, new_column_defaults); + ColumnsDescription new_columns = data.columns; + params.apply(new_columns); - new_columns_str = ColumnsDescription{ - new_columns, new_materialized_columns, - new_alias_columns, new_column_defaults}.toString(); + new_columns_str = new_columns.toString(); /// Do ALTER. getZooKeeper()->set(zookeeper_path + "/columns", new_columns_str, -1, &stat); diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.h b/dbms/src/Storages/StorageReplicatedMergeTree.h index b1cbf630b1b..468f097534d 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.h +++ b/dbms/src/Storages/StorageReplicatedMergeTree.h @@ -84,8 +84,6 @@ public: bool supportsPrewhere() const override { return data.supportsPrewhere(); } bool supportsReplication() const override { return true; } - const NamesAndTypesList & getColumnsListImpl() const override { return data.getColumnsListNonMaterialized(); } - NameAndTypePair getColumn(const String & column_name) const override { return data.getColumn(column_name); @@ -443,10 +441,7 @@ protected: const String & replica_name_, bool attach, const String & path_, const String & database_name_, const String & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, Context & context_, const ASTPtr & primary_expr_ast_, const ASTPtr & secondary_sorting_expr_list_, diff --git a/dbms/src/Storages/StorageSet.cpp b/dbms/src/Storages/StorageSet.cpp index 1303aa6271f..5ba5d737435 100644 --- a/dbms/src/Storages/StorageSet.cpp +++ b/dbms/src/Storages/StorageSet.cpp @@ -88,18 +88,14 @@ BlockOutputStreamPtr StorageSetOrJoinBase::write(const ASTPtr & /*query*/, const StorageSetOrJoinBase::StorageSetOrJoinBase( const String & path_, - const String & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, - name(name_) + const String & table_name_, + const ColumnsDescription & columns_) + : IStorage{columns_}, table_name(table_name_) { if (path_.empty()) throw Exception("Join and Set storages require data path", ErrorCodes::INCORRECT_FILE_NAME); - path = path_ + escapeForFileName(name_) + '/'; + path = path_ + escapeForFileName(table_name_) + '/'; } @@ -107,11 +103,8 @@ StorageSetOrJoinBase::StorageSetOrJoinBase( StorageSet::StorageSet( const String & path_, const String & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_) - : StorageSetOrJoinBase{path_, name_, columns_, materialized_columns_, alias_columns_, column_defaults_}, + const ColumnsDescription & columns_) + : StorageSetOrJoinBase{path_, name_, columns_}, set(std::make_shared(SizeLimits())) { restore(); @@ -181,7 +174,7 @@ void StorageSetOrJoinBase::rename(const String & new_path_to_db, const String & Poco::File(path).renameTo(new_path); path = new_path + "/"; - name = new_table_name; + table_name = new_table_name; } @@ -194,9 +187,7 @@ void registerStorageSet(StorageFactory & factory) "Engine " + args.engine_name + " doesn't support any arguments (" + toString(args.engine_args.size()) + " given)", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - return StorageSet::create( - args.data_path, args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults); + return StorageSet::create(args.data_path, args.table_name, args.columns); }); } diff --git a/dbms/src/Storages/StorageSet.h b/dbms/src/Storages/StorageSet.h index 2546967b24a..d1e4ae89226 100644 --- a/dbms/src/Storages/StorageSet.h +++ b/dbms/src/Storages/StorageSet.h @@ -19,7 +19,7 @@ class StorageSetOrJoinBase : public IStorage friend class SetOrJoinBlockOutputStream; public: - String getTableName() const override { return name; } + String getTableName() const override { return table_name; } void rename(const String & new_path_to_db, const String & new_database_name, const String & new_table_name) override; @@ -30,14 +30,11 @@ public: protected: StorageSetOrJoinBase( const String & path_, - const String & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_); + const String & table_name_, + const ColumnsDescription & columns_); String path; - String name; + String table_name; UInt64 increment = 0; /// For the backup file names. @@ -78,10 +75,7 @@ protected: StorageSet( const String & path_, const String & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_); + const ColumnsDescription & columns_); }; } diff --git a/dbms/src/Storages/StorageStripeLog.cpp b/dbms/src/Storages/StorageStripeLog.cpp index 5f746dc246c..1bebca62322 100644 --- a/dbms/src/Storages/StorageStripeLog.cpp +++ b/dbms/src/Storages/StorageStripeLog.cpp @@ -193,13 +193,10 @@ private: StorageStripeLog::StorageStripeLog( const std::string & path_, const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach, size_t max_compress_block_size_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, path(path_), name(name_), max_compress_block_size(max_compress_block_size_), file_checker(path + escapeForFileName(name) + '/' + "sizes.json"), @@ -301,7 +298,6 @@ void registerStorageStripeLog(StorageFactory & factory) return StorageStripeLog::create( args.data_path, args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, args.attach, args.context.getSettings().max_compress_block_size); }); } diff --git a/dbms/src/Storages/StorageStripeLog.h b/dbms/src/Storages/StorageStripeLog.h index e1514f8329f..115f070f8d0 100644 --- a/dbms/src/Storages/StorageStripeLog.h +++ b/dbms/src/Storages/StorageStripeLog.h @@ -68,10 +68,7 @@ protected: StorageStripeLog( const std::string & path_, const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach, size_t max_compress_block_size_); }; diff --git a/dbms/src/Storages/StorageTinyLog.cpp b/dbms/src/Storages/StorageTinyLog.cpp index 4ed7d6dfff2..039f470c366 100644 --- a/dbms/src/Storages/StorageTinyLog.cpp +++ b/dbms/src/Storages/StorageTinyLog.cpp @@ -276,13 +276,10 @@ void TinyLogBlockOutputStream::write(const Block & block) StorageTinyLog::StorageTinyLog( const std::string & path_, const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach, size_t max_compress_block_size_) - : IStorage{columns_, materialized_columns_, alias_columns_, column_defaults_}, + : IStorage{columns_}, path(path_), name(name_), max_compress_block_size(max_compress_block_size_), file_checker(path + escapeForFileName(name) + '/' + "sizes.json"), @@ -299,7 +296,7 @@ StorageTinyLog::StorageTinyLog( throwFromErrno("Cannot create directory " + full_path, ErrorCodes::CANNOT_CREATE_DIRECTORY); } - for (const auto & col : getColumnsList()) + for (const auto & col : columns.getList()) addFiles(col.name, *col.type); } @@ -351,7 +348,7 @@ BlockInputStreams StorageTinyLog::read( check(column_names); processed_stage = QueryProcessingStage::FetchColumns; return BlockInputStreams(1, std::make_shared( - max_block_size, Nested::collect(getColumnsList().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); + max_block_size, Nested::collect(columns.getList().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); } @@ -379,7 +376,6 @@ void registerStorageTinyLog(StorageFactory & factory) return StorageTinyLog::create( args.data_path, args.table_name, args.columns, - args.materialized_columns, args.alias_columns, args.column_defaults, args.attach, args.context.getSettings().max_compress_block_size); }); } diff --git a/dbms/src/Storages/StorageTinyLog.h b/dbms/src/Storages/StorageTinyLog.h index e64301227ad..acaf7944f30 100644 --- a/dbms/src/Storages/StorageTinyLog.h +++ b/dbms/src/Storages/StorageTinyLog.h @@ -71,10 +71,7 @@ protected: StorageTinyLog( const std::string & path_, const std::string & name_, - const NamesAndTypesList & columns_, - const NamesAndTypesList & materialized_columns_, - const NamesAndTypesList & alias_columns_, - const ColumnDefaults & column_defaults_, + const ColumnsDescription & columns_, bool attach, size_t max_compress_block_size_); }; diff --git a/dbms/src/Storages/StorageView.cpp b/dbms/src/Storages/StorageView.cpp index 76cd481a855..06809ffb4e3 100644 --- a/dbms/src/Storages/StorageView.cpp +++ b/dbms/src/Storages/StorageView.cpp @@ -19,8 +19,8 @@ namespace ErrorCodes StorageView::StorageView( const String & table_name_, const ASTCreateQuery & query, - const NamesAndTypesList & columns_) - : IStorage{columns_, {}, {}, {}}, table_name(table_name_) + const ColumnsDescription & columns_) + : IStorage{columns_}, table_name(table_name_) { if (!query.select) throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY); diff --git a/dbms/src/Storages/StorageView.h b/dbms/src/Storages/StorageView.h index 6a16e0d16e6..20a8f76189c 100644 --- a/dbms/src/Storages/StorageView.h +++ b/dbms/src/Storages/StorageView.h @@ -42,7 +42,7 @@ protected: StorageView( const String & table_name_, const ASTCreateQuery & query, - const NamesAndTypesList & columns_); + const ColumnsDescription & columns_); }; } diff --git a/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp b/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp index 44f8d933c99..f08808f799a 100644 --- a/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp +++ b/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp @@ -16,7 +16,7 @@ StorageSystemAsynchronousMetrics::StorageSystemAsynchronousMetrics(const std::st : name(name_), async_metrics(async_metrics_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ {"metric", std::make_shared()}, {"value", std::make_shared()}, }; diff --git a/dbms/src/Storages/System/StorageSystemBuildOptions.cpp b/dbms/src/Storages/System/StorageSystemBuildOptions.cpp index c8da9f12c40..7a864090e59 100644 --- a/dbms/src/Storages/System/StorageSystemBuildOptions.cpp +++ b/dbms/src/Storages/System/StorageSystemBuildOptions.cpp @@ -13,7 +13,7 @@ namespace DB StorageSystemBuildOptions::StorageSystemBuildOptions(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "name", std::make_shared() }, { "value", std::make_shared() }, }; diff --git a/dbms/src/Storages/System/StorageSystemClusters.cpp b/dbms/src/Storages/System/StorageSystemClusters.cpp index 084f295de74..8d772e5ebb8 100644 --- a/dbms/src/Storages/System/StorageSystemClusters.cpp +++ b/dbms/src/Storages/System/StorageSystemClusters.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemClusters::StorageSystemClusters(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "cluster", std::make_shared() }, { "shard_num", std::make_shared() }, { "shard_weight", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemColumns.cpp b/dbms/src/Storages/System/StorageSystemColumns.cpp index 5f9116b08a5..adec6a70c58 100644 --- a/dbms/src/Storages/System/StorageSystemColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemColumns.cpp @@ -18,7 +18,7 @@ namespace DB StorageSystemColumns::StorageSystemColumns(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "database", std::make_shared() }, { "table", std::make_shared() }, { "name", std::make_shared() }, @@ -137,9 +137,9 @@ BlockInputStreams StorageSystemColumns::read( throw; } - columns = storage->getColumnsList(); - columns.insert(std::end(columns), std::begin(storage->alias_columns), std::end(storage->alias_columns)); - column_defaults = storage->column_defaults; + columns = storage->columns.getList(); + columns.insert(std::end(columns), std::begin(storage->columns.aliases), std::end(storage->columns.aliases)); + column_defaults = storage->columns.defaults; /** Info about sizes of columns for tables of MergeTree family. * NOTE: It is possible to add getter for this info to IStorage interface. diff --git a/dbms/src/Storages/System/StorageSystemDatabases.cpp b/dbms/src/Storages/System/StorageSystemDatabases.cpp index 93917b81000..12c35c7ec9e 100644 --- a/dbms/src/Storages/System/StorageSystemDatabases.cpp +++ b/dbms/src/Storages/System/StorageSystemDatabases.cpp @@ -13,7 +13,7 @@ namespace DB StorageSystemDatabases::StorageSystemDatabases(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ {"name", std::make_shared()}, {"engine", std::make_shared()}, {"data_path", std::make_shared()}, diff --git a/dbms/src/Storages/System/StorageSystemDictionaries.cpp b/dbms/src/Storages/System/StorageSystemDictionaries.cpp index 93c742ef1a7..3cb4bd7962b 100644 --- a/dbms/src/Storages/System/StorageSystemDictionaries.cpp +++ b/dbms/src/Storages/System/StorageSystemDictionaries.cpp @@ -21,7 +21,7 @@ namespace DB StorageSystemDictionaries::StorageSystemDictionaries(const std::string & name) : name{name} { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "name", std::make_shared() }, { "origin", std::make_shared() }, { "type", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemEvents.cpp b/dbms/src/Storages/System/StorageSystemEvents.cpp index 96a02d72332..0838eb739a5 100644 --- a/dbms/src/Storages/System/StorageSystemEvents.cpp +++ b/dbms/src/Storages/System/StorageSystemEvents.cpp @@ -13,7 +13,7 @@ namespace DB StorageSystemEvents::StorageSystemEvents(const std::string & name_) : name(name_) { - columns = NamesAndTypesList + columns.ordinary = NamesAndTypesList { {"event", std::make_shared()}, {"value", std::make_shared()} diff --git a/dbms/src/Storages/System/StorageSystemFunctions.cpp b/dbms/src/Storages/System/StorageSystemFunctions.cpp index 74e58338d40..4d013eb2268 100644 --- a/dbms/src/Storages/System/StorageSystemFunctions.cpp +++ b/dbms/src/Storages/System/StorageSystemFunctions.cpp @@ -16,7 +16,7 @@ namespace DB StorageSystemFunctions::StorageSystemFunctions(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "name", std::make_shared() }, { "is_aggregate", std::make_shared() } }; diff --git a/dbms/src/Storages/System/StorageSystemGraphite.cpp b/dbms/src/Storages/System/StorageSystemGraphite.cpp index 76f3defe885..e99c037ea78 100644 --- a/dbms/src/Storages/System/StorageSystemGraphite.cpp +++ b/dbms/src/Storages/System/StorageSystemGraphite.cpp @@ -125,7 +125,7 @@ static Strings getAllGraphiteSections(const AbstractConfiguration & config) StorageSystemGraphite::StorageSystemGraphite(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ {"config_name", std::make_shared()}, {"regexp", std::make_shared()}, {"function", std::make_shared()}, diff --git a/dbms/src/Storages/System/StorageSystemMerges.cpp b/dbms/src/Storages/System/StorageSystemMerges.cpp index f6667c19908..fea37df35a1 100644 --- a/dbms/src/Storages/System/StorageSystemMerges.cpp +++ b/dbms/src/Storages/System/StorageSystemMerges.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemMerges::StorageSystemMerges(const std::string & name) : name{name} { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "database", std::make_shared() }, { "table", std::make_shared() }, { "elapsed", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemMetrics.cpp b/dbms/src/Storages/System/StorageSystemMetrics.cpp index c60d7f4b4f5..54002318ef6 100644 --- a/dbms/src/Storages/System/StorageSystemMetrics.cpp +++ b/dbms/src/Storages/System/StorageSystemMetrics.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemMetrics::StorageSystemMetrics(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ {"metric", std::make_shared()}, {"value", std::make_shared()}, }; diff --git a/dbms/src/Storages/System/StorageSystemModels.cpp b/dbms/src/Storages/System/StorageSystemModels.cpp index da0249b1705..9057c6de626 100644 --- a/dbms/src/Storages/System/StorageSystemModels.cpp +++ b/dbms/src/Storages/System/StorageSystemModels.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemModels::StorageSystemModels(const std::string & name) : name{name} { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "name", std::make_shared() }, { "origin", std::make_shared() }, { "type", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemNumbers.cpp b/dbms/src/Storages/System/StorageSystemNumbers.cpp index 30586bbbba3..803f651639d 100644 --- a/dbms/src/Storages/System/StorageSystemNumbers.cpp +++ b/dbms/src/Storages/System/StorageSystemNumbers.cpp @@ -47,7 +47,7 @@ private: StorageSystemNumbers::StorageSystemNumbers(const std::string & name_, bool multithreaded_, size_t limit_) : name(name_), multithreaded(multithreaded_), limit(limit_) { - columns = NamesAndTypesList{{"number", std::make_shared()}}; + columns.ordinary = NamesAndTypesList{{"number", std::make_shared()}}; } diff --git a/dbms/src/Storages/System/StorageSystemOne.cpp b/dbms/src/Storages/System/StorageSystemOne.cpp index 4ddc64031e3..f35580c3882 100644 --- a/dbms/src/Storages/System/StorageSystemOne.cpp +++ b/dbms/src/Storages/System/StorageSystemOne.cpp @@ -13,7 +13,7 @@ namespace DB StorageSystemOne::StorageSystemOne(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{{"dummy", std::make_shared()}}; + columns.ordinary = NamesAndTypesList{{"dummy", std::make_shared()}}; } diff --git a/dbms/src/Storages/System/StorageSystemPartsBase.cpp b/dbms/src/Storages/System/StorageSystemPartsBase.cpp index f1f99c312f4..c6dc2a2c551 100644 --- a/dbms/src/Storages/System/StorageSystemPartsBase.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsBase.cpp @@ -245,20 +245,20 @@ BlockInputStreams StorageSystemPartsBase::read( /// Create the result. - MutableColumns columns = getSampleBlock().cloneEmptyColumns(); + MutableColumns res_columns = getSampleBlock().cloneEmptyColumns(); if (has_state_column) - columns.push_back(ColumnString::create()); + res_columns.push_back(ColumnString::create()); while (StoragesInfo info = stream.next()) { - processNextStorage(columns, info, has_state_column); + processNextStorage(res_columns, info, has_state_column); } Block block = getSampleBlock(); if (has_state_column) block.insert(ColumnWithTypeAndName(std::make_shared(), "_state")); - return BlockInputStreams(1, std::make_shared(block.cloneWithColumns(std::move(columns)))); + return BlockInputStreams(1, std::make_shared(block.cloneWithColumns(std::move(res_columns)))); } NameAndTypePair StorageSystemPartsBase::getColumn(const String & column_name) const @@ -280,7 +280,7 @@ bool StorageSystemPartsBase::hasColumn(const String & column_name) const StorageSystemPartsBase::StorageSystemPartsBase(std::string name_, NamesAndTypesList && columns_) : name(std::move(name_)) { - columns = columns_; + columns.ordinary = columns_; } } diff --git a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp index 9667399c534..5f0a584c1d6 100644 --- a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp @@ -61,9 +61,9 @@ void StorageSystemPartsColumns::processNextStorage(MutableColumns & columns, con String default_expression; }; - NamesAndTypesList columns_list = info.storage->getColumnsList(); - columns_list.insert(std::end(columns_list), std::begin(info.storage->alias_columns), std::end(info.storage->alias_columns)); - const auto & column_defaults = info.storage->column_defaults; + NamesAndTypesList columns_list = info.storage->columns.getList(); + columns_list.insert(std::end(columns_list), std::begin(info.storage->columns.aliases), std::end(info.storage->columns.aliases)); + const auto & column_defaults = info.storage->columns.defaults; std::unordered_map columns_info; for (const auto & column : columns_list) diff --git a/dbms/src/Storages/System/StorageSystemProcesses.cpp b/dbms/src/Storages/System/StorageSystemProcesses.cpp index 55f3bb120db..e8262723d89 100644 --- a/dbms/src/Storages/System/StorageSystemProcesses.cpp +++ b/dbms/src/Storages/System/StorageSystemProcesses.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemProcesses::StorageSystemProcesses(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "is_initial_query", std::make_shared() }, { "user", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemReplicas.cpp b/dbms/src/Storages/System/StorageSystemReplicas.cpp index 6dc11214b7c..ca240a80568 100644 --- a/dbms/src/Storages/System/StorageSystemReplicas.cpp +++ b/dbms/src/Storages/System/StorageSystemReplicas.cpp @@ -17,7 +17,7 @@ namespace DB StorageSystemReplicas::StorageSystemReplicas(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "database", std::make_shared() }, { "table", std::make_shared() }, { "engine", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp b/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp index a2432525044..363306437bb 100644 --- a/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp +++ b/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp @@ -20,7 +20,7 @@ namespace DB StorageSystemReplicationQueue::StorageSystemReplicationQueue(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ /// Table properties. { "database", std::make_shared() }, { "table", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemSettings.cpp b/dbms/src/Storages/System/StorageSystemSettings.cpp index 6099883eeb6..3848583688b 100644 --- a/dbms/src/Storages/System/StorageSystemSettings.cpp +++ b/dbms/src/Storages/System/StorageSystemSettings.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemSettings::StorageSystemSettings(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "name", std::make_shared() }, { "value", std::make_shared() }, { "changed", std::make_shared() }, diff --git a/dbms/src/Storages/System/StorageSystemTables.cpp b/dbms/src/Storages/System/StorageSystemTables.cpp index 852392a63d1..91ab3581bc8 100644 --- a/dbms/src/Storages/System/StorageSystemTables.cpp +++ b/dbms/src/Storages/System/StorageSystemTables.cpp @@ -114,7 +114,7 @@ protected: StorageSystemTables::StorageSystemTables(const std::string & name_) : name(name_) { - columns = NamesAndTypesList + columns.ordinary = NamesAndTypesList { {"database", std::make_shared()}, {"name", std::make_shared()}, diff --git a/dbms/src/Storages/System/StorageSystemZooKeeper.cpp b/dbms/src/Storages/System/StorageSystemZooKeeper.cpp index 80ca3bc2f0e..9aae0ce5b3b 100644 --- a/dbms/src/Storages/System/StorageSystemZooKeeper.cpp +++ b/dbms/src/Storages/System/StorageSystemZooKeeper.cpp @@ -22,7 +22,7 @@ namespace DB StorageSystemZooKeeper::StorageSystemZooKeeper(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + columns.ordinary = NamesAndTypesList{ { "name", std::make_shared() }, { "value", std::make_shared() }, { "czxid", std::make_shared() }, diff --git a/dbms/src/Storages/tests/storage_log.cpp b/dbms/src/Storages/tests/storage_log.cpp index 6d9cb5d0def..da53fcc356d 100644 --- a/dbms/src/Storages/tests/storage_log.cpp +++ b/dbms/src/Storages/tests/storage_log.cpp @@ -36,7 +36,7 @@ try { ColumnWithTypeAndName column; column.name = "a"; - column.type = table->getDataTypeByName("a"); + column.type = table->columns.getColumn("a").type; auto col = column.type->createColumn(); ColumnUInt64::Container & vec = typeid_cast(*col).getData(); @@ -51,7 +51,7 @@ try { ColumnWithTypeAndName column; column.name = "b"; - column.type = table->getDataTypeByName("b"); + column.type = table->columns.getColumn("b").type; auto col = column.type->createColumn(); ColumnUInt8::Container & vec = typeid_cast(*col).getData(); diff --git a/dbms/src/TableFunctions/TableFunctionMerge.cpp b/dbms/src/TableFunctions/TableFunctionMerge.cpp index d37d2002d5a..b471969b847 100644 --- a/dbms/src/TableFunctions/TableFunctionMerge.cpp +++ b/dbms/src/TableFunctions/TableFunctionMerge.cpp @@ -51,7 +51,7 @@ static NamesAndTypesList chooseColumns(const String & source_database, const Str throw Exception("Error while executing table function merge. In database " + source_database + " no one matches regular expression: " + table_name_regexp_, ErrorCodes::UNKNOWN_TABLE); - return any_table->getColumnsList(); + return any_table->columns.getList(); } @@ -79,10 +79,12 @@ StoragePtr TableFunctionMerge::executeImpl(const ASTPtr & ast_function, const Co auto res = StorageMerge::create( getName(), - chooseColumns(source_database, table_name_regexp, context), - NamesAndTypesList{}, - NamesAndTypesList{}, - ColumnDefaults{}, + ColumnsDescription{ + chooseColumns(source_database, table_name_regexp, context), + NamesAndTypesList{}, + NamesAndTypesList{}, + ColumnDefaults{}, + }, source_database, table_name_regexp, context); diff --git a/dbms/src/TableFunctions/TableFunctionMySQL.cpp b/dbms/src/TableFunctions/TableFunctionMySQL.cpp index f1b4e911385..1ced8800255 100644 --- a/dbms/src/TableFunctions/TableFunctionMySQL.cpp +++ b/dbms/src/TableFunctions/TableFunctionMySQL.cpp @@ -152,7 +152,7 @@ StoragePtr TableFunctionMySQL::executeImpl(const ASTPtr & ast_function, const Co std::move(pool), database_name, table_name, - columns); + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); res->startup(); return res; diff --git a/dbms/src/TableFunctions/TableFunctionODBC.cpp b/dbms/src/TableFunctions/TableFunctionODBC.cpp index cc4c430ae8f..cacdbe29670 100644 --- a/dbms/src/TableFunctions/TableFunctionODBC.cpp +++ b/dbms/src/TableFunctions/TableFunctionODBC.cpp @@ -113,7 +113,8 @@ StoragePtr TableFunctionODBC::executeImpl(const ASTPtr & ast_function, const Con columns.emplace_back(reinterpret_cast(column_name), getDataType(type)); } - auto result = StorageODBC::create(table_name, connection_string, "", table_name, columns); + auto result = StorageODBC::create(table_name, connection_string, "", table_name, + ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); result->startup(); return result; } diff --git a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp index 3cb68d25416..181448714ba 100644 --- a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp +++ b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp @@ -32,7 +32,7 @@ NamesAndTypesList getStructureOfRemoteTable( const auto & shard_info = cluster.getAnyShardInfo(); if (shard_info.isLocal()) - return context.getTable(database, table)->getColumnsList(); + return context.getTable(database, table)->columns.getList(); auto input = std::make_shared(shard_info.pool, query, InterpreterDescribeQuery::getSampleBlock(), context); input->setPoolMode(PoolMode::GET_ONE); From 972db7b0723db78f45554acd2cc5f7d195ae7c70 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Sat, 10 Mar 2018 23:37:26 +0300 Subject: [PATCH 031/244] iterate over materialized columns where it makes sense --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 4 ++-- dbms/src/Storages/StorageDistributed.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 7933a9454c7..ea36f75a96c 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -903,7 +903,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) columns_alter_forbidden.insert(merging_params.sign_column); std::map old_types; - for (const auto & column : columns.ordinary) + for (const auto & column : columns.getList()) old_types.emplace(column.name, column.type.get()); for (const AlterCommand & command : commands) @@ -1868,7 +1868,7 @@ void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : columns.ordinary) + for (const auto & column : columns.getList()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 1b7c5fdf69a..b543e802ef9 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -142,7 +142,7 @@ StorageDistributed::StorageDistributed( table_name(table_name_), remote_database(remote_database_), remote_table(remote_table_), context(context_), cluster_name(context.getMacros().expand(cluster_name_)), has_sharding_key(sharding_key_), - sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns.ordinary).getActions(false) : nullptr), + sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns.getList()).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(table_name) + '/')) { @@ -385,7 +385,7 @@ void registerStorageDistributed(StorageFactory & factory) /// Check that sharding_key exists in the table and has numeric type. if (sharding_key) { - auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.ordinary).getActions(true); + auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.getList()).getActions(true); const Block & block = sharding_expr->getSampleBlock(); if (block.columns() != 1) From 78d92f67945db374033f13214ed3c62b27ac07d7 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Sat, 10 Mar 2018 20:03:57 +0300 Subject: [PATCH 032/244] add some useful methods, rename for clarity [#CLICKHOUSE-3241] --- dbms/src/Analyzers/ExecuteTableFunctions.cpp | 2 +- dbms/src/Common/ExternalTable.h | 4 +-- dbms/src/Core/NamesAndTypes.cpp | 10 ++++++ dbms/src/Core/NamesAndTypes.h | 2 ++ dbms/src/Core/iostream_debug_helpers.cpp | 2 +- .../tests/filter_stream_hitlog.cpp | 4 +-- dbms/src/DataStreams/tests/native_streams.cpp | 4 +-- dbms/src/DataStreams/tests/sorting_stream.cpp | 4 +-- dbms/src/Databases/DatabaseDictionary.cpp | 6 ++-- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 10 +++--- .../Interpreters/InterpreterCreateQuery.cpp | 2 +- .../Interpreters/InterpreterDescribeQuery.cpp | 3 +- .../Interpreters/InterpreterInsertQuery.cpp | 2 +- .../tests/in_join_subqueries_preprocessor.cpp | 2 -- dbms/src/Storages/AlterCommands.cpp | 13 ++------ dbms/src/Storages/ColumnsDescription.cpp | 8 ++++- dbms/src/Storages/ColumnsDescription.h | 32 +++++++++++++------ dbms/src/Storages/ITableDeclaration.cpp | 8 ++--- .../MergeTree/MergeTreeBlockInputStream.cpp | 4 +-- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 20 ++++++------ .../MergeTree/MergeTreeDataMerger.cpp | 2 +- .../Storages/MergeTree/MergeTreeDataPart.cpp | 6 ++-- .../MergeTree/MergeTreeDataSelectExecutor.cpp | 4 +-- .../MergeTree/MergeTreeDataWriter.cpp | 2 +- .../Storages/MergeTree/MergeTreeReadPool.cpp | 4 +-- .../MergeTree/MergeTreeWhereOptimizer.cpp | 4 +-- .../ReplicatedMergeTreeAlterThread.cpp | 4 +-- dbms/src/Storages/StorageDistributed.cpp | 6 ++-- dbms/src/Storages/StorageFactory.cpp | 4 +-- dbms/src/Storages/StorageLog.cpp | 4 +-- dbms/src/Storages/StorageMerge.cpp | 2 +- dbms/src/Storages/StorageMergeTree.cpp | 4 +-- .../Storages/StorageReplicatedMergeTree.cpp | 2 +- dbms/src/Storages/StorageTinyLog.cpp | 4 +-- .../StorageSystemAsynchronousMetrics.cpp | 4 +-- .../System/StorageSystemBuildOptions.cpp | 4 +-- .../Storages/System/StorageSystemClusters.cpp | 6 ++-- .../Storages/System/StorageSystemColumns.cpp | 7 ++-- .../System/StorageSystemDatabases.cpp | 4 +-- .../System/StorageSystemDictionaries.cpp | 6 ++-- .../Storages/System/StorageSystemEvents.cpp | 6 ++-- .../System/StorageSystemFunctions.cpp | 6 ++-- .../Storages/System/StorageSystemGraphite.cpp | 6 ++-- .../Storages/System/StorageSystemMerges.cpp | 4 +-- .../Storages/System/StorageSystemMetrics.cpp | 4 +-- .../Storages/System/StorageSystemModels.cpp | 6 ++-- .../Storages/System/StorageSystemNumbers.cpp | 2 +- dbms/src/Storages/System/StorageSystemOne.cpp | 2 +- .../System/StorageSystemPartsBase.cpp | 2 +- .../System/StorageSystemPartsColumns.cpp | 3 +- .../System/StorageSystemProcesses.cpp | 6 ++-- .../Storages/System/StorageSystemReplicas.cpp | 4 +-- .../System/StorageSystemReplicationQueue.cpp | 4 +-- .../Storages/System/StorageSystemSettings.cpp | 6 ++-- .../Storages/System/StorageSystemTables.cpp | 4 +-- .../System/StorageSystemZooKeeper.cpp | 4 +-- dbms/src/Storages/tests/hit_log.cpp | 4 +-- dbms/src/Storages/tests/storage_log.cpp | 8 ++--- .../src/TableFunctions/TableFunctionMerge.cpp | 9 ++---- .../src/TableFunctions/TableFunctionMySQL.cpp | 2 +- dbms/src/TableFunctions/TableFunctionODBC.cpp | 3 +- .../getStructureOfRemoteTable.cpp | 2 +- 62 files changed, 162 insertions(+), 160 deletions(-) diff --git a/dbms/src/Analyzers/ExecuteTableFunctions.cpp b/dbms/src/Analyzers/ExecuteTableFunctions.cpp index 326c5df62ed..3feabc8f490 100644 --- a/dbms/src/Analyzers/ExecuteTableFunctions.cpp +++ b/dbms/src/Analyzers/ExecuteTableFunctions.cpp @@ -72,7 +72,7 @@ void ExecuteTableFunctions::dump(WriteBuffer & out) const { writeString(table.second->getName(), out); writeCString("\n\n", out); - writeString(table.second->columns.getList().toString(), out); + writeString(table.second->columns.getPhysical().toString(), out); writeCString("\n", out); } } diff --git a/dbms/src/Common/ExternalTable.h b/dbms/src/Common/ExternalTable.h index b5b0c522339..7cc8069108b 100644 --- a/dbms/src/Common/ExternalTable.h +++ b/dbms/src/Common/ExternalTable.h @@ -198,9 +198,7 @@ public: /// Create table NamesAndTypesList columns = sample_block.getNamesAndTypesList(); - StoragePtr storage = StorageMemory::create( - data.second, - ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); + StoragePtr storage = StorageMemory::create(data.second, ColumnsDescription{columns}); storage->startup(); context.addExternalTable(data.second, storage); BlockOutputStreamPtr output = storage->write(ASTPtr(), context.getSettingsRef()); diff --git a/dbms/src/Core/NamesAndTypes.cpp b/dbms/src/Core/NamesAndTypes.cpp index 14faaa133ea..a5240ba4a91 100644 --- a/dbms/src/Core/NamesAndTypes.cpp +++ b/dbms/src/Core/NamesAndTypes.cpp @@ -138,4 +138,14 @@ NamesAndTypesList NamesAndTypesList::addTypes(const Names & names) const return res; } +bool NamesAndTypesList::contains(const String & name) const +{ + for (const NameAndTypePair & column : *this) + { + if (column.name == name) + return true; + } + return false; +} + } diff --git a/dbms/src/Core/NamesAndTypes.h b/dbms/src/Core/NamesAndTypes.h index 7aa9f3b3ff4..849141e43f7 100644 --- a/dbms/src/Core/NamesAndTypes.h +++ b/dbms/src/Core/NamesAndTypes.h @@ -69,6 +69,8 @@ public: /// Unlike `filter`, returns columns in the order in which they go in `names`. NamesAndTypesList addTypes(const Names & names) const; + + bool contains(const String & name) const; }; } diff --git a/dbms/src/Core/iostream_debug_helpers.cpp b/dbms/src/Core/iostream_debug_helpers.cpp index 822bbf58376..723b3dc2e90 100644 --- a/dbms/src/Core/iostream_debug_helpers.cpp +++ b/dbms/src/Core/iostream_debug_helpers.cpp @@ -44,7 +44,7 @@ std::ostream & operator<<(std::ostream & stream, const IDataType & what) std::ostream & operator<<(std::ostream & stream, const IStorage & what) { stream << "IStorage(name = " << what.getName() << ", tableName = " << what.getTableName() << ") {" - << what.columns.getList().toString() + << what.columns.getPhysical().toString() << "}"; // isRemote supportsSampling supportsFinal supportsPrewhere return stream; diff --git a/dbms/src/DataStreams/tests/filter_stream_hitlog.cpp b/dbms/src/DataStreams/tests/filter_stream_hitlog.cpp index fe9ce592a43..2eb65c30df3 100644 --- a/dbms/src/DataStreams/tests/filter_stream_hitlog.cpp +++ b/dbms/src/DataStreams/tests/filter_stream_hitlog.cpp @@ -104,8 +104,8 @@ int main(int, char **) /// create an object of an existing hit log table - StoragePtr table = StorageLog::create("./", "HitLog", names_and_types_list, - NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + StoragePtr table = StorageLog::create( + "./", "HitLog", ColumnsDescription{names_and_types_list}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); table->startup(); /// read from it, apply the expression, filter, and write in tsv form to the console diff --git a/dbms/src/DataStreams/tests/native_streams.cpp b/dbms/src/DataStreams/tests/native_streams.cpp index bd0a998f88e..5d02d491ec4 100644 --- a/dbms/src/DataStreams/tests/native_streams.cpp +++ b/dbms/src/DataStreams/tests/native_streams.cpp @@ -95,8 +95,8 @@ try /// create an object of an existing hit log table - StoragePtr table = StorageLog::create("./", "HitLog", names_and_types_list, - NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + StoragePtr table = StorageLog::create( + "./", "HitLog", ColumnsDescription{names_and_types_list}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); table->startup(); /// read from it diff --git a/dbms/src/DataStreams/tests/sorting_stream.cpp b/dbms/src/DataStreams/tests/sorting_stream.cpp index cd6fe515a53..0cfffec295f 100644 --- a/dbms/src/DataStreams/tests/sorting_stream.cpp +++ b/dbms/src/DataStreams/tests/sorting_stream.cpp @@ -107,8 +107,8 @@ try /// create an object of an existing hit log table - StoragePtr table = StorageLog::create("./", "HitLog", names_and_types_list, - NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + StoragePtr table = StorageLog::create( + "./", "HitLog", ColumnsDescription{names_and_types_list}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); table->startup(); /// read from it, sort it, and write it in tsv form to the console diff --git a/dbms/src/Databases/DatabaseDictionary.cpp b/dbms/src/Databases/DatabaseDictionary.cpp index 439fe8f4d79..503d0195168 100644 --- a/dbms/src/Databases/DatabaseDictionary.cpp +++ b/dbms/src/Databases/DatabaseDictionary.cpp @@ -41,8 +41,7 @@ Tables DatabaseDictionary::loadTables() { const DictionaryStructure & dictionary_structure = dict_ptr->getStructure(); auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure); - tables[name] = StorageDictionary::create(name, - ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}, dictionary_structure, name); + tables[name] = StorageDictionary::create(name, ColumnsDescription{columns}, dictionary_structure, name); } } @@ -76,8 +75,7 @@ StoragePtr DatabaseDictionary::tryGetTable( { const DictionaryStructure & dictionary_structure = dict_ptr->getStructure(); auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure); - return StorageDictionary::create(table_name, - ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}, dictionary_structure, table_name); + return StorageDictionary::create(table_name, ColumnsDescription{columns}, dictionary_structure, table_name); } } } diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index fe85e154e92..e6190b8f1df 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -190,7 +190,7 @@ ExpressionAnalyzer::ExpressionAnalyzer( } if (storage && source_columns.empty()) - source_columns = storage->columns.getList(); + source_columns = storage->columns.getPhysical(); else removeDuplicateColumns(source_columns); @@ -712,7 +712,7 @@ static std::shared_ptr interpretSubquery( /// get columns list for target table auto database_table = getDatabaseAndTableNameFromIdentifier(*table); const auto & storage = context.getTable(database_table.first, database_table.second); - const auto & columns = storage->columns.getListNonMaterialized(); + const auto & columns = storage->columns.ordinary; select_expression_list->children.reserve(columns.size()); /// manually substitute column names in place of asterisk @@ -826,9 +826,7 @@ void ExpressionAnalyzer::addExternalStorage(ASTPtr & subquery_or_table_name_or_t Block sample = interpreter->getSampleBlock(); NamesAndTypesList columns = sample.getNamesAndTypesList(); - StoragePtr external_storage = StorageMemory::create( - external_table_name, - ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); + StoragePtr external_storage = StorageMemory::create(external_table_name, ColumnsDescription{columns}); external_storage->startup(); /** We replace the subquery with the name of the temporary table. @@ -1052,7 +1050,7 @@ void ExpressionAnalyzer::normalizeTreeImpl( if (storage) { /// If we select from a table, get only not MATERIALIZED, not ALIAS columns. - for (const auto & name_type : storage->columns.getListNonMaterialized()) + for (const auto & name_type : storage->columns.ordinary) all_columns.emplace_back(std::make_shared(name_type.name)); } else diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 6033947b474..e5d20648fbd 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -305,7 +305,7 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) { auto columns_list = std::make_shared(); - for (const auto & column : boost::join(columns.ordinary, boost::join(columns.materialized, columns.aliases))) + for (const auto & column : columns.getAll()) { const auto column_declaration = std::make_shared(); ASTPtr column_declaration_ptr{column_declaration}; diff --git a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp index b0d7e4c0363..c03034af49a 100644 --- a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp +++ b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp @@ -99,8 +99,7 @@ BlockInputStreamPtr InterpreterDescribeQuery::executeImpl() } auto table_lock = table->lockStructure(false, __PRETTY_FUNCTION__); - columns = table->columns.getList(); - columns.insert(std::end(columns), std::begin(table->columns.aliases), std::end(table->columns.aliases)); + columns = table->columns.getAll(); column_defaults = table->columns.defaults; } diff --git a/dbms/src/Interpreters/InterpreterInsertQuery.cpp b/dbms/src/Interpreters/InterpreterInsertQuery.cpp index 5f0b8201ac3..973fdc31a27 100644 --- a/dbms/src/Interpreters/InterpreterInsertQuery.cpp +++ b/dbms/src/Interpreters/InterpreterInsertQuery.cpp @@ -95,7 +95,7 @@ BlockIO InterpreterInsertQuery::execute() auto table_lock = table->lockStructure(true, __PRETTY_FUNCTION__); - NamesAndTypesList required_columns = table->columns.getList(); + NamesAndTypesList required_columns = table->columns.getPhysical(); /// We create a pipeline of several streams, into which we will write data. BlockOutputStreamPtr out; diff --git a/dbms/src/Interpreters/tests/in_join_subqueries_preprocessor.cpp b/dbms/src/Interpreters/tests/in_join_subqueries_preprocessor.cpp index 0a67da3a5d8..e5c04025c59 100644 --- a/dbms/src/Interpreters/tests/in_join_subqueries_preprocessor.cpp +++ b/dbms/src/Interpreters/tests/in_join_subqueries_preprocessor.cpp @@ -38,7 +38,6 @@ public: std::string getRemoteTableName() const { return remote_table; } std::string getTableName() const override { return ""; } - const DB::NamesAndTypesList & getColumnsListImpl() const override { return names_and_types; } protected: StorageDistributedFake(const std::string & remote_database_, const std::string & remote_table_, size_t shard_count_) @@ -50,7 +49,6 @@ private: const std::string remote_database; const std::string remote_table; size_t shard_count; - DB::NamesAndTypesList names_and_types; }; diff --git a/dbms/src/Storages/AlterCommands.cpp b/dbms/src/Storages/AlterCommands.cpp index defad6f5cba..184f63c070f 100644 --- a/dbms/src/Storages/AlterCommands.cpp +++ b/dbms/src/Storages/AlterCommands.cpp @@ -25,15 +25,7 @@ void AlterCommand::apply(ColumnsDescription & columns_description) const { if (type == ADD_COLUMN) { - const auto exists_in = [this] (const NamesAndTypesList & columns) - { - return columns.end() != std::find_if(columns.begin(), columns.end(), - std::bind(namesEqual, std::cref(column_name), std::placeholders::_1)); - }; - - if (exists_in(columns_description.ordinary) || - exists_in(columns_description.materialized) || - exists_in(columns_description.aliases)) + if (columns_description.getAll().contains(column_name)) { throw Exception{ "Cannot add column " + column_name + ": column with this name already exists", @@ -185,8 +177,7 @@ void AlterCommands::apply(ColumnsDescription & columns_description) const void AlterCommands::validate(IStorage * table, const Context & context) { - auto all_columns = table->columns.getList(); - all_columns.insert(std::end(all_columns), std::begin(table->columns.aliases), std::end(table->columns.aliases)); + auto all_columns = table->columns.getAll(); auto defaults = table->columns.defaults; std::vector> defaulted_columns{}; diff --git a/dbms/src/Storages/ColumnsDescription.cpp b/dbms/src/Storages/ColumnsDescription.cpp index b8fae53ed4e..95b5001a1f9 100644 --- a/dbms/src/Storages/ColumnsDescription.cpp +++ b/dbms/src/Storages/ColumnsDescription.cpp @@ -27,12 +27,18 @@ namespace ErrorCodes } -NamesAndTypesList ColumnsDescription::getList() const +NamesAndTypesList ColumnsDescription::getPhysical() const { return ext::collection_cast(boost::join(ordinary, materialized)); } +NamesAndTypesList ColumnsDescription::getAll() const +{ + return ext::collection_cast(boost::join(ordinary, boost::join(materialized, aliases))); +} + + Names ColumnsDescription::getNames() const { return ext::map(boost::join(ordinary, materialized), [] (const auto & it) { return it.name; }); diff --git a/dbms/src/Storages/ColumnsDescription.h b/dbms/src/Storages/ColumnsDescription.h index 888f0864701..e4e45ff6fe2 100644 --- a/dbms/src/Storages/ColumnsDescription.h +++ b/dbms/src/Storages/ColumnsDescription.h @@ -16,6 +16,20 @@ struct ColumnsDescription NamesAndTypesList aliases; ColumnDefaults defaults; + ColumnsDescription() = default; + + ColumnsDescription( + NamesAndTypesList ordinary_, + NamesAndTypesList materialized_, + NamesAndTypesList aliases_, + ColumnDefaults defaults_) + : ordinary(std::move(ordinary_)) + , materialized(std::move(materialized_)) + , aliases(std::move(aliases_)) + , defaults(std::move(defaults_)) + {} + + explicit ColumnsDescription(NamesAndTypesList ordinary_) : ordinary(std::move(ordinary_)) {} bool operator==(const ColumnsDescription & other) const { @@ -27,21 +41,19 @@ struct ColumnsDescription bool operator!=(const ColumnsDescription & other) const { return !(*this == other); } - /** Get a list of names and table column types, only non-virtual. - */ - NamesAndTypesList getList() const; - const NamesAndTypesList & getListNonMaterialized() const { return ordinary; } + /// ordinary + materialized. + NamesAndTypesList getPhysical() const; - /** Get a list of column names. - */ + /// ordinary + materialized + aliases. + NamesAndTypesList getAll() const; + + /// Get names of physical columns. Names getNames() const; - /** Get a description of any column by its name. - */ + /// Get a physical column by name. NameAndTypePair get(const String & column_name) const; - /** Is there a column with that name. - */ + /// Is there a physical column with the given name. bool has(const String & column_name) const; diff --git a/dbms/src/Storages/ITableDeclaration.cpp b/dbms/src/Storages/ITableDeclaration.cpp index d4bbb4b501e..b5a6c035b96 100644 --- a/dbms/src/Storages/ITableDeclaration.cpp +++ b/dbms/src/Storages/ITableDeclaration.cpp @@ -111,7 +111,7 @@ static NamesAndTypesMap getColumnsMap(const Args &... args) void ITableDeclaration::check(const Names & column_names) const { - const NamesAndTypesList & available_columns = columns.getList(); + const NamesAndTypesList & available_columns = columns.getPhysical(); if (column_names.empty()) throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns), @@ -139,7 +139,7 @@ void ITableDeclaration::check(const Names & column_names) const void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const { - const NamesAndTypesList & available_columns = columns.getList(); + const NamesAndTypesList & available_columns = columns.getPhysical(); const auto columns_map = getColumnsMap(available_columns); using UniqueStrings = google::dense_hash_set; @@ -167,7 +167,7 @@ void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const Names & column_names) const { - const NamesAndTypesList & available_columns = columns.getList(); + const NamesAndTypesList & available_columns = columns.getPhysical(); const auto available_columns_map = getColumnsMap(available_columns); const NamesAndTypesMap & provided_columns_map = getColumnsMap(provided_columns); @@ -204,7 +204,7 @@ void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const void ITableDeclaration::check(const Block & block, bool need_all) const { - const NamesAndTypesList & available_columns = columns.getList(); + const NamesAndTypesList & available_columns = columns.getPhysical(); const auto columns_map = getColumnsMap(available_columns); using NameSet = std::unordered_set; diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp index 5a67714db64..6fb7c8fb611 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp @@ -141,8 +141,8 @@ try if (!column_names.empty()) storage.check(data_part->columns, column_names); - pre_columns = storage.columns.getList().addTypes(pre_column_names); - columns = storage.columns.getList().addTypes(column_names); + pre_columns = storage.columns.getPhysical().addTypes(pre_column_names); + columns = storage.columns.getPhysical().addTypes(column_names); } else { diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index ea36f75a96c..de16c22593d 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -110,7 +110,7 @@ MergeTreeData::MergeTreeData( data_parts_by_state_and_info(data_parts_indexes.get()) { /// NOTE: using the same columns list as is read when performing actual merges. - merging_params.check(columns.getList()); + merging_params.check(columns.getPhysical()); if (!primary_expr_ast) throw Exception("Primary key cannot be empty", ErrorCodes::BAD_ARGUMENTS); @@ -222,11 +222,11 @@ void MergeTreeData::initPrimaryKey() primary_sort_descr.clear(); addSortDescription(primary_sort_descr, primary_expr_ast); - primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getList()).getActions(false); + primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getPhysical()).getActions(false); { ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getList()).getActions(true); + ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getPhysical()).getActions(true); primary_key_sample = projected_expr->getSampleBlock(); } @@ -241,10 +241,10 @@ void MergeTreeData::initPrimaryKey() if (secondary_sort_expr_ast) { addSortDescription(sort_descr, secondary_sort_expr_ast); - secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getList()).getActions(false); + secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getPhysical()).getActions(false); ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getList()).getActions(true); + ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getPhysical()).getActions(true); auto secondary_key_sample = projected_expr->getSampleBlock(); checkKeyExpression(*secondary_sort_expr, secondary_key_sample, "Secondary"); @@ -257,7 +257,7 @@ void MergeTreeData::initPartitionKey() if (!partition_expr_ast || partition_expr_ast->children.empty()) return; - partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, columns.getList()).getActions(false); + partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, columns.getPhysical()).getActions(false); for (const ASTPtr & ast : partition_expr_ast->children) { String col_name = ast->getColumnName(); @@ -903,7 +903,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) columns_alter_forbidden.insert(merging_params.sign_column); std::map old_types; - for (const auto & column : columns.getList()) + for (const auto & column : columns.getPhysical()) old_types.emplace(column.name, column.type.get()); for (const AlterCommand & command : commands) @@ -931,7 +931,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) NameToNameMap unused_map; bool unused_bool; - createConvertExpression(nullptr, columns.getList(), new_columns.getList(), unused_expression, unused_map, unused_bool); + createConvertExpression(nullptr, columns.getPhysical(), new_columns.getPhysical(), unused_expression, unused_map, unused_bool); } void MergeTreeData::createConvertExpression(const DataPartPtr & part, const NamesAndTypesList & old_columns, const NamesAndTypesList & new_columns, @@ -1835,7 +1835,7 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : columns.getList()) + for (const auto & column : columns.getPhysical()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; @@ -1868,7 +1868,7 @@ void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : columns.getList()) + for (const auto & column : columns.getPhysical()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index 4e3e9788aaa..8e30320aefb 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -537,7 +537,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataMerger::mergePartsToTemporaryPart part->accumulateColumnSizes(merged_column_to_size); Names all_column_names = data.columns.getNames(); - NamesAndTypesList all_columns = data.columns.getList(); + NamesAndTypesList all_columns = data.columns.getPhysical(); const SortDescription sort_desc = data.getSortDescription(); NamesAndTypesList gathering_columns, merging_columns; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 9c0269c7437..f37cd8e579c 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -418,7 +418,7 @@ UInt64 MergeTreeDataPart::getColumnMrkSize(const String & name) const */ String MergeTreeDataPart::getColumnNameWithMinumumCompressedSize() const { - const auto & columns = storage.columns.getList(); + const auto & columns = storage.columns.getPhysical(); const std::string * minimum_size_column = nullptr; UInt64 minimum_size = std::numeric_limits::max(); @@ -774,7 +774,7 @@ void MergeTreeDataPart::accumulateColumnSizes(ColumnToSize & column_to_size) con { std::shared_lock part_lock(columns_lock); - for (const NameAndTypePair & name_type : storage.columns.getList()) + for (const NameAndTypePair & name_type : storage.columns.getPhysical()) { name_type.type->enumerateStreams([&](const IDataType::SubstreamPath & substream_path) { @@ -794,7 +794,7 @@ void MergeTreeDataPart::loadColumns(bool require) throw Exception("No columns.txt in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); /// If there is no file with a list of columns, write it down. - for (const NameAndTypePair & column : storage.columns.getList()) + for (const NameAndTypePair & column : storage.columns.getPhysical()) if (Poco::File(getFullPath() + escapeForFileName(column.name) + ".bin").exists()) columns.push_back(column); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp index 605091e6386..0890163078d 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp @@ -175,7 +175,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read( } } - NamesAndTypesList available_real_columns = data.columns.getList(); + NamesAndTypesList available_real_columns = data.columns.getPhysical(); NamesAndTypesList available_real_and_virtual_columns = available_real_columns; for (const auto & name : virt_column_names) @@ -857,7 +857,7 @@ void MergeTreeDataSelectExecutor::createPositiveSignCondition( arguments->children.push_back(sign); arguments->children.push_back(one); - out_expression = ExpressionAnalyzer(function, context, {}, data.columns.getList()).getActions(false); + out_expression = ExpressionAnalyzer(function, context, {}, data.columns.getPhysical()).getActions(false); out_column = function->getColumnName(); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index f4db6b934ba..19eb2e8eecd 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -205,7 +205,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithPa /// either default lz4 or compression method with zero thresholds on absolute and relative part size. auto compression_settings = data.context.chooseCompressionSettings(0, 0); - NamesAndTypesList columns = data.columns.getList().filter(block.getNames()); + NamesAndTypesList columns = data.columns.getPhysical().filter(block.getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_settings); out.writePrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp index c32aa71a731..2c600dbd32d 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp @@ -238,8 +238,8 @@ std::vector MergeTreeReadPool::fillPerPartInfo( if (!required_column_names.empty()) data.check(part.data_part->columns, required_column_names); - per_part_pre_columns.push_back(data.columns.getList().addTypes(required_pre_column_names)); - per_part_columns.push_back(data.columns.getList().addTypes(required_column_names)); + per_part_pre_columns.push_back(data.columns.getPhysical().addTypes(required_pre_column_names)); + per_part_columns.push_back(data.columns.getPhysical().addTypes(required_column_names)); } else { diff --git a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp index 005ca750226..ce4047fc85f 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp @@ -41,9 +41,9 @@ MergeTreeWhereOptimizer::MergeTreeWhereOptimizer( Logger * log) : primary_key_columns{ext::map(data.getPrimarySortDescription(), [] (const SortColumnDescription & col) { return col.column_name; })}, - table_columns{ext::map(data.columns.getList(), + table_columns{ext::map(data.columns.getPhysical(), [] (const NameAndTypePair & col) { return col.name; })}, - block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.columns.getList())}, + block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.columns.getPhysical())}, prepared_sets(query_info.sets), log{log} { diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp index c359a889bfb..948902d8302 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp @@ -126,7 +126,7 @@ void ReplicatedMergeTreeAlterThread::run() if (!changed_version) parts = storage.data.getDataParts(); - const auto columns_plus_materialized = storage.data.columns.getList(); + const auto columns_for_parts = storage.data.columns.getPhysical(); for (const MergeTreeData::DataPartPtr & part : parts) { @@ -134,7 +134,7 @@ void ReplicatedMergeTreeAlterThread::run() /// TODO: You can skip checking for too large changes if ZooKeeper has, for example, /// node /flags/force_alter. auto transaction = storage.data.alterDataPart( - part, columns_plus_materialized, storage.data.primary_expr_ast, false); + part, columns_for_parts, storage.data.primary_expr_ast, false); if (!transaction) continue; diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index b543e802ef9..c010ca768d1 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -142,7 +142,7 @@ StorageDistributed::StorageDistributed( table_name(table_name_), remote_database(remote_database_), remote_table(remote_table_), context(context_), cluster_name(context.getMacros().expand(cluster_name_)), has_sharding_key(sharding_key_), - sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns.getList()).getActions(false) : nullptr), + sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns.getPhysical()).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(table_name) + '/')) { @@ -158,7 +158,7 @@ StoragePtr StorageDistributed::createWithOwnCluster( const Context & context_) { auto res = ext::shared_ptr_helper::create( - name_, ColumnsDescription{columns_, NamesAndTypesList(), NamesAndTypesList(), ColumnDefaults()}, + name_, ColumnsDescription{columns_}, remote_database_, remote_table_, String{}, context_, ASTPtr(), String()); res->owned_cluster = owned_cluster_; @@ -385,7 +385,7 @@ void registerStorageDistributed(StorageFactory & factory) /// Check that sharding_key exists in the table and has numeric type. if (sharding_key) { - auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.getList()).getActions(true); + auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.getPhysical()).getActions(true); const Block & block = sharding_expr->getSampleBlock(); if (block.columns() != 1) diff --git a/dbms/src/Storages/StorageFactory.cpp b/dbms/src/Storages/StorageFactory.cpp index 1b8970aba24..e6e661571aa 100644 --- a/dbms/src/Storages/StorageFactory.cpp +++ b/dbms/src/Storages/StorageFactory.cpp @@ -64,9 +64,7 @@ StoragePtr StorageFactory::get( { /// Check for some special types, that are not allowed to be stored in tables. Example: NULL data type. /// Exception: any type is allowed in View, because plain (non-materialized) View does not store anything itself. - checkAllTypesAreAllowedInTable(columns.ordinary); - checkAllTypesAreAllowedInTable(columns.materialized); - checkAllTypesAreAllowedInTable(columns.aliases); + checkAllTypesAreAllowedInTable(columns.getAll()); if (query.is_materialized_view) { diff --git a/dbms/src/Storages/StorageLog.cpp b/dbms/src/Storages/StorageLog.cpp index 27881d8b8fe..137c1d55616 100644 --- a/dbms/src/Storages/StorageLog.cpp +++ b/dbms/src/Storages/StorageLog.cpp @@ -371,7 +371,7 @@ StorageLog::StorageLog( /// create files if they do not exist Poco::File(path + escapeForFileName(name) + '/').createDirectories(); - for (const auto & column : columns.getList()) + for (const auto & column : columns.getPhysical()) addFiles(column.name, *column.type); marks_file = Poco::File(path + escapeForFileName(name) + '/' + DBMS_STORAGE_LOG_MARKS_FILE_NAME); @@ -499,7 +499,7 @@ BlockInputStreams StorageLog::read( processed_stage = QueryProcessingStage::FetchColumns; loadMarks(); - NamesAndTypesList all_columns = Nested::collect(columns.getList().addTypes(column_names)); + NamesAndTypesList all_columns = Nested::collect(columns.getPhysical().addTypes(column_names)); std::shared_lock lock(rwlock); diff --git a/dbms/src/Storages/StorageMerge.cpp b/dbms/src/Storages/StorageMerge.cpp index 39fed81e538..f26544975cd 100644 --- a/dbms/src/Storages/StorageMerge.cpp +++ b/dbms/src/Storages/StorageMerge.cpp @@ -181,7 +181,7 @@ BlockInputStreams StorageMerge::read( /// If there are only virtual columns in query, you must request at least one other column. if (real_column_names.size() == 0) - real_column_names.push_back(ExpressionActions::getSmallestColumn(table->columns.getList())); + real_column_names.push_back(ExpressionActions::getSmallestColumn(table->columns.getPhysical())); /// Substitute virtual column for its value when querying tables. ASTPtr modified_query_ast = query->clone(); diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index 71d8013e4db..5e799c91909 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -176,7 +176,7 @@ void StorageMergeTree::alter( throw Exception("MODIFY PRIMARY KEY only supported for tables without sampling key", ErrorCodes::BAD_ARGUMENTS); auto parts = data.getDataParts({MergeTreeDataPartState::PreCommitted, MergeTreeDataPartState::Committed, MergeTreeDataPartState::Outdated}); - auto columns_for_parts = new_columns.getList(); + auto columns_for_parts = new_columns.getPhysical(); for (const MergeTreeData::DataPartPtr & part : parts) { if (auto transaction = data.alterDataPart(part, columns_for_parts, new_primary_key_ast, false)) @@ -422,7 +422,7 @@ void StorageMergeTree::clearColumnInPartition(const ASTPtr & partition, const Fi auto new_columns = data.columns; alter_command.apply(new_columns); - auto columns_for_parts = new_columns.getList(); + auto columns_for_parts = new_columns.getPhysical(); for (const auto & part : parts) { if (part->info.partition_id != partition_id) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index 9f6553f6512..d69db2d388e 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -1512,7 +1512,7 @@ void StorageReplicatedMergeTree::executeClearColumnInPartition(const LogEntry & size_t modified_parts = 0; auto parts = data.getDataParts(); - auto columns_for_parts = new_columns.getList(); + auto columns_for_parts = new_columns.getPhysical(); for (const auto & part : parts) { if (!entry_part_info.contains(part->info)) diff --git a/dbms/src/Storages/StorageTinyLog.cpp b/dbms/src/Storages/StorageTinyLog.cpp index 039f470c366..8c7fe1963a8 100644 --- a/dbms/src/Storages/StorageTinyLog.cpp +++ b/dbms/src/Storages/StorageTinyLog.cpp @@ -296,7 +296,7 @@ StorageTinyLog::StorageTinyLog( throwFromErrno("Cannot create directory " + full_path, ErrorCodes::CANNOT_CREATE_DIRECTORY); } - for (const auto & col : columns.getList()) + for (const auto & col : columns.getPhysical()) addFiles(col.name, *col.type); } @@ -348,7 +348,7 @@ BlockInputStreams StorageTinyLog::read( check(column_names); processed_stage = QueryProcessingStage::FetchColumns; return BlockInputStreams(1, std::make_shared( - max_block_size, Nested::collect(columns.getList().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); + max_block_size, Nested::collect(columns.getPhysical().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); } diff --git a/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp b/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp index f08808f799a..3c77244c557 100644 --- a/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp +++ b/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp @@ -16,10 +16,10 @@ StorageSystemAsynchronousMetrics::StorageSystemAsynchronousMetrics(const std::st : name(name_), async_metrics(async_metrics_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ {"metric", std::make_shared()}, {"value", std::make_shared()}, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemBuildOptions.cpp b/dbms/src/Storages/System/StorageSystemBuildOptions.cpp index 7a864090e59..f354da97944 100644 --- a/dbms/src/Storages/System/StorageSystemBuildOptions.cpp +++ b/dbms/src/Storages/System/StorageSystemBuildOptions.cpp @@ -13,10 +13,10 @@ namespace DB StorageSystemBuildOptions::StorageSystemBuildOptions(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "name", std::make_shared() }, { "value", std::make_shared() }, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemClusters.cpp b/dbms/src/Storages/System/StorageSystemClusters.cpp index 8d772e5ebb8..1e67e433d48 100644 --- a/dbms/src/Storages/System/StorageSystemClusters.cpp +++ b/dbms/src/Storages/System/StorageSystemClusters.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemClusters::StorageSystemClusters(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "cluster", std::make_shared() }, { "shard_num", std::make_shared() }, { "shard_weight", std::make_shared() }, @@ -24,8 +24,8 @@ StorageSystemClusters::StorageSystemClusters(const std::string & name_) { "port", std::make_shared() }, { "is_local", std::make_shared() }, { "user", std::make_shared() }, - { "default_database", std::make_shared() } - }; + { "default_database", std::make_shared() }, + }); } diff --git a/dbms/src/Storages/System/StorageSystemColumns.cpp b/dbms/src/Storages/System/StorageSystemColumns.cpp index adec6a70c58..75c8afa1515 100644 --- a/dbms/src/Storages/System/StorageSystemColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemColumns.cpp @@ -18,7 +18,7 @@ namespace DB StorageSystemColumns::StorageSystemColumns(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "database", std::make_shared() }, { "table", std::make_shared() }, { "name", std::make_shared() }, @@ -28,7 +28,7 @@ StorageSystemColumns::StorageSystemColumns(const std::string & name_) { "data_compressed_bytes", std::make_shared() }, { "data_uncompressed_bytes", std::make_shared() }, { "marks_bytes", std::make_shared() }, - }; + }); } @@ -137,8 +137,7 @@ BlockInputStreams StorageSystemColumns::read( throw; } - columns = storage->columns.getList(); - columns.insert(std::end(columns), std::begin(storage->columns.aliases), std::end(storage->columns.aliases)); + columns = storage->columns.getAll(); column_defaults = storage->columns.defaults; /** Info about sizes of columns for tables of MergeTree family. diff --git a/dbms/src/Storages/System/StorageSystemDatabases.cpp b/dbms/src/Storages/System/StorageSystemDatabases.cpp index 12c35c7ec9e..79a3b3483a6 100644 --- a/dbms/src/Storages/System/StorageSystemDatabases.cpp +++ b/dbms/src/Storages/System/StorageSystemDatabases.cpp @@ -13,12 +13,12 @@ namespace DB StorageSystemDatabases::StorageSystemDatabases(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ {"name", std::make_shared()}, {"engine", std::make_shared()}, {"data_path", std::make_shared()}, {"metadata_path", std::make_shared()}, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemDictionaries.cpp b/dbms/src/Storages/System/StorageSystemDictionaries.cpp index 3cb4bd7962b..84bf4a2c98f 100644 --- a/dbms/src/Storages/System/StorageSystemDictionaries.cpp +++ b/dbms/src/Storages/System/StorageSystemDictionaries.cpp @@ -21,7 +21,7 @@ namespace DB StorageSystemDictionaries::StorageSystemDictionaries(const std::string & name) : name{name} { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "name", std::make_shared() }, { "origin", std::make_shared() }, { "type", std::make_shared() }, @@ -35,8 +35,8 @@ StorageSystemDictionaries::StorageSystemDictionaries(const std::string & name) { "load_factor", std::make_shared() }, { "creation_time", std::make_shared() }, { "source", std::make_shared() }, - { "last_exception", std::make_shared() } - }; + { "last_exception", std::make_shared() }, + }); } diff --git a/dbms/src/Storages/System/StorageSystemEvents.cpp b/dbms/src/Storages/System/StorageSystemEvents.cpp index 0838eb739a5..ac613a7e84e 100644 --- a/dbms/src/Storages/System/StorageSystemEvents.cpp +++ b/dbms/src/Storages/System/StorageSystemEvents.cpp @@ -13,11 +13,11 @@ namespace DB StorageSystemEvents::StorageSystemEvents(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList + columns = ColumnsDescription( { {"event", std::make_shared()}, - {"value", std::make_shared()} - }; + {"value", std::make_shared()}, + }); } diff --git a/dbms/src/Storages/System/StorageSystemFunctions.cpp b/dbms/src/Storages/System/StorageSystemFunctions.cpp index 4d013eb2268..2d42bee9a46 100644 --- a/dbms/src/Storages/System/StorageSystemFunctions.cpp +++ b/dbms/src/Storages/System/StorageSystemFunctions.cpp @@ -16,10 +16,10 @@ namespace DB StorageSystemFunctions::StorageSystemFunctions(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "name", std::make_shared() }, - { "is_aggregate", std::make_shared() } - }; + { "is_aggregate", std::make_shared() }, + }); } diff --git a/dbms/src/Storages/System/StorageSystemGraphite.cpp b/dbms/src/Storages/System/StorageSystemGraphite.cpp index e99c037ea78..30cc56c55e3 100644 --- a/dbms/src/Storages/System/StorageSystemGraphite.cpp +++ b/dbms/src/Storages/System/StorageSystemGraphite.cpp @@ -125,15 +125,15 @@ static Strings getAllGraphiteSections(const AbstractConfiguration & config) StorageSystemGraphite::StorageSystemGraphite(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ {"config_name", std::make_shared()}, {"regexp", std::make_shared()}, {"function", std::make_shared()}, {"age", std::make_shared()}, {"precision", std::make_shared()}, {"priority", std::make_shared()}, - {"is_default", std::make_shared()} - }; + {"is_default", std::make_shared()}, + }); } diff --git a/dbms/src/Storages/System/StorageSystemMerges.cpp b/dbms/src/Storages/System/StorageSystemMerges.cpp index fea37df35a1..c32cad1265b 100644 --- a/dbms/src/Storages/System/StorageSystemMerges.cpp +++ b/dbms/src/Storages/System/StorageSystemMerges.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemMerges::StorageSystemMerges(const std::string & name) : name{name} { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "database", std::make_shared() }, { "table", std::make_shared() }, { "elapsed", std::make_shared() }, @@ -31,7 +31,7 @@ StorageSystemMerges::StorageSystemMerges(const std::string & name) { "columns_written", std::make_shared() }, { "memory_usage", std::make_shared() }, { "thread_number", std::make_shared() }, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemMetrics.cpp b/dbms/src/Storages/System/StorageSystemMetrics.cpp index 54002318ef6..57935b13fea 100644 --- a/dbms/src/Storages/System/StorageSystemMetrics.cpp +++ b/dbms/src/Storages/System/StorageSystemMetrics.cpp @@ -14,10 +14,10 @@ namespace DB StorageSystemMetrics::StorageSystemMetrics(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ {"metric", std::make_shared()}, {"value", std::make_shared()}, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemModels.cpp b/dbms/src/Storages/System/StorageSystemModels.cpp index 9057c6de626..6ef9d157303 100644 --- a/dbms/src/Storages/System/StorageSystemModels.cpp +++ b/dbms/src/Storages/System/StorageSystemModels.cpp @@ -14,13 +14,13 @@ namespace DB StorageSystemModels::StorageSystemModels(const std::string & name) : name{name} { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "name", std::make_shared() }, { "origin", std::make_shared() }, { "type", std::make_shared() }, { "creation_time", std::make_shared() }, - { "last_exception", std::make_shared() } - }; + { "last_exception", std::make_shared() }, + }); } diff --git a/dbms/src/Storages/System/StorageSystemNumbers.cpp b/dbms/src/Storages/System/StorageSystemNumbers.cpp index 803f651639d..d5e72bcbdc3 100644 --- a/dbms/src/Storages/System/StorageSystemNumbers.cpp +++ b/dbms/src/Storages/System/StorageSystemNumbers.cpp @@ -47,7 +47,7 @@ private: StorageSystemNumbers::StorageSystemNumbers(const std::string & name_, bool multithreaded_, size_t limit_) : name(name_), multithreaded(multithreaded_), limit(limit_) { - columns.ordinary = NamesAndTypesList{{"number", std::make_shared()}}; + columns = ColumnsDescription({{"number", std::make_shared()}}); } diff --git a/dbms/src/Storages/System/StorageSystemOne.cpp b/dbms/src/Storages/System/StorageSystemOne.cpp index f35580c3882..9cd74a7525c 100644 --- a/dbms/src/Storages/System/StorageSystemOne.cpp +++ b/dbms/src/Storages/System/StorageSystemOne.cpp @@ -13,7 +13,7 @@ namespace DB StorageSystemOne::StorageSystemOne(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{{"dummy", std::make_shared()}}; + columns = ColumnsDescription({{"dummy", std::make_shared()}}); } diff --git a/dbms/src/Storages/System/StorageSystemPartsBase.cpp b/dbms/src/Storages/System/StorageSystemPartsBase.cpp index c6dc2a2c551..5143b73955f 100644 --- a/dbms/src/Storages/System/StorageSystemPartsBase.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsBase.cpp @@ -280,7 +280,7 @@ bool StorageSystemPartsBase::hasColumn(const String & column_name) const StorageSystemPartsBase::StorageSystemPartsBase(std::string name_, NamesAndTypesList && columns_) : name(std::move(name_)) { - columns.ordinary = columns_; + columns = ColumnsDescription(std::move(columns_)); } } diff --git a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp index 5f0a584c1d6..326dfbf30ad 100644 --- a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp @@ -61,8 +61,7 @@ void StorageSystemPartsColumns::processNextStorage(MutableColumns & columns, con String default_expression; }; - NamesAndTypesList columns_list = info.storage->columns.getList(); - columns_list.insert(std::end(columns_list), std::begin(info.storage->columns.aliases), std::end(info.storage->columns.aliases)); + NamesAndTypesList columns_list = info.storage->columns.getAll(); const auto & column_defaults = info.storage->columns.defaults; std::unordered_map columns_info; diff --git a/dbms/src/Storages/System/StorageSystemProcesses.cpp b/dbms/src/Storages/System/StorageSystemProcesses.cpp index e8262723d89..15ecc1a3d95 100644 --- a/dbms/src/Storages/System/StorageSystemProcesses.cpp +++ b/dbms/src/Storages/System/StorageSystemProcesses.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemProcesses::StorageSystemProcesses(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "is_initial_query", std::make_shared() }, { "user", std::make_shared() }, @@ -50,8 +50,8 @@ StorageSystemProcesses::StorageSystemProcesses(const std::string & name_) { "written_bytes", std::make_shared() }, { "memory_usage", std::make_shared() }, { "peak_memory_usage", std::make_shared() }, - { "query", std::make_shared() } - }; + { "query", std::make_shared() }, + }); } diff --git a/dbms/src/Storages/System/StorageSystemReplicas.cpp b/dbms/src/Storages/System/StorageSystemReplicas.cpp index ca240a80568..fdcc6984861 100644 --- a/dbms/src/Storages/System/StorageSystemReplicas.cpp +++ b/dbms/src/Storages/System/StorageSystemReplicas.cpp @@ -17,7 +17,7 @@ namespace DB StorageSystemReplicas::StorageSystemReplicas(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "database", std::make_shared() }, { "table", std::make_shared() }, { "engine", std::make_shared() }, @@ -44,7 +44,7 @@ StorageSystemReplicas::StorageSystemReplicas(const std::string & name_) { "absolute_delay", std::make_shared() }, { "total_replicas", std::make_shared() }, { "active_replicas", std::make_shared() }, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp b/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp index 363306437bb..b0ba714fef4 100644 --- a/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp +++ b/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp @@ -20,7 +20,7 @@ namespace DB StorageSystemReplicationQueue::StorageSystemReplicationQueue(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ /// Table properties. { "database", std::make_shared() }, { "table", std::make_shared() }, @@ -43,7 +43,7 @@ StorageSystemReplicationQueue::StorageSystemReplicationQueue(const std::string & { "num_postponed", std::make_shared() }, { "postpone_reason", std::make_shared() }, { "last_postpone_time", std::make_shared() }, - }; + }); } diff --git a/dbms/src/Storages/System/StorageSystemSettings.cpp b/dbms/src/Storages/System/StorageSystemSettings.cpp index 3848583688b..d8a758becc7 100644 --- a/dbms/src/Storages/System/StorageSystemSettings.cpp +++ b/dbms/src/Storages/System/StorageSystemSettings.cpp @@ -14,12 +14,12 @@ namespace DB StorageSystemSettings::StorageSystemSettings(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "name", std::make_shared() }, { "value", std::make_shared() }, { "changed", std::make_shared() }, - { "description", std::make_shared() } - }; + { "description", std::make_shared() }, + }); } diff --git a/dbms/src/Storages/System/StorageSystemTables.cpp b/dbms/src/Storages/System/StorageSystemTables.cpp index 91ab3581bc8..2db2a8052cc 100644 --- a/dbms/src/Storages/System/StorageSystemTables.cpp +++ b/dbms/src/Storages/System/StorageSystemTables.cpp @@ -114,7 +114,7 @@ protected: StorageSystemTables::StorageSystemTables(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList + columns = ColumnsDescription( { {"database", std::make_shared()}, {"name", std::make_shared()}, @@ -122,7 +122,7 @@ StorageSystemTables::StorageSystemTables(const std::string & name_) {"is_temporary", std::make_shared()}, {"data_path", std::make_shared()}, {"metadata_path", std::make_shared()}, - }; + }); virtual_columns = { diff --git a/dbms/src/Storages/System/StorageSystemZooKeeper.cpp b/dbms/src/Storages/System/StorageSystemZooKeeper.cpp index 9aae0ce5b3b..a5d5e2dab96 100644 --- a/dbms/src/Storages/System/StorageSystemZooKeeper.cpp +++ b/dbms/src/Storages/System/StorageSystemZooKeeper.cpp @@ -22,7 +22,7 @@ namespace DB StorageSystemZooKeeper::StorageSystemZooKeeper(const std::string & name_) : name(name_) { - columns.ordinary = NamesAndTypesList{ + columns = ColumnsDescription({ { "name", std::make_shared() }, { "value", std::make_shared() }, { "czxid", std::make_shared() }, @@ -37,7 +37,7 @@ StorageSystemZooKeeper::StorageSystemZooKeeper(const std::string & name_) { "numChildren", std::make_shared() }, { "pzxid", std::make_shared() }, { "path", std::make_shared() }, - }; + }); } diff --git a/dbms/src/Storages/tests/hit_log.cpp b/dbms/src/Storages/tests/hit_log.cpp index 3dd75206a2b..305974b22d9 100644 --- a/dbms/src/Storages/tests/hit_log.cpp +++ b/dbms/src/Storages/tests/hit_log.cpp @@ -98,8 +98,8 @@ try /// create a hit log table - StoragePtr table = StorageLog::create("./", "HitLog", names_and_types_list, - NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + StoragePtr table = StorageLog::create( + "./", "HitLog", ColumnsDescription{names_and_types_list}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); table->startup(); /// create a description of how to read data from the tab separated dump diff --git a/dbms/src/Storages/tests/storage_log.cpp b/dbms/src/Storages/tests/storage_log.cpp index da53fcc356d..edad84b5b8c 100644 --- a/dbms/src/Storages/tests/storage_log.cpp +++ b/dbms/src/Storages/tests/storage_log.cpp @@ -25,8 +25,8 @@ try names_and_types.emplace_back("a", std::make_shared()); names_and_types.emplace_back("b", std::make_shared()); - StoragePtr table = StorageLog::create("./", "test", names_and_types, - NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + StoragePtr table = StorageLog::create( + "./", "test", ColumnsDescription{names_and_types}, DEFAULT_MAX_COMPRESS_BLOCK_SIZE); table->startup(); /// write into it @@ -36,7 +36,7 @@ try { ColumnWithTypeAndName column; column.name = "a"; - column.type = table->columns.getColumn("a").type; + column.type = table->getColumn("a").type; auto col = column.type->createColumn(); ColumnUInt64::Container & vec = typeid_cast(*col).getData(); @@ -51,7 +51,7 @@ try { ColumnWithTypeAndName column; column.name = "b"; - column.type = table->columns.getColumn("b").type; + column.type = table->getColumn("b").type; auto col = column.type->createColumn(); ColumnUInt8::Container & vec = typeid_cast(*col).getData(); diff --git a/dbms/src/TableFunctions/TableFunctionMerge.cpp b/dbms/src/TableFunctions/TableFunctionMerge.cpp index b471969b847..2a12dbca275 100644 --- a/dbms/src/TableFunctions/TableFunctionMerge.cpp +++ b/dbms/src/TableFunctions/TableFunctionMerge.cpp @@ -51,7 +51,7 @@ static NamesAndTypesList chooseColumns(const String & source_database, const Str throw Exception("Error while executing table function merge. In database " + source_database + " no one matches regular expression: " + table_name_regexp_, ErrorCodes::UNKNOWN_TABLE); - return any_table->columns.getList(); + return any_table->columns.getPhysical(); } @@ -79,12 +79,7 @@ StoragePtr TableFunctionMerge::executeImpl(const ASTPtr & ast_function, const Co auto res = StorageMerge::create( getName(), - ColumnsDescription{ - chooseColumns(source_database, table_name_regexp, context), - NamesAndTypesList{}, - NamesAndTypesList{}, - ColumnDefaults{}, - }, + ColumnsDescription{chooseColumns(source_database, table_name_regexp, context)}, source_database, table_name_regexp, context); diff --git a/dbms/src/TableFunctions/TableFunctionMySQL.cpp b/dbms/src/TableFunctions/TableFunctionMySQL.cpp index 1ced8800255..1f7839ada86 100644 --- a/dbms/src/TableFunctions/TableFunctionMySQL.cpp +++ b/dbms/src/TableFunctions/TableFunctionMySQL.cpp @@ -152,7 +152,7 @@ StoragePtr TableFunctionMySQL::executeImpl(const ASTPtr & ast_function, const Co std::move(pool), database_name, table_name, - ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); + ColumnsDescription{columns}); res->startup(); return res; diff --git a/dbms/src/TableFunctions/TableFunctionODBC.cpp b/dbms/src/TableFunctions/TableFunctionODBC.cpp index cacdbe29670..b75e48de054 100644 --- a/dbms/src/TableFunctions/TableFunctionODBC.cpp +++ b/dbms/src/TableFunctions/TableFunctionODBC.cpp @@ -113,8 +113,7 @@ StoragePtr TableFunctionODBC::executeImpl(const ASTPtr & ast_function, const Con columns.emplace_back(reinterpret_cast(column_name), getDataType(type)); } - auto result = StorageODBC::create(table_name, connection_string, "", table_name, - ColumnsDescription{columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{}}); + auto result = StorageODBC::create(table_name, connection_string, "", table_name, ColumnsDescription{columns}); result->startup(); return result; } diff --git a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp index 181448714ba..2c56688c522 100644 --- a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp +++ b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp @@ -32,7 +32,7 @@ NamesAndTypesList getStructureOfRemoteTable( const auto & shard_info = cluster.getAnyShardInfo(); if (shard_info.isLocal()) - return context.getTable(database, table)->columns.getList(); + return context.getTable(database, table)->columns.getPhysical(); auto input = std::make_shared(shard_info.pool, query, InterpreterDescribeQuery::getSampleBlock(), context); input->setPoolMode(PoolMode::GET_ONE); From de1db216a50ea83323d8c2cb9dae21e80d0fbee2 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Mon, 12 Mar 2018 16:47:01 +0300 Subject: [PATCH 033/244] getStructureOfRemoteTable returns info about column default kinds [#CLICKHOUSE-3241] --- .../Interpreters/InterpreterAlterQuery.cpp | 4 +- .../Interpreters/InterpreterCreateQuery.cpp | 12 +++--- .../Interpreters/InterpreterDescribeQuery.cpp | 2 +- .../Interpreters/InterpreterSelectQuery.cpp | 5 ++- dbms/src/Server/ClusterCopier.cpp | 4 +- dbms/src/Storages/AlterCommands.cpp | 28 ++++++------ dbms/src/Storages/AlterCommands.h | 6 +-- dbms/src/Storages/ColumnDefault.cpp | 26 +++++------ dbms/src/Storages/ColumnDefault.h | 8 ++-- dbms/src/Storages/ColumnsDescription.cpp | 16 +++---- dbms/src/Storages/StorageCatBoostPool.cpp | 2 +- dbms/src/Storages/StorageDistributed.cpp | 5 +-- dbms/src/Storages/StorageDistributed.h | 2 +- .../Storages/System/StorageSystemColumns.cpp | 2 +- .../System/StorageSystemPartsColumns.cpp | 2 +- .../getStructureOfRemoteTable.cpp | 43 ++++++++++++++----- .../getStructureOfRemoteTable.h | 4 +- 17 files changed, 97 insertions(+), 74 deletions(-) diff --git a/dbms/src/Interpreters/InterpreterAlterQuery.cpp b/dbms/src/Interpreters/InterpreterAlterQuery.cpp index 1fb3e1e80db..08254c8e8f8 100644 --- a/dbms/src/Interpreters/InterpreterAlterQuery.cpp +++ b/dbms/src/Interpreters/InterpreterAlterQuery.cpp @@ -110,7 +110,7 @@ void InterpreterAlterQuery::parseAlter( } if (ast_col_decl.default_expression) { - command.default_type = columnDefaultTypeFromString(ast_col_decl.default_specifier); + command.default_kind = columnDefaultKindFromString(ast_col_decl.default_specifier); command.default_expression = ast_col_decl.default_expression; } @@ -157,7 +157,7 @@ void InterpreterAlterQuery::parseAlter( if (ast_col_decl.default_expression) { - command.default_type = columnDefaultTypeFromString(ast_col_decl.default_specifier); + command.default_kind = columnDefaultKindFromString(ast_col_decl.default_specifier); command.default_expression = ast_col_decl.default_expression; } diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index e5d20648fbd..43f4336f896 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -246,7 +246,7 @@ static ColumnsAndDefaults parseColumns(const ASTExpressionList & column_list_ast explicit_type = block.getByName(column_name).type; defaults.emplace(column_name, ColumnDefault{ - columnDefaultTypeFromString(col_decl_ptr->default_specifier), + columnDefaultKindFromString(col_decl_ptr->default_specifier), col_decl_ptr->default_expression }); } @@ -256,7 +256,7 @@ static ColumnsAndDefaults parseColumns(const ASTExpressionList & column_list_ast } -static NamesAndTypesList removeAndReturnColumns(ColumnsAndDefaults & columns_and_defaults, const ColumnDefaultType type) +static NamesAndTypesList removeAndReturnColumns(ColumnsAndDefaults & columns_and_defaults, const ColumnDefaultKind kind) { auto & columns = columns_and_defaults.first; auto & defaults = columns_and_defaults.second; @@ -266,7 +266,7 @@ static NamesAndTypesList removeAndReturnColumns(ColumnsAndDefaults & columns_and for (auto it = std::begin(columns); it != std::end(columns);) { const auto jt = defaults.find(it->name); - if (jt != std::end(defaults) && jt->second.type == type) + if (jt != std::end(defaults) && jt->second.kind == kind) { removed.push_back(*it); it = columns.erase(it); @@ -323,7 +323,7 @@ ASTPtr InterpreterCreateQuery::formatColumns(const ColumnsDescription & columns) const auto it = columns.defaults.find(column.name); if (it != std::end(columns.defaults)) { - column_declaration->default_specifier = toString(it->second.type); + column_declaration->default_specifier = toString(it->second.kind); column_declaration->default_expression = it->second.expression->clone(); } @@ -339,8 +339,8 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription(const ASTExpres ColumnsDescription res; auto && columns_and_defaults = parseColumns(columns, context); - res.materialized = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Materialized); - res.aliases = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Alias); + res.materialized = removeAndReturnColumns(columns_and_defaults, ColumnDefaultKind::Materialized); + res.aliases = removeAndReturnColumns(columns_and_defaults, ColumnDefaultKind::Alias); res.ordinary = std::move(columns_and_defaults.first); res.defaults = std::move(columns_and_defaults.second); diff --git a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp index c03034af49a..07eefbd913b 100644 --- a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp +++ b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp @@ -119,7 +119,7 @@ BlockInputStreamPtr InterpreterDescribeQuery::executeImpl() } else { - res_columns[2]->insert(toString(it->second.type)); + res_columns[2]->insert(toString(it->second.kind)); res_columns[3]->insert(queryToString(it->second.expression)); } } diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 04e05e975ac..ba93c737f08 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -521,7 +521,7 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline for (const auto & column : required_columns) { const auto default_it = storage->columns.defaults.find(column); - if (default_it != std::end(storage->columns.defaults) && default_it->second.type == ColumnDefaultType::Alias) + if (default_it != std::end(storage->columns.defaults) && default_it->second.kind == ColumnDefaultKind::Alias) { alias_columns_required = true; break; @@ -536,7 +536,7 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline for (const auto & column : required_columns) { const auto default_it = storage->columns.defaults.find(column); - if (default_it != std::end(storage->columns.defaults) && default_it->second.type == ColumnDefaultType::Alias) + if (default_it != std::end(storage->columns.defaults) && default_it->second.kind == ColumnDefaultKind::Alias) required_columns_expr_list->children.emplace_back(setAlias(default_it->second.expression->clone(), column)); else required_columns_expr_list->children.emplace_back(std::make_shared(column)); @@ -711,6 +711,7 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline else throw Exception("Logical error in InterpreterSelectQuery: nowhere to read", ErrorCodes::LOGICAL_ERROR); + StackTrace st; /// Aliases in table declaration. if (from_stage == QueryProcessingStage::FetchColumns && alias_actions) { diff --git a/dbms/src/Server/ClusterCopier.cpp b/dbms/src/Server/ClusterCopier.cpp index 77172a22b23..3ae6a9ed205 100644 --- a/dbms/src/Server/ClusterCopier.cpp +++ b/dbms/src/Server/ClusterCopier.cpp @@ -1120,8 +1120,8 @@ protected: if (!column.default_specifier.empty()) { - ColumnDefaultType type = columnDefaultTypeFromString(column.default_specifier); - if (type == ColumnDefaultType::Materialized || type == ColumnDefaultType::Alias) + ColumnDefaultKind kind = columnDefaultKindFromString(column.default_specifier); + if (kind == ColumnDefaultKind::Materialized || kind == ColumnDefaultKind::Alias) continue; } diff --git a/dbms/src/Storages/AlterCommands.cpp b/dbms/src/Storages/AlterCommands.cpp index 184f63c070f..6c16acf5300 100644 --- a/dbms/src/Storages/AlterCommands.cpp +++ b/dbms/src/Storages/AlterCommands.cpp @@ -57,17 +57,17 @@ void AlterCommand::apply(ColumnsDescription & columns_description) const columns.emplace(insert_it, column_name, data_type); }; - if (default_type == ColumnDefaultType::Default) + if (default_kind == ColumnDefaultKind::Default) add_column(columns_description.ordinary); - else if (default_type == ColumnDefaultType::Materialized) + else if (default_kind == ColumnDefaultKind::Materialized) add_column(columns_description.materialized); - else if (default_type == ColumnDefaultType::Alias) + else if (default_kind == ColumnDefaultKind::Alias) add_column(columns_description.aliases); else - throw Exception{"Unknown ColumnDefaultType value", ErrorCodes::LOGICAL_ERROR}; + throw Exception{"Unknown ColumnDefaultKind value", ErrorCodes::LOGICAL_ERROR}; if (default_expression) - columns_description.defaults.emplace(column_name, ColumnDefault{default_type, default_expression}); + columns_description.defaults.emplace(column_name, ColumnDefault{default_kind, default_expression}); /// Slow, because each time a list is copied columns_description.ordinary = Nested::flatten(columns_description.ordinary); @@ -103,12 +103,12 @@ void AlterCommand::apply(ColumnsDescription & columns_description) const { const auto default_it = columns_description.defaults.find(column_name); const auto had_default_expr = default_it != std::end(columns_description.defaults); - const auto old_default_type = had_default_expr ? default_it->second.type : ColumnDefaultType{}; + const auto old_default_kind = had_default_expr ? default_it->second.kind : ColumnDefaultKind{}; /// target column list auto & new_columns = - default_type == ColumnDefaultType::Default ? columns_description.ordinary - : default_type == ColumnDefaultType::Materialized ? columns_description.materialized + default_kind == ColumnDefaultKind::Default ? columns_description.ordinary + : default_kind == ColumnDefaultKind::Materialized ? columns_description.materialized : columns_description.aliases; /// find column or throw exception @@ -124,12 +124,12 @@ void AlterCommand::apply(ColumnsDescription & columns_description) const }; /// if default types differ, remove column from the old list, then add to the new list - if (default_type != old_default_type) + if (default_kind != old_default_kind) { /// source column list auto & old_columns = - old_default_type == ColumnDefaultType::Default ? columns_description.ordinary - : old_default_type == ColumnDefaultType::Materialized ? columns_description.materialized + old_default_kind == ColumnDefaultKind::Default ? columns_description.ordinary + : old_default_kind == ColumnDefaultKind::Materialized ? columns_description.materialized : columns_description.aliases; const auto old_column_it = find_column(old_columns); @@ -138,7 +138,7 @@ void AlterCommand::apply(ColumnsDescription & columns_description) const /// do not forget to change the default type of old column if (had_default_expr) - columns_description.defaults[column_name].type = default_type; + columns_description.defaults[column_name].kind = default_kind; } /// find column in one of three column lists @@ -150,7 +150,7 @@ void AlterCommand::apply(ColumnsDescription & columns_description) const columns_description.defaults.erase(column_name); else if (default_expression && !had_default_expr) /// new column has a default expression while the old one had not, add it it column_defaults - columns_description.defaults.emplace(column_name, ColumnDefault{default_type, default_expression}); + columns_description.defaults.emplace(column_name, ColumnDefault{default_kind, default_expression}); else if (had_default_expr) /// both old and new columns have default expression, update it columns_description.defaults[column_name].expression = default_expression; @@ -333,7 +333,7 @@ void AlterCommands::validate(IStorage * table, const Context & context) /// add a new alter command to modify existing column this->emplace_back(AlterCommand{ AlterCommand::MODIFY_COLUMN, column_name, explicit_type, - default_it->second.type, default_it->second.expression + default_it->second.kind, default_it->second.expression }); command_ptr = &this->back(); diff --git a/dbms/src/Storages/AlterCommands.h b/dbms/src/Storages/AlterCommands.h index 44c44e8bfd0..306d5cec54c 100644 --- a/dbms/src/Storages/AlterCommands.h +++ b/dbms/src/Storages/AlterCommands.h @@ -27,7 +27,7 @@ struct AlterCommand /// For ADD and MODIFY, a new column type. DataTypePtr data_type; - ColumnDefaultType default_type{}; + ColumnDefaultKind default_kind{}; ASTPtr default_expression{}; /// For ADD - after which column to add a new one. If an empty string, add to the end. To add to the beginning now it is impossible. @@ -47,9 +47,9 @@ struct AlterCommand AlterCommand() = default; AlterCommand(const Type type, const String & column_name, const DataTypePtr & data_type, - const ColumnDefaultType default_type, const ASTPtr & default_expression, + const ColumnDefaultKind default_kind, const ASTPtr & default_expression, const String & after_column = String{}) - : type{type}, column_name{column_name}, data_type{data_type}, default_type{default_type}, + : type{type}, column_name{column_name}, data_type{data_type}, default_kind{default_kind}, default_expression{default_expression}, after_column{after_column} {} }; diff --git a/dbms/src/Storages/ColumnDefault.cpp b/dbms/src/Storages/ColumnDefault.cpp index dcdfe2a6e51..0ff885ab1e5 100644 --- a/dbms/src/Storages/ColumnDefault.cpp +++ b/dbms/src/Storages/ColumnDefault.cpp @@ -6,12 +6,12 @@ namespace DB { -ColumnDefaultType columnDefaultTypeFromString(const std::string & str) +ColumnDefaultKind columnDefaultKindFromString(const std::string & str) { - static const std::unordered_map map{ - { "DEFAULT", ColumnDefaultType::Default }, - { "MATERIALIZED", ColumnDefaultType::Materialized }, - { "ALIAS", ColumnDefaultType::Alias } + static const std::unordered_map map{ + { "DEFAULT", ColumnDefaultKind::Default }, + { "MATERIALIZED", ColumnDefaultKind::Materialized }, + { "ALIAS", ColumnDefaultKind::Alias } }; const auto it = map.find(str); @@ -19,22 +19,22 @@ ColumnDefaultType columnDefaultTypeFromString(const std::string & str) } -std::string toString(const ColumnDefaultType type) +std::string toString(const ColumnDefaultKind kind) { - static const std::unordered_map map{ - { ColumnDefaultType::Default, "DEFAULT" }, - { ColumnDefaultType::Materialized, "MATERIALIZED" }, - { ColumnDefaultType::Alias, "ALIAS" } + static const std::unordered_map map{ + { ColumnDefaultKind::Default, "DEFAULT" }, + { ColumnDefaultKind::Materialized, "MATERIALIZED" }, + { ColumnDefaultKind::Alias, "ALIAS" } }; - const auto it = map.find(type); - return it != std::end(map) ? it->second : throw Exception{"Invalid ColumnDefaultType"}; + const auto it = map.find(kind); + return it != std::end(map) ? it->second : throw Exception{"Invalid ColumnDefaultKind"}; } bool operator==(const ColumnDefault & lhs, const ColumnDefault & rhs) { - return lhs.type == rhs.type && queryToString(lhs.expression) == queryToString(rhs.expression); + return lhs.kind == rhs.kind && queryToString(lhs.expression) == queryToString(rhs.expression); } } diff --git a/dbms/src/Storages/ColumnDefault.h b/dbms/src/Storages/ColumnDefault.h index 33f17952d08..95eb4d5b597 100644 --- a/dbms/src/Storages/ColumnDefault.h +++ b/dbms/src/Storages/ColumnDefault.h @@ -9,7 +9,7 @@ namespace DB { -enum class ColumnDefaultType +enum class ColumnDefaultKind { Default, Materialized, @@ -17,13 +17,13 @@ enum class ColumnDefaultType }; -ColumnDefaultType columnDefaultTypeFromString(const std::string & str); -std::string toString(const ColumnDefaultType type); +ColumnDefaultKind columnDefaultKindFromString(const std::string & str); +std::string toString(const ColumnDefaultKind type); struct ColumnDefault { - ColumnDefaultType type; + ColumnDefaultKind kind; ASTPtr expression; }; diff --git a/dbms/src/Storages/ColumnsDescription.cpp b/dbms/src/Storages/ColumnsDescription.cpp index 95b5001a1f9..683f10f324d 100644 --- a/dbms/src/Storages/ColumnsDescription.cpp +++ b/dbms/src/Storages/ColumnsDescription.cpp @@ -88,7 +88,7 @@ String ColumnsDescription::toString() const else writeChar('\t', buf); - writeString(DB::toString(it->second.type), buf); + writeString(DB::toString(it->second.kind), buf); writeChar('\t', buf); writeString(queryToString(it->second.expression), buf); writeChar('\n', buf); @@ -134,9 +134,9 @@ ColumnsDescription ColumnsDescription::parse(const String & str) } assertChar('\t', buf); - String default_type_str; - readString(default_type_str, buf); - const auto default_type = columnDefaultTypeFromString(default_type_str); + String default_kind_str; + readString(default_kind_str, buf); + const auto default_kind = columnDefaultKindFromString(default_kind_str); assertChar('\t', buf); String default_expr_str; @@ -147,14 +147,14 @@ ColumnsDescription ColumnsDescription::parse(const String & str) const auto end = begin + default_expr_str.size(); ASTPtr default_expr = parseQuery(expr_parser, begin, end, "default expression"); - if (ColumnDefaultType::Default == default_type) + if (ColumnDefaultKind::Default == default_kind) result.ordinary.emplace_back(column_name, std::move(type)); - else if (ColumnDefaultType::Materialized == default_type) + else if (ColumnDefaultKind::Materialized == default_kind) result.materialized.emplace_back(column_name, std::move(type)); - else if (ColumnDefaultType::Alias == default_type) + else if (ColumnDefaultKind::Alias == default_kind) result.aliases.emplace_back(column_name, std::move(type)); - result.defaults.emplace(column_name, ColumnDefault{default_type, default_expr}); + result.defaults.emplace(column_name, ColumnDefault{default_kind, default_expr}); } assertEOF(buf); diff --git a/dbms/src/Storages/StorageCatBoostPool.cpp b/dbms/src/Storages/StorageCatBoostPool.cpp index 1a973f7dd75..d20da89b170 100644 --- a/dbms/src/Storages/StorageCatBoostPool.cpp +++ b/dbms/src/Storages/StorageCatBoostPool.cpp @@ -243,7 +243,7 @@ void StorageCatBoostPool::createSampleBlockAndColumns() if (!desc.alias.empty()) { auto alias = std::make_shared(desc.column_name); - columns.defaults[desc.alias] = {ColumnDefaultType::Alias, alias}; + columns.defaults[desc.alias] = {ColumnDefaultKind::Alias, alias}; columns.aliases.emplace_back(desc.alias, type); } diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index c010ca768d1..e3ff7f30369 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -151,15 +151,14 @@ StorageDistributed::StorageDistributed( StoragePtr StorageDistributed::createWithOwnCluster( const std::string & name_, - const NamesAndTypesList & columns_, + const ColumnsDescription & columns_, const String & remote_database_, const String & remote_table_, ClusterPtr & owned_cluster_, const Context & context_) { auto res = ext::shared_ptr_helper::create( - name_, ColumnsDescription{columns_}, - remote_database_, remote_table_, String{}, context_, ASTPtr(), String()); + name_, columns_, remote_database_, remote_table_, String{}, context_, ASTPtr(), String()); res->owned_cluster = owned_cluster_; diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 22e24c3f9fb..451c9f12d8a 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -35,7 +35,7 @@ public: static StoragePtr createWithOwnCluster( const std::string & table_name_, - const NamesAndTypesList & columns_, + const ColumnsDescription & columns_, const String & remote_database_, /// database on remote servers. const String & remote_table_, /// The name of the table on the remote servers. ClusterPtr & owned_cluster_, diff --git a/dbms/src/Storages/System/StorageSystemColumns.cpp b/dbms/src/Storages/System/StorageSystemColumns.cpp index 75c8afa1515..83c5dca9117 100644 --- a/dbms/src/Storages/System/StorageSystemColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemColumns.cpp @@ -171,7 +171,7 @@ BlockInputStreams StorageSystemColumns::read( } else { - res_columns[i++]->insert(toString(it->second.type)); + res_columns[i++]->insert(toString(it->second.kind)); res_columns[i++]->insert(queryToString(it->second.expression)); } } diff --git a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp index 326dfbf30ad..d804504f13a 100644 --- a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp @@ -72,7 +72,7 @@ void StorageSystemPartsColumns::processNextStorage(MutableColumns & columns, con const auto it = column_defaults.find(column.name); if (it != std::end(column_defaults)) { - column_info.default_kind = toString(it->second.type); + column_info.default_kind = toString(it->second.kind); column_info.default_expression = queryToString(it->second.expression); } diff --git a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp index 2c56688c522..6eede709352 100644 --- a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp +++ b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp @@ -1,12 +1,12 @@ +#include #include #include #include #include #include #include -#include - -#include +#include +#include namespace DB @@ -18,21 +18,21 @@ namespace ErrorCodes } -NamesAndTypesList getStructureOfRemoteTable( +ColumnsDescription getStructureOfRemoteTable( const Cluster & cluster, const std::string & database, const std::string & table, const Context & context) { - /// Request for a table description - String query = "DESC TABLE " + backQuoteIfNeed(database) + "." + backQuoteIfNeed(table); - NamesAndTypesList res; - /// Send to the first any remote shard. const auto & shard_info = cluster.getAnyShardInfo(); if (shard_info.isLocal()) - return context.getTable(database, table)->columns.getPhysical(); + return context.getTable(database, table)->columns; + + /// Request for a table description + String query = "DESC TABLE " + backQuoteIfNeed(database) + "." + backQuoteIfNeed(table); + ColumnsDescription res; auto input = std::make_shared(shard_info.pool, query, InterpreterDescribeQuery::getSampleBlock(), context); input->setPoolMode(PoolMode::GET_ONE); @@ -41,18 +41,41 @@ NamesAndTypesList getStructureOfRemoteTable( const DataTypeFactory & data_type_factory = DataTypeFactory::instance(); + ParserExpression expr_parser; + while (Block current = input->read()) { ColumnPtr name = current.getByName("name").column; ColumnPtr type = current.getByName("type").column; + ColumnPtr default_kind = current.getByName("default_type").column; + ColumnPtr default_expr = current.getByName("default_expression").column; size_t size = name->size(); for (size_t i = 0; i < size; ++i) { String column_name = (*name)[i].get(); String data_type_name = (*type)[i].get(); + String kind_name = (*default_kind)[i].get(); - res.emplace_back(column_name, data_type_factory.get(data_type_name)); + auto data_type = data_type_factory.get(data_type_name); + + if (kind_name.empty()) + res.ordinary.emplace_back(column_name, std::move(data_type)); + else + { + auto kind = columnDefaultKindFromString(kind_name); + + String expr_str = (*default_expr)[i].get(); + ASTPtr expr = parseQuery(expr_parser, expr_str.data(), expr_str.data() + expr_str.size(), "default expression"); + res.defaults.emplace(column_name, ColumnDefault{kind, expr}); + + if (ColumnDefaultKind::Default == kind) + res.ordinary.emplace_back(column_name, std::move(data_type)); + else if (ColumnDefaultKind::Materialized == kind) + res.materialized.emplace_back(column_name, std::move(data_type)); + else if (ColumnDefaultKind::Alias == kind) + res.aliases.emplace_back(column_name, std::move(data_type)); + } } } diff --git a/dbms/src/TableFunctions/getStructureOfRemoteTable.h b/dbms/src/TableFunctions/getStructureOfRemoteTable.h index 70b3d83b8f1..20417ef50e1 100644 --- a/dbms/src/TableFunctions/getStructureOfRemoteTable.h +++ b/dbms/src/TableFunctions/getStructureOfRemoteTable.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace DB @@ -11,7 +11,7 @@ class Context; /// Find the names and types of the table columns on any server in the cluster. /// Used to implement the `remote` table function and others. -NamesAndTypesList getStructureOfRemoteTable( +ColumnsDescription getStructureOfRemoteTable( const Cluster & cluster, const std::string & database, const std::string & table, From d51e0b72563a2492cbf6d2d20020f5fa36c7a1c5 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Tue, 13 Mar 2018 12:58:21 +0300 Subject: [PATCH 034/244] Update reference.md --- docs/en/agg_functions/reference.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/docs/en/agg_functions/reference.md b/docs/en/agg_functions/reference.md index d907f79647c..90ff9da58e7 100644 --- a/docs/en/agg_functions/reference.md +++ b/docs/en/agg_functions/reference.md @@ -19,7 +19,7 @@ In some cases, you can rely on the order of execution. This applies to cases whe When a `SELECT` query has the `GROUP BY` clause or at least one aggregate function, ClickHouse (in contrast to MySQL) requires that all expressions in the `SELECT`, `HAVING`, and `ORDER BY` clauses be calculated from keys or from aggregate functions. In other words, each column selected from the table must be used either in keys or inside aggregate functions. To get behavior like in MySQL, you can put the other columns in the `any` aggregate function. -## anyHeavy +## anyHeavy(x) Selects a frequently occurring value using the [heavy hitters](http://www.cs.umd.edu/~samir/498/karp.pdf) algorithm. If there is a value that occurs more than in half the cases in each of the query's execution threads, this value is returned. Normally, the result is nondeterministic. @@ -33,7 +33,7 @@ anyHeavy(column) **Example** -Take the [OnTime](../getting_started/example_datasets/ontime.md#example_datasets-ontime)data set and select any frequently occurring value in the `AirlineID` column. +Take the [OnTime](../getting_started/example_datasets/ontime.md#example_datasets-ontime) data set and select any frequently occurring value in the `AirlineID` column. ```sql SELECT anyHeavy(AirlineID) AS res @@ -170,7 +170,7 @@ In some cases, you can still rely on the order of execution. This applies to cas -## groupArrayInsertAt +## groupArrayInsertAt(x) Inserts a value into the array in the specified position. @@ -257,7 +257,7 @@ The performance of the function is lower than for ` quantile`, ` quantileTiming` The result depends on the order of running the query, and is nondeterministic. -## median +## median(x) All the quantile functions have corresponding median functions: `median`, `medianDeterministic`, `medianTiming`, `medianTimingWeighted`, `medianExact`, `medianExactWeighted`, `medianTDigest`. They are synonyms and their behavior is identical. @@ -287,16 +287,12 @@ The result is equal to the square root of `varSamp(x)`. The result is equal to the square root of `varPop(x)`. -## topK +## topK(N)(column) Returns an array of the most frequent values in the specified column. The resulting array is sorted in descending order of frequency of values (not by the values themselves). Implements the [ Filtered Space-Saving](http://www.l2f.inesc-id.pt/~fmmb/wiki/uploads/Work/misnis.ref0a.pdf) algorithm for analyzing TopK, based on the reduce-and-combine algorithm from [Parallel Space Saving](https://arxiv.org/pdf/1401.0702.pdf). -``` -topK(N)(column) -``` - This function doesn't provide a guaranteed result. In certain situations, errors might occur and it might return frequent values that aren't the most frequent values. We recommend using the `N < 10 ` value; performance is reduced with large `N` values. Maximum value of ` N = 65536`. From 632a2ecabc59f78de86c52f84b122149b6dd8841 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 13 Mar 2018 13:41:47 +0300 Subject: [PATCH 035/244] added SYSTEM RELOAD CONFIG query [#CLICKHOUSE-3591] --- dbms/src/Common/Config/ConfigReloader.cpp | 2 ++ dbms/src/Common/Config/ConfigReloader.h | 6 ++++++ dbms/src/Interpreters/Context.cpp | 18 ++++++++++++++++++ dbms/src/Interpreters/Context.h | 4 ++++ .../Interpreters/InterpreterSystemQuery.cpp | 3 +++ dbms/src/Parsers/ASTSystemQuery.cpp | 2 ++ dbms/src/Parsers/ASTSystemQuery.h | 1 + dbms/src/Server/Server.cpp | 6 ++++++ 8 files changed, 42 insertions(+) diff --git a/dbms/src/Common/Config/ConfigReloader.cpp b/dbms/src/Common/Config/ConfigReloader.cpp index 54cbf507055..e06fca6316a 100644 --- a/dbms/src/Common/Config/ConfigReloader.cpp +++ b/dbms/src/Common/Config/ConfigReloader.cpp @@ -73,6 +73,8 @@ void ConfigReloader::run() void ConfigReloader::reloadIfNewer(bool force, bool throw_on_error, bool fallback_to_preprocessed) { + std::lock_guard lock(reload_mutex); + FilesChangesTracker new_files = getNewFileList(); if (force || new_files.isDifferOrNewerThan(files)) { diff --git a/dbms/src/Common/Config/ConfigReloader.h b/dbms/src/Common/Config/ConfigReloader.h index 94b2d3c629c..74a5294832b 100644 --- a/dbms/src/Common/Config/ConfigReloader.h +++ b/dbms/src/Common/Config/ConfigReloader.h @@ -42,6 +42,9 @@ public: /// Call this method to run the backround thread. void start(); + /// Reload immediately. For SYSTEM RELOAD CONFIG query. + void reload() { reloadIfNewer(/* force */ true, /* throw_on_error */ true, /* fallback_to_preprocessed */ false); } + private: void run(); @@ -74,6 +77,9 @@ private: std::atomic quit{false}; std::thread thread; + + /// Is taken after entering into reloadIfNewer. + std::mutex reload_mutex; }; } diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 7a2358f36c0..6bc4cde2d06 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -186,6 +186,8 @@ struct ContextShared pcg64 rng{randomSeed()}; + Context::ConfigReloadCallback config_reload_callback; + ContextShared(std::shared_ptr runtime_components_factory_) : runtime_components_factory(std::move(runtime_components_factory_)) { @@ -1624,6 +1626,22 @@ time_t Context::getUptimeSeconds() const } +void Context::setConfigReloadCallback(ConfigReloadCallback && callback) +{ + /// Is initialized at server startup, so lock isn't required. Otherwise use mutex. + shared->config_reload_callback = std::move(callback); +} + +void Context::reloadConfig() const +{ + /// Use mutex if callback may be changed after startup. + if (!shared->config_reload_callback) + throw Exception("Can't reload config beacuse config_reload_callback is not set.", ErrorCodes::LOGICAL_ERROR); + + shared->config_reload_callback(); +} + + void Context::shutdown() { system_logs.reset(); diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index 4148b79923b..32ba0b8cd7f 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -361,6 +361,10 @@ public: /// Get the server uptime in seconds. time_t getUptimeSeconds() const; + using ConfigReloadCallback = std::function; + void setConfigReloadCallback(ConfigReloadCallback && callback); + void reloadConfig() const; + void shutdown(); enum class ApplicationType diff --git a/dbms/src/Interpreters/InterpreterSystemQuery.cpp b/dbms/src/Interpreters/InterpreterSystemQuery.cpp index 419a4937a72..ef8197f5ffb 100644 --- a/dbms/src/Interpreters/InterpreterSystemQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSystemQuery.cpp @@ -97,6 +97,9 @@ BlockIO InterpreterSystemQuery::execute() throw Exception(status.message, status.code); break; } + case Type::RELOAD_CONFIG: + context.reloadConfig(); + break; case Type::STOP_LISTEN_QUERIES: case Type::START_LISTEN_QUERIES: case Type::RESTART_REPLICAS: diff --git a/dbms/src/Parsers/ASTSystemQuery.cpp b/dbms/src/Parsers/ASTSystemQuery.cpp index 9f6914e7f4c..a50a98f03d6 100644 --- a/dbms/src/Parsers/ASTSystemQuery.cpp +++ b/dbms/src/Parsers/ASTSystemQuery.cpp @@ -39,6 +39,8 @@ const char * ASTSystemQuery::typeToString(Type type) return "RELOAD DICTIONARY"; case Type::RELOAD_DICTIONARIES: return "RELOAD DICTIONARIES"; + case Type::RELOAD_CONFIG: + return "RELOAD CONFIG"; case Type::STOP_MERGES: return "STOP MERGES"; case Type::START_MERGES: diff --git a/dbms/src/Parsers/ASTSystemQuery.h b/dbms/src/Parsers/ASTSystemQuery.h index 1821b73bc12..87eaded44ef 100644 --- a/dbms/src/Parsers/ASTSystemQuery.h +++ b/dbms/src/Parsers/ASTSystemQuery.h @@ -24,6 +24,7 @@ public: SYNC_REPLICA, RELOAD_DICTIONARY, RELOAD_DICTIONARIES, + RELOAD_CONFIG, STOP_MERGES, START_MERGES, STOP_REPLICATION_QUEUES, diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 08153b00b1d..390eec74f43 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -251,6 +251,12 @@ int Server::main(const std::vector & /*args*/) [&](ConfigurationPtr config) { global_context->setUsersConfig(config); }, /* already_loaded = */ false); + /// Reload config in SYSTEM RELOAD CONFIG query. + global_context->setConfigReloadCallback([&]() { + main_config_reloader->reload(); + users_config_reloader->reload(); + }); + /// Limit on total number of concurrently executed queries. global_context->getProcessList().setMaxSize(config().getInt("max_concurrent_queries", 0)); From 8b802ad7743803df206a194a8c577102994361a7 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 13 Mar 2018 14:47:32 +0300 Subject: [PATCH 036/244] added test for SYSTEM RELOAD CONFIG and system.macros [#CLICKHOUSE-3591] --- dbms/tests/integration/test_system_queries/test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dbms/tests/integration/test_system_queries/test.py b/dbms/tests/integration/test_system_queries/test.py index 063d9c005bd..46ab2561a83 100644 --- a/dbms/tests/integration/test_system_queries/test.py +++ b/dbms/tests/integration/test_system_queries/test.py @@ -74,6 +74,17 @@ def test_DROP_DNS_CACHE(started_cluster): assert TSV(instance.query("SELECT DISTINCT host_name, host_address FROM system.clusters WHERE cluster='lost_host_cluster'")) == TSV("lost_host\t127.0.0.1\n") +def test_RELOAD_CONFIG_AND_MACROS(started_cluster): + + macros = "ro" + create_macros = 'echo "{}" > /etc/clickhouse-server/config.d/macros.xml'.format(macros) + + instance = cluster.instances['ch1'] + + instance.exec_in_container(['bash', '-c', create_macros], privileged=True, user='root') + instance.query("SYSTEM RELOAD CONFIG") + assert TSV(instance.query("select * from system.macros")) == TSV("mac\tro\n") + if __name__ == '__main__': with contextmanager(started_cluster)() as cluster: for name, instance in cluster.instances.items(): From 324cda232ceb5be9212f3513fab68a3e1ca28231 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 13 Mar 2018 14:53:27 +0300 Subject: [PATCH 037/244] fix clang build [#CLICKHOUSE-3591] --- dbms/src/Common/Macros.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/src/Common/Macros.h b/dbms/src/Common/Macros.h index 316d526b5a7..dae3bd10aa9 100644 --- a/dbms/src/Common/Macros.h +++ b/dbms/src/Common/Macros.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace DB From cda51eb920ce3adbb96a15bd01de6bb8b44627bb Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 13 Mar 2018 15:31:58 +0300 Subject: [PATCH 038/244] added fake create query for default database [#CLICKHOUSE-3590] --- dbms/src/Databases/DatabaseOrdinary.cpp | 9 +++++++-- dbms/src/Databases/DatabaseOrdinary.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dbms/src/Databases/DatabaseOrdinary.cpp b/dbms/src/Databases/DatabaseOrdinary.cpp index b0719649094..73152387cf6 100644 --- a/dbms/src/Databases/DatabaseOrdinary.cpp +++ b/dbms/src/Databases/DatabaseOrdinary.cpp @@ -336,16 +336,21 @@ void DatabaseOrdinary::removeTable( } -static ASTPtr getCreateQueryImpl(const String & path, const String & table_name) +ASTPtr DatabaseOrdinary::getCreateQueryImpl(const String & path, const String & table_name) const { String metadata_path; + String query; if (table_name.empty()) + { metadata_path = detail::getDatabaseMetadataPath(path); + if (!Poco::File(metadata_path).exists()) + query = "CREATE DATABASE " + backQuoteIfNeed(name) + " ENGINE = Ordinary"; + } else metadata_path = detail::getTableMetadataPath(path, table_name); - String query; + if (query.empty()) { ReadBufferFromFile in(metadata_path, 4096); readStringUntilEOF(query, in); diff --git a/dbms/src/Databases/DatabaseOrdinary.h b/dbms/src/Databases/DatabaseOrdinary.h index dbd44586c74..4cd77c85895 100644 --- a/dbms/src/Databases/DatabaseOrdinary.h +++ b/dbms/src/Databases/DatabaseOrdinary.h @@ -68,6 +68,7 @@ public: private: void startupTables(ThreadPool * thread_pool); + ASTPtr getCreateQueryImpl(const String & path, const String & table_name) const; }; } From 2f573e4f7714e595d993a4c9eafbebe5245fdd18 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Mon, 12 Mar 2018 21:38:24 +0300 Subject: [PATCH 039/244] add tests [#CLICKHOUSE-3241] --- ...c_table_functions_and_subqueries.reference | 12 +++--- ...remote_and_columns_with_defaults.reference | 13 +++++++ ...shard_remote_and_columns_with_defaults.sql | 38 +++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.reference create mode 100644 dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql diff --git a/dbms/tests/queries/0_stateless/00515_shard_desc_table_functions_and_subqueries.reference b/dbms/tests/queries/0_stateless/00515_shard_desc_table_functions_and_subqueries.reference index 20d07b74593..b0615b7993f 100644 --- a/dbms/tests/queries/0_stateless/00515_shard_desc_table_functions_and_subqueries.reference +++ b/dbms/tests/queries/0_stateless/00515_shard_desc_table_functions_and_subqueries.reference @@ -12,15 +12,15 @@ val4 UInt64 ALIAS val - date Date val UInt64 -val2 UInt8 -val3 UInt8 -val4 UInt64 +val2 UInt8 DEFAULT 42 +val3 UInt8 DEFAULT CAST((val2 + 1) AS UInt8) +val4 UInt64 ALIAS val - date Date val UInt64 -val2 UInt8 -val3 UInt8 -val4 UInt64 +val2 UInt8 DEFAULT 42 +val3 UInt8 DEFAULT CAST((val2 + 1) AS UInt8) +val4 UInt64 ALIAS val - 1 UInt8 - diff --git a/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.reference b/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.reference new file mode 100644 index 00000000000..8a5c72b9000 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.reference @@ -0,0 +1,13 @@ +1 1 +2 2 +*** With a DEFAULT column *** +1 1 +2 2 +*** With a MATERIALIZED column *** +1 +1 2 +*** With an ALIAS column *** +1 +2 +1 2 +2 3 diff --git a/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql b/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql new file mode 100644 index 00000000000..ba955f7848b --- /dev/null +++ b/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql @@ -0,0 +1,38 @@ +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +DROP TABLE IF EXISTS test.t4; + +CREATE TABLE test.t1(x UInt32, y UInt32) ENGINE TinyLog; +CREATE TABLE test.t2(x UInt32, y UInt32 DEFAULT x + 1) ENGINE TinyLog; +CREATE TABLE test.t3(x UInt32, y UInt32 MATERIALIZED x + 1) ENGINE TinyLog; +CREATE TABLE test.t4(x UInt32, y UInt32 ALIAS x + 1) ENGINE TinyLog; + +INSERT INTO test.t1 VALUES (1, 1); +INSERT INTO test.t2 VALUES (1, 1); +INSERT INTO test.t3 VALUES (1); +INSERT INTO test.t4 VALUES (1); + +INSERT INTO FUNCTION remote('127.0.0.2', test.t1) VALUES (2, 2); +INSERT INTO FUNCTION remote('127.0.0.2', test.t2) VALUES (2, 2); +--TODO: INSERT into remote tables with MATERIALIZED columns. +--INSERT INTO FUNCTION remote('127.0.0.2', test.t3) VALUES (2); +INSERT INTO FUNCTION remote('127.0.0.2', test.t4) VALUES (2); + +SELECT * FROM remote('127.0.0.2', test.t1); + +SELECT '*** With a DEFAULT column ***'; +SELECT * FROM remote('127.0.0.2', test.t2); + +SELECT '*** With a MATERIALIZED column ***'; +SELECT * FROM remote('127.0.0.2', test.t3); +SELECT x, y FROM remote('127.0.0.2', test.t3); + +SELECT '*** With an ALIAS column ***'; +SELECT * FROM remote('127.0.0.2', test.t4); +SELECT x, y FROM remote('127.0.0.2', test.t4); + +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +DROP TABLE IF EXISTS test.t4; From fdffbe53ac010d2a54822d16c67944b1451b4218 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Tue, 13 Mar 2018 17:18:11 +0300 Subject: [PATCH 040/244] encapsulate ColumnsDeclaration [#CLICKHOUSE-3241] --- dbms/src/Analyzers/AnalyzeColumns.cpp | 2 +- dbms/src/Analyzers/ExecuteTableFunctions.cpp | 2 +- dbms/src/Core/iostream_debug_helpers.cpp | 2 +- .../DataStreams/RemoteBlockInputStream.cpp | 2 +- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 9 +++--- .../Interpreters/InterpreterAlterQuery.cpp | 2 +- .../Interpreters/InterpreterCreateQuery.cpp | 2 +- .../Interpreters/InterpreterDescribeQuery.cpp | 4 +-- .../Interpreters/InterpreterInsertQuery.cpp | 6 ++-- .../Interpreters/InterpreterSelectQuery.cpp | 11 ++++---- dbms/src/Storages/AlterCommands.cpp | 4 +-- dbms/src/Storages/ITableDeclaration.cpp | 28 +++++++++++-------- dbms/src/Storages/ITableDeclaration.h | 11 ++++---- .../MergeTree/MergeTreeBlockInputStream.cpp | 5 ++-- .../MergeTree/MergeTreeBlockReadUtils.cpp | 4 +-- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 22 +++++++-------- dbms/src/Storages/MergeTree/MergeTreeData.h | 4 +-- .../MergeTree/MergeTreeDataMerger.cpp | 4 +-- .../Storages/MergeTree/MergeTreeDataPart.cpp | 6 ++-- .../MergeTree/MergeTreeDataSelectExecutor.cpp | 4 +-- .../MergeTree/MergeTreeDataWriter.cpp | 2 +- .../Storages/MergeTree/MergeTreeReadPool.cpp | 5 ++-- .../Storages/MergeTree/MergeTreeReader.cpp | 4 +-- .../MergeTree/MergeTreeWhereOptimizer.cpp | 4 +-- .../ReplicatedMergeTreeAlterThread.cpp | 8 ++---- dbms/src/Storages/StorageBuffer.cpp | 6 ++-- dbms/src/Storages/StorageCatBoostPool.cpp | 3 ++ dbms/src/Storages/StorageDictionary.cpp | 2 +- dbms/src/Storages/StorageDistributed.cpp | 12 ++++---- dbms/src/Storages/StorageJoin.cpp | 2 +- dbms/src/Storages/StorageLog.cpp | 8 +++--- dbms/src/Storages/StorageMerge.cpp | 8 ++++-- dbms/src/Storages/StorageMergeTree.cpp | 12 +++----- dbms/src/Storages/StorageMergeTree.h | 3 ++ dbms/src/Storages/StorageMySQL.cpp | 2 +- dbms/src/Storages/StorageNull.cpp | 7 +++-- dbms/src/Storages/StorageODBC.cpp | 3 +- .../Storages/StorageReplicatedMergeTree.cpp | 21 +++++++------- .../src/Storages/StorageReplicatedMergeTree.h | 3 ++ dbms/src/Storages/StorageTinyLog.cpp | 4 +-- .../StorageSystemAsynchronousMetrics.cpp | 4 +-- .../System/StorageSystemBuildOptions.cpp | 4 +-- .../Storages/System/StorageSystemClusters.cpp | 4 +-- .../Storages/System/StorageSystemColumns.cpp | 8 +++--- .../System/StorageSystemDatabases.cpp | 4 +-- .../System/StorageSystemDictionaries.cpp | 4 +-- .../Storages/System/StorageSystemEvents.cpp | 4 +-- .../System/StorageSystemFunctions.cpp | 4 +-- .../Storages/System/StorageSystemGraphite.cpp | 4 +-- .../Storages/System/StorageSystemMerges.cpp | 4 +-- .../Storages/System/StorageSystemMetrics.cpp | 4 +-- .../Storages/System/StorageSystemModels.cpp | 4 +-- .../Storages/System/StorageSystemNumbers.cpp | 2 +- dbms/src/Storages/System/StorageSystemOne.cpp | 2 +- .../System/StorageSystemPartsBase.cpp | 2 +- .../System/StorageSystemPartsColumns.cpp | 4 +-- .../System/StorageSystemProcesses.cpp | 4 +-- .../Storages/System/StorageSystemReplicas.cpp | 4 +-- .../System/StorageSystemReplicationQueue.cpp | 4 +-- .../Storages/System/StorageSystemSettings.cpp | 4 +-- .../Storages/System/StorageSystemTables.cpp | 4 +-- .../System/StorageSystemZooKeeper.cpp | 4 +-- .../src/TableFunctions/TableFunctionMerge.cpp | 2 +- .../getStructureOfRemoteTable.cpp | 2 +- 64 files changed, 182 insertions(+), 161 deletions(-) diff --git a/dbms/src/Analyzers/AnalyzeColumns.cpp b/dbms/src/Analyzers/AnalyzeColumns.cpp index 78568b080c6..efcbaf66888 100644 --- a/dbms/src/Analyzers/AnalyzeColumns.cpp +++ b/dbms/src/Analyzers/AnalyzeColumns.cpp @@ -173,7 +173,7 @@ ASTPtr createASTIdentifierForColumnInTable(const String & column, const CollectT void createASTsForAllColumnsInTable(const CollectTables::TableInfo & table, ASTs & res) { if (table.storage) - for (const auto & name : table.storage->columns.getNames()) + for (const auto & name : table.storage->getColumns().getNames()) res.emplace_back(createASTIdentifierForColumnInTable(name, table)); else for (size_t i = 0, size = table.structure_of_subquery.columns(); i < size; ++i) diff --git a/dbms/src/Analyzers/ExecuteTableFunctions.cpp b/dbms/src/Analyzers/ExecuteTableFunctions.cpp index 3feabc8f490..37cc3d66eec 100644 --- a/dbms/src/Analyzers/ExecuteTableFunctions.cpp +++ b/dbms/src/Analyzers/ExecuteTableFunctions.cpp @@ -72,7 +72,7 @@ void ExecuteTableFunctions::dump(WriteBuffer & out) const { writeString(table.second->getName(), out); writeCString("\n\n", out); - writeString(table.second->columns.getPhysical().toString(), out); + writeString(table.second->getColumns().getPhysical().toString(), out); writeCString("\n", out); } } diff --git a/dbms/src/Core/iostream_debug_helpers.cpp b/dbms/src/Core/iostream_debug_helpers.cpp index 723b3dc2e90..bd19c453d8d 100644 --- a/dbms/src/Core/iostream_debug_helpers.cpp +++ b/dbms/src/Core/iostream_debug_helpers.cpp @@ -44,7 +44,7 @@ std::ostream & operator<<(std::ostream & stream, const IDataType & what) std::ostream & operator<<(std::ostream & stream, const IStorage & what) { stream << "IStorage(name = " << what.getName() << ", tableName = " << what.getTableName() << ") {" - << what.columns.getPhysical().toString() + << what.getColumns().getPhysical().toString() << "}"; // isRemote supportsSampling supportsFinal supportsPrewhere return stream; diff --git a/dbms/src/DataStreams/RemoteBlockInputStream.cpp b/dbms/src/DataStreams/RemoteBlockInputStream.cpp index 079cabe8dee..b5e20898b89 100644 --- a/dbms/src/DataStreams/RemoteBlockInputStream.cpp +++ b/dbms/src/DataStreams/RemoteBlockInputStream.cpp @@ -138,7 +138,7 @@ void RemoteBlockInputStream::sendExternalTables() { StoragePtr cur = table.second; QueryProcessingStage::Enum stage = QueryProcessingStage::Complete; - BlockInputStreams input = cur->read(cur->columns.getNames(), {}, context, + BlockInputStreams input = cur->read(cur->getColumns().getNames(), {}, context, stage, DEFAULT_BLOCK_SIZE, 1); if (input.size() == 0) res.push_back(std::make_pair(std::make_shared(cur->getSampleBlock()), table.first)); diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index e6190b8f1df..4f0fe52bcff 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -190,7 +190,7 @@ ExpressionAnalyzer::ExpressionAnalyzer( } if (storage && source_columns.empty()) - source_columns = storage->columns.getPhysical(); + source_columns = storage->getColumns().getPhysical(); else removeDuplicateColumns(source_columns); @@ -712,7 +712,7 @@ static std::shared_ptr interpretSubquery( /// get columns list for target table auto database_table = getDatabaseAndTableNameFromIdentifier(*table); const auto & storage = context.getTable(database_table.first, database_table.second); - const auto & columns = storage->columns.ordinary; + const auto & columns = storage->getColumns().ordinary; select_expression_list->children.reserve(columns.size()); /// manually substitute column names in place of asterisk @@ -1050,7 +1050,7 @@ void ExpressionAnalyzer::normalizeTreeImpl( if (storage) { /// If we select from a table, get only not MATERIALIZED, not ALIAS columns. - for (const auto & name_type : storage->columns.ordinary) + for (const auto & name_type : storage->getColumns().ordinary) all_columns.emplace_back(std::make_shared(name_type.name)); } else @@ -1147,7 +1147,8 @@ void ExpressionAnalyzer::addAliasColumns() if (!storage) return; - source_columns.insert(std::end(source_columns), std::begin(storage->columns.aliases), std::end(storage->columns.aliases)); + const auto & aliases = storage->getColumns().aliases; + source_columns.insert(std::end(source_columns), std::begin(aliases), std::end(aliases)); } diff --git a/dbms/src/Interpreters/InterpreterAlterQuery.cpp b/dbms/src/Interpreters/InterpreterAlterQuery.cpp index 08254c8e8f8..377f92d6c8d 100644 --- a/dbms/src/Interpreters/InterpreterAlterQuery.cpp +++ b/dbms/src/Interpreters/InterpreterAlterQuery.cpp @@ -200,7 +200,7 @@ void InterpreterAlterQuery::PartitionCommands::validate(const IStorage * table) { String column_name = command.column_name.safeGet(); - if (!table->columns.has(column_name)) + if (!table->getColumns().has(column_name)) { throw Exception("Wrong column name. Cannot find column " + column_name + " to clear it from partition", DB::ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 43f4336f896..dd594d2993a 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -362,7 +362,7 @@ ColumnsDescription InterpreterCreateQuery::setColumns( } else if (!create.as_table.empty()) { - res = as_storage->columns; + res = as_storage->getColumns(); } else if (create.select) { diff --git a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp index 07eefbd913b..536c554e996 100644 --- a/dbms/src/Interpreters/InterpreterDescribeQuery.cpp +++ b/dbms/src/Interpreters/InterpreterDescribeQuery.cpp @@ -99,8 +99,8 @@ BlockInputStreamPtr InterpreterDescribeQuery::executeImpl() } auto table_lock = table->lockStructure(false, __PRETTY_FUNCTION__); - columns = table->columns.getAll(); - column_defaults = table->columns.defaults; + columns = table->getColumns().getAll(); + column_defaults = table->getColumns().defaults; } Block sample_block = getSampleBlock(); diff --git a/dbms/src/Interpreters/InterpreterInsertQuery.cpp b/dbms/src/Interpreters/InterpreterInsertQuery.cpp index 973fdc31a27..3e054f576a4 100644 --- a/dbms/src/Interpreters/InterpreterInsertQuery.cpp +++ b/dbms/src/Interpreters/InterpreterInsertQuery.cpp @@ -95,7 +95,7 @@ BlockIO InterpreterInsertQuery::execute() auto table_lock = table->lockStructure(true, __PRETTY_FUNCTION__); - NamesAndTypesList required_columns = table->columns.getPhysical(); + NamesAndTypesList required_columns = table->getColumns().getPhysical(); /// We create a pipeline of several streams, into which we will write data. BlockOutputStreamPtr out; @@ -103,7 +103,7 @@ BlockIO InterpreterInsertQuery::execute() out = std::make_shared(query.database, query.table, table, context, query_ptr, query.no_destination); out = std::make_shared( - out, getSampleBlock(query, table), required_columns, table->columns.defaults, context); + out, getSampleBlock(query, table), required_columns, table->getColumns().defaults, context); /// Do not squash blocks if it is a sync INSERT into Distributed if (!(context.getSettingsRef().insert_distributed_sync && table->getName() == "Distributed")) @@ -135,7 +135,7 @@ BlockIO InterpreterInsertQuery::execute() if (!allow_materialized) { Block in_header = res.in->getHeader(); - for (const auto & name_type : table->columns.materialized) + for (const auto & name_type : table->getColumns().materialized) if (in_header.has(name_type.name)) throw Exception("Cannot insert column " + name_type.name + ", because it is MATERIALIZED column.", ErrorCodes::ILLEGAL_COLUMN); } diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index ba93c737f08..49a46abeb13 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -516,12 +516,13 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline /// Are ALIAS columns required for query execution? auto alias_columns_required = false; - if (storage && !storage->columns.aliases.empty()) + if (storage && !storage->getColumns().aliases.empty()) { + const auto & column_defaults = storage->getColumns().defaults; for (const auto & column : required_columns) { - const auto default_it = storage->columns.defaults.find(column); - if (default_it != std::end(storage->columns.defaults) && default_it->second.kind == ColumnDefaultKind::Alias) + const auto default_it = column_defaults.find(column); + if (default_it != std::end(column_defaults) && default_it->second.kind == ColumnDefaultKind::Alias) { alias_columns_required = true; break; @@ -535,8 +536,8 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline for (const auto & column : required_columns) { - const auto default_it = storage->columns.defaults.find(column); - if (default_it != std::end(storage->columns.defaults) && default_it->second.kind == ColumnDefaultKind::Alias) + const auto default_it = column_defaults.find(column); + if (default_it != std::end(column_defaults) && default_it->second.kind == ColumnDefaultKind::Alias) required_columns_expr_list->children.emplace_back(setAlias(default_it->second.expression->clone(), column)); else required_columns_expr_list->children.emplace_back(std::make_shared(column)); diff --git a/dbms/src/Storages/AlterCommands.cpp b/dbms/src/Storages/AlterCommands.cpp index 6c16acf5300..274f9315f5f 100644 --- a/dbms/src/Storages/AlterCommands.cpp +++ b/dbms/src/Storages/AlterCommands.cpp @@ -177,8 +177,8 @@ void AlterCommands::apply(ColumnsDescription & columns_description) const void AlterCommands::validate(IStorage * table, const Context & context) { - auto all_columns = table->columns.getAll(); - auto defaults = table->columns.defaults; + auto all_columns = table->getColumns().getAll(); + auto defaults = table->getColumns().defaults; std::vector> defaulted_columns{}; diff --git a/dbms/src/Storages/ITableDeclaration.cpp b/dbms/src/Storages/ITableDeclaration.cpp index b5a6c035b96..783b0b2a7ed 100644 --- a/dbms/src/Storages/ITableDeclaration.cpp +++ b/dbms/src/Storages/ITableDeclaration.cpp @@ -24,14 +24,22 @@ namespace ErrorCodes } +void ITableDeclaration::setColumns(ColumnsDescription columns_) +{ + if (columns_.ordinary.empty()) + throw Exception("Empty list of columns passed", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED); + columns = std::move(columns_); +} + + bool ITableDeclaration::hasColumn(const String & column_name) const { - return columns.has(column_name); /// By default, we assume that there are no virtual columns in the storage. + return getColumns().has(column_name); /// By default, we assume that there are no virtual columns in the storage. } NameAndTypePair ITableDeclaration::getColumn(const String & column_name) const { - return columns.get(column_name); /// By default, we assume that there are no virtual columns in the storage. + return getColumns().get(column_name); /// By default, we assume that there are no virtual columns in the storage. } @@ -39,7 +47,7 @@ Block ITableDeclaration::getSampleBlock() const { Block res; - for (const auto & col : boost::join(columns.ordinary, columns.materialized)) + for (const auto & col : boost::join(getColumns().ordinary, getColumns().materialized)) res.insert({ col.type->createColumn(), col.type, col.name }); return res; @@ -50,7 +58,7 @@ Block ITableDeclaration::getSampleBlockNonMaterialized() const { Block res; - for (const auto & col : columns.ordinary) + for (const auto & col : getColumns().ordinary) res.insert({ col.type->createColumn(), col.type, col.name }); return res; @@ -111,7 +119,7 @@ static NamesAndTypesMap getColumnsMap(const Args &... args) void ITableDeclaration::check(const Names & column_names) const { - const NamesAndTypesList & available_columns = columns.getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getPhysical(); if (column_names.empty()) throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns), @@ -139,7 +147,7 @@ void ITableDeclaration::check(const Names & column_names) const void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const { - const NamesAndTypesList & available_columns = columns.getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getPhysical(); const auto columns_map = getColumnsMap(available_columns); using UniqueStrings = google::dense_hash_set; @@ -167,7 +175,7 @@ void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const Names & column_names) const { - const NamesAndTypesList & available_columns = columns.getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getPhysical(); const auto available_columns_map = getColumnsMap(available_columns); const NamesAndTypesMap & provided_columns_map = getColumnsMap(provided_columns); @@ -204,7 +212,7 @@ void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const void ITableDeclaration::check(const Block & block, bool need_all) const { - const NamesAndTypesList & available_columns = columns.getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getPhysical(); const auto columns_map = getColumnsMap(available_columns); using NameSet = std::unordered_set; @@ -242,10 +250,8 @@ void ITableDeclaration::check(const Block & block, bool need_all) const ITableDeclaration::ITableDeclaration(ColumnsDescription columns_) - : columns{std::move(columns_)} { - if (columns.ordinary.empty()) - throw Exception("Empty list of columns passed to storage constructor", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED); + setColumns(std::move(columns_)); } } diff --git a/dbms/src/Storages/ITableDeclaration.h b/dbms/src/Storages/ITableDeclaration.h index 4c4ea59e4b5..270ab175576 100644 --- a/dbms/src/Storages/ITableDeclaration.h +++ b/dbms/src/Storages/ITableDeclaration.h @@ -12,12 +12,12 @@ namespace DB class ITableDeclaration { public: - /** Get a description of any column by its name. - */ - virtual NameAndTypePair getColumn(const String & column_name) const; + virtual const ColumnsDescription & getColumns() const { return columns; } + virtual void setColumns(ColumnsDescription columns_); - /** Is there a column with that name. - */ + /// NOTE: These methods should include virtual columns, but should NOT include ALIAS columns + /// (they are treated separately). + virtual NameAndTypePair getColumn(const String & column_name) const; virtual bool hasColumn(const String & column_name) const; Block getSampleBlock() const; @@ -48,6 +48,7 @@ public: explicit ITableDeclaration(ColumnsDescription columns_); virtual ~ITableDeclaration() = default; +private: ColumnsDescription columns; }; diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp index 6fb7c8fb611..a6d2958a786 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp @@ -141,8 +141,9 @@ try if (!column_names.empty()) storage.check(data_part->columns, column_names); - pre_columns = storage.columns.getPhysical().addTypes(pre_column_names); - columns = storage.columns.getPhysical().addTypes(column_names); + const NamesAndTypesList & physical_columns = storage.getColumns().getPhysical(); + pre_columns = physical_columns.addTypes(pre_column_names); + columns = physical_columns.addTypes(column_names); } else { diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp b/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp index b6d8ff3cd5a..5d52eedfda1 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.cpp @@ -26,9 +26,9 @@ NameSet injectRequiredColumns(const MergeTreeData & storage, const MergeTreeData continue; } - const auto default_it = storage.columns.defaults.find(column_name); + const auto default_it = storage.getColumns().defaults.find(column_name); /// columns has no explicit default expression - if (default_it == std::end(storage.columns.defaults)) + if (default_it == std::end(storage.getColumns().defaults)) continue; /// collect identifiers required for evaluation diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index de16c22593d..ed16d1536de 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -110,7 +110,7 @@ MergeTreeData::MergeTreeData( data_parts_by_state_and_info(data_parts_indexes.get()) { /// NOTE: using the same columns list as is read when performing actual merges. - merging_params.check(columns.getPhysical()); + merging_params.check(getColumns().getPhysical()); if (!primary_expr_ast) throw Exception("Primary key cannot be empty", ErrorCodes::BAD_ARGUMENTS); @@ -222,11 +222,11 @@ void MergeTreeData::initPrimaryKey() primary_sort_descr.clear(); addSortDescription(primary_sort_descr, primary_expr_ast); - primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getPhysical()).getActions(false); + primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(false); { ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(primary_expr_ast, context, nullptr, columns.getPhysical()).getActions(true); + ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(true); primary_key_sample = projected_expr->getSampleBlock(); } @@ -241,10 +241,10 @@ void MergeTreeData::initPrimaryKey() if (secondary_sort_expr_ast) { addSortDescription(sort_descr, secondary_sort_expr_ast); - secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getPhysical()).getActions(false); + secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(false); ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, columns.getPhysical()).getActions(true); + ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(true); auto secondary_key_sample = projected_expr->getSampleBlock(); checkKeyExpression(*secondary_sort_expr, secondary_key_sample, "Secondary"); @@ -257,7 +257,7 @@ void MergeTreeData::initPartitionKey() if (!partition_expr_ast || partition_expr_ast->children.empty()) return; - partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, columns.getPhysical()).getActions(false); + partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(false); for (const ASTPtr & ast : partition_expr_ast->children) { String col_name = ast->getColumnName(); @@ -861,7 +861,7 @@ bool isMetadataOnlyConversion(const IDataType * from, const IDataType * to) void MergeTreeData::checkAlter(const AlterCommands & commands) { /// Check that needed transformations can be applied to the list of columns without considering type conversions. - auto new_columns = columns; + auto new_columns = getColumns(); commands.apply(new_columns); /// Set of columns that shouldn't be altered. @@ -903,7 +903,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) columns_alter_forbidden.insert(merging_params.sign_column); std::map old_types; - for (const auto & column : columns.getPhysical()) + for (const auto & column : getColumns().getPhysical()) old_types.emplace(column.name, column.type.get()); for (const AlterCommand & command : commands) @@ -931,7 +931,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) NameToNameMap unused_map; bool unused_bool; - createConvertExpression(nullptr, columns.getPhysical(), new_columns.getPhysical(), unused_expression, unused_map, unused_bool); + createConvertExpression(nullptr, getColumns().getPhysical(), new_columns.getPhysical(), unused_expression, unused_map, unused_bool); } void MergeTreeData::createConvertExpression(const DataPartPtr & part, const NamesAndTypesList & old_columns, const NamesAndTypesList & new_columns, @@ -1835,7 +1835,7 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : columns.getPhysical()) + for (const auto & column : getColumns().getPhysical()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; @@ -1868,7 +1868,7 @@ void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : columns.getPhysical()) + for (const auto & column : getColumns().getPhysical()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.h b/dbms/src/Storages/MergeTree/MergeTreeData.h index a32baf797ef..da6999ac965 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.h +++ b/dbms/src/Storages/MergeTree/MergeTreeData.h @@ -313,12 +313,12 @@ public: if (column_name == "_sample_factor") return NameAndTypePair("_sample_factor", std::make_shared()); - return columns.get(column_name); + return getColumns().get(column_name); } bool hasColumn(const String & column_name) const override { - return columns.has(column_name) + return getColumns().has(column_name) || column_name == "_part" || column_name == "_part_index" || column_name == "_sample_factor"; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index 8e30320aefb..dafa27e2346 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -536,8 +536,8 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataMerger::mergePartsToTemporaryPart for (const MergeTreeData::DataPartPtr & part : parts) part->accumulateColumnSizes(merged_column_to_size); - Names all_column_names = data.columns.getNames(); - NamesAndTypesList all_columns = data.columns.getPhysical(); + Names all_column_names = data.getColumns().getNames(); + NamesAndTypesList all_columns = data.getColumns().getPhysical(); const SortDescription sort_desc = data.getSortDescription(); NamesAndTypesList gathering_columns, merging_columns; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index f37cd8e579c..92936e2adc7 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -418,7 +418,7 @@ UInt64 MergeTreeDataPart::getColumnMrkSize(const String & name) const */ String MergeTreeDataPart::getColumnNameWithMinumumCompressedSize() const { - const auto & columns = storage.columns.getPhysical(); + const auto & columns = storage.getColumns().getPhysical(); const std::string * minimum_size_column = nullptr; UInt64 minimum_size = std::numeric_limits::max(); @@ -774,7 +774,7 @@ void MergeTreeDataPart::accumulateColumnSizes(ColumnToSize & column_to_size) con { std::shared_lock part_lock(columns_lock); - for (const NameAndTypePair & name_type : storage.columns.getPhysical()) + for (const NameAndTypePair & name_type : storage.getColumns().getPhysical()) { name_type.type->enumerateStreams([&](const IDataType::SubstreamPath & substream_path) { @@ -794,7 +794,7 @@ void MergeTreeDataPart::loadColumns(bool require) throw Exception("No columns.txt in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); /// If there is no file with a list of columns, write it down. - for (const NameAndTypePair & column : storage.columns.getPhysical()) + for (const NameAndTypePair & column : storage.getColumns().getPhysical()) if (Poco::File(getFullPath() + escapeForFileName(column.name) + ".bin").exists()) columns.push_back(column); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp index 0890163078d..77ba844ee0b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp @@ -175,7 +175,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read( } } - NamesAndTypesList available_real_columns = data.columns.getPhysical(); + NamesAndTypesList available_real_columns = data.getColumns().getPhysical(); NamesAndTypesList available_real_and_virtual_columns = available_real_columns; for (const auto & name : virt_column_names) @@ -857,7 +857,7 @@ void MergeTreeDataSelectExecutor::createPositiveSignCondition( arguments->children.push_back(sign); arguments->children.push_back(one); - out_expression = ExpressionAnalyzer(function, context, {}, data.columns.getPhysical()).getActions(false); + out_expression = ExpressionAnalyzer(function, context, {}, data.getColumns().getPhysical()).getActions(false); out_column = function->getColumnName(); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index 19eb2e8eecd..c57d1d5bfdd 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -205,7 +205,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithPa /// either default lz4 or compression method with zero thresholds on absolute and relative part size. auto compression_settings = data.context.chooseCompressionSettings(0, 0); - NamesAndTypesList columns = data.columns.getPhysical().filter(block.getNames()); + NamesAndTypesList columns = data.getColumns().getPhysical().filter(block.getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_settings); out.writePrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp index 2c600dbd32d..452aee79bf3 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp @@ -238,8 +238,9 @@ std::vector MergeTreeReadPool::fillPerPartInfo( if (!required_column_names.empty()) data.check(part.data_part->columns, required_column_names); - per_part_pre_columns.push_back(data.columns.getPhysical().addTypes(required_pre_column_names)); - per_part_columns.push_back(data.columns.getPhysical().addTypes(required_column_names)); + const NamesAndTypesList & physical_columns = data.getColumns().getPhysical(); + per_part_pre_columns.push_back(physical_columns.addTypes(required_pre_column_names)); + per_part_columns.push_back(physical_columns.addTypes(required_column_names)); } else { diff --git a/dbms/src/Storages/MergeTree/MergeTreeReader.cpp b/dbms/src/Storages/MergeTree/MergeTreeReader.cpp index 7bce149776a..e172760b17f 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeReader.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeReader.cpp @@ -463,7 +463,7 @@ void MergeTreeReader::fillMissingColumns(Block & res, const Names & ordered_name if (!has_column) { should_sort = true; - if (storage.columns.defaults.count(requested_column.name) != 0) + if (storage.getColumns().defaults.count(requested_column.name) != 0) { should_evaluate_defaults = true; continue; @@ -498,7 +498,7 @@ void MergeTreeReader::fillMissingColumns(Block & res, const Names & ordered_name /// evaluate defaulted columns if necessary if (should_evaluate_defaults) - evaluateMissingDefaults(res, columns, storage.columns.defaults, storage.context); + evaluateMissingDefaults(res, columns, storage.getColumns().defaults, storage.context); /// sort columns to ensure consistent order among all blocks if (should_sort) diff --git a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp index ce4047fc85f..ac28d3e782d 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp @@ -41,9 +41,9 @@ MergeTreeWhereOptimizer::MergeTreeWhereOptimizer( Logger * log) : primary_key_columns{ext::map(data.getPrimarySortDescription(), [] (const SortColumnDescription & col) { return col.column_name; })}, - table_columns{ext::map(data.columns.getPhysical(), + table_columns{ext::map(data.getColumns().getPhysical(), [] (const NameAndTypePair & col) { return col.name; })}, - block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.columns.getPhysical())}, + block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.getColumns().getPhysical())}, prepared_sets(query_info.sets), log{log} { diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp index 948902d8302..1fcba112fed 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp @@ -87,15 +87,13 @@ void ReplicatedMergeTreeAlterThread::run() auto table_lock = storage.lockStructureForAlter(__PRETTY_FUNCTION__); - if (columns_in_zk != storage.data.columns) + if (columns_in_zk != storage.getColumns()) { LOG_INFO(log, "Columns list changed in ZooKeeper. Applying changes locally."); storage.context.getDatabase(storage.database_name)->alterTable( storage.context, storage.table_name, columns_in_zk, {}); - - storage.columns = columns_in_zk; - storage.data.columns = std::move(columns_in_zk); + storage.setColumns(std::move(columns_in_zk)); /// Reinitialize primary key because primary key column types might have changed. storage.data.initPrimaryKey(); @@ -126,7 +124,7 @@ void ReplicatedMergeTreeAlterThread::run() if (!changed_version) parts = storage.data.getDataParts(); - const auto columns_for_parts = storage.data.columns.getPhysical(); + const auto columns_for_parts = storage.getColumns().getPhysical(); for (const MergeTreeData::DataPartPtr & part : parts) { diff --git a/dbms/src/Storages/StorageBuffer.cpp b/dbms/src/Storages/StorageBuffer.cpp index c76a1edc81b..2072ac72c5c 100644 --- a/dbms/src/Storages/StorageBuffer.cpp +++ b/dbms/src/Storages/StorageBuffer.cpp @@ -595,8 +595,10 @@ void StorageBuffer::alter(const AlterCommands & params, const String & database_ /// So that no blocks of the old structure remain. optimize({} /*query*/, {} /*partition_id*/, false /*final*/, false /*deduplicate*/, context); - params.apply(columns); - context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); + ColumnsDescription new_columns = getColumns(); + params.apply(new_columns); + context.getDatabase(database_name)->alterTable(context, table_name, new_columns, {}); + setColumns(std::move(new_columns)); } diff --git a/dbms/src/Storages/StorageCatBoostPool.cpp b/dbms/src/Storages/StorageCatBoostPool.cpp index d20da89b170..9fa8133617c 100644 --- a/dbms/src/Storages/StorageCatBoostPool.cpp +++ b/dbms/src/Storages/StorageCatBoostPool.cpp @@ -220,6 +220,7 @@ void StorageCatBoostPool::parseColumnDescription() void StorageCatBoostPool::createSampleBlockAndColumns() { + ColumnsDescription columns; NamesAndTypesList cat_columns; NamesAndTypesList num_columns; sample_block.clear(); @@ -251,6 +252,8 @@ void StorageCatBoostPool::createSampleBlockAndColumns() } columns.ordinary.insert(columns.ordinary.end(), num_columns.begin(), num_columns.end()); columns.ordinary.insert(columns.ordinary.end(), cat_columns.begin(), cat_columns.end()); + + setColumns(columns); } BlockInputStreams StorageCatBoostPool::read(const Names & column_names, diff --git a/dbms/src/Storages/StorageDictionary.cpp b/dbms/src/Storages/StorageDictionary.cpp index 954b8ae898b..b3dbf39e9c2 100644 --- a/dbms/src/Storages/StorageDictionary.cpp +++ b/dbms/src/Storages/StorageDictionary.cpp @@ -72,7 +72,7 @@ void StorageDictionary::checkNamesAndTypesCompatibleWithDictionary(const Diction auto dictionary_names_and_types = getNamesAndTypes(dictionary_structure); std::set namesAndTypesSet(dictionary_names_and_types.begin(), dictionary_names_and_types.end()); - for (auto & column : columns.ordinary) + for (auto & column : getColumns().ordinary) { if (namesAndTypesSet.find(column) == namesAndTypesSet.end()) { diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index e3ff7f30369..972a4817009 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -142,7 +142,7 @@ StorageDistributed::StorageDistributed( table_name(table_name_), remote_database(remote_database_), remote_table(remote_table_), context(context_), cluster_name(context.getMacros().expand(cluster_name_)), has_sharding_key(sharding_key_), - sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, columns.getPhysical()).getActions(false) : nullptr), + sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, getColumns().getPhysical()).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(table_name) + '/')) { @@ -232,9 +232,11 @@ void StorageDistributed::alter(const AlterCommands & params, const String & data throw Exception("Storage engine " + getName() + " doesn't support primary key.", ErrorCodes::NOT_IMPLEMENTED); auto lock = lockStructureForAlter(__PRETTY_FUNCTION__); - params.apply(columns); - context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); + ColumnsDescription new_columns = getColumns(); + params.apply(new_columns); + context.getDatabase(database_name)->alterTable(context, table_name, new_columns, {}); + setColumns(std::move(new_columns)); } @@ -285,13 +287,13 @@ NameAndTypePair StorageDistributed::getColumn(const String & column_name) const if (const auto & type = VirtualColumnFactory::tryGetType(column_name)) return { column_name, type }; - return columns.get(column_name); + return getColumns().get(column_name); } bool StorageDistributed::hasColumn(const String & column_name) const { - return VirtualColumnFactory::hasColumn(column_name) || columns.has(column_name); + return VirtualColumnFactory::hasColumn(column_name) || getColumns().has(column_name); } void StorageDistributed::createDirectoryMonitors() diff --git a/dbms/src/Storages/StorageJoin.cpp b/dbms/src/Storages/StorageJoin.cpp index c3dfc16c5d7..746f15bab50 100644 --- a/dbms/src/Storages/StorageJoin.cpp +++ b/dbms/src/Storages/StorageJoin.cpp @@ -29,7 +29,7 @@ StorageJoin::StorageJoin( key_names(key_names_), kind(kind_), strictness(strictness_) { for (const auto & key : key_names) - if (!columns.has(key)) + if (!getColumns().has(key)) throw Exception{ "Key column (" + key + ") does not exist in table declaration.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE}; diff --git a/dbms/src/Storages/StorageLog.cpp b/dbms/src/Storages/StorageLog.cpp index 137c1d55616..c23d92de8fa 100644 --- a/dbms/src/Storages/StorageLog.cpp +++ b/dbms/src/Storages/StorageLog.cpp @@ -371,7 +371,7 @@ StorageLog::StorageLog( /// create files if they do not exist Poco::File(path + escapeForFileName(name) + '/').createDirectories(); - for (const auto & column : columns.getPhysical()) + for (const auto & column : getColumns().getPhysical()) addFiles(column.name, *column.type); marks_file = Poco::File(path + escapeForFileName(name) + '/' + DBMS_STORAGE_LOG_MARKS_FILE_NAME); @@ -465,8 +465,8 @@ void StorageLog::rename(const String & new_path_to_db, const String & /*new_data const StorageLog::Marks & StorageLog::getMarksWithRealRowCount() const { - const String & column_name = columns.ordinary.front().name; - const IDataType & column_type = *columns.ordinary.front().type; + const String & column_name = getColumns().ordinary.front().name; + const IDataType & column_type = *getColumns().ordinary.front().type; String filename; /** We take marks from first column. @@ -499,7 +499,7 @@ BlockInputStreams StorageLog::read( processed_stage = QueryProcessingStage::FetchColumns; loadMarks(); - NamesAndTypesList all_columns = Nested::collect(columns.getPhysical().addTypes(column_names)); + NamesAndTypesList all_columns = Nested::collect(getColumns().getPhysical().addTypes(column_names)); std::shared_lock lock(rwlock); diff --git a/dbms/src/Storages/StorageMerge.cpp b/dbms/src/Storages/StorageMerge.cpp index f26544975cd..6f29850c8d1 100644 --- a/dbms/src/Storages/StorageMerge.cpp +++ b/dbms/src/Storages/StorageMerge.cpp @@ -181,7 +181,7 @@ BlockInputStreams StorageMerge::read( /// If there are only virtual columns in query, you must request at least one other column. if (real_column_names.size() == 0) - real_column_names.push_back(ExpressionActions::getSmallestColumn(table->columns.getPhysical())); + real_column_names.push_back(ExpressionActions::getSmallestColumn(table->getColumns().getPhysical())); /// Substitute virtual column for its value when querying tables. ASTPtr modified_query_ast = query->clone(); @@ -334,8 +334,10 @@ void StorageMerge::alter(const AlterCommands & params, const String & database_n auto lock = lockStructureForAlter(__PRETTY_FUNCTION__); - params.apply(columns); - context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); + ColumnsDescription new_columns = getColumns(); + params.apply(new_columns); + context.getDatabase(database_name)->alterTable(context, table_name, new_columns, {}); + setColumns(new_columns); } diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index 5e799c91909..f22f24082fb 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -46,8 +46,7 @@ StorageMergeTree::StorageMergeTree( const MergeTreeData::MergingParams & merging_params_, const MergeTreeSettings & settings_, bool has_force_restore_data_flag) - : IStorage{columns_}, - path(path_), database_name(database_name_), table_name(table_name_), full_path(path + escapeForFileName(table_name) + '/'), + : path(path_), database_name(database_name_), table_name(table_name_), full_path(path + escapeForFileName(table_name) + '/'), context(context_), background_pool(context_.getBackgroundPool()), data(database_name, table_name, full_path, columns_, @@ -153,8 +152,7 @@ void StorageMergeTree::alter( data.checkAlter(params); - auto new_columns = data.columns; - + auto new_columns = data.getColumns(); params.apply(new_columns); std::vector transactions; @@ -203,9 +201,7 @@ void StorageMergeTree::alter( } context.getDatabase(database_name)->alterTable(context, table_name, new_columns, storage_modifier); - - columns = new_columns; - data.columns = std::move(new_columns); + setColumns(std::move(new_columns)); if (primary_key_is_modified) { @@ -419,7 +415,7 @@ void StorageMergeTree::clearColumnInPartition(const ASTPtr & partition, const Fi alter_command.type = AlterCommand::DROP_COLUMN; alter_command.column_name = get(column_name); - auto new_columns = data.columns; + auto new_columns = getColumns(); alter_command.apply(new_columns); auto columns_for_parts = new_columns.getPhysical(); diff --git a/dbms/src/Storages/StorageMergeTree.h b/dbms/src/Storages/StorageMergeTree.h index e2ad6177a82..acb0e03a60a 100644 --- a/dbms/src/Storages/StorageMergeTree.h +++ b/dbms/src/Storages/StorageMergeTree.h @@ -36,6 +36,9 @@ public: bool supportsFinal() const override { return data.supportsFinal(); } bool supportsPrewhere() const override { return data.supportsPrewhere(); } + const ColumnsDescription & getColumns() const override { return data.getColumns(); } + void setColumns(ColumnsDescription columns_) override { return data.setColumns(std::move(columns_)); } + NameAndTypePair getColumn(const String & column_name) const override { return data.getColumn(column_name); diff --git a/dbms/src/Storages/StorageMySQL.cpp b/dbms/src/Storages/StorageMySQL.cpp index 28a367f17e0..3c63ebe4ca5 100644 --- a/dbms/src/Storages/StorageMySQL.cpp +++ b/dbms/src/Storages/StorageMySQL.cpp @@ -43,7 +43,7 @@ BlockInputStreams StorageMySQL::read( { check(column_names); processed_stage = QueryProcessingStage::FetchColumns; - String query = transformQueryForExternalDatabase(*query_info.query, columns.ordinary, remote_database_name, remote_table_name, context); + String query = transformQueryForExternalDatabase(*query_info.query, getColumns().ordinary, remote_database_name, remote_table_name, context); Block sample_block; for (const String & name : column_names) diff --git a/dbms/src/Storages/StorageNull.cpp b/dbms/src/Storages/StorageNull.cpp index 13232068ca9..25ecfecf2c9 100644 --- a/dbms/src/Storages/StorageNull.cpp +++ b/dbms/src/Storages/StorageNull.cpp @@ -33,9 +33,10 @@ void StorageNull::alter(const AlterCommands & params, const String & database_na { auto lock = lockStructureForAlter(__PRETTY_FUNCTION__); - params.apply(columns); - - context.getDatabase(database_name)->alterTable(context, table_name, columns, {}); + ColumnsDescription new_columns = getColumns(); + params.apply(new_columns); + context.getDatabase(database_name)->alterTable(context, table_name, new_columns, {}); + setColumns(std::move(new_columns)); } } diff --git a/dbms/src/Storages/StorageODBC.cpp b/dbms/src/Storages/StorageODBC.cpp index 7856ee9a231..09791c0e314 100644 --- a/dbms/src/Storages/StorageODBC.cpp +++ b/dbms/src/Storages/StorageODBC.cpp @@ -43,7 +43,8 @@ BlockInputStreams StorageODBC::read( { check(column_names); processed_stage = QueryProcessingStage::FetchColumns; - String query = transformQueryForExternalDatabase(*query_info.query, columns.ordinary, remote_database_name, remote_table_name, context); + String query = transformQueryForExternalDatabase( + *query_info.query, getColumns().ordinary, remote_database_name, remote_table_name, context); Block sample_block; for (const String & name : column_names) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index d69db2d388e..c2cf65e1c85 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -184,7 +184,7 @@ StorageReplicatedMergeTree::StorageReplicatedMergeTree( const MergeTreeData::MergingParams & merging_params_, const MergeTreeSettings & settings_, bool has_force_restore_data_flag) - : IStorage{columns_}, context(context_), + : context(context_), current_zookeeper(context.getZooKeeper()), database_name(database_name_), table_name(name_), full_path(path_ + escapeForFileName(table_name) + '/'), zookeeper_path(context.getMacros().expand(zookeeper_path_)), @@ -484,7 +484,7 @@ void StorageReplicatedMergeTree::createTableIfNotExists() acl, zkutil::CreateMode::Persistent)); ops.emplace_back(std::make_unique(zookeeper_path + "/metadata", metadata, acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/columns", data.columns.toString(), + ops.emplace_back(std::make_unique(zookeeper_path + "/columns", getColumns().toString(), acl, zkutil::CreateMode::Persistent)); ops.emplace_back(std::make_unique(zookeeper_path + "/log", "", acl, zkutil::CreateMode::Persistent)); @@ -519,23 +519,22 @@ void StorageReplicatedMergeTree::checkTableStructure(bool skip_sanity_checks, bo zkutil::Stat stat; auto columns_from_zk = ColumnsDescription::parse(zookeeper->get(zookeeper_path + "/columns", &stat)); - columns_version = stat.version; - if (columns_from_zk != data.columns) + const ColumnsDescription & old_columns = getColumns(); + if (columns_from_zk != old_columns) { if (allow_alter && (skip_sanity_checks || - data.columns.ordinary.sizeOfDifference(columns_from_zk.ordinary) + - data.columns.materialized.sizeOfDifference(columns_from_zk.materialized) <= 2)) + old_columns.ordinary.sizeOfDifference(columns_from_zk.ordinary) + + old_columns.materialized.sizeOfDifference(columns_from_zk.materialized) <= 2)) { LOG_WARNING(log, "Table structure in ZooKeeper is a little different from local table structure. Assuming ALTER."); /// Without any locks, because table has not been created yet. context.getDatabase(database_name)->alterTable(context, table_name, columns_from_zk, {}); - columns = columns_from_zk; - data.columns = std::move(columns_from_zk); + setColumns(std::move(columns_from_zk)); } else { @@ -697,7 +696,7 @@ void StorageReplicatedMergeTree::createReplica() LOG_DEBUG(log, "Copied " << source_queue.size() << " queue entries"); } - zookeeper->create(replica_path + "/columns", data.columns.toString(), zkutil::CreateMode::Persistent); + zookeeper->create(replica_path + "/columns", getColumns().toString(), zkutil::CreateMode::Persistent); } @@ -1507,7 +1506,7 @@ void StorageReplicatedMergeTree::executeClearColumnInPartition(const LogEntry & alter_command.type = AlterCommand::DROP_COLUMN; alter_command.column_name = entry.column_name; - auto new_columns = data.columns; + auto new_columns = getColumns(); alter_command.apply(new_columns); size_t modified_parts = 0; @@ -2544,7 +2543,7 @@ void StorageReplicatedMergeTree::alter(const AlterCommands & params, if (param.type == AlterCommand::MODIFY_PRIMARY_KEY) throw Exception("Modification of primary key is not supported for replicated tables", ErrorCodes::NOT_IMPLEMENTED); - ColumnsDescription new_columns = data.columns; + ColumnsDescription new_columns = data.getColumns(); params.apply(new_columns); new_columns_str = new_columns.toString(); diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.h b/dbms/src/Storages/StorageReplicatedMergeTree.h index 468f097534d..4a2193b05db 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.h +++ b/dbms/src/Storages/StorageReplicatedMergeTree.h @@ -84,6 +84,9 @@ public: bool supportsPrewhere() const override { return data.supportsPrewhere(); } bool supportsReplication() const override { return true; } + const ColumnsDescription & getColumns() const override { return data.getColumns(); } + void setColumns(ColumnsDescription columns_) override { return data.setColumns(std::move(columns_)); } + NameAndTypePair getColumn(const String & column_name) const override { return data.getColumn(column_name); diff --git a/dbms/src/Storages/StorageTinyLog.cpp b/dbms/src/Storages/StorageTinyLog.cpp index 8c7fe1963a8..bd4a8ca304f 100644 --- a/dbms/src/Storages/StorageTinyLog.cpp +++ b/dbms/src/Storages/StorageTinyLog.cpp @@ -296,7 +296,7 @@ StorageTinyLog::StorageTinyLog( throwFromErrno("Cannot create directory " + full_path, ErrorCodes::CANNOT_CREATE_DIRECTORY); } - for (const auto & col : columns.getPhysical()) + for (const auto & col : getColumns().getPhysical()) addFiles(col.name, *col.type); } @@ -348,7 +348,7 @@ BlockInputStreams StorageTinyLog::read( check(column_names); processed_stage = QueryProcessingStage::FetchColumns; return BlockInputStreams(1, std::make_shared( - max_block_size, Nested::collect(columns.getPhysical().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); + max_block_size, Nested::collect(getColumns().getPhysical().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); } diff --git a/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp b/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp index 3c77244c557..bc2f76379e9 100644 --- a/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp +++ b/dbms/src/Storages/System/StorageSystemAsynchronousMetrics.cpp @@ -16,10 +16,10 @@ StorageSystemAsynchronousMetrics::StorageSystemAsynchronousMetrics(const std::st : name(name_), async_metrics(async_metrics_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ {"metric", std::make_shared()}, {"value", std::make_shared()}, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemBuildOptions.cpp b/dbms/src/Storages/System/StorageSystemBuildOptions.cpp index f354da97944..e62e6e9bbfd 100644 --- a/dbms/src/Storages/System/StorageSystemBuildOptions.cpp +++ b/dbms/src/Storages/System/StorageSystemBuildOptions.cpp @@ -13,10 +13,10 @@ namespace DB StorageSystemBuildOptions::StorageSystemBuildOptions(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "name", std::make_shared() }, { "value", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemClusters.cpp b/dbms/src/Storages/System/StorageSystemClusters.cpp index 1e67e433d48..904d22d180e 100644 --- a/dbms/src/Storages/System/StorageSystemClusters.cpp +++ b/dbms/src/Storages/System/StorageSystemClusters.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemClusters::StorageSystemClusters(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "cluster", std::make_shared() }, { "shard_num", std::make_shared() }, { "shard_weight", std::make_shared() }, @@ -25,7 +25,7 @@ StorageSystemClusters::StorageSystemClusters(const std::string & name_) { "is_local", std::make_shared() }, { "user", std::make_shared() }, { "default_database", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemColumns.cpp b/dbms/src/Storages/System/StorageSystemColumns.cpp index 83c5dca9117..18598b1c1dc 100644 --- a/dbms/src/Storages/System/StorageSystemColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemColumns.cpp @@ -18,7 +18,7 @@ namespace DB StorageSystemColumns::StorageSystemColumns(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "database", std::make_shared() }, { "table", std::make_shared() }, { "name", std::make_shared() }, @@ -28,7 +28,7 @@ StorageSystemColumns::StorageSystemColumns(const std::string & name_) { "data_compressed_bytes", std::make_shared() }, { "data_uncompressed_bytes", std::make_shared() }, { "marks_bytes", std::make_shared() }, - }); + })); } @@ -137,8 +137,8 @@ BlockInputStreams StorageSystemColumns::read( throw; } - columns = storage->columns.getAll(); - column_defaults = storage->columns.defaults; + columns = storage->getColumns().getAll(); + column_defaults = storage->getColumns().defaults; /** Info about sizes of columns for tables of MergeTree family. * NOTE: It is possible to add getter for this info to IStorage interface. diff --git a/dbms/src/Storages/System/StorageSystemDatabases.cpp b/dbms/src/Storages/System/StorageSystemDatabases.cpp index 79a3b3483a6..49c78688616 100644 --- a/dbms/src/Storages/System/StorageSystemDatabases.cpp +++ b/dbms/src/Storages/System/StorageSystemDatabases.cpp @@ -13,12 +13,12 @@ namespace DB StorageSystemDatabases::StorageSystemDatabases(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ {"name", std::make_shared()}, {"engine", std::make_shared()}, {"data_path", std::make_shared()}, {"metadata_path", std::make_shared()}, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemDictionaries.cpp b/dbms/src/Storages/System/StorageSystemDictionaries.cpp index 84bf4a2c98f..c57c1c7f459 100644 --- a/dbms/src/Storages/System/StorageSystemDictionaries.cpp +++ b/dbms/src/Storages/System/StorageSystemDictionaries.cpp @@ -21,7 +21,7 @@ namespace DB StorageSystemDictionaries::StorageSystemDictionaries(const std::string & name) : name{name} { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "name", std::make_shared() }, { "origin", std::make_shared() }, { "type", std::make_shared() }, @@ -36,7 +36,7 @@ StorageSystemDictionaries::StorageSystemDictionaries(const std::string & name) { "creation_time", std::make_shared() }, { "source", std::make_shared() }, { "last_exception", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemEvents.cpp b/dbms/src/Storages/System/StorageSystemEvents.cpp index ac613a7e84e..1dc49ad37b2 100644 --- a/dbms/src/Storages/System/StorageSystemEvents.cpp +++ b/dbms/src/Storages/System/StorageSystemEvents.cpp @@ -13,11 +13,11 @@ namespace DB StorageSystemEvents::StorageSystemEvents(const std::string & name_) : name(name_) { - columns = ColumnsDescription( + setColumns(ColumnsDescription( { {"event", std::make_shared()}, {"value", std::make_shared()}, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemFunctions.cpp b/dbms/src/Storages/System/StorageSystemFunctions.cpp index 2d42bee9a46..909bf1d8089 100644 --- a/dbms/src/Storages/System/StorageSystemFunctions.cpp +++ b/dbms/src/Storages/System/StorageSystemFunctions.cpp @@ -16,10 +16,10 @@ namespace DB StorageSystemFunctions::StorageSystemFunctions(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "name", std::make_shared() }, { "is_aggregate", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemGraphite.cpp b/dbms/src/Storages/System/StorageSystemGraphite.cpp index 30cc56c55e3..f558adc1d95 100644 --- a/dbms/src/Storages/System/StorageSystemGraphite.cpp +++ b/dbms/src/Storages/System/StorageSystemGraphite.cpp @@ -125,7 +125,7 @@ static Strings getAllGraphiteSections(const AbstractConfiguration & config) StorageSystemGraphite::StorageSystemGraphite(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ {"config_name", std::make_shared()}, {"regexp", std::make_shared()}, {"function", std::make_shared()}, @@ -133,7 +133,7 @@ StorageSystemGraphite::StorageSystemGraphite(const std::string & name_) {"precision", std::make_shared()}, {"priority", std::make_shared()}, {"is_default", std::make_shared()}, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemMerges.cpp b/dbms/src/Storages/System/StorageSystemMerges.cpp index c32cad1265b..d3af993e29e 100644 --- a/dbms/src/Storages/System/StorageSystemMerges.cpp +++ b/dbms/src/Storages/System/StorageSystemMerges.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemMerges::StorageSystemMerges(const std::string & name) : name{name} { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "database", std::make_shared() }, { "table", std::make_shared() }, { "elapsed", std::make_shared() }, @@ -31,7 +31,7 @@ StorageSystemMerges::StorageSystemMerges(const std::string & name) { "columns_written", std::make_shared() }, { "memory_usage", std::make_shared() }, { "thread_number", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemMetrics.cpp b/dbms/src/Storages/System/StorageSystemMetrics.cpp index 57935b13fea..9d3b1cc9fbc 100644 --- a/dbms/src/Storages/System/StorageSystemMetrics.cpp +++ b/dbms/src/Storages/System/StorageSystemMetrics.cpp @@ -14,10 +14,10 @@ namespace DB StorageSystemMetrics::StorageSystemMetrics(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ {"metric", std::make_shared()}, {"value", std::make_shared()}, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemModels.cpp b/dbms/src/Storages/System/StorageSystemModels.cpp index 6ef9d157303..5175989b861 100644 --- a/dbms/src/Storages/System/StorageSystemModels.cpp +++ b/dbms/src/Storages/System/StorageSystemModels.cpp @@ -14,13 +14,13 @@ namespace DB StorageSystemModels::StorageSystemModels(const std::string & name) : name{name} { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "name", std::make_shared() }, { "origin", std::make_shared() }, { "type", std::make_shared() }, { "creation_time", std::make_shared() }, { "last_exception", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemNumbers.cpp b/dbms/src/Storages/System/StorageSystemNumbers.cpp index d5e72bcbdc3..49a3c7ca513 100644 --- a/dbms/src/Storages/System/StorageSystemNumbers.cpp +++ b/dbms/src/Storages/System/StorageSystemNumbers.cpp @@ -47,7 +47,7 @@ private: StorageSystemNumbers::StorageSystemNumbers(const std::string & name_, bool multithreaded_, size_t limit_) : name(name_), multithreaded(multithreaded_), limit(limit_) { - columns = ColumnsDescription({{"number", std::make_shared()}}); + setColumns(ColumnsDescription({{"number", std::make_shared()}})); } diff --git a/dbms/src/Storages/System/StorageSystemOne.cpp b/dbms/src/Storages/System/StorageSystemOne.cpp index 9cd74a7525c..7714a0ea53c 100644 --- a/dbms/src/Storages/System/StorageSystemOne.cpp +++ b/dbms/src/Storages/System/StorageSystemOne.cpp @@ -13,7 +13,7 @@ namespace DB StorageSystemOne::StorageSystemOne(const std::string & name_) : name(name_) { - columns = ColumnsDescription({{"dummy", std::make_shared()}}); + setColumns(ColumnsDescription({{"dummy", std::make_shared()}})); } diff --git a/dbms/src/Storages/System/StorageSystemPartsBase.cpp b/dbms/src/Storages/System/StorageSystemPartsBase.cpp index 5143b73955f..9d94655fc18 100644 --- a/dbms/src/Storages/System/StorageSystemPartsBase.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsBase.cpp @@ -280,7 +280,7 @@ bool StorageSystemPartsBase::hasColumn(const String & column_name) const StorageSystemPartsBase::StorageSystemPartsBase(std::string name_, NamesAndTypesList && columns_) : name(std::move(name_)) { - columns = ColumnsDescription(std::move(columns_)); + setColumns(ColumnsDescription(std::move(columns_))); } } diff --git a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp index d804504f13a..8e55625c5cd 100644 --- a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp @@ -61,8 +61,8 @@ void StorageSystemPartsColumns::processNextStorage(MutableColumns & columns, con String default_expression; }; - NamesAndTypesList columns_list = info.storage->columns.getAll(); - const auto & column_defaults = info.storage->columns.defaults; + NamesAndTypesList columns_list = info.storage->getColumns().getAll(); + const auto & column_defaults = info.storage->getColumns().defaults; std::unordered_map columns_info; for (const auto & column : columns_list) diff --git a/dbms/src/Storages/System/StorageSystemProcesses.cpp b/dbms/src/Storages/System/StorageSystemProcesses.cpp index 15ecc1a3d95..793e3124a2a 100644 --- a/dbms/src/Storages/System/StorageSystemProcesses.cpp +++ b/dbms/src/Storages/System/StorageSystemProcesses.cpp @@ -14,7 +14,7 @@ namespace DB StorageSystemProcesses::StorageSystemProcesses(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "is_initial_query", std::make_shared() }, { "user", std::make_shared() }, @@ -51,7 +51,7 @@ StorageSystemProcesses::StorageSystemProcesses(const std::string & name_) { "memory_usage", std::make_shared() }, { "peak_memory_usage", std::make_shared() }, { "query", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemReplicas.cpp b/dbms/src/Storages/System/StorageSystemReplicas.cpp index fdcc6984861..ea2c8b1cde2 100644 --- a/dbms/src/Storages/System/StorageSystemReplicas.cpp +++ b/dbms/src/Storages/System/StorageSystemReplicas.cpp @@ -17,7 +17,7 @@ namespace DB StorageSystemReplicas::StorageSystemReplicas(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "database", std::make_shared() }, { "table", std::make_shared() }, { "engine", std::make_shared() }, @@ -44,7 +44,7 @@ StorageSystemReplicas::StorageSystemReplicas(const std::string & name_) { "absolute_delay", std::make_shared() }, { "total_replicas", std::make_shared() }, { "active_replicas", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp b/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp index b0ba714fef4..77b265ad065 100644 --- a/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp +++ b/dbms/src/Storages/System/StorageSystemReplicationQueue.cpp @@ -20,7 +20,7 @@ namespace DB StorageSystemReplicationQueue::StorageSystemReplicationQueue(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ /// Table properties. { "database", std::make_shared() }, { "table", std::make_shared() }, @@ -43,7 +43,7 @@ StorageSystemReplicationQueue::StorageSystemReplicationQueue(const std::string & { "num_postponed", std::make_shared() }, { "postpone_reason", std::make_shared() }, { "last_postpone_time", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemSettings.cpp b/dbms/src/Storages/System/StorageSystemSettings.cpp index d8a758becc7..efb50c559cc 100644 --- a/dbms/src/Storages/System/StorageSystemSettings.cpp +++ b/dbms/src/Storages/System/StorageSystemSettings.cpp @@ -14,12 +14,12 @@ namespace DB StorageSystemSettings::StorageSystemSettings(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "name", std::make_shared() }, { "value", std::make_shared() }, { "changed", std::make_shared() }, { "description", std::make_shared() }, - }); + })); } diff --git a/dbms/src/Storages/System/StorageSystemTables.cpp b/dbms/src/Storages/System/StorageSystemTables.cpp index 2db2a8052cc..99ed89739f9 100644 --- a/dbms/src/Storages/System/StorageSystemTables.cpp +++ b/dbms/src/Storages/System/StorageSystemTables.cpp @@ -114,7 +114,7 @@ protected: StorageSystemTables::StorageSystemTables(const std::string & name_) : name(name_) { - columns = ColumnsDescription( + setColumns(ColumnsDescription( { {"database", std::make_shared()}, {"name", std::make_shared()}, @@ -122,7 +122,7 @@ StorageSystemTables::StorageSystemTables(const std::string & name_) {"is_temporary", std::make_shared()}, {"data_path", std::make_shared()}, {"metadata_path", std::make_shared()}, - }); + })); virtual_columns = { diff --git a/dbms/src/Storages/System/StorageSystemZooKeeper.cpp b/dbms/src/Storages/System/StorageSystemZooKeeper.cpp index a5d5e2dab96..67660ea3446 100644 --- a/dbms/src/Storages/System/StorageSystemZooKeeper.cpp +++ b/dbms/src/Storages/System/StorageSystemZooKeeper.cpp @@ -22,7 +22,7 @@ namespace DB StorageSystemZooKeeper::StorageSystemZooKeeper(const std::string & name_) : name(name_) { - columns = ColumnsDescription({ + setColumns(ColumnsDescription({ { "name", std::make_shared() }, { "value", std::make_shared() }, { "czxid", std::make_shared() }, @@ -37,7 +37,7 @@ StorageSystemZooKeeper::StorageSystemZooKeeper(const std::string & name_) { "numChildren", std::make_shared() }, { "pzxid", std::make_shared() }, { "path", std::make_shared() }, - }); + })); } diff --git a/dbms/src/TableFunctions/TableFunctionMerge.cpp b/dbms/src/TableFunctions/TableFunctionMerge.cpp index 2a12dbca275..6b0710d4ba0 100644 --- a/dbms/src/TableFunctions/TableFunctionMerge.cpp +++ b/dbms/src/TableFunctions/TableFunctionMerge.cpp @@ -51,7 +51,7 @@ static NamesAndTypesList chooseColumns(const String & source_database, const Str throw Exception("Error while executing table function merge. In database " + source_database + " no one matches regular expression: " + table_name_regexp_, ErrorCodes::UNKNOWN_TABLE); - return any_table->columns.getPhysical(); + return any_table->getColumns().getPhysical(); } diff --git a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp index 6eede709352..56bb257f252 100644 --- a/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp +++ b/dbms/src/TableFunctions/getStructureOfRemoteTable.cpp @@ -28,7 +28,7 @@ ColumnsDescription getStructureOfRemoteTable( const auto & shard_info = cluster.getAnyShardInfo(); if (shard_info.isLocal()) - return context.getTable(database, table)->columns; + return context.getTable(database, table)->getColumns(); /// Request for a table description String query = "DESC TABLE " + backQuoteIfNeed(database) + "." + backQuoteIfNeed(table); From 5906c9a9886ad74e4d4a95ebb454fadc4bb8987a Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Tue, 13 Mar 2018 18:00:28 +0300 Subject: [PATCH 041/244] rename for clarity --- dbms/src/Analyzers/AnalyzeColumns.cpp | 2 +- dbms/src/Analyzers/ExecuteTableFunctions.cpp | 2 +- dbms/src/Core/iostream_debug_helpers.cpp | 2 +- .../DataStreams/RemoteBlockInputStream.cpp | 2 +- dbms/src/Functions/FunctionsMiscellaneous.cpp | 5 ++--- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 2 +- .../Interpreters/InterpreterAlterQuery.cpp | 2 +- .../Interpreters/InterpreterInsertQuery.cpp | 2 +- dbms/src/Storages/ColumnsDescription.cpp | 8 ++++---- dbms/src/Storages/ColumnsDescription.h | 11 ++++------ dbms/src/Storages/ITableDeclaration.cpp | 12 +++++------ .../MergeTree/MergeTreeBlockInputStream.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 20 +++++++++---------- dbms/src/Storages/MergeTree/MergeTreeData.h | 4 ++-- .../MergeTree/MergeTreeDataMerger.cpp | 4 ++-- .../Storages/MergeTree/MergeTreeDataPart.cpp | 6 +++--- .../MergeTree/MergeTreeDataSelectExecutor.cpp | 4 ++-- .../MergeTree/MergeTreeDataWriter.cpp | 2 +- .../Storages/MergeTree/MergeTreeReadPool.cpp | 2 +- .../MergeTree/MergeTreeWhereOptimizer.cpp | 4 ++-- .../ReplicatedMergeTreeAlterThread.cpp | 2 +- dbms/src/Storages/StorageDistributed.cpp | 8 ++++---- dbms/src/Storages/StorageJoin.cpp | 2 +- dbms/src/Storages/StorageLog.cpp | 4 ++-- dbms/src/Storages/StorageMerge.cpp | 2 +- dbms/src/Storages/StorageMergeTree.cpp | 4 ++-- .../Storages/StorageReplicatedMergeTree.cpp | 2 +- dbms/src/Storages/StorageTinyLog.cpp | 4 ++-- .../src/TableFunctions/TableFunctionMerge.cpp | 2 +- 29 files changed, 62 insertions(+), 66 deletions(-) diff --git a/dbms/src/Analyzers/AnalyzeColumns.cpp b/dbms/src/Analyzers/AnalyzeColumns.cpp index efcbaf66888..73760c4ff01 100644 --- a/dbms/src/Analyzers/AnalyzeColumns.cpp +++ b/dbms/src/Analyzers/AnalyzeColumns.cpp @@ -173,7 +173,7 @@ ASTPtr createASTIdentifierForColumnInTable(const String & column, const CollectT void createASTsForAllColumnsInTable(const CollectTables::TableInfo & table, ASTs & res) { if (table.storage) - for (const auto & name : table.storage->getColumns().getNames()) + for (const auto & name : table.storage->getColumns().getNamesOfPhysical()) res.emplace_back(createASTIdentifierForColumnInTable(name, table)); else for (size_t i = 0, size = table.structure_of_subquery.columns(); i < size; ++i) diff --git a/dbms/src/Analyzers/ExecuteTableFunctions.cpp b/dbms/src/Analyzers/ExecuteTableFunctions.cpp index 37cc3d66eec..d79fa1481f0 100644 --- a/dbms/src/Analyzers/ExecuteTableFunctions.cpp +++ b/dbms/src/Analyzers/ExecuteTableFunctions.cpp @@ -72,7 +72,7 @@ void ExecuteTableFunctions::dump(WriteBuffer & out) const { writeString(table.second->getName(), out); writeCString("\n\n", out); - writeString(table.second->getColumns().getPhysical().toString(), out); + writeString(table.second->getColumns().getAllPhysical().toString(), out); writeCString("\n", out); } } diff --git a/dbms/src/Core/iostream_debug_helpers.cpp b/dbms/src/Core/iostream_debug_helpers.cpp index bd19c453d8d..2ad56c402b7 100644 --- a/dbms/src/Core/iostream_debug_helpers.cpp +++ b/dbms/src/Core/iostream_debug_helpers.cpp @@ -44,7 +44,7 @@ std::ostream & operator<<(std::ostream & stream, const IDataType & what) std::ostream & operator<<(std::ostream & stream, const IStorage & what) { stream << "IStorage(name = " << what.getName() << ", tableName = " << what.getTableName() << ") {" - << what.getColumns().getPhysical().toString() + << what.getColumns().getAllPhysical().toString() << "}"; // isRemote supportsSampling supportsFinal supportsPrewhere return stream; diff --git a/dbms/src/DataStreams/RemoteBlockInputStream.cpp b/dbms/src/DataStreams/RemoteBlockInputStream.cpp index b5e20898b89..7b851ec8469 100644 --- a/dbms/src/DataStreams/RemoteBlockInputStream.cpp +++ b/dbms/src/DataStreams/RemoteBlockInputStream.cpp @@ -138,7 +138,7 @@ void RemoteBlockInputStream::sendExternalTables() { StoragePtr cur = table.second; QueryProcessingStage::Enum stage = QueryProcessingStage::Complete; - BlockInputStreams input = cur->read(cur->getColumns().getNames(), {}, context, + BlockInputStreams input = cur->read(cur->getColumns().getNamesOfPhysical(), {}, context, stage, DEFAULT_BLOCK_SIZE, 1); if (input.size() == 0) res.push_back(std::make_pair(std::make_shared(cur->getSampleBlock()), table.first)); diff --git a/dbms/src/Functions/FunctionsMiscellaneous.cpp b/dbms/src/Functions/FunctionsMiscellaneous.cpp index 99ed8b2dda6..475fd47ce6f 100644 --- a/dbms/src/Functions/FunctionsMiscellaneous.cpp +++ b/dbms/src/Functions/FunctionsMiscellaneous.cpp @@ -1750,9 +1750,8 @@ void FunctionHasColumnInTable::executeImpl(Block & block, const ColumnNumbers & { std::vector> host_names = {{ host_name }}; auto cluster = std::make_shared(global_context.getSettings(), host_names, !user_name.empty() ? user_name : "default", password, global_context.getTCPPort(), false); - auto names_and_types_list = getStructureOfRemoteTable(*cluster, database_name, table_name, global_context); - const auto & names = names_and_types_list.getNames(); - has_column = std::find(names.begin(), names.end(), column_name) != names.end(); + auto remote_columns = getStructureOfRemoteTable(*cluster, database_name, table_name, global_context); + has_column = remote_columns.hasPhysical(column_name); } block.getByPosition(result).column = DataTypeUInt8().createColumnConst(block.rows(), UInt64(has_column)); diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 4f0fe52bcff..f0bc8137029 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -190,7 +190,7 @@ ExpressionAnalyzer::ExpressionAnalyzer( } if (storage && source_columns.empty()) - source_columns = storage->getColumns().getPhysical(); + source_columns = storage->getColumns().getAllPhysical(); else removeDuplicateColumns(source_columns); diff --git a/dbms/src/Interpreters/InterpreterAlterQuery.cpp b/dbms/src/Interpreters/InterpreterAlterQuery.cpp index 377f92d6c8d..f4708a67c3d 100644 --- a/dbms/src/Interpreters/InterpreterAlterQuery.cpp +++ b/dbms/src/Interpreters/InterpreterAlterQuery.cpp @@ -200,7 +200,7 @@ void InterpreterAlterQuery::PartitionCommands::validate(const IStorage * table) { String column_name = command.column_name.safeGet(); - if (!table->getColumns().has(column_name)) + if (!table->getColumns().hasPhysical(column_name)) { throw Exception("Wrong column name. Cannot find column " + column_name + " to clear it from partition", DB::ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/src/Interpreters/InterpreterInsertQuery.cpp b/dbms/src/Interpreters/InterpreterInsertQuery.cpp index 3e054f576a4..c21e3c26f93 100644 --- a/dbms/src/Interpreters/InterpreterInsertQuery.cpp +++ b/dbms/src/Interpreters/InterpreterInsertQuery.cpp @@ -95,7 +95,7 @@ BlockIO InterpreterInsertQuery::execute() auto table_lock = table->lockStructure(true, __PRETTY_FUNCTION__); - NamesAndTypesList required_columns = table->getColumns().getPhysical(); + NamesAndTypesList required_columns = table->getColumns().getAllPhysical(); /// We create a pipeline of several streams, into which we will write data. BlockOutputStreamPtr out; diff --git a/dbms/src/Storages/ColumnsDescription.cpp b/dbms/src/Storages/ColumnsDescription.cpp index 683f10f324d..d17f532b0ef 100644 --- a/dbms/src/Storages/ColumnsDescription.cpp +++ b/dbms/src/Storages/ColumnsDescription.cpp @@ -27,7 +27,7 @@ namespace ErrorCodes } -NamesAndTypesList ColumnsDescription::getPhysical() const +NamesAndTypesList ColumnsDescription::getAllPhysical() const { return ext::collection_cast(boost::join(ordinary, materialized)); } @@ -39,13 +39,13 @@ NamesAndTypesList ColumnsDescription::getAll() const } -Names ColumnsDescription::getNames() const +Names ColumnsDescription::getNamesOfPhysical() const { return ext::map(boost::join(ordinary, materialized), [] (const auto & it) { return it.name; }); } -NameAndTypePair ColumnsDescription::get(const String & column_name) const +NameAndTypePair ColumnsDescription::getPhysical(const String & column_name) const { for (auto & it : boost::join(ordinary, materialized)) if (it.name == column_name) @@ -54,7 +54,7 @@ NameAndTypePair ColumnsDescription::get(const String & column_name) const } -bool ColumnsDescription::has(const String & column_name) const +bool ColumnsDescription::hasPhysical(const String & column_name) const { for (auto & it : boost::join(ordinary, materialized)) if (it.name == column_name) diff --git a/dbms/src/Storages/ColumnsDescription.h b/dbms/src/Storages/ColumnsDescription.h index e4e45ff6fe2..288d2712b3b 100644 --- a/dbms/src/Storages/ColumnsDescription.h +++ b/dbms/src/Storages/ColumnsDescription.h @@ -42,19 +42,16 @@ struct ColumnsDescription bool operator!=(const ColumnsDescription & other) const { return !(*this == other); } /// ordinary + materialized. - NamesAndTypesList getPhysical() const; + NamesAndTypesList getAllPhysical() const; /// ordinary + materialized + aliases. NamesAndTypesList getAll() const; - /// Get names of physical columns. - Names getNames() const; + Names getNamesOfPhysical() const; - /// Get a physical column by name. - NameAndTypePair get(const String & column_name) const; + NameAndTypePair getPhysical(const String & column_name) const; - /// Is there a physical column with the given name. - bool has(const String & column_name) const; + bool hasPhysical(const String & column_name) const; String toString() const; diff --git a/dbms/src/Storages/ITableDeclaration.cpp b/dbms/src/Storages/ITableDeclaration.cpp index 783b0b2a7ed..9a6ac0e2538 100644 --- a/dbms/src/Storages/ITableDeclaration.cpp +++ b/dbms/src/Storages/ITableDeclaration.cpp @@ -34,12 +34,12 @@ void ITableDeclaration::setColumns(ColumnsDescription columns_) bool ITableDeclaration::hasColumn(const String & column_name) const { - return getColumns().has(column_name); /// By default, we assume that there are no virtual columns in the storage. + return getColumns().hasPhysical(column_name); /// By default, we assume that there are no virtual columns in the storage. } NameAndTypePair ITableDeclaration::getColumn(const String & column_name) const { - return getColumns().get(column_name); /// By default, we assume that there are no virtual columns in the storage. + return getColumns().getPhysical(column_name); /// By default, we assume that there are no virtual columns in the storage. } @@ -119,7 +119,7 @@ static NamesAndTypesMap getColumnsMap(const Args &... args) void ITableDeclaration::check(const Names & column_names) const { - const NamesAndTypesList & available_columns = getColumns().getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getAllPhysical(); if (column_names.empty()) throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns), @@ -147,7 +147,7 @@ void ITableDeclaration::check(const Names & column_names) const void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const { - const NamesAndTypesList & available_columns = getColumns().getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getAllPhysical(); const auto columns_map = getColumnsMap(available_columns); using UniqueStrings = google::dense_hash_set; @@ -175,7 +175,7 @@ void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const Names & column_names) const { - const NamesAndTypesList & available_columns = getColumns().getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getAllPhysical(); const auto available_columns_map = getColumnsMap(available_columns); const NamesAndTypesMap & provided_columns_map = getColumnsMap(provided_columns); @@ -212,7 +212,7 @@ void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const void ITableDeclaration::check(const Block & block, bool need_all) const { - const NamesAndTypesList & available_columns = getColumns().getPhysical(); + const NamesAndTypesList & available_columns = getColumns().getAllPhysical(); const auto columns_map = getColumnsMap(available_columns); using NameSet = std::unordered_set; diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp index a6d2958a786..1e9cea1887f 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockInputStream.cpp @@ -141,7 +141,7 @@ try if (!column_names.empty()) storage.check(data_part->columns, column_names); - const NamesAndTypesList & physical_columns = storage.getColumns().getPhysical(); + const NamesAndTypesList & physical_columns = storage.getColumns().getAllPhysical(); pre_columns = physical_columns.addTypes(pre_column_names); columns = physical_columns.addTypes(column_names); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index ed16d1536de..b5200441383 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -110,7 +110,7 @@ MergeTreeData::MergeTreeData( data_parts_by_state_and_info(data_parts_indexes.get()) { /// NOTE: using the same columns list as is read when performing actual merges. - merging_params.check(getColumns().getPhysical()); + merging_params.check(getColumns().getAllPhysical()); if (!primary_expr_ast) throw Exception("Primary key cannot be empty", ErrorCodes::BAD_ARGUMENTS); @@ -222,11 +222,11 @@ void MergeTreeData::initPrimaryKey() primary_sort_descr.clear(); addSortDescription(primary_sort_descr, primary_expr_ast); - primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(false); + primary_expr = ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumns().getAllPhysical()).getActions(false); { ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(true); + ExpressionAnalyzer(primary_expr_ast, context, nullptr, getColumns().getAllPhysical()).getActions(true); primary_key_sample = projected_expr->getSampleBlock(); } @@ -241,10 +241,10 @@ void MergeTreeData::initPrimaryKey() if (secondary_sort_expr_ast) { addSortDescription(sort_descr, secondary_sort_expr_ast); - secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(false); + secondary_sort_expr = ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumns().getAllPhysical()).getActions(false); ExpressionActionsPtr projected_expr = - ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(true); + ExpressionAnalyzer(secondary_sort_expr_ast, context, nullptr, getColumns().getAllPhysical()).getActions(true); auto secondary_key_sample = projected_expr->getSampleBlock(); checkKeyExpression(*secondary_sort_expr, secondary_key_sample, "Secondary"); @@ -257,7 +257,7 @@ void MergeTreeData::initPartitionKey() if (!partition_expr_ast || partition_expr_ast->children.empty()) return; - partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, getColumns().getPhysical()).getActions(false); + partition_expr = ExpressionAnalyzer(partition_expr_ast, context, nullptr, getColumns().getAllPhysical()).getActions(false); for (const ASTPtr & ast : partition_expr_ast->children) { String col_name = ast->getColumnName(); @@ -903,7 +903,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) columns_alter_forbidden.insert(merging_params.sign_column); std::map old_types; - for (const auto & column : getColumns().getPhysical()) + for (const auto & column : getColumns().getAllPhysical()) old_types.emplace(column.name, column.type.get()); for (const AlterCommand & command : commands) @@ -931,7 +931,7 @@ void MergeTreeData::checkAlter(const AlterCommands & commands) NameToNameMap unused_map; bool unused_bool; - createConvertExpression(nullptr, getColumns().getPhysical(), new_columns.getPhysical(), unused_expression, unused_map, unused_bool); + createConvertExpression(nullptr, getColumns().getAllPhysical(), new_columns.getAllPhysical(), unused_expression, unused_map, unused_bool); } void MergeTreeData::createConvertExpression(const DataPartPtr & part, const NamesAndTypesList & old_columns, const NamesAndTypesList & new_columns, @@ -1835,7 +1835,7 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : getColumns().getPhysical()) + for (const auto & column : getColumns().getAllPhysical()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; @@ -1868,7 +1868,7 @@ void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : getColumns().getPhysical()) + for (const auto & column : getColumns().getAllPhysical()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.h b/dbms/src/Storages/MergeTree/MergeTreeData.h index da6999ac965..d440d86d62b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.h +++ b/dbms/src/Storages/MergeTree/MergeTreeData.h @@ -313,12 +313,12 @@ public: if (column_name == "_sample_factor") return NameAndTypePair("_sample_factor", std::make_shared()); - return getColumns().get(column_name); + return getColumns().getPhysical(column_name); } bool hasColumn(const String & column_name) const override { - return getColumns().has(column_name) + return getColumns().hasPhysical(column_name) || column_name == "_part" || column_name == "_part_index" || column_name == "_sample_factor"; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index dafa27e2346..229c40404bb 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -536,8 +536,8 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataMerger::mergePartsToTemporaryPart for (const MergeTreeData::DataPartPtr & part : parts) part->accumulateColumnSizes(merged_column_to_size); - Names all_column_names = data.getColumns().getNames(); - NamesAndTypesList all_columns = data.getColumns().getPhysical(); + Names all_column_names = data.getColumns().getNamesOfPhysical(); + NamesAndTypesList all_columns = data.getColumns().getAllPhysical(); const SortDescription sort_desc = data.getSortDescription(); NamesAndTypesList gathering_columns, merging_columns; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 92936e2adc7..38608f6ea32 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -418,7 +418,7 @@ UInt64 MergeTreeDataPart::getColumnMrkSize(const String & name) const */ String MergeTreeDataPart::getColumnNameWithMinumumCompressedSize() const { - const auto & columns = storage.getColumns().getPhysical(); + const auto & columns = storage.getColumns().getAllPhysical(); const std::string * minimum_size_column = nullptr; UInt64 minimum_size = std::numeric_limits::max(); @@ -774,7 +774,7 @@ void MergeTreeDataPart::accumulateColumnSizes(ColumnToSize & column_to_size) con { std::shared_lock part_lock(columns_lock); - for (const NameAndTypePair & name_type : storage.getColumns().getPhysical()) + for (const NameAndTypePair & name_type : storage.getColumns().getAllPhysical()) { name_type.type->enumerateStreams([&](const IDataType::SubstreamPath & substream_path) { @@ -794,7 +794,7 @@ void MergeTreeDataPart::loadColumns(bool require) throw Exception("No columns.txt in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); /// If there is no file with a list of columns, write it down. - for (const NameAndTypePair & column : storage.getColumns().getPhysical()) + for (const NameAndTypePair & column : storage.getColumns().getAllPhysical()) if (Poco::File(getFullPath() + escapeForFileName(column.name) + ".bin").exists()) columns.push_back(column); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp index 77ba844ee0b..afc9700cf0b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp @@ -175,7 +175,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read( } } - NamesAndTypesList available_real_columns = data.getColumns().getPhysical(); + NamesAndTypesList available_real_columns = data.getColumns().getAllPhysical(); NamesAndTypesList available_real_and_virtual_columns = available_real_columns; for (const auto & name : virt_column_names) @@ -857,7 +857,7 @@ void MergeTreeDataSelectExecutor::createPositiveSignCondition( arguments->children.push_back(sign); arguments->children.push_back(one); - out_expression = ExpressionAnalyzer(function, context, {}, data.getColumns().getPhysical()).getActions(false); + out_expression = ExpressionAnalyzer(function, context, {}, data.getColumns().getAllPhysical()).getActions(false); out_column = function->getColumnName(); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index c57d1d5bfdd..e85efa435fd 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -205,7 +205,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithPa /// either default lz4 or compression method with zero thresholds on absolute and relative part size. auto compression_settings = data.context.chooseCompressionSettings(0, 0); - NamesAndTypesList columns = data.getColumns().getPhysical().filter(block.getNames()); + NamesAndTypesList columns = data.getColumns().getAllPhysical().filter(block.getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_settings); out.writePrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp index 452aee79bf3..370797968b3 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeReadPool.cpp @@ -238,7 +238,7 @@ std::vector MergeTreeReadPool::fillPerPartInfo( if (!required_column_names.empty()) data.check(part.data_part->columns, required_column_names); - const NamesAndTypesList & physical_columns = data.getColumns().getPhysical(); + const NamesAndTypesList & physical_columns = data.getColumns().getAllPhysical(); per_part_pre_columns.push_back(physical_columns.addTypes(required_pre_column_names)); per_part_columns.push_back(physical_columns.addTypes(required_column_names)); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp index ac28d3e782d..077ea9fed5d 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeWhereOptimizer.cpp @@ -41,9 +41,9 @@ MergeTreeWhereOptimizer::MergeTreeWhereOptimizer( Logger * log) : primary_key_columns{ext::map(data.getPrimarySortDescription(), [] (const SortColumnDescription & col) { return col.column_name; })}, - table_columns{ext::map(data.getColumns().getPhysical(), + table_columns{ext::map(data.getColumns().getAllPhysical(), [] (const NameAndTypePair & col) { return col.name; })}, - block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.getColumns().getPhysical())}, + block_with_constants{PKCondition::getBlockWithConstants(query_info.query, context, data.getColumns().getAllPhysical())}, prepared_sets(query_info.sets), log{log} { diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp index 1fcba112fed..35a2dfcc6b7 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp @@ -124,7 +124,7 @@ void ReplicatedMergeTreeAlterThread::run() if (!changed_version) parts = storage.data.getDataParts(); - const auto columns_for_parts = storage.getColumns().getPhysical(); + const auto columns_for_parts = storage.getColumns().getAllPhysical(); for (const MergeTreeData::DataPartPtr & part : parts) { diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 972a4817009..690d513f50e 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -142,7 +142,7 @@ StorageDistributed::StorageDistributed( table_name(table_name_), remote_database(remote_database_), remote_table(remote_table_), context(context_), cluster_name(context.getMacros().expand(cluster_name_)), has_sharding_key(sharding_key_), - sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, getColumns().getPhysical()).getActions(false) : nullptr), + sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, getColumns().getAllPhysical()).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(table_name) + '/')) { @@ -287,13 +287,13 @@ NameAndTypePair StorageDistributed::getColumn(const String & column_name) const if (const auto & type = VirtualColumnFactory::tryGetType(column_name)) return { column_name, type }; - return getColumns().get(column_name); + return getColumns().getPhysical(column_name); } bool StorageDistributed::hasColumn(const String & column_name) const { - return VirtualColumnFactory::hasColumn(column_name) || getColumns().has(column_name); + return VirtualColumnFactory::hasColumn(column_name) || getColumns().hasPhysical(column_name); } void StorageDistributed::createDirectoryMonitors() @@ -386,7 +386,7 @@ void registerStorageDistributed(StorageFactory & factory) /// Check that sharding_key exists in the table and has numeric type. if (sharding_key) { - auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.getPhysical()).getActions(true); + auto sharding_expr = ExpressionAnalyzer(sharding_key, args.context, nullptr, args.columns.getAllPhysical()).getActions(true); const Block & block = sharding_expr->getSampleBlock(); if (block.columns() != 1) diff --git a/dbms/src/Storages/StorageJoin.cpp b/dbms/src/Storages/StorageJoin.cpp index 746f15bab50..aab48c3ed2a 100644 --- a/dbms/src/Storages/StorageJoin.cpp +++ b/dbms/src/Storages/StorageJoin.cpp @@ -29,7 +29,7 @@ StorageJoin::StorageJoin( key_names(key_names_), kind(kind_), strictness(strictness_) { for (const auto & key : key_names) - if (!getColumns().has(key)) + if (!getColumns().hasPhysical(key)) throw Exception{ "Key column (" + key + ") does not exist in table declaration.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE}; diff --git a/dbms/src/Storages/StorageLog.cpp b/dbms/src/Storages/StorageLog.cpp index c23d92de8fa..04d9f18ffd1 100644 --- a/dbms/src/Storages/StorageLog.cpp +++ b/dbms/src/Storages/StorageLog.cpp @@ -371,7 +371,7 @@ StorageLog::StorageLog( /// create files if they do not exist Poco::File(path + escapeForFileName(name) + '/').createDirectories(); - for (const auto & column : getColumns().getPhysical()) + for (const auto & column : getColumns().getAllPhysical()) addFiles(column.name, *column.type); marks_file = Poco::File(path + escapeForFileName(name) + '/' + DBMS_STORAGE_LOG_MARKS_FILE_NAME); @@ -499,7 +499,7 @@ BlockInputStreams StorageLog::read( processed_stage = QueryProcessingStage::FetchColumns; loadMarks(); - NamesAndTypesList all_columns = Nested::collect(getColumns().getPhysical().addTypes(column_names)); + NamesAndTypesList all_columns = Nested::collect(getColumns().getAllPhysical().addTypes(column_names)); std::shared_lock lock(rwlock); diff --git a/dbms/src/Storages/StorageMerge.cpp b/dbms/src/Storages/StorageMerge.cpp index 6f29850c8d1..e7090ad66ed 100644 --- a/dbms/src/Storages/StorageMerge.cpp +++ b/dbms/src/Storages/StorageMerge.cpp @@ -181,7 +181,7 @@ BlockInputStreams StorageMerge::read( /// If there are only virtual columns in query, you must request at least one other column. if (real_column_names.size() == 0) - real_column_names.push_back(ExpressionActions::getSmallestColumn(table->getColumns().getPhysical())); + real_column_names.push_back(ExpressionActions::getSmallestColumn(table->getColumns().getAllPhysical())); /// Substitute virtual column for its value when querying tables. ASTPtr modified_query_ast = query->clone(); diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index f22f24082fb..293c3254a8f 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -174,7 +174,7 @@ void StorageMergeTree::alter( throw Exception("MODIFY PRIMARY KEY only supported for tables without sampling key", ErrorCodes::BAD_ARGUMENTS); auto parts = data.getDataParts({MergeTreeDataPartState::PreCommitted, MergeTreeDataPartState::Committed, MergeTreeDataPartState::Outdated}); - auto columns_for_parts = new_columns.getPhysical(); + auto columns_for_parts = new_columns.getAllPhysical(); for (const MergeTreeData::DataPartPtr & part : parts) { if (auto transaction = data.alterDataPart(part, columns_for_parts, new_primary_key_ast, false)) @@ -418,7 +418,7 @@ void StorageMergeTree::clearColumnInPartition(const ASTPtr & partition, const Fi auto new_columns = getColumns(); alter_command.apply(new_columns); - auto columns_for_parts = new_columns.getPhysical(); + auto columns_for_parts = new_columns.getAllPhysical(); for (const auto & part : parts) { if (part->info.partition_id != partition_id) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index c2cf65e1c85..7ff7b1373e0 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -1511,7 +1511,7 @@ void StorageReplicatedMergeTree::executeClearColumnInPartition(const LogEntry & size_t modified_parts = 0; auto parts = data.getDataParts(); - auto columns_for_parts = new_columns.getPhysical(); + auto columns_for_parts = new_columns.getAllPhysical(); for (const auto & part : parts) { if (!entry_part_info.contains(part->info)) diff --git a/dbms/src/Storages/StorageTinyLog.cpp b/dbms/src/Storages/StorageTinyLog.cpp index bd4a8ca304f..cb62c911e63 100644 --- a/dbms/src/Storages/StorageTinyLog.cpp +++ b/dbms/src/Storages/StorageTinyLog.cpp @@ -296,7 +296,7 @@ StorageTinyLog::StorageTinyLog( throwFromErrno("Cannot create directory " + full_path, ErrorCodes::CANNOT_CREATE_DIRECTORY); } - for (const auto & col : getColumns().getPhysical()) + for (const auto & col : getColumns().getAllPhysical()) addFiles(col.name, *col.type); } @@ -348,7 +348,7 @@ BlockInputStreams StorageTinyLog::read( check(column_names); processed_stage = QueryProcessingStage::FetchColumns; return BlockInputStreams(1, std::make_shared( - max_block_size, Nested::collect(getColumns().getPhysical().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); + max_block_size, Nested::collect(getColumns().getAllPhysical().addTypes(column_names)), *this, context.getSettingsRef().max_read_buffer_size)); } diff --git a/dbms/src/TableFunctions/TableFunctionMerge.cpp b/dbms/src/TableFunctions/TableFunctionMerge.cpp index 6b0710d4ba0..45aa42fea32 100644 --- a/dbms/src/TableFunctions/TableFunctionMerge.cpp +++ b/dbms/src/TableFunctions/TableFunctionMerge.cpp @@ -51,7 +51,7 @@ static NamesAndTypesList chooseColumns(const String & source_database, const Str throw Exception("Error while executing table function merge. In database " + source_database + " no one matches regular expression: " + table_name_regexp_, ErrorCodes::UNKNOWN_TABLE); - return any_table->getColumns().getPhysical(); + return any_table->getColumns().getAllPhysical(); } From 13879f749107bd946fc4b038f1128de40f471104 Mon Sep 17 00:00:00 2001 From: proller Date: Tue, 13 Mar 2018 22:49:21 +0300 Subject: [PATCH 042/244] Test client-server ssl --- dbms/src/Server/Server.cpp | 4 ++-- dbms/src/Server/TCPHandlerFactory.h | 4 ++-- dbms/tests/clickhouse-test-server | 8 ++++++-- dbms/tests/client-test.xml | 1 + dbms/tests/server-test.xml | 30 ++++++++++++++++++++++++++++- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index db20c194573..9f09ffd549b 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -387,7 +387,7 @@ int Server::main(const std::vector & /*args*/) http_socket.setSendTimeout(settings.http_send_timeout); servers.emplace_back(new Poco::Net::HTTPServer( - new HTTPHandlerFactory(*this, "HTTPHandler-factory"), + new HTTPHandlerFactory(*this, "HTTPSHandler-factory"), server_pool, http_socket, http_params)); @@ -425,7 +425,7 @@ int Server::main(const std::vector & /*args*/) tcp_socket.setReceiveTimeout(settings.receive_timeout); tcp_socket.setSendTimeout(settings.send_timeout); servers.emplace_back(new Poco::Net::TCPServer( - new TCPHandlerFactory(*this), + new TCPHandlerFactory(*this, /* secure= */ true ), server_pool, tcp_socket, new Poco::Net::TCPServerParams)); diff --git a/dbms/src/Server/TCPHandlerFactory.h b/dbms/src/Server/TCPHandlerFactory.h index 1f454b35a8f..99cc23a45da 100644 --- a/dbms/src/Server/TCPHandlerFactory.h +++ b/dbms/src/Server/TCPHandlerFactory.h @@ -17,9 +17,9 @@ private: Poco::Logger * log; public: - explicit TCPHandlerFactory(IServer & server_) + explicit TCPHandlerFactory(IServer & server_, bool secure_ = false) : server(server_) - , log(&Logger::get("TCPHandlerFactory")) + , log(&Logger::get("TCP" + (secure_ ? "S" : "") + "HandlerFactory")) { } diff --git a/dbms/tests/clickhouse-test-server b/dbms/tests/clickhouse-test-server index 82d254017bf..7fb6918bfe5 100755 --- a/dbms/tests/clickhouse-test-server +++ b/dbms/tests/clickhouse-test-server @@ -22,8 +22,10 @@ export CLICKHOUSE_CONFIG=${CLICKHOUSE_CONFIG:=${CONFIG_SERVER_DIR}server-test.xm [ ! -d "$QUERIES_DIR" ] && QUERIES_DIR=${QUERIES_DIR=/usr/share/clickhouse-test/queries} rm -rf $DATA_DIR -mkdir -p $LOG_DIR +mkdir -p $LOG_DIR $DATA_DIR +openssl dhparam -out `clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.dhParamsFile` 256 +openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout `clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.privateKeyFile` -out `clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.certificateFile` # Start a local clickhouse server which will be used to run tests #PATH=$PATH:$BIN_DIR \ @@ -31,6 +33,8 @@ ${BIN_DIR}clickhouse-server --config-file=${CLICKHOUSE_CONFIG} > $LOG_DIR/stdout CH_PID=$! sleep 3 +tail -n50 $LOG_DIR/* + # Define needed stuff to kill test clickhouse server after tests completion function finish { kill $CH_PID || true @@ -38,7 +42,7 @@ function finish { tail -n 50 $LOG_DIR/stdout rm -rf $DATA_DIR } -trap finish EXIT +trap finish EXIT SIGINT SIGQUIT SIGTERM # Do tests if [ -n "$*" ]; then diff --git a/dbms/tests/client-test.xml b/dbms/tests/client-test.xml index 0cd3bdd5dc0..c5478dcb80d 100644 --- a/dbms/tests/client-test.xml +++ b/dbms/tests/client-test.xml @@ -1,4 +1,5 @@ 59000 + 59440 diff --git a/dbms/tests/server-test.xml b/dbms/tests/server-test.xml index cdb8e9caf5d..57f3f8ad9ea 100644 --- a/dbms/tests/server-test.xml +++ b/dbms/tests/server-test.xml @@ -13,8 +13,36 @@ 1 58123 59000 - 0.0.0.0 + 58443 + 59440 59009 + + + + /tmp/clickhouse/server.crt + /tmp/clickhouse/server.key + + /tmp/clickhouse/dhparam.pem + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + 3 /tmp/clickhouse/data/ /tmp/clickhouse/tmp/ From 9f22e4677472bf4a6304866fe4c4168027260a49 Mon Sep 17 00:00:00 2001 From: proller Date: Tue, 13 Mar 2018 22:51:12 +0300 Subject: [PATCH 043/244] Add openssl to debian test --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index df43f4538ee..79666ace2e5 100644 --- a/debian/control +++ b/debian/control @@ -51,5 +51,5 @@ Description: debugging symbols for clickhouse-server-base Package: clickhouse-test Priority: extra Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, clickhouse-client, bash, expect, python, python-lxml, python-termcolor, curl, perl, sudo +Depends: ${shlibs:Depends}, ${misc:Depends}, clickhouse-client, bash, expect, python, python-lxml, python-termcolor, curl, perl, sudo, openssl Description: Clickhouse tests From 53095aba45ad6ecbedd06c79420dced1f78255f7 Mon Sep 17 00:00:00 2001 From: proller Date: Tue, 13 Mar 2018 22:58:26 +0300 Subject: [PATCH 044/244] fix --- dbms/src/Server/TCPHandlerFactory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Server/TCPHandlerFactory.h b/dbms/src/Server/TCPHandlerFactory.h index 99cc23a45da..0eb8be13a2d 100644 --- a/dbms/src/Server/TCPHandlerFactory.h +++ b/dbms/src/Server/TCPHandlerFactory.h @@ -19,7 +19,7 @@ private: public: explicit TCPHandlerFactory(IServer & server_, bool secure_ = false) : server(server_) - , log(&Logger::get("TCP" + (secure_ ? "S" : "") + "HandlerFactory")) + , log(&Logger::get(std::string("TCP") + (secure_ ? "S" : "") + "HandlerFactory")) { } From 24651f7dd688a29d53036ed1305654b066d31332 Mon Sep 17 00:00:00 2001 From: proller Date: Tue, 13 Mar 2018 23:38:35 +0300 Subject: [PATCH 045/244] Fixes --- dbms/tests/clickhouse-test-server | 5 +++-- dbms/tests/queries/0_stateless/00505_tcp_ssl.reference | 1 + dbms/tests/queries/0_stateless/00505_tcp_ssl.sh | 2 ++ dbms/tests/queries/shell_config.sh | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dbms/tests/clickhouse-test-server b/dbms/tests/clickhouse-test-server index 7fb6918bfe5..b22058d5d7e 100755 --- a/dbms/tests/clickhouse-test-server +++ b/dbms/tests/clickhouse-test-server @@ -1,5 +1,6 @@ #!/usr/bin/env bash +set -x set -o errexit set -o pipefail @@ -24,8 +25,8 @@ export CLICKHOUSE_CONFIG=${CLICKHOUSE_CONFIG:=${CONFIG_SERVER_DIR}server-test.xm rm -rf $DATA_DIR mkdir -p $LOG_DIR $DATA_DIR -openssl dhparam -out `clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.dhParamsFile` 256 -openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout `clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.privateKeyFile` -out `clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.certificateFile` +openssl dhparam -out `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.dhParamsFile` 256 +openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.privateKeyFile` -out `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.certificateFile` # Start a local clickhouse server which will be used to run tests #PATH=$PATH:$BIN_DIR \ diff --git a/dbms/tests/queries/0_stateless/00505_tcp_ssl.reference b/dbms/tests/queries/0_stateless/00505_tcp_ssl.reference index 1191247b6d9..01e79c32a8c 100644 --- a/dbms/tests/queries/0_stateless/00505_tcp_ssl.reference +++ b/dbms/tests/queries/0_stateless/00505_tcp_ssl.reference @@ -1,2 +1,3 @@ 1 2 +3 diff --git a/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh b/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh index 40b90d572b0..47f3c3b35da 100755 --- a/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh +++ b/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh @@ -13,4 +13,6 @@ else # Auto port detect ${CLICKHOUSE_CLIENT} --ssl -q "SELECT 1"; ${CLICKHOUSE_CLIENT} --ssl --port=${CLICKHOUSE_PORT_TCP_SSL} -q "SELECT 2"; + + ${CLICKHOUSE_CURL} -sS --insecure ${CLICKHOUSE_URL_HTTPS}?query=SELECT%203 fi diff --git a/dbms/tests/queries/shell_config.sh b/dbms/tests/queries/shell_config.sh index b060c56877d..0aec2aab89e 100644 --- a/dbms/tests/queries/shell_config.sh +++ b/dbms/tests/queries/shell_config.sh @@ -18,6 +18,7 @@ export CLICKHOUSE_PORT_HTTPS=${CLICKHOUSE_PORT_HTTPS:=`${CLICKHOUSE_EXTRACT_CONF export CLICKHOUSE_PORT_HTTPS=${CLICKHOUSE_PORT_HTTPS:="8443"} export CLICKHOUSE_PORT_HTTP_PROTO=${CLICKHOUSE_PORT_HTTP_PROTO:="http"} export CLICKHOUSE_URL=${CLICKHOUSE_URL:="${CLICKHOUSE_PORT_HTTP_PROTO}://${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_HTTP}/"} +export CLICKHOUSE_URL_HTTPS=${CLICKHOUSE_URL_HTTPS:="https://${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_HTTPS}/"} export CLICKHOUSE_CURL=${CLICKHOUSE_CURL:="curl --max-time 10"} export CLICKHOUSE_TMP=${CLICKHOUSE_TMP:="."} mkdir -p ${CLICKHOUSE_TMP} From 16c8aefba24e83c85b38ed6b80cc34fdd09b3310 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Tue, 13 Mar 2018 23:49:13 +0300 Subject: [PATCH 046/244] Fixed test after refactoring. [#CLICKHOUSE-2] --- .../queries/0_stateless/00429_long_http_bufferization.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/tests/queries/0_stateless/00429_long_http_bufferization.sh b/dbms/tests/queries/0_stateless/00429_long_http_bufferization.sh index 27a79f37cd1..e94db0d951f 100755 --- a/dbms/tests/queries/0_stateless/00429_long_http_bufferization.sh +++ b/dbms/tests/queries/0_stateless/00429_long_http_bufferization.sh @@ -20,15 +20,15 @@ function ch_url() { # Check correct exceptions handling -exception_pattern="Code: 307, e\.displayText() = DB::Exception:[[:print:]]* e\.what() = DB::Exception$" +exception_pattern="displayText() = DB::Exception:[[:print:]]* e\.what() = DB::Exception" function check_only_exception() { local res=`ch_url "$1" "$2"` #(echo "$res") #(echo "$res" | wc -l) - #(echo "$res" | grep -c "^$exception_pattern") + #(echo "$res" | grep -c "$exception_pattern") [[ `echo "$res" | wc -l` -eq 1 ]] || echo FAIL 1 $@ - [[ $(echo "$res" | grep -c "^$exception_pattern") -eq 1 ]] || echo FAIL 2 $@ + [[ $(echo "$res" | grep -c "$exception_pattern") -eq 1 ]] || echo FAIL 2 $@ } function check_last_line_exception() { From f11f8e0365c7f1f4a22b68de3de57b7235c102d5 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 00:20:08 +0300 Subject: [PATCH 047/244] Fixed DDLWorker after recent changes. [#CLICKHOUSE-2] --- dbms/src/Interpreters/DDLWorker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/src/Interpreters/DDLWorker.cpp b/dbms/src/Interpreters/DDLWorker.cpp index 1c60b6d766c..30cccb5d848 100644 --- a/dbms/src/Interpreters/DDLWorker.cpp +++ b/dbms/src/Interpreters/DDLWorker.cpp @@ -523,6 +523,7 @@ bool DDLWorker::tryExecuteQuery(const String & query, const DDLTask & task, Exec try { Context local_context(context); + local_context.setCurrentQueryId(""); // generate random query_id executeQuery(istr, ostr, false, local_context, nullptr); } catch (...) From 40845794350c911c4ad8b4988e645e8af6f64cac Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 14 Mar 2018 00:19:42 +0300 Subject: [PATCH 048/244] Use openssl --- .travis.yml | 4 ++-- debian/changelog | 2 +- debian/pbuilder-hooks/B90test-server | 5 +++++ debian/pbuilder-hooks/ssl.xml | 4 ++++ release | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 debian/pbuilder-hooks/ssl.xml diff --git a/.travis.yml b/.travis.yml index 6dab6f478ab..7af12080396 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ matrix: # apt: # sources: # - ubuntu-toolchain-r-test -# packages: [ g++-7, libicu-dev, libreadline-dev, libmysqlclient-dev, unixodbc-dev, libltdl-dev, libssl-dev, libboost-dev, zlib1g-dev, libdouble-conversion-dev, libzookeeper-mt-dev, libsparsehash-dev, librdkafka-dev, libcapnp-dev, libsparsehash-dev, libgoogle-perftools-dev, bash, expect, python, python-lxml, python-termcolor, curl, perl, sudo ] +# packages: [ g++-7, libicu-dev, libreadline-dev, libmysqlclient-dev, unixodbc-dev, libltdl-dev, libssl-dev, libboost-dev, zlib1g-dev, libdouble-conversion-dev, libzookeeper-mt-dev, libsparsehash-dev, librdkafka-dev, libcapnp-dev, libsparsehash-dev, libgoogle-perftools-dev, bash, expect, python, python-lxml, python-termcolor, curl, perl, sudo, openssl ] # # env: # - MATRIX_EVAL="export CC=gcc-7 && export CXX=g++-7" @@ -36,7 +36,7 @@ matrix: sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-5.0 - packages: [ g++-7, clang-5.0, lld-5.0, libicu-dev, libreadline-dev, libmysqlclient-dev, unixodbc-dev, libltdl-dev, libssl-dev, libboost-dev, zlib1g-dev, libdouble-conversion-dev, libzookeeper-mt-dev, libsparsehash-dev, librdkafka-dev, libcapnp-dev, libsparsehash-dev, libgoogle-perftools-dev, bash, expect, python, python-lxml, python-termcolor, curl, perl, sudo ] + packages: [ g++-7, clang-5.0, lld-5.0, libicu-dev, libreadline-dev, libmysqlclient-dev, unixodbc-dev, libltdl-dev, libssl-dev, libboost-dev, zlib1g-dev, libdouble-conversion-dev, libzookeeper-mt-dev, libsparsehash-dev, librdkafka-dev, libcapnp-dev, libsparsehash-dev, libgoogle-perftools-dev, bash, expect, python, python-lxml, python-termcolor, curl, perl, sudo, openssl] env: - MATRIX_EVAL="export CC=clang-5.0 && export CXX=clang++-5.0" diff --git a/debian/changelog b/debian/changelog index b5eaa0afae3..64bd8096d89 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,4 +2,4 @@ clickhouse (1.1.54363) unstable; urgency=low * Modified source code - -- Tue, 13 Mar 2018 21:18:53 +0300 + -- proller Wed, 14 Mar 2018 00:06:37 +0300 diff --git a/debian/pbuilder-hooks/B90test-server b/debian/pbuilder-hooks/B90test-server index 5f163771582..6efbd387e31 100755 --- a/debian/pbuilder-hooks/B90test-server +++ b/debian/pbuilder-hooks/B90test-server @@ -16,6 +16,11 @@ ln -fs /usr/share/zoneinfo/Europe/Moscow /etc/localtime echo 'Europe/Moscow' > /etc/timezone dpkg-reconfigure -f noninteractive tzdata +pwd +mkdir -p /etc/clickhouse-server/config.d +cp ssl.xml /etc/clickhouse-server/config.d +openssl dhparam -out /etc/clickhouse-server/dhparam.pem 256 +openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt service clickhouse-server start sleep 3 diff --git a/debian/pbuilder-hooks/ssl.xml b/debian/pbuilder-hooks/ssl.xml new file mode 100644 index 00000000000..8b4580a14d4 --- /dev/null +++ b/debian/pbuilder-hooks/ssl.xml @@ -0,0 +1,4 @@ + + 8443 + 9440 + diff --git a/release b/release index 0fba786373b..6c36a594cfe 100755 --- a/release +++ b/release @@ -39,7 +39,7 @@ do shift elif [[ $1 == '--fast' ]]; then # Wrong but fast pbuilder mode: create base package with all depends - EXTRAPACKAGES="$EXTRAPACKAGES debhelper cmake gcc-7 g++-7 libc6-dev libmariadbclient-dev libicu-dev libltdl-dev libreadline-dev libssl-dev unixodbc-dev psmisc bash expect python python-lxml python-termcolor curl perl sudo" + EXTRAPACKAGES="$EXTRAPACKAGES debhelper cmake gcc-7 g++-7 libc6-dev libmariadbclient-dev libicu-dev libltdl-dev libreadline-dev libssl-dev unixodbc-dev psmisc bash expect python python-lxml python-termcolor curl perl sudo openssl" shift else echo "Unknown option $1" From b5b1f7c8bd516f9a0a1e76359b24446f9b308147 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 14 Mar 2018 02:01:03 +0300 Subject: [PATCH 049/244] Update ConfigReloader.h --- dbms/src/Common/Config/ConfigReloader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Common/Config/ConfigReloader.h b/dbms/src/Common/Config/ConfigReloader.h index 74a5294832b..e50b9e34837 100644 --- a/dbms/src/Common/Config/ConfigReloader.h +++ b/dbms/src/Common/Config/ConfigReloader.h @@ -78,7 +78,7 @@ private: std::atomic quit{false}; std::thread thread; - /// Is taken after entering into reloadIfNewer. + /// Locked inside reloadIfNewer. std::mutex reload_mutex; }; From 165de1bc3686b34b6640e31928ef217772a4da42 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 14 Mar 2018 02:03:00 +0300 Subject: [PATCH 050/244] Update Context.cpp --- dbms/src/Interpreters/Context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 6bc4cde2d06..acb9816699a 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -130,8 +130,8 @@ struct ContextShared ConfigurationPtr users_config; /// Config with the users, profiles and quotas sections. InterserverIOHandler interserver_io_handler; /// Handler for interserver communication. BackgroundProcessingPoolPtr background_pool; /// The thread pool for the background work performed by the tables. - mutable std::mutex macros_mutex; MacrosPtr macros; /// Substitutions extracted from config. + mutable std::mutex macros_mutex; std::unique_ptr compiler; /// Used for dynamic compilation of queries' parts if it necessary. std::shared_ptr ddl_worker; /// Process ddl commands from zk. /// Rules for selecting the compression settings, depending on the size of the part. From 8522a1b4d187b72ca1c473bd1de8258c5a993244 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 14 Mar 2018 02:09:26 +0300 Subject: [PATCH 051/244] Update StorageSystemMacros.h --- dbms/src/Storages/System/StorageSystemMacros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/System/StorageSystemMacros.h b/dbms/src/Storages/System/StorageSystemMacros.h index ec8af55a0d3..d4bb5ab3732 100644 --- a/dbms/src/Storages/System/StorageSystemMacros.h +++ b/dbms/src/Storages/System/StorageSystemMacros.h @@ -10,7 +10,7 @@ namespace DB class Context; -/** Implements `databases` system table, which allows you to get information about all databases. +/** Information about macros for introspection. */ class StorageSystemMacros : public ext::shared_ptr_helper, public IStorage { From 153fcd6c9ff797c3c85e90b9b7ad23d495b56520 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 14 Mar 2018 02:13:39 +0300 Subject: [PATCH 052/244] Fix double free in LibraryDictionarySource (#2028) * Fix double free in LibraryDictionarySource * Fix {} * wip * wip * Better Exception * Fix possible leak --- .../ComplexKeyCacheDictionary.cpp | 1 - .../Dictionaries/LibraryDictionarySource.cpp | 62 ++++++++++--------- .../Dictionaries/LibraryDictionarySource.h | 19 +++--- .../dictionary_library/dictionary_library.cpp | 2 +- .../dictionary_library/dictionary_library_c.c | 2 +- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/dbms/src/Dictionaries/ComplexKeyCacheDictionary.cpp b/dbms/src/Dictionaries/ComplexKeyCacheDictionary.cpp index 540b71a80dd..fcd73cdb889 100644 --- a/dbms/src/Dictionaries/ComplexKeyCacheDictionary.cpp +++ b/dbms/src/Dictionaries/ComplexKeyCacheDictionary.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include diff --git a/dbms/src/Dictionaries/LibraryDictionarySource.cpp b/dbms/src/Dictionaries/LibraryDictionarySource.cpp index 04ee831bb1b..8c911771a20 100644 --- a/dbms/src/Dictionaries/LibraryDictionarySource.cpp +++ b/dbms/src/Dictionaries/LibraryDictionarySource.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace DB { @@ -70,11 +71,11 @@ namespace Block dataToBlock(const Block & sample_block, const void * data) { if (!data) - return sample_block.cloneEmpty(); + throw Exception("LibraryDictionarySource: No data returned", ErrorCodes::EXTERNAL_LIBRARY_ERROR); auto columns_received = static_cast(data); if (columns_received->error_code) - throw Exception("Received error: " + std::to_string(columns_received->error_code) + " " + throw Exception("LibraryDictionarySource: Returned error: " + std::to_string(columns_received->error_code) + " " + (columns_received->error_string ? columns_received->error_string : ""), ErrorCodes::EXTERNAL_LIBRARY_ERROR); @@ -85,7 +86,7 @@ namespace for (size_t col_n = 0; col_n < columns_received->size; ++col_n) { if (columns.size() != columns_received->data[col_n].size) - throw Exception("Received unexpected number of columns: " + std::to_string(columns_received->data[col_n].size) + throw Exception("LibraryDictionarySource: Returned unexpected number of columns: " + std::to_string(columns_received->data[col_n].size) + ", must be " + std::to_string(columns.size()), ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); @@ -123,9 +124,8 @@ LibraryDictionarySource::LibraryDictionarySource(const DictionaryStructure & dic description.init(sample_block); library = std::make_shared(path); settings = std::make_shared(getLibSettings(config, config_prefix + lib_config_settings)); - auto fptr = library->tryGet("ClickHouseDictionary_v2_libNew"); - if (fptr) - lib_data = fptr(); + if (auto libNew = library->tryGetstrings))>("ClickHouseDictionary_v2_libNew")) + lib_data = libNew(&settings->strings); } LibraryDictionarySource::LibraryDictionarySource(const LibraryDictionarySource & other) @@ -138,15 +138,17 @@ LibraryDictionarySource::LibraryDictionarySource(const LibraryDictionarySource & , library{other.library} , description{other.description} , settings{other.settings} - , lib_data{other.lib_data} { + if (auto libClone = library->tryGet("ClickHouseDictionary_v2_libClone")) + lib_data = libClone(other.lib_data); + else if (auto libNew = library->tryGetstrings))>("ClickHouseDictionary_v2_libNew")) + lib_data = libNew(&settings->strings); } LibraryDictionarySource::~LibraryDictionarySource() { - auto fptr = library->tryGet("ClickHouseDictionary_v2_libDelete"); - if (fptr) - fptr(lib_data); + if (auto libDelete = library->tryGet("ClickHouseDictionary_v2_libDelete")) + libDelete(lib_data); } BlockInputStreamPtr LibraryDictionarySource::loadAll() @@ -165,12 +167,12 @@ BlockInputStreamPtr LibraryDictionarySource::loadAll() void * data_ptr = nullptr; /// Get function pointer before dataNew call because library->get may throw. - auto fptr + auto func_loadAll = library->getstrings), decltype(&columns))>("ClickHouseDictionary_v2_loadAll"); - data_ptr = library->get("ClickHouseDictionary_v2_dataNew")(lib_data); - auto data = fptr(data_ptr, &settings->strings, &columns); + data_ptr = library->get("ClickHouseDictionary_v2_dataNew")(lib_data); + auto data = func_loadAll(data_ptr, &settings->strings, &columns); auto block = dataToBlock(description.sample_block, data); - library->get("ClickHouseDictionary_v2_dataDelete")(lib_data, data_ptr); + SCOPE_EXIT(library->get("ClickHouseDictionary_v2_dataDelete")(lib_data, data_ptr)); return std::make_shared(block); } @@ -191,12 +193,13 @@ BlockInputStreamPtr LibraryDictionarySource::loadIds(const std::vector & void * data_ptr = nullptr; /// Get function pointer before dataNew call because library->get may throw. - auto fptr = library->getstrings), decltype(&columns_pass), decltype(&ids_data))>( - "ClickHouseDictionary_v2_loadIds"); - data_ptr = library->get("ClickHouseDictionary_v2_dataNew")(lib_data); - auto data = fptr(data_ptr, &settings->strings, &columns_pass, &ids_data); + auto func_loadIds + = library->getstrings), decltype(&columns_pass), decltype(&ids_data))>( + "ClickHouseDictionary_v2_loadIds"); + data_ptr = library->get("ClickHouseDictionary_v2_dataNew")(lib_data); + auto data = func_loadIds(data_ptr, &settings->strings, &columns_pass, &ids_data); auto block = dataToBlock(description.sample_block, data); - library->get("ClickHouseDictionary_v2_dataDelete")(lib_data, data_ptr); + SCOPE_EXIT(library->get("ClickHouseDictionary_v2_dataDelete")(lib_data, data_ptr)); return std::make_shared(block); } @@ -218,30 +221,29 @@ BlockInputStreamPtr LibraryDictionarySource::loadKeys(const Columns & key_column void * data_ptr = nullptr; /// Get function pointer before dataNew call because library->get may throw. - auto fptr + auto func_loadKeys = library->getstrings), decltype(&columns_pass), decltype(&requested_rows_c))>( "ClickHouseDictionary_v2_loadKeys"); - data_ptr = library->get("ClickHouseDictionary_v2_dataNew")(lib_data); - auto data = fptr(data_ptr, &settings->strings, &columns_pass, &requested_rows_c); + data_ptr = library->get("ClickHouseDictionary_v2_dataNew")(lib_data); + auto data = func_loadKeys(data_ptr, &settings->strings, &columns_pass, &requested_rows_c); auto block = dataToBlock(description.sample_block, data); - library->get("ClickHouseDictionary_v2_dataDelete")(lib_data, data_ptr); + SCOPE_EXIT(library->get("ClickHouseDictionary_v2_dataDelete")(lib_data, data_ptr)); return std::make_shared(block); } bool LibraryDictionarySource::isModified() const { - auto fptr = library->tryGetstrings))>("ClickHouseDictionary_v2_isModified"); - if (fptr) - return fptr(lib_data, &settings->strings); + if (auto func_isModified + = library->tryGetstrings))>("ClickHouseDictionary_v2_isModified")) + return func_isModified(lib_data, &settings->strings); return true; } bool LibraryDictionarySource::supportsSelectiveLoad() const { - auto fptr - = library->tryGetstrings))>("ClickHouseDictionary_v2_supportsSelectiveLoad"); - if (fptr) - return fptr(lib_data, &settings->strings); + if (auto func_supportsSelectiveLoad + = library->tryGetstrings))>("ClickHouseDictionary_v2_supportsSelectiveLoad")) + return func_supportsSelectiveLoad(lib_data, &settings->strings); return true; } diff --git a/dbms/src/Dictionaries/LibraryDictionarySource.h b/dbms/src/Dictionaries/LibraryDictionarySource.h index ce136b90318..1765968adca 100644 --- a/dbms/src/Dictionaries/LibraryDictionarySource.h +++ b/dbms/src/Dictionaries/LibraryDictionarySource.h @@ -1,26 +1,25 @@ #pragma once -#include #include #include #include +#include #include namespace Poco { - class Logger; +class Logger; - namespace Util - { - class AbstractConfiguration; - } +namespace Util +{ + class AbstractConfiguration; +} } namespace DB { - class CStringsHolder; /// Allows loading dictionaries from dynamic libraries (.so) @@ -55,7 +54,10 @@ public: bool supportsSelectiveLoad() const override; ///Not yet supported - bool hasUpdateField() const override { return false; } + bool hasUpdateField() const override + { + return false; + } DictionarySourcePtr clone() const override; @@ -76,5 +78,4 @@ private: std::shared_ptr settings; void * lib_data = nullptr; }; - } diff --git a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp index 7bb6e2eb726..9ddaf69e1fd 100644 --- a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp +++ b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp @@ -158,7 +158,7 @@ void * ClickHouseDictionary_v2_loadKeys(void * data_ptr, return nullptr; } -void * ClickHouseDictionary_v2_libNew() +void * ClickHouseDictionary_v2_libNew(ClickHouseLibrary::CStrings * /*settings*/) { auto lib_ptr = new LibHolder; return lib_ptr; diff --git a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c index 9d95894302a..6caea3ac2cf 100644 --- a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c +++ b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c @@ -39,7 +39,7 @@ void * ClickHouseDictionary_v2_loadKeys( return 0; } -void * ClickHouseDictionary_v2_libNew() +void * ClickHouseDictionary_v2_libNew(ClickHouseLibCStrings * settings) { int size = 101; void * lib_ptr = malloc(size); From 8b59db58c3ce92a82037c643302027d18e0bf586 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 02:44:23 +0300 Subject: [PATCH 053/244] Fixed uneven code #2032 --- dbms/src/Common/Macros.cpp | 2 ++ dbms/src/Common/Macros.h | 12 +++++-- dbms/src/Interpreters/Context.cpp | 13 +++---- dbms/src/Interpreters/Context.h | 7 ++-- .../src/Interpreters/EmbeddedDictionaries.cpp | 2 +- dbms/src/Server/LocalServer.cpp | 2 +- dbms/src/Server/Server.cpp | 4 +-- libs/libcommon/include/common/MultiVersion.h | 34 ++----------------- libs/libdaemon/src/BaseDaemon.cpp | 1 + 9 files changed, 27 insertions(+), 50 deletions(-) diff --git a/dbms/src/Common/Macros.cpp b/dbms/src/Common/Macros.cpp index cb3d43cd21c..56b766eda68 100644 --- a/dbms/src/Common/Macros.cpp +++ b/dbms/src/Common/Macros.cpp @@ -1,6 +1,8 @@ +#include #include #include + namespace DB { diff --git a/dbms/src/Common/Macros.h b/dbms/src/Common/Macros.h index dae3bd10aa9..d2602cf62e7 100644 --- a/dbms/src/Common/Macros.h +++ b/dbms/src/Common/Macros.h @@ -1,9 +1,16 @@ #pragma once #include -#include #include -#include + + +namespace Poco +{ + namespace Util + { + class AbstractConfiguration; + } +} namespace DB @@ -29,6 +36,5 @@ private: MacroMap macros; }; -using MacrosPtr = std::shared_ptr; } diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index acb9816699a..8fe51bf5c08 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -130,8 +130,7 @@ struct ContextShared ConfigurationPtr users_config; /// Config with the users, profiles and quotas sections. InterserverIOHandler interserver_io_handler; /// Handler for interserver communication. BackgroundProcessingPoolPtr background_pool; /// The thread pool for the background work performed by the tables. - MacrosPtr macros; /// Substitutions extracted from config. - mutable std::mutex macros_mutex; + MultiVersion macros; /// Substitutions extracted from config. std::unique_ptr compiler; /// Used for dynamic compilation of queries' parts if it necessary. std::shared_ptr ddl_worker; /// Process ddl commands from zk. /// Rules for selecting the compression settings, depending on the size of the part. @@ -1045,16 +1044,14 @@ void Context::setDefaultFormat(const String & name) default_format = name; } -const MacrosPtr & Context::getMacros() const +MultiVersion::Version Context::getMacros() const { - std::unique_lock lock(shared->macros_mutex); - return shared->macros; + return shared->macros.get(); } -void Context::setMacros(Macros && macros) +void Context::setMacros(std::unique_ptr && macros) { - std::unique_lock lock(shared->macros_mutex); - shared->macros = std::make_shared(std::move(macros)); + shared->macros.set(std::move(macros)); } const Context & Context::getQueryContext() const diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index 32ba0b8cd7f..4f714842b62 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -80,8 +81,6 @@ using Dependencies = std::vector; using TableAndCreateAST = std::pair; using TableAndCreateASTs = std::map; -using MacrosPtr = std::shared_ptr; - /** A set of known objects that can be used in the query. * Consists of a shared part (always common to all sessions and queries) * and copied part (which can be its own for each session or query). @@ -207,8 +206,8 @@ public: String getDefaultFormat() const; /// If default_format is not specified, some global default format is returned. void setDefaultFormat(const String & name); - const MacrosPtr & getMacros() const; - void setMacros(Macros && macros); + MultiVersion::Version getMacros() const; + void setMacros(std::unique_ptr && macros); Settings getSettings() const; void setSettings(const Settings & settings_); diff --git a/dbms/src/Interpreters/EmbeddedDictionaries.cpp b/dbms/src/Interpreters/EmbeddedDictionaries.cpp index f5567e0a1bc..441bb7c92d8 100644 --- a/dbms/src/Interpreters/EmbeddedDictionaries.cpp +++ b/dbms/src/Interpreters/EmbeddedDictionaries.cpp @@ -49,7 +49,7 @@ bool EmbeddedDictionaries::reloadDictionary( { auto new_dictionary = reload_dictionary(config); if (new_dictionary) - dictionary.set(new_dictionary.release()); + dictionary.set(std::move(new_dictionary)); } catch (...) { diff --git a/dbms/src/Server/LocalServer.cpp b/dbms/src/Server/LocalServer.cpp index aec3f4152f1..1196c62f06f 100644 --- a/dbms/src/Server/LocalServer.cpp +++ b/dbms/src/Server/LocalServer.cpp @@ -275,7 +275,7 @@ try /// Maybe useless if (config().has("macros")) - context->setMacros(Macros(config(), "macros")); + context->setMacros(std::make_unique(config(), "macros")); /// Skip networking diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 25a55f1ff8d..12598af18e6 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -221,7 +221,7 @@ int Server::main(const std::vector & /*args*/) } if (config().has("macros")) - global_context->setMacros(Macros(config(), "macros")); + global_context->setMacros(std::make_unique(config(), "macros")); /// Initialize main config reloader. std::string include_from_path = config().getString("include_from", "/etc/metrika.xml"); @@ -231,7 +231,7 @@ int Server::main(const std::vector & /*args*/) [&](ConfigurationPtr config) { global_context->setClustersConfig(config); - global_context->setMacros(Macros(*config, "macros")); + global_context->setMacros(std::make_unique(*config, "macros")); }, /* already_loaded = */ true); diff --git a/libs/libcommon/include/common/MultiVersion.h b/libs/libcommon/include/common/MultiVersion.h index 6b55bfa9e05..3014689f861 100644 --- a/libs/libcommon/include/common/MultiVersion.h +++ b/libs/libcommon/include/common/MultiVersion.h @@ -30,30 +30,13 @@ public: /// Default initialization - by nullptr. MultiVersion() = default; - /// Initialization with first version. - MultiVersion(const Version & value) - { - set(value); - } - - /// Take an ownership of first version. - MultiVersion(const T * value) - { - set(value); - } - - MultiVersion(Version && value) - { - set(std::move(value)); - } - MultiVersion(std::unique_ptr && value) { set(std::move(value)); } /// Obtain current version for read-only usage. Returns shared_ptr, that manages lifetime of version. - const Version get() const + Version get() const { /// NOTE: is it possible to lock-free replace of shared_ptr? std::lock_guard lock(mutex); @@ -61,21 +44,10 @@ public: } /// Update an object with new version. - void set(const Version & value) - { - std::lock_guard lock(mutex); - current_version = value; - } - - /// Update an object with new version and take an ownership of it. - void set(const T * value) - { - set(Version(value)); - } - void set(std::unique_ptr && value) { - set(Version(value.release())); + std::lock_guard lock(mutex); + current_version = std::move(value); } private: diff --git a/libs/libdaemon/src/BaseDaemon.cpp b/libs/libdaemon/src/BaseDaemon.cpp index 1d4a4dffc2a..29405901206 100644 --- a/libs/libdaemon/src/BaseDaemon.cpp +++ b/libs/libdaemon/src/BaseDaemon.cpp @@ -63,6 +63,7 @@ #include #include + using Poco::Logger; using Poco::AutoPtr; using Poco::Observer; From 0a33b774a3f34ddc80e10262e100e4ab94f0e63c Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Sat, 10 Mar 2018 14:41:11 +0200 Subject: [PATCH 054/244] Fix quotes in partition display name based on Date, DateTime or UUID type --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreePartition.cpp | 4 ++-- dbms/src/Storages/MergeTree/MergeTreePartition.h | 2 +- dbms/src/Storages/System/StorageSystemParts.cpp | 2 +- dbms/src/Storages/System/StorageSystemPartsColumns.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 392c45a7cc7..1270c645a2b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -2050,7 +2050,7 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, const Context { WriteBufferFromOwnString buf; writeCString("Parsed partition value: ", buf); - partition.serializeTextQuoted(*this, buf); + partition.serializeText(*this, buf); writeCString(" doesn't match partition value for an existing part with the same partition ID: ", buf); writeString(existing_part_in_partition->name, buf); throw Exception(buf.str(), ErrorCodes::INVALID_PARTITION_VALUE); diff --git a/dbms/src/Storages/MergeTree/MergeTreePartition.cpp b/dbms/src/Storages/MergeTree/MergeTreePartition.cpp index b95916b2164..0857f285d9b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreePartition.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreePartition.cpp @@ -77,7 +77,7 @@ String MergeTreePartition::getID(const MergeTreeData & storage) const return result; } -void MergeTreePartition::serializeTextQuoted(const MergeTreeData & storage, WriteBuffer & out) const +void MergeTreePartition::serializeText(const MergeTreeData & storage, WriteBuffer & out) const { size_t key_size = storage.partition_key_sample.columns(); @@ -98,7 +98,7 @@ void MergeTreePartition::serializeTextQuoted(const MergeTreeData & storage, Writ const DataTypePtr & type = storage.partition_key_sample.getByPosition(i).type; auto column = type->createColumn(); column->insert(value[i]); - type->serializeTextQuoted(*column, 0, out); + type->serializeText(*column, 0, out); } if (key_size > 1) diff --git a/dbms/src/Storages/MergeTree/MergeTreePartition.h b/dbms/src/Storages/MergeTree/MergeTreePartition.h index d32b5f4401a..f3ae17b468c 100644 --- a/dbms/src/Storages/MergeTree/MergeTreePartition.h +++ b/dbms/src/Storages/MergeTree/MergeTreePartition.h @@ -25,7 +25,7 @@ public: String getID(const MergeTreeData & storage) const; - void serializeTextQuoted(const MergeTreeData & storage, WriteBuffer & out) const; + void serializeText(const MergeTreeData & storage, WriteBuffer & out) const; void load(const MergeTreeData & storage, const String & part_path); void store(const MergeTreeData & storage, const String & part_path, MergeTreeDataPartChecksums & checksums) const; diff --git a/dbms/src/Storages/System/StorageSystemParts.cpp b/dbms/src/Storages/System/StorageSystemParts.cpp index 0914cae72da..9972c4832f3 100644 --- a/dbms/src/Storages/System/StorageSystemParts.cpp +++ b/dbms/src/Storages/System/StorageSystemParts.cpp @@ -56,7 +56,7 @@ void StorageSystemParts::processNextStorage(MutableColumns & columns, const Stor size_t i = 0; { WriteBufferFromOwnString out; - part->partition.serializeTextQuoted(*info.data, out); + part->partition.serializeText(*info.data, out); columns[i++]->insert(out.str()); } columns[i++]->insert(part->name); diff --git a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp index 9667399c534..5e73a14c970 100644 --- a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp @@ -101,7 +101,7 @@ void StorageSystemPartsColumns::processNextStorage(MutableColumns & columns, con size_t j = 0; { WriteBufferFromOwnString out; - part->partition.serializeTextQuoted(*info.data, out); + part->partition.serializeText(*info.data, out); columns[j++]->insert(out.str()); } columns[j++]->insert(part->name); From 3ae2e443fdf81d7480d9179ba42ff74afeff91ec Mon Sep 17 00:00:00 2001 From: kshvakov Date: Sat, 10 Mar 2018 16:00:32 +0200 Subject: [PATCH 055/244] Revert "Fix quotes in partition display name based on Date, DateTime or UUID type" This reverts commit 10aa9cfc8a90f272200b343b45e9e8447aa92558. --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreePartition.cpp | 4 ++-- dbms/src/Storages/MergeTree/MergeTreePartition.h | 2 +- dbms/src/Storages/System/StorageSystemParts.cpp | 2 +- dbms/src/Storages/System/StorageSystemPartsColumns.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 1270c645a2b..392c45a7cc7 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -2050,7 +2050,7 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, const Context { WriteBufferFromOwnString buf; writeCString("Parsed partition value: ", buf); - partition.serializeText(*this, buf); + partition.serializeTextQuoted(*this, buf); writeCString(" doesn't match partition value for an existing part with the same partition ID: ", buf); writeString(existing_part_in_partition->name, buf); throw Exception(buf.str(), ErrorCodes::INVALID_PARTITION_VALUE); diff --git a/dbms/src/Storages/MergeTree/MergeTreePartition.cpp b/dbms/src/Storages/MergeTree/MergeTreePartition.cpp index 0857f285d9b..b95916b2164 100644 --- a/dbms/src/Storages/MergeTree/MergeTreePartition.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreePartition.cpp @@ -77,7 +77,7 @@ String MergeTreePartition::getID(const MergeTreeData & storage) const return result; } -void MergeTreePartition::serializeText(const MergeTreeData & storage, WriteBuffer & out) const +void MergeTreePartition::serializeTextQuoted(const MergeTreeData & storage, WriteBuffer & out) const { size_t key_size = storage.partition_key_sample.columns(); @@ -98,7 +98,7 @@ void MergeTreePartition::serializeText(const MergeTreeData & storage, WriteBuffe const DataTypePtr & type = storage.partition_key_sample.getByPosition(i).type; auto column = type->createColumn(); column->insert(value[i]); - type->serializeText(*column, 0, out); + type->serializeTextQuoted(*column, 0, out); } if (key_size > 1) diff --git a/dbms/src/Storages/MergeTree/MergeTreePartition.h b/dbms/src/Storages/MergeTree/MergeTreePartition.h index f3ae17b468c..d32b5f4401a 100644 --- a/dbms/src/Storages/MergeTree/MergeTreePartition.h +++ b/dbms/src/Storages/MergeTree/MergeTreePartition.h @@ -25,7 +25,7 @@ public: String getID(const MergeTreeData & storage) const; - void serializeText(const MergeTreeData & storage, WriteBuffer & out) const; + void serializeTextQuoted(const MergeTreeData & storage, WriteBuffer & out) const; void load(const MergeTreeData & storage, const String & part_path); void store(const MergeTreeData & storage, const String & part_path, MergeTreeDataPartChecksums & checksums) const; diff --git a/dbms/src/Storages/System/StorageSystemParts.cpp b/dbms/src/Storages/System/StorageSystemParts.cpp index 9972c4832f3..0914cae72da 100644 --- a/dbms/src/Storages/System/StorageSystemParts.cpp +++ b/dbms/src/Storages/System/StorageSystemParts.cpp @@ -56,7 +56,7 @@ void StorageSystemParts::processNextStorage(MutableColumns & columns, const Stor size_t i = 0; { WriteBufferFromOwnString out; - part->partition.serializeText(*info.data, out); + part->partition.serializeTextQuoted(*info.data, out); columns[i++]->insert(out.str()); } columns[i++]->insert(part->name); diff --git a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp index 5e73a14c970..9667399c534 100644 --- a/dbms/src/Storages/System/StorageSystemPartsColumns.cpp +++ b/dbms/src/Storages/System/StorageSystemPartsColumns.cpp @@ -101,7 +101,7 @@ void StorageSystemPartsColumns::processNextStorage(MutableColumns & columns, con size_t j = 0; { WriteBufferFromOwnString out; - part->partition.serializeText(*info.data, out); + part->partition.serializeTextQuoted(*info.data, out); columns[j++]->insert(out.str()); } columns[j++]->insert(part->name); From b28cef987132b8b90c50ac2b4c2c2c031d555504 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 04:42:51 +0300 Subject: [PATCH 056/244] Disabled ill-formed test #2035 --- .../0_stateless/{00505_tcp_ssl.sh => 00505_tcp_ssl.sh.disabled} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dbms/tests/queries/0_stateless/{00505_tcp_ssl.sh => 00505_tcp_ssl.sh.disabled} (100%) diff --git a/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh b/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh.disabled similarity index 100% rename from dbms/tests/queries/0_stateless/00505_tcp_ssl.sh rename to dbms/tests/queries/0_stateless/00505_tcp_ssl.sh.disabled From 1c0999932f5de655b1db265658371123e1ed7d76 Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov <1549571+filimonov@users.noreply.github.com> Date: Wed, 14 Mar 2018 00:33:56 +0100 Subject: [PATCH 057/244] Documenting numbers table function, VerticalRaw format, HTTP sessions, HTTP compression. --- docs/en/formats/verticalraw.md | 24 ++++++++++++++++++++++++ docs/en/interfaces/http_interface.md | 13 ++++++++++--- docs/en/table_functions/numbers.md | 17 +++++++++++++++++ docs/mkdocs_en.yml | 2 ++ docs/mkdocs_ru.yml | 2 ++ docs/ru/formats/verticalraw.md | 26 ++++++++++++++++++++++++++ docs/ru/interfaces/http_interface.md | 11 +++++++++-- docs/ru/table_functions/numbers.md | 16 ++++++++++++++++ 8 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 docs/en/formats/verticalraw.md create mode 100644 docs/en/table_functions/numbers.md create mode 100644 docs/ru/formats/verticalraw.md create mode 100644 docs/ru/table_functions/numbers.md diff --git a/docs/en/formats/verticalraw.md b/docs/en/formats/verticalraw.md new file mode 100644 index 00000000000..440967eb598 --- /dev/null +++ b/docs/en/formats/verticalraw.md @@ -0,0 +1,24 @@ +# VerticalRaw + +Differs from `TabSeparated` format in that the rows are written without escaping. +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). + +Samples: +``` +:) SHOW CREATE TABLE geonames FORMAT VerticalRaw; +Row 1: +────── +statement: CREATE TABLE default.geonames ( geonameid UInt32, name String, asciiname String, alternatenames String, latitude Float32, longitude Float32, feature_class String, feature_code String, country_code String, cc2 String, admin1_code String, admin2_code String, admin3_code String, admin4_code String, population Int64, elevation String, dem String, timezone String, modification_date Date, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) + +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; +Row 1: +────── +test: string with 'quotes' and with some special + characters + +-- the same in Vertical format: +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical; +Row 1: +────── +test: string with \'quotes\' and \t with some special \n characters +``` diff --git a/docs/en/interfaces/http_interface.md b/docs/en/interfaces/http_interface.md index 91c6790f975..8c223cf69cf 100644 --- a/docs/en/interfaces/http_interface.md +++ b/docs/en/interfaces/http_interface.md @@ -130,11 +130,15 @@ POST 'http://localhost:8123/?query=DROP TABLE t' For successful requests that don't return a data table, an empty response body is returned. -You can use compression when transmitting data. The compressed data has a non-standard format, and you will need to use the special compressor program to work with it (sudo apt-get install compressor-metrika-yandex). +You can use compression when transmitting data. +For using ClickHouse internal compression format, and you will need to use the special compressor program to work with it (sudo apt-get install compressor-metrika-yandex). If you specified 'compress=1' in the URL, the server will compress the data it sends you. If you specified 'decompress=1' in the URL, the server will decompress the same data that you pass in the POST method. +Also standard gzip-based HTTP compression can be used. To send gzip compressed POST data just add `Content-Encoding: gzip` to request headers, and gzip POST body. +To get response compressed, you need to add `Accept-Encoding: gzip` to request headers, and turn on ClickHouse setting called `enable_http_compression`. + You can use this to reduce network traffic when transmitting a large amount of data, or for creating dumps that are immediately compressed. You can use the 'database' URL parameter to specify the default database. @@ -190,7 +194,11 @@ $ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'http://localhost:812 For information about other parameters, see the section "SET". -In contrast to the native interface, the HTTP interface does not support the concept of sessions or session settings, does not allow aborting a query (to be exact, it allows this in only a few cases), and does not show the progress of query processing. Parsing and data formatting are performed on the server side, and using the network might be ineffective. +You can use ClickHouse sessions in the HTTP protocol. To do this, you need to specify the `session_id` GET parameter in HTTP request. You can use any alphanumeric string as a session_id. By default session will be timed out after 60 seconds of inactivity. You can change that by setting `default_session_timeout` in server config file, or by adding GET parameter `session_timeout`. You can also check the status of the session by using GET parameter `session_check=1`. When using sessions you can't run 2 queries with the same session_id simultaneously. + +You can get the progress of query execution in X-ClickHouse-Progress headers, by enabling setting send_progress_in_http_headers. + +Running query are not aborted automatically after closing HTTP connection. Parsing and data formatting are performed on the server side, and using the network might be ineffective. The optional 'query_id' parameter can be passed as the query ID (any string). For more information, see the section "Settings, replace_running_query". The optional 'quota_key' parameter can be passed as the quota key (any string). For more information, see the section "Quotas". @@ -212,4 +220,3 @@ curl -sS 'http://localhost:8123/?max_result_bytes=4000000&buffer_size=3000000&wa ``` Use buffering to avoid situations where a query processing error occurred after the response code and HTTP headers were sent to the client. In this situation, an error message is written at the end of the response body, and on the client side, the error can only be detected at the parsing stage. - diff --git a/docs/en/table_functions/numbers.md b/docs/en/table_functions/numbers.md new file mode 100644 index 00000000000..b055f1cd56e --- /dev/null +++ b/docs/en/table_functions/numbers.md @@ -0,0 +1,17 @@ +# numbers + +`numbers(N)` - returns the table with one column named `number` (UInt64 type), containing integer numbers from 0 to N-1. + +`numbers(N)` (like a table `system.numbers`) can be used in tests or for sequences generation. + +Two following queries are equal: +```sql +SELECT * FROM numbers(10); +SELECT * FROM system.numbers LIMIT 10; +``` + +Samples: +```sql +-- generation of sequence of dates from 2010-01-01 to 2010-12-31 +select toDate('2010-01-01') + number as d FROM numbers(365); +``` diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 1daf36ecfd8..c94e33c7818 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -122,6 +122,7 @@ pages: - 'Introduction': 'table_functions/index.md' - 'remote': 'table_functions/remote.md' - 'merge': 'table_functions/merge.md' + - 'numbers': 'table_functions/numbers.md' - 'Formats': - 'Introduction': 'formats/index.md' @@ -133,6 +134,7 @@ pages: - 'CSVWithNames': 'formats/csvwithnames.md' - 'Values': 'formats/values.md' - 'Vertical': 'formats/vertical.md' + - 'VerticalRaw': 'formats/verticalraw.md' - 'JSON': 'formats/json.md' - 'JSONCompact': 'formats/jsoncompact.md' - 'JSONEachRow': 'formats/jsoneachrow.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 23734934bb5..eb8c002847d 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -124,6 +124,7 @@ pages: - 'Введение': 'table_functions/index.md' - 'remote': 'table_functions/remote.md' - 'merge': 'table_functions/merge.md' + - 'numbers': 'table_functions/numbers.md' - 'Форматы': - 'Введение': 'formats/index.md' @@ -135,6 +136,7 @@ pages: - 'CSVWithNames': 'formats/csvwithnames.md' - 'Values': 'formats/values.md' - 'Vertical': 'formats/vertical.md' + - 'VerticalRaw': 'formats/verticalraw.md' - 'JSON': 'formats/json.md' - 'JSONCompact': 'formats/jsoncompact.md' - 'JSONEachRow': 'formats/jsoneachrow.md' diff --git a/docs/ru/formats/verticalraw.md b/docs/ru/formats/verticalraw.md new file mode 100644 index 00000000000..9693cabe3c3 --- /dev/null +++ b/docs/ru/formats/verticalraw.md @@ -0,0 +1,26 @@ +# VerticalRaw + +Отличается от формата `Vertical` тем, что строки выводятся без экранирования. +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). + +Примеры: +``` +:) SHOW CREATE TABLE geonames FORMAT VerticalRaw; +Row 1: +────── +statement: CREATE TABLE default.geonames ( geonameid UInt32, name String, asciiname String, alternatenames String, latitude Float32, longitude Float32, feature_class String, feature_code String, country_code String, cc2 String, admin1_code String, admin2_code String, admin3_code String, admin4_code String, population Int64, elevation String, dem String, timezone String, modification_date Date, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) + +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; +Row 1: +────── +test: string with 'quotes' and with some special + characters +``` + +Для сравнения - формат Vertical: +``` +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical; +Row 1: +────── +test: string with \'quotes\' and \t with some special \n characters +``` diff --git a/docs/ru/interfaces/http_interface.md b/docs/ru/interfaces/http_interface.md index 28cb8ce6c66..a20ca4d844e 100644 --- a/docs/ru/interfaces/http_interface.md +++ b/docs/ru/interfaces/http_interface.md @@ -132,11 +132,14 @@ POST 'http://localhost:8123/?query=DROP TABLE t' Для запросов, которые не возвращают таблицу с данными, в случае успеха, выдаётся пустое тело ответа. -Вы можете использовать сжатие при передаче данных. Формат сжатых данных нестандартный, и вам придётся использовать для работы с ним специальную программу compressor (sudo apt-get install compressor-metrika-yandex). +Вы можете использовать внутренний формат сжатия Clickhouse при передаче данных. Формат сжатых данных нестандартный, и вам придётся использовать для работы с ним специальную программу compressor (sudo apt-get install compressor-metrika-yandex). Если вы указали в URL compress=1, то сервер будет сжимать отправляемые вам данные. Если вы указали в URL decompress=1, то сервер будет разжимать те данные, которые вы передаёте ему POST-ом. +Также имеется возможность использования стандартного сжатия HTTP, на основе gzip. Чтобы отправить POST-запрос, сжатый с помощью gzip, добавьте к запросу заголовок `Content-Encoding: gzip`. +Чтобы ClickHouse сжимал ответ на запрос с помощью gzip, необходимо добавить `Accept-Encoding: gzip` к заголовкам запроса, и включить настройку ClickHouse `enable_http_compression`. + Это может быть использовано для уменьшения трафика по сети при передаче большого количества данных, а также для создания сразу сжатых дампов. В параметре URL database может быть указана БД по умолчанию. @@ -193,7 +196,11 @@ $ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'http://localhost:812 Об остальных параметрах смотри раздел "SET". -В отличие от родного интерфейса, HTTP интерфейс не поддерживает понятие сессии и настройки в пределах сессии, не позволяет (вернее, позволяет лишь в некоторых случаях) прервать выполнение запроса, не показывает прогресс выполнения запроса. Парсинг и форматирование данных производится на стороне сервера и использование сети может быть неэффективным. +В HTTP-протоколе можно использовать ClickHouse-сессии, для этого необходимо добавить к запросу GET-пaраметр `session_id`. В качестве идентификатора сессии можно использовать произвольную строку. По умолчанию через 60 секунд бездействия сессия будет прервана. Можно изменить этот таймаут, изменяя настройку `default_session_timeout` в конфигурации сервера, или добавив к запросу GET параметр `session_timeout`. Статус сессии можно проверить с помощью параметра `session_check=1`. В рамках одной сессии одновременно может испольняться только один запрос. + +Имеется возможность получать информацию о прогрессе выполнения запроса в залоголвках X-ClickHouse-Progress, для этого нужно включить настройку send_progress_in_http_headers. + +Запущенные запросы не останавливаются автоматически при разрыве HTTP соединения. Парсинг и форматирование данных производится на стороне сервера и использование сети может быть неэффективным. Может быть передан необязательный параметр query_id - идентификатор запроса, произвольная строка. Подробнее смотрите раздел "Настройки, replace_running_query". Может быть передан необязательный параметр quota_key - ключ квоты, произвольная строка. Подробнее смотрите раздел "Квоты". diff --git a/docs/ru/table_functions/numbers.md b/docs/ru/table_functions/numbers.md new file mode 100644 index 00000000000..21bf3492ca1 --- /dev/null +++ b/docs/ru/table_functions/numbers.md @@ -0,0 +1,16 @@ +# numbers + +`numbers(N)` - возвращает таблицу с единственным столбцом number (тип UInt64), содержащую натуральные числа от 0 до N-1. + +Так же как и таблица `system.numbers` может использоваться для тестов и генерации последовательных значений. + +Следующие 2 запроса эквивалентны: +```sql +SELECT * FROM numbers(10); +SELECT * FROM system.numbers LIMIT 10; +``` +Примеры: +```sql +-- генарация последовательности всех дат от 2010-01-01 до 2010-12-31 +select toDate('2010-01-01') + number as d FROM numbers(365); +``` From 04235f2e510b66ff7879fdb01811bc683292c8d2 Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov <1549571+filimonov@users.noreply.github.com> Date: Wed, 14 Mar 2018 00:42:06 +0100 Subject: [PATCH 058/244] Fixing bad copy-paste, shorten sample --- docs/en/formats/verticalraw.md | 4 ++-- docs/ru/formats/verticalraw.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/formats/verticalraw.md b/docs/en/formats/verticalraw.md index 440967eb598..9bb53ee1260 100644 --- a/docs/en/formats/verticalraw.md +++ b/docs/en/formats/verticalraw.md @@ -1,6 +1,6 @@ # VerticalRaw -Differs from `TabSeparated` format in that the rows are written without escaping. +Differs from `Vertical` format in that the rows are written without escaping. This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). Samples: @@ -8,7 +8,7 @@ Samples: :) SHOW CREATE TABLE geonames FORMAT VerticalRaw; Row 1: ────── -statement: CREATE TABLE default.geonames ( geonameid UInt32, name String, asciiname String, alternatenames String, latitude Float32, longitude Float32, feature_class String, feature_code String, country_code String, cc2 String, admin1_code String, admin2_code String, admin3_code String, admin4_code String, population Int64, elevation String, dem String, timezone String, modification_date Date, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) +statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) :) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; Row 1: diff --git a/docs/ru/formats/verticalraw.md b/docs/ru/formats/verticalraw.md index 9693cabe3c3..fb497430fcd 100644 --- a/docs/ru/formats/verticalraw.md +++ b/docs/ru/formats/verticalraw.md @@ -8,7 +8,7 @@ :) SHOW CREATE TABLE geonames FORMAT VerticalRaw; Row 1: ────── -statement: CREATE TABLE default.geonames ( geonameid UInt32, name String, asciiname String, alternatenames String, latitude Float32, longitude Float32, feature_class String, feature_code String, country_code String, cc2 String, admin1_code String, admin2_code String, admin3_code String, admin4_code String, population Int64, elevation String, dem String, timezone String, modification_date Date, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) +statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) :) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; Row 1: From 2c083b9b5916c0a868ebe27a5727a45e3703f3fa Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov <1549571+filimonov@users.noreply.github.com> Date: Wed, 14 Mar 2018 00:49:12 +0100 Subject: [PATCH 059/244] Fixing obsolete name of clickhouse-compressor --- docs/en/interfaces/http_interface.md | 2 +- docs/ru/interfaces/http_interface.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/interfaces/http_interface.md b/docs/en/interfaces/http_interface.md index 8c223cf69cf..5c989a59d65 100644 --- a/docs/en/interfaces/http_interface.md +++ b/docs/en/interfaces/http_interface.md @@ -132,7 +132,7 @@ For successful requests that don't return a data table, an empty response body i You can use compression when transmitting data. -For using ClickHouse internal compression format, and you will need to use the special compressor program to work with it (sudo apt-get install compressor-metrika-yandex). +For using ClickHouse internal compression format, and you will need to use the special clickhouse-compressor program to work with it (installed as a part of clickhouse-client package). If you specified 'compress=1' in the URL, the server will compress the data it sends you. If you specified 'decompress=1' in the URL, the server will decompress the same data that you pass in the POST method. diff --git a/docs/ru/interfaces/http_interface.md b/docs/ru/interfaces/http_interface.md index a20ca4d844e..8f2ae4377f4 100644 --- a/docs/ru/interfaces/http_interface.md +++ b/docs/ru/interfaces/http_interface.md @@ -132,7 +132,7 @@ POST 'http://localhost:8123/?query=DROP TABLE t' Для запросов, которые не возвращают таблицу с данными, в случае успеха, выдаётся пустое тело ответа. -Вы можете использовать внутренний формат сжатия Clickhouse при передаче данных. Формат сжатых данных нестандартный, и вам придётся использовать для работы с ним специальную программу compressor (sudo apt-get install compressor-metrika-yandex). +Вы можете использовать внутренний формат сжатия Clickhouse при передаче данных. Формат сжатых данных нестандартный, и вам придётся использовать для работы с ним специальную программу clickhouse-compressor (устанавливается вместе с пакетом clickhouse-client). Если вы указали в URL compress=1, то сервер будет сжимать отправляемые вам данные. Если вы указали в URL decompress=1, то сервер будет разжимать те данные, которые вы передаёте ему POST-ом. From 614cc887101a35a0db24729da41cdaa66b3d8f5d Mon Sep 17 00:00:00 2001 From: filimonov <1549571+filimonov@users.noreply.github.com> Date: Wed, 14 Mar 2018 00:52:38 +0100 Subject: [PATCH 060/244] fix word end --- docs/ru/table_functions/numbers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/table_functions/numbers.md b/docs/ru/table_functions/numbers.md index 21bf3492ca1..bd5d566f78e 100644 --- a/docs/ru/table_functions/numbers.md +++ b/docs/ru/table_functions/numbers.md @@ -1,6 +1,6 @@ # numbers -`numbers(N)` - возвращает таблицу с единственным столбцом number (тип UInt64), содержащую натуральные числа от 0 до N-1. +`numbers(N)` - возвращает таблицу с единственным столбцом number (тип UInt64), содержащим натуральные числа от 0 до N-1. Так же как и таблица `system.numbers` может использоваться для тестов и генерации последовательных значений. From 8bb3672beac6b2c659f13ff09b1e95da38a2263f Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 14 Mar 2018 05:42:48 +0300 Subject: [PATCH 061/244] Update InterpreterSelectQuery.cpp --- dbms/src/Interpreters/InterpreterSelectQuery.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 49a46abeb13..49b3ba27004 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -712,7 +712,6 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline else throw Exception("Logical error in InterpreterSelectQuery: nowhere to read", ErrorCodes::LOGICAL_ERROR); - StackTrace st; /// Aliases in table declaration. if (from_stage == QueryProcessingStage::FetchColumns && alias_actions) { From cbab87f18eb6c295de5f23eb91b003a8059a34ee Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 14 Mar 2018 05:59:27 +0300 Subject: [PATCH 062/244] Update AggregateFunctionIntersectionsMax.cpp --- .../AggregateFunctions/AggregateFunctionIntersectionsMax.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp index 854737ceba4..1292bcb8561 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp @@ -133,10 +133,10 @@ AggregateFunctionPtr createAggregateFunctionIntersectionsMaxPos(const std::strin void registerAggregateFunctionIntersectionsMax(AggregateFunctionFactory & factory) { - factory.registerFunction("IntersectionsMax", + factory.registerFunction("intersectionsMax", createAggregateFunctionIntersectionsMax, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("IntersectionsMaxPos", + factory.registerFunction("intersectionsMaxPos", createAggregateFunctionIntersectionsMaxPos, AggregateFunctionFactory::CaseInsensitive); } From b4f1ecb7f8f8f9198fb071af5f509a71a8599945 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 06:02:18 +0300 Subject: [PATCH 063/244] clang-format #2012 --- .../AggregateFunctionIntersectionsMax.cpp | 123 +++++++++--------- .../AggregateFunctionIntersectionsMax.h | 79 ++++++----- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp index 1292bcb8561..e9e6c739422 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp @@ -7,62 +7,66 @@ namespace DB { - template -typename Intersections::PointsMap::iterator -Intersections::insert_point(const T &v) +typename Intersections::PointsMap::iterator Intersections::insert_point(const T & v) { - auto res = points.emplace(v,0); - auto &i = res.first; - if(!res.second) return i; - if(i==points.begin()) return i; + auto res = points.emplace(v, 0); + auto & i = res.first; + if (!res.second) + return i; + if (i == points.begin()) + return i; auto prev = i; prev--; - i->second=prev->second; + i->second = prev->second; return i; } template -void Intersections::add(const T &start, const T &end, T weight) +void Intersections::add(const T & start, const T & end, T weight) { auto sp = insert_point(start); auto ep = end ? insert_point(end) : points.end(); - do { - sp->second+=weight; - if(sp->second > max_weight) { + do + { + sp->second += weight; + if (sp->second > max_weight) + { max_weight = sp->second; max_weight_pos = sp->first; } - } while(++sp != ep); + } while (++sp != ep); } template -void Intersections::merge(const Intersections &other) +void Intersections::merge(const Intersections & other) { - if(other.points.empty()) + if (other.points.empty()) return; typename PointsMap::const_iterator prev, i = other.points.begin(); prev = i; i++; - while(i != other.points.end()) { - add(prev->first,i->first,prev->second); + while (i != other.points.end()) + { + add(prev->first, i->first, prev->second); prev = i; i++; } - if(prev != other.points.end()) - add(prev->first,0,prev->second); + if (prev != other.points.end()) + add(prev->first, 0, prev->second); } template void Intersections::serialize(WriteBuffer & buf) const { - writeBinary(points.size(),buf); - for(const auto &p: points) { - writeBinary(p.first,buf); - writeBinary(p.second,buf); + writeBinary(points.size(), buf); + for (const auto & p : points) + { + writeBinary(p.first, buf); + writeBinary(p.second, buf); } } @@ -74,72 +78,71 @@ void Intersections::deserialize(ReadBuffer & buf) T weight; readBinary(size, buf); - for (std::size_t i = 0; i < size; ++i) { + for (std::size_t i = 0; i < size; ++i) + { readBinary(point, buf); - readBinary(weight,buf); - points.emplace(point,weight); + readBinary(weight, buf); + points.emplace(point, weight); } } void AggregateFunctionIntersectionsMax::_add( - AggregateDataPtr place, - const IColumn & column_start, - const IColumn & column_end, - size_t row_num) const + AggregateDataPtr place, const IColumn & column_start, const IColumn & column_end, size_t row_num) const { PointType start_time, end_time; Field tmp_start_time_field, tmp_end_time_field; - column_start.get(row_num,tmp_start_time_field); - if(tmp_start_time_field.isNull()) + column_start.get(row_num, tmp_start_time_field); + if (tmp_start_time_field.isNull()) return; start_time = tmp_start_time_field.template get(); - if(0==start_time) + if (0 == start_time) return; - column_end.get(row_num,tmp_end_time_field); - if(tmp_end_time_field.isNull()) { + column_end.get(row_num, tmp_end_time_field); + if (tmp_end_time_field.isNull()) + { end_time = 0; - } else { + } + else + { end_time = tmp_end_time_field.template get(); - if(0!=end_time) { - if(end_time==start_time) { + if (0 != end_time) + { + if (end_time == start_time) + { end_time = 0; - } else if(end_time < start_time) { + } + else if (end_time < start_time) + { return; } } } - data(place).add(start_time,end_time); + data(place).add(start_time, end_time); } namespace { + AggregateFunctionPtr createAggregateFunctionIntersectionsMax( + const std::string & name, const DataTypes & argument_types, const Array & parameters) + { + assertBinary(name, argument_types); + return std::make_shared(argument_types, parameters, false); + } -AggregateFunctionPtr createAggregateFunctionIntersectionsMax(const std::string & name, const DataTypes & argument_types, const Array & parameters) -{ - assertBinary(name, argument_types); - return std::make_shared(argument_types,parameters,false); -} - -AggregateFunctionPtr createAggregateFunctionIntersectionsMaxPos(const std::string & name, const DataTypes & argument_types, const Array & parameters) -{ - assertBinary(name, argument_types); - return std::make_shared(argument_types,parameters,true); -} - + AggregateFunctionPtr createAggregateFunctionIntersectionsMaxPos( + const std::string & name, const DataTypes & argument_types, const Array & parameters) + { + assertBinary(name, argument_types); + return std::make_shared(argument_types, parameters, true); + } } void registerAggregateFunctionIntersectionsMax(AggregateFunctionFactory & factory) { - factory.registerFunction("intersectionsMax", - createAggregateFunctionIntersectionsMax, - AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("intersectionsMaxPos", - createAggregateFunctionIntersectionsMaxPos, - AggregateFunctionFactory::CaseInsensitive); + factory.registerFunction("intersectionsMax", createAggregateFunctionIntersectionsMax, AggregateFunctionFactory::CaseInsensitive); + factory.registerFunction("intersectionsMaxPos", createAggregateFunctionIntersectionsMaxPos, AggregateFunctionFactory::CaseInsensitive); } - } - diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h index ca97986e678..c15ae1ae33d 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h @@ -2,10 +2,10 @@ #include -#include -#include #include #include +#include +#include #include @@ -15,7 +15,6 @@ namespace DB { - namespace ErrorCodes { extern const int AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS; @@ -26,71 +25,68 @@ namespace ErrorCodes template class Intersections final { - using PointsMap = std::map; PointsMap points; T max_weight; T max_weight_pos; - typename PointsMap::iterator insert_point(const T &v); - public: + typename PointsMap::iterator insert_point(const T & v); - Intersections() - : max_weight(0) - { } +public: + Intersections() : max_weight(0) {} - void add(const T &start, const T &end, T weight = 1); - void merge(const Intersections &other); + void add(const T & start, const T & end, T weight = 1); + void merge(const Intersections & other); void serialize(WriteBuffer & buf) const; void deserialize(ReadBuffer & buf); - T max() const { return max_weight; } - T max_pos() const { return max_weight_pos; } + T max() const + { + return max_weight; + } + T max_pos() const + { + return max_weight_pos; + } }; class AggregateFunctionIntersectionsMax final - : public IAggregateFunctionDataHelper, AggregateFunctionIntersectionsMax> + : public IAggregateFunctionDataHelper, AggregateFunctionIntersectionsMax> { using PointType = UInt64; bool return_position; void _add(AggregateDataPtr place, const IColumn & column_start, const IColumn & column_end, size_t row_num) const; - public: +public: AggregateFunctionIntersectionsMax(const DataTypes & arguments, const Array & params, bool return_position) - : return_position(return_position) + : return_position(return_position) { - if (!params.empty()) { + if (!params.empty()) + { throw Exception( - "Aggregate function " + getName() + " does not allow paremeters.", - ErrorCodes::AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS); + "Aggregate function " + getName() + " does not allow paremeters.", ErrorCodes::AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS); } if (arguments.size() != 2) throw Exception("Aggregate function " + getName() + " requires two arguments.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - if(!arguments[0]->isValueRepresentedByInteger()) - throw Exception { - getName() + ": first argument must be represented by integer", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT - }; + if (!arguments[0]->isValueRepresentedByInteger()) + throw Exception{getName() + ": first argument must be represented by integer", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - if(!arguments[1]->isValueRepresentedByInteger()) - throw Exception { - getName() + ": second argument must be represented by integer", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT - }; + if (!arguments[1]->isValueRepresentedByInteger()) + throw Exception{getName() + ": second argument must be represented by integer", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - if(!arguments[0]->equals(*arguments[1])) - throw Exception { - getName() + ": arguments must have the same type", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT - }; + if (!arguments[0]->equals(*arguments[1])) + throw Exception{getName() + ": arguments must have the same type", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } - String getName() const override { return "IntersectionsMax"; } + String getName() const override + { + return "IntersectionsMax"; + } DataTypePtr getReturnType() const override { @@ -99,7 +95,7 @@ class AggregateFunctionIntersectionsMax final void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena *) const override { - _add(place,*columns[0],*columns[1],row_num); + _add(place, *columns[0], *columns[1], row_num); } void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override @@ -119,14 +115,15 @@ class AggregateFunctionIntersectionsMax final void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override { - auto &ret = static_cast(to).getData(); + auto & ret = static_cast(to).getData(); ret.push_back(data(place).max()); - if(return_position) + if (return_position) ret.push_back(data(place).max_pos()); } - const char * getHeaderFilePath() const override { return __FILE__; } + const char * getHeaderFilePath() const override + { + return __FILE__; + } }; - } - From c9d1b61ef7a8a3c67c89354e7f3d502a3b62f561 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 06:19:23 +0300 Subject: [PATCH 064/244] Fixed build after merge #2029 --- dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.h | 3 +++ dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp | 2 ++ dbms/src/Storages/System/StorageSystemMacros.cpp | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.h b/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.h index b694b4535da..055581eb518 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.h +++ b/dbms/src/Storages/MergeTree/MergeTreeBlockReadUtils.h @@ -1,8 +1,11 @@ #pragma once + +#include #include #include #include + namespace DB { diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 38608f6ea32..8ab7699a03b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include diff --git a/dbms/src/Storages/System/StorageSystemMacros.cpp b/dbms/src/Storages/System/StorageSystemMacros.cpp index 37c3197fd60..456730bde4b 100644 --- a/dbms/src/Storages/System/StorageSystemMacros.cpp +++ b/dbms/src/Storages/System/StorageSystemMacros.cpp @@ -13,10 +13,10 @@ namespace DB StorageSystemMacros::StorageSystemMacros(const std::string & name_) : name(name_) { - columns = NamesAndTypesList{ + setColumns(ColumnsDescription({ {"macro", std::make_shared()}, {"substitution", std::make_shared()}, - }; + })); } From 688d277ad4bcd3826f5ceb40ca32c1ca9c894132 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 07:36:41 +0300 Subject: [PATCH 065/244] Adaptation #2012 --- .../AggregateFunctionIntersectionsMax.cpp | 148 ---------------- .../AggregateFunctionIntersectionsMax.h | 129 -------------- .../AggregateFunctionMaxIntersections.cpp | 32 ++++ .../AggregateFunctionMaxIntersections.h | 167 ++++++++++++++++++ .../registerAggregateFunctions.cpp | 4 +- ...ntersections_aggregate_functions.reference | 2 + ...0605_intersections_aggregate_functions.sql | 20 +++ 7 files changed, 223 insertions(+), 279 deletions(-) delete mode 100644 dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp delete mode 100644 dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h create mode 100644 dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.reference create mode 100644 dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.sql diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp deleted file mode 100644 index e9e6c739422..00000000000 --- a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include -#include - -#include -#include - -namespace DB -{ -template -typename Intersections::PointsMap::iterator Intersections::insert_point(const T & v) -{ - auto res = points.emplace(v, 0); - auto & i = res.first; - if (!res.second) - return i; - if (i == points.begin()) - return i; - auto prev = i; - prev--; - i->second = prev->second; - return i; -} - -template -void Intersections::add(const T & start, const T & end, T weight) -{ - auto sp = insert_point(start); - auto ep = end ? insert_point(end) : points.end(); - do - { - sp->second += weight; - if (sp->second > max_weight) - { - max_weight = sp->second; - max_weight_pos = sp->first; - } - } while (++sp != ep); -} - -template -void Intersections::merge(const Intersections & other) -{ - if (other.points.empty()) - return; - - typename PointsMap::const_iterator prev, i = other.points.begin(); - prev = i; - i++; - - while (i != other.points.end()) - { - add(prev->first, i->first, prev->second); - prev = i; - i++; - } - - if (prev != other.points.end()) - add(prev->first, 0, prev->second); -} - -template -void Intersections::serialize(WriteBuffer & buf) const -{ - writeBinary(points.size(), buf); - for (const auto & p : points) - { - writeBinary(p.first, buf); - writeBinary(p.second, buf); - } -} - -template -void Intersections::deserialize(ReadBuffer & buf) -{ - std::size_t size; - T point; - T weight; - - readBinary(size, buf); - for (std::size_t i = 0; i < size; ++i) - { - readBinary(point, buf); - readBinary(weight, buf); - points.emplace(point, weight); - } -} - -void AggregateFunctionIntersectionsMax::_add( - AggregateDataPtr place, const IColumn & column_start, const IColumn & column_end, size_t row_num) const -{ - PointType start_time, end_time; - Field tmp_start_time_field, tmp_end_time_field; - - column_start.get(row_num, tmp_start_time_field); - if (tmp_start_time_field.isNull()) - return; - start_time = tmp_start_time_field.template get(); - if (0 == start_time) - return; - - column_end.get(row_num, tmp_end_time_field); - if (tmp_end_time_field.isNull()) - { - end_time = 0; - } - else - { - end_time = tmp_end_time_field.template get(); - if (0 != end_time) - { - if (end_time == start_time) - { - end_time = 0; - } - else if (end_time < start_time) - { - return; - } - } - } - - data(place).add(start_time, end_time); -} - -namespace -{ - AggregateFunctionPtr createAggregateFunctionIntersectionsMax( - const std::string & name, const DataTypes & argument_types, const Array & parameters) - { - assertBinary(name, argument_types); - return std::make_shared(argument_types, parameters, false); - } - - AggregateFunctionPtr createAggregateFunctionIntersectionsMaxPos( - const std::string & name, const DataTypes & argument_types, const Array & parameters) - { - assertBinary(name, argument_types); - return std::make_shared(argument_types, parameters, true); - } -} - -void registerAggregateFunctionIntersectionsMax(AggregateFunctionFactory & factory) -{ - factory.registerFunction("intersectionsMax", createAggregateFunctionIntersectionsMax, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("intersectionsMaxPos", createAggregateFunctionIntersectionsMaxPos, AggregateFunctionFactory::CaseInsensitive); -} -} diff --git a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h b/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h deleted file mode 100644 index c15ae1ae33d..00000000000 --- a/dbms/src/AggregateFunctions/AggregateFunctionIntersectionsMax.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include - -#include - -#include - -#include - -namespace DB -{ -namespace ErrorCodes -{ - extern const int AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; -} - -template -class Intersections final -{ - using PointsMap = std::map; - - PointsMap points; - T max_weight; - T max_weight_pos; - - typename PointsMap::iterator insert_point(const T & v); - -public: - Intersections() : max_weight(0) {} - - void add(const T & start, const T & end, T weight = 1); - void merge(const Intersections & other); - - void serialize(WriteBuffer & buf) const; - void deserialize(ReadBuffer & buf); - - T max() const - { - return max_weight; - } - T max_pos() const - { - return max_weight_pos; - } -}; - -class AggregateFunctionIntersectionsMax final - : public IAggregateFunctionDataHelper, AggregateFunctionIntersectionsMax> -{ - using PointType = UInt64; - - bool return_position; - void _add(AggregateDataPtr place, const IColumn & column_start, const IColumn & column_end, size_t row_num) const; - -public: - AggregateFunctionIntersectionsMax(const DataTypes & arguments, const Array & params, bool return_position) - : return_position(return_position) - { - if (!params.empty()) - { - throw Exception( - "Aggregate function " + getName() + " does not allow paremeters.", ErrorCodes::AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS); - } - - if (arguments.size() != 2) - throw Exception("Aggregate function " + getName() + " requires two arguments.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - - if (!arguments[0]->isValueRepresentedByInteger()) - throw Exception{getName() + ": first argument must be represented by integer", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - - if (!arguments[1]->isValueRepresentedByInteger()) - throw Exception{getName() + ": second argument must be represented by integer", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - - if (!arguments[0]->equals(*arguments[1])) - throw Exception{getName() + ": arguments must have the same type", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } - - String getName() const override - { - return "IntersectionsMax"; - } - - DataTypePtr getReturnType() const override - { - return std::make_shared(); - } - - void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena *) const override - { - _add(place, *columns[0], *columns[1], row_num); - } - - void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override - { - this->data(place).merge(data(rhs)); - } - - void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override - { - this->data(place).serialize(buf); - } - - void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override - { - this->data(place).deserialize(buf); - } - - void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override - { - auto & ret = static_cast(to).getData(); - ret.push_back(data(place).max()); - if (return_position) - ret.push_back(data(place).max_pos()); - } - - const char * getHeaderFilePath() const override - { - return __FILE__; - } -}; -} diff --git a/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp new file mode 100644 index 00000000000..e81dfe98259 --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + + +namespace DB +{ + +namespace +{ + AggregateFunctionPtr createAggregateFunctionMaxIntersections( + AggregateFunctionIntersectionsKind kind, + const std::string & name, const DataTypes & argument_types, const Array & parameters) + { + assertBinary(name, argument_types); + assertNoParameters(name, parameters); + + return AggregateFunctionPtr{createWithNumericType(*argument_types[0], kind, argument_types)}; + } +} + +void registerAggregateFunctionsMaxIntersections(AggregateFunctionFactory & factory) +{ + factory.registerFunction("maxIntersections", [](const std::string & name, const DataTypes & argument_types, const Array & parameters) + { return createAggregateFunctionMaxIntersections(AggregateFunctionIntersectionsKind::Count, name, argument_types, parameters); }); + + factory.registerFunction("maxIntersectionsPosition", [](const std::string & name, const DataTypes & argument_types, const Array & parameters) + { return createAggregateFunctionMaxIntersections(AggregateFunctionIntersectionsKind::Position, name, argument_types, parameters); }); +} + +} diff --git a/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h new file mode 100644 index 00000000000..ebc283c03fc --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h @@ -0,0 +1,167 @@ +#pragma once + +#include + +#include +#include + +#include +#include + +#include + +#include + +#define AGGREGATE_FUNCTION_MAX_INTERSECTIONS_MAX_ARRAY_SIZE 0xFFFFFF + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int TOO_LARGE_ARRAY_SIZE; +} + + +/** maxIntersections: returns maximum count of the intersected intervals defined by start_column and end_column values, + * maxIntersectionsPosition: returns leftmost position of maximum intersection of intervals. + */ + +/// Similar to GroupArrayNumericData. +template +struct MaxIntersectionsData +{ + /// Left or right end of the interval and signed weight; with positive sign for begin of interval and negative sign for end of interval. + using Value = std::pair; + + // Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena + using Allocator = MixedArenaAllocator<4096>; + using Array = PODArray; + + Array value; +}; + +enum class AggregateFunctionIntersectionsKind +{ + Count, + Position +}; + +template +class AggregateFunctionIntersectionsMax final + : public IAggregateFunctionDataHelper, AggregateFunctionIntersectionsMax> +{ +private: + AggregateFunctionIntersectionsKind kind; + +public: + AggregateFunctionIntersectionsMax(AggregateFunctionIntersectionsKind kind_, const DataTypes & arguments) + : kind(kind_) + { + if (!arguments[0]->isNumber()) + throw Exception{getName() + ": first argument must be represented by integer", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + + if (!arguments[1]->isNumber()) + throw Exception{getName() + ": second argument must be represented by integer", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + + if (!arguments[0]->equals(*arguments[1])) + throw Exception{getName() + ": arguments must have the same type", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + } + + String getName() const override + { + return kind == AggregateFunctionIntersectionsKind::Count + ? "maxIntersections" + : "maxIntersectionsPosition"; + } + + DataTypePtr getReturnType() const override + { + if (kind == AggregateFunctionIntersectionsKind::Count) + return std::make_shared(); + else + return std::make_shared>(); + } + + void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena * arena) const override + { + PointType left = static_cast &>(*columns[0]).getData()[row_num]; + PointType right = static_cast &>(*columns[1]).getData()[row_num]; + + this->data(place).value.push_back(std::make_pair(left, Int64(1)), arena); + this->data(place).value.push_back(std::make_pair(right, Int64(-1)), arena); + } + + void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override + { + auto & cur_elems = this->data(place); + auto & rhs_elems = this->data(rhs); + + cur_elems.value.insert(rhs_elems.value.begin(), rhs_elems.value.end(), arena); + } + + void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override + { + const auto & value = this->data(place).value; + size_t size = value.size(); + writeVarUInt(size, buf); + buf.write(reinterpret_cast(&value[0]), size * sizeof(value[0])); + } + + void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena * arena) const override + { + size_t size = 0; + readVarUInt(size, buf); + + if (unlikely(size > AGGREGATE_FUNCTION_MAX_INTERSECTIONS_MAX_ARRAY_SIZE)) + throw Exception("Too large array size", ErrorCodes::TOO_LARGE_ARRAY_SIZE); + + auto & value = this->data(place).value; + + value.resize(size, arena); + buf.read(reinterpret_cast(&value[0]), size * sizeof(value[0])); + } + + void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override + { + Int64 current_intersections = 0; + Int64 max_intersections = 0; + PointType position_of_max_intersections = 0; + + /// const_cast because we will sort the array + auto & array = const_cast::Array &>(this->data(place).value); + + /// TODO NaNs? + std::sort(array.begin(), array.end(), [](const auto & a, const auto & b) { return a.first < b.first; }); + + for (const auto & point_weight : array) + { + current_intersections += point_weight.second; + if (current_intersections > max_intersections) + { + max_intersections = current_intersections; + position_of_max_intersections = point_weight.first; + } + } + + if (kind == AggregateFunctionIntersectionsKind::Count) + { + auto & result_column = static_cast(to).getData(); + result_column.push_back(max_intersections); + } + else + { + auto & result_column = static_cast &>(to).getData(); + result_column.push_back(position_of_max_intersections); + } + } + + const char * getHeaderFilePath() const override + { + return __FILE__; + } +}; + +} diff --git a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp index d054107c705..644543e4f2e 100644 --- a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp +++ b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp @@ -23,7 +23,7 @@ void registerAggregateFunctionsUniq(AggregateFunctionFactory &); void registerAggregateFunctionUniqUpTo(AggregateFunctionFactory &); void registerAggregateFunctionTopK(AggregateFunctionFactory &); void registerAggregateFunctionsBitwise(AggregateFunctionFactory &); -void registerAggregateFunctionIntersectionsMax(AggregateFunctionFactory &); +void registerAggregateFunctionsMaxIntersections(AggregateFunctionFactory &); void registerAggregateFunctionCombinatorIf(AggregateFunctionCombinatorFactory &); void registerAggregateFunctionCombinatorArray(AggregateFunctionCombinatorFactory &); @@ -54,7 +54,7 @@ void registerAggregateFunctions() registerAggregateFunctionUniqUpTo(factory); registerAggregateFunctionTopK(factory); registerAggregateFunctionsBitwise(factory); - registerAggregateFunctionIntersectionsMax(factory); + registerAggregateFunctionsMaxIntersections(factory); } { diff --git a/dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.reference b/dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.reference new file mode 100644 index 00000000000..61c83cba41c --- /dev/null +++ b/dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.reference @@ -0,0 +1,2 @@ +4 +5 diff --git a/dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.sql b/dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.sql new file mode 100644 index 00000000000..c23583dd8c8 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00605_intersections_aggregate_functions.sql @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS test.test; +CREATE TABLE test.test(start Integer, end Integer) engine = Memory; +INSERT INTO test.test(start,end) VALUES (1,3),(2,7),(3,999),(4,7),(5,8); + +/* +1 2 3 4 5 6 7 8 9 +------------------> +1---3 + 2---------7 + 3------------- + 4-----7 + 5-----8 +------------------> +1 2 3 3 4 4 4 2 1 //intersections count for each point +*/ + +SELECT maxIntersections(start,end) FROM test.test; +SELECT maxIntersectionsPosition(start,end) FROM test.test; + +DROP TABLE test.test; From f08940c04c020e2ecdd5a1998571ebab4042a01e Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 08:03:51 +0300 Subject: [PATCH 066/244] Fixed handling of NaNs in aggregate functions that use comparison based sorting #2012 --- .../AggregateFunctionMaxIntersections.h | 9 ++++++--- dbms/src/AggregateFunctions/QuantileExact.h | 5 ++++- dbms/src/AggregateFunctions/QuantileExactWeighted.h | 8 ++++++-- dbms/src/AggregateFunctions/QuantilesCommon.h | 6 ++++++ dbms/src/AggregateFunctions/ReservoirSampler.h | 4 ++++ .../AggregateFunctions/ReservoirSamplerDeterministic.h | 4 ++++ .../0_stateless/00606_quantiles_and_nans.reference | 1 + .../queries/0_stateless/00606_quantiles_and_nans.sql | 1 + 8 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference create mode 100644 dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql diff --git a/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h index ebc283c03fc..11ec01e52e4 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionMaxIntersections.h @@ -9,6 +9,7 @@ #include #include +#include #include @@ -90,8 +91,11 @@ public: PointType left = static_cast &>(*columns[0]).getData()[row_num]; PointType right = static_cast &>(*columns[1]).getData()[row_num]; - this->data(place).value.push_back(std::make_pair(left, Int64(1)), arena); - this->data(place).value.push_back(std::make_pair(right, Int64(-1)), arena); + if (!isNaN(left)) + this->data(place).value.push_back(std::make_pair(left, Int64(1)), arena); + + if (!isNaN(right)) + this->data(place).value.push_back(std::make_pair(right, Int64(-1)), arena); } void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override @@ -133,7 +137,6 @@ public: /// const_cast because we will sort the array auto & array = const_cast::Array &>(this->data(place).value); - /// TODO NaNs? std::sort(array.begin(), array.end(), [](const auto & a, const auto & b) { return a.first < b.first; }); for (const auto & point_weight : array) diff --git a/dbms/src/AggregateFunctions/QuantileExact.h b/dbms/src/AggregateFunctions/QuantileExact.h index c134ad1653d..568ad8d0950 100644 --- a/dbms/src/AggregateFunctions/QuantileExact.h +++ b/dbms/src/AggregateFunctions/QuantileExact.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -32,7 +33,9 @@ struct QuantileExact void add(const Value & x) { - array.push_back(x); + /// We must skip NaNs as they are not compatible with comparison sorting. + if (!isNaN(x)) + array.push_back(x); } template diff --git a/dbms/src/AggregateFunctions/QuantileExactWeighted.h b/dbms/src/AggregateFunctions/QuantileExactWeighted.h index f524426392a..76e65f07dac 100644 --- a/dbms/src/AggregateFunctions/QuantileExactWeighted.h +++ b/dbms/src/AggregateFunctions/QuantileExactWeighted.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace DB @@ -33,12 +34,15 @@ struct QuantileExactWeighted void add(const Value & x) { - ++map[x]; + /// We must skip NaNs as they are not compatible with comparison sorting. + if (!isNaN(x)) + ++map[x]; } void add(const Value & x, const Weight & weight) { - map[x] += weight; + if (!isNaN(x)) + map[x] += weight; } void merge(const QuantileExactWeighted & rhs) diff --git a/dbms/src/AggregateFunctions/QuantilesCommon.h b/dbms/src/AggregateFunctions/QuantilesCommon.h index 53802834379..1f70fde74dd 100644 --- a/dbms/src/AggregateFunctions/QuantilesCommon.h +++ b/dbms/src/AggregateFunctions/QuantilesCommon.h @@ -4,6 +4,7 @@ #include #include +#include namespace DB @@ -12,6 +13,7 @@ namespace DB namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int PARAMETER_OUT_OF_BOUND; } @@ -55,6 +57,10 @@ struct QuantileLevels for (size_t i = 0; i < size; ++i) { levels[i] = applyVisitor(FieldVisitorConvertToNumber(), params[i]); + + if (isNaN(levels[i]) || levels[i] < 0 || levels[i] > 1) + throw Exception("Quantile level is out of range [0..1]", ErrorCodes::PARAMETER_OUT_OF_BOUND); + permutation[i] = i; } diff --git a/dbms/src/AggregateFunctions/ReservoirSampler.h b/dbms/src/AggregateFunctions/ReservoirSampler.h index 77d9f7285b7..ad5bf10f48f 100644 --- a/dbms/src/AggregateFunctions/ReservoirSampler.h +++ b/dbms/src/AggregateFunctions/ReservoirSampler.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,9 @@ public: void insert(const T & v) { + if (isNaN(v)) + return; + sorted = false; ++total_values; if (samples.size() < sample_count) diff --git a/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h b/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h index bff3fcb78ea..44760d8e5a5 100644 --- a/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h +++ b/dbms/src/AggregateFunctions/ReservoirSamplerDeterministic.h @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -66,6 +67,9 @@ public: void insert(const T & v, const UInt64 determinator) { + if (isNaN(v)) + return; + const UInt32 hash = intHash64(determinator); if (!good(hash)) return; diff --git a/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference new file mode 100644 index 00000000000..d00491fd7e5 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.reference @@ -0,0 +1 @@ +1 diff --git a/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql new file mode 100644 index 00000000000..c89883e356b --- /dev/null +++ b/dbms/tests/queries/0_stateless/00606_quantiles_and_nans.sql @@ -0,0 +1 @@ +SELECT DISTINCT eq FROM (WITH range(number % 10) AS arr, arrayMap(x -> x = intDiv(number, 10) ? nan : x, arr) AS arr_with_nan, arrayFilter(x -> x != intDiv(number, 10), arr) AS arr_filtered SELECT number, arrayReduce('quantileExact', arr_with_nan) AS q1, arrayReduce('quantileExact', arr_filtered) AS q2, q1 = q2 AS eq FROM numbers(100)); \ No newline at end of file From 6d6eca5e23253e8677825dbd2039d897b9186f4d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 08:29:05 +0300 Subject: [PATCH 067/244] Reverted bad modification #2035 --- debian/pbuilder-hooks/B90test-server | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/debian/pbuilder-hooks/B90test-server b/debian/pbuilder-hooks/B90test-server index 6efbd387e31..bf0bbfbba63 100755 --- a/debian/pbuilder-hooks/B90test-server +++ b/debian/pbuilder-hooks/B90test-server @@ -3,8 +3,8 @@ set -e set -x for PKG in $(ls /tmp/buildd/*.deb | sed -e's,.*/,,;s,_.*,,' ); do - apt-get install -y --force-yes "$PKG" || true - apt-get remove -y "$PKG" || true + apt-get install -y --force-yes "$PKG" || true + apt-get remove -y "$PKG" || true done dpkg -i /tmp/buildd/*.deb || true @@ -18,9 +18,6 @@ dpkg-reconfigure -f noninteractive tzdata pwd mkdir -p /etc/clickhouse-server/config.d -cp ssl.xml /etc/clickhouse-server/config.d -openssl dhparam -out /etc/clickhouse-server/dhparam.pem 256 -openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt service clickhouse-server start sleep 3 From 905652d0baa313cd467c8fa42f47731349d6c74d Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Wed, 14 Mar 2018 10:03:38 +0300 Subject: [PATCH 068/244] Auto version update to [54364] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index b82d8afccbb..4f6d925f969 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54363-testing) -set(VERSION_REVISION 54363) +set(VERSION_DESCRIBE v1.1.54364-testing) +set(VERSION_REVISION 54364) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 64bd8096d89..7623f7307d3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54363) unstable; urgency=low +clickhouse (1.1.54364) unstable; urgency=low * Modified source code - -- proller Wed, 14 Mar 2018 00:06:37 +0300 + -- Wed, 14 Mar 2018 10:03:38 +0300 From 974e2cf5e7b728f774a4de58acd2f9c83607570b Mon Sep 17 00:00:00 2001 From: Alexander Millin Date: Wed, 14 Mar 2018 12:08:37 +0300 Subject: [PATCH 069/244] Add docs for "ip_trie" dict layout --- docs/en/dicts/external_dicts_dict_layout.md | 87 +++++++++++++++++++-- docs/ru/dicts/external_dicts_dict_layout.md | 76 ++++++++++++++++-- 2 files changed, 148 insertions(+), 15 deletions(-) diff --git a/docs/en/dicts/external_dicts_dict_layout.md b/docs/en/dicts/external_dicts_dict_layout.md index 38be4187de4..ad635db94f5 100644 --- a/docs/en/dicts/external_dicts_dict_layout.md +++ b/docs/en/dicts/external_dicts_dict_layout.md @@ -2,11 +2,11 @@ # Storing dictionaries in memory -There are [many different ways](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-manner) to store dictionaries in memory. +There are [many different ways](external_dicts_dict_layout#dicts-external_dicts_dict_layout-manner) to store dictionaries in memory. -We recommend [flat](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-flat), [hashed](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-hashed), and [complex_key_hashed](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-complex_key_hashed). which provide optimal processing speed. +We recommend [flat](external_dicts_dict_layout#dicts-external_dicts_dict_layout-flat), [hashed](external_dicts_dict_layout#dicts-external_dicts_dict_layout-hashed), and [complex_key_hashed](external_dicts_dict_layout#dicts-external_dicts_dict_layout-complex_key_hashed). which provide optimal processing speed. -Caching is not recommended because of potentially poor performance and difficulties in selecting optimal parameters. Read more about this in the "[cache](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-cache)" section. +Caching is not recommended because of potentially poor performance and difficulties in selecting optimal parameters. Read more about this in the "[cache](external_dicts_dict_layout#dicts-external_dicts_dict_layout-cache)" section. There are several ways to improve dictionary performance: @@ -46,6 +46,7 @@ The configuration looks like this: - [range_hashed](#dicts-external_dicts_dict_layout-range_hashed) - [complex_key_hashed](#dicts-external_dicts_dict_layout-complex_key_hashed) - [complex_key_cache](#dicts-external_dicts_dict_layout-complex_key_cache) +- [ip_trie](#dicts-external_dicts_dict_layout-ip_trie) @@ -87,7 +88,7 @@ Configuration example: ### complex_key_hashed -This type of storage is designed for use with compound [keys](external_dicts_dict_structure.md#dicts-external_dicts_dict_structure). It is similar to hashed. +This type of storage is designed for use with compound [keys](external_dicts_dict_structure#dicts-external_dicts_dict_structure). It is similar to hashed. Configuration example: @@ -108,10 +109,18 @@ This storage method works the same way as hashed and allows using date/time rang Example: The table contains discounts for each advertiser in the format: ``` -+------------------+-----------------------------+------------+----------+ | advertiser id | discount start date | discount end date | amount | +==================+=============================+============+==========+ | 123 | 2015-01-01 | 2015-01-15 | 0.15 | +------------------+-----------------------------+------------+----------+ | 123 | 2015-01-16 | 2015-01-31 | 0.25 | +------------------+-----------------------------+------------+----------+ | 456 | 2015-01-01 | 2015-01-15 | 0.05 | +------------------+-----------------------------+------------+----------+ + +---------------+---------------------+-------------------+--------+ + | advertiser id | discount start date | discount end date | amount | + +===============+=====================+===================+========+ + | 123 | 2015-01-01 | 2015-01-15 | 0.15 | + +---------------+---------------------+-------------------+--------+ + | 123 | 2015-01-16 | 2015-01-31 | 0.25 | + +---------------+---------------------+-------------------+--------+ + | 456 | 2015-01-01 | 2015-01-15 | 0.05 | + +---------------+---------------------+-------------------+--------+ ``` -To use a sample for date ranges, define `range_min` and `range_max` in [structure](external_dicts_dict_structure.md#dicts-external_dicts_dict_structure). +To use a sample for date ranges, define `range_min` and `range_max` in [structure](external_dicts_dict_structure#dicts-external_dicts_dict_structure). Example: @@ -188,7 +197,7 @@ This is the least effective of all the ways to store dictionaries. The speed of To improve cache performance, use a subquery with ` LIMIT`, and call the function with the dictionary externally. -Supported [sources](external_dicts_dict_sources.md#dicts-external_dicts_dict_sources): MySQL, ClickHouse, executable, HTTP. +Supported [sources](external_dicts_dict_sources#dicts-external_dicts_dict_sources): MySQL, ClickHouse, executable, HTTP. Example of settings: @@ -218,4 +227,66 @@ Do not use ClickHouse as a source, because it is slow to process queries with ra ### complex_key_cache -This type of storage is designed for use with compound [keys](external_dicts_dict_structure.md#dicts-external_dicts_dict_structure). Similar to `cache`. +This type of storage is designed for use with compound [keys](external_dicts_dict_structure#dicts-external_dicts_dict_structure). Similar to `cache`. + + + +### ip_trie + + +The table stores IP prefixes for each key (IP address), which makes it possible to map IP addresses to metadata such as ASN or threat score. + +Example: in the table there are prefixes matches to AS number and country: + +``` + +-----------------+-------+--------+ + | prefix | asn | cca2 | + +=================+=======+========+ + | 202.79.32.0/20 | 17501 | NP | + +-----------------+-------+--------+ + | 2620:0:870::/48 | 3856 | US | + +-----------------+-------+--------+ + | 2a02:6b8:1::/48 | 13238 | RU | + +-----------------+-------+--------+ + | 2001:db8::/32 | 65536 | ZZ | + +-----------------+-------+--------+ +``` + +When using such a layout, the structure should have the "key" element. + +Example: + +```xml + + + + prefix + String + + + + asn + UInt32 + + + + cca2 + String + ?? + + ... +``` + +These key must have only one attribute of type String, containing a valid IP prefix. Other types are not yet supported. + +For querying, same functions (dictGetT with tuple) as for complex key dictionaries have to be used: + + dictGetT('dict_name', 'attr_name', tuple(ip)) + +The function accepts either UInt32 for IPv4 address or FixedString(16) for IPv6 address in wire format: + + dictGetString('prefix', 'asn', tuple(IPv6StringToNum('2001:db8::1'))) + +No other type is supported. The function returns attribute for a prefix matching the given IP address. If there are overlapping prefixes, the most specific one is returned. + +The data is stored currently in a bitwise trie, it has to fit in memory. diff --git a/docs/ru/dicts/external_dicts_dict_layout.md b/docs/ru/dicts/external_dicts_dict_layout.md index e88ddf7c735..ff1b9c0cdd5 100644 --- a/docs/ru/dicts/external_dicts_dict_layout.md +++ b/docs/ru/dicts/external_dicts_dict_layout.md @@ -2,11 +2,11 @@ # Хранение словарей в памяти -Словари можно размещать в памяти [множеством способов](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-manner). +Словари можно размещать в памяти [множеством способов](external_dicts_dict_layout#dicts-external_dicts_dict_layout-manner). -Рекомендуем [flat](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-flat), [hashed](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-hashed) и [complex_key_hashed](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-complex_key_hashed). Скорость обработки словарей при этом максимальна. +Рекомендуем [flat](external_dicts_dict_layout#dicts-external_dicts_dict_layout-flat), [hashed](external_dicts_dict_layout#dicts-external_dicts_dict_layout-hashed) и [complex_key_hashed](external_dicts_dict_layout#dicts-external_dicts_dict_layout-complex_key_hashed). Скорость обработки словарей при этом максимальна. -Размещение с кэшированием не рекомендуется использовать из-за потенциально низкой производительности и сложностей в подборе оптимальных параметров. Читайте об этом подробнее в разделе " [cache](external_dicts_dict_layout.md#dicts-external_dicts_dict_layout-cache)". +Размещение с кэшированием не рекомендуется использовать из-за потенциально низкой производительности и сложностей в подборе оптимальных параметров. Читайте об этом подробнее в разделе " [cache](external_dicts_dict_layout#dicts-external_dicts_dict_layout-cache)". Повысить производительнось словарей можно следующими способами: @@ -46,6 +46,7 @@ - [range_hashed](#dicts-external_dicts_dict_layout-range_hashed) - [complex_key_hashed](#dicts-external_dicts_dict_layout-complex_key_hashed) - [complex_key_cache](#dicts-external_dicts_dict_layout-complex_key_cache) +- [ip_trie](#dicts-external_dicts_dict_layout-ip_trie) @@ -87,7 +88,7 @@ ### complex_key_hashed -Тип размещения предназначен для использования с составными [ключами](external_dicts_dict_structure.md#dicts-external_dicts_dict_structure). Аналогичен `hashed`. +Тип размещения предназначен для использования с составными [ключами](external_dicts_dict_structure#dicts-external_dicts_dict_structure). Аналогичен `hashed`. Пример конфигурации: @@ -119,7 +120,7 @@ +------------------+-----------------------------+------------+----------+ ``` -Чтобы использовать выборку по диапазонам дат, необходимо в [structure](external_dicts_dict_structure.md#dicts-external_dicts_dict_structure) определить элементы `range_min`, `range_max`. +Чтобы использовать выборку по диапазонам дат, необходимо в [structure](external_dicts_dict_structure#dicts-external_dicts_dict_structure) определить элементы `range_min`, `range_max`. Пример: @@ -196,7 +197,7 @@ Чтобы увеличить производительность кэша, используйте подзапрос с `LIMIT`, а снаружи вызывайте функцию со словарём. -Поддерживаются [источники](external_dicts_dict_sources.md#dicts-external_dicts_dict_sources): MySQL, ClickHouse, executable, HTTP. +Поддерживаются [источники](external_dicts_dict_sources#dicts-external_dicts_dict_sources): MySQL, ClickHouse, executable, HTTP. Пример настройки: @@ -226,4 +227,65 @@ ### complex_key_cache -Тип размещения предназначен для использования с составными [ключами](external_dicts_dict_structure.md#dicts-external_dicts_dict_structure). Аналогичен `cache`. +Тип размещения предназначен для использования с составными [ключами](external_dicts_dict_structure#dicts-external_dicts_dict_structure). Аналогичен `cache`. + + + +### ip_trie + +Тип размещения предназначен для сопоставления префиксов сети (IP адресов) с метаданными, такими как ASN. + +Пример: таблица содержит префиксы сети и соответствующие им номера AS и коды стран: + +``` + +-----------------+-------+--------+ + | prefix | asn | cca2 | + +=================+=======+========+ + | 202.79.32.0/20 | 17501 | NP | + +-----------------+-------+--------+ + | 2620:0:870::/48 | 3856 | US | + +-----------------+-------+--------+ + | 2a02:6b8:1::/48 | 13238 | RU | + +-----------------+-------+--------+ + | 2001:db8::/32 | 65536 | ZZ | + +-----------------+-------+--------+ +``` + +При использовании такого макета структура должна иметь составной ключ. + +Пример: + +```xml + + + + prefix + String + + + + asn + UInt32 + + + + cca2 + String + ?? + + ... +``` + +Этот ключ должен иметь только один атрибут типа String, содержащий допустимый префикс IP. Другие типы еще не поддерживаются. + +Для запросов необходимо использовать те же функции (`dictGetT` с кортежем), что и для словарей с составными ключами: + + dictGetT('dict_name', 'attr_name', tuple(ip)) + +Функция принимает либо UInt32 для адреса IPv4, либо FixedString(16) для адреса IPv6: + + dictGetString('prefix', 'asn', tuple(IPv6StringToNum('2001:db8::1'))) + +Никакие другие типы не поддерживаются. Функция возвращает атрибут для префикса, соответствующего данному IP-адресу. Если есть перекрывающиеся префиксы, возвращается наиболее специфический. + +Данные хранятся в побитовом дереве (trie), он должены полностью помещаться в оперативной памяти. From c04ad1aa3eb7df39fc3ed7f5b4961576347e9b83 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 14 Mar 2018 13:35:07 +0300 Subject: [PATCH 070/244] typo --- docs/ru/query_language/queries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index 53063705410..c5a1d46273e 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -76,7 +76,7 @@ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... Его значения не могут быть вставлены в таблицу, он не подставляется при использовании звёздочки в запросе SELECT. Он может быть использован в SELECT-ах - в таком случае, во время разбора запроса, алиас раскрывается. -При добавлении новых столбцов с помощью запроса ALTER, старые данные для этих столбцов не записываются. Вместо этого, при чтении старых данных, для которых отсутствуют значения новых столбцов, выполняется вычисление выражений по умолчанию налету. При этом, если выполнение выражения требует использования других столбцов, не указанных в запросе, то эти столбцы будут дополнительно прочитаны, но только для тех блоков данных, для которых это необходимо. +При добавлении новых столбцов с помощью запроса ALTER, старые данные для этих столбцов не записываются. Вместо этого, при чтении старых данных, для которых отсутствуют значения новых столбцов, выполняется вычисление выражений по умолчанию на лету. При этом, если выполнение выражения требует использования других столбцов, не указанных в запросе, то эти столбцы будут дополнительно прочитаны, но только для тех блоков данных, для которых это необходимо. Если добавить в таблицу новый столбец, а через некоторое время изменить его выражение по умолчанию, то используемые значения для старых данных (для данных, где значения не хранились на диске) поменяются. Также заметим, что при выполнении фоновых слияний, данные для столбцов, отсутствующих в одном из сливаемых кусков, записываются в объединённый кусок. From b910e729460e7da4072e0c182d0c796c3a96433a Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Wed, 14 Mar 2018 15:30:39 +0300 Subject: [PATCH 071/244] stable order in a test --- ...shard_remote_and_columns_with_defaults.sql | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql b/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql index ba955f7848b..c1c47d225db 100644 --- a/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql +++ b/dbms/tests/queries/0_stateless/00604_shard_remote_and_columns_with_defaults.sql @@ -19,20 +19,20 @@ INSERT INTO FUNCTION remote('127.0.0.2', test.t2) VALUES (2, 2); --INSERT INTO FUNCTION remote('127.0.0.2', test.t3) VALUES (2); INSERT INTO FUNCTION remote('127.0.0.2', test.t4) VALUES (2); -SELECT * FROM remote('127.0.0.2', test.t1); +SELECT * FROM remote('127.0.0.2', test.t1) ORDER BY x; SELECT '*** With a DEFAULT column ***'; -SELECT * FROM remote('127.0.0.2', test.t2); +SELECT * FROM remote('127.0.0.2', test.t2) ORDER BY x; SELECT '*** With a MATERIALIZED column ***'; -SELECT * FROM remote('127.0.0.2', test.t3); -SELECT x, y FROM remote('127.0.0.2', test.t3); +SELECT * FROM remote('127.0.0.2', test.t3) ORDER BY x; +SELECT x, y FROM remote('127.0.0.2', test.t3) ORDER BY x; SELECT '*** With an ALIAS column ***'; -SELECT * FROM remote('127.0.0.2', test.t4); -SELECT x, y FROM remote('127.0.0.2', test.t4); +SELECT * FROM remote('127.0.0.2', test.t4) ORDER BY x; +SELECT x, y FROM remote('127.0.0.2', test.t4) ORDER BY x; -DROP TABLE IF EXISTS test.t1; -DROP TABLE IF EXISTS test.t2; -DROP TABLE IF EXISTS test.t3; -DROP TABLE IF EXISTS test.t4; +DROP TABLE test.t1; +DROP TABLE test.t2; +DROP TABLE test.t3; +DROP TABLE test.t4; From d6e9d08d5ef49b82e210c42f401d8c0aad7d43e5 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 13 Mar 2018 16:28:32 +0300 Subject: [PATCH 072/244] getCreateTableQuery and getCreateDatabaseQuery [#CLICKHOUSE-3590] --- dbms/src/Databases/DatabaseDictionary.cpp | 36 ++++++++- dbms/src/Databases/DatabaseDictionary.h | 4 +- dbms/src/Databases/DatabaseMemory.cpp | 7 +- dbms/src/Databases/DatabaseMemory.h | 8 +- dbms/src/Databases/DatabaseOrdinary.cpp | 76 ++++++++++++------- dbms/src/Databases/DatabaseOrdinary.h | 5 +- dbms/src/Databases/IDatabase.h | 8 +- dbms/src/Interpreters/Context.cpp | 15 +++- dbms/src/Interpreters/Context.h | 5 +- .../Interpreters/InterpreterCreateQuery.cpp | 4 +- .../InterpreterShowCreateQuery.cpp | 9 ++- dbms/src/Storages/StorageDictionary.cpp | 1 - dbms/src/Storages/StorageDictionary.h | 40 +++++----- .../Storages/System/StorageSystemTables.cpp | 2 +- 14 files changed, 149 insertions(+), 71 deletions(-) diff --git a/dbms/src/Databases/DatabaseDictionary.cpp b/dbms/src/Databases/DatabaseDictionary.cpp index 8a10535fd09..6c14312c2e3 100644 --- a/dbms/src/Databases/DatabaseDictionary.cpp +++ b/dbms/src/Databases/DatabaseDictionary.cpp @@ -3,6 +3,11 @@ #include #include #include +#include +#include +#include +#include +#include namespace DB { @@ -158,11 +163,34 @@ time_t DatabaseDictionary::getTableMetadataModificationTime( return static_cast(0); } -ASTPtr DatabaseDictionary::getCreateQuery( - const Context &, - const String &) const +ASTPtr DatabaseDictionary::getCreateTableQuery( + const Context & context, + const String & table_name) const { - throw Exception("There is no CREATE TABLE query for DatabaseDictionary tables", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); + String query; + { + WriteBufferFromString buffer(query); + + auto dictionary = context.getExternalDictionaries().getDictionary(table_name); + auto names_and_types = StorageDictionary::getNamesAndTypes(dictionary->getStructure()); + buffer << "CREATE TABLE " << backQuoteIfNeed(name) << '.' << backQuoteIfNeed(table_name) << " ("; + buffer << StorageDictionary::generateNamesAndTypesDescription(names_and_types.begin(), names_and_types.end()); + buffer << ") Engine = Dictionary(" << backQuoteIfNeed(table_name) << ")"; + } + + ParserCreateQuery parser; + return parseQuery(parser, query.data(), query.data() + query.size(), ""); +} + +ASTPtr DatabaseDictionary::getCreateDatabaseQuery(const Context & /*context*/) const +{ + String query; + { + WriteBufferFromString buffer(query); + buffer << "CREATE DATABASE " << backQuoteIfNeed(name) << " ENGINE = Dictionary"; + } + ParserCreateQuery parser; + return parseQuery(parser, query.data(), query.data() + query.size(), ""); } void DatabaseDictionary::shutdown() diff --git a/dbms/src/Databases/DatabaseDictionary.h b/dbms/src/Databases/DatabaseDictionary.h index 1308ea20a40..f62bfc3e1c3 100644 --- a/dbms/src/Databases/DatabaseDictionary.h +++ b/dbms/src/Databases/DatabaseDictionary.h @@ -89,10 +89,12 @@ public: const Context & context, const String & table_name) override; - ASTPtr getCreateQuery( + ASTPtr getCreateTableQuery( const Context & context, const String & table_name) const override; + ASTPtr getCreateDatabaseQuery(const Context & context) const override; + void shutdown() override; void drop() override; }; diff --git a/dbms/src/Databases/DatabaseMemory.cpp b/dbms/src/Databases/DatabaseMemory.cpp index 66b23f07ca6..b50fb78468e 100644 --- a/dbms/src/Databases/DatabaseMemory.cpp +++ b/dbms/src/Databases/DatabaseMemory.cpp @@ -121,13 +121,18 @@ time_t DatabaseMemory::getTableMetadataModificationTime( return static_cast(0); } -ASTPtr DatabaseMemory::getCreateQuery( +ASTPtr DatabaseMemory::getCreateTableQuery( const Context &, const String &) const { throw Exception("There is no CREATE TABLE query for DatabaseMemory tables", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); } +ASTPtr DatabaseMemory::getCreateDatabaseQuery(const Context &) const +{ + throw Exception("There is no CREATE DATABASE query for DatabaseMemory", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); +} + void DatabaseMemory::shutdown() { /// You can not hold a lock during shutdown. diff --git a/dbms/src/Databases/DatabaseMemory.h b/dbms/src/Databases/DatabaseMemory.h index be095ad3755..dbf37acb5f6 100644 --- a/dbms/src/Databases/DatabaseMemory.h +++ b/dbms/src/Databases/DatabaseMemory.h @@ -80,9 +80,11 @@ public: const Context & context, const String & table_name) override; - ASTPtr getCreateQuery( - const Context & context, - const String & table_name) const override; + ASTPtr getCreateTableQuery( + const Context & context, + const String & table_name) const override; + + ASTPtr getCreateDatabaseQuery(const Context & context) const override; void shutdown() override; void drop() override; diff --git a/dbms/src/Databases/DatabaseOrdinary.cpp b/dbms/src/Databases/DatabaseOrdinary.cpp index 73152387cf6..1f09c118666 100644 --- a/dbms/src/Databases/DatabaseOrdinary.cpp +++ b/dbms/src/Databases/DatabaseOrdinary.cpp @@ -335,22 +335,13 @@ void DatabaseOrdinary::removeTable( } } - -ASTPtr DatabaseOrdinary::getCreateQueryImpl(const String & path, const String & table_name) const +static ASTPtr getQueryFromMetadata(const String & metadata_path) { - String metadata_path; + if (!Poco::File(metadata_path).exists()) + return nullptr; + String query; - if (table_name.empty()) - { - metadata_path = detail::getDatabaseMetadataPath(path); - if (!Poco::File(metadata_path).exists()) - query = "CREATE DATABASE " + backQuoteIfNeed(name) + " ENGINE = Ordinary"; - } - else - metadata_path = detail::getTableMetadataPath(path, table_name); - - if (query.empty()) { ReadBufferFromFile in(metadata_path, 4096); readStringUntilEOF(query, in); @@ -360,6 +351,20 @@ ASTPtr DatabaseOrdinary::getCreateQueryImpl(const String & path, const String & return parseQuery(parser, query.data(), query.data() + query.size(), "in file " + metadata_path); } +static ASTPtr getCreateQueryFromMetadata(const String & metadata_path, const String & database) +{ + ASTPtr ast = getQueryFromMetadata(metadata_path); + + if (ast) + { + ASTCreateQuery & ast_create_query = typeid_cast(*ast); + ast_create_query.attach = false; + ast_create_query.database = database; + } + + return ast; +} + void DatabaseOrdinary::renameTable( const Context & context, @@ -394,7 +399,9 @@ void DatabaseOrdinary::renameTable( throw Exception{e}; } - ASTPtr ast = getCreateQueryImpl(metadata_path, table_name); + ASTPtr ast = getQueryFromMetadata(detail::getTableMetadataPath(metadata_path, table_name)); + if (!ast) + throw Exception("There is no metadata file for table " + table_name, ErrorCodes::FILE_DOESNT_EXIST); ASTCreateQuery & ast_create_query = typeid_cast(*ast); ast_create_query.table = to_table_name; @@ -422,27 +429,40 @@ time_t DatabaseOrdinary::getTableMetadataModificationTime( } -ASTPtr DatabaseOrdinary::getCreateQuery( +ASTPtr DatabaseOrdinary::getCreateTableQuery( const Context & context, const String & table_name) const { ASTPtr ast; - try - { - ast = getCreateQueryImpl(metadata_path, table_name); - } - catch (const Exception & e) - { - /// Handle system.* tables for which there are no table.sql files - if (e.code() == ErrorCodes::FILE_DOESNT_EXIST && tryGetTable(context, table_name) != nullptr) - throw Exception("There is no CREATE TABLE query for table " + table_name, ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); - throw; + auto table_metadata_path = detail::getTableMetadataPath(metadata_path, table_name); + ast = getCreateQueryFromMetadata(table_metadata_path, name); + if (!ast) + { + /// Handle system.* tables for which there are no table.sql files. + auto msg = tryGetTable(context, table_name) + ? "There is no CREATE TABLE query for table " + : "There is no metadata file for table "; + + throw Exception(msg + table_name, ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); } - ASTCreateQuery & ast_create_query = typeid_cast(*ast); - ast_create_query.attach = false; - ast_create_query.database = name; + return ast; +} + +ASTPtr DatabaseOrdinary::getCreateDatabaseQuery(const Context & /*context*/) const +{ + ASTPtr ast; + + auto database_metadata_path = detail::getDatabaseMetadataPath(metadata_path); + ast = getCreateQueryFromMetadata(database_metadata_path, name); + if (!ast) + { + /// Handle databases (such as default) for which there are no database.sql files. + String query = "CREATE DATABASE " + backQuoteIfNeed(name) + " ENGINE = Ordinary"; + ParserCreateQuery parser; + ast = parseQuery(parser, query.data(), query.data() + query.size(), ""); + } return ast; } diff --git a/dbms/src/Databases/DatabaseOrdinary.h b/dbms/src/Databases/DatabaseOrdinary.h index 4cd77c85895..9d8d2458df6 100644 --- a/dbms/src/Databases/DatabaseOrdinary.h +++ b/dbms/src/Databases/DatabaseOrdinary.h @@ -55,10 +55,12 @@ public: const Context & context, const String & table_name) override; - ASTPtr getCreateQuery( + ASTPtr getCreateTableQuery( const Context & context, const String & table_name) const override; + ASTPtr getCreateDatabaseQuery(const Context & context) const override; + String getDataPath() const override; String getMetadataPath() const override; String getTableMetadataPath(const String & table_name) const override; @@ -68,7 +70,6 @@ public: private: void startupTables(ThreadPool * thread_pool); - ASTPtr getCreateQueryImpl(const String & path, const String & table_name) const; }; } diff --git a/dbms/src/Databases/IDatabase.h b/dbms/src/Databases/IDatabase.h index 8d62c0e3d45..01c8970901d 100644 --- a/dbms/src/Databases/IDatabase.h +++ b/dbms/src/Databases/IDatabase.h @@ -124,12 +124,14 @@ public: const Context & context, const String & name) = 0; - /// Get the CREATE TABLE query for the table or CREATE DATABASE query for database if name is empty. - /// It can also provide information for detached tables for which there is metadata. - virtual ASTPtr getCreateQuery( + /// Get the CREATE TABLE query for the table. It can also provide information for detached tables for which there is metadata. + virtual ASTPtr getCreateTableQuery( const Context & context, const String & name) const = 0; + /// Get the CREATE DATABASE query for current database. + virtual ASTPtr getCreateDatabaseQuery(const Context & context) const = 0; + /// Returns path for persistent data storage if the database supports it, empty string otherwise virtual String getDataPath() const { return {}; } /// Returns metadata path if the database supports it, empty string otherwise diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 6fddcbc2f05..e3e0e268f98 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -910,17 +910,17 @@ DatabasePtr Context::detachDatabase(const String & database_name) } -ASTPtr Context::getCreateQuery(const String & database_name, const String & table_name) const +ASTPtr Context::getCreateTableQuery(const String & database_name, const String & table_name) const { auto lock = getLock(); String db = resolveDatabase(database_name, current_database); assertDatabaseExists(db); - return shared->databases[db]->getCreateQuery(*this, table_name); + return shared->databases[db]->getCreateTableQuery(*this, table_name); } -ASTPtr Context::getCreateExternalQuery(const String & table_name) const +ASTPtr Context::getCreateExternalTableQuery(const String & table_name) const { TableAndCreateASTs::const_iterator jt = external_tables.find(table_name); if (external_tables.end() == jt) @@ -929,6 +929,15 @@ ASTPtr Context::getCreateExternalQuery(const String & table_name) const return jt->second.second; } +ASTPtr Context::getCreateDatabaseQuery(const String & database_name) const +{ + auto lock = getLock(); + + String db = resolveDatabase(database_name, current_database); + assertDatabaseExists(db); + + return shared->databases[db]->getCreateDatabaseQuery(*this); +} Settings Context::getSettings() const { diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index bab3be07add..f1e44705f3a 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -241,8 +241,9 @@ public: UInt16 getTCPPort() const; /// Get query for the CREATE table. - ASTPtr getCreateQuery(const String & database_name, const String & table_name) const; - ASTPtr getCreateExternalQuery(const String & table_name) const; + ASTPtr getCreateTableQuery(const String & database_name, const String & table_name) const; + ASTPtr getCreateExternalTableQuery(const String & table_name) const; + ASTPtr getCreateDatabaseQuery(const String & database_name) const; const DatabasePtr getDatabase(const String & database_name) const; DatabasePtr getDatabase(const String & database_name); diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 2b6d333d1f6..347d6208e70 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -432,7 +432,7 @@ void InterpreterCreateQuery::setEngine(ASTCreateQuery & create) const String as_database_name = create.as_database.empty() ? context.getCurrentDatabase() : create.as_database; String as_table_name = create.as_table; - ASTPtr as_create_ptr = context.getCreateQuery(as_database_name, as_table_name); + ASTPtr as_create_ptr = context.getCreateTableQuery(as_database_name, as_table_name); const auto & as_create = typeid_cast(*as_create_ptr); if (as_create.is_view) @@ -461,7 +461,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create) if (create.attach && !create.storage && !create.columns) { // Table SQL definition is available even if the table is detached - auto query = context.getCreateQuery(database_name, table_name); + auto query = context.getCreateTableQuery(database_name, table_name); auto & as_create = typeid_cast(*query); create = as_create; // Copy the saved create query, but use ATTACH instead of CREATE create.attach = true; diff --git a/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp b/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp index 705b9bb4120..a4c3bd7224c 100644 --- a/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterShowCreateQuery.cpp @@ -44,8 +44,13 @@ BlockInputStreamPtr InterpreterShowCreateQuery::executeImpl() if (ast.temporary && !ast.database.empty()) throw Exception("Temporary databases are not possible.", ErrorCodes::SYNTAX_ERROR); - ASTPtr create_query = (ast.temporary ? context.getCreateExternalQuery(ast.table) : - context.getCreateQuery(ast.database, ast.table)); + ASTPtr create_query; + if (ast.temporary) + create_query = context.getCreateExternalTableQuery(ast.table); + else if (ast.table.empty()) + create_query = context.getCreateDatabaseQuery(ast.database); + else + create_query = context.getCreateTableQuery(ast.database, ast.table); if (!create_query && ast.temporary) throw Exception("Unable to show the create query of " + ast.table + ". Maybe it was created by the system.", ErrorCodes::THERE_IS_NO_QUERY); diff --git a/dbms/src/Storages/StorageDictionary.cpp b/dbms/src/Storages/StorageDictionary.cpp index 2bb69748c6d..89d59e11b38 100644 --- a/dbms/src/Storages/StorageDictionary.cpp +++ b/dbms/src/Storages/StorageDictionary.cpp @@ -89,7 +89,6 @@ void StorageDictionary::checkNamesAndTypesCompatibleWithDictionary(const Diction } } - void registerStorageDictionary(StorageFactory & factory) { factory.registerStorage("Dictionary", [](const StorageFactory::Arguments & args) diff --git a/dbms/src/Storages/StorageDictionary.h b/dbms/src/Storages/StorageDictionary.h index 0f21373f546..079c65ff134 100644 --- a/dbms/src/Storages/StorageDictionary.h +++ b/dbms/src/Storages/StorageDictionary.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace Poco @@ -33,6 +35,26 @@ public: void drop() override {} static NamesAndTypesList getNamesAndTypes(const DictionaryStructure & dictionary_structure); + template + static std::string generateNamesAndTypesDescription(ForwardIterator begin, ForwardIterator end) + { + std::string description; + { + WriteBufferFromString buffer(description); + bool first = true; + for (; begin != end; ++begin) + { + if (!first) + buffer << ", "; + first = false; + + buffer << begin->name << ' ' << begin->type->getName(); + } + } + + return description; + } + private: using Ptr = MultiVersion::Version; @@ -42,24 +64,6 @@ private: void checkNamesAndTypesCompatibleWithDictionary(const DictionaryStructure & dictionary_structure) const; - template - std::string generateNamesAndTypesDescription(ForwardIterator begin, ForwardIterator end) const - { - if (begin == end) - { - return ""; - } - std::string description; - for (; begin != end; ++begin) - { - description += ", "; - description += begin->name; - description += ' '; - description += begin->type->getName(); - } - return description.substr(2, description.size()); - } - protected: StorageDictionary(const String & table_name_, const NamesAndTypesList & columns_, diff --git a/dbms/src/Storages/System/StorageSystemTables.cpp b/dbms/src/Storages/System/StorageSystemTables.cpp index 852392a63d1..493750d5dfa 100644 --- a/dbms/src/Storages/System/StorageSystemTables.cpp +++ b/dbms/src/Storages/System/StorageSystemTables.cpp @@ -204,7 +204,7 @@ BlockInputStreams StorageSystemTables::read( try { - ast = database->getCreateQuery(context, table_name); + ast = database->getCreateTableQuery(context, table_name); } catch (const Exception & e) { From 5e7ba54e0635c9db2d7961eeb9a21513b48fb232 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Wed, 14 Mar 2018 15:42:02 +0300 Subject: [PATCH 073/244] max_memory_usage, max_memory_usage_for_user, max_memory_usage_for_all_queries parameter descriptions are added. --- .../operations/settings/query_complexity.md | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/docs/ru/operations/settings/query_complexity.md b/docs/ru/operations/settings/query_complexity.md index 83251f6813c..c964ad6e41c 100644 --- a/docs/ru/operations/settings/query_complexity.md +++ b/docs/ru/operations/settings/query_complexity.md @@ -27,21 +27,43 @@ При использовании метода GET HTTP интерфейса, автоматически выставляется readonly = 1. То есть, для запросов, модифицирующие данные, можно использовать только метод POST. Сам запрос при этом можно отправлять как в теле POST-а, так и в параметре URL. + + ## max_memory_usage -Максимальное количество потребляемой памяти при выполнении запроса на одном сервере. По умолчанию - 10 GB. +Максимальный возможный объем оперативной памяти для выполнения запроса на одном сервере. + +Значения по умолчанию определены в файле [Settings.h](https://github.com/yandex/ClickHouse/blob/master/dbms/src/Interpreters/Settings.h#L243). По умолчанию размер не ограничен (`max_memory_usage = 0`). Настройка не учитывает объём свободной памяти или общий объём памяти на машине. Ограничение действует на один запрос, в пределах одного сервера. -Текущее потребление оперативки для каждого запроса можно посмотреть с помощью SHOW PROCESSLIST. -Также отслеживается пиковое потребление оперативки для каждого запроса, и выводится в лог. +Текущее потребление памяти для каждого запроса можно посмотреть с помощью `SHOW PROCESSLIST`. +Также отслеживается и выводится в лог пиковое потребление памяти для каждого запроса. -Некоторые случаи потребления оперативки не отслеживаются: +Потребление памяти не отслеживается для: -- большие константы (например, очень длинная константная строка); -- состояния некоторых агрегатных функций; +- Констант. +- Состояний некоторых агрегатных функций. -Потребление оперативки не полностью учитывается для состояний агрегатных функций min, max, any, anyLast, argMin, argMax от аргументов String и Array. +Потребление памяти не полностью учитывается для состояний агрегатных функций `min`, `max`, `any`, `anyLast`, `argMin`, `argMax` от аргументов `String` и `Array`. + +Потребление памяти ограничивается также параметрами `max_memory_usage_for_user` и `max_memory_usage_for_all_queries`. + +## max_memory_usage_for_user + +Максимальный возможный объем оперативной памяти для запросов пользователя на одном сервере. + +Значения по умолчанию определены в файле [Settings.h](https://github.com/yandex/ClickHouse/blob/master/dbms/src/Interpreters/Settings.h#L244). По умолчанию размер не ограничен (`max_memory_usage_for_user = 0`). + +Смотрите также описание настройки [max_memory_usage](#settings_max_memory_usage). + +## max_memory_usage_for_all_queries + +Максимальный возможный объем оперативной памяти для всех запросов на одном сервере. + +Значения по умолчанию определены в файле [Settings.h](https://github.com/yandex/ClickHouse/blob/master/dbms/src/Interpreters/Settings.h#L245). По умолчанию размер не ограничен (`max_memory_usage_for_all_queries = 0`). + +Смотрите также описание настройки [max_memory_usage](#settings_max_memory_usage). ## max_rows_to_read From 22794bc93ea1fb0d3c678838391c5b0c3791cecd Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Mon, 12 Mar 2018 20:45:24 +0300 Subject: [PATCH 074/244] ZooKeeper multi op is transparent with chroot prefixes. [#CLICKHOUSE-3639] --- dbms/src/Common/ZooKeeper/Types.h | 13 ++- dbms/src/Common/ZooKeeper/ZooKeeper.cpp | 100 ++++++++++++------ dbms/src/Common/ZooKeeper/ZooKeeper.h | 6 +- .../gtest_zkutil_test_multi_exception.cpp | 12 ++- 4 files changed, 89 insertions(+), 42 deletions(-) diff --git a/dbms/src/Common/ZooKeeper/Types.h b/dbms/src/Common/ZooKeeper/Types.h index 4097627f395..08183f8128d 100644 --- a/dbms/src/Common/ZooKeeper/Types.h +++ b/dbms/src/Common/ZooKeeper/Types.h @@ -12,6 +12,8 @@ namespace zkutil using ACLPtr = const ACL_vector *; using Stat = ::Stat; +class ZooKeeper; + struct Op { @@ -136,10 +138,15 @@ private: int32_t version; }; -struct OpResult : public zoo_op_result_t +/// C++ version of zoo_op_result_t +struct OpResult { - /// Pointers in this class point to fields of class Op. - /// Op instances have the same (or longer lifetime), therefore destructor is not required. + int err; + std::string value; + std::unique_ptr stat; + + /// ZooKeeper is required for correct chroot path prefixes handling + explicit OpResult(const zoo_op_result_t & op_result, const ZooKeeper * zookeeper = nullptr); }; using OpPtr = std::unique_ptr; diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp index 85bbe140d39..105c275e711 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp @@ -82,19 +82,21 @@ void ZooKeeper::processCallback(zhandle_t *, int type, int state, const char * p } void ZooKeeper::init(const std::string & hosts_, const std::string & identity_, - int32_t session_timeout_ms_, bool check_root_exists) + int32_t session_timeout_ms_, const std::string & chroot_) { log = &Logger::get("ZooKeeper"); - zoo_set_debug_level(ZOO_LOG_LEVEL_ERROR); + zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG); hosts = hosts_; identity = identity_; session_timeout_ms = session_timeout_ms_; + chroot = chroot_; - impl = zookeeper_init(hosts.c_str(), nullptr, session_timeout_ms, nullptr, nullptr, 0); + std::string hosts_for_lib = hosts + chroot; + impl = zookeeper_init(hosts_for_lib.c_str(), nullptr, session_timeout_ms, nullptr, nullptr, 0); ProfileEvents::increment(ProfileEvents::ZooKeeperInit); if (!impl) - throw KeeperException("Fail to initialize zookeeper. Hosts are " + hosts); + throw KeeperException("Fail to initialize zookeeper. Hosts are " + hosts_for_lib); if (!identity.empty()) { @@ -107,16 +109,16 @@ void ZooKeeper::init(const std::string & hosts_, const std::string & identity_, else default_acl = &ZOO_OPEN_ACL_UNSAFE; - LOG_TRACE(log, "initialized, hosts: " << hosts); + LOG_TRACE(log, "initialized, hosts: " << hosts << (chroot.empty() ? "" : ", chroot: " + chroot)); - if (check_root_exists && !exists("/")) - throw KeeperException("Zookeeper root doesn't exist. You should create root node before start."); + if (!chroot.empty() && !exists("/")) + throw KeeperException("Zookeeper root doesn't exist. You should create root node " + chroot + " before start."); } ZooKeeper::ZooKeeper(const std::string & hosts, const std::string & identity, - int32_t session_timeout_ms, bool check_root_exists) + int32_t session_timeout_ms, const std::string & chroot) { - init(hosts, identity, session_timeout_ms, check_root_exists); + init(hosts, identity, session_timeout_ms, chroot); } struct ZooKeeperArgs @@ -127,10 +129,8 @@ struct ZooKeeperArgs config.keys(config_name, keys); std::vector hosts_strings; - std::string root; session_timeout_ms = DEFAULT_SESSION_TIMEOUT; - has_chroot = false; for (const auto & key : keys) { if (startsWith(key, "node")) @@ -150,7 +150,7 @@ struct ZooKeeperArgs } else if (key == "root") { - root = config.getString(config_name + "." + key); + chroot = config.getString(config_name + "." + key); } else throw KeeperException(std::string("Unknown key ") + key + " in config file"); } @@ -166,28 +166,25 @@ struct ZooKeeperArgs hosts += host; } - if (!root.empty()) + if (!chroot.empty()) { - if (root.front() != '/') - throw KeeperException(std::string("Root path in config file should start with '/', but got ") + root); - if (root.back() == '/') - root.pop_back(); - - hosts += root; - has_chroot = true; + if (chroot.front() != '/') + throw KeeperException(std::string("Root path in config file should start with '/', but got ") + chroot); + if (chroot.back() == '/') + chroot.pop_back(); } } std::string hosts; std::string identity; int session_timeout_ms; - bool has_chroot; + std::string chroot; }; ZooKeeper::ZooKeeper(const Poco::Util::AbstractConfiguration & config, const std::string & config_name) { ZooKeeperArgs args(config, config_name); - init(args.hosts, args.identity, args.session_timeout_ms, args.has_chroot); + init(args.hosts, args.identity, args.session_timeout_ms, args.chroot); } WatchCallback ZooKeeper::callbackForEvent(const EventPtr & event) @@ -290,19 +287,18 @@ int32_t ZooKeeper::createImpl(const std::string & path, const std::string & data int code; /// The name of the created node can be longer than path if the sequential node is created. size_t name_buffer_size = path.size() + SEQUENTIAL_SUFFIX_SIZE; - char * name_buffer = new char[name_buffer_size]; + std::string name_buffer(name_buffer_size, '\0'); - code = zoo_create(impl, path.c_str(), data.c_str(), data.size(), getDefaultACL(), mode, name_buffer, name_buffer_size); + code = zoo_create(impl, path.c_str(), data.c_str(), data.size(), getDefaultACL(), mode, name_buffer.data(), name_buffer_size); ProfileEvents::increment(ProfileEvents::ZooKeeperCreate); ProfileEvents::increment(ProfileEvents::ZooKeeperTransactions); if (code == ZOK) { - path_created = std::string(name_buffer); + name_buffer.resize(strlen(name_buffer.data())); + path_created = std::move(name_buffer); } - delete[] name_buffer; - return code; } @@ -571,6 +567,18 @@ int32_t ZooKeeper::trySet(const std::string & path, const std::string & data, return code; } + +static void convertOpResults(const std::vector & out_results_native, OpResultsPtr & out_results, + const ZooKeeper * zookeeper = nullptr) +{ + if (!out_results) + out_results = std::make_shared(); + + out_results->reserve(out_results_native.size()); + for (const zoo_op_result_t & res_native : out_results_native) + out_results->emplace_back(res_native, zookeeper); +} + int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_) { if (ops_.empty()) @@ -585,7 +593,7 @@ int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_) return ZINVALIDSTATE; size_t count = ops_.size(); - OpResultsPtr out_results(new OpResults(count)); + std::vector out_results_native(count); /// Copy the struct containing pointers with default copy-constructor. /// It is safe because it hasn't got a destructor. @@ -594,12 +602,12 @@ int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_) for (const auto & op : ops_) ops.push_back(*(op->data)); - int32_t code = zoo_multi(impl, static_cast(ops.size()), ops.data(), out_results->data()); + int32_t code = zoo_multi(impl, static_cast(ops.size()), ops.data(), out_results_native.data()); ProfileEvents::increment(ProfileEvents::ZooKeeperMulti); ProfileEvents::increment(ProfileEvents::ZooKeeperTransactions); if (out_results_) - *out_results_ = out_results; + convertOpResults(out_results_native, *out_results_, this); return code; } @@ -754,7 +762,7 @@ ZooKeeper::~ZooKeeper() ZooKeeperPtr ZooKeeper::startNewSession() const { - return std::make_shared(hosts, identity, session_timeout_ms); + return std::make_shared(hosts, identity, session_timeout_ms, chroot); } Op::Create::Create(const std::string & path_pattern_, const std::string & value_, ACLPtr acl_, int32_t flags_) @@ -982,7 +990,7 @@ ZooKeeper::TryRemoveFuture ZooKeeper::asyncTryRemove(const std::string & path, i ZooKeeper::MultiFuture ZooKeeper::asyncMultiImpl(const zkutil::Ops & ops_, bool throw_exception) { size_t count = ops_.size(); - OpResultsPtr results(new OpResults(count)); + auto results_native = std::make_shared>(count); /// We need to hold all references to ops data until the end of multi callback struct OpsHolder @@ -997,10 +1005,10 @@ ZooKeeper::MultiFuture ZooKeeper::asyncMultiImpl(const zkutil::Ops & ops_, bool holder.ops_raw_ptr->push_back(*holder.ops_ptr->back()->data); } - MultiFuture future{ [throw_exception, results, holder] (int rc) { + MultiFuture future{ [throw_exception, results_native, holder, zookeeper=this] (int rc) { OpResultsAndCode res; res.code = rc; - res.results = results; + convertOpResults(*results_native, res.results, zookeeper); res.ops_ptr = holder.ops_ptr; if (throw_exception && rc != ZOK) throw zkutil::KeeperException(rc); @@ -1020,7 +1028,7 @@ ZooKeeper::MultiFuture ZooKeeper::asyncMultiImpl(const zkutil::Ops & ops_, bool auto & ops = *holder.ops_raw_ptr; - int32_t code = zoo_amulti(impl, static_cast(ops.size()), ops.data(), results->data(), + int32_t code = zoo_amulti(impl, static_cast(ops.size()), ops.data(), results_native->data(), [] (int rc, const void * data) { MultiFuture::TaskPtr owned_task = @@ -1069,4 +1077,26 @@ size_t getFailedOpIndex(const OpResultsPtr & op_results, int32_t transaction_ret } +OpResult::OpResult(const zoo_op_result_t & op_result, const ZooKeeper * zookeeper) + : err(op_result.err) +{ + if (op_result.value) + { + value = std::string(op_result.value, op_result.value + op_result.valuelen); + + /// Current version of libzookeeper does not cut chroot path prefixes + /// We do it here manually + if (zookeeper && !zookeeper->chroot.empty()) + { + if (startsWith(value, zookeeper->chroot)) + value = value.substr(zookeeper->chroot.length()); + else + throw DB::Exception("Expected ZooKeeper path with chroot " + zookeeper->chroot + ", got " + value, + DB::ErrorCodes::LOGICAL_ERROR); + } + } + + if (op_result.stat) + stat = std::make_unique(*op_result.stat); +} } diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.h b/dbms/src/Common/ZooKeeper/ZooKeeper.h index 8d35e37d27f..29b1d2fb69b 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.h +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.h @@ -56,7 +56,7 @@ public: using Ptr = std::shared_ptr; ZooKeeper(const std::string & hosts, const std::string & identity = "", - int32_t session_timeout_ms = DEFAULT_SESSION_TIMEOUT, bool check_root_exists = false); + int32_t session_timeout_ms = DEFAULT_SESSION_TIMEOUT, const std::string & chroot = ""); /** Config of the form: @@ -366,9 +366,10 @@ public: private: friend struct WatchContext; friend class EphemeralNodeHolder; + friend class OpResult; void init(const std::string & hosts, const std::string & identity, - int32_t session_timeout_ms, bool check_root_exists); + int32_t session_timeout_ms, const std::string & chroot); void removeChildrenRecursive(const std::string & path); void tryRemoveChildrenRecursive(const std::string & path); @@ -414,6 +415,7 @@ private: std::string hosts; std::string identity; int32_t session_timeout_ms; + std::string chroot; std::mutex mutex; ACLPtr default_acl; diff --git a/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp b/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp index df71feab43e..4d1d05b54e1 100644 --- a/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp +++ b/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp @@ -134,10 +134,13 @@ TEST(zkutil, multi_create_sequential) try { auto zookeeper = std::make_unique("localhost:2181"); + zookeeper->createAncestors("/clickhouse_test/"); + + zookeeper = std::make_unique("localhost:2181", "", zkutil::DEFAULT_SESSION_TIMEOUT, "/clickhouse_test"); auto acl = zookeeper->getDefaultACL(); zkutil::Ops ops; - String base_path = "/clickhouse_test/zkutil/multi_create_sequential"; + String base_path = "/zkutil/multi_create_sequential"; zookeeper->tryRemoveRecursive(base_path); zookeeper->createAncestors(base_path + "/"); @@ -147,6 +150,10 @@ TEST(zkutil, multi_create_sequential) zkutil::OpResult & result = results->at(0); EXPECT_TRUE(result.value != nullptr); + + String path = result.value; + std::cout << path << "\n"; + EXPECT_TRUE(startsWith(result.value, entry_path)); } catch (...) @@ -154,5 +161,6 @@ TEST(zkutil, multi_create_sequential) std::cerr << getCurrentExceptionMessage(false); throw; } - } + + From 8028ba0de98ad8e187fdc05ee042f2b4426c8163 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Tue, 13 Mar 2018 23:36:22 +0300 Subject: [PATCH 075/244] Refactoring of zkutil::ZooKeeper::multi* functions. [#CLICKHOUSE-2] --- dbms/src/Common/ZooKeeper/KeeperException.h | 15 +++ dbms/src/Common/ZooKeeper/Types.h | 50 +++++++--- dbms/src/Common/ZooKeeper/ZooKeeper.cpp | 93 ++++++++++++------- dbms/src/Common/ZooKeeper/ZooKeeper.h | 53 ++--------- .../tests/zkutil_expiration_test.cpp | 4 +- dbms/src/Interpreters/DDLWorker.cpp | 12 +-- dbms/src/Server/ClusterCopier.cpp | 28 +++--- .../MergeTree/AbandonableLockInZooKeeper.h | 59 ++++++------ .../ReplicatedMergeTreeAlterThread.cpp | 4 +- .../ReplicatedMergeTreeBlockOutputStream.cpp | 59 ++++++------ .../ReplicatedMergeTreeCleanupThread.cpp | 4 +- .../MergeTree/ReplicatedMergeTreeQueue.cpp | 10 +- .../ReplicatedMergeTreeRestartingThread.cpp | 4 +- .../Storages/StorageReplicatedMergeTree.cpp | 66 ++++++------- 14 files changed, 247 insertions(+), 214 deletions(-) diff --git a/dbms/src/Common/ZooKeeper/KeeperException.h b/dbms/src/Common/ZooKeeper/KeeperException.h index b6a46930b97..37b0a04b564 100644 --- a/dbms/src/Common/ZooKeeper/KeeperException.h +++ b/dbms/src/Common/ZooKeeper/KeeperException.h @@ -102,4 +102,19 @@ private: }; + +class KeeperMultiException : public KeeperException +{ +public: + MultiTransactionInfo info; + + /// If it is user error throws KeeperMultiException else throws ordinary KeeperException + /// If it is ZOK does nothing + static void check(const MultiTransactionInfo & info); + static void check(int code, const Ops & ops, const OpResultsPtr & op_results); + +protected: + KeeperMultiException(const MultiTransactionInfo & info, size_t failed_op_index); +}; + }; diff --git a/dbms/src/Common/ZooKeeper/Types.h b/dbms/src/Common/ZooKeeper/Types.h index 08183f8128d..1938081bb2e 100644 --- a/dbms/src/Common/ZooKeeper/Types.h +++ b/dbms/src/Common/ZooKeeper/Types.h @@ -21,7 +21,7 @@ public: Op() : data(new zoo_op_t) {} virtual ~Op() {} - virtual std::unique_ptr clone() const = 0; + virtual std::shared_ptr clone() const = 0; virtual std::string getPath() const = 0; @@ -35,6 +35,9 @@ public: struct Check; }; +using OpPtr = std::shared_ptr; + + struct Op::Remove : public Op { Remove(const std::string & path_, int32_t version_) : @@ -43,9 +46,9 @@ struct Op::Remove : public Op zoo_delete_op_init(data.get(), path.c_str(), version); } - std::unique_ptr clone() const override + OpPtr clone() const override { - return std::unique_ptr(new Remove(path, version)); + return std::make_shared(path, version); } std::string getPath() const override { return path; } @@ -61,9 +64,9 @@ struct Op::Create : public Op { Create(const std::string & path_pattern_, const std::string & value_, ACLPtr acl_, int32_t flags_); - std::unique_ptr clone() const override + OpPtr clone() const override { - return std::unique_ptr(new Create(path_pattern, value, acl, flags)); + return std::make_shared(path_pattern, value, acl, flags); } std::string getPathCreated() { return created_path.data(); } @@ -93,9 +96,9 @@ struct Op::SetData : public Op zoo_set_op_init(data.get(), path.c_str(), value.c_str(), value.size(), version, &stat); } - std::unique_ptr clone() const override + OpPtr clone() const override { - return std::unique_ptr(new SetData(path, value, version)); + return std::make_shared(path, value, version); } std::string getPath() const override { return path; } @@ -124,9 +127,9 @@ struct Op::Check : public Op zoo_check_op_init(data.get(), path.c_str(), version); } - std::unique_ptr clone() const override + OpPtr clone() const override { - return std::unique_ptr(new Check(path, version)); + return std::make_shared(path, version); } std::string getPath() const override { return path; } @@ -138,6 +141,9 @@ private: int32_t version; }; +using Ops = std::vector; + + /// C++ version of zoo_op_result_t struct OpResult { @@ -148,13 +154,33 @@ struct OpResult /// ZooKeeper is required for correct chroot path prefixes handling explicit OpResult(const zoo_op_result_t & op_result, const ZooKeeper * zookeeper = nullptr); }; - -using OpPtr = std::unique_ptr; -using Ops = std::vector; using OpResults = std::vector; using OpResultsPtr = std::shared_ptr; using Strings = std::vector; + +/// Simple structure to handle transaction execution results +struct MultiTransactionInfo +{ + Ops ops; + int32_t code = ZOK; + OpResultsPtr op_results; + + MultiTransactionInfo() = default; + + MultiTransactionInfo(int32_t code_, const Ops & ops_, const OpResultsPtr & op_results_) + : ops(ops_), code(code_), op_results(op_results_) {} + + bool empty() const + { + return ops.empty(); + } + + /// Returns failed op if zkutil::isUserError(code) is true + const Op & getFailedOp() const; +}; + + namespace CreateMode { extern const int Persistent; diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp index 105c275e711..8d3866a0008 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp @@ -85,7 +85,7 @@ void ZooKeeper::init(const std::string & hosts_, const std::string & identity_, int32_t session_timeout_ms_, const std::string & chroot_) { log = &Logger::get("ZooKeeper"); - zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG); + zoo_set_debug_level(ZOO_LOG_LEVEL_ERROR); hosts = hosts_; identity = identity_; session_timeout_ms = session_timeout_ms_; @@ -567,19 +567,19 @@ int32_t ZooKeeper::trySet(const std::string & path, const std::string & data, return code; } - -static void convertOpResults(const std::vector & out_results_native, OpResultsPtr & out_results, +/// Makes deep copy of zoo_op_result_t and removes chroot prefix from paths +static void convertOpResults(const std::vector & op_results_native, OpResultsPtr & out_op_results, const ZooKeeper * zookeeper = nullptr) { - if (!out_results) - out_results = std::make_shared(); + if (!out_op_results) + out_op_results = std::make_shared(); - out_results->reserve(out_results_native.size()); - for (const zoo_op_result_t & res_native : out_results_native) - out_results->emplace_back(res_native, zookeeper); + out_op_results->reserve(op_results_native.size()); + for (const zoo_op_result_t & res_native : op_results_native) + out_op_results->emplace_back(res_native, zookeeper); } -int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_) +int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_op_results, MultiTransactionInfo * out_info) { if (ops_.empty()) return ZOK; @@ -606,30 +606,27 @@ int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_) ProfileEvents::increment(ProfileEvents::ZooKeeperMulti); ProfileEvents::increment(ProfileEvents::ZooKeeperTransactions); - if (out_results_) - convertOpResults(out_results_native, *out_results_, this); + if (out_op_results || out_info) + { + OpResultsPtr op_results; + convertOpResults(out_results_native, op_results, this); + + if (out_op_results) + *out_op_results = op_results; + + if (out_info) + *out_info = MultiTransactionInfo(code, ops_, op_results); + } return code; } OpResultsPtr ZooKeeper::multi(const Ops & ops) { - OpResultsPtr results; - int code = tryMulti(ops, &results); - if (code != ZOK) - { - if (results && results->size() == ops.size()) - { - for (size_t i = 0; i < ops.size(); ++i) - { - if (results->at(i).err == code) - throw KeeperException("Transaction failed at op #" + std::to_string(i) + ": " + ops[i]->describe(), code); - } - } - - throw KeeperException(code); - } - return results; + OpResultsPtr op_results; + int code = multiImpl(ops, &op_results); + KeeperMultiException::check(code, ops, op_results); + return op_results; } int32_t ZooKeeper::tryMulti(const Ops & ops_, OpResultsPtr * out_results_) @@ -646,17 +643,9 @@ int32_t ZooKeeper::tryMulti(const Ops & ops_, OpResultsPtr * out_results_) return code; } -int32_t ZooKeeper::tryMultiUnsafe(const Ops & ops, MultiTransactionInfo & info) -{ - info.code = multiImpl(ops, &info.op_results); - for (const OpPtr & op : ops) - info.ops.emplace_back(op->clone()); - return info.code; -} - int32_t ZooKeeper::tryMultiWithRetries(const Ops & ops, OpResultsPtr * out_results, size_t * attempt) { - int32_t code = retry(std::bind(&ZooKeeper::multiImpl, this, std::ref(ops), out_results), attempt); + int32_t code = retry(std::bind(&ZooKeeper::multiImpl, this, std::ref(ops), out_results, nullptr), attempt); if (!(code == ZOK || code == ZNONODE || code == ZNODEEXISTS || @@ -1099,4 +1088,36 @@ OpResult::OpResult(const zoo_op_result_t & op_result, const ZooKeeper * zookeepe if (op_result.stat) stat = std::make_unique(*op_result.stat); } + + +KeeperMultiException::KeeperMultiException(const MultiTransactionInfo & info_, size_t failed_op_index_) + :KeeperException( + "Transaction failed at op #" + std::to_string(failed_op_index_) + ": " + info_.ops.at(failed_op_index_)->describe(), + info_.code), + info(info_) {} + +void KeeperMultiException::check(int code, const Ops & ops, const OpResultsPtr & op_results) +{ + if (code == ZOK) {} + else if (zkutil::isUserError(code)) + throw KeeperMultiException(MultiTransactionInfo(code, ops, op_results), getFailedOpIndex(op_results, code)); + else + throw KeeperException(code); +} + +void KeeperMultiException::check(const MultiTransactionInfo & info) +{ + if (info.code == ZOK) {} + else if (zkutil::isUserError(info.code)) + throw KeeperMultiException(info, getFailedOpIndex(info.op_results, info.code)); + else + throw KeeperException(info.code); +} + + +const Op & MultiTransactionInfo::getFailedOp() const +{ + return *ops.at(getFailedOpIndex(op_results, code)); +} + } diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.h b/dbms/src/Common/ZooKeeper/ZooKeeper.h index 29b1d2fb69b..2b0d195fd80 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.h +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.h @@ -196,14 +196,16 @@ public: /// Performs several operations in a transaction. /// Throws on every error. OpResultsPtr multi(const Ops & ops); - /// Throws only if some operation has returned an "unexpected" error /// - an error that would cause the corresponding try- method to throw. int32_t tryMulti(const Ops & ops, OpResultsPtr * out_results = nullptr); - /// Like previous one, but does not throw any ZooKeeper exceptions - int32_t tryMultiUnsafe(const Ops & ops, MultiTransactionInfo & info); /// Use only with read-only operations. int32_t tryMultiWithRetries(const Ops & ops, OpResultsPtr * out_results = nullptr, size_t * attempt = nullptr); + /// Throws nothing, just alias of multiImpl + int32_t tryMultiNoThrow(const Ops & ops, OpResultsPtr * out_op_results = nullptr, MultiTransactionInfo * out_info = nullptr) + { + return multiImpl(ops, out_op_results, out_info); + } Int64 getClientID(); @@ -368,8 +370,8 @@ private: friend class EphemeralNodeHolder; friend class OpResult; - void init(const std::string & hosts, const std::string & identity, - int32_t session_timeout_ms, const std::string & chroot); + void init(const std::string & hosts, const std::string & identity, int32_t session_timeout_ms, const std::string & chroot); + void removeChildrenRecursive(const std::string & path); void tryRemoveChildrenRecursive(const std::string & path); @@ -392,7 +394,7 @@ private: /// If the connection has been lost, wait timeout/3 hoping for connection re-establishment. static const int MAX_SLEEP_TIME = 10; if (code == ZCONNECTIONLOSS) - usleep(std::min(session_timeout_ms * 1000 / 3, MAX_SLEEP_TIME * 1000 * 1000)); + usleep(std::min(session_timeout_ms * 1000u / 3, MAX_SLEEP_TIME * 1000u * 1000u)); LOG_WARNING(log, "Error on attempt " << i << ": " << error2string(code) << ". Retry"); code = operation(); @@ -407,7 +409,7 @@ private: int32_t getImpl(const std::string & path, std::string & res, Stat * stat, WatchCallback watch_callback); int32_t setImpl(const std::string & path, const std::string & data, int32_t version = -1, Stat * stat = nullptr); int32_t getChildrenImpl(const std::string & path, Strings & res, Stat * stat, WatchCallback watch_callback); - int32_t multiImpl(const Ops & ops, OpResultsPtr * out_results = nullptr); + int32_t multiImpl(const Ops & ops, OpResultsPtr * out_op_results = nullptr, MultiTransactionInfo * out_info = nullptr); int32_t existsImpl(const std::string & path, Stat * stat_, WatchCallback watch_callback); MultiFuture asyncMultiImpl(const zkutil::Ops & ops_, bool throw_exception); @@ -495,41 +497,4 @@ private: using EphemeralNodeHolderPtr = EphemeralNodeHolder::Ptr; - -/// Simple structure to handle transaction execution results -struct MultiTransactionInfo -{ - MultiTransactionInfo() = default; - - Ops ops; - int32_t code = ZOK; - OpResultsPtr op_results; - - bool empty() const - { - return ops.empty(); - } - - bool hasFailedOp() const - { - return zkutil::isUserError(code); - } - - const Op & getFailedOp() const - { - return *ops.at(getFailedOpIndex(op_results, code)); - } - - KeeperException getException() const - { - if (hasFailedOp()) - { - size_t i = getFailedOpIndex(op_results, code); - return KeeperException("Transaction failed at op #" + std::to_string(i) + ": " + ops.at(i)->describe(), code); - } - else - return KeeperException(code); - } -}; - } diff --git a/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp b/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp index 2079f7a84da..54648bdad8f 100644 --- a/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp +++ b/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp @@ -34,8 +34,8 @@ int main(int argc, char ** argv) { { zkutil::Ops ops; - ops.emplace_back(std::make_unique("/test/zk_expiration_test", "hello", zk.getDefaultACL(), zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique("/test/zk_expiration_test", -1)); + ops.emplace_back(std::make_shared("/test/zk_expiration_test", "hello", zk.getDefaultACL(), zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared("/test/zk_expiration_test", -1)); zkutil::MultiTransactionInfo info; zk.tryMultiUnsafe(ops, info); diff --git a/dbms/src/Interpreters/DDLWorker.cpp b/dbms/src/Interpreters/DDLWorker.cpp index bc9cac4e206..7deabb7872e 100644 --- a/dbms/src/Interpreters/DDLWorker.cpp +++ b/dbms/src/Interpreters/DDLWorker.cpp @@ -600,8 +600,8 @@ void DDLWorker::processTask(DDLTask & task) /// Delete active flag and create finish flag zkutil::Ops ops; - ops.emplace_back(std::make_unique(active_node_path, -1)); - ops.emplace_back(std::make_unique(finished_node_path, task.execution_status.serializeText(), + ops.emplace_back(std::make_shared(active_node_path, -1)); + ops.emplace_back(std::make_shared(finished_node_path, task.execution_status.serializeText(), zookeeper->getDefaultACL(), zkutil::CreateMode::Persistent)); zookeeper->multi(ops); } @@ -780,8 +780,8 @@ void DDLWorker::cleanupQueue() /// Remove the lock node and its parent atomically zkutil::Ops ops; - ops.emplace_back(std::make_unique(lock_path, -1)); - ops.emplace_back(std::make_unique(node_path, -1)); + ops.emplace_back(std::make_shared(lock_path, -1)); + ops.emplace_back(std::make_shared(node_path, -1)); zookeeper->multi(ops); lock->unlockAssumeLockNodeRemovedManually(); @@ -800,8 +800,8 @@ void DDLWorker::createStatusDirs(const std::string & node_path) { zkutil::Ops ops; auto acl = zookeeper->getDefaultACL(); - ops.emplace_back(std::make_unique(node_path + "/active", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(node_path + "/finished", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(node_path + "/active", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(node_path + "/finished", "", acl, zkutil::CreateMode::Persistent)); int code = zookeeper->tryMulti(ops); if (code != ZOK && code != ZNODEEXISTS) diff --git a/dbms/src/Server/ClusterCopier.cpp b/dbms/src/Server/ClusterCopier.cpp index 3ae6a9ed205..077dc43c5f6 100644 --- a/dbms/src/Server/ClusterCopier.cpp +++ b/dbms/src/Server/ClusterCopier.cpp @@ -355,20 +355,23 @@ struct TaskCluster /// Atomically checks that is_dirty node is not exists, and made the remaining op /// Returns relative number of failed operation in the second field (the passed op has 0 index) -static void checkNoNodeAndCommit( +static zkutil::MultiTransactionInfo checkNoNodeAndCommit( const zkutil::ZooKeeperPtr & zookeeper, const String & checking_node_path, - zkutil::OpPtr && op, - zkutil::MultiTransactionInfo & info) + zkutil::OpPtr && op) { zkutil::Ops ops; - ops.emplace_back(std::make_unique(checking_node_path, "", zookeeper->getDefaultACL(), zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(checking_node_path, -1)); + ops.emplace_back(std::make_shared(checking_node_path, "", zookeeper->getDefaultACL(), zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(checking_node_path, -1)); ops.emplace_back(std::move(op)); - zookeeper->tryMultiUnsafe(ops, info); + zkutil::MultiTransactionInfo info; + zookeeper->tryMultiNoThrow(ops, nullptr, &info); + if (info.code != ZOK && !zkutil::isUserError(info.code)) - throw info.getException(); + throw zkutil::KeeperException(info.code); + + return info; } @@ -1542,10 +1545,8 @@ protected: /// Try start processing, create node about it { String start_state = TaskStateWithOwner::getData(TaskState::Started, host_id); - auto op_create = std::make_unique(current_task_status_path, start_state, acl, zkutil::CreateMode::Persistent); - - zkutil::MultiTransactionInfo info; - checkNoNodeAndCommit(zookeeper, is_dirty_flag_path, std::move(op_create), info); + auto op_create = std::make_shared(current_task_status_path, start_state, acl, zkutil::CreateMode::Persistent); + zkutil::MultiTransactionInfo info = checkNoNodeAndCommit(zookeeper, is_dirty_flag_path, std::move(op_create)); if (info.code != ZOK) { @@ -1683,9 +1684,8 @@ protected: /// Finalize the processing, change state of current partition task (and also check is_dirty flag) { String state_finished = TaskStateWithOwner::getData(TaskState::Finished, host_id); - auto op_set = std::make_unique(current_task_status_path, state_finished, 0); - zkutil::MultiTransactionInfo info; - checkNoNodeAndCommit(zookeeper, is_dirty_flag_path, std::move(op_set), info); + auto op_set = std::make_shared(current_task_status_path, state_finished, 0); + zkutil::MultiTransactionInfo info = checkNoNodeAndCommit(zookeeper, is_dirty_flag_path, std::move(op_set)); if (info.code != ZOK) { diff --git a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h index 96ccd5d4dfc..690217302bf 100644 --- a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h +++ b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h @@ -19,7 +19,7 @@ namespace ErrorCodes * When the destructor is called or the session ends in ZooKeeper, it goes into the ABANDONED state. * (Including when the program is halted). */ -class AbandonableLockInZooKeeper : private boost::noncopyable +class AbandonableLockInZooKeeper : public boost::noncopyable { public: enum State @@ -31,44 +31,52 @@ public: AbandonableLockInZooKeeper( const String & path_prefix_, const String & temp_path, zkutil::ZooKeeper & zookeeper_, zkutil::Ops * precheck_ops = nullptr) - : zookeeper(zookeeper_), path_prefix(path_prefix_) + : zookeeper(&zookeeper_), path_prefix(path_prefix_) { String abandonable_path = temp_path + "/abandonable_lock-"; /// Let's create an secondary ephemeral node. if (!precheck_ops || precheck_ops->empty()) { - holder_path = zookeeper.create(abandonable_path, "", zkutil::CreateMode::EphemeralSequential); + holder_path = zookeeper->create(abandonable_path, "", zkutil::CreateMode::EphemeralSequential); } else { - precheck_ops->emplace_back(std::make_unique( - abandonable_path, "", zookeeper.getDefaultACL(), zkutil::CreateMode::EphemeralSequential)); + precheck_ops->emplace_back(std::make_shared( + abandonable_path, "", zookeeper->getDefaultACL(), zkutil::CreateMode::EphemeralSequential)); - if (zookeeper.tryMultiUnsafe(*precheck_ops, precheck_info) != ZOK) - return; + zkutil::OpResultsPtr op_results = zookeeper->multi(*precheck_ops); - holder_path = precheck_info.op_results->back().value; + holder_path = op_results->back().value; } /// Write the path to the secondary node in the main node. - path = zookeeper.create(path_prefix, holder_path, zkutil::CreateMode::PersistentSequential); + path = zookeeper->create(path_prefix, holder_path, zkutil::CreateMode::PersistentSequential); if (path.size() <= path_prefix.size()) throw Exception("Logical error: name of sequential node is shorter than prefix.", ErrorCodes::LOGICAL_ERROR); } - AbandonableLockInZooKeeper(AbandonableLockInZooKeeper && rhs) - : zookeeper(rhs.zookeeper) + AbandonableLockInZooKeeper() = default; + + AbandonableLockInZooKeeper(AbandonableLockInZooKeeper && rhs) noexcept { - std::swap(path_prefix, rhs.path_prefix); - std::swap(path, rhs.path); - std::swap(holder_path, rhs.holder_path); + *this = std::move(rhs); + } + + AbandonableLockInZooKeeper & operator=(AbandonableLockInZooKeeper && rhs) noexcept + { + zookeeper = rhs.zookeeper; + rhs.zookeeper = nullptr; + path_prefix = std::move(rhs.path_prefix); + path = std::move(rhs.path); + holder_path = std::move(rhs.holder_path); + return *this; } bool isCreated() const { - return !holder_path.empty() && !path.empty(); + return zookeeper && !holder_path.empty() && !path.empty(); } String getPath() const @@ -87,8 +95,8 @@ public: void unlock() { checkCreated(); - zookeeper.remove(path); - zookeeper.remove(holder_path); + zookeeper->remove(path); + zookeeper->remove(holder_path); holder_path = ""; } @@ -96,8 +104,8 @@ public: void getUnlockOps(zkutil::Ops & ops) { checkCreated(); - ops.emplace_back(std::make_unique(path, -1)); - ops.emplace_back(std::make_unique(holder_path, -1)); + ops.emplace_back(std::make_shared(path, -1)); + ops.emplace_back(std::make_shared(holder_path, -1)); } void checkCreated() const @@ -108,13 +116,13 @@ public: ~AbandonableLockInZooKeeper() { - if (holder_path.empty()) + if (!zookeeper || holder_path.empty()) return; try { - zookeeper.tryRemoveEphemeralNodeWithRetries(holder_path); - zookeeper.trySet(path, ""); /// It's not necessary. + zookeeper->tryRemoveEphemeralNodeWithRetries(holder_path); + zookeeper->trySet(path, ""); /// It's not necessary. } catch (...) { @@ -153,15 +161,10 @@ public: } private: - zkutil::ZooKeeper & zookeeper; + zkutil::ZooKeeper * zookeeper = nullptr; String path_prefix; String path; String holder_path; - -public: - /// Contains information about execution of passed precheck ops and block-creation payload - /// TODO: quite ugly interface to handle precheck ops - zkutil::MultiTransactionInfo precheck_info; }; } diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp index 35a2dfcc6b7..72d7cd91e3a 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp @@ -141,9 +141,9 @@ void ReplicatedMergeTreeAlterThread::run() /// Update part metadata in ZooKeeper. zkutil::Ops ops; - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.replica_path + "/parts/" + part->name + "/columns", transaction->getNewColumns().toString(), -1)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.replica_path + "/parts/" + part->name + "/checksums", transaction->getNewChecksums().toString(), -1)); try diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp index e34f0f68b6d..7e8ae99cad2 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp @@ -218,32 +218,35 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo block_id_path = storage.zookeeper_path + "/blocks/" + block_id; /// Lets check for duplicates in advance, to avoid superflous block numbers allocation - deduplication_check_ops.emplace_back(std::make_unique(block_id_path, "", acl, zkutil::CreateMode::Persistent)); - deduplication_check_ops.emplace_back(std::make_unique(block_id_path, -1)); + deduplication_check_ops.emplace_back(std::make_shared(block_id_path, "", acl, zkutil::CreateMode::Persistent)); + deduplication_check_ops.emplace_back(std::make_shared(block_id_path, -1)); deduplication_check_ops_ptr = &deduplication_check_ops; } - /// 2 RTT - AbandonableLockInZooKeeper block_number_lock = storage.allocateBlockNumber(part->info.partition_id, zookeeper, deduplication_check_ops_ptr); - if (!block_number_lock.isCreated()) + AbandonableLockInZooKeeper block_number_lock; + try { - zkutil::MultiTransactionInfo & info = block_number_lock.precheck_info; + /// 2 RTT + block_number_lock = storage.allocateBlockNumber(part->info.partition_id, zookeeper, deduplication_check_ops_ptr); + } + catch (zkutil::KeeperMultiException & e) + { + zkutil::MultiTransactionInfo & info = e.info; - if (!info.empty() && info.code != ZOK) + if (deduplicate_block && info.code == ZNODEEXISTS && info.getFailedOp().getPath() == block_id_path) { - if (deduplicate_block && info.code == ZNODEEXISTS && info.getFailedOp().getPath() == block_id_path) - { - LOG_INFO(log, "Block with ID " << block_id << " already exists; ignoring it (skip the insertion)"); - part->is_duplicate = true; - last_block_is_duplicate = true; - ProfileEvents::increment(ProfileEvents::DuplicatedInsertedBlocks); - return; - } - - throw Exception("Cannot allocate block number in ZooKeeper: " + info.getException().displayText(), ErrorCodes::KEEPER_EXCEPTION); + LOG_INFO(log, "Block with ID " << block_id << " already exists; ignoring it (skip the insertion)"); + part->is_duplicate = true; + last_block_is_duplicate = true; + ProfileEvents::increment(ProfileEvents::DuplicatedInsertedBlocks); + return; } - throw Exception("Cannot allocate block number in ZooKeeper", ErrorCodes::KEEPER_EXCEPTION); + throw Exception("Cannot allocate block number in ZooKeeper: " + e.displayText(), ErrorCodes::KEEPER_EXCEPTION); + } + catch (zkutil::KeeperException & e) + { + throw Exception("Cannot allocate block number in ZooKeeper: " + e.displayText(), ErrorCodes::KEEPER_EXCEPTION); } Int64 block_number = block_number_lock.getNumber(); @@ -279,7 +282,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo { /// Make final duplicate check and commit block_id ops.emplace_back( - std::make_unique( + std::make_shared( block_id_path, toString(block_number), /// We will able to know original part number for duplicate blocks, if we want. acl, @@ -288,27 +291,27 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo /// Information about the part, in the replica data. - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.zookeeper_path + "/columns", storage.columns_version)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.replica_path + "/parts/" + part->name, "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.replica_path + "/parts/" + part->name + "/columns", part->columns.toString(), acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.replica_path + "/parts/" + part->name + "/checksums", part->checksums.toString(), acl, zkutil::CreateMode::Persistent)); /// Replication log. - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( storage.zookeeper_path + "/log/log-", log_entry.toString(), acl, @@ -336,7 +339,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo */ ops.emplace_back( - std::make_unique( + std::make_shared( quorum_info.status_path, quorum_entry.toString(), acl, @@ -344,7 +347,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo /// Make sure that during the insertion time, the replica was not reinitialized or disabled (when the server is finished). ops.emplace_back( - std::make_unique( + std::make_shared( storage.replica_path + "/is_active", quorum_info.is_active_node_version)); @@ -352,7 +355,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo /// But then the `host` value will change. We will check this. /// It's great that these two nodes change in the same transaction (see MergeTreeRestartingThread). ops.emplace_back( - std::make_unique( + std::make_shared( storage.replica_path + "/host", quorum_info.host_node_version)); } @@ -361,7 +364,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo storage.data.renameTempPartAndAdd(part, nullptr, &transaction); zkutil::MultiTransactionInfo info; - zookeeper->tryMultiUnsafe(ops, info); /// 1 RTT + zookeeper->tryMultiNoThrow(ops, nullptr, &info); /// 1 RTT if (info.code == ZOK) { diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeCleanupThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeCleanupThread.cpp index ecd201ef765..0352374fd0f 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeCleanupThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeCleanupThread.cpp @@ -98,12 +98,12 @@ void ReplicatedMergeTreeCleanupThread::clearOldLogs() zkutil::Ops ops; for (size_t i = 0; i < entries.size(); ++i) { - ops.emplace_back(std::make_unique(storage.zookeeper_path + "/log/" + entries[i], -1)); + ops.emplace_back(std::make_shared(storage.zookeeper_path + "/log/" + entries[i], -1)); if (ops.size() > 4 * zkutil::MULTI_BATCH_SIZE || i + 1 == entries.size()) { /// Simultaneously with clearing the log, we check to see if replica was added since we received replicas list. - ops.emplace_back(std::make_unique(storage.zookeeper_path + "/replicas", stat.version)); + ops.emplace_back(std::make_shared(storage.zookeeper_path + "/replicas", stat.version)); zookeeper->multi(ops); ops.clear(); } diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp index b2fe028f5d7..c5d4a41d496 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp @@ -164,11 +164,11 @@ void ReplicatedMergeTreeQueue::updateTimesInZooKeeper( zkutil::Ops ops; if (min_unprocessed_insert_time_changed) - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/min_unprocessed_insert_time", toString(*min_unprocessed_insert_time_changed), -1)); if (max_processed_insert_time_changed) - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/max_processed_insert_time", toString(*max_processed_insert_time_changed), -1)); if (!ops.empty()) @@ -334,7 +334,7 @@ bool ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, z zkutil::ZooKeeper::ValueAndStat res = future.second.get(); copied_entries.emplace_back(LogEntry::parse(res.value, res.stat)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/queue/queue-", res.value, zookeeper->getDefaultACL(), zkutil::CreateMode::PersistentSequential)); const auto & entry = *copied_entries.back(); @@ -349,11 +349,11 @@ bool ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, z } } - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/log_pointer", toString(last_entry_index + 1), -1)); if (min_unprocessed_insert_time_changed) - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/min_unprocessed_insert_time", toString(*min_unprocessed_insert_time_changed), -1)); try diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp index 64e4c31e4a8..f6686c273ce 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp @@ -322,9 +322,9 @@ void ReplicatedMergeTreeRestartingThread::activateReplica() /// Simultaneously declare that this replica is active, and update the host. zkutil::Ops ops; - ops.emplace_back(std::make_unique(is_active_path, + ops.emplace_back(std::make_shared(is_active_path, active_node_identifier, zookeeper->getDefaultACL(), zkutil::CreateMode::Ephemeral)); - ops.emplace_back(std::make_unique(storage.replica_path + "/host", address.toString(), -1)); + ops.emplace_back(std::make_shared(storage.replica_path + "/host", address.toString(), -1)); try { diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index d619f37d696..ebdc5320ddf 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -480,25 +480,25 @@ void StorageReplicatedMergeTree::createTableIfNotExists() auto acl = zookeeper->getDefaultACL(); zkutil::Ops ops; - ops.emplace_back(std::make_unique(zookeeper_path, "", + ops.emplace_back(std::make_shared(zookeeper_path, "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/metadata", metadata, + ops.emplace_back(std::make_shared(zookeeper_path + "/metadata", metadata, acl, zkutil::CreateMode::Persistent)); ops.emplace_back(std::make_unique(zookeeper_path + "/columns", getColumns().toString(), acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/log", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/log", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/blocks", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/blocks", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/block_numbers", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/block_numbers", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/nonincrement_block_numbers", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/nonincrement_block_numbers", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/leader_election", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/leader_election", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/temp", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/temp", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(zookeeper_path + "/replicas", "", + ops.emplace_back(std::make_shared(zookeeper_path + "/replicas", "", acl, zkutil::CreateMode::Persistent)); auto code = zookeeper->tryMulti(ops); @@ -573,12 +573,12 @@ void StorageReplicatedMergeTree::createReplica() /// Create an empty replica. We'll create `columns` node at the end - we'll use it as a sign that replica creation is complete. auto acl = zookeeper->getDefaultACL(); zkutil::Ops ops; - ops.emplace_back(std::make_unique(replica_path, "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(replica_path + "/host", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(replica_path + "/log_pointer", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(replica_path + "/queue", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(replica_path + "/parts", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique(replica_path + "/flags", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(replica_path, "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(replica_path + "/host", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(replica_path + "/log_pointer", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(replica_path + "/queue", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(replica_path + "/parts", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(std::make_shared(replica_path + "/flags", "", acl, zkutil::CreateMode::Persistent)); try { @@ -866,7 +866,7 @@ void StorageReplicatedMergeTree::checkParts(bool skip_sanity_checks) /// We assume that this occurs before the queue is loaded (queue.initialize). zkutil::Ops ops; removePartFromZooKeeper(name, ops); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/queue/queue-", log_entry.toString(), zookeeper->getDefaultACL(), zkutil::CreateMode::PersistentSequential)); zookeeper->multi(ops); } @@ -931,20 +931,20 @@ void StorageReplicatedMergeTree::checkPartAndAddToZooKeeper( auto acl = zookeeper->getDefaultACL(); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( zookeeper_path + "/columns", expected_columns_version)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/parts/" + part_name, "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/parts/" + part_name + "/columns", part->columns.toString(), acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/parts/" + part_name + "/checksums", part->checksums.toString(), acl, @@ -1307,7 +1307,7 @@ bool StorageReplicatedMergeTree::executeFetch(const StorageReplicatedMergeTree:: Stat stat; String path = zookeeper_path + "/replicas/" + replicas[i] + "/host"; zookeeper->get(path, &stat); - ops.emplace_back(std::make_unique(path, stat.version)); + ops.emplace_back(std::make_shared(path, stat.version)); } /// We verify that while we were collecting versions, the replica with the necessary part did not come alive. @@ -1326,7 +1326,7 @@ bool StorageReplicatedMergeTree::executeFetch(const StorageReplicatedMergeTree:: if (quorum_entry.part_name == entry.new_part_name) { - ops.emplace_back(std::make_unique(quorum_path, quorum_stat.version)); + ops.emplace_back(std::make_shared(quorum_path, quorum_stat.version)); auto part_info = MergeTreePartInfo::fromPartName(entry.new_part_name, data.format_version); @@ -1338,13 +1338,13 @@ bool StorageReplicatedMergeTree::executeFetch(const StorageReplicatedMergeTree:: auto acl = zookeeper->getDefaultACL(); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( zookeeper_path + "/nonincrement_block_numbers/" + part_info.partition_id + "/block-" + padIndex(part_info.min_block), "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( zookeeper_path + "/quorum/failed_parts/" + entry.new_part_name, "", acl, @@ -1352,7 +1352,7 @@ bool StorageReplicatedMergeTree::executeFetch(const StorageReplicatedMergeTree:: /// Deleting from `blocks`. if (!entry.block_id.empty() && zookeeper->exists(zookeeper_path + "/blocks/" + entry.block_id)) - ops.emplace_back(std::make_unique(zookeeper_path + "/blocks/" + entry.block_id, -1)); + ops.emplace_back(std::make_shared(zookeeper_path + "/blocks/" + entry.block_id, -1)); auto code = zookeeper->tryMulti(ops); @@ -1525,9 +1525,9 @@ void StorageReplicatedMergeTree::executeClearColumnInPartition(const LogEntry & /// Update part metadata in ZooKeeper. zkutil::Ops ops; - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/parts/" + part->name + "/columns", transaction->getNewColumns().toString(), -1)); - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/parts/" + part->name + "/checksums", transaction->getNewChecksums().toString(), -1)); zookeeper->multi(ops); @@ -1970,9 +1970,9 @@ void StorageReplicatedMergeTree::removePartFromZooKeeper(const String & part_nam { String part_path = replica_path + "/parts/" + part_name; - ops.emplace_back(std::make_unique(part_path + "/checksums", -1)); - ops.emplace_back(std::make_unique(part_path + "/columns", -1)); - ops.emplace_back(std::make_unique(part_path, -1)); + ops.emplace_back(std::make_shared(part_path + "/checksums", -1)); + ops.emplace_back(std::make_shared(part_path + "/columns", -1)); + ops.emplace_back(std::make_shared(part_path, -1)); } @@ -1989,7 +1989,7 @@ void StorageReplicatedMergeTree::removePartAndEnqueueFetch(const String & part_n log_entry->new_part_name = part_name; zkutil::Ops ops; - ops.emplace_back(std::make_unique( + ops.emplace_back(std::make_shared( replica_path + "/queue/queue-", log_entry->toString(), zookeeper->getDefaultACL(), zkutil::CreateMode::PersistentSequential)); @@ -2139,8 +2139,8 @@ void StorageReplicatedMergeTree::updateQuorum(const String & part_name) /// The quorum is reached. Delete the node, and update information about the last part that was successfully written with quorum. zkutil::Ops ops; - ops.emplace_back(std::make_unique(quorum_status_path, stat.version)); - ops.emplace_back(std::make_unique(quorum_last_part_path, part_name, -1)); + ops.emplace_back(std::make_shared(quorum_status_path, stat.version)); + ops.emplace_back(std::make_shared(quorum_last_part_path, part_name, -1)); auto code = zookeeper->tryMulti(ops); if (code == ZOK) From f38dc334d68147a1b5981476930e4221996abace Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 16:19:30 +0300 Subject: [PATCH 076/244] Refactor of asyncMulti. [#CLICKHOUSE-2] --- dbms/src/Common/ZooKeeper/ZooKeeper.cpp | 31 ++++---- .../gtest_zkutil_test_multi_exception.cpp | 77 ++++++++++++------- 2 files changed, 64 insertions(+), 44 deletions(-) diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp index 8d3866a0008..746ed4c609a 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp @@ -978,26 +978,27 @@ ZooKeeper::TryRemoveFuture ZooKeeper::asyncTryRemove(const std::string & path, i ZooKeeper::MultiFuture ZooKeeper::asyncMultiImpl(const zkutil::Ops & ops_, bool throw_exception) { - size_t count = ops_.size(); - auto results_native = std::make_shared>(count); - /// We need to hold all references to ops data until the end of multi callback struct OpsHolder { - std::shared_ptr ops_ptr = std::make_shared(); - std::shared_ptr> ops_raw_ptr = std::make_shared>(); + std::shared_ptr ops_ptr; + std::shared_ptr> ops_native; + std::shared_ptr> op_results_native; } holder; - for (const auto & op : ops_) - { - holder.ops_ptr->emplace_back(op->clone()); - holder.ops_raw_ptr->push_back(*holder.ops_ptr->back()->data); - } + /// Copy ops (swallow copy) + holder.ops_ptr = std::make_shared(ops_); + /// Copy native ops to contiguous vector + holder.ops_native = std::make_shared>(); + for (const OpPtr & op : *holder.ops_ptr) + holder.ops_native->push_back(*op->data); + /// Allocate native result holders + holder.op_results_native = std::make_shared>(holder.ops_ptr->size()); - MultiFuture future{ [throw_exception, results_native, holder, zookeeper=this] (int rc) { + MultiFuture future{ [throw_exception, holder, zookeeper=this] (int rc) { OpResultsAndCode res; res.code = rc; - convertOpResults(*results_native, res.results, zookeeper); + convertOpResults(*holder.op_results_native, res.results, zookeeper); res.ops_ptr = holder.ops_ptr; if (throw_exception && rc != ZOK) throw zkutil::KeeperException(rc); @@ -1015,9 +1016,9 @@ ZooKeeper::MultiFuture ZooKeeper::asyncMultiImpl(const zkutil::Ops & ops_, bool if (expired()) throw KeeperException(ZINVALIDSTATE); - auto & ops = *holder.ops_raw_ptr; - - int32_t code = zoo_amulti(impl, static_cast(ops.size()), ops.data(), results_native->data(), + int32_t code = zoo_amulti(impl, static_cast(holder.ops_native->size()), + holder.ops_native->data(), + holder.op_results_native->data(), [] (int rc, const void * data) { MultiFuture::TaskPtr owned_task = diff --git a/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp b/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp index 4d1d05b54e1..695b9949a66 100644 --- a/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp +++ b/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp @@ -6,6 +6,9 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" #include +#include + + #pragma GCC diagnostic pop using namespace DB; @@ -32,32 +35,32 @@ TEST(zkutil, multi_nice_exception_msg) zkutil::Ops ops; ASSERT_NO_THROW( - zookeeper->tryRemoveRecursive("/clickhouse_test_zkutil_multi"); + zookeeper->tryRemoveRecursive("/clickhouse_test/zkutil_multi"); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); zookeeper->multi(ops); ); try { ops.clear(); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/c", "_", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Remove("/clickhouse_test_zkutil_multi/c", -1)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "BadBoy", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/b", "_", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/c", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Remove("/clickhouse_test/zkutil_multi/c", -1)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/a", "BadBoy", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/b", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); zookeeper->multi(ops); FAIL(); } catch (...) { - zookeeper->tryRemoveRecursive("/clickhouse_test_zkutil_multi"); + zookeeper->tryRemoveRecursive("/clickhouse_test/zkutil_multi"); String msg = getCurrentExceptionMessage(false); - bool msg_has_reqired_patterns = msg.find("/clickhouse_test_zkutil_multi/a") != std::string::npos && msg.find("#2") != std::string::npos; + bool msg_has_reqired_patterns = msg.find("/clickhouse_test/zkutil_multi/a") != std::string::npos && msg.find("#2") != std::string::npos; EXPECT_TRUE(msg_has_reqired_patterns) << msg; } } @@ -69,7 +72,7 @@ TEST(zkutil, multi_async) auto acl = zookeeper->getDefaultACL(); zkutil::Ops ops; - zookeeper->tryRemoveRecursive("/clickhouse_test_zkutil_multi"); + zookeeper->tryRemoveRecursive("/clickhouse_test/zkutil_multi"); { ops.clear(); @@ -78,8 +81,8 @@ TEST(zkutil, multi_async) { ops.clear(); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi", "", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi", "", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/a", "", acl, zkutil::CreateMode::Persistent)); auto fut = zookeeper->tryAsyncMulti(ops); ops.clear(); @@ -97,11 +100,11 @@ TEST(zkutil, multi_async) for (size_t i = 0; i < 10000; ++i) { ops.clear(); - ops.emplace_back(new zkutil::Op::Remove("/clickhouse_test_zkutil_multi", -1)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Check("/clickhouse_test_zkutil_multi", -1)); - ops.emplace_back(new zkutil::Op::SetData("/clickhouse_test_zkutil_multi", "xxx", 42)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Remove("/clickhouse_test/zkutil_multi", -1)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Check("/clickhouse_test/zkutil_multi", -1)); + ops.emplace_back(new zkutil::Op::SetData("/clickhouse_test/zkutil_multi", "xxx", 42)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); futures.emplace_back(zookeeper->asyncMulti(ops)); } @@ -115,8 +118,8 @@ TEST(zkutil, multi_async) { ops.clear(); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); - ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test/zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); auto fut = zookeeper->tryAsyncMulti(ops); ops.clear(); @@ -128,11 +131,30 @@ TEST(zkutil, multi_async) } } +/// Run this test under sudo +TEST(zkutil, multi_async_libzookeeper_segfault) +{ + auto zookeeper = std::make_unique("localhost:2181", "", 1000); + zkutil::Ops ops; + + ops.emplace_back(new zkutil::Op::Check("/clickhouse_test/zkutil_multi", 0)); + + /// Uncomment to test + //auto cmd = ShellCommand::execute("sudo service zookeeper restart"); + //cmd->wait(); + + auto future = zookeeper->asyncMulti(ops); + auto res = future.get(); + + EXPECT_TRUE(zkutil::isUnrecoverableErrorCode(res.code)); +} + TEST(zkutil, multi_create_sequential) { try { + /// Create chroot node firstly auto zookeeper = std::make_unique("localhost:2181"); zookeeper->createAncestors("/clickhouse_test/"); @@ -144,17 +166,14 @@ TEST(zkutil, multi_create_sequential) zookeeper->tryRemoveRecursive(base_path); zookeeper->createAncestors(base_path + "/"); - String entry_path = base_path + "/queue-"; - ops.emplace_back(new zkutil::Op::Create(entry_path, "", acl, zkutil::CreateMode::EphemeralSequential)); + String sequential_node_prefix = base_path + "/queue-"; + ops.emplace_back(new zkutil::Op::Create(sequential_node_prefix, "", acl, zkutil::CreateMode::EphemeralSequential)); zkutil::OpResultsPtr results = zookeeper->multi(ops); - zkutil::OpResult & result = results->at(0); + zkutil::OpResult & sequential_node_result_op = results->at(0); - EXPECT_TRUE(result.value != nullptr); - - String path = result.value; - std::cout << path << "\n"; - - EXPECT_TRUE(startsWith(result.value, entry_path)); + EXPECT_FALSE(sequential_node_result_op.value.empty()); + EXPECT_GT(sequential_node_result_op.value.length(), sequential_node_prefix.length()); + EXPECT_EQ(sequential_node_result_op.value.substr(0, sequential_node_prefix.length()), sequential_node_prefix); } catch (...) { From a2560045b39b64e580d5141581b20ed13790468b Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Wed, 14 Mar 2018 16:50:31 +0300 Subject: [PATCH 077/244] Auto version update to [54365] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 4f6d925f969..49bda24e075 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54364-testing) -set(VERSION_REVISION 54364) +set(VERSION_DESCRIBE v1.1.54365-testing) +set(VERSION_REVISION 54365) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 7623f7307d3..8ee6e628a17 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54364) unstable; urgency=low +clickhouse (1.1.54365) unstable; urgency=low * Modified source code - -- Wed, 14 Mar 2018 10:03:38 +0300 + -- Wed, 14 Mar 2018 16:50:31 +0300 From 93a693f84fed485c09c4fde8e61283431f6cbbd3 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Wed, 14 Mar 2018 16:52:35 +0300 Subject: [PATCH 078/244] Data replication topic is actualized. --- docs/mkdocs_ru.yml | 2 +- docs/ru/table_engines/replication.md | 76 +++++++++++++++------------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index bc8b74a3d17..2d2bed6baca 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -84,7 +84,7 @@ pages: - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' - - 'Data replication': 'table_engines/replication.md' + - 'Репликация данных': 'table_engines/replication.md' - 'Distributed': 'table_engines/distributed.md' - 'Dictionary': 'table_engines/dictionary.md' - 'Merge': 'table_engines/merge.md' diff --git a/docs/ru/table_engines/replication.md b/docs/ru/table_engines/replication.md index f76f7644a77..970e431370e 100644 --- a/docs/ru/table_engines/replication.md +++ b/docs/ru/table_engines/replication.md @@ -2,26 +2,28 @@ # Репликация данных -## ReplicatedAggregatingMergeTree +Репликация поддерживается только для таблиц семейства MergeTree: -## ReplicatedCollapsingMergeTree +- ReplicatedAggregatingMergeTree +- ReplicatedCollapsingMergeTree +- ReplicatedGraphiteMergeTree +- ReplicatedMergeTree +- ReplicatedReplacingMergeTree +- ReplicatedSummingMergeTree -## ReplicatedGraphiteMergeTree +Репликация работает на уровне отдельных таблиц, а не всего сервера. То есть, на сервере могут быть расположены одновременно реплицируемые и не реплицируемые таблицы. -## ReplicatedMergeTree +Репликация не зависит от шардирования. На каждом шарде репликация работает независимо. -## ReplicatedReplacingMergeTree +Реплицируются сжатые данные запросов `INSERT`, `ALTER` (см. подробности в описании запроса [ALTER](../query_language/queries.md#query_language_queries_alter)). -## ReplicatedSummingMergeTree +Запросы `CREATE`, `DROP`, `ATTACH`, `DETACH`, `RENAME` выполняются на одном сервере и не реплицируются: -Репликация поддерживается только для таблиц семейства MergeTree. Репликация работает на уровне отдельных таблиц, а не всего сервера. То есть, на сервере могут быть расположены одновременно реплицируемые и не реплицируемые таблицы. +- `CREATE TABLE` создаёт новую реплицируемую таблицу на том сервере, где выполняется запрос, а если на других серверах такая таблица уже есть - добавляет новую реплику. +- `DROP TABLE` удаляет реплику, расположенную на том сервере, где выполняется запрос. +- `RENAME` переименовывает таблицу на одной из реплик - то есть, реплицируемые таблицы на разных репликах могут называться по разному. -Реплицируются INSERT, ALTER (см. подробности в описании запроса ALTER). Реплицируются сжатые данные, а не тексты запросов. -Запросы CREATE, DROP, ATTACH, DETACH, RENAME не реплицируются - то есть, относятся к одному серверу. Запрос CREATE TABLE создаёт новую реплицируемую таблицу на том сервере, где выполняется запрос; а если на других серверах такая таблица уже есть - добавляет новую реплику. Запрос DROP TABLE удаляет реплику, расположенную на том сервере, где выполняется запрос. Запрос RENAME переименовывает таблицу на одной из реплик - то есть, реплицируемые таблицы на разных репликах могут называться по разному. - -Репликация никак не связана с шардированием. На каждом шарде репликация работает независимо. - -Репликация является опциональной возможностью. Для использования репликации, укажите в конфигурационном файле адреса ZooKeeper кластера. Пример: +Чтобы использовать репликацию, укажите в конфигурационном файле адреса ZooKeeper кластера. Пример: ```xml @@ -40,25 +42,25 @@ ``` -**Используйте версию ZooKeeper не старее 3.4.5.** Для примера, в Ubuntu Precise слишком старая версия в пакете. +Используйте ZooKeeper 3.4.5 и больше. Можно указать любой имеющийся у вас ZooKeeper-кластер - система будет использовать в нём одну директорию для своих данных (директория указывается при создании реплицируемой таблицы). Если в конфигурационном файле не настроен ZooKeeper, то вы не сможете создать реплицируемые таблицы, а уже имеющиеся реплицируемые таблицы будут доступны в режиме только на чтение. -При запросах SELECT, ZooKeeper не используется. То есть, репликация никак не влияет на производительность SELECT-ов - запросы работают так же быстро, как и для нереплицируемых таблиц. При запросах к распределенным реплицированным таблицам поведение ClickHouse регулируется настройками [max_replica_delay_for_distributed_queries](../operations/settings/settings.md#settings_settings_max_replica_delay_for_distributed_queries) и [fallback_to_stale_replicas_for_distributed_queries](../operations/settings/settings.md#settings-settings-fallback_to_stale_replicas_for_distributed_queries). +При запросах `SELECT`, ZooKeeper не используется, т.е. репликация не влияет на производительность `SELECT` и запросы работают так же быстро, как и для нереплицируемых таблиц. При запросах к распределенным реплицированным таблицам поведение ClickHouse регулируется настройками [max_replica_delay_for_distributed_queries](../operations/settings/settings.md#settings_settings_max_replica_delay_for_distributed_queries) и [fallback_to_stale_replicas_for_distributed_queries](../operations/settings/settings.md#settings-settings-fallback_to_stale_replicas_for_distributed_queries). -При каждом запросе INSERT (точнее, на каждый вставляемый блок данных; запрос INSERT содержит один блок, или по блоку на каждые max_insert_block_size = 1048576 строк), делается около десятка записей в ZooKeeper в рамках нескольких транзакций. Это приводит к некоторому увеличению задержек при INSERT-е, по сравнению с нереплицируемыми таблицами. Но если придерживаться обычных рекомендаций - вставлять данные пачками не более одного INSERT-а в секунду, то это не составляет проблем. На всём кластере ClickHouse, использующим для координации один кластер ZooKeeper, может быть в совокупности несколько сотен INSERT-ов в секунду. Пропускная способность при вставке данных (количество строчек в секунду) такая же высокая, как для нереплицируемых таблиц. +При каждом запросе `INSERT` (точнее, на каждый вставляемый блок данных; запрос INSERT содержит один блок, или по блоку на каждые `max_insert_block_size = 1048576` строк), делается около десятка записей в ZooKeeper в рамках нескольких транзакций. Это приводит к некоторому увеличению задержек при `INSERT`, по сравнению с нереплицируемыми таблицами. Но если придерживаться обычных рекомендаций - вставлять данные пачками не более одного `INSERT` в секунду, то это не составляет проблем. На всём кластере ClickHouse, использующим для координации один кластер ZooKeeper, может быть в совокупности несколько сотен `INSERT` в секунду. Пропускная способность при вставке данных (количество строчек в секунду) такая же высокая, как для нереплицируемых таблиц. Для очень больших кластеров, можно использовать разные кластеры ZooKeeper для разных шардов. Впрочем, на кластере Яндекс.Метрики (примерно 300 серверов) такой необходимости не возникает. -Репликация асинхронная, мульти-мастер. Запросы INSERT (а также ALTER) можно отправлять на любой доступный сервер. Данные вставятся на этот сервер, а затем приедут на остальные серверы. В связи с асинхронностью, только что вставленные данные, появляются на остальных репликах с небольшой задержкой. Если часть реплик недоступна - данные на них запишутся тогда, когда они станут доступны. Если реплика доступна, то задержка составляет столько времени, сколько требуется для передачи блока сжатых данных по сети. +Репликация асинхронная, мульти-мастер. Запросы `INSERT` (а также `ALTER`) можно отправлять на любой доступный сервер. Данные вставятся на сервер, где выполнен запрос, а затем скопируются на остальные серверы. В связи с асинхронностью, только что вставленные данные появляются на остальных репликах с небольшой задержкой. Если часть реплик недоступна, данные на них запишутся тогда, когда они станут доступны. Если реплика доступна, то задержка составляет столько времени, сколько требуется для передачи блока сжатых данных по сети. -Кворумная запись отсутствует. То есть, вы не можете записать данные с подтверждением их получения более одной репликой. Если вы записали пачку данных на одну реплику, и данные ещё не успели разъехаться по остальным репликам, после чего сервер с этими данными перестал существовать, то эта пачка данных будет потеряна. +Кворумная запись отсутствует. Вы можете записать данные с подтвержением только от одной реплики. Если вы записали данные на одну реплику, а сервер с этой репликой перестал существовать, то записанные данные будут потеряны, если репликация еще не завершилась. -Каждый блок данных записывается атомарно. Запрос INSERT разбивается на блоки данных размером до max_insert_block_size = 1048576 строк. То есть, если в запросе INSERT менее 1048576 строк, то он делается атомарно. +Каждый блок данных записывается атомарно. Запрос INSERT разбивается на блоки данных размером до `max_insert_block_size = 1048576` строк. То есть, если в запросе `INSERT` менее 1048576 строк, то он делается атомарно. -Блоки данных дедуплицируются. При многократной записи одного и того же блока данных (блоков данных одинакового размера, содержащих одни и те же строчки в одном и том же порядке), блок будет записан только один раз. Это сделано для того, чтобы в случае сбоя в сети, когда клиентское приложение не может понять, были ли данные записаны в БД, можно было просто повторить запрос INSERT. При этом не имеет значения, на какую реплику будут отправлены INSERT-ы с одинаковыми данными. То есть, обеспечивается идемпотентность INSERT-ов. Это работает только для последних 100 вставленных в таблицу блоков. +Блоки данных дедуплицируются. При многократной записи одного и того же блока данных (блоков данных одинакового размера, содержащих одни и те же строчки в одном и том же порядке), блок будет записан только один раз. Это сделано для того, чтобы в случае сбоя в сети, когда клиентское приложение не может понять, были ли данные записаны в БД, можно было просто повторить запрос `INSERT`. При этом не имеет значения, на какую реплику будут отправлены INSERT-ы с одинаковыми данными. То есть, обеспечивается идемпотентность `INSERT`. Параметры дедупликации регулируются настройками сервера [merge_tree](../operations/server_settings/settings.md#server_settings-merge_tree). При репликации, по сети передаются только исходные вставляемые данные. Дальнейшие преобразования данных (слияния) координируются и делаются на всех репликах одинаковым образом. За счёт этого минимизируется использование сети, и благодаря этому, репликация хорошо работает при расположении реплик в разных датацентрах. (Стоит заметить, что дублирование данных в разных датацентрах, по сути, является основной задачей репликации). @@ -101,19 +103,21 @@ ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/hits', '{replica}', Even Имя реплики - то, что идентифицирует разные реплики одной и той же таблицы. Можно использовать для него имя сервера, как показано в примере. Впрочем, достаточно, чтобы имя было уникально лишь в пределах каждого шарда. -Можно не использовать подстановки, а прописать всё явно. Это может быть удобным для тестирования и при настройке маленьких кластеров, но менее удобным при работе с большими кластерами. +Можно не использовать подстановки, а указать соответствующие параметры явно. Это может быть удобным для тестирования и при настройке маленьких кластеров. Однако в этом случае нельзя пользоваться распределенными DDL-запросами (`ON CLUSTER`). -Выполните запрос CREATE TABLE на каждой реплике. Запрос создаёт новую реплицируемую таблицу, или добавляет новую реплику к имеющимся. +При работе с большими кластерами мы рекомендуем использовать подстановки, они уменьшают вероятность ошибки. + +Выполните запрос `CREATE TABLE` на каждой реплике. Запрос создаёт новую реплицируемую таблицу, или добавляет новую реплику к имеющимся. Если вы добавляете новую реплику после того, как таблица на других репликах уже содержит некоторые данные, то после выполнения запроса, данные на новую реплику будут скачаны с других реплик. То есть, новая реплика синхронизирует себя с остальными. -Для удаления реплики, выполните запрос DROP TABLE. При этом, удаляется только одна реплика - расположенная на том сервере, где вы выполняете запрос. +Для удаления реплики, выполните запрос `DROP TABLE`. При этом, удаляется только одна реплика - расположенная на том сервере, где вы выполняете запрос. ## Восстановление после сбоя Если при старте сервера, недоступен ZooKeeper, реплицируемые таблицы переходят в режим только для чтения. Система будет пытаться периодически установить соединение с ZooKeeper. -Если при INSERT-е недоступен ZooKeeper, или происходит ошибка при взаимодействии с ним, будет выкинуто исключение. +Если при `INSERT` недоступен ZooKeeper, или происходит ошибка при взаимодействии с ним, будет выкинуто исключение. При подключении к ZooKeeper, система проверяет соответствие между имеющимся в локальной файловой системе набором данных и ожидаемым набором данных (информация о котором хранится в ZooKeeper). Если имеются небольшие несоответствия, то система устраняет их, синхронизируя данные с реплик. @@ -121,7 +125,7 @@ ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/hits', '{replica}', Even Стоит заметить, что ClickHouse не делает самостоятельно никаких деструктивных действий типа автоматического удаления большого количества данных. -При старте сервера (или создании новой сессии с ZooKeeper), проверяется только количество и размеры всех файлов. Если у файлов совпадают размеры, но изменены байты где-то посередине, то это обнаруживается не сразу, а только при попытке их прочитать при каком-либо запросе SELECT - запрос кинет исключение о несоответствующей чексумме или размере сжатого блока. В этом случае, куски данных добавляются в очередь на проверку, и при необходимости, скачиваются с реплик. +При старте сервера (или создании новой сессии с ZooKeeper), проверяется только количество и размеры всех файлов. Если у файлов совпадают размеры, но изменены байты где-то посередине, то это обнаруживается не сразу, а только при попытке их прочитать при каком-либо запросе `SELECT` - запрос кинет исключение о несоответствующей чексумме или размере сжатого блока. В этом случае, куски данных добавляются в очередь на проверку, и при необходимости, скачиваются с реплик. Если обнаруживается, что локальный набор данных слишком сильно отличается от ожидаемого, то срабатывает защитный механизм - сервер сообщает об этом в лог и отказывается запускаться. Это сделано, так как такой случай может свидетельствовать об ошибке конфигурации - например, если реплика одного шарда была случайно сконфигурирована, как реплика другого шарда. Тем не менее, пороги защитного механизма поставлены довольно низкими, и такая ситуация может возникнуть и при обычном восстановлении после сбоя. В этом случае, восстановление делается полуавтоматически - "по кнопке". @@ -138,13 +142,13 @@ sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data Если на одном из серверов исчезли все данные и метаданные, восстановление делается следующим образом: 1. Установите на сервер ClickHouse. Корректно пропишите подстановки в конфигурационном файле, отвечающие за идентификатор шарда и реплики, если вы их используете. -2. Если у вас были нереплицируемые таблицы, которые должны быть вручную продублированы на серверах, скопируйте их данные (в директории /var/lib/clickhouse/data/db_name/table_name/) с реплики. -3. Скопируйте с реплики определения таблиц, находящиеся в /var/lib/clickhouse/metadata/. Если в определениях таблиц, идентификатор шарда или реплики, прописаны в явном виде - исправьте их, чтобы они соответствовали данной реплике. (Альтернативный вариант - запустить сервер и сделать самостоятельно все запросы ATTACH TABLE, которые должны были бы быть в соответствующих .sql файлах в /var/lib/clickhouse/metadata/.) -4. Создайте в ZooKeeper узел /path_to_table/replica_name/flags/force_restore_data с любым содержимым или выполните команду для восстановления всех реплицируемых таблиц: `sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data` +2. Если у вас были нереплицируемые таблицы, которые должны быть вручную продублированы на серверах, скопируйте их данные (в директории `/var/lib/clickhouse/data/db_name/table_name/`) с реплики. +3. Скопируйте с реплики определения таблиц, находящиеся в `/var/lib/clickhouse/metadata/`. Если в определениях таблиц, идентификатор шарда или реплики, прописаны в явном виде - исправьте их, чтобы они соответствовали данной реплике. (Альтернативный вариант - запустить сервер и сделать самостоятельно все запросы `ATTACH TABLE`, которые должны были бы быть в соответствующих .sql файлах в `/var/lib/clickhouse/metadata/`.) +4. Создайте в ZooKeeper узел `/path_to_table/replica_name/flags/force_restore_data` с любым содержимым или выполните команду для восстановления всех реплицируемых таблиц: `sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data` Затем запустите сервер (перезапустите, если уже запущен). Данные будут скачаны с реплик. -В качестве альтернативного варианта восстановления, вы можете удалить из ZooKeeper информацию о потерянной реплике - `/path_to_table/replica_name`, и затем создать реплику заново, как написано в разделе "Создание реплицируемых таблиц". +В качестве альтернативного варианта восстановления, вы можете удалить из ZooKeeper информацию о потерянной реплике - `/path_to_table/replica_name`, и затем создать реплику заново, как написано в разделе "[Создание реплицируемых таблиц](#table_engines-replication-creation_of_rep_tables)". Отсутствует ограничение на использование сетевой полосы при восстановлении. Имейте это ввиду, если восстанавливаете сразу много реплик. @@ -152,24 +156,24 @@ sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data Здесь и далее, под `MergeTree` подразумеваются все движки таблиц семейства `MergeTree`, так же для `ReplicatedMergeTree`. -Если у вас была таблица типа MergeTree, репликация которой делалась вручную, вы можете преобразовать её в реплицируемую таблицу. Это может понадобиться лишь в случаях, когда вы уже успели накопить большое количество данных в таблице типа MergeTree, а сейчас хотите включить репликацию. +Если у вас была таблица типа `MergeTree`, репликация которой делалась вручную, вы можете преобразовать её в реплицируемую таблицу. Это может понадобиться лишь в случаях, когда вы уже успели накопить большое количество данных в таблице типа `MergeTree`, а сейчас хотите включить репликацию. Если на разных репликах данные отличаются, то сначала синхронизируйте их, либо удалите эти данные на всех репликах кроме одной. -Переименуйте имеющуюся MergeTree таблицу, затем создайте со старым именем таблицу типа ReplicatedMergeTree. +Переименуйте имеющуюся MergeTree таблицу, затем создайте со старым именем таблицу типа `ReplicatedMergeTree`. Перенесите данные из старой таблицы в поддиректорию detached в директории с данными новой таблицы (`/var/lib/clickhouse/data/db_name/table_name/`). -Затем добавьте эти куски данных в рабочий набор с помощью выполнения запросов ALTER TABLE ATTACH PARTITION на одной из реплик. +Затем добавьте эти куски данных в рабочий набор с помощью выполнения запросов `ALTER TABLE ATTACH PARTITION` на одной из реплик. ## Преобразование из ReplicatedMergeTree в MergeTree -Создайте таблицу типа MergeTree с другим именем. Перенесите в её директорию с данными все данные из директории с данными таблицы типа ReplicatedMergeTree. Затем удалите таблицу типа ReplicatedMergeTree и перезапустите сервер. +Создайте таблицу типа MergeTree с другим именем. Перенесите в её директорию с данными все данные из директории с данными таблицы типа `ReplicatedMergeTree`. Затем удалите таблицу типа `ReplicatedMergeTree` и перезапустите сервер. -Если вы хотите избавиться от таблицы ReplicatedMergeTree, не запуская сервер, то +Если вы хотите избавиться от таблицы `ReplicatedMergeTree`, не запуская сервер, то -- удалите соответствующий файл .sql в директории с метаданными (`/var/lib/clickhouse/metadata/`); +- удалите соответствующий файл `.sql` в директории с метаданными (`/var/lib/clickhouse/metadata/`); - удалите соответствующий путь в ZooKeeper (`/path_to_table/replica_name`); -После этого, вы можете запустить сервер, создать таблицу типа MergeTree, перенести данные в её директорию, и перезапустить сервер. +После этого, вы можете запустить сервер, создать таблицу типа `MergeTree`, перенести данные в её директорию, и перезапустить сервер. ## Восстановление в случае потери или повреждения метаданных на ZooKeeper кластере From 56bfb05ebb70fa7fb2c0a54c6876219a49d89984 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 18:57:13 +0300 Subject: [PATCH 079/244] Fix insane DateTime in system.parts. [#CLICKHOUSE-3] --- dbms/src/Storages/MergeTree/MergeTreeDataPart.h | 4 +++- libs/libcommon/include/common/DateLUTImpl.h | 5 ++++- libs/libcommon/src/DateLUTImpl.cpp | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.h b/dbms/src/Storages/MergeTree/MergeTreeDataPart.h index 43ddf7abfdd..cb9a5cf79f1 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.h +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.h @@ -139,7 +139,9 @@ struct MergeTreeDataPart std::atomic size_in_bytes {0}; /// size in bytes, 0 - if not counted; /// is used from several threads without locks (it is changed with ALTER). time_t modification_time = 0; - mutable std::atomic remove_time { std::numeric_limits::max() }; /// When the part is removed from the working set. Changes once. + /// When the part is removed from the working set. Changes once. + /// Use DATE_LUT_MAX which is almost 2^32 to produce correct time_t to String conversions using DateLUT + mutable std::atomic remove_time { DATE_LUT_MAX }; /// If true, the destructor will delete the directory with the part. bool is_temp = false; diff --git a/libs/libcommon/include/common/DateLUTImpl.h b/libs/libcommon/include/common/DateLUTImpl.h index 669f228cb34..754a83d4023 100644 --- a/libs/libcommon/include/common/DateLUTImpl.h +++ b/libs/libcommon/include/common/DateLUTImpl.h @@ -70,6 +70,7 @@ private: std::string time_zone; + /// We can correctly process only timestamps that less DATE_LUT_MAX (i.e. up to 2015 year inclusively) inline size_t findIndex(time_t t) const { /// First guess. @@ -242,8 +243,10 @@ public: { size_t index = findIndex(t); + /// If it is not 1970 year (findIndex found nothing appropriate), + /// than limit number of hours to avoid insane results like 1970-01-01 89:28:15 if (unlikely(index == 0)) - return (t + offset_at_start_of_epoch) / 3600; + return static_cast((t + offset_at_start_of_epoch) / 3600) % 24; time_t res = t - lut[index].date; diff --git a/libs/libcommon/src/DateLUTImpl.cpp b/libs/libcommon/src/DateLUTImpl.cpp index 570b277602c..5b3fc2a295e 100644 --- a/libs/libcommon/src/DateLUTImpl.cpp +++ b/libs/libcommon/src/DateLUTImpl.cpp @@ -64,7 +64,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_) { cctz::time_zone::civil_lookup lookup = cctz_time_zone.lookup(date); - start_of_day = std::chrono::system_clock::to_time_t(lookup.pre); /// Ambiguouty is possible. + start_of_day = std::chrono::system_clock::to_time_t(lookup.pre); /// Ambiguity is possible. Values & values = lut[i]; values.year = date.year(); From 7abbe093e98bc21f60630d7246ef62ea9feb1dd6 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 19:04:19 +0300 Subject: [PATCH 080/244] Avoid magic constants in system.parts. [#CLICKHOUSE-3] Resolves #2039 --- dbms/src/Storages/MergeTree/MergeTreeDataPart.h | 3 +-- dbms/src/Storages/System/StorageSystemParts.cpp | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.h b/dbms/src/Storages/MergeTree/MergeTreeDataPart.h index cb9a5cf79f1..95bed39eaec 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.h +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.h @@ -140,8 +140,7 @@ struct MergeTreeDataPart /// is used from several threads without locks (it is changed with ALTER). time_t modification_time = 0; /// When the part is removed from the working set. Changes once. - /// Use DATE_LUT_MAX which is almost 2^32 to produce correct time_t to String conversions using DateLUT - mutable std::atomic remove_time { DATE_LUT_MAX }; + mutable std::atomic remove_time { std::numeric_limits::max() }; /// If true, the destructor will delete the directory with the part. bool is_temp = false; diff --git a/dbms/src/Storages/System/StorageSystemParts.cpp b/dbms/src/Storages/System/StorageSystemParts.cpp index 0914cae72da..a07e8bc26dd 100644 --- a/dbms/src/Storages/System/StorageSystemParts.cpp +++ b/dbms/src/Storages/System/StorageSystemParts.cpp @@ -66,7 +66,9 @@ void StorageSystemParts::processNextStorage(MutableColumns & columns, const Stor columns[i++]->insert(static_cast(part->rows_count)); columns[i++]->insert(static_cast(part->size_in_bytes)); columns[i++]->insert(static_cast(part->modification_time)); - columns[i++]->insert(static_cast(part->remove_time.load(std::memory_order_relaxed))); + + time_t remove_time = part->remove_time.load(std::memory_order_relaxed); + columns[i++]->insert(static_cast(remove_time == std::numeric_limits::max() ? 0 : remove_time)); /// For convenience, in returned refcount, don't add references that was due to local variables in this method: all_parts, active_parts. columns[i++]->insert(static_cast(part.use_count() - 1)); From bfc568741066ac684b8c189d285a963998dc6847 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 14 Mar 2018 19:19:22 +0300 Subject: [PATCH 081/244] Update DateLUTImpl.h --- libs/libcommon/include/common/DateLUTImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libcommon/include/common/DateLUTImpl.h b/libs/libcommon/include/common/DateLUTImpl.h index 754a83d4023..535c863eeb3 100644 --- a/libs/libcommon/include/common/DateLUTImpl.h +++ b/libs/libcommon/include/common/DateLUTImpl.h @@ -70,7 +70,7 @@ private: std::string time_zone; - /// We can correctly process only timestamps that less DATE_LUT_MAX (i.e. up to 2015 year inclusively) + /// We can correctly process only timestamps that less DATE_LUT_MAX (i.e. up to 2105 year inclusively) inline size_t findIndex(time_t t) const { /// First guess. From fd4c0403ba82b8e80ca2589aaef8d3184a8bb430 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 14 Mar 2018 19:37:56 +0300 Subject: [PATCH 082/244] Tests compile fix --- libs/libcommon/src/tests/CMakeLists.txt | 1 + libs/libcommon/src/tests/multi_version.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/libcommon/src/tests/CMakeLists.txt b/libs/libcommon/src/tests/CMakeLists.txt index 56b9a927e76..68d8a7e68ce 100644 --- a/libs/libcommon/src/tests/CMakeLists.txt +++ b/libs/libcommon/src/tests/CMakeLists.txt @@ -15,6 +15,7 @@ target_link_libraries (date_lut3 common ${PLATFORM_LIBS}) target_link_libraries (date_lut4 common ${PLATFORM_LIBS}) target_link_libraries (date_lut_default_timezone common ${PLATFORM_LIBS}) target_link_libraries (multi_version common) +add_check(multi_version) add_executable (unit_tests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp) target_link_libraries (unit_tests_libcommon gtest_main common) diff --git a/libs/libcommon/src/tests/multi_version.cpp b/libs/libcommon/src/tests/multi_version.cpp index 94035360008..9cab2e095e4 100644 --- a/libs/libcommon/src/tests/multi_version.cpp +++ b/libs/libcommon/src/tests/multi_version.cpp @@ -19,7 +19,7 @@ void thread1(MV & x, T & result) void thread2(MV & x, const char * result) { - x.set(std::make_shared(result)); + x.set(std::make_unique(result)); } @@ -31,7 +31,7 @@ int main(int argc, char ** argv) const char * s2 = "Goodbye!"; size_t n = 1000; - MV x(std::make_shared(s1)); + MV x(std::make_unique(s1)); Results results(n); ThreadPool tp(8); From 57279a87c7e654b4ef5d535586909ffea5687ed7 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 19:40:08 +0300 Subject: [PATCH 083/244] Whitespaces [#CLICKHOUSE-2]. --- dbms/src/Storages/StorageReplicatedMergeTree.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index d619f37d696..1a63b0b52c5 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -773,7 +773,6 @@ void StorageReplicatedMergeTree::checkParts(bool skip_sanity_checks) unexpected_parts_rows += part->rows_count; } - /// Additional helpful statistics auto get_blocks_count_in_data_part = [&] (const String & part_name) -> UInt64 { @@ -793,7 +792,6 @@ void StorageReplicatedMergeTree::checkParts(bool skip_sanity_checks) for (const String & name : expected_parts) expected_parts_blocks += get_blocks_count_in_data_part(name); - std::stringstream sanity_report; sanity_report << "There are " << unexpected_parts.size() << " unexpected parts with " << unexpected_parts_rows << " rows (" From d056d7e516443f97ef1d8eba6f6f037957612e24 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 14 Mar 2018 19:57:15 +0300 Subject: [PATCH 084/244] Fix ssl tests (#2042) * Revert "Reverted bad modification #2035" This reverts commit 6d6eca5e23253e8677825dbd2039d897b9186f4d. * spaces * fix * better * Revert "Disabled ill-formed test #2035" This reverts commit b28cef987132b8b90c50ac2b4c2c2c031d555504. * debug * fix * fix * fix * fix * fix * fix * clean * Tests compile fix --- dbms/tests/CMakeLists.txt | 8 +++++++- dbms/tests/clickhouse-test-server | 2 +- dbms/tests/client-test.xml | 12 ++++++++++++ .../{00505_tcp_ssl.sh.disabled => 00505_tcp_ssl.sh} | 0 dbms/tests/server-test.xml | 5 ++--- debian/pbuilder-hooks/B90test-server | 12 ++++++++---- debian/pbuilder-hooks/ssl.xml | 4 ---- 7 files changed, 30 insertions(+), 13 deletions(-) rename dbms/tests/queries/0_stateless/{00505_tcp_ssl.sh.disabled => 00505_tcp_ssl.sh} (100%) delete mode 100644 debian/pbuilder-hooks/ssl.xml diff --git a/dbms/tests/CMakeLists.txt b/dbms/tests/CMakeLists.txt index 30978652315..be51bcb8d69 100644 --- a/dbms/tests/CMakeLists.txt +++ b/dbms/tests/CMakeLists.txt @@ -25,6 +25,12 @@ add_subdirectory (external_dictionaries) if (ENABLE_TESTS) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_BINARY_DIR}) + if ($ENV{TEST_OPT}) + set(TEST_OPT $ENV{TEST_OPT}) + else () + set(TEST_OPT "--skip compile") + endif () + # maybe add --no-long ? - add_test(NAME with_server COMMAND bash -c "env BUILD_DIR=${ClickHouse_BINARY_DIR} TEST_OPT='--skip compile' ${CMAKE_CURRENT_SOURCE_DIR}/clickhouse-test-server") + add_test(NAME with_server COMMAND bash -c "env BUILD_DIR=${ClickHouse_BINARY_DIR} TEST_OPT='${TEST_OPT}' ${CMAKE_CURRENT_SOURCE_DIR}/clickhouse-test-server") endif () diff --git a/dbms/tests/clickhouse-test-server b/dbms/tests/clickhouse-test-server index b22058d5d7e..b3c9e4eaae5 100755 --- a/dbms/tests/clickhouse-test-server +++ b/dbms/tests/clickhouse-test-server @@ -23,7 +23,7 @@ export CLICKHOUSE_CONFIG=${CLICKHOUSE_CONFIG:=${CONFIG_SERVER_DIR}server-test.xm [ ! -d "$QUERIES_DIR" ] && QUERIES_DIR=${QUERIES_DIR=/usr/share/clickhouse-test/queries} rm -rf $DATA_DIR -mkdir -p $LOG_DIR $DATA_DIR +mkdir -p $LOG_DIR openssl dhparam -out `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.dhParamsFile` 256 openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.privateKeyFile` -out `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.certificateFile` diff --git a/dbms/tests/client-test.xml b/dbms/tests/client-test.xml index c5478dcb80d..8747c773a66 100644 --- a/dbms/tests/client-test.xml +++ b/dbms/tests/client-test.xml @@ -2,4 +2,16 @@ 59000 59440 + + + true + true + sslv2,sslv3 + true + none + + AcceptCertificateHandler + + + diff --git a/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh.disabled b/dbms/tests/queries/0_stateless/00505_tcp_ssl.sh similarity index 100% rename from dbms/tests/queries/0_stateless/00505_tcp_ssl.sh.disabled rename to dbms/tests/queries/0_stateless/00505_tcp_ssl.sh diff --git a/dbms/tests/server-test.xml b/dbms/tests/server-test.xml index 57f3f8ad9ea..78e53e576e2 100644 --- a/dbms/tests/server-test.xml +++ b/dbms/tests/server-test.xml @@ -35,10 +35,9 @@ true sslv2,sslv3 true - + none - - RejectCertificateHandler + AcceptCertificateHandler diff --git a/debian/pbuilder-hooks/B90test-server b/debian/pbuilder-hooks/B90test-server index bf0bbfbba63..e710cea45c1 100755 --- a/debian/pbuilder-hooks/B90test-server +++ b/debian/pbuilder-hooks/B90test-server @@ -16,8 +16,12 @@ ln -fs /usr/share/zoneinfo/Europe/Moscow /etc/localtime echo 'Europe/Moscow' > /etc/timezone dpkg-reconfigure -f noninteractive tzdata -pwd -mkdir -p /etc/clickhouse-server/config.d +mkdir -p /etc/clickhouse-server/config.d /etc/clickhouse-client/config.d +echo "84439440" > /etc/clickhouse-server/config.d/ssl.xml +echo "noneAcceptCertificateHandler" > /etc/clickhouse-client/config.d/ssl.xml + +openssl dhparam -out /etc/clickhouse-server/dhparam.pem 256 +openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt service clickhouse-server start sleep 3 @@ -25,8 +29,8 @@ sleep 3 # TODO: remove me or make only on error: tail -n100 /var/log/clickhouse-server/* -clickhouse-client -q "SELECT * from system.build_options;" -clickhouse-client -q "SELECT toDateTime(1);" +clickhouse-client --ssl -q "SELECT * from system.build_options;" +clickhouse-client --ssl -q "SELECT toDateTime(1);" ( [ "${TEST_RUN}" ] && clickhouse-test --queries /usr/share/clickhouse-test/queries --tmp /tmp/clickhouse-test/ ${TEST_OPT} ) || ${TEST_TRUE:=true} diff --git a/debian/pbuilder-hooks/ssl.xml b/debian/pbuilder-hooks/ssl.xml deleted file mode 100644 index 8b4580a14d4..00000000000 --- a/debian/pbuilder-hooks/ssl.xml +++ /dev/null @@ -1,4 +0,0 @@ - - 8443 - 9440 - From 0ee9b8ee369928d37eb7e4367d9e315ff7379d69 Mon Sep 17 00:00:00 2001 From: Eugene Klimov Date: Wed, 14 Mar 2018 23:20:33 +0500 Subject: [PATCH 085/244] remove xenial, trusty etc... currently --- docs/ru/getting_started/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/ru/getting_started/index.md b/docs/ru/getting_started/index.md index be4ce4f0333..3847663b3d5 100644 --- a/docs/ru/getting_started/index.md +++ b/docs/ru/getting_started/index.md @@ -16,7 +16,7 @@ grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not su В целях тестирования и разработки, система может быть установлена на один сервер или на рабочий компьютер. -### Установка из пакетов +### Установка из пакетов для Debian/Ubuntu Пропишите в `/etc/apt/sources.list` (или в отдельный файл `/etc/apt/sources.list.d/clickhouse.list`) репозитории: @@ -24,7 +24,6 @@ grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not su deb http://repo.yandex.ru/clickhouse/deb/stable/ main/ ``` -На других версиях Ubuntu, замените `trusty` на `xenial` или `precise`. Если вы хотите использовать наиболее свежую тестовую версию, замените stable на testing. Затем выполните: From 595bc175db44ef6d53bb988d7341e65318e76165 Mon Sep 17 00:00:00 2001 From: Eugene Klimov Date: Wed, 14 Mar 2018 23:21:22 +0500 Subject: [PATCH 086/244] remove xenial, trusty etc. currently one common package for debian\ubuntu --- docs/en/getting_started/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/en/getting_started/index.md b/docs/en/getting_started/index.md index 3d81e359227..42fc1c75551 100644 --- a/docs/en/getting_started/index.md +++ b/docs/en/getting_started/index.md @@ -16,7 +16,7 @@ The terminal must use UTF-8 encoding (the default in Ubuntu). For testing and development, the system can be installed on a single server or on a desktop computer. -### Installing from packages +### Installing from packages Debian/Ubuntu In `/etc/apt/sources.list` (or in a separate `/etc/apt/sources.list.d/clickhouse.list` file), add the repository: @@ -24,7 +24,6 @@ In `/etc/apt/sources.list` (or in a separate `/etc/apt/sources.list.d/clickhouse deb http://repo.yandex.ru/clickhouse/deb/stable/ main/ ``` -On other versions of Ubuntu, replace `trusty` with `xenial` or `precise`. If you want to use the most recent test version, replace 'stable' with 'testing'. Then run: From 597160443a7bd0f992178098daff256a70ecd56d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 14 Mar 2018 21:58:40 +0300 Subject: [PATCH 087/244] Fixed build after merge #2036 --- dbms/src/Common/ZooKeeper/ZooKeeper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.h b/dbms/src/Common/ZooKeeper/ZooKeeper.h index 2b0d195fd80..52f1968eba6 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.h +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.h @@ -368,7 +368,7 @@ public: private: friend struct WatchContext; friend class EphemeralNodeHolder; - friend class OpResult; + friend struct OpResult; void init(const std::string & hosts, const std::string & identity, int32_t session_timeout_ms, const std::string & chroot); From 6a965bb70727891b3948c52063137edcd4a54c09 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 14 Mar 2018 22:38:48 +0300 Subject: [PATCH 088/244] Client: use ConfigProcessor (#2049) * Client: use ConfigProcessor --- dbms/src/Server/Client.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 661d91e68d7..1580f45640b 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -175,14 +176,22 @@ private: if (home_path_cstr) home_path = home_path_cstr; + std::string config_path; if (config().has("config-file")) - loadConfiguration(config().getString("config-file")); + config_path = config().getString("config-file"); else if (Poco::File("./clickhouse-client.xml").exists()) - loadConfiguration("./clickhouse-client.xml"); + config_path = "./clickhouse-client.xml"; else if (!home_path.empty() && Poco::File(home_path + "/.clickhouse-client/config.xml").exists()) - loadConfiguration(home_path + "/.clickhouse-client/config.xml"); + config_path = home_path + "/.clickhouse-client/config.xml"; else if (Poco::File("/etc/clickhouse-client/config.xml").exists()) - loadConfiguration("/etc/clickhouse-client/config.xml"); + config_path = "/etc/clickhouse-client/config.xml"; + + if (!config_path.empty()) + { + ConfigProcessor config_processor(config_path); + auto loaded_config = config_processor.loadConfig(); + config().add(loaded_config.configuration); + } context.setApplicationType(Context::ApplicationType::CLIENT); From 51301d38cd81b0b1757163023af92cf7275ea390 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 14 Mar 2018 22:56:44 +0300 Subject: [PATCH 089/244] added tryGetCreateTableQuery [#CLICKHOUSE-3590] --- dbms/src/Databases/DatabaseDictionary.cpp | 5 +++++ dbms/src/Databases/DatabaseDictionary.h | 4 ++++ dbms/src/Databases/DatabaseMemory.cpp | 7 +++++++ dbms/src/Databases/DatabaseMemory.h | 4 ++++ dbms/src/Databases/DatabaseOrdinary.cpp | 21 +++++++++++++++---- dbms/src/Databases/DatabaseOrdinary.h | 5 +++++ dbms/src/Databases/IDatabase.h | 5 +++++ .../Storages/System/StorageSystemTables.cpp | 12 +---------- 8 files changed, 48 insertions(+), 15 deletions(-) diff --git a/dbms/src/Databases/DatabaseDictionary.cpp b/dbms/src/Databases/DatabaseDictionary.cpp index 6c14312c2e3..c68c801e4cb 100644 --- a/dbms/src/Databases/DatabaseDictionary.cpp +++ b/dbms/src/Databases/DatabaseDictionary.cpp @@ -182,6 +182,11 @@ ASTPtr DatabaseDictionary::getCreateTableQuery( return parseQuery(parser, query.data(), query.data() + query.size(), ""); } +ASTPtr DatabaseDictionary::tryGetCreateTableQuery(const Context & context, const String & table_name) const +{ + return getCreateTableQuery(context, table_name); +} + ASTPtr DatabaseDictionary::getCreateDatabaseQuery(const Context & /*context*/) const { String query; diff --git a/dbms/src/Databases/DatabaseDictionary.h b/dbms/src/Databases/DatabaseDictionary.h index f62bfc3e1c3..e2a036362b0 100644 --- a/dbms/src/Databases/DatabaseDictionary.h +++ b/dbms/src/Databases/DatabaseDictionary.h @@ -93,6 +93,10 @@ public: const Context & context, const String & table_name) const override; + ASTPtr tryGetCreateTableQuery( + const Context & context, + const String & table_name) const override; + ASTPtr getCreateDatabaseQuery(const Context & context) const override; void shutdown() override; diff --git a/dbms/src/Databases/DatabaseMemory.cpp b/dbms/src/Databases/DatabaseMemory.cpp index b50fb78468e..8eacc7f856f 100644 --- a/dbms/src/Databases/DatabaseMemory.cpp +++ b/dbms/src/Databases/DatabaseMemory.cpp @@ -128,6 +128,13 @@ ASTPtr DatabaseMemory::getCreateTableQuery( throw Exception("There is no CREATE TABLE query for DatabaseMemory tables", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); } +ASTPtr DatabaseMemory::tryGetCreateTableQuery( + const Context &, + const String &) const +{ + throw Exception("There is no CREATE TABLE query for DatabaseMemory tables", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); +} + ASTPtr DatabaseMemory::getCreateDatabaseQuery(const Context &) const { throw Exception("There is no CREATE DATABASE query for DatabaseMemory", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY); diff --git a/dbms/src/Databases/DatabaseMemory.h b/dbms/src/Databases/DatabaseMemory.h index dbf37acb5f6..1b5f0a20c62 100644 --- a/dbms/src/Databases/DatabaseMemory.h +++ b/dbms/src/Databases/DatabaseMemory.h @@ -84,6 +84,10 @@ public: const Context & context, const String & table_name) const override; + ASTPtr tryGetCreateTableQuery( + const Context & context, + const String & table_name) const override; + ASTPtr getCreateDatabaseQuery(const Context & context) const override; void shutdown() override; diff --git a/dbms/src/Databases/DatabaseOrdinary.cpp b/dbms/src/Databases/DatabaseOrdinary.cpp index 1f09c118666..4f63834d396 100644 --- a/dbms/src/Databases/DatabaseOrdinary.cpp +++ b/dbms/src/Databases/DatabaseOrdinary.cpp @@ -429,9 +429,7 @@ time_t DatabaseOrdinary::getTableMetadataModificationTime( } -ASTPtr DatabaseOrdinary::getCreateTableQuery( - const Context & context, - const String & table_name) const +ASTPtr DatabaseOrdinary::getCreateTableQueryImpl(const Context & context, const String & table_name, bool try_get) const { ASTPtr ast; @@ -440,7 +438,12 @@ ASTPtr DatabaseOrdinary::getCreateTableQuery( if (!ast) { /// Handle system.* tables for which there are no table.sql files. - auto msg = tryGetTable(context, table_name) + bool has_table = tryGetTable(context, table_name) != nullptr; + + if (has_table && try_get) + return nullptr; + + auto msg = has_table ? "There is no CREATE TABLE query for table " : "There is no metadata file for table "; @@ -450,6 +453,16 @@ ASTPtr DatabaseOrdinary::getCreateTableQuery( return ast; } +ASTPtr DatabaseOrdinary::getCreateTableQuery(const Context & context, const String & table_name) const +{ + return getCreateTableQueryImpl(context, table_name, false); +} + +ASTPtr DatabaseOrdinary::tryGetCreateTableQuery(const Context & context, const String & table_name) const +{ + return getCreateTableQueryImpl(context, table_name, true); +} + ASTPtr DatabaseOrdinary::getCreateDatabaseQuery(const Context & /*context*/) const { ASTPtr ast; diff --git a/dbms/src/Databases/DatabaseOrdinary.h b/dbms/src/Databases/DatabaseOrdinary.h index 9d8d2458df6..cae6686d5ba 100644 --- a/dbms/src/Databases/DatabaseOrdinary.h +++ b/dbms/src/Databases/DatabaseOrdinary.h @@ -59,6 +59,10 @@ public: const Context & context, const String & table_name) const override; + ASTPtr tryGetCreateTableQuery( + const Context & context, + const String & table_name) const override; + ASTPtr getCreateDatabaseQuery(const Context & context) const override; String getDataPath() const override; @@ -70,6 +74,7 @@ public: private: void startupTables(ThreadPool * thread_pool); + ASTPtr getCreateTableQueryImpl(const Context & context, const String & table_name, bool try_get) const; }; } diff --git a/dbms/src/Databases/IDatabase.h b/dbms/src/Databases/IDatabase.h index 01c8970901d..6b84f3fa165 100644 --- a/dbms/src/Databases/IDatabase.h +++ b/dbms/src/Databases/IDatabase.h @@ -129,6 +129,11 @@ public: const Context & context, const String & name) const = 0; + /// Like getCreateTableQuery, but don't throw for existing tables without metadata. + virtual ASTPtr tryGetCreateTableQuery( + const Context & context, + const String & name) const = 0; + /// Get the CREATE DATABASE query for current database. virtual ASTPtr getCreateDatabaseQuery(const Context & context) const = 0; diff --git a/dbms/src/Storages/System/StorageSystemTables.cpp b/dbms/src/Storages/System/StorageSystemTables.cpp index 493750d5dfa..77700c2a256 100644 --- a/dbms/src/Storages/System/StorageSystemTables.cpp +++ b/dbms/src/Storages/System/StorageSystemTables.cpp @@ -200,17 +200,7 @@ BlockInputStreams StorageSystemTables::read( if (has_create_table_query || has_engine_full) { - ASTPtr ast; - - try - { - ast = database->getCreateTableQuery(context, table_name); - } - catch (const Exception & e) - { - if (e.code() != ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY) - throw; - } + ASTPtr ast = database->tryGetCreateTableQuery(context, table_name); if (has_create_table_query) res_columns[j++]->insert(ast ? queryToString(ast) : ""); From f1b32e8982f1f5b5d2d19f8884183fa5eab085e6 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 19:43:18 +0300 Subject: [PATCH 090/244] Fixed ordinary MergeTree merges in case of empty ORDER BY key. [#CLICKHOUSE-2] --- dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp | 12 ++++++++---- .../00578_merge_trees_without_primary_key.sql | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index 229c40404bb..ae8677c57be 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -330,12 +330,12 @@ static void extractMergingAndGatheringColumns(const NamesAndTypesList & all_colu NamesAndTypesList & merging_columns, Names & merging_column_names ) { - Names primary_key_columns_dup = primary_key_expressions->getRequiredColumns(); - std::set key_columns(primary_key_columns_dup.cbegin(), primary_key_columns_dup.cend()); + Names primary_key_columns_vec = primary_key_expressions->getRequiredColumns(); + std::set key_columns(primary_key_columns_vec.cbegin(), primary_key_columns_vec.cend()); if (secondary_key_expressions) { - Names secondary_key_columns_dup = secondary_key_expressions->getRequiredColumns(); - key_columns.insert(secondary_key_columns_dup.begin(), secondary_key_columns_dup.end()); + Names secondary_key_columns_vec = secondary_key_expressions->getRequiredColumns(); + key_columns.insert(secondary_key_columns_vec.begin(), secondary_key_columns_vec.end()); } /// Force sign column for Collapsing mode @@ -350,6 +350,10 @@ static void extractMergingAndGatheringColumns(const NamesAndTypesList & all_colu if (merging_params.mode == MergeTreeData::MergingParams::VersionedCollapsing) key_columns.emplace(merging_params.sign_column); + /// Force to merge at least one column in case of empty key + if (key_columns.empty()) + key_columns.emplace(all_columns.front().name); + /// TODO: also force "summing" and "aggregating" columns to make Horizontal merge only for such columns for (auto & column : all_columns) diff --git a/dbms/tests/queries/0_stateless/00578_merge_trees_without_primary_key.sql b/dbms/tests/queries/0_stateless/00578_merge_trees_without_primary_key.sql index efd881ae006..2e1c0d24024 100644 --- a/dbms/tests/queries/0_stateless/00578_merge_trees_without_primary_key.sql +++ b/dbms/tests/queries/0_stateless/00578_merge_trees_without_primary_key.sql @@ -1,7 +1,7 @@ SELECT '*** MergeTree ***'; DROP TABLE IF EXISTS test.unsorted; -CREATE TABLE test.unsorted (x UInt32, y String) ENGINE MergeTree ORDER BY tuple(); +CREATE TABLE test.unsorted (x UInt32, y String) ENGINE MergeTree ORDER BY tuple() SETTINGS vertical_merge_algorithm_min_rows_to_activate=0, vertical_merge_algorithm_min_columns_to_activate=0; INSERT INTO test.unsorted VALUES (1, 'a'), (5, 'b'); INSERT INTO test.unsorted VALUES (2, 'c'), (4, 'd'); From 4011afa399593c2e207e07b03a441b88b30bf00f Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 22:07:57 +0300 Subject: [PATCH 091/244] Parallel SELECT and INSERT in ClusterCopier. [#CLICKHOUSE-2] --- dbms/src/Server/ClusterCopier.cpp | 26 ++++++++++++------- .../DistributedBlockOutputStream.cpp | 5 +++- .../DistributedBlockOutputStream.h | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/dbms/src/Server/ClusterCopier.cpp b/dbms/src/Server/ClusterCopier.cpp index 077dc43c5f6..c38c81e73ed 100644 --- a/dbms/src/Server/ClusterCopier.cpp +++ b/dbms/src/Server/ClusterCopier.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ #include #include #include -#include +#include #include #include #include @@ -46,20 +47,20 @@ #include #include #include -#include #include #include -#include +#include #include -#include #include #include #include #include #include #include -#include #include +#include +#include +#include #include #include @@ -697,7 +698,7 @@ void DB::TaskCluster::reloadSettings(const Poco::Util::AbstractConfiguration & c settings_pull.load_balancing = LoadBalancing::NEAREST_HOSTNAME; settings_pull.readonly = 1; settings_pull.max_threads = 1; - settings_pull.max_block_size = std::min(8192UL, settings_pull.max_block_size.value); + settings_pull.max_block_size = settings_pull.max_block_size.changed ? settings_pull.max_block_size.value : 8192UL; settings_pull.preferred_block_size_bytes = 0; settings_push.insert_distributed_timeout = 0; @@ -1609,8 +1610,15 @@ protected: Context context_insert = context; context_insert.getSettingsRef() = task_cluster->settings_push; - BlockIO io_select = InterpreterFactory::get(query_select_ast, context_select)->execute(); - BlockIO io_insert = InterpreterFactory::get(query_insert_ast, context_insert)->execute(); + BlockInputStreamPtr input; + BlockOutputStreamPtr output; + { + BlockIO io_select = InterpreterFactory::get(query_select_ast, context_select)->execute(); + BlockIO io_insert = InterpreterFactory::get(query_insert_ast, context_insert)->execute(); + + input = std::make_shared(io_select.in); + output = io_insert.out; + } using ExistsFuture = zkutil::ZooKeeper::ExistsFuture; auto future_is_dirty_checker = std::make_unique(zookeeper->asyncExists(is_dirty_flag_path)); @@ -1665,7 +1673,7 @@ protected: }; /// Main work is here - copyData(*io_select.in, *io_insert.out, cancel_check, update_stats); + copyData(*input, *output, cancel_check, update_stats); // Just in case if (future_is_dirty_checker != nullptr) diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp index 8db08dfb09a..607eb9efb67 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp @@ -337,7 +337,10 @@ void DistributedBlockOutputStream::writeSuffix() throw; } - LOG_DEBUG(log, getCurrentStateDescription()); + double elapsed = watch.elapsedSeconds(); + LOG_DEBUG(log, "It took " << std::fixed << std::setprecision(1) << elapsed << " sec. to insert " << blocks_inserted << " blocks" + << " (average " << std::fixed << std::setprecision(1) << elapsed / blocks_inserted * 1000 << " ms. per block)" + << ". " << getCurrentStateDescription()); } } diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h index 199700d742c..eed38adf417 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h @@ -118,7 +118,7 @@ private: size_t remote_jobs_count = 0; size_t local_jobs_count = 0; - + std::atomic finished_jobs_count{0}; Poco::Logger * log; From 1f1870abd41b5044b30c1a449660feb82cde4dee Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 23:19:25 +0300 Subject: [PATCH 092/244] Add more priority to local ClusterCopier workers. [#CLICKHOUSE-2] --- dbms/src/Server/ClusterCopier.cpp | 51 +++++++++++++++---- .../test_cluster_copier/task0_description.xml | 2 +- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/dbms/src/Server/ClusterCopier.cpp b/dbms/src/Server/ClusterCopier.cpp index c38c81e73ed..4233ce70e3f 100644 --- a/dbms/src/Server/ClusterCopier.cpp +++ b/dbms/src/Server/ClusterCopier.cpp @@ -760,6 +760,7 @@ public: /// Do not initialize tables, will make deferred initialization in process() + getZooKeeper()->createAncestors(getWorkersPathVersion() + "/"); getZooKeeper()->createAncestors(getWorkersPath() + "/"); } @@ -1012,32 +1013,65 @@ protected: return task_cluster->task_zookeeper_path + "/task_active_workers"; } + String getWorkersPathVersion() const + { + return getWorkersPath() + "_version"; + } + String getCurrentWorkerNodePath() const { return getWorkersPath() + "/" + host_id; } zkutil::EphemeralNodeHolder::Ptr createTaskWorkerNodeAndWaitIfNeed(const zkutil::ZooKeeperPtr & zookeeper, - const String & description) + const String & description, bool unprioritized) { + std::chrono::milliseconds current_sleep_time = default_sleep_time; + static constexpr std::chrono::milliseconds max_sleep_time(30000); // 30 sec + + if (unprioritized) + std::this_thread::sleep_for(current_sleep_time); + + String workers_version_path = getWorkersPathVersion(); + String workers_path = getWorkersPath(); + String current_worker_path = getCurrentWorkerNodePath(); + while (true) { zkutil::Stat stat; - zookeeper->get(getWorkersPath(), &stat); + zookeeper->get(workers_version_path, &stat); + auto version = stat.version; + zookeeper->get(workers_path, &stat); if (static_cast(stat.numChildren) >= task_cluster->max_workers) { LOG_DEBUG(log, "Too many workers (" << stat.numChildren << ", maximum " << task_cluster->max_workers << ")" << ". Postpone processing " << description); - - std::this_thread::sleep_for(default_sleep_time); - - updateConfigIfNeeded(); } else { - return std::make_shared(getCurrentWorkerNodePath(), *zookeeper, true, false, description); + zkutil::Ops ops; + ops.emplace_back(new zkutil::Op::SetData(workers_version_path, description, version)); + ops.emplace_back(new zkutil::Op::Create(current_worker_path, description, zookeeper->getDefaultACL(), zkutil::CreateMode::Ephemeral)); + auto code = zookeeper->tryMulti(ops); + + if (code == ZOK || code == ZNODEEXISTS) + return std::make_shared(current_worker_path, *zookeeper, false, false, description); + + if (code == ZBADVERSION) + { + LOG_DEBUG(log, "A concurrent worker has just been added, will check free worker slots again"); + } + else + throw zkutil::KeeperException(code); } + + if (unprioritized) + current_sleep_time = std::min(max_sleep_time, current_sleep_time + default_sleep_time); + + std::this_thread::sleep_for(current_sleep_time); + + updateConfigIfNeeded(); } } @@ -1445,9 +1479,8 @@ protected: return parseQuery(p_query, query); }; - /// Load balancing - auto worker_node_holder = createTaskWorkerNodeAndWaitIfNeed(zookeeper, current_task_status_path); + auto worker_node_holder = createTaskWorkerNodeAndWaitIfNeed(zookeeper, current_task_status_path, task_shard.priority.is_remote); LOG_DEBUG(log, "Processing " << current_task_status_path); diff --git a/dbms/tests/integration/test_cluster_copier/task0_description.xml b/dbms/tests/integration/test_cluster_copier/task0_description.xml index 0031a18c552..e8e4df99254 100644 --- a/dbms/tests/integration/test_cluster_copier/task0_description.xml +++ b/dbms/tests/integration/test_cluster_copier/task0_description.xml @@ -1,7 +1,7 @@ - 4 + 3 From 9e9739ce2d8559b88171e83d9bb3e476864400cb Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 14 Mar 2018 23:54:16 +0300 Subject: [PATCH 093/244] Fixed a test. [#CLICKHOUSE-2] --- dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp b/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp index 54648bdad8f..073e482e109 100644 --- a/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp +++ b/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp @@ -38,7 +38,7 @@ int main(int argc, char ** argv) ops.emplace_back(std::make_shared("/test/zk_expiration_test", -1)); zkutil::MultiTransactionInfo info; - zk.tryMultiUnsafe(ops, info); + zk.tryMultiNoThrow(ops, nullptr, &info); std::cout << time(nullptr) - time0 << "s: " << zkutil::ZooKeeper::error2string(info.code) << std::endl; try From d52f688883fe2a703dd83164dc172b76745d8e0f Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 15 Mar 2018 00:19:47 +0300 Subject: [PATCH 094/244] Attempt to fix regression: missing support for remote tables in IN section when querying Distributed tables [#CLICKHOUSE-2] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 5 +++++ .../Interpreters/InterpreterSelectQuery.cpp | 3 ++- dbms/src/Storages/IStorage.h | 14 +++++++++++++ dbms/src/Storages/StorageDistributed.cpp | 20 +++++++++++++++++++ dbms/src/Storages/StorageDistributed.h | 6 ++++++ 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index f0bc8137029..5360e750a33 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -61,6 +61,8 @@ #include #include +#include + namespace DB { @@ -2438,6 +2440,9 @@ bool ExpressionAnalyzer::appendWhere(ExpressionActionsChain & chain, bool only_t initChain(chain, source_columns); ExpressionActionsChain::Step & step = chain.steps.back(); + DUMP(only_types); + DUMP(StackTrace().toString()); + step.required_output.push_back(select_query->where_expression->getColumnName()); getRootActions(select_query->where_expression, only_types, false, step.actions); diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 49b3ba27004..1f6aeb9d3c5 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -676,7 +676,8 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline pipeline.streams = storage->read(required_columns, query_info, context, from_stage, max_block_size, max_streams); if (pipeline.streams.empty()) - pipeline.streams.emplace_back(std::make_shared(storage->getSampleBlockForColumns(required_columns))); + pipeline.streams.emplace_back(std::make_shared( + storage->analyze(required_columns, query_info, context, from_stage))); pipeline.transform([&](auto & stream) { diff --git a/dbms/src/Storages/IStorage.h b/dbms/src/Storages/IStorage.h index ef9fd8004ce..b30aeb2bfb8 100644 --- a/dbms/src/Storages/IStorage.h +++ b/dbms/src/Storages/IStorage.h @@ -180,6 +180,20 @@ public: throw Exception("Method read is not supported by storage " + getName(), ErrorCodes::NOT_IMPLEMENTED); } + /** Without executing a query determine, + * what structure of result and what query processed stage + * we will get if we will call 'read' method. + */ + virtual Block analyze( + const Names & column_names, + const SelectQueryInfo & /*query_info*/, + const Context & /*context*/, + QueryProcessingStage::Enum & processed_stage) + { + processed_stage = QueryProcessingStage::FetchColumns; + return getSampleBlockForColumns(column_names); + } + /** Writes the data to a table. * Receives a description of the query, which can contain information about the data write method. * Returns an object by which you can write data sequentially. diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 2b1dfe66523..f73f23e5a13 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -197,6 +197,26 @@ BlockInputStreams StorageDistributed::read( } +Block StorageDistributed::analyze( + const Names & /*column_names*/, + const SelectQueryInfo & query_info, + const Context & context, + QueryProcessingStage::Enum & processed_stage) +{ + auto cluster = getCluster(); + + const Settings & settings = context.getSettingsRef(); + + size_t result_size = (cluster->getRemoteShardCount() * settings.max_parallel_replicas) + cluster->getLocalShardCount(); + + processed_stage = result_size == 1 || settings.distributed_group_by_no_merge + ? QueryProcessingStage::Complete + : QueryProcessingStage::WithMergeableState; + + return materializeBlock(InterpreterSelectQuery(query_info.query, context, {}, processed_stage).getSampleBlock()); +} + + BlockOutputStreamPtr StorageDistributed::write(const ASTPtr & query, const Settings & settings) { auto cluster = (owned_cluster) ? owned_cluster : context.getCluster(cluster_name); diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 451c9f12d8a..63fefbfe501 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -60,6 +60,12 @@ public: size_t max_block_size, unsigned num_streams) override; + Block analyze( + const Names & column_names, + const SelectQueryInfo & query_info, + const Context & context, + QueryProcessingStage::Enum & processed_stage) override; + BlockOutputStreamPtr write(const ASTPtr & query, const Settings & settings) override; void drop() override {} From 56947de18a120d0522f7c359866b2feb8c3dc062 Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 15 Mar 2018 02:04:35 +0300 Subject: [PATCH 095/244] Try fix ssl (#2051) * Revert "Reverted bad modification #2035" This reverts commit 6d6eca5e23253e8677825dbd2039d897b9186f4d. * spaces * fix * better * Revert "Disabled ill-formed test #2035" This reverts commit b28cef987132b8b90c50ac2b4c2c2c031d555504. * debug * fix * fix * fix * fix * fix * fix * clean * Tests compile fix * fix * Try fix ssl * version * Test fixes, ./release now uses pbuilder by default * fix --- debian/pbuilder-hooks/B90test-server | 17 +++++++++++------ release | 5 +++-- utils/travis/normal.sh | 8 +++++--- utils/travis/pbuilder.sh | 7 +++++-- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/debian/pbuilder-hooks/B90test-server b/debian/pbuilder-hooks/B90test-server index e710cea45c1..fc7c0a04167 100755 --- a/debian/pbuilder-hooks/B90test-server +++ b/debian/pbuilder-hooks/B90test-server @@ -17,11 +17,16 @@ echo 'Europe/Moscow' > /etc/timezone dpkg-reconfigure -f noninteractive tzdata mkdir -p /etc/clickhouse-server/config.d /etc/clickhouse-client/config.d -echo "84439440" > /etc/clickhouse-server/config.d/ssl.xml -echo "noneAcceptCertificateHandler" > /etc/clickhouse-client/config.d/ssl.xml -openssl dhparam -out /etc/clickhouse-server/dhparam.pem 256 -openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt +TEST_SSL=${TEST_SSL=1} +if [ "${TEST_SSL}" ]; then + echo "84439440" > /etc/clickhouse-server/config.d/ssl.xml + echo "noneAcceptCertificateHandler" > /etc/clickhouse-client/config.d/ssl.xml + + openssl dhparam -out /etc/clickhouse-server/dhparam.pem 256 + openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt + CLIENT_ADD="--ssl" +fi service clickhouse-server start sleep 3 @@ -29,8 +34,8 @@ sleep 3 # TODO: remove me or make only on error: tail -n100 /var/log/clickhouse-server/* -clickhouse-client --ssl -q "SELECT * from system.build_options;" -clickhouse-client --ssl -q "SELECT toDateTime(1);" +clickhouse-client -q "SELECT * from system.build_options;" +clickhouse-client ${CLIENT_ADD} -q "SELECT toDateTime(1);" ( [ "${TEST_RUN}" ] && clickhouse-test --queries /usr/share/clickhouse-test/queries --tmp /tmp/clickhouse-test/ ${TEST_OPT} ) || ${TEST_TRUE:=true} diff --git a/release b/release index 6c36a594cfe..fb0ce279a9d 100755 --- a/release +++ b/release @@ -13,6 +13,7 @@ DEB_CXX=${DEB_CXX:=g++-7} CONTROL=debian/control DEBUILD_NOSIGN_OPTIONS="-us -uc" DEBUILD_NODEPS_OPTIONS="-d" +USE_PBUILDER=1 if [ -z "$REVISION" ] ; then get_revision_author @@ -34,8 +35,8 @@ do elif [[ $1 == '--head' ]]; then REVISION=`git rev-parse HEAD` shift - elif [[ $1 == '--pbuilder' ]]; then - USE_PBUILDER=1 + elif [[ $1 == '--no-pbuilder' ]]; then + USE_PBUILDER= shift elif [[ $1 == '--fast' ]]; then # Wrong but fast pbuilder mode: create base package with all depends diff --git a/utils/travis/normal.sh b/utils/travis/normal.sh index 6f94981b735..ba5b294535f 100755 --- a/utils/travis/normal.sh +++ b/utils/travis/normal.sh @@ -1,9 +1,11 @@ -#!/bin/sh +#!/bin/bash # Manual run: # env CXX=g++-7 CC=gcc-7 utils/travis/normal.sh # env CXX=clang++-5.0 CC=clang-5.0 utils/travis/normal.sh +CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) + set -e set -x @@ -20,7 +22,7 @@ date mkdir -p build cd build -cmake .. -DCMAKE_CXX_COMPILER=`which $DEB_CXX $CXX` -DCMAKE_C_COMPILER=`which $DEB_CC $CC` \ +cmake $CUR_DIR/../.. -DCMAKE_CXX_COMPILER=`which $DEB_CXX $CXX` -DCMAKE_C_COMPILER=`which $DEB_CC $CC` \ `# Does not optimize to speedup build, skip debug info to use less disk` \ -DCMAKE_C_FLAGS_ADD="-O0 -g0" -DCMAKE_CXX_FLAGS_ADD="-O0 -g0" \ `# ignore ccache disabler on trusty` \ @@ -33,6 +35,6 @@ cmake .. -DCMAKE_CXX_COMPILER=`which $DEB_CXX $CXX` -DCMAKE_C_COMPILER=`which $D `# Skip tests:` \ `# 00281 requires internal compiler` \ `# 00428 requires sudo (not all vms allow this)` \ - && ( [ ${TEST_RUN=1} ] && ( ( cd .. && env TEST_OPT="--skip long compile 00428 $TEST_OPT" bash -x dbms/tests/clickhouse-test-server ) || ${TEST_TRUE=false} ) || true ) + && ( [ ${TEST_RUN=1} ] && ( ( cd $CUR_DIR/../.. && env TEST_OPT="--skip long compile 00428 $TEST_OPT" bash -x dbms/tests/clickhouse-test-server ) || ${TEST_TRUE=false} ) || true ) date diff --git a/utils/travis/pbuilder.sh b/utils/travis/pbuilder.sh index 635db59fdaf..9d5cce6a366 100755 --- a/utils/travis/pbuilder.sh +++ b/utils/travis/pbuilder.sh @@ -1,4 +1,6 @@ -#!/bin/sh +#!/bin/bash + +CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # env CXX=clang++-5.0 CC=clang-5.0 DH_VERBOSE=1 utils/travis/pbuilder.sh @@ -14,6 +16,7 @@ env TEST_RUN=${TEST_RUN=1} \ `# 00281 requires internal compiler` \ `# 00416 requires patched poco from contrib/` \ TEST_OPT="--skip long pocopatch $TEST_OPT" \ + TEST_SSL="" `# Application: SSL context exception: Error loading certificate from file /etc/clickhouse-server/server.crt: No error -- when using system poco on artful` \ TEST_TRUE=${TEST_TRUE=false} \ `# travisci will not upload ccache cache after timeout (48min), use our less timeout` \ PBUILDER_OPT="--timeout ${PBUILDER_TIMEOUT:=35m} $PBUILDER_OPT" \ @@ -25,6 +28,6 @@ env TEST_RUN=${TEST_RUN=1} \ `# Use all possible contrib libs from system` \ `# psmisc - killall` \ EXTRAPACKAGES="psmisc clang-5.0 lld-5.0 liblld-5.0-dev libclang-5.0-dev liblld-5.0 libc++abi-dev libc++-dev libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev zlib1g-dev liblz4-dev libdouble-conversion-dev libzookeeper-mt-dev libsparsehash-dev librdkafka-dev libpoco-dev libsparsehash-dev libgoogle-perftools-dev libzstd-dev libre2-dev $EXTRAPACKAGES" \ - ./release --pbuilder $RELEASE_OPT + $CUR_DIR/../../release $RELEASE_OPT date From b39fa2027d415a123ce87fb292508138f77dfadf Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 15 Mar 2018 12:41:06 +0300 Subject: [PATCH 096/244] release: ignore --pbuilder flag --- release | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release b/release index fb0ce279a9d..ae19a8ada46 100755 --- a/release +++ b/release @@ -35,6 +35,9 @@ do elif [[ $1 == '--head' ]]; then REVISION=`git rev-parse HEAD` shift + elif [[ $1 == '--pbuilder' ]]; then + # Default + shift elif [[ $1 == '--no-pbuilder' ]]; then USE_PBUILDER= shift From b1967ff0d50977483e9c61f8ae4710e0314616f5 Mon Sep 17 00:00:00 2001 From: Valera Ryaboshapko Date: Thu, 15 Mar 2018 14:48:19 +0300 Subject: [PATCH 097/244] Update mergetree.md --- docs/ru/table_engines/mergetree.md | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/ru/table_engines/mergetree.md b/docs/ru/table_engines/mergetree.md index 4da83967e26..714d368909d 100644 --- a/docs/ru/table_engines/mergetree.md +++ b/docs/ru/table_engines/mergetree.md @@ -2,45 +2,45 @@ # MergeTree -Движок MergeTree поддерживает индекс по первичному ключу и по дате, и обеспечивает возможность обновления данных в реальном времени. +Движок MergeTree поддерживает индекс по первичному ключу и по дате и обеспечивает возможность обновления данных в реальном времени. Это наиболее продвинутый движок таблиц в ClickHouse. Не путайте с движком Merge. -Движок принимает параметры: имя столбца типа Date, содержащего дату; выражение для семплирования (не обязательно); кортеж, определяющий первичный ключ таблицы; гранулированность индекса. Пример: +Движок принимает параметры: имя столбца типа Date, содержащего дату; выражение для семплирования (не обязательно); кортеж, определяющий первичный ключ таблицы; гранулированность индекса. -Пример без поддержки сэмплирования: +Пример без поддержки сэмплирования. ```text MergeTree(EventDate, (CounterID, EventDate), 8192) ``` -Пример с поддержкой сэмплирования: +Пример с поддержкой сэмплирования. ```text MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192) ``` -В таблице типа MergeTree обязательно должен быть отдельный столбец, содержащий дату. В этом примере, это - столбец EventDate. Тип столбца с датой - обязательно Date (а не DateTime). +В таблице типа MergeTree обязательно должен быть отдельный столбец, содержащий дату, здесь это столбец EventDate. Тип столбца с датой — обязательно Date (а не DateTime). Первичным ключом может быть кортеж из произвольных выражений (обычно это просто кортеж столбцов) или одно выражение. -Выражение для сэмплирования (использовать не обязательно) - произвольное выражение. Оно должно также присутствовать в первичном ключе. В примере используется хэширование по идентификатору посетителя, чтобы псевдослучайно перемешать данные в таблице для каждого CounterID и EventDate. То есть, при использовании секции SAMPLE в запросе, вы получите равномерно-псевдослучайную выборку данных для подмножества посетителей. +Выражение для сэмплирования (использовать не обязательно) — произвольное выражение. Оно должно также присутствовать в первичном ключе. В примере используется хэширование по идентификатору посетителя, чтобы псевдослучайно перемешать данные в таблице для каждого CounterID и EventDate. То есть, при использовании секции SAMPLE в запросе вы получите равномерно-псевдослучайную выборку данных для подмножества посетителей. -Таблица реализована, как набор кусочков. Каждый кусочек сортирован по первичному ключу. Также, для каждого кусочка прописана минимальная и максимальная дата. При вставке в таблицу, создаётся новый сортированный кусочек. В фоне, периодически инициируется процесс слияния. При слиянии, выбирается несколько кусочков, обычно наименьших, и сливаются в один большой сортированный кусочек. +Таблица реализована как набор кусочков. Каждый кусочек сортирован по первичному ключу. Также для каждого кусочка прописана минимальная и максимальная дата. При вставке в таблицу создаётся новый сортированный кусочек. В фоне периодически инициируется процесс слияния. При слиянии выбирается несколько кусочков, обычно наименьших, и сливаются в один большой сортированный кусочек. То есть, при вставке в таблицу производится инкрементальная сортировка. Слияние реализовано таким образом, что таблица постоянно состоит из небольшого количества сортированных кусочков, а также само слияние делает не слишком много работы. -При вставке, данные относящиеся к разным месяцам, разбиваются на разные кусочки. Кусочки, соответствующие разным месяцам, никогда не объединяются. Это сделано, чтобы обеспечить локальность модификаций данных (для упрощения бэкапов). +При вставке данные, относящиеся к разным месяцам, разбиваются на разные кусочки. Кусочки, соответствующие разным месяцам, никогда не объединяются. Это сделано, чтобы обеспечить локальность модификаций данных (для упрощения бэкапов). -Кусочки объединяются до некоторого предельного размера - чтобы не было слишком длительных слияний. +Кусочки объединяются до некоторого предельного размера, чтобы не было слишком длительных слияний. -Для каждого кусочка также пишется индексный файл. Индексный файл содержит значение первичного ключа для каждой index_granularity строки таблицы. То есть, это - разреженный индекс сортированных данных. +Для каждого кусочка также пишется индексный файл. Индексный файл содержит значение первичного ключа для каждой index_granularity строки таблицы. То есть, это разреженный индекс сортированных данных. -Для столбцов также пишутся "засечки" каждую index_granularity строку, чтобы данные можно было читать в определённом диапазоне. +Для столбцов также пишутся «засечки» каждую index_granularity строку, чтобы данные можно было читать в определённом диапазоне. При чтении из таблицы, запрос SELECT анализируется на предмет того, можно ли использовать индексы. Индекс может использоваться, если в секции WHERE/PREWHERE, в качестве одного из элементов конъюнкции, или целиком, есть выражение, представляющее операции сравнения на равенства, неравенства, а также IN над столбцами, входящими в первичный ключ / дату, а также логические связки над ними. -Таким образом, обеспечивается возможность быстро выполнять запросы по одному или многим диапазонам первичного ключа. Например, в указанном примере, будут быстро работать запросы для конкретного счётчика; для конкретного счётчика и диапазона дат; для конкретного счётчика и даты, для нескольких счётчиков и диапазона дат и т. п. +Таким образом, обеспечивается возможность быстро выполнять запросы по одному или многим диапазонам первичного ключа. Например, в указанном примере будут быстро работать запросы для конкретного счётчика; для конкретного счётчика и диапазона дат; для конкретного счётчика и даты, для нескольких счётчиков и диапазона дат и т. п. ```sql SELECT count() FROM table WHERE EventDate = toDate(now()) AND CounterID = 34 @@ -50,22 +50,22 @@ SELECT count() FROM table WHERE ((EventDate >= toDate('2014-01-01') AND EventDat Во всех этих случаях будет использоваться индекс по дате и по первичному ключу. Видно, что индекс используется даже для достаточно сложных выражений. Чтение из таблицы организовано так, что использование индекса не может быть медленнее full scan-а. -В этом примере, индекс не может использоваться: +В этом примере индекс не может использоваться. ```sql SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%' ``` -Чтобы проверить сможет ли ClickHouse использовать индекс при выполнении запроса, используйте настройки [force_index_by_date](../operations/settings/settings.md#settings-settings-force_index_by_date) и [force_primary_key](../operations/settings/settings.md#settings-settings-force_primary_key). +Чтобы проверить, сможет ли ClickHouse использовать индекс при выполнении запроса, используйте настройки [force_index_by_date](../operations/settings/settings.md#settings-settings-force_index_by_date) и [force_primary_key](../operations/settings/settings.md#settings-settings-force_primary_key). -Индекс по дате обеспечивает чтение только кусков, содержащих даты из нужного диапазона. При этом, кусок данных может содержать данные за многие даты (до целого месяца), а в пределах одного куска, данные лежат упорядоченными по первичному ключу, который может не содержать дату в качестве первого столбца. В связи с этим, при использовании запроса с указанием условия только на дату, но не на префикс первичного ключа, будет читаться данных больше, чем за одну дату. +Индекс по дате обеспечивает чтение только кусков, содержащих даты из нужного диапазона. При этом кусок данных может содержать данные за многие даты (до целого месяца), а в пределах одного куска данные лежат упорядоченными по первичному ключу, который может не содержать дату в качестве первого столбца. В связи с этим, при использовании запроса с указанием условия только на дату, но не на префикс первичного ключа, будет читаться данных больше, чем за одну дату. -Для конкуррентного доступа к таблице, используется мульти-версионность. То есть, при одновременном чтении и обновлении таблицы, данные будут читаться из набора кусочков, актуального на момент запроса. Длинных блокировок нет. Вставки никак не мешают чтениям. +Для конкуррентного доступа к таблице используется мультиверсионность. То есть, при одновременном чтении и обновлении таблицы, данные будут читаться из набора кусочков, актуального на момент запроса. Длинных блокировок нет. Вставки никак не мешают чтениям. Чтения из таблицы автоматически распараллеливаются. Поддерживается запрос `OPTIMIZE`, который вызывает один внеочередной шаг слияния. -Вы можете использовать одну большую таблицу, постоянно добавляя в неё данные небольшими пачками - именно для этого предназначен движок MergeTree. +Вы можете использовать одну большую таблицу, постоянно добавляя в неё данные небольшими пачками, именно для этого предназначен движок MergeTree. -Для всех типов таблиц семейства MergeTree возможна репликация данных - смотрите раздел "Репликация данных". +Для всех типов таблиц семейства MergeTree возможна репликация данных — смотрите раздел «Репликация данных». From b4bb6f4bc3c36822902daa7e6098858f0a41de90 Mon Sep 17 00:00:00 2001 From: Valera Ryaboshapko Date: Thu, 15 Mar 2018 15:33:12 +0300 Subject: [PATCH 098/244] Update replacingmergetree.md --- docs/ru/table_engines/replacingmergetree.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ru/table_engines/replacingmergetree.md b/docs/ru/table_engines/replacingmergetree.md index 4c86b489f99..8e09810ca2b 100644 --- a/docs/ru/table_engines/replacingmergetree.md +++ b/docs/ru/table_engines/replacingmergetree.md @@ -2,15 +2,15 @@ Движок таблиц отличается от `MergeTree` тем, что выполняет удаление дублирующихся записей с одинаковым значением первичного ключа. -Последний, необязательный параметр движка таблицы - столбец с "версией". При слиянии, для всех строк с одинаковым значением первичного ключа, оставляет только одну строку: если задан столбец версии - строку с максимальной версией, иначе - последнюю строку. +Последний, необязательный параметр движка таблицы — столбец с версией. При слиянии для всех строк с одинаковым значением первичного ключа оставляет только одну строку: если задан столбец версии — строку с максимальной версией, иначе — последнюю строку. -Столбец с версией должен иметь тип из семейства `UInt`, либо `Date` или `DateTime`. +Столбец с версией должен иметь тип из семейства `UInt`, или `Date`, или `DateTime`. ```sql ReplacingMergeTree(EventDate, (OrderID, EventDate, BannerID, ...), 8192, ver) ``` -Обратите внимание, что дедупликация данных производится лишь во время слияний. Слияние происходят в фоне, в неизвестный момент времени, на который вы не можете ориентироваться. Некоторая часть данных может так и остаться необработанной. Хотя вы можете вызвать внеочередное слияние с помощью запроса OPTIMIZE, на это не стоит рассчитывать, так как запрос OPTIMIZE приводит к чтению и записи большого объёма данных. +Обратите внимание, что дедупликация данных производится лишь во время слияний. Слияние происходят в фоне в неизвестный момент времени, на который вы не можете ориентироваться. Некоторая часть данных может так и остаться необработанной. Хотя вы можете вызвать внеочередное слияние с помощью запроса OPTIMIZE, на это не стоит рассчитывать, так как запрос OPTIMIZE приводит к чтению и записи большого объёма данных. Таким образом, `ReplacingMergeTree` подходит для фоновой чистки дублирующихся данных в целях экономии места, но не даёт гарантий отсутствия дубликатов. From 12d9c30d2b28783e61355bcbed13cb560fd3d298 Mon Sep 17 00:00:00 2001 From: Valera Ryaboshapko Date: Thu, 15 Mar 2018 16:26:19 +0300 Subject: [PATCH 099/244] Update merge.md --- docs/ru/table_engines/merge.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/ru/table_engines/merge.md b/docs/ru/table_engines/merge.md index b3d9ced8f89..661d979fdf5 100644 --- a/docs/ru/table_engines/merge.md +++ b/docs/ru/table_engines/merge.md @@ -2,33 +2,33 @@ Движок Merge (не путайте с движком `MergeTree`) не хранит данные самостоятельно, а позволяет читать одновременно из произвольного количества других таблиц. Чтение автоматически распараллеливается. Запись в таблицу не поддерживается. При чтении будут использованы индексы тех таблиц, из которых реально идёт чтение, если они существуют. -Движок Merge принимает параметры: имя базы данных и регулярное выражение для таблиц. Пример: +Движок Merge принимает параметры: имя базы данных и регулярное выражение для таблиц. Пример. ```text Merge(hits, '^WatchLog') ``` -- данные будут читаться из таблиц в базе hits, имена которых соответствуют регулярному выражению '`^WatchLog`'. +Данные будут читаться из таблиц в базе hits, имена которых соответствуют регулярному выражению '`^WatchLog`'. Вместо имени базы данных может использоваться константное выражение, возвращающее строку. Например, `currentDatabase()`. -Регулярные выражения - re2 (как PCRE, но без особых извратов), регистрозависимые. +Регулярные выражения — [re2](https://github.com/google/re2) (облегчённая версия PCRE), регистрозависимые. Смотрите замечание об экранировании в регулярных выражениях в разделе "match". -При выборе таблиц для чтения, сама Merge-таблица не будет выбрана, даже если попадает под регулярное выражение - чтобы не возникло циклов. -Впрочем, вы можете создать две Merge-таблицы, которые будут пытаться бесконечно читать данные друг-друга. Этого делать не нужно. +При выборе таблиц для чтения, сама Merge-таблица не будет выбрана, даже если попадает под регулярное выражение, чтобы не возникло циклов. +Впрочем, вы можете создать две Merge-таблицы, которые будут пытаться бесконечно читать данные друг друга, но делать этого не нужно. -Типичный способ использования движка Merge - возможность работы с большим количеством таблиц типа TinyLog, как с одной. +Типичный способ использования движка Merge — работа с большим количеством таблиц типа TinyLog, как с одной. ## Виртуальные столбцы -Виртуальные столбцы - столбцы, предоставляемые движком таблиц, независимо от определения таблицы. То есть, такие столбцы не указываются в CREATE TABLE, но доступны для SELECT-а. +Виртуальные столбцы — столбцы, предоставляемые движком таблиц независимо от определения таблицы. То есть, такие столбцы не указываются в CREATE TABLE, но доступны для SELECT-а. Виртуальные столбцы отличаются от обычных следующими особенностями: - они не указываются в определении таблицы; - в них нельзя вставить данные при INSERT-е; -- при INSERT-е без указания списка столбцов, виртуальные столбцы не учитываются; +- при INSERT-е без указания списка столбцов виртуальные столбцы не учитываются; - они не выбираются при использовании звёздочки (`SELECT *`); - виртуальные столбцы не показываются в запросах `SHOW CREATE TABLE` и `DESC TABLE`; From d9848d89047519f51626eef0882f4be69c483b19 Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 15 Mar 2018 18:09:44 +0300 Subject: [PATCH 100/244] Allow run test under gdb --- dbms/tests/clickhouse-test-server | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dbms/tests/clickhouse-test-server b/dbms/tests/clickhouse-test-server index b3c9e4eaae5..778dc29b041 100755 --- a/dbms/tests/clickhouse-test-server +++ b/dbms/tests/clickhouse-test-server @@ -28,20 +28,33 @@ mkdir -p $LOG_DIR openssl dhparam -out `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.dhParamsFile` 256 openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.privateKeyFile` -out `${BIN_DIR}clickhouse-extract-from-config --config=$CLICKHOUSE_CONFIG --key=openSSL.server.certificateFile` +if [ "$TEST_GDB" ]; then + echo -e "run \nset pagination off \nset logging file $DATA_DIR/gdb.log \nset logging on \nthread apply all backtrace \ndetach \nquit " > $DATA_DIR/gdb.cmd + GDB="gdb -x $DATA_DIR/gdb.cmd --args " +fi + # Start a local clickhouse server which will be used to run tests #PATH=$PATH:$BIN_DIR \ -${BIN_DIR}clickhouse-server --config-file=${CLICKHOUSE_CONFIG} > $LOG_DIR/stdout 2>&1 & +$GDB ${BIN_DIR}clickhouse-server --config-file=${CLICKHOUSE_CONFIG} > $LOG_DIR/stdout 2>&1 & CH_PID=$! sleep 3 +if [ "$GDB" ]; then + # Long symbols read + sleep 40 +fi + tail -n50 $LOG_DIR/* # Define needed stuff to kill test clickhouse server after tests completion function finish { - kill $CH_PID || true - wait - tail -n 50 $LOG_DIR/stdout - rm -rf $DATA_DIR + kill $CH_PID || true + wait + tail -n 50 $LOG_DIR/* + if [ "$GDB" ]; then + cat $DATA_DIR/gdb.log || true + fi + rm -rf $DATA_DIR } trap finish EXIT SIGINT SIGQUIT SIGTERM From 1656eafd8ce561c66829455f59e8044d50b65055 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 15 Mar 2018 19:22:43 +0300 Subject: [PATCH 101/244] Revert "Attempt to fix regression: missing support for remote tables in IN section when querying Distributed tables [#CLICKHOUSE-2]" This reverts commit d52f688883fe2a703dd83164dc172b76745d8e0f. --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 5 ----- .../Interpreters/InterpreterSelectQuery.cpp | 3 +-- dbms/src/Storages/IStorage.h | 14 ------------- dbms/src/Storages/StorageDistributed.cpp | 20 ------------------- dbms/src/Storages/StorageDistributed.h | 6 ------ 5 files changed, 1 insertion(+), 47 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 5360e750a33..f0bc8137029 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -61,8 +61,6 @@ #include #include -#include - namespace DB { @@ -2440,9 +2438,6 @@ bool ExpressionAnalyzer::appendWhere(ExpressionActionsChain & chain, bool only_t initChain(chain, source_columns); ExpressionActionsChain::Step & step = chain.steps.back(); - DUMP(only_types); - DUMP(StackTrace().toString()); - step.required_output.push_back(select_query->where_expression->getColumnName()); getRootActions(select_query->where_expression, only_types, false, step.actions); diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 1f6aeb9d3c5..49b3ba27004 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -676,8 +676,7 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(Pipeline pipeline.streams = storage->read(required_columns, query_info, context, from_stage, max_block_size, max_streams); if (pipeline.streams.empty()) - pipeline.streams.emplace_back(std::make_shared( - storage->analyze(required_columns, query_info, context, from_stage))); + pipeline.streams.emplace_back(std::make_shared(storage->getSampleBlockForColumns(required_columns))); pipeline.transform([&](auto & stream) { diff --git a/dbms/src/Storages/IStorage.h b/dbms/src/Storages/IStorage.h index b30aeb2bfb8..ef9fd8004ce 100644 --- a/dbms/src/Storages/IStorage.h +++ b/dbms/src/Storages/IStorage.h @@ -180,20 +180,6 @@ public: throw Exception("Method read is not supported by storage " + getName(), ErrorCodes::NOT_IMPLEMENTED); } - /** Without executing a query determine, - * what structure of result and what query processed stage - * we will get if we will call 'read' method. - */ - virtual Block analyze( - const Names & column_names, - const SelectQueryInfo & /*query_info*/, - const Context & /*context*/, - QueryProcessingStage::Enum & processed_stage) - { - processed_stage = QueryProcessingStage::FetchColumns; - return getSampleBlockForColumns(column_names); - } - /** Writes the data to a table. * Receives a description of the query, which can contain information about the data write method. * Returns an object by which you can write data sequentially. diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index f73f23e5a13..2b1dfe66523 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -197,26 +197,6 @@ BlockInputStreams StorageDistributed::read( } -Block StorageDistributed::analyze( - const Names & /*column_names*/, - const SelectQueryInfo & query_info, - const Context & context, - QueryProcessingStage::Enum & processed_stage) -{ - auto cluster = getCluster(); - - const Settings & settings = context.getSettingsRef(); - - size_t result_size = (cluster->getRemoteShardCount() * settings.max_parallel_replicas) + cluster->getLocalShardCount(); - - processed_stage = result_size == 1 || settings.distributed_group_by_no_merge - ? QueryProcessingStage::Complete - : QueryProcessingStage::WithMergeableState; - - return materializeBlock(InterpreterSelectQuery(query_info.query, context, {}, processed_stage).getSampleBlock()); -} - - BlockOutputStreamPtr StorageDistributed::write(const ASTPtr & query, const Settings & settings) { auto cluster = (owned_cluster) ? owned_cluster : context.getCluster(cluster_name); diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 63fefbfe501..451c9f12d8a 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -60,12 +60,6 @@ public: size_t max_block_size, unsigned num_streams) override; - Block analyze( - const Names & column_names, - const SelectQueryInfo & query_info, - const Context & context, - QueryProcessingStage::Enum & processed_stage) override; - BlockOutputStreamPtr write(const ASTPtr & query, const Settings & settings) override; void drop() override {} From 16dad209f7ffd91d0d2b38fffff548044ed7a0e7 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Thu, 15 Mar 2018 20:04:47 +0300 Subject: [PATCH 102/244] Do not make extra ZK RTTs in inserts. [#CLICKHOUSE-3] Resolves #2054 --- dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h | 6 ++++++ .../MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp | 3 +++ 2 files changed, 9 insertions(+) diff --git a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h index 690217302bf..75c2c01eaaf 100644 --- a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h +++ b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h @@ -108,6 +108,12 @@ public: ops.emplace_back(std::make_shared(holder_path, -1)); } + /// Do not delete nodes in destructor + void setIsUnlocked() + { + holder_path = ""; + } + void checkCreated() const { if (!isCreated()) diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp index 7e8ae99cad2..22fb1794756 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp @@ -370,6 +370,9 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo { transaction.commit(); storage.merge_selecting_event.set(); + + /// Lock nodes have been already deleted, do not delete them in destructor + block_number_lock.setIsUnlocked(); } else if (zkutil::isUserError(info.code)) { From e77701bd4bd6b6a205445abc1a21b90cb38ffd99 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Thu, 15 Mar 2018 19:57:10 +0300 Subject: [PATCH 103/244] Enable alisas for sets and tuples for IN operator. [#CLICKHOUSE-3] Resolves #2044 --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 3 ++- .../queries/0_stateless/00172_constexprs_in_set.reference | 1 + dbms/tests/queries/0_stateless/00172_constexprs_in_set.sql | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index f0bc8137029..411c868d6f0 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -980,7 +980,8 @@ void ExpressionAnalyzer::normalizeTreeImpl( /// `IN t` can be specified, where t is a table, which is equivalent to `IN (SELECT * FROM t)`. if (functionIsInOrGlobalInOperator(func_node->name)) if (ASTIdentifier * right = typeid_cast(func_node->arguments->children.at(1).get())) - right->kind = ASTIdentifier::Table; + if (!aliases.count(right->name)) + right->kind = ASTIdentifier::Table; /// Special cases for count function. String func_name_lowercase = Poco::toLower(func_node->name); diff --git a/dbms/tests/queries/0_stateless/00172_constexprs_in_set.reference b/dbms/tests/queries/0_stateless/00172_constexprs_in_set.reference index c06d3de5a56..ac284bbc084 100644 --- a/dbms/tests/queries/0_stateless/00172_constexprs_in_set.reference +++ b/dbms/tests/queries/0_stateless/00172_constexprs_in_set.reference @@ -4,3 +4,4 @@ 1 1 1 +1 0 diff --git a/dbms/tests/queries/0_stateless/00172_constexprs_in_set.sql b/dbms/tests/queries/0_stateless/00172_constexprs_in_set.sql index 3c438417053..5d79185ee8d 100644 --- a/dbms/tests/queries/0_stateless/00172_constexprs_in_set.sql +++ b/dbms/tests/queries/0_stateless/00172_constexprs_in_set.sql @@ -4,3 +4,4 @@ SELECT toDate('2015-06-12') IN (toDate('2015-06-12')); SELECT today() IN (toDate('2014-01-01'), toDate(now())); SELECT - -1 IN (2 - 1); SELECT - -1 IN (2 - 1, 3); +WITH (1, 2) AS a SELECT 1 IN a, 3 IN a; From 2097ee9a825ecbde1ac6ddcad93d34749ce9aa63 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Thu, 15 Mar 2018 21:44:04 +0300 Subject: [PATCH 104/244] Update merge.md --- docs/ru/table_engines/merge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/table_engines/merge.md b/docs/ru/table_engines/merge.md index 661d979fdf5..1124e54b5bb 100644 --- a/docs/ru/table_engines/merge.md +++ b/docs/ru/table_engines/merge.md @@ -12,7 +12,7 @@ Merge(hits, '^WatchLog') Вместо имени базы данных может использоваться константное выражение, возвращающее строку. Например, `currentDatabase()`. -Регулярные выражения — [re2](https://github.com/google/re2) (облегчённая версия PCRE), регистрозависимые. +Регулярные выражения — [re2](https://github.com/google/re2) (поддерживает подмножество PCRE), регистрозависимые. Смотрите замечание об экранировании в регулярных выражениях в разделе "match". При выборе таблиц для чтения, сама Merge-таблица не будет выбрана, даже если попадает под регулярное выражение, чтобы не возникло циклов. From 1554390baba5bfcb7b53054a589c212b377c38dd Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Thu, 15 Mar 2018 22:05:58 +0300 Subject: [PATCH 105/244] Update AbandonableLockInZooKeeper.h --- dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h index 75c2c01eaaf..b1c82483e38 100644 --- a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h +++ b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h @@ -108,8 +108,9 @@ public: ops.emplace_back(std::make_shared(holder_path, -1)); } - /// Do not delete nodes in destructor - void setIsUnlocked() + /// Do not delete nodes in destructor. You may call this method after 'getUnlockOps' and successful execution of these ops, + /// because the nodes will be already deleted. + void assumeUnlocked() { holder_path = ""; } From e64b2df87492d0cb1da61c1101e4d5d45f16fec3 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Thu, 15 Mar 2018 22:06:23 +0300 Subject: [PATCH 106/244] Update ReplicatedMergeTreeBlockOutputStream.cpp --- .../Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp index 22fb1794756..1d5ec76c652 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp @@ -372,7 +372,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo storage.merge_selecting_event.set(); /// Lock nodes have been already deleted, do not delete them in destructor - block_number_lock.setIsUnlocked(); + block_number_lock.assumeUnlocked(); } else if (zkutil::isUserError(info.code)) { From 1e88f2fe5c44d8b649eee658b04be8670a140ea7 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Thu, 15 Mar 2018 22:06:53 +0300 Subject: [PATCH 107/244] Update AbandonableLockInZooKeeper.h --- dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h index b1c82483e38..35f56fa429f 100644 --- a/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h +++ b/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h @@ -112,7 +112,7 @@ public: /// because the nodes will be already deleted. void assumeUnlocked() { - holder_path = ""; + holder_path.clear(); } void checkCreated() const From 8a432e40b95105c3cfa65b9d6d004d7410ddafe5 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Thu, 15 Mar 2018 22:24:20 +0300 Subject: [PATCH 108/244] Fixed 569 test. [#CLICKHOUSE-2] --- .../0_stateless/00569_parse_date_time_best_effort.reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference b/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference index c0ad225ca1e..38264a337f0 100644 --- a/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference +++ b/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference @@ -7,7 +7,7 @@ s a b 02/01/17 010203 MSK 2017-01-01 22:02:03 2017-01-01 22:02:03 02/01/17 010203 MSK+0100 2017-01-01 21:02:03 2017-01-01 21:02:03 02/01/17 010203 UTC+0300 2017-01-01 22:02:03 2017-01-01 22:02:03 -020117 010203 UTC+0300 1970-01-01 84:30:19 1970-01-01 84:30:19 +020117 010203 UTC+0300 1970-01-01 04:30:19 1970-01-01 04:30:19 02/01/17 010203Z 2017-01-02 01:02:03 2017-01-02 01:02:03 02/01/1970 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03 02/01/70 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03 From b2e4fd30981f9bd700f25dc3bd0adbbbc2a0259e Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 15 Mar 2018 22:29:53 +0300 Subject: [PATCH 109/244] Updated test [#CLICKHOUSE-2] --- .../0_stateless/00569_parse_date_time_best_effort.reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference b/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference index c0ad225ca1e..38264a337f0 100644 --- a/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference +++ b/dbms/tests/queries/0_stateless/00569_parse_date_time_best_effort.reference @@ -7,7 +7,7 @@ s a b 02/01/17 010203 MSK 2017-01-01 22:02:03 2017-01-01 22:02:03 02/01/17 010203 MSK+0100 2017-01-01 21:02:03 2017-01-01 21:02:03 02/01/17 010203 UTC+0300 2017-01-01 22:02:03 2017-01-01 22:02:03 -020117 010203 UTC+0300 1970-01-01 84:30:19 1970-01-01 84:30:19 +020117 010203 UTC+0300 1970-01-01 04:30:19 1970-01-01 04:30:19 02/01/17 010203Z 2017-01-02 01:02:03 2017-01-02 01:02:03 02/01/1970 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03 02/01/70 010203Z 1970-01-02 01:02:03 1970-01-02 01:02:03 From cc19e40fa02b8519e0238c6f863a722f8fa0726a Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Fri, 16 Mar 2018 00:07:09 +0300 Subject: [PATCH 110/244] Auto version update to [54366] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 49bda24e075..80e9aaf2e57 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54365-testing) -set(VERSION_REVISION 54365) +set(VERSION_DESCRIBE v1.1.54366-testing) +set(VERSION_REVISION 54366) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 8ee6e628a17..6f142ef0c16 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54365) unstable; urgency=low +clickhouse (1.1.54366) unstable; urgency=low * Modified source code - -- Wed, 14 Mar 2018 16:50:31 +0300 + -- Fri, 16 Mar 2018 00:07:09 +0300 From 3a8d6c28ef6333c3f7e3e168978ba73d5eee594a Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 00:44:09 +0300 Subject: [PATCH 111/244] Attempt to fix a regression [#CLICKHOUSE-2] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 411c868d6f0..ca9bc493566 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1580,7 +1580,7 @@ void ExpressionAnalyzer::makeSet(const ASTFunction * node, const Block & sample_ * in the subquery_for_set object, this subquery is set as source and the temporary table _data1 as the table. * - this function shows the expression IN_data1. */ - if (!subquery_for_set.source) + if (!subquery_for_set.source && (!storage || !storage->isRemote())) { auto interpreter = interpretSubquery(arg, context, subquery_depth, {}); subquery_for_set.source = std::make_shared( From 9017f1d66427e14b17c77c4f4e6b175baec84bb7 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 16 Mar 2018 02:22:36 +0300 Subject: [PATCH 112/244] Update query_complexity.md --- docs/ru/operations/settings/query_complexity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/operations/settings/query_complexity.md b/docs/ru/operations/settings/query_complexity.md index c964ad6e41c..3c4ae65b370 100644 --- a/docs/ru/operations/settings/query_complexity.md +++ b/docs/ru/operations/settings/query_complexity.md @@ -33,7 +33,7 @@ Максимальный возможный объем оперативной памяти для выполнения запроса на одном сервере. -Значения по умолчанию определены в файле [Settings.h](https://github.com/yandex/ClickHouse/blob/master/dbms/src/Interpreters/Settings.h#L243). По умолчанию размер не ограничен (`max_memory_usage = 0`). +В конфигурационном файле по-умолчанию, ограничение равно 10 ГБ. Настройка не учитывает объём свободной памяти или общий объём памяти на машине. Ограничение действует на один запрос, в пределах одного сервера. From 70ab16e864239c3baff6148716854cf0d51f754b Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 16 Mar 2018 02:23:13 +0300 Subject: [PATCH 113/244] Update query_complexity.md --- docs/ru/operations/settings/query_complexity.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/ru/operations/settings/query_complexity.md b/docs/ru/operations/settings/query_complexity.md index 3c4ae65b370..afbba3bc688 100644 --- a/docs/ru/operations/settings/query_complexity.md +++ b/docs/ru/operations/settings/query_complexity.md @@ -40,10 +40,7 @@ Текущее потребление памяти для каждого запроса можно посмотреть с помощью `SHOW PROCESSLIST`. Также отслеживается и выводится в лог пиковое потребление памяти для каждого запроса. -Потребление памяти не отслеживается для: - -- Констант. -- Состояний некоторых агрегатных функций. +Потребление памяти не отслеживается для состояний некоторых агрегатных функций. Потребление памяти не полностью учитывается для состояний агрегатных функций `min`, `max`, `any`, `anyLast`, `argMin`, `argMax` от аргументов `String` и `Array`. From bbb101845aedfd3cc1731291df3cdd70faa21038 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 16 Mar 2018 02:24:21 +0300 Subject: [PATCH 114/244] Update replication.md --- docs/ru/table_engines/replication.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ru/table_engines/replication.md b/docs/ru/table_engines/replication.md index 970e431370e..0a2aa2e1e71 100644 --- a/docs/ru/table_engines/replication.md +++ b/docs/ru/table_engines/replication.md @@ -4,12 +4,12 @@ Репликация поддерживается только для таблиц семейства MergeTree: +- ReplicatedMergeTree +- ReplicatedSummingMergeTree +- ReplicatedReplacingMergeTree - ReplicatedAggregatingMergeTree - ReplicatedCollapsingMergeTree - ReplicatedGraphiteMergeTree -- ReplicatedMergeTree -- ReplicatedReplacingMergeTree -- ReplicatedSummingMergeTree Репликация работает на уровне отдельных таблиц, а не всего сервера. То есть, на сервере могут быть расположены одновременно реплицируемые и не реплицируемые таблицы. From 93c0dd3f428563a62dbc9d9ddfc98828bd12f899 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 16 Mar 2018 02:25:57 +0300 Subject: [PATCH 115/244] Update replication.md --- docs/ru/table_engines/replication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/table_engines/replication.md b/docs/ru/table_engines/replication.md index 0a2aa2e1e71..8bdd9c13c36 100644 --- a/docs/ru/table_engines/replication.md +++ b/docs/ru/table_engines/replication.md @@ -42,7 +42,7 @@ ``` -Используйте ZooKeeper 3.4.5 и больше. +Используйте ZooKeeper версии 3.4.5 или более новый. Можно указать любой имеющийся у вас ZooKeeper-кластер - система будет использовать в нём одну директорию для своих данных (директория указывается при создании реплицируемой таблицы). From ee88475c5b87d39ae9c11b76e2113bd0ed58682e Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 16 Mar 2018 02:30:26 +0300 Subject: [PATCH 116/244] Update replication.md --- docs/ru/table_engines/replication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/table_engines/replication.md b/docs/ru/table_engines/replication.md index 8bdd9c13c36..30d8882d4eb 100644 --- a/docs/ru/table_engines/replication.md +++ b/docs/ru/table_engines/replication.md @@ -56,7 +56,7 @@ Репликация асинхронная, мульти-мастер. Запросы `INSERT` (а также `ALTER`) можно отправлять на любой доступный сервер. Данные вставятся на сервер, где выполнен запрос, а затем скопируются на остальные серверы. В связи с асинхронностью, только что вставленные данные появляются на остальных репликах с небольшой задержкой. Если часть реплик недоступна, данные на них запишутся тогда, когда они станут доступны. Если реплика доступна, то задержка составляет столько времени, сколько требуется для передачи блока сжатых данных по сети. -Кворумная запись отсутствует. Вы можете записать данные с подтвержением только от одной реплики. Если вы записали данные на одну реплику, а сервер с этой репликой перестал существовать, то записанные данные будут потеряны, если репликация еще не завершилась. +По-умолчанию, запрос INSERT ждёт подтверждения записи только от одной реплики. Если данные были успешно записаны только на одну реплику, и сервер с этой репликой перестал существовать, то записанные данные будут потеряны. Вы можете включить подтверждение записи от нескольких реплик, используя настройку `insert_quorum`. Каждый блок данных записывается атомарно. Запрос INSERT разбивается на блоки данных размером до `max_insert_block_size = 1048576` строк. То есть, если в запросе `INSERT` менее 1048576 строк, то он делается атомарно. From b949865d34f858c53f89e23409c833ea998940d2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 04:06:02 +0300 Subject: [PATCH 117/244] Added configuration for ad-hoc testing purposes [#CLICKHOUSE-2]. --- dbms/src/Server/config.d/more_clusters.xml | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 dbms/src/Server/config.d/more_clusters.xml diff --git a/dbms/src/Server/config.d/more_clusters.xml b/dbms/src/Server/config.d/more_clusters.xml new file mode 100644 index 00000000000..ca31b883540 --- /dev/null +++ b/dbms/src/Server/config.d/more_clusters.xml @@ -0,0 +1,44 @@ + + + + + + + localhost + 9001 + + + + + + + + localhost + 9001 + + + + + localhost + 9002 + + + + + + + + localhost + 9000 + + + + + localhost + 9001 + + + + + + From ace7046acb0bc81d11ecb1e9b96ce000da5ec2b9 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 04:09:31 +0300 Subject: [PATCH 118/244] Added comment [#CLICKHOUSE-2]. --- dbms/src/Server/config.d/more_clusters.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dbms/src/Server/config.d/more_clusters.xml b/dbms/src/Server/config.d/more_clusters.xml index ca31b883540..aecbf9e0ba7 100644 --- a/dbms/src/Server/config.d/more_clusters.xml +++ b/dbms/src/Server/config.d/more_clusters.xml @@ -1,6 +1,11 @@ + + From e845d3456988df9d196733ac189434bb5c184579 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 04:15:50 +0300 Subject: [PATCH 119/244] Miscellaneous [#CLICKHOUSE-2] --- dbms/tests/integration/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/integration/README.md b/dbms/tests/integration/README.md index 0f8f615b616..cc704022e79 100644 --- a/dbms/tests/integration/README.md +++ b/dbms/tests/integration/README.md @@ -5,7 +5,7 @@ This directory contains tests that involve several ClickHouse instances, custom ### Running Prerequisites: -* Ubuntu 14.04 (Trusty). +* Ubuntu 14.04 (Trusty) or higher. * [docker](https://www.docker.com/community-edition#/download). Minimum required API version: 1.25, check with `docker version`. You must install latest Docker from From a16dd1cee73312da30cfd8f3a8122391a801b640 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 04:22:02 +0300 Subject: [PATCH 120/244] Little better [#CLICKHOUSE-3650] --- .../Functions/FunctionsExternalDictionaries.h | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/dbms/src/Functions/FunctionsExternalDictionaries.h b/dbms/src/Functions/FunctionsExternalDictionaries.h index cb77d84b751..b921ba50b9a 100644 --- a/dbms/src/Functions/FunctionsExternalDictionaries.h +++ b/dbms/src/Functions/FunctionsExternalDictionaries.h @@ -76,6 +76,9 @@ public: private: size_t getNumberOfArguments() const override { return 2; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; } + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!arguments[0]->isString()) @@ -135,15 +138,6 @@ private: dict->has(ids, out->getData()); block.getByPosition(result).column = std::move(out); } - else if (const auto id_col = checkAndGetColumnConst>(id_col_untyped)) - { - const PaddedPODArray ids(1, id_col->getValue()); - PaddedPODArray out(1); - - dict->has(ids, out); - - block.getByPosition(result).column = DataTypeUInt8().createColumnConst(id_col->size(), toField(out.front())); - } else throw Exception{ "Second argument of function " + getName() + " must be UInt64", @@ -161,11 +155,7 @@ private: return false; const ColumnWithTypeAndName & key_col_with_type = block.getByPosition(arguments[1]); - ColumnPtr key_col = key_col_with_type.column; - - /// Functions in external dictionaries only support full-value (not constant) columns with keys. - if (ColumnPtr key_col_materialized = key_col_with_type.column->convertToFullColumnIfConst()) - key_col = key_col_materialized; + const ColumnPtr & key_col = key_col_with_type.column; if (checkColumn(key_col.get())) { From b5e4d0692a6794d9ef07b0476d294c6be2ff526a Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 04:23:37 +0300 Subject: [PATCH 121/244] Disallow PREWHERE, SAMPLE, FINAL in MATERIALIZED VIEWs [#CLICKHOUSE-2]. --- dbms/src/Common/ErrorCodes.cpp | 1 + dbms/src/Storages/StorageMaterializedView.cpp | 32 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index 6c07a5e3422..46b4c3394e5 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -372,6 +372,7 @@ namespace ErrorCodes extern const int QUERY_WAS_CANCELLED = 394; extern const int FUNCTION_THROW_IF_VALUE_IS_NON_ZERO = 395; extern const int TOO_MANY_ROWS_OR_BYTES = 396; + extern const int QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW = 397; extern const int KEEPER_EXCEPTION = 999; diff --git a/dbms/src/Storages/StorageMaterializedView.cpp b/dbms/src/Storages/StorageMaterializedView.cpp index 1146028830b..ccdbcf204fc 100644 --- a/dbms/src/Storages/StorageMaterializedView.cpp +++ b/dbms/src/Storages/StorageMaterializedView.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -22,6 +23,7 @@ namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int INCORRECT_QUERY; + extern const int QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW; } @@ -46,7 +48,7 @@ static void extractDependentTable(ASTSelectQuery & query, String & select_databa else if (auto ast_select = typeid_cast(query_table.get())) { if (ast_select->list_of_selects->children.size() != 1) - throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::INCORRECT_QUERY); + throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); auto & inner_query = ast_select->list_of_selects->children.at(0); @@ -59,6 +61,28 @@ static void extractDependentTable(ASTSelectQuery & query, String & select_databa } +static void checkAllowedQueries(const ASTSelectQuery & query) +{ + if (query.prewhere_expression || query.final() || query.sample_size()) + throw Exception("MATERIALIZED VIEW cannot have PREWHERE, SAMPLE or FINAL.", DB::ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); + + auto query_table = query.table(); + + if (!query_table) + return; + + if (auto ast_select = typeid_cast(query_table.get())) + { + if (ast_select->list_of_selects->children.size() != 1) + throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); + + const auto & inner_query = ast_select->list_of_selects->children.at(0); + + checkAllowedQueries(typeid_cast(*inner_query)); + } +} + + StorageMaterializedView::StorageMaterializedView( const String & table_name_, const String & database_name_, @@ -80,11 +104,13 @@ StorageMaterializedView::StorageMaterializedView( /// Default value, if only table name exist in the query select_database_name = local_context.getCurrentDatabase(); if (query.select->list_of_selects->children.size() != 1) - throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::INCORRECT_QUERY); + throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); inner_query = query.select->list_of_selects->children.at(0); - extractDependentTable(typeid_cast(*inner_query), select_database_name, select_table_name); + ASTSelectQuery & select_query = typeid_cast(*inner_query); + extractDependentTable(select_query, select_database_name, select_table_name); + checkAllowedQueries(select_query); if (!select_table_name.empty()) global_context.addDependency( From 25a691f03d906d872ef4d99353bf83ed53fa9561 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 05:08:31 +0300 Subject: [PATCH 122/244] Don't allow Distributed table that look at itself [#CLICKHOUSE-2919]. --- .../Interpreters/InterpreterSelectQuery.cpp | 4 +++ dbms/src/Storages/StorageDistributed.cpp | 31 +++++++++++++------ dbms/src/Storages/StorageDistributed.h | 6 ++-- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 49b3ba27004..ec6b9395701 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -63,6 +63,7 @@ namespace ErrorCodes extern const int ILLEGAL_PREWHERE; extern const int TOO_MANY_COLUMNS; extern const int LOGICAL_ERROR; + extern const int NOT_IMPLEMENTED; } InterpreterSelectQuery::InterpreterSelectQuery( @@ -338,6 +339,9 @@ void InterpreterSelectQuery::executeImpl(Pipeline & pipeline, const BlockInputSt /** Read the data from Storage. from_stage - to what stage the request was completed in Storage. */ QueryProcessingStage::Enum from_stage = executeFetchColumns(pipeline, dry_run); + if (from_stage == QueryProcessingStage::WithMergeableState && to_stage == QueryProcessingStage::WithMergeableState) + throw Exception("Distributed on Distributed is not supported", ErrorCodes::NOT_IMPLEMENTED); + if (!dry_run) LOG_TRACE(log, QueryProcessingStage::toString(from_stage) << " -> " << QueryProcessingStage::toString(to_stage)); diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 2b1dfe66523..e239ae3d65e 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -52,6 +52,7 @@ namespace ErrorCodes extern const int READONLY; extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int INCORRECT_NUMBER_OF_COLUMNS; + extern const int INFINITE_LOOP; } @@ -130,14 +131,16 @@ StorageDistributed::~StorageDistributed() = default; StorageDistributed::StorageDistributed( - const std::string & table_name_, + const String & database_name, + const String & table_name_, const ColumnsDescription & columns_, const String & remote_database_, const String & remote_table_, const String & cluster_name_, const Context & context_, const ASTPtr & sharding_key_, - const String & data_path_) + const String & data_path_, + bool attach) : IStorage{columns_}, table_name(table_name_), remote_database(remote_database_), remote_table(remote_table_), @@ -146,6 +149,13 @@ StorageDistributed::StorageDistributed( sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(table_name) + '/')) { + /// Sanity check. Skip check if the table is already created to allow the server to start. + if (!attach && !cluster_name.empty()) + { + size_t num_local_shards = context.getCluster(cluster_name)->getLocalShardCount(); + if (num_local_shards && remote_database == database_name && remote_table == table_name) + throw Exception("Distributed table " + table_name + " looks at itself", ErrorCodes::INFINITE_LOOP); + } } @@ -158,7 +168,7 @@ StoragePtr StorageDistributed::createWithOwnCluster( const Context & context_) { auto res = ext::shared_ptr_helper::create( - name_, columns_, remote_database_, remote_table_, String{}, context_, ASTPtr(), String()); + String{}, name_, columns_, remote_database_, remote_table_, String{}, context_, ASTPtr(), String(), false); res->owned_cluster = owned_cluster_; @@ -178,7 +188,9 @@ BlockInputStreams StorageDistributed::read( const Settings & settings = context.getSettingsRef(); - size_t result_size = (cluster->getRemoteShardCount() * settings.max_parallel_replicas) + cluster->getLocalShardCount(); + size_t num_local_shards = cluster->getLocalShardCount(); + size_t num_remote_shards = cluster->getRemoteShardCount(); + size_t result_size = (num_remote_shards * settings.max_parallel_replicas) + num_local_shards; processed_stage = result_size == 1 || settings.distributed_group_by_no_merge ? QueryProcessingStage::Complete @@ -199,7 +211,7 @@ BlockInputStreams StorageDistributed::read( BlockOutputStreamPtr StorageDistributed::write(const ASTPtr & query, const Settings & settings) { - auto cluster = (owned_cluster) ? owned_cluster : context.getCluster(cluster_name); + auto cluster = getCluster(); /// Ban an attempt to make async insert into the table belonging to DatabaseMemory if (path.empty() && !owned_cluster && !settings.insert_distributed_sync.value) @@ -327,13 +339,13 @@ ConnectionPoolPtr StorageDistributed::requireConnectionPool(const std::string & size_t StorageDistributed::getShardCount() const { - return getCluster()->getRemoteShardCount(); + return getCluster()->getShardCount(); } ClusterPtr StorageDistributed::getCluster() const { - return (owned_cluster) ? owned_cluster : context.getCluster(cluster_name); + return owned_cluster ? owned_cluster : context.getCluster(cluster_name); } void StorageDistributed::ClusterNodeData::requireConnectionPool(const std::string & name, const StorageDistributed & storage) @@ -400,9 +412,10 @@ void registerStorageDistributed(StorageFactory & factory) } return StorageDistributed::create( - args.table_name, args.columns, + args.database_name, args.table_name, args.columns, remote_database, remote_table, cluster_name, - args.context, sharding_key, args.data_path); + args.context, sharding_key, args.data_path, + args.attach); }); } diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 451c9f12d8a..41a11fa3199 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -130,14 +130,16 @@ public: protected: StorageDistributed( - const std::string & name_, + const String & database_name, + const String & table_name_, const ColumnsDescription & columns_, const String & remote_database_, const String & remote_table_, const String & cluster_name_, const Context & context_, const ASTPtr & sharding_key_, - const String & data_path_); + const String & data_path_, + bool attach); }; } From e272f6d79e9dbb2652771807d3a124e6ed19fdd4 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 06:03:17 +0300 Subject: [PATCH 123/244] Not a fix [#CLICKHOUSE-3650]. --- dbms/src/Common/isLocalAddress.h | 1 - .../Functions/FunctionsExternalDictionaries.h | 460 +++++------------- 2 files changed, 134 insertions(+), 327 deletions(-) diff --git a/dbms/src/Common/isLocalAddress.h b/dbms/src/Common/isLocalAddress.h index d90d7aef63a..981d343a97f 100644 --- a/dbms/src/Common/isLocalAddress.h +++ b/dbms/src/Common/isLocalAddress.h @@ -12,7 +12,6 @@ namespace Poco namespace DB { - /** Lets you check if the address is similar to `localhost`. * The purpose of this check is usually to make an assumption, * that when we go to this address via the Internet, we'll get to ourselves. diff --git a/dbms/src/Functions/FunctionsExternalDictionaries.h b/dbms/src/Functions/FunctionsExternalDictionaries.h index b921ba50b9a..abb8c518aa6 100644 --- a/dbms/src/Functions/FunctionsExternalDictionaries.h +++ b/dbms/src/Functions/FunctionsExternalDictionaries.h @@ -82,17 +82,13 @@ private: DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!arguments[0]->isString()) - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[1].get()) && !checkDataType(arguments[1].get())) - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() - + ", must be UInt64 or tuple(...).", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", must be UInt64 or tuple(...).", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; return std::make_shared(); } @@ -103,9 +99,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -116,9 +110,7 @@ private: !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -139,9 +131,7 @@ private: block.getByPosition(result).column = std::move(out); } else - throw Exception{ - "Second argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -167,9 +157,7 @@ private: block.getByPosition(result).column = std::move(out); } else - throw Exception{ - "Second argument of function " + getName() + " must be " + dict->getKeyDescription(), - ErrorCodes::TYPE_MISMATCH}; + throw Exception{"Second argument of function " + getName() + " must be " + dict->getKeyDescription(), ErrorCodes::TYPE_MISMATCH}; return true; } @@ -185,15 +173,11 @@ static bool isDictGetFunctionInjective(const ExternalDictionaries & dictionaries const auto dict_name_col = checkAndGetColumnConst(sample_block.getByPosition(0).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function dictGet... must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function dictGet... must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; const auto attr_name_col = checkAndGetColumnConst(sample_block.getByPosition(1).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function dictGet... must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function dictGet... must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; return dictionaries.getDictionary(dict_name_col->getValue())->isInjective(attr_name_col->getValue()); } @@ -217,6 +201,9 @@ private: bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 0; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 1}; } + bool isInjective(const Block & sample_block) override { return isDictGetFunctionInjective(dictionaries, sample_block); @@ -225,42 +212,33 @@ private: DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (arguments.size() != 3 && arguments.size() != 4) - throw Exception{ - "Number of arguments for function " + getName() + " doesn't match: passed " - + toString(arguments.size()) + ", should be 3 or 4.", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 3 or 4.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; if (!arguments[0]->isString()) { - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } if (!arguments[1]->isString()) { - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } if (!checkDataType(arguments[2].get()) && !checkDataType(arguments[2].get())) { - throw Exception{ - "Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() - + ", must be UInt64 or tuple(...).", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() + + ", must be UInt64 or tuple(...).", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } + /// This is for the case of range dictionaries. if (arguments.size() == 4 && !checkDataType(arguments[3].get())) { - throw Exception{ - "Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() - + ", must be Date.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() + + ", must be Date.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } return std::make_shared(); @@ -272,9 +250,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -286,9 +262,7 @@ private: !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchRange(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -300,16 +274,12 @@ private: return false; if (arguments.size() != 3) - throw Exception{ - "Function " + getName() + " for dictionary of type " + dict->getTypeName() + - " requires exactly 3 arguments", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Function " + getName() + " for dictionary of type " + dict->getTypeName() + + " requires exactly 3 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -320,19 +290,8 @@ private: dict->getString(attr_name, id_col->getData(), out.get()); block.getByPosition(result).column = std::move(out); } - else if (const auto id_col = checkAndGetColumnConst>(id_col_untyped)) - { - const PaddedPODArray ids(1, id_col->getValue()); - auto out = ColumnString::create(); - dict->getString(attr_name, ids, out.get()); - block.getByPosition(result).column = DataTypeString().createColumnConst(id_col->size(), out->getDataAt(0).toString()); - } else - { - throw Exception{ - "Third argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Third argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -346,16 +305,12 @@ private: return false; if (arguments.size() != 3) - throw Exception{ - "Function " + getName() + " for dictionary of type " + dict->getTypeName() + - " requires exactly 3 arguments", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Function " + getName() + " for dictionary of type " + dict->getTypeName() + + " requires exactly 3 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -376,9 +331,7 @@ private: block.getByPosition(result).column = std::move(out); } else - throw Exception{ - "Third argument of function " + getName() + " must be " + dict->getKeyDescription(), - ErrorCodes::TYPE_MISMATCH}; + throw Exception{"Third argument of function " + getName() + " must be " + dict->getKeyDescription(), ErrorCodes::TYPE_MISMATCH}; return true; } @@ -392,16 +345,12 @@ private: return false; if (arguments.size() != 4) - throw Exception{ - "Function " + getName() + " for dictionary of type " + dict->getTypeName() + - " requires exactly 4 arguments", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Function " + getName() + " for dictionary of type " + dict->getTypeName() + + " requires exactly 4 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -413,9 +362,7 @@ private: executeRange(block, result, dict, attr_name, id_col, date_col_untyped); else { - throw Exception{ - "Third argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Third argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; } return true; @@ -441,9 +388,7 @@ private: } else { - throw Exception{ - "Fourth argument of function " + getName() + " must be Date", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be Date", ErrorCodes::ILLEGAL_COLUMN}; } } @@ -470,9 +415,7 @@ private: } else { - throw Exception{ - "Fourth argument of function " + getName() + " must be Date", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be Date", ErrorCodes::ILLEGAL_COLUMN}; } } @@ -497,34 +440,29 @@ public: private: size_t getNumberOfArguments() const override { return 4; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 1}; } + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!arguments[0]->isString()) - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + - ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!arguments[1]->isString()) - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + - ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[2].get()) && !checkDataType(arguments[2].get())) { - throw Exception{ - "Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() - + ", must be UInt64 or tuple(...).", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() + + ", must be UInt64 or tuple(...).", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } if (!arguments[3]->isString()) - throw Exception{ - "Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() + - ", must be String.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; + throw Exception{"Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() + + ", must be String.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; return std::make_shared(); } @@ -535,9 +473,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -548,9 +484,7 @@ private: !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -563,9 +497,7 @@ private: const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -575,9 +507,7 @@ private: else if (const auto id_col = checkAndGetColumnConst>(id_col_untyped)) executeDispatch(block, arguments, result, dict, attr_name, id_col); else - throw Exception{ - "Third argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Third argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -607,9 +537,7 @@ private: block.getByPosition(result).column = std::move(out); } else - throw Exception{ - "Fourth argument of function " + getName() + " must be String", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be String", ErrorCodes::ILLEGAL_COLUMN}; } template @@ -638,9 +566,7 @@ private: block.getByPosition(result).column = DataTypeString().createColumnConst(id_col->size(), out->getDataAt(0).toString()); } else - throw Exception{ - "Fourth argument of function " + getName() + " must be String", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be String", ErrorCodes::ILLEGAL_COLUMN}; } template @@ -653,9 +579,7 @@ private: const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -682,9 +606,7 @@ private: dict->getString(attr_name, key_columns, key_types, def, out.get()); } else - throw Exception{ - "Fourth argument of function " + getName() + " must be String", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be String", ErrorCodes::ILLEGAL_COLUMN}; block.getByPosition(result).column = std::move(out); return true; @@ -771,6 +693,9 @@ private: bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 0; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 1}; } + bool isInjective(const Block & sample_block) override { return isDictGetFunctionInjective(dictionaries, sample_block); @@ -782,37 +707,21 @@ private: throw Exception{"Function " + getName() + " takes 3 or 4 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; if (!arguments[0]->isString()) - { - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!arguments[1]->isString()) - { - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[2].get()) && !checkDataType(arguments[2].get())) - { - throw Exception{ - "Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() - + ", must be UInt64 or tuple(...).", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() + + ", must be UInt64 or tuple(...).", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (arguments.size() == 4 && !checkDataType(arguments[3].get())) - { - throw Exception{ - "Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() - + ", must be Date.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() + + ", must be Date.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; return std::make_shared(); } @@ -823,9 +732,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -837,9 +744,7 @@ private: !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchRange(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -851,16 +756,12 @@ private: return false; if (arguments.size() != 3) - throw Exception{ - "Function " + getName() + " for dictionary of type " + dict->getTypeName() + - " requires exactly 3 arguments.", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Function " + getName() + " for dictionary of type " + dict->getTypeName() + + " requires exactly 3 arguments.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -881,11 +782,7 @@ private: block.getByPosition(result).column = DataTypeNumber().createColumnConst(id_col->size(), toField(data.front())); } else - { - throw Exception{ - "Third argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Third argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -899,16 +796,12 @@ private: return false; if (arguments.size() != 3) - throw Exception{ - "Function " + getName() + " for dictionary of type " + dict->getTypeName() + - " requires exactly 3 arguments", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Function " + getName() + " for dictionary of type " + dict->getTypeName() + + " requires exactly 3 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -930,9 +823,7 @@ private: block.getByPosition(result).column = std::move(out); } else - throw Exception{ - "Third argument of function " + getName() + " must be " + dict->getKeyDescription(), - ErrorCodes::TYPE_MISMATCH}; + throw Exception{"Third argument of function " + getName() + " must be " + dict->getKeyDescription(), ErrorCodes::TYPE_MISMATCH}; return true; } @@ -946,16 +837,12 @@ private: return false; if (arguments.size() != 4) - throw Exception{ - "Function " + getName() + " for dictionary of type " + dict->getTypeName() + - " requires exactly 4 arguments", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; + throw Exception{"Function " + getName() + " for dictionary of type " + dict->getTypeName() + + " requires exactly 4 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -966,11 +853,7 @@ private: else if (const auto id_col = checkAndGetColumnConst>(id_col_untyped)) executeRange(block, result, dict, attr_name, id_col, date_col_untyped); else - { - throw Exception{ - "Third argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Third argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -1003,11 +886,7 @@ private: block.getByPosition(result).column = std::move(out); } else - { - throw Exception{ - "Fourth argument of function " + getName() + " must be Date", - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Fourth argument of function " + getName() + " must be Date", ErrorCodes::ILLEGAL_COLUMN}; } template @@ -1035,11 +914,7 @@ private: block.getByPosition(result).column = DataTypeNumber().createColumnConst(id_col->size(), toField(data.front())); } else - { - throw Exception{ - "Fourth argument of function " + getName() + " must be Date", - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Fourth argument of function " + getName() + " must be Date", ErrorCodes::ILLEGAL_COLUMN}; } const ExternalDictionaries & dictionaries; @@ -1094,40 +969,27 @@ public: private: size_t getNumberOfArguments() const override { return 4; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 1}; } + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!arguments[0]->isString()) - { - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!arguments[1]->isString()) - { - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[2].get()) && !checkDataType(arguments[2].get())) - { - throw Exception{ - "Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() - + ", must be UInt64 or tuple(...).", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() + + ", must be UInt64 or tuple(...).", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[3].get())) - { - throw Exception{ - "Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() - + ", must be " + String(DataType{}.getFamilyName()) + ".", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[3]->getName() + " of fourth argument of function " + getName() + + ", must be " + String(DataType{}.getFamilyName()) + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; return std::make_shared(); } @@ -1138,9 +1000,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -1151,9 +1011,7 @@ private: !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -1166,9 +1024,7 @@ private: const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -1178,9 +1034,7 @@ private: else if (const auto id_col = checkAndGetColumnConst>(id_col_untyped)) executeDispatch(block, arguments, result, dict, attr_name, id_col); else - throw Exception{ - "Third argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Third argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -1213,9 +1067,7 @@ private: block.getByPosition(result).column = std::move(out); } else - throw Exception{ - "Fourth argument of function " + getName() + " must be " + String(DataType{}.getFamilyName()), - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be " + String(DataType{}.getFamilyName()), ErrorCodes::ILLEGAL_COLUMN}; } template @@ -1247,9 +1099,7 @@ private: block.getByPosition(result).column = DataTypeNumber().createColumnConst(id_col->size(), toField(data.front())); } else - throw Exception{ - "Fourth argument of function " + getName() + " must be " + String(DataType{}.getFamilyName()), - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be " + String(DataType{}.getFamilyName()), ErrorCodes::ILLEGAL_COLUMN}; } template @@ -1262,9 +1112,7 @@ private: const auto attr_name_col = checkAndGetColumnConst(block.getByPosition(arguments[1]).column.get()); if (!attr_name_col) - throw Exception{ - "Second argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Second argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; String attr_name = attr_name_col->getValue(); @@ -1298,9 +1146,7 @@ private: DictGetTraits::getOrDefault(dict, attr_name, key_columns, key_types, def, data); } else - throw Exception{ - "Fourth argument of function " + getName() + " must be " + String(DataType{}.getFamilyName()), - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Fourth argument of function " + getName() + " must be " + String(DataType{}.getFamilyName()), ErrorCodes::ILLEGAL_COLUMN}; block.getByPosition(result).column = std::move(out); return true; @@ -1358,23 +1204,18 @@ private: size_t getNumberOfArguments() const override { return 2; } bool isInjective(const Block & /*sample_block*/) override { return true; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; } + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!arguments[0]->isString()) - { - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[1].get())) - { - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() - + ", must be UInt64.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; return std::make_shared(std::make_shared()); } @@ -1385,9 +1226,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -1395,9 +1234,7 @@ private: if (!executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -1409,9 +1246,7 @@ private: return false; if (!dict->hasHierarchy()) - throw Exception{ - "Dictionary does not have a hierarchy", - ErrorCodes::UNSUPPORTED_METHOD}; + throw Exception{"Dictionary does not have a hierarchy", ErrorCodes::UNSUPPORTED_METHOD}; const auto get_hierarchies = [&] (const PaddedPODArray & in, PaddedPODArray & out, PaddedPODArray & offsets) { @@ -1492,11 +1327,7 @@ private: block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(id_col->size(), (*array)[0].get()); } else - { - throw Exception{ - "Second argument of function " + getName() + " must be UInt64", - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Second argument of function " + getName() + " must be UInt64", ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -1522,31 +1353,22 @@ public: private: size_t getNumberOfArguments() const override { return 3; } + bool useDefaultImplementationForConstants() const final { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; } + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!arguments[0]->isString()) - { - throw Exception{ - "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() - + ", expected a string.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName() + + ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[1].get())) - { - throw Exception{ - "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() - + ", must be UInt64.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName() + + ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; if (!checkDataType(arguments[2].get())) - { - throw Exception{ - "Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() - + ", must be UInt64.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; - } + throw Exception{"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName() + + ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; return std::make_shared(); } @@ -1557,9 +1379,7 @@ private: { const auto dict_name_col = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); if (!dict_name_col) - throw Exception{ - "First argument of function " + getName() + " must be a constant string", - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -1567,9 +1387,7 @@ private: if (!executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr)) - throw Exception{ - "Unsupported dictionary type " + dict_ptr->getTypeName(), - ErrorCodes::UNKNOWN_TYPE}; + throw Exception{"Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; } template @@ -1581,9 +1399,7 @@ private: return false; if (!dict->hasHierarchy()) - throw Exception{ - "Dictionary does not have a hierarchy", - ErrorCodes::UNSUPPORTED_METHOD}; + throw Exception{"Dictionary does not have a hierarchy", ErrorCodes::UNSUPPORTED_METHOD}; const auto child_id_col_untyped = block.getByPosition(arguments[1]).column.get(); const auto ancestor_id_col_untyped = block.getByPosition(arguments[2]).column.get(); @@ -1593,10 +1409,8 @@ private: else if (const auto child_id_col = checkAndGetColumnConst>(child_id_col_untyped)) execute(block, result, dict, child_id_col, ancestor_id_col_untyped); else - throw Exception{ - "Illegal column " + child_id_col_untyped->getName() - + " of second argument of function " + getName(), - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Illegal column " + child_id_col_untyped->getName() + + " of second argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN}; return true; } @@ -1633,10 +1447,8 @@ private: } else { - throw Exception{ - "Illegal column " + ancestor_id_col_untyped->getName() - + " of third argument of function " + getName(), - ErrorCodes::ILLEGAL_COLUMN}; + throw Exception{"Illegal column " + ancestor_id_col_untyped->getName() + + " of third argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN}; } return true; @@ -1669,12 +1481,8 @@ private: block.getByPosition(result).column = DataTypeUInt8().createColumnConst(child_id_col->size(), UInt64(res)); } else - { - throw Exception{ - "Illegal column " + ancestor_id_col_untyped->getName() - + " of third argument of function " + getName(), - ErrorCodes::ILLEGAL_COLUMN}; - } + throw Exception{"Illegal column " + ancestor_id_col_untyped->getName() + + " of third argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN}; return true; } From 30192b1b42bf272012e40fea228570cb2cd5388c Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 06:13:13 +0300 Subject: [PATCH 124/244] Fixed backward compatibility [#CLICKHOUSE-3650]. --- .../Functions/FunctionsExternalDictionaries.h | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/dbms/src/Functions/FunctionsExternalDictionaries.h b/dbms/src/Functions/FunctionsExternalDictionaries.h index abb8c518aa6..bbf9b1b5c60 100644 --- a/dbms/src/Functions/FunctionsExternalDictionaries.h +++ b/dbms/src/Functions/FunctionsExternalDictionaries.h @@ -101,6 +101,20 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + /** Do not require existence of the dictionary if the function is called for empty block. + * This is needed to allow successful query analysis on a server, + * that is the initiator of a distributed query, + * in the case when the function will be invoked for real data only at the remote servers. + * This feature is controversial and implemented specially + * for backward compatibility with the case in Yandex Banner System. + */ + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -252,6 +266,13 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -475,6 +496,13 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -734,6 +762,13 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -1002,6 +1037,13 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -1228,6 +1270,13 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); @@ -1381,6 +1430,13 @@ private: if (!dict_name_col) throw Exception{"First argument of function " + getName() + " must be a constant string", ErrorCodes::ILLEGAL_COLUMN}; + if (block.rows() == 0) + { + auto & elem = block.getByPosition(result); + elem.column = elem.type->createColumn(); + return; + } + auto dict = dictionaries.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); From f4c54f02a5629e18af37b8812d4864b5bf2687c9 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:00:00 +0300 Subject: [PATCH 125/244] Removed trashy, obsolete code [#CLICKHOUSE-3649] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index ca9bc493566..059e557baf7 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1647,15 +1647,7 @@ void ExpressionAnalyzer::makeExplicitSet(const ASTFunction * node, const Block & if (left_arg_tuple && left_arg_tuple->name == "tuple") { for (const auto & arg : left_arg_tuple->arguments->children) - { - const auto & data_type = sample_block.getByName(arg->getColumnName()).type; - - /// NOTE prevent crash in query: SELECT (1, [1]) in (1, 1) - if (const auto array = typeid_cast(data_type.get())) - throw Exception("Incorrect element of tuple: " + array->getName(), ErrorCodes::INCORRECT_ELEMENT_OF_SET); - - set_element_types.push_back(data_type); - } + set_element_types.push_back(sample_block.getByName(arg->getColumnName()).type); } else { From 83b775fbf53c08ca5b1eefc53c3078266eba152e Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:10:38 +0300 Subject: [PATCH 126/244] Attempt to fix bad code, try 1 [#CLICKHOUSE-3649] #1830 --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 059e557baf7..a32ea02754f 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1504,21 +1504,12 @@ void ExpressionAnalyzer::makeSetsForIndexImpl(const ASTPtr & node, const Block & } else { - try - { - ExpressionActionsPtr temp_actions = std::make_shared(source_columns, settings); - getRootActions(func->arguments->children.at(0), true, false, temp_actions); - makeExplicitSet(func, temp_actions->getSampleBlock(), true); - } - catch (const Exception & e) - { - /// in `sample_block` there are no columns that are added by `getActions` - if (e.code() != ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK && e.code() != ErrorCodes::UNKNOWN_IDENTIFIER) - throw; + ExpressionActionsPtr temp_actions = std::make_shared(source_columns, settings); + getRootActions(func->arguments->children.at(0), true, false, temp_actions); - /// TODO: Delete the catch in the next release - tryLogCurrentException(&Poco::Logger::get("ExpressionAnalyzer")); - } + Block sample_block_with_calculated_columns = temp_actions->getSampleBlock(); + if (sample_block_with_calculated_columns.has(args.children.at(0)->getColumnName())) + makeExplicitSet(func, sample_block_with_calculated_columns, true); } } } From eb0095a7b9b19cc8b77b0906f095acfb1d23fede Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:13:24 +0300 Subject: [PATCH 127/244] Attempt to fix bad code, try 2 [#CLICKHOUSE-3649] #1830 --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index a32ea02754f..67fcad625c5 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1504,12 +1504,10 @@ void ExpressionAnalyzer::makeSetsForIndexImpl(const ASTPtr & node, const Block & } else { - ExpressionActionsPtr temp_actions = std::make_shared(source_columns, settings); + ExpressionActionsPtr temp_actions = std::make_shared(aggregated_columns, settings); getRootActions(func->arguments->children.at(0), true, false, temp_actions); - Block sample_block_with_calculated_columns = temp_actions->getSampleBlock(); - if (sample_block_with_calculated_columns.has(args.children.at(0)->getColumnName())) - makeExplicitSet(func, sample_block_with_calculated_columns, true); + makeExplicitSet(func, sample_block_with_calculated_columns, true); } } } From 73b04a4d278c5f1ad24621a67ad2b455df6e55ef Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:37:21 +0300 Subject: [PATCH 128/244] Revert "Attempt to fix bad code, try 2 [#CLICKHOUSE-3649] #1830" This reverts commit eb0095a7b9b19cc8b77b0906f095acfb1d23fede. --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 67fcad625c5..a32ea02754f 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1504,10 +1504,12 @@ void ExpressionAnalyzer::makeSetsForIndexImpl(const ASTPtr & node, const Block & } else { - ExpressionActionsPtr temp_actions = std::make_shared(aggregated_columns, settings); + ExpressionActionsPtr temp_actions = std::make_shared(source_columns, settings); getRootActions(func->arguments->children.at(0), true, false, temp_actions); + Block sample_block_with_calculated_columns = temp_actions->getSampleBlock(); - makeExplicitSet(func, sample_block_with_calculated_columns, true); + if (sample_block_with_calculated_columns.has(args.children.at(0)->getColumnName())) + makeExplicitSet(func, sample_block_with_calculated_columns, true); } } } From 50ae82d9fbac72bfaf861070127b23133e988d50 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:47:00 +0300 Subject: [PATCH 129/244] Removing --ssl from test under pbuilder, because nothing works #2051 --- debian/pbuilder-hooks/B90test-server | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/pbuilder-hooks/B90test-server b/debian/pbuilder-hooks/B90test-server index fc7c0a04167..da929746937 100755 --- a/debian/pbuilder-hooks/B90test-server +++ b/debian/pbuilder-hooks/B90test-server @@ -25,7 +25,6 @@ if [ "${TEST_SSL}" ]; then openssl dhparam -out /etc/clickhouse-server/dhparam.pem 256 openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt - CLIENT_ADD="--ssl" fi service clickhouse-server start From ed9517bb0ba6ab97f25e7aeb486b71a876c2ea4d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:49:00 +0300 Subject: [PATCH 130/244] Whitespace #2051 --- dbms/src/Server/Client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 1580f45640b..1c838a99569 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -387,8 +387,8 @@ private: void connect() { auto encryption = config().getBool("ssl", false) - ? Protocol::Encryption::Enable - : Protocol::Encryption::Disable; + ? Protocol::Encryption::Enable + : Protocol::Encryption::Disable; String host = config().getString("host", "localhost"); UInt16 port = config().getInt("port", config().getInt(static_cast(encryption) ? "tcp_ssl_port" : "tcp_port", static_cast(encryption) ? DBMS_DEFAULT_SECURE_PORT : DBMS_DEFAULT_PORT)); From 536a4a0c52921af935645d871e84997e9157cb10 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 07:49:22 +0300 Subject: [PATCH 131/244] More checks [#CLICKHOUSE-2] --- dbms/src/Functions/IFunction.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dbms/src/Functions/IFunction.cpp b/dbms/src/Functions/IFunction.cpp index 81ada906a8d..ba05bc34e9d 100644 --- a/dbms/src/Functions/IFunction.cpp +++ b/dbms/src/Functions/IFunction.cpp @@ -15,7 +15,8 @@ namespace DB namespace ErrorCodes { -extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int ILLEGAL_COLUMN; } namespace @@ -127,7 +128,7 @@ NullPresence getNullPresense(const ColumnsWithTypeAndName & args) bool allArgumentsAreConstants(const Block & block, const ColumnNumbers & args) { for (auto arg : args) - if (!typeid_cast(block.getByPosition(arg).column.get())) + if (!block.getByPosition(arg).column->isColumnConst()) return false; return true; } @@ -135,11 +136,16 @@ bool allArgumentsAreConstants(const Block & block, const ColumnNumbers & args) bool PreparedFunctionImpl::defaultImplementationForConstantArguments(Block & block, const ColumnNumbers & args, size_t result) { + ColumnNumbers arguments_to_remain_constants = getArgumentsThatAreAlwaysConstant(); + + /// Check that these arguments are really constant. + for (auto arg_num : arguments_to_remain_constants) + if (arg_num < args.size() && !block.getByPosition(args[arg_num]).column->isColumnConst()) + throw Exception("Argument at index " + toString(arg_num) + " for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN); + if (args.empty() || !useDefaultImplementationForConstants() || !allArgumentsAreConstants(block, args)) return false; - ColumnNumbers arguments_to_remain_constants = getArgumentsThatAreAlwaysConstant(); - Block temporary_block; bool have_converted_columns = false; @@ -162,7 +168,7 @@ bool PreparedFunctionImpl::defaultImplementationForConstantArguments(Block & blo */ if (!have_converted_columns) throw Exception("Number of arguments for function " + getName() + " doesn't match: the function requires more arguments", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); temporary_block.insert(block.getByPosition(result)); From 7633c0bf2b2c1c68ccfe52ba8195332182daeb5f Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Fri, 16 Mar 2018 07:51:36 +0300 Subject: [PATCH 132/244] Auto version update to [54367] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 80e9aaf2e57..623d51823fb 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54366-testing) -set(VERSION_REVISION 54366) +set(VERSION_DESCRIBE v1.1.54367-testing) +set(VERSION_REVISION 54367) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 6f142ef0c16..0ee6be63a8b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54366) unstable; urgency=low +clickhouse (1.1.54367) unstable; urgency=low * Modified source code - -- Fri, 16 Mar 2018 00:07:09 +0300 + -- Fri, 16 Mar 2018 07:51:36 +0300 From 2bc42d53f46a3ac476319f33d7947e80bc293201 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 08:18:13 +0300 Subject: [PATCH 133/244] More information on signals [#CLICKHOUSE-2] --- libs/libdaemon/src/BaseDaemon.cpp | 146 +++++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 13 deletions(-) diff --git a/libs/libdaemon/src/BaseDaemon.cpp b/libs/libdaemon/src/BaseDaemon.cpp index 29405901206..849a80ff193 100644 --- a/libs/libdaemon/src/BaseDaemon.cpp +++ b/libs/libdaemon/src/BaseDaemon.cpp @@ -311,19 +311,6 @@ private: LOG_ERROR(log, "(from thread " << thread_num << ") " << "Received signal " << strsignal(sig) << " (" << sig << ")" << "."); - if (sig == SIGSEGV) - { - /// Print info about address and reason. - if (nullptr == info.si_addr) - LOG_ERROR(log, "Address: NULL pointer."); - else - LOG_ERROR(log, "Address: " << info.si_addr - << (info.si_code == SEGV_ACCERR ? ". Attempted access has violated the permissions assigned to the memory area." : "")); - } - - if (already_printed_stack_trace) - return; - void * caller_address = nullptr; #if defined(__x86_64__) @@ -334,11 +321,144 @@ private: caller_address = reinterpret_cast(context.uc_mcontext->__ss.__rip); #else caller_address = reinterpret_cast(context.uc_mcontext.gregs[REG_RIP]); + auto err_mask = context.uc_mcontext.gregs[REG_ERR]; #endif #elif defined(__aarch64__) caller_address = reinterpret_cast(context.uc_mcontext.pc); #endif + switch (sig) + { + case SIGSEGV: + { + /// Print info about address and reason. + if (nullptr == info.si_addr) + LOG_ERROR(log, "Address: NULL pointer."); + else + LOG_ERROR(log, "Address: " << info.si_addr); + +#if defined(__x86_64__) && !defined(__FreeBSD__) && !defined(__APPLE__) + if ((err_mask & 0x02)) + LOG_ERROR(log, "Access: write."); + else + LOG_ERROR(log, "Access: read."); +#endif + + switch (info.si_code) + { + case SEGV_ACCERR: + LOG_ERROR(log, "Attempted access has violated the permissions assigned to the memory area."); + break; + case SEGV_MAPERR: + LOG_ERROR(log, "Address not mapped to object."); + break; + default: + LOG_ERROR(log, "Unknown si_code."); + break; + } + break; + } + + case SIGBUS: + { + switch (info.si_code) + { + case BUS_ADRALN: + LOG_ERROR(log, "Invalid address alignment."); + break; + case BUS_ADRERR: + LOG_ERROR(log, "Non-existant physical address."); + break; + case BUS_OBJERR: + LOG_ERROR(log, "Object specific hardware error."); + break; + case BUS_MCEERR_AR: + LOG_ERROR(log, "Hardware memory error: action required."); + break; + case BUS_MCEERR_AO: + LOG_ERROR(log, "Hardware memory error: action optional."); + break; + default: + LOG_ERROR(log, "Unknown si_code."); + break; + } + break; + } + + case SIGILL: + { + switch (info.si_code) + { + case ILL_ILLOPC: + LOG_ERROR(log, "Illegal opcode."); + break; + case ILL_ILLOPN: + LOG_ERROR(log, "Illegal operand."); + break; + case ILL_ILLADR: + LOG_ERROR(log, "Illegal addressing mode."); + break; + case ILL_ILLTRP: + LOG_ERROR(log, "Illegal trap."); + break; + case ILL_PRVOPC: + LOG_ERROR(log, "Privileged opcode."); + break; + case ILL_PRVREG: + LOG_ERROR(log, "Privileged register."); + break; + case ILL_COPROC: + LOG_ERROR(log, "Coprocessor error."); + break; + case ILL_BADSTK: + LOG_ERROR(log, "Internal stack error."); + break; + default: + LOG_ERROR(log, "Unknown si_code."); + break; + } + break; + } + + case SIGFPE: + { + switch (info.si_code) + { + case FPE_INTDIV: + LOG_ERROR(log, "Integer divide by zero."); + break; + case FPE_INTOVF: + LOG_ERROR(log, "Integer overflow."); + break; + case FPE_FLTDIV: + LOG_ERROR(log, "Floating point divide by zero."); + break; + case FPE_FLTOVF: + LOG_ERROR(log, "Floating point overflow."); + break; + case FPE_FLTUND: + LOG_ERROR(log, "Floating point underflow."); + break; + case FPE_FLTRES: + LOG_ERROR(log, "Floating point inexact result."); + break; + case FPE_FLTINV: + LOG_ERROR(log, "Floating point invalid operation."); + break; + case FPE_FLTSUB: + LOG_ERROR(log, "Subscript out of range."); + break; + default: + LOG_ERROR(log, "Unknown si_code."); + break; + } + break; + } + } + + if (already_printed_stack_trace) + return; + static const int max_frames = 50; void * frames[max_frames]; From dc4a9be6fa7d41b499963bf8eb25a449618a076b Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 09:33:23 +0300 Subject: [PATCH 134/244] Fixed error with "makeSetsForIndex" [#CLICKHOUSE-2] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index a32ea02754f..f9967a8f9e8 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1458,8 +1458,13 @@ void ExpressionAnalyzer::optimizeLimitBy() void ExpressionAnalyzer::makeSetsForIndex() { - if (storage && ast && storage->supportsIndexForIn()) - makeSetsForIndexImpl(ast, storage->getSampleBlock()); + if (storage && select_query && storage->supportsIndexForIn()) + { + if (select_query->where_expression) + makeSetsForIndexImpl(select_query->where_expression, storage->getSampleBlock()); + if (select_query->prewhere_expression) + makeSetsForIndexImpl(select_query->prewhere_expression, storage->getSampleBlock()); + } } @@ -1485,8 +1490,15 @@ void ExpressionAnalyzer::makeSetsForIndexImpl(const ASTPtr & node, const Block & for (auto & child : node->children) { /// Process expression only in current subquery - if (!typeid_cast(child.get())) - makeSetsForIndexImpl(child, sample_block); + if (typeid_cast(child.get())) + continue; + + /// Don't dive into lambda functions + const ASTFunction * func = typeid_cast(child.get()); + if (func && func->name == "lambda") + continue; + + makeSetsForIndexImpl(child, sample_block); } const ASTFunction * func = typeid_cast(node.get()); From 2e23b43ed37d89d2e555c7e2b421e3c49c3544a5 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Fri, 16 Mar 2018 09:35:34 +0300 Subject: [PATCH 135/244] Auto version update to [54368] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 623d51823fb..7da4f053dfb 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54367-testing) -set(VERSION_REVISION 54367) +set(VERSION_DESCRIBE v1.1.54368-testing) +set(VERSION_REVISION 54368) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 0ee6be63a8b..2d4e333778f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54367) unstable; urgency=low +clickhouse (1.1.54368) unstable; urgency=low * Modified source code - -- Fri, 16 Mar 2018 07:51:36 +0300 + -- Fri, 16 Mar 2018 09:35:34 +0300 From cf6112fd377bcd306ac85ce979749c6f425de91a Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 09:39:32 +0300 Subject: [PATCH 136/244] Fixed half of bad code [#CLICKHOUSE-2] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 32 +++++++++++--------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index f9967a8f9e8..abe503137cf 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1505,23 +1505,27 @@ void ExpressionAnalyzer::makeSetsForIndexImpl(const ASTPtr & node, const Block & if (func && functionIsInOperator(func->name)) { const IAST & args = *func->arguments; - const ASTPtr & arg = args.children.at(1); - if (!prepared_sets.count(arg.get())) /// Not already prepared. + if (storage && storage->mayBenefitFromIndexForIn(args.children.at(0))) { - if (typeid_cast(arg.get()) || typeid_cast(arg.get())) - { - if (settings.use_index_for_in_with_subqueries && storage->mayBenefitFromIndexForIn(args.children.at(0))) - tryMakeSetFromSubquery(arg); - } - else - { - ExpressionActionsPtr temp_actions = std::make_shared(source_columns, settings); - getRootActions(func->arguments->children.at(0), true, false, temp_actions); + const ASTPtr & arg = args.children.at(1); - Block sample_block_with_calculated_columns = temp_actions->getSampleBlock(); - if (sample_block_with_calculated_columns.has(args.children.at(0)->getColumnName())) - makeExplicitSet(func, sample_block_with_calculated_columns, true); + if (!prepared_sets.count(arg.get())) /// Not already prepared. + { + if (typeid_cast(arg.get()) || typeid_cast(arg.get())) + { + if (settings.use_index_for_in_with_subqueries) + tryMakeSetFromSubquery(arg); + } + else + { + ExpressionActionsPtr temp_actions = std::make_shared(source_columns, settings); + getRootActions(func->arguments->children.at(0), true, false, temp_actions); + + Block sample_block_with_calculated_columns = temp_actions->getSampleBlock(); + if (sample_block_with_calculated_columns.has(args.children.at(0)->getColumnName())) + makeExplicitSet(func, sample_block_with_calculated_columns, true); + } } } } From 02c67e2b13572c76dc6fdd59e541c7d6b8f7ab8e Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 09:51:37 +0300 Subject: [PATCH 137/244] Fixed error [#CLICKHOUSE-2] --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 12 ++++++++---- dbms/src/Storages/MergeTree/MergeTreeData.h | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index b5200441383..ef4b8022323 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -2194,7 +2194,7 @@ MergeTreeData::DataPartsVector MergeTreeData::Transaction::commit() return total_covered_parts; } -bool MergeTreeData::isPrimaryKeyColumn(const ASTPtr &node) const +bool MergeTreeData::isPrimaryKeyColumnPossiblyWrappedInFunctions(const ASTPtr & node) const { String column_name = node->getColumnName(); @@ -2202,6 +2202,10 @@ bool MergeTreeData::isPrimaryKeyColumn(const ASTPtr &node) const if (column_name == column.column_name) return true; + if (const ASTFunction * func = typeid_cast(node.get())) + if (func->arguments->children.size() == 1) + return isPrimaryKeyColumnPossiblyWrappedInFunctions(func->arguments->children.front()); + return false; } @@ -2213,16 +2217,16 @@ bool MergeTreeData::mayBenefitFromIndexForIn(const ASTPtr & left_in_operand) con if (left_in_operand_tuple && left_in_operand_tuple->name == "tuple") { for (const auto & item : left_in_operand_tuple->arguments->children) - if (!isPrimaryKeyColumn(item)) + if (!isPrimaryKeyColumnPossiblyWrappedInFunctions(item)) /// The tuple itself may be part of the primary key, so check that as a last resort. - return isPrimaryKeyColumn(left_in_operand); + return isPrimaryKeyColumnPossiblyWrappedInFunctions(left_in_operand); /// tuple() is invalid but can still be found here since this method may be called before the arguments are validated. return !left_in_operand_tuple->arguments->children.empty(); } else { - return isPrimaryKeyColumn(left_in_operand); + return isPrimaryKeyColumnPossiblyWrappedInFunctions(left_in_operand); } } diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.h b/dbms/src/Storages/MergeTree/MergeTreeData.h index d440d86d62b..47abd959645 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.h +++ b/dbms/src/Storages/MergeTree/MergeTreeData.h @@ -675,8 +675,8 @@ private: DataPartPtr & out_covering_part, std::lock_guard & data_parts_lock) const; - /// Checks whether the column is in the primary key. - bool isPrimaryKeyColumn(const ASTPtr &node) const; + /// Checks whether the column is in the primary key, possibly wrapped in a chain of functions with single argument. + bool isPrimaryKeyColumnPossiblyWrappedInFunctions(const ASTPtr &node) const; }; } From 796c65a09ff98e93e094a5cd533bbfa0eb1c6f9e Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 10:04:51 +0300 Subject: [PATCH 138/244] Added test [#CLICKHOUSE-2] --- .../0_stateless/00607_index_in_in.reference | 6 ++++++ .../queries/0_stateless/00607_index_in_in.sql | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00607_index_in_in.reference create mode 100644 dbms/tests/queries/0_stateless/00607_index_in_in.sql diff --git a/dbms/tests/queries/0_stateless/00607_index_in_in.reference b/dbms/tests/queries/0_stateless/00607_index_in_in.reference new file mode 100644 index 00000000000..a9e2f17562a --- /dev/null +++ b/dbms/tests/queries/0_stateless/00607_index_in_in.reference @@ -0,0 +1,6 @@ +1 +1 +1 +1 +1 +1 diff --git a/dbms/tests/queries/0_stateless/00607_index_in_in.sql b/dbms/tests/queries/0_stateless/00607_index_in_in.sql new file mode 100644 index 00000000000..a1e2efa6a71 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00607_index_in_in.sql @@ -0,0 +1,16 @@ +DROP TABLE IF EXISTS test.merge_tree; +CREATE TABLE test.merge_tree (x UInt32) ENGINE = MergeTree ORDER BY x SETTINGS index_granularity = 1; +INSERT INTO test.merge_tree VALUES (0), (1); + +SET force_primary_key = 1; +SET max_rows_to_read = 1; + +SELECT count() FROM test.merge_tree WHERE x = 0; +SELECT count() FROM test.merge_tree WHERE toUInt32(x) = 0; +SELECT count() FROM test.merge_tree WHERE toUInt64(x) = 0; + +SELECT count() FROM test.merge_tree WHERE x IN (0, 0); +SELECT count() FROM test.merge_tree WHERE toUInt32(x) IN (0, 0); +SELECT count() FROM test.merge_tree WHERE toUInt64(x) IN (0, 0); + +DROP TABLE test.merge_tree; From 91266924419b083295fd2821c0c59060de1ea0d0 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Fri, 16 Mar 2018 10:31:37 +0300 Subject: [PATCH 139/244] Auto version update to [54369] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 7da4f053dfb..17e609f794b 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54368-testing) -set(VERSION_REVISION 54368) +set(VERSION_DESCRIBE v1.1.54369-testing) +set(VERSION_REVISION 54369) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 2d4e333778f..180d00dfaf3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54368) unstable; urgency=low +clickhouse (1.1.54369) unstable; urgency=low * Modified source code - -- Fri, 16 Mar 2018 09:35:34 +0300 + -- Fri, 16 Mar 2018 10:31:36 +0300 From a6892b881388b42f7cb04fb6204e9cfd66b84cb2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 16 Mar 2018 12:00:04 +0300 Subject: [PATCH 140/244] Fixed test [#CLICKHOUSE-2] --- dbms/src/Storages/StorageBuffer.cpp | 14 ++++++++++++++ dbms/src/Storages/StorageBuffer.h | 2 ++ dbms/src/Storages/StorageMerge.cpp | 21 +++++++++++++++++++++ dbms/src/Storages/StorageMerge.h | 2 ++ 4 files changed, 39 insertions(+) diff --git a/dbms/src/Storages/StorageBuffer.cpp b/dbms/src/Storages/StorageBuffer.cpp index 2072ac72c5c..5c59ffa7c40 100644 --- a/dbms/src/Storages/StorageBuffer.cpp +++ b/dbms/src/Storages/StorageBuffer.cpp @@ -323,6 +323,20 @@ BlockOutputStreamPtr StorageBuffer::write(const ASTPtr & /*query*/, const Settin } +bool StorageBuffer::mayBenefitFromIndexForIn(const ASTPtr & left_in_operand) const +{ + if (no_destination) + return false; + + auto destination = context.getTable(destination_database, destination_table); + + if (destination.get() == this) + throw Exception("Destination table is myself. Read will cause infinite loop.", ErrorCodes::INFINITE_LOOP); + + return destination->mayBenefitFromIndexForIn(left_in_operand); +} + + void StorageBuffer::startup() { if (context.getSettingsRef().readonly) diff --git a/dbms/src/Storages/StorageBuffer.h b/dbms/src/Storages/StorageBuffer.h index 02c2ef9b09b..ea8a0562628 100644 --- a/dbms/src/Storages/StorageBuffer.h +++ b/dbms/src/Storages/StorageBuffer.h @@ -75,6 +75,8 @@ public: bool supportsFinal() const override { return true; } bool supportsIndexForIn() const override { return true; } + bool mayBenefitFromIndexForIn(const ASTPtr & left_in_operand) const override; + /// The structure of the subordinate table is not checked and does not change. void alter(const AlterCommands & params, const String & database_name, const String & table_name, const Context & context) override; diff --git a/dbms/src/Storages/StorageMerge.cpp b/dbms/src/Storages/StorageMerge.cpp index e7090ad66ed..c0f264e7f85 100644 --- a/dbms/src/Storages/StorageMerge.cpp +++ b/dbms/src/Storages/StorageMerge.cpp @@ -111,6 +111,27 @@ namespace } +bool StorageMerge::mayBenefitFromIndexForIn(const ASTPtr & left_in_operand) const +{ + /// It's beneficial if it is true for at least one table. + StorageListWithLocks selected_tables = getSelectedTables(); + + size_t i = 0; + for (const auto & table : selected_tables) + { + if (table.first->mayBenefitFromIndexForIn(left_in_operand)) + return true; + + ++i; + /// For simplicity reasons, check only first ten tables. + if (i > 10) + break; + } + + return false; +} + + BlockInputStreams StorageMerge::read( const Names & column_names, const SelectQueryInfo & query_info, diff --git a/dbms/src/Storages/StorageMerge.h b/dbms/src/Storages/StorageMerge.h index 0c37e4e7fb4..e48cfc1d1fc 100644 --- a/dbms/src/Storages/StorageMerge.h +++ b/dbms/src/Storages/StorageMerge.h @@ -44,6 +44,8 @@ public: /// the structure of sub-tables is not checked void alter(const AlterCommands & params, const String & database_name, const String & table_name, const Context & context) override; + bool mayBenefitFromIndexForIn(const ASTPtr & left_in_operand) const override; + private: String name; String source_database; From 86e4099cc23182809c9bcb13819a1b2c75847c31 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Fri, 16 Mar 2018 12:01:50 +0300 Subject: [PATCH 141/244] Auto version update to [54370] --- dbms/cmake/version.cmake | 4 ++-- debian/changelog | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 17e609f794b..ad5ad09cce2 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54369-testing) -set(VERSION_REVISION 54369) +set(VERSION_DESCRIBE v1.1.54370-testing) +set(VERSION_REVISION 54370) # end of autochange set (VERSION_MAJOR 1) diff --git a/debian/changelog b/debian/changelog index 180d00dfaf3..75502e3cc96 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (1.1.54369) unstable; urgency=low +clickhouse (1.1.54370) unstable; urgency=low * Modified source code - -- Fri, 16 Mar 2018 10:31:36 +0300 + -- Fri, 16 Mar 2018 12:01:50 +0300 From 1f28410490a6bedc23a4b6c123f454ad7b6f0ad8 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Fri, 16 Mar 2018 17:01:00 +0300 Subject: [PATCH 142/244] Fixed false positive error messages for queries with IN and ARRAY JOIN. [#CLICKHOUSE-2] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 2 +- .../0_stateless/00563_complex_in_expression.reference | 4 ++++ .../queries/0_stateless/00563_complex_in_expression.sql | 9 ++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index abe503137cf..500e4cd775d 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1489,7 +1489,7 @@ void ExpressionAnalyzer::makeSetsForIndexImpl(const ASTPtr & node, const Block & { for (auto & child : node->children) { - /// Process expression only in current subquery + /// Don't descent into subqueries. if (typeid_cast(child.get())) continue; diff --git a/dbms/tests/queries/0_stateless/00563_complex_in_expression.reference b/dbms/tests/queries/0_stateless/00563_complex_in_expression.reference index b7d32274dd7..480b2d124fe 100644 --- a/dbms/tests/queries/0_stateless/00563_complex_in_expression.reference +++ b/dbms/tests/queries/0_stateless/00563_complex_in_expression.reference @@ -1,3 +1,7 @@ 2018-01-29 100 key 2018-01-29 100 key 2 +0 1 +1 0 +2 0 +99 1 diff --git a/dbms/tests/queries/0_stateless/00563_complex_in_expression.sql b/dbms/tests/queries/0_stateless/00563_complex_in_expression.sql index 522ff0168ed..1a84e560509 100644 --- a/dbms/tests/queries/0_stateless/00563_complex_in_expression.sql +++ b/dbms/tests/queries/0_stateless/00563_complex_in_expression.sql @@ -22,4 +22,11 @@ ALL INNER JOIN FROM test.join_with_index WHERE toUInt64(data) IN (0, 529335254087962442) ) USING (key); -DROP TABLE IF EXISTS test.join_with_index; \ No newline at end of file + +SELECT _uniq, _uniq IN (0, 99) +FROM test.join_with_index +ARRAY JOIN + [key, data] AS _uniq +ORDER BY _uniq; + +DROP TABLE IF EXISTS test.join_with_index; From 109b73b94724225afabb93621f1bd8e9d39deba3 Mon Sep 17 00:00:00 2001 From: Kirill Shvakov Date: Mon, 12 Mar 2018 17:36:33 +0200 Subject: [PATCH 143/244] fix CREATE TEMPORARY TABLE IF NOT EXISTS --- dbms/src/Interpreters/InterpreterCreateQuery.cpp | 4 +++- .../00600_create_temporary_table_if_not_exists.reference | 3 +++ .../00600_create_temporary_table_if_not_exists.sql | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.reference create mode 100644 dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.sql diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index dd594d2993a..3d70fc343b9 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -516,7 +516,9 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create) throw Exception("Table " + database_name + "." + table_name + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS); } } - + else if (context.tryGetExternalTable(table_name) && create.if_not_exists) + return {}; + res = StorageFactory::instance().get(create, data_path, table_name, diff --git a/dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.reference b/dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.reference new file mode 100644 index 00000000000..01e79c32a8c --- /dev/null +++ b/dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.reference @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.sql b/dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.sql new file mode 100644 index 00000000000..3f4c80ddcc6 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00600_create_temporary_table_if_not_exists.sql @@ -0,0 +1,4 @@ +CREATE TEMPORARY TABLE IF NOT EXISTS temporary_table (column UInt32) ENGINE = Memory; +CREATE TEMPORARY TABLE IF NOT EXISTS temporary_table (column UInt32) ENGINE = Memory; +INSERT INTO temporary_table VALUES (1), (2), (3); +SELECT column FROM temporary_table ORDER BY column; \ No newline at end of file From 02aacc894580add12be2132d7d7dec4ce6070cf6 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Sat, 17 Mar 2018 02:11:15 +0300 Subject: [PATCH 144/244] fix packages repo URL in Dockerfiles --- docker/client/Dockerfile | 2 +- docker/server/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/client/Dockerfile b/docker/client/Dockerfile index 61f27405b83..9c8f3d087a3 100644 --- a/docker/client/Dockerfile +++ b/docker/client/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -ARG repository="deb https://repo.yandex.ru/clickhouse/xenial/ dists/stable/main/binary-amd64/" +ARG repository="deb http://repo.yandex.ru/clickhouse/deb/stable/ main/" ARG version=\* RUN apt-get update && \ diff --git a/docker/server/Dockerfile b/docker/server/Dockerfile index ddc189877ac..2d4f998eff1 100644 --- a/docker/server/Dockerfile +++ b/docker/server/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -ARG repository="deb https://repo.yandex.ru/clickhouse/xenial/ dists/stable/main/binary-amd64/" +ARG repository="deb http://repo.yandex.ru/clickhouse/deb/stable/ main/" ARG version=\* RUN apt-get update && \ From 60ecc03253ef6e517c22d7663c3e9b482bfb661f Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 17 Mar 2018 20:46:25 +0300 Subject: [PATCH 145/244] Preparation #2026 --- dbms/src/Functions/FunctionsComparison.h | 179 ++++++++--------------- 1 file changed, 62 insertions(+), 117 deletions(-) diff --git a/dbms/src/Functions/FunctionsComparison.h b/dbms/src/Functions/FunctionsComparison.h index 011ecdfb030..5ea8f8e738d 100644 --- a/dbms/src/Functions/FunctionsComparison.h +++ b/dbms/src/Functions/FunctionsComparison.h @@ -135,11 +135,6 @@ struct NumComparisonImpl { NumComparisonImpl::vector_constant(b, a, c); } - - static void constant_constant(A a, B b, UInt8 & c) - { - c = Op::apply(a, b); - } }; @@ -338,18 +333,6 @@ struct StringComparisonImpl { StringComparisonImpl::fixed_string_vector_constant(b_data, b_n, a, c); } - - static void constant_constant( - const std::string & a, - const std::string & b, - UInt8 & c) - { - size_t a_n = a.size(); - size_t b_n = b.size(); - - int res = memcmp(a.data(), b.data(), std::min(a_n, b_n)); - c = Op::apply(res, 0) || (res == 0 && Op::apply(a_n, b_n)); - } }; @@ -513,14 +496,6 @@ struct StringEqualsImpl { fixed_string_vector_constant(b_data, b_n, a, c); } - - static void constant_constant( - const std::string & a, - const std::string & b, - UInt8 & c) - { - c = positive == (a == b); - } }; @@ -552,11 +527,6 @@ struct GenericComparisonImpl { GenericComparisonImpl::vector_constant(b, a, c); } - - static void constant_constant(const IColumn & a, const IColumn & b, UInt8 & c) - { - c = Op::apply(a.compareAt(0, 0, b, 1), 0); - } }; @@ -577,6 +547,8 @@ public: static constexpr auto name = Name::name; static FunctionPtr create(const Context &) { return std::make_shared(); }; + bool useDefaultImplementationForConstants() const override { return true; } + private: template bool executeNumRightType(Block & block, size_t result, const ColumnVector * col_left, const IColumn * col_right_untyped) @@ -621,14 +593,6 @@ private: block.getByPosition(result).column = std::move(col_res); return true; } - else if (auto col_right = checkAndGetColumnConst>(col_right_untyped)) - { - UInt8 res = 0; - NumComparisonImpl>::constant_constant(col_left->template getValue(), col_right->template getValue(), res); - - block.getByPosition(result).column = DataTypeUInt8().createColumnConst(col_left->size(), toField(res)); - return true; - } return false; } @@ -692,68 +656,58 @@ private: using StringImpl = StringComparisonImpl>; - if (c0_const && c1_const) - { - UInt8 res = 0; - StringImpl::constant_constant(c0_const->getValue(), c1_const->getValue(), res); - block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(c0_const->size(), toField(res)); - return true; - } + auto c_res = ColumnUInt8::create(); + ColumnUInt8::Container & vec_res = c_res->getData(); + vec_res.resize(c0->size()); + + if (c0_string && c1_string) + StringImpl::string_vector_string_vector( + c0_string->getChars(), c0_string->getOffsets(), + c1_string->getChars(), c1_string->getOffsets(), + c_res->getData()); + else if (c0_string && c1_fixed_string) + StringImpl::string_vector_fixed_string_vector( + c0_string->getChars(), c0_string->getOffsets(), + c1_fixed_string->getChars(), c1_fixed_string->getN(), + c_res->getData()); + else if (c0_string && c1_const) + StringImpl::string_vector_constant( + c0_string->getChars(), c0_string->getOffsets(), + c1_const->getValue(), + c_res->getData()); + else if (c0_fixed_string && c1_string) + StringImpl::fixed_string_vector_string_vector( + c0_fixed_string->getChars(), c0_fixed_string->getN(), + c1_string->getChars(), c1_string->getOffsets(), + c_res->getData()); + else if (c0_fixed_string && c1_fixed_string) + StringImpl::fixed_string_vector_fixed_string_vector( + c0_fixed_string->getChars(), c0_fixed_string->getN(), + c1_fixed_string->getChars(), c1_fixed_string->getN(), + c_res->getData()); + else if (c0_fixed_string && c1_const) + StringImpl::fixed_string_vector_constant( + c0_fixed_string->getChars(), c0_fixed_string->getN(), + c1_const->getValue(), + c_res->getData()); + else if (c0_const && c1_string) + StringImpl::constant_string_vector( + c0_const->getValue(), + c1_string->getChars(), c1_string->getOffsets(), + c_res->getData()); + else if (c0_const && c1_fixed_string) + StringImpl::constant_fixed_string_vector( + c0_const->getValue(), + c1_fixed_string->getChars(), c1_fixed_string->getN(), + c_res->getData()); else - { - auto c_res = ColumnUInt8::create(); - ColumnUInt8::Container & vec_res = c_res->getData(); - vec_res.resize(c0->size()); + throw Exception("Illegal columns " + + c0->getName() + " and " + c1->getName() + + " of arguments of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); - if (c0_string && c1_string) - StringImpl::string_vector_string_vector( - c0_string->getChars(), c0_string->getOffsets(), - c1_string->getChars(), c1_string->getOffsets(), - c_res->getData()); - else if (c0_string && c1_fixed_string) - StringImpl::string_vector_fixed_string_vector( - c0_string->getChars(), c0_string->getOffsets(), - c1_fixed_string->getChars(), c1_fixed_string->getN(), - c_res->getData()); - else if (c0_string && c1_const) - StringImpl::string_vector_constant( - c0_string->getChars(), c0_string->getOffsets(), - c1_const->getValue(), - c_res->getData()); - else if (c0_fixed_string && c1_string) - StringImpl::fixed_string_vector_string_vector( - c0_fixed_string->getChars(), c0_fixed_string->getN(), - c1_string->getChars(), c1_string->getOffsets(), - c_res->getData()); - else if (c0_fixed_string && c1_fixed_string) - StringImpl::fixed_string_vector_fixed_string_vector( - c0_fixed_string->getChars(), c0_fixed_string->getN(), - c1_fixed_string->getChars(), c1_fixed_string->getN(), - c_res->getData()); - else if (c0_fixed_string && c1_const) - StringImpl::fixed_string_vector_constant( - c0_fixed_string->getChars(), c0_fixed_string->getN(), - c1_const->getValue(), - c_res->getData()); - else if (c0_const && c1_string) - StringImpl::constant_string_vector( - c0_const->getValue(), - c1_string->getChars(), c1_string->getOffsets(), - c_res->getData()); - else if (c0_const && c1_fixed_string) - StringImpl::constant_fixed_string_vector( - c0_const->getValue(), - c1_fixed_string->getChars(), c1_fixed_string->getN(), - c_res->getData()); - else - throw Exception("Illegal columns " - + c0->getName() + " and " + c1->getName() - + " of arguments of function " + getName(), - ErrorCodes::ILLEGAL_COLUMN); - - block.getByPosition(result).column = std::move(c_res); - return true; - } + block.getByPosition(result).column = std::move(c_res); + return true; } void executeDateOrDateTimeOrEnumWithConstString( @@ -985,27 +939,18 @@ private: bool c0_const = c0->isColumnConst(); bool c1_const = c1->isColumnConst(); - if (c0_const && c1_const) - { - UInt8 res = 0; - GenericComparisonImpl>::constant_constant(*c0, *c1, res); - block.getByPosition(result).column = DataTypeUInt8().createColumnConst(c0->size(), toField(res)); - } + auto c_res = ColumnUInt8::create(); + ColumnUInt8::Container & vec_res = c_res->getData(); + vec_res.resize(c0->size()); + + if (c0_const) + GenericComparisonImpl>::constant_vector(*c0, *c1, vec_res); + else if (c1_const) + GenericComparisonImpl>::vector_constant(*c0, *c1, vec_res); else - { - auto c_res = ColumnUInt8::create(); - ColumnUInt8::Container & vec_res = c_res->getData(); - vec_res.resize(c0->size()); + GenericComparisonImpl>::vector_vector(*c0, *c1, vec_res); - if (c0_const) - GenericComparisonImpl>::constant_vector(*c0, *c1, vec_res); - else if (c1_const) - GenericComparisonImpl>::vector_constant(*c0, *c1, vec_res); - else - GenericComparisonImpl>::vector_vector(*c0, *c1, vec_res); - - block.getByPosition(result).column = std::move(c_res); - } + block.getByPosition(result).column = std::move(c_res); } public: From 60701afa3e93c6753ec4e88068c2ef91e84c3540 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 17 Mar 2018 21:02:19 +0300 Subject: [PATCH 146/244] Removed unused code #2010 --- .../AggregateFunctionUniq.h | 54 ++++--------------- 1 file changed, 11 insertions(+), 43 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionUniq.h b/dbms/src/AggregateFunctions/AggregateFunctionUniq.h index f5949a6d468..288d1fc5c3c 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionUniq.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionUniq.h @@ -122,8 +122,8 @@ struct AggregateFunctionUniqExactData static String getName() { return "uniqExact"; } }; -template -struct BaseUniqCombinedData +template +struct AggregateFunctionUniqCombinedData { using Key = UInt32; using Set = CombinedCardinalityEstimator< @@ -135,14 +135,15 @@ struct BaseUniqCombinedData TrivialHash, UInt32, HyperLogLogBiasEstimator, - mode - >; + HyperLogLogMode::FullFeatured>; Set set; + + static String getName() { return "uniqCombined"; } }; -template -struct BaseUniqCombinedData +template <> +struct AggregateFunctionUniqCombinedData { using Key = UInt64; using Set = CombinedCardinalityEstimator< @@ -154,44 +155,14 @@ struct BaseUniqCombinedData TrivialHash, UInt64, HyperLogLogBiasEstimator, - mode - >; + HyperLogLogMode::FullFeatured>; Set set; -}; -/// Aggregate functions uniqCombinedRaw, uniqCombinedLinearCounting, and uniqCombinedBiasCorrected -/// are intended for development of new versions of the uniqCombined function. -/// Users should only use uniqCombined. - -template -struct AggregateFunctionUniqCombinedRawData - : public BaseUniqCombinedData -{ - static String getName() { return "uniqCombinedRaw"; } -}; - -template -struct AggregateFunctionUniqCombinedLinearCountingData - : public BaseUniqCombinedData -{ - static String getName() { return "uniqCombinedLinearCounting"; } -}; - -template -struct AggregateFunctionUniqCombinedBiasCorrectedData - : public BaseUniqCombinedData -{ - static String getName() { return "uniqCombinedBiasCorrected"; } -}; - -template -struct AggregateFunctionUniqCombinedData - : public BaseUniqCombinedData -{ static String getName() { return "uniqCombined"; } }; + namespace detail { @@ -288,10 +259,7 @@ struct OneAdder data.set.insert(CityHash_v1_0_2::CityHash64(value.data, value.size)); } } - else if constexpr (std::is_same_v> - || std::is_same_v> - || std::is_same_v> - || std::is_same_v>) + else if constexpr (std::is_same_v>) { if constexpr (!std::is_same_v) { @@ -371,7 +339,7 @@ public: /** For multiple arguments. To compute, hashes them. * You can pass multiple arguments as is; You can also pass one argument - a tuple. - * But (for the possibility of effective implementation), you can not pass several arguments, among which there are tuples. + * But (for the possibility of efficient implementation), you can not pass several arguments, among which there are tuples. */ template class AggregateFunctionUniqVariadic final : public IAggregateFunctionDataHelper> From b916f17215fd504399bd6550979bfa26dd559df1 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 17 Mar 2018 21:14:05 +0300 Subject: [PATCH 147/244] Implemented 'uniq' family of functions for generic case including Array argument #2010 --- .../AggregateFunctionUniq.cpp | 34 +++++++++---------- .../AggregateFunctionUniqUpTo.cpp | 16 ++++----- .../0_stateless/00608_uniq_array.reference | 3 ++ .../queries/0_stateless/00608_uniq_array.sql | 3 ++ 4 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00608_uniq_array.reference create mode 100644 dbms/tests/queries/0_stateless/00608_uniq_array.sql diff --git a/dbms/src/AggregateFunctions/AggregateFunctionUniq.cpp b/dbms/src/AggregateFunctions/AggregateFunctionUniq.cpp index e64247796af..d6831ce1c43 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionUniq.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionUniq.cpp @@ -33,6 +33,10 @@ AggregateFunctionPtr createAggregateFunctionUniq(const std::string & name, const { assertNoParameters(name, params); + if (argument_types.empty()) + throw Exception("Incorrect number of arguments for aggregate function " + name, + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + if (argument_types.size() == 1) { const IDataType & argument_type = *argument_types[0]; @@ -51,23 +55,18 @@ AggregateFunctionPtr createAggregateFunctionUniq(const std::string & name, const return std::make_shared>(argument_types); else if (typeid_cast(&argument_type)) return std::make_shared>(); - else - throw Exception("Illegal type " + argument_types[0]->getName() + " of argument for aggregate function " + name, - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } - else if (argument_types.size() > 1) + else { /// If there are several arguments, then no tuples allowed among them. for (const auto & type : argument_types) if (typeid_cast(type.get())) throw Exception("Tuple argument of function " + name + " must be the only argument", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - - return std::make_shared>(argument_types); } - else - throw Exception("Incorrect number of arguments for aggregate function " + name, - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + /// "Variadic" method also works as a fallback generic case for single argument. + return std::make_shared>(argument_types); } template