Merge branch 'master' into bettertestalterttl

This commit is contained in:
alexey-milovidov 2020-01-19 01:03:25 +03:00 committed by GitHub
commit 7583f8744a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 1606 additions and 932 deletions

3
.gitmodules vendored
View File

@ -134,6 +134,9 @@
[submodule "contrib/libc-headers"]
path = contrib/libc-headers
url = https://github.com/ClickHouse-Extras/libc-headers.git
[submodule "contrib/replxx"]
path = contrib/replxx
url = https://github.com/AmokHuginnsson/replxx.git
[submodule "contrib/ryu"]
path = contrib/ryu
url = https://github.com/ClickHouse-Extras/ryu.git

View File

@ -328,7 +328,6 @@ include (cmake/find/xxhash.cmake)
include (cmake/find/sparsehash.cmake)
include (cmake/find/rt.cmake)
include (cmake/find/execinfo.cmake)
include (cmake/find/readline_edit.cmake)
include (cmake/find/re2.cmake)
include (cmake/find/libgsasl.cmake)
include (cmake/find/rdkafka.cmake)

View File

@ -11,7 +11,6 @@ if (ENABLE_BASE64)
if (NOT EXISTS "${ClickHouse_SOURCE_DIR}/contrib/base64")
message (WARNING "submodule contrib/base64 is missing. to fix try run: \n git submodule update --init --recursive")
else()
set (BASE64_INCLUDE_DIR ${ClickHouse_SOURCE_DIR}/contrib/base64/include)
set (BASE64_LIBRARY base64)
set (USE_BASE64 1)
endif()

View File

@ -1,60 +0,0 @@
include (CMakePushCheckState)
cmake_push_check_state ()
option (ENABLE_READLINE "Enable readline" ${ENABLE_LIBRARIES})
if (ENABLE_READLINE)
set (READLINE_PATHS "/usr/local/opt/readline/lib")
# First try find custom lib for macos users (default lib without history support)
find_library (READLINE_LIB NAMES readline PATHS ${READLINE_PATHS} NO_DEFAULT_PATH)
if (NOT READLINE_LIB)
find_library (READLINE_LIB NAMES readline PATHS ${READLINE_PATHS})
endif ()
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .so.2)
find_library (EDIT_LIB NAMES edit)
set(READLINE_INCLUDE_PATHS "/usr/local/opt/readline/include")
if (READLINE_LIB AND TERMCAP_LIBRARY)
find_path (READLINE_INCLUDE_DIR NAMES readline/readline.h PATHS ${READLINE_INCLUDE_PATHS} NO_DEFAULT_PATH)
if (NOT READLINE_INCLUDE_DIR)
find_path (READLINE_INCLUDE_DIR NAMES readline/readline.h PATHS ${READLINE_INCLUDE_PATHS})
endif ()
if (READLINE_INCLUDE_DIR AND READLINE_LIB)
set (USE_READLINE 1)
set (LINE_EDITING_LIBS ${READLINE_LIB} ${TERMCAP_LIBRARY})
message (STATUS "Using line editing libraries (readline): ${READLINE_INCLUDE_DIR} : ${LINE_EDITING_LIBS}")
endif ()
elseif (EDIT_LIB AND TERMCAP_LIBRARY)
find_library (CURSES_LIB NAMES curses)
find_path (READLINE_INCLUDE_DIR NAMES editline/readline.h PATHS ${READLINE_INCLUDE_PATHS})
if (CURSES_LIB AND READLINE_INCLUDE_DIR)
set (USE_LIBEDIT 1)
set (LINE_EDITING_LIBS ${EDIT_LIB} ${CURSES_LIB} ${TERMCAP_LIBRARY})
message (STATUS "Using line editing libraries (edit): ${READLINE_INCLUDE_DIR} : ${LINE_EDITING_LIBS}")
endif ()
endif ()
endif ()
if (LINE_EDITING_LIBS AND READLINE_INCLUDE_DIR)
include (CheckCXXSourceRuns)
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${LINE_EDITING_LIBS})
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${READLINE_INCLUDE_DIR})
check_cxx_source_runs ("
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
int main() {
add_history(NULL);
append_history(1,NULL);
return 0;
}
" HAVE_READLINE_HISTORY)
else ()
message (STATUS "Not using any library for line editing.")
endif ()
cmake_pop_check_state ()

View File

@ -48,7 +48,6 @@ if (SANITIZE)
set (ENABLE_EMBEDDED_COMPILER 0 CACHE BOOL "")
set (USE_INTERNAL_CAPNP_LIBRARY 0 CACHE BOOL "")
set (USE_SIMDJSON 0 CACHE BOOL "")
set (ENABLE_READLINE 0 CACHE BOOL "")
set (ENABLE_ORC 0 CACHE BOOL "")
set (ENABLE_PARQUET 0 CACHE BOOL "")
set (USE_CAPNP 0 CACHE BOOL "")

View File

@ -15,7 +15,6 @@ if (CMAKE_CROSSCOMPILING)
set (USE_SNAPPY OFF CACHE INTERNAL "")
set (ENABLE_PROTOBUF OFF CACHE INTERNAL "")
set (ENABLE_PARQUET OFF CACHE INTERNAL "")
set (ENABLE_READLINE OFF CACHE INTERNAL "")
set (ENABLE_ICU OFF CACHE INTERNAL "")
set (ENABLE_FASTOPS OFF CACHE INTERNAL "")
elseif (OS_LINUX)

View File

@ -331,3 +331,5 @@ endif()
if (USE_FASTOPS)
add_subdirectory (fastops-cmake)
endif()
add_subdirectory (replxx-cmake)

View File

@ -74,7 +74,6 @@ file(GLOB S3_UNIFIED_SRC
)
set(S3_INCLUDES
"${CMAKE_CURRENT_SOURCE_DIR}/include/"
"${AWS_COMMON_LIBRARY_DIR}/include/"
"${AWS_EVENT_STREAM_LIBRARY_DIR}/include/"
"${AWS_S3_LIBRARY_DIR}/include/"
@ -96,7 +95,7 @@ target_compile_definitions(aws_s3 PUBLIC -DENABLE_CURL_CLIENT)
target_compile_definitions(aws_s3 PUBLIC "AWS_SDK_VERSION_MAJOR=1")
target_compile_definitions(aws_s3 PUBLIC "AWS_SDK_VERSION_MINOR=7")
target_compile_definitions(aws_s3 PUBLIC "AWS_SDK_VERSION_PATCH=231")
target_include_directories(aws_s3 PUBLIC ${S3_INCLUDES} "${CMAKE_BINARY_DIR}/install")
target_include_directories(aws_s3 PUBLIC ${S3_INCLUDES})
if (OPENSSL_FOUND)
target_compile_definitions(aws_s3 PUBLIC -DENABLE_OPENSSL_ENCRYPTION)

1
contrib/replxx vendored Submodule

@ -0,0 +1 @@
Subproject commit 37582f0bb8c52513c6c6b76797c02d852d701dad

View File

@ -0,0 +1,53 @@
option (ENABLE_READLINE "Enable readline support" ${ENABLE_LIBRARIES})
if (ENABLE_READLINE)
option (USE_INTERNAL_REPLXX "Use internal replxx library" ${NOT_UNBUNDLED})
if (USE_INTERNAL_REPLXX)
set (LIBRARY_DIR "${ClickHouse_SOURCE_DIR}/contrib/replxx")
set(SRCS
${LIBRARY_DIR}/src/conversion.cxx
${LIBRARY_DIR}/src/ConvertUTF.cpp
${LIBRARY_DIR}/src/escape.cxx
${LIBRARY_DIR}/src/history.cxx
${LIBRARY_DIR}/src/io.cxx
${LIBRARY_DIR}/src/prompt.cxx
${LIBRARY_DIR}/src/replxx.cxx
${LIBRARY_DIR}/src/replxx_impl.cxx
${LIBRARY_DIR}/src/util.cxx
${LIBRARY_DIR}/src/wcwidth.cpp
${LIBRARY_DIR}/src/windows.cxx
)
add_library(replxx ${SRCS})
target_include_directories(replxx PUBLIC ${LIBRARY_DIR}/include)
target_compile_options(replxx PUBLIC -Wno-documentation)
else ()
find_library(LIBRARY_REPLXX NAMES replxx replxx-static)
find_path(INCLUDE_REPLXX replxx.hxx)
add_library(replxx UNKNOWN IMPORTED)
set_property(TARGET replxx PROPERTY IMPORTED_LOCATION ${LIBRARY_REPLXX})
target_include_directories(replxx PUBLIC ${INCLUDE_REPLXX})
set(CMAKE_REQUIRED_LIBRARIES replxx)
check_cxx_source_compiles(
"
#include <replxx.hxx>
int main() {
replxx::Replxx rx;
}
"
EXTERNAL_REPLXX_WORKS
)
if (NOT EXTERNAL_REPLXX_WORKS)
message (FATAL_ERROR "replxx is unusable: ${LIBRARY_REPLXX} ${INCLUDE_REPLXX}")
endif ()
endif ()
target_compile_definitions(replxx PUBLIC USE_REPLXX)
message (STATUS "Using replxx")
endif ()

View File

@ -142,10 +142,10 @@ elseif (COMPILER_GCC)
add_cxx_compile_options(-Wmaybe-uninitialized)
# Warn when the indentation of the code does not reflect the block structure
add_cxx_compile_options(-Wmisleading-indentation)
# Warn if a global function is defined without a previous declaration
# Warn if a global function is defined without a previous declaration - disabled because of build times
# add_cxx_compile_options(-Wmissing-declarations)
# Warn if a user-supplied include directory does not exist
# add_cxx_compile_options(-Wmissing-include-dirs)
add_cxx_compile_options(-Wmissing-include-dirs)
# Obvious
add_cxx_compile_options(-Wnon-virtual-dtor)
# Obvious
@ -563,7 +563,7 @@ if (USE_JEMALLOC)
endif()
endif ()
dbms_target_include_directories (PUBLIC ${DBMS_INCLUDE_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src/Formats/include)
dbms_target_include_directories (PUBLIC ${DBMS_INCLUDE_DIR})
target_include_directories (clickhouse_common_io PUBLIC ${DBMS_INCLUDE_DIR})
target_include_directories (clickhouse_common_io SYSTEM BEFORE PUBLIC ${DOUBLE_CONVERSION_INCLUDE_DIR})

View File

@ -418,7 +418,7 @@ private:
std::cerr << percent << "%\t\t";
for (const auto & info : infos)
{
std::cerr << info->sampler.quantileInterpolated(percent / 100.0) << " sec." << "\t";
std::cerr << info->sampler.quantileNearest(percent / 100.0) << " sec." << "\t";
}
std::cerr << "\n";
};
@ -453,7 +453,7 @@ private:
auto print_percentile = [&json_out](Stats & info, auto percent, bool with_comma = true)
{
json_out << "\"" << percent << "\"" << ": " << info.sampler.quantileInterpolated(percent / 100.0) << (with_comma ? ",\n" : "\n");
json_out << "\"" << percent << "\"" << ": " << info.sampler.quantileNearest(percent / 100.0) << (with_comma ? ",\n" : "\n");
};
json_out << "{\n";

View File

@ -1,14 +1,10 @@
set(CLICKHOUSE_CLIENT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ConnectionParameters.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Suggest.cpp
)
set(CLICKHOUSE_CLIENT_LINK PRIVATE clickhouse_common_config clickhouse_functions clickhouse_aggregate_functions clickhouse_common_io clickhouse_parsers string_utils ${LINE_EDITING_LIBS} ${Boost_PROGRAM_OPTIONS_LIBRARY})
set(CLICKHOUSE_CLIENT_INCLUDE PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include)
if (READLINE_INCLUDE_DIR)
set(CLICKHOUSE_CLIENT_INCLUDE ${CLICKHOUSE_CLIENT_INCLUDE} SYSTEM PRIVATE ${READLINE_INCLUDE_DIR})
endif ()
include(CheckSymbolExists)
check_symbol_exists(readpassphrase readpassphrase.h HAVE_READPASSPHRASE)

View File

@ -1,7 +1,7 @@
#include "TestHint.h"
#include "ConnectionParameters.h"
#include "Suggest.h"
#include <port/unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
@ -18,8 +18,8 @@
#include <Poco/String.h>
#include <Poco/File.h>
#include <Poco/Util/Application.h>
#include <common/readline_use.h>
#include <common/find_symbols.h>
#include <common/LineReader.h>
#include <Common/ClickHouseRevision.h>
#include <Common/Stopwatch.h>
#include <Common/Exception.h>
@ -69,10 +69,6 @@
#include <common/argsToConfig.h>
#include <Common/TerminalSize.h>
#if USE_READLINE
#include "Suggest.h"
#endif
#ifndef __clang__
#pragma GCC optimize("-fno-var-tracking-assignments")
#endif
@ -89,39 +85,6 @@
#define DISABLE_LINE_WRAPPING "\033[?7l"
#define ENABLE_LINE_WRAPPING "\033[?7h"
#if USE_READLINE && RL_VERSION_MAJOR >= 7
#define BRACK_PASTE_PREF "\033[200~"
#define BRACK_PASTE_SUFF "\033[201~"
#define BRACK_PASTE_LAST '~'
#define BRACK_PASTE_SLEN 6
/// This handler bypasses some unused macro/event checkings.
static int clickhouse_rl_bracketed_paste_begin(int /* count */, int /* key */)
{
std::string buf;
buf.reserve(128);
RL_SETSTATE(RL_STATE_MOREINPUT);
SCOPE_EXIT(RL_UNSETSTATE(RL_STATE_MOREINPUT));
int c;
while ((c = rl_read_key()) >= 0)
{
if (c == '\r')
c = '\n';
buf.push_back(c);
if (buf.size() >= BRACK_PASTE_SLEN && c == BRACK_PASTE_LAST && buf.substr(buf.size() - BRACK_PASTE_SLEN) == BRACK_PASTE_SUFF)
{
buf.resize(buf.size() - BRACK_PASTE_SLEN);
break;
}
}
return static_cast<size_t>(rl_insert_text(buf.c_str())) == buf.size() ? 0 : 1;
}
#endif
namespace DB
{
@ -136,7 +99,6 @@ namespace ErrorCodes
extern const int UNEXPECTED_PACKET_FROM_SERVER;
extern const int CLIENT_OUTPUT_FORMAT_SPECIFIED;
extern const int CANNOT_SET_SIGNAL_HANDLER;
extern const int CANNOT_READLINE;
extern const int SYSTEM_ERROR;
extern const int INVALID_USAGE_OF_INPUT;
}
@ -157,7 +119,7 @@ private:
"учшеж", "йгшеж", "дщпщгеж",
"q", "й", "\\q", "\\Q", "\\й", "\\Й", ":q", "Жй"
};
bool is_interactive = true; /// Use either readline interface or batch mode.
bool is_interactive = true; /// Use either interactive line editing interface or batch mode.
bool need_render_progress = true; /// Render query execution progress.
bool echo_queries = false; /// Print queries before execution in batch mode.
bool ignore_error = false; /// In case of errors, don't print error message, continue to next query. Only applicable for non-interactive mode.
@ -514,26 +476,10 @@ private:
if (print_time_to_stderr)
throw Exception("time option could be specified only in non-interactive mode", ErrorCodes::BAD_ARGUMENTS);
#if USE_READLINE
SCOPE_EXIT({ Suggest::instance().finalize(); });
if (server_revision >= Suggest::MIN_SERVER_REVISION
&& !config().getBool("disable_suggestion", false))
{
if (server_revision >= Suggest::MIN_SERVER_REVISION && !config().getBool("disable_suggestion", false))
/// Load suggestion data from the server.
Suggest::instance().load(connection_parameters, config().getInt("suggestion_limit"));
Suggest::instance()->load(connection_parameters, config().getInt("suggestion_limit"));
/// Added '.' to the default list. Because it is used to separate database and table.
rl_basic_word_break_characters = " \t\n\r\"\\'`@$><=;|&{(.";
/// Not append whitespace after single suggestion. Because whitespace after function name is meaningless.
rl_completion_append_character = '\0';
rl_completion_entry_function = Suggest::generator;
}
else
/// Turn tab completion off.
rl_bind_key('\t', rl_insert);
#endif
/// Load command history if present.
if (config().has("history_file"))
history_file = config().getString("history_file");
@ -546,70 +492,45 @@ private:
history_file = home_path + "/.clickhouse-client-history";
}
if (!history_file.empty())
if (!history_file.empty() && !Poco::File(history_file).exists())
Poco::File(history_file).createFile();
LineReader lr(Suggest::instance(), history_file, '\\', config().has("multiline") ? ';' : 0);
do
{
if (Poco::File(history_file).exists())
auto input = lr.readLine(prompt(), ":-] ");
if (input.empty())
break;
try
{
#if USE_READLINE
int res = read_history(history_file.c_str());
if (res)
std::cerr << "Cannot read history from file " + history_file + ": "+ errnoToString(ErrorCodes::CANNOT_READ_HISTORY);
#endif
if (!process(input))
break;
}
catch (const Exception & e)
{
actual_client_error = e.code();
if (!actual_client_error || actual_client_error != expected_client_error)
{
std::cerr << std::endl
<< "Exception on client:" << std::endl
<< "Code: " << e.code() << ". " << e.displayText() << std::endl;
if (config().getBool("stacktrace", false))
std::cerr << "Stack trace:" << std::endl << e.getStackTraceString() << std::endl;
std::cerr << std::endl;
}
/// Client-side exception during query execution can result in the loss of
/// sync in the connection protocol.
/// So we reconnect and allow to enter the next query.
connect();
}
else /// Create history file.
Poco::File(history_file).createFile();
}
#if USE_READLINE
/// Install Ctrl+C signal handler that will be used in interactive mode.
if (rl_initialize())
throw Exception("Cannot initialize readline", ErrorCodes::CANNOT_READLINE);
#if RL_VERSION_MAJOR >= 7
/// Enable bracketed-paste-mode only when multiquery is enabled and multiline is
/// disabled, so that we are able to paste and execute multiline queries in a whole
/// instead of erroring out, while be less intrusive.
if (config().has("multiquery") && !config().has("multiline"))
{
/// When bracketed paste mode is set, pasted text is bracketed with control sequences so
/// that the program can differentiate pasted text from typed-in text. This helps
/// clickhouse-client so that without -m flag, one can still paste multiline queries, and
/// possibly get better pasting performance. See https://cirw.in/blog/bracketed-paste for
/// more details.
rl_variable_bind("enable-bracketed-paste", "on");
/// Use our bracketed paste handler to get better user experience. See comments above.
rl_bind_keyseq(BRACK_PASTE_PREF, clickhouse_rl_bracketed_paste_begin);
}
#endif
auto clear_prompt_or_exit = [](int)
{
/// This is signal safe.
ssize_t res = write(STDOUT_FILENO, "\n", 1);
/// Allow to quit client while query is in progress by pressing Ctrl+C twice.
/// (First press to Ctrl+C will try to cancel query by InterruptListener).
if (res == 1 && rl_line_buffer[0] && !RL_ISSTATE(RL_STATE_DONE))
{
rl_replace_line("", 0);
if (rl_forced_update_display())
_exit(0);
}
else
{
/// A little dirty, but we struggle to find better way to correctly
/// force readline to exit after returning from the signal handler.
_exit(0);
}
};
if (signal(SIGINT, clear_prompt_or_exit) == SIG_ERR)
throwFromErrno("Cannot set signal handler.", ErrorCodes::CANNOT_SET_SIGNAL_HANDLER);
#endif
loop();
while (true);
if (isNewYearMode())
std::cout << "Happy new year." << std::endl;
@ -624,11 +545,11 @@ private:
/// This is intended for testing purposes.
if (config().getBool("always_load_suggestion_data", false))
{
#if USE_READLINE
#ifdef USE_REPLXX
SCOPE_EXIT({ Suggest::instance().finalize(); });
Suggest::instance().load(connection_parameters, config().getInt("suggestion_limit"));
#else
throw Exception("Command line suggestions cannot work without readline", ErrorCodes::BAD_ARGUMENTS);
throw Exception("Command line suggestions cannot work without line editing library", ErrorCodes::BAD_ARGUMENTS);
#endif
}
@ -706,111 +627,11 @@ private:
}
/// Check if multi-line query is inserted from the paste buffer.
/// Allows delaying the start of query execution until the entirety of query is inserted.
static bool hasDataInSTDIN()
{
timeval timeout = { 0, 0 };
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
return select(1, &fds, nullptr, nullptr, &timeout) == 1;
}
inline const String prompt() const
{
return boost::replace_all_copy(prompt_by_server_display_name, "{database}", config().getString("database", "default"));
}
void loop()
{
String input;
String prev_input;
while (char * line_ = readline(input.empty() ? prompt().c_str() : ":-] "))
{
String line = line_;
free(line_);
size_t ws = line.size();
while (ws > 0 && isWhitespaceASCII(line[ws - 1]))
--ws;
if (ws == 0 || line.empty())
continue;
bool ends_with_semicolon = line[ws - 1] == ';';
bool ends_with_backslash = line[ws - 1] == '\\';
has_vertical_output_suffix = (ws >= 2) && (line[ws - 2] == '\\') && (line[ws - 1] == 'G');
if (ends_with_backslash)
line = line.substr(0, ws - 1);
input += line;
if (!ends_with_backslash && (ends_with_semicolon || has_vertical_output_suffix || (!config().has("multiline") && !hasDataInSTDIN())))
{
// TODO: should we do sensitive data masking on client too? History file can be source of secret leaks.
if (input != prev_input)
{
/// Replace line breaks with spaces to prevent the following problem.
/// Every line of multi-line query is saved to history file as a separate line.
/// If the user restarts the client then after pressing the "up" button
/// every line of the query will be displayed separately.
std::string logged_query = input;
if (config().has("multiline"))
std::replace(logged_query.begin(), logged_query.end(), '\n', ' ');
add_history(logged_query.c_str());
#if USE_READLINE && HAVE_READLINE_HISTORY
if (!history_file.empty() && append_history(1, history_file.c_str()))
std::cerr << "Cannot append history to file " + history_file + ": " + errnoToString(ErrorCodes::CANNOT_APPEND_HISTORY);
#endif
prev_input = input;
}
if (has_vertical_output_suffix)
input = input.substr(0, input.length() - 2);
try
{
if (!process(input))
break;
}
catch (const Exception & e)
{
actual_client_error = e.code();
if (!actual_client_error || actual_client_error != expected_client_error)
{
std::cerr << std::endl
<< "Exception on client:" << std::endl
<< "Code: " << e.code() << ". " << e.displayText() << std::endl;
if (config().getBool("stacktrace", false))
std::cerr << "Stack trace:" << std::endl
<< e.getStackTraceString() << std::endl;
std::cerr << std::endl;
}
/// Client-side exception during query execution can result in the loss of
/// sync in the connection protocol.
/// So we reconnect and allow to enter the next query.
connect();
}
input = "";
}
else
{
input += '\n';
}
}
}
void nonInteractive()
{

View File

@ -0,0 +1,144 @@
#include "Suggest.h"
#include <Columns/ColumnString.h>
#include <Common/typeid_cast.h>
namespace DB
{
void Suggest::load(const ConnectionParameters & connection_parameters, size_t suggestion_limit)
{
loading_thread = std::thread([connection_parameters, suggestion_limit, this]
{
try
{
Connection connection(
connection_parameters.host,
connection_parameters.port,
connection_parameters.default_database,
connection_parameters.user,
connection_parameters.password,
"client",
connection_parameters.compression,
connection_parameters.security);
loadImpl(connection, connection_parameters.timeouts, suggestion_limit);
}
catch (...)
{
std::cerr << "Cannot load data for command line suggestions: " << getCurrentExceptionMessage(false, true) << "\n";
}
/// Note that keyword suggestions are available even if we cannot load data from server.
std::sort(words.begin(), words.end());
ready = true;
});
}
Suggest::Suggest()
{
/// Keywords may be not up to date with ClickHouse parser.
words = {"CREATE", "DATABASE", "IF", "NOT", "EXISTS", "TEMPORARY", "TABLE", "ON", "CLUSTER", "DEFAULT",
"MATERIALIZED", "ALIAS", "ENGINE", "AS", "VIEW", "POPULATE", "SETTINGS", "ATTACH", "DETACH", "DROP",
"RENAME", "TO", "ALTER", "ADD", "MODIFY", "CLEAR", "COLUMN", "AFTER", "COPY", "PROJECT",
"PRIMARY", "KEY", "CHECK", "PARTITION", "PART", "FREEZE", "FETCH", "FROM", "SHOW", "INTO",
"OUTFILE", "FORMAT", "TABLES", "DATABASES", "LIKE", "PROCESSLIST", "CASE", "WHEN", "THEN", "ELSE",
"END", "DESCRIBE", "DESC", "USE", "SET", "OPTIMIZE", "FINAL", "DEDUPLICATE", "INSERT", "VALUES",
"SELECT", "DISTINCT", "SAMPLE", "ARRAY", "JOIN", "GLOBAL", "LOCAL", "ANY", "ALL", "INNER",
"LEFT", "RIGHT", "FULL", "OUTER", "CROSS", "USING", "PREWHERE", "WHERE", "GROUP", "BY",
"WITH", "TOTALS", "HAVING", "ORDER", "COLLATE", "LIMIT", "UNION", "AND", "OR", "ASC",
"IN", "KILL", "QUERY", "SYNC", "ASYNC", "TEST", "BETWEEN", "TRUNCATE"};
}
void Suggest::loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit)
{
std::stringstream query;
query << "SELECT DISTINCT arrayJoin(extractAll(name, '[\\\\w_]{2,}')) AS res FROM ("
"SELECT name FROM system.functions"
" UNION ALL "
"SELECT name FROM system.table_engines"
" UNION ALL "
"SELECT name FROM system.formats"
" UNION ALL "
"SELECT name FROM system.table_functions"
" UNION ALL "
"SELECT name FROM system.data_type_families"
" UNION ALL "
"SELECT name FROM system.settings"
" UNION ALL "
"SELECT cluster FROM system.clusters"
" UNION ALL "
"SELECT concat(func.name, comb.name) FROM system.functions AS func CROSS JOIN system.aggregate_function_combinators AS comb WHERE is_aggregate";
/// The user may disable loading of databases, tables, columns by setting suggestion_limit to zero.
if (suggestion_limit > 0)
{
String limit_str = toString(suggestion_limit);
query <<
" UNION ALL "
"SELECT name FROM system.databases LIMIT " << limit_str
<< " UNION ALL "
"SELECT DISTINCT name FROM system.tables LIMIT " << limit_str
<< " UNION ALL "
"SELECT DISTINCT name FROM system.columns LIMIT " << limit_str;
}
query << ") WHERE notEmpty(res)";
fetch(connection, timeouts, query.str());
}
void Suggest::fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query)
{
connection.sendQuery(timeouts, query);
while (true)
{
Packet packet = connection.receivePacket();
switch (packet.type)
{
case Protocol::Server::Data:
fillWordsFromBlock(packet.block);
continue;
case Protocol::Server::Progress:
continue;
case Protocol::Server::ProfileInfo:
continue;
case Protocol::Server::Totals:
continue;
case Protocol::Server::Extremes:
continue;
case Protocol::Server::Log:
continue;
case Protocol::Server::Exception:
packet.exception->rethrow();
return;
case Protocol::Server::EndOfStream:
return;
default:
throw Exception("Unknown packet from server", ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
}
}
}
void Suggest::fillWordsFromBlock(const Block & block)
{
if (!block)
return;
if (block.columns() != 1)
throw Exception("Wrong number of columns received for query to read words for suggestion", ErrorCodes::LOGICAL_ERROR);
const ColumnString & column = typeid_cast<const ColumnString &>(*block.getByPosition(0).column);
size_t rows = block.rows();
for (size_t i = 0; i < rows; ++i)
words.emplace_back(column.getDataAt(i).toString());
}
}

View File

@ -2,18 +2,9 @@
#include "ConnectionParameters.h"
#include <string>
#include <sstream>
#include <string.h>
#include <vector>
#include <algorithm>
#include <common/readline_use.h>
#include <Common/typeid_cast.h>
#include <Columns/ColumnString.h>
#include <Client/Connection.h>
#include <IO/ConnectionTimeouts.h>
#include <common/LineReader.h>
namespace DB
@ -24,206 +15,34 @@ namespace ErrorCodes
extern const int UNKNOWN_PACKET_FROM_SERVER;
}
class Suggest : private boost::noncopyable
class Suggest : public LineReader::Suggest, boost::noncopyable
{
private:
/// The vector will be filled with completion words from the server and sorted.
using Words = std::vector<std::string>;
/// Keywords may be not up to date with ClickHouse parser.
Words words
{
"CREATE", "DATABASE", "IF", "NOT", "EXISTS", "TEMPORARY", "TABLE", "ON", "CLUSTER", "DEFAULT", "MATERIALIZED", "ALIAS", "ENGINE",
"AS", "VIEW", "POPULATE", "SETTINGS", "ATTACH", "DETACH", "DROP", "RENAME", "TO", "ALTER", "ADD", "MODIFY", "CLEAR", "COLUMN", "AFTER",
"COPY", "PROJECT", "PRIMARY", "KEY", "CHECK", "PARTITION", "PART", "FREEZE", "FETCH", "FROM", "SHOW", "INTO", "OUTFILE", "FORMAT", "TABLES",
"DATABASES", "LIKE", "PROCESSLIST", "CASE", "WHEN", "THEN", "ELSE", "END", "DESCRIBE", "DESC", "USE", "SET", "OPTIMIZE", "FINAL", "DEDUPLICATE",
"INSERT", "VALUES", "SELECT", "DISTINCT", "SAMPLE", "ARRAY", "JOIN", "GLOBAL", "LOCAL", "ANY", "ALL", "INNER", "LEFT", "RIGHT", "FULL", "OUTER",
"CROSS", "USING", "PREWHERE", "WHERE", "GROUP", "BY", "WITH", "TOTALS", "HAVING", "ORDER", "COLLATE", "LIMIT", "UNION", "AND", "OR", "ASC", "IN",
"KILL", "QUERY", "SYNC", "ASYNC", "TEST", "BETWEEN", "TRUNCATE"
};
/// Words are fetched asynchronously.
std::thread loading_thread;
std::atomic<bool> ready{false};
/// Points to current word to suggest.
Words::const_iterator pos;
/// Points after the last possible match.
Words::const_iterator end;
/// Set iterators to the matched range of words if any.
void findRange(const char * prefix, size_t prefix_length)
{
std::string prefix_str(prefix);
std::tie(pos, end) = std::equal_range(words.begin(), words.end(), prefix_str,
[prefix_length](const std::string & s, const std::string & prefix_searched) { return strncmp(s.c_str(), prefix_searched.c_str(), prefix_length) < 0; });
}
/// Iterates through matched range.
char * nextMatch()
{
if (pos >= end)
return nullptr;
/// readline will free memory by itself.
char * word = strdup(pos->c_str());
++pos;
return word;
}
void loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit)
{
std::stringstream query;
query << "SELECT DISTINCT arrayJoin(extractAll(name, '[\\\\w_]{2,}')) AS res FROM ("
"SELECT name FROM system.functions"
" UNION ALL "
"SELECT name FROM system.table_engines"
" UNION ALL "
"SELECT name FROM system.formats"
" UNION ALL "
"SELECT name FROM system.table_functions"
" UNION ALL "
"SELECT name FROM system.data_type_families"
" UNION ALL "
"SELECT name FROM system.settings"
" UNION ALL "
"SELECT concat(func.name, comb.name) FROM system.functions AS func CROSS JOIN system.aggregate_function_combinators AS comb WHERE is_aggregate";
/// The user may disable loading of databases, tables, columns by setting suggestion_limit to zero.
if (suggestion_limit > 0)
{
String limit_str = toString(suggestion_limit);
query <<
" UNION ALL "
"SELECT name FROM system.databases LIMIT " << limit_str
<< " UNION ALL "
"SELECT DISTINCT name FROM system.tables LIMIT " << limit_str
<< " UNION ALL "
"SELECT DISTINCT name FROM system.columns LIMIT " << limit_str;
}
query << ") WHERE notEmpty(res)";
fetch(connection, timeouts, query.str());
}
void fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query)
{
connection.sendQuery(timeouts, query);
while (true)
{
Packet packet = connection.receivePacket();
switch (packet.type)
{
case Protocol::Server::Data:
fillWordsFromBlock(packet.block);
continue;
case Protocol::Server::Progress:
continue;
case Protocol::Server::ProfileInfo:
continue;
case Protocol::Server::Totals:
continue;
case Protocol::Server::Extremes:
continue;
case Protocol::Server::Log:
continue;
case Protocol::Server::Exception:
packet.exception->rethrow();
return;
case Protocol::Server::EndOfStream:
return;
default:
throw Exception("Unknown packet from server", ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
}
}
}
void fillWordsFromBlock(const Block & block)
{
if (!block)
return;
if (block.columns() != 1)
throw Exception("Wrong number of columns received for query to read words for suggestion", ErrorCodes::LOGICAL_ERROR);
const ColumnString & column = typeid_cast<const ColumnString &>(*block.getByPosition(0).column);
size_t rows = block.rows();
for (size_t i = 0; i < rows; ++i)
words.emplace_back(column.getDataAt(i).toString());
}
public:
static Suggest & instance()
static Suggest * instance()
{
static Suggest instance;
return instance;
return &instance;
}
/// More old server versions cannot execute the query above.
void load(const ConnectionParameters & connection_parameters, size_t suggestion_limit);
/// Older server versions cannot execute the query above.
static constexpr int MIN_SERVER_REVISION = 54406;
void load(const ConnectionParameters & connection_parameters, size_t suggestion_limit)
{
loading_thread = std::thread([connection_parameters, suggestion_limit, this]
{
try
{
Connection connection(
connection_parameters.host,
connection_parameters.port,
connection_parameters.default_database,
connection_parameters.user,
connection_parameters.password,
"client",
connection_parameters.compression,
connection_parameters.security);
loadImpl(connection, connection_parameters.timeouts, suggestion_limit);
}
catch (...)
{
std::cerr << "Cannot load data for command line suggestions: " << getCurrentExceptionMessage(false, true) << "\n";
}
/// Note that keyword suggestions are available even if we cannot load data from server.
std::sort(words.begin(), words.end());
ready = true;
});
}
void finalize()
private:
Suggest();
~Suggest()
{
if (loading_thread.joinable())
loading_thread.join();
}
/// A function for readline.
static char * generator(const char * text, int state)
{
Suggest & suggest = Suggest::instance();
if (!suggest.ready)
return nullptr;
if (state == 0)
suggest.findRange(text, strlen(text));
void loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit);
void fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query);
void fillWordsFromBlock(const Block & block);
/// Do not append whitespace after word. For unknown reason, rl_completion_append_character = '\0' does not work.
rl_completion_suppress_append = 1;
return suggest.nextMatch();
}
~Suggest()
{
finalize();
}
/// Words are fetched asynchronously.
std::thread loading_thread;
};
}

View File

@ -10,4 +10,4 @@ set_target_properties(readpassphrase
PROPERTIES LINKER_LANGUAGE C
)
# . to allow #include <readpassphrase.h>
target_include_directories(readpassphrase PUBLIC . ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/../include)
target_include_directories(readpassphrase PUBLIC . ${CMAKE_CURRENT_BINARY_DIR}/include)

View File

@ -15,20 +15,24 @@ set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE PUBLIC ${ClickHouse_SOURCE_DIR}/libs/libdaemo
if (USE_POCO_SQLODBC)
set(CLICKHOUSE_ODBC_BRIDGE_LINK ${CLICKHOUSE_ODBC_BRIDGE_LINK} PRIVATE ${Poco_SQLODBC_LIBRARY})
set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${ODBC_INCLUDE_DIRS} ${Poco_SQLODBC_INCLUDE_DIR})
# Wouldnt work anyway because of the way list variable got expanded in `target_include_directories`
# set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${ODBC_INCLUDE_DIRS} ${Poco_SQLODBC_INCLUDE_DIR})
endif ()
if (Poco_SQL_FOUND)
set(CLICKHOUSE_ODBC_BRIDGE_LINK ${CLICKHOUSE_ODBC_BRIDGE_LINK} PRIVATE ${Poco_SQL_LIBRARY})
set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${Poco_SQL_INCLUDE_DIR})
# Wouldnt work anyway because of the way list variable got expanded in `target_include_directories`
# set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${Poco_SQL_INCLUDE_DIR})
endif ()
if (USE_POCO_DATAODBC)
set(CLICKHOUSE_ODBC_BRIDGE_LINK ${CLICKHOUSE_ODBC_BRIDGE_LINK} PRIVATE ${Poco_DataODBC_LIBRARY})
set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${ODBC_INCLUDE_DIRS} ${Poco_DataODBC_INCLUDE_DIR})
# Wouldnt work anyway because of the way list variable got expanded in `target_include_directories`
# set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${ODBC_INCLUDE_DIRS} ${Poco_DataODBC_INCLUDE_DIR})
endif()
if (Poco_Data_FOUND)
set(CLICKHOUSE_ODBC_BRIDGE_LINK ${CLICKHOUSE_ODBC_BRIDGE_LINK} PRIVATE ${Poco_Data_LIBRARY})
set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${Poco_Data_INCLUDE_DIR})
# Wouldnt work anyway because of the way list variable got expanded in `target_include_directories`
# set(CLICKHOUSE_ODBC_BRIDGE_INCLUDE ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE} SYSTEM PRIVATE ${Poco_Data_INCLUDE_DIR})
endif ()
clickhouse_program_add_library(odbc-bridge)

View File

@ -61,6 +61,10 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque
ReadBufferFromIStream body(request.stream());
auto endpoint = server.context().getInterserverIOHandler().getEndpoint(endpoint_name);
/// Locked for read while query processing
std::shared_lock lock(endpoint->rwlock);
if (endpoint->blocker.isCancelled())
throw Exception("Transferring part to replica was cancelled", ErrorCodes::ABORTED);
if (compress)
{

View File

@ -436,8 +436,10 @@ int Server::main(const std::vector<std::string> & /*args*/)
main_config_zk_changed_event,
[&](ConfigurationPtr config)
{
setTextLog(global_context->getTextLog());
buildLoggers(*config, logger());
// FIXME logging-related things need synchronization -- see the 'Logger * log' saved
// in a lot of places. For now, disable updating log configuration without server restart.
//setTextLog(global_context->getTextLog());
//buildLoggers(*config, logger());
global_context->setClustersConfig(config);
global_context->setMacros(std::make_unique<Macros>(*config, "macros"));
@ -862,6 +864,9 @@ int Server::main(const std::vector<std::string> & /*args*/)
for (auto & server : servers)
server->start();
setTextLog(global_context->getTextLog());
buildLoggers(config(), logger());
main_config_reloader->start();
users_config_reloader->start();
if (dns_cache_updater)

View File

@ -387,7 +387,6 @@ namespace ErrorCodes
extern const int PTHREAD_ERROR = 411;
extern const int NETLINK_ERROR = 412;
extern const int CANNOT_SET_SIGNAL_HANDLER = 413;
extern const int CANNOT_READLINE = 414;
extern const int ALL_REPLICAS_LOST = 415;
extern const int REPLICA_STATUS_CHANGED = 416;
extern const int EXPECTED_ALL_OR_ANY = 417;

View File

@ -10,8 +10,6 @@ namespace DB
{
namespace ErrorCodes
{
extern const int UNKNOWN_ELEMENT_IN_CONFIG;
extern const int EXCESSIVE_ELEMENT_IN_CONFIG;
extern const int FILE_DOESNT_EXIST;
extern const int FILE_ALREADY_EXISTS;
extern const int DIRECTORY_DOESNT_EXIST;

View File

@ -1,19 +1,24 @@
#pragma once
#include <Disks/IDisk.h>
#include <IO/ReadBuffer.h>
#include <IO/WriteBuffer.h>
#include <mutex>
#include <memory>
#include <unordered_map>
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
class ReadBuffer;
class WriteBuffer;
/** Implementation of Disk intended only for testing purposes.
* All filesystem objects are stored in memory and lost on server restart.
*
* NOTE Work in progress. Currently the interface is not viable enough to support MergeTree or even StripeLog tables.
* Please delete this interface if it will not be finished after 2020-06-18.
*/
class DiskMemory : public IDisk
{
public:

View File

@ -32,7 +32,6 @@ if (OPENSSL_CRYPTO_LIBRARY)
target_link_libraries(clickhouse_functions PUBLIC ${OPENSSL_CRYPTO_LIBRARY})
endif()
target_include_directories(clickhouse_functions PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include)
target_include_directories(clickhouse_functions SYSTEM PRIVATE ${DIVIDE_INCLUDE_DIR} ${METROHASH_INCLUDE_DIR} ${SPARSEHASH_INCLUDE_DIR})
if (CONSISTENT_HASHING_INCLUDE_DIR)

View File

@ -2,7 +2,6 @@ include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake)
add_headers_and_sources(clickhouse_functions_url .)
add_library(clickhouse_functions_url ${clickhouse_functions_url_sources} ${clickhouse_functions_url_headers})
target_link_libraries(clickhouse_functions_url PRIVATE dbms)
target_include_directories(clickhouse_functions_url PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../include) # ${CMAKE_CURRENT_BINARY_DIR}/include
if (CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO" OR CMAKE_BUILD_TYPE_UC STREQUAL "MINSIZEREL")
# Won't generate debug info for files with heavy template instantiation to achieve faster linking and lower size.

View File

@ -14,6 +14,7 @@ namespace ErrorCodes
{
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int ILLEGAL_COLUMN;
}
/// arrayZip(['a', 'b', 'c'], ['d', 'e', 'f']) = [('a', 'd'), ('b', 'e'), ('c', 'f')]
@ -44,9 +45,8 @@ public:
const DataTypeArray * array_type = checkAndGetDataType<DataTypeArray>(arguments[index].type.get());
if (!array_type)
throw Exception(
"Argument " + toString(index + 1) + " of function must be array. Found " + arguments[0].type->getName() + " instead.",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
throw Exception("Argument " + toString(index + 1) + " of function " + getName()
+ " must be array. Found " + arguments[0].type->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
arguments_types.emplace_back(array_type->getNestedType());
}
@ -56,26 +56,37 @@ public:
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
{
auto first_argument = block.getByPosition(arguments[0]);
const auto & first_array_column = checkAndGetColumn<ColumnArray>(first_argument.column.get());
size_t num_arguments = arguments.size();
Columns res_tuple_columns(arguments.size());
res_tuple_columns[0] = first_array_column->getDataPtr();
ColumnPtr first_array_column;
Columns tuple_columns(num_arguments);
for (size_t index = 1; index < arguments.size(); ++index)
for (size_t i = 0; i < num_arguments; ++i)
{
const auto & argument_type_and_column = block.getByPosition(arguments[index]);
const auto & argument_array_column = checkAndGetColumn<ColumnArray>(argument_type_and_column.column.get());
/// Constant columns cannot be inside tuple. It's only possible to have constant tuple as a whole.
ColumnPtr holder = block.getByPosition(arguments[i]).column->convertToFullColumnIfConst();
if (!first_array_column->hasEqualOffsets(*argument_array_column))
throw Exception("The argument 1 and argument " + toString(index + 1) + " of function have different array sizes",
ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
const ColumnArray * column_array = checkAndGetColumn<ColumnArray>(holder.get());
res_tuple_columns[index] = argument_array_column->getDataPtr();
if (!column_array)
throw Exception("Argument " + toString(i + 1) + " of function " + getName() + " must be array."
" Found column " + holder->getName() + " instead.", ErrorCodes::ILLEGAL_COLUMN);
if (i == 0)
{
first_array_column = holder;
}
else if (!column_array->hasEqualOffsets(static_cast<const ColumnArray &>(*first_array_column)))
{
throw Exception("The argument 1 and argument " + toString(i + 1) + " of function " + getName() + " have different array sizes",
ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
}
tuple_columns[i] = column_array->getDataPtr();
}
block.getByPosition(result).column = ColumnArray::create(
ColumnTuple::create(res_tuple_columns), first_array_column->getOffsetsPtr());
ColumnTuple::create(tuple_columns), static_cast<const ColumnArray &>(*first_array_column).getOffsetsPtr());
}
};

View File

@ -0,0 +1,45 @@
#include <ext/bit_cast.h>
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionUnaryArithmetic.h>
namespace DB
{
template <typename A>
struct BitCountImpl
{
using ResultType = UInt8;
static inline ResultType apply(A a)
{
/// We count bits in the value representation in memory. For example, we support floats.
/// We need to avoid sign-extension when converting signed numbers to larger type. So, uint8_t(-1) has 8 bits.
return __builtin_popcountll(ext::bit_cast<unsigned long long>(a));
}
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = false;
#endif
};
struct NameBitCount { static constexpr auto name = "bitCount"; };
using FunctionBitCount = FunctionUnaryArithmetic<BitCountImpl, NameBitCount, false /* is injective */>;
/// The function has no ranges of monotonicity.
template <> struct FunctionUnaryArithmeticMonotonicity<NameBitCount>
{
static bool has() { return false; }
static IFunction::Monotonicity get(const Field &, const Field &)
{
return {};
}
};
void registerFunctionBitCount(FunctionFactory & factory)
{
factory.registerFunction<FunctionBitCount>();
}
}

View File

@ -0,0 +1,73 @@
#include <Functions/IFunctionImpl.h>
#include <Functions/FunctionHelpers.h>
#include <Functions/FunctionFactory.h>
#include <DataTypes/DataTypesNumber.h>
#include <DataTypes/getLeastSupertype.h>
#include <Core/ColumnNumbers.h>
namespace DB
{
/// ifNotFinite(x, y) is equivalent to isFinite(x) ? x : y.
class FunctionIfNotFinite : public IFunction
{
public:
static constexpr auto name = "ifNotFinite";
FunctionIfNotFinite(const Context & context_) : context(context_) {}
static FunctionPtr create(const Context & context)
{
return std::make_shared<FunctionIfNotFinite>(context);
}
std::string getName() const override
{
return name;
}
size_t getNumberOfArguments() const override { return 2; }
bool useDefaultImplementationForNulls() const override { return false; }
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const override { return {0}; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
auto is_finite_type = FunctionFactory::instance().get("isFinite", context)->build({arguments[0]})->getReturnType();
auto if_type = FunctionFactory::instance().get("if", context)->build({{nullptr, is_finite_type, ""}, arguments[0], arguments[1]})->getReturnType();
return if_type;
}
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
{
Block temp_block = block;
auto is_finite = FunctionFactory::instance().get("isFinite", context)->build(
{temp_block.getByPosition(arguments[0])});
size_t is_finite_pos = temp_block.columns();
temp_block.insert({nullptr, is_finite->getReturnType(), ""});
auto func_if = FunctionFactory::instance().get("if", context)->build(
{temp_block.getByPosition(is_finite_pos), temp_block.getByPosition(arguments[0]), temp_block.getByPosition(arguments[1])});
is_finite->execute(temp_block, {arguments[0]}, is_finite_pos, input_rows_count);
func_if->execute(temp_block, {is_finite_pos, arguments[0], arguments[1]}, result, input_rows_count);
block.getByPosition(result).column = std::move(temp_block.getByPosition(result).column);
}
private:
const Context & context;
};
void registerFunctionIfNotFinite(FunctionFactory & factory)
{
factory.registerFunction<FunctionIfNotFinite>();
}
}

View File

@ -20,6 +20,7 @@ void registerFunctionBitShiftLeft(FunctionFactory & factory);
void registerFunctionBitShiftRight(FunctionFactory & factory);
void registerFunctionBitRotateLeft(FunctionFactory & factory);
void registerFunctionBitRotateRight(FunctionFactory & factory);
void registerFunctionBitCount(FunctionFactory & factory);
void registerFunctionLeast(FunctionFactory & factory);
void registerFunctionGreatest(FunctionFactory & factory);
void registerFunctionBitTest(FunctionFactory & factory);
@ -58,6 +59,7 @@ void registerFunctionsArithmetic(FunctionFactory & factory)
registerFunctionBitShiftRight(factory);
registerFunctionBitRotateLeft(factory);
registerFunctionBitRotateRight(factory);
registerFunctionBitCount(factory);
registerFunctionLeast(factory);
registerFunctionGreatest(factory);
registerFunctionBitTest(factory);

View File

@ -36,6 +36,7 @@ void registerFunctionHasColumnInTable(FunctionFactory &);
void registerFunctionIsFinite(FunctionFactory &);
void registerFunctionIsInfinite(FunctionFactory &);
void registerFunctionIsNaN(FunctionFactory &);
void registerFunctionIfNotFinite(FunctionFactory &);
void registerFunctionThrowIf(FunctionFactory &);
void registerFunctionVersion(FunctionFactory &);
void registerFunctionUptime(FunctionFactory &);
@ -93,6 +94,7 @@ void registerFunctionsMiscellaneous(FunctionFactory & factory)
registerFunctionIsFinite(factory);
registerFunctionIsInfinite(factory);
registerFunctionIsNaN(factory);
registerFunctionIfNotFinite(factory);
registerFunctionThrowIf(factory);
registerFunctionVersion(factory);
registerFunctionUptime(factory);

View File

@ -11,6 +11,7 @@
#include <map>
#include <atomic>
#include <utility>
#include <shared_mutex>
#include <Poco/Net/HTMLForm.h>
namespace Poco { namespace Net { class HTTPServerResponse; } }
@ -24,42 +25,6 @@ namespace ErrorCodes
extern const int NO_SUCH_INTERSERVER_IO_ENDPOINT;
}
/** Location of the service.
*/
struct InterserverIOEndpointLocation
{
public:
InterserverIOEndpointLocation(const std::string & name_, const std::string & host_, UInt16 port_)
: name(name_), host(host_), port(port_)
{
}
/// Creates a location based on its serialized representation.
InterserverIOEndpointLocation(const std::string & serialized_location)
{
ReadBufferFromString buf(serialized_location);
readBinary(name, buf);
readBinary(host, buf);
readBinary(port, buf);
assertEOF(buf);
}
/// Serializes the location.
std::string toString() const
{
WriteBufferFromOwnString buf;
writeBinary(name, buf);
writeBinary(host, buf);
writeBinary(port, buf);
return buf.str();
}
public:
std::string name;
std::string host;
UInt16 port;
};
/** Query processor from other servers.
*/
class InterserverIOEndpoint
@ -71,6 +36,7 @@ public:
/// You need to stop the data transfer if blocker is activated.
ActionBlocker blocker;
std::shared_mutex rwlock;
};
using InterserverIOEndpointPtr = std::shared_ptr<InterserverIOEndpoint>;
@ -90,11 +56,10 @@ public:
throw Exception("Duplicate interserver IO endpoint: " + name, ErrorCodes::DUPLICATE_INTERSERVER_IO_ENDPOINT);
}
void removeEndpoint(const String & name)
bool removeEndpointIfExists(const String & name)
{
std::lock_guard lock(mutex);
if (!endpoint_map.erase(name))
throw Exception("No interserver IO endpoint named " + name, ErrorCodes::NO_SUCH_INTERSERVER_IO_ENDPOINT);
return endpoint_map.erase(name);
}
InterserverIOEndpointPtr getEndpoint(const String & name)
@ -115,41 +80,4 @@ private:
std::mutex mutex;
};
/// In the constructor calls `addEndpoint`, in the destructor - `removeEndpoint`.
class InterserverIOEndpointHolder
{
public:
InterserverIOEndpointHolder(const String & name_, InterserverIOEndpointPtr endpoint_, InterserverIOHandler & handler_)
: name(name_), endpoint(std::move(endpoint_)), handler(handler_)
{
handler.addEndpoint(name, endpoint);
}
InterserverIOEndpointPtr getEndpoint()
{
return endpoint;
}
~InterserverIOEndpointHolder()
try
{
handler.removeEndpoint(name);
/// After destroying the object, `endpoint` can still live, since its ownership is acquired during the processing of the request,
/// see InterserverIOHTTPHandler.cpp
}
catch (...)
{
tryLogCurrentException("~InterserverIOEndpointHolder");
}
ActionBlocker & getBlocker() { return endpoint->blocker; }
private:
String name;
InterserverIOEndpointPtr endpoint;
InterserverIOHandler & handler;
};
using InterserverIOEndpointHolderPtr = std::shared_ptr<InterserverIOEndpointHolder>;
}

View File

@ -11,7 +11,6 @@ namespace DB
class IStorage;
using StoragePtr = std::shared_ptr<IStorage>;
using StorageWeakPtr = std::weak_ptr<IStorage>;
using Tables = std::map<String, StoragePtr>;
}

View File

@ -1,8 +1,6 @@
#include <Storages/MergeTree/DataPartsExchange.h>
#include <Storages/IStorage.h>
#include <Common/CurrentMetrics.h>
#include <Common/NetException.h>
#include <Common/typeid_cast.h>
#include <IO/HTTPCommon.h>
#include <Poco/File.h>
#include <ext/scope_guard.h>
@ -53,9 +51,6 @@ std::string Service::getId(const std::string & node_id) const
void Service::processQuery(const Poco::Net::HTMLForm & params, ReadBuffer & /*body*/, WriteBuffer & out, Poco::Net::HTTPServerResponse & response)
{
if (blocker.isCancelled())
throw Exception("Transferring part to replica was cancelled", ErrorCodes::ABORTED);
String client_protocol_version = params.get("client_protocol_version", REPLICATION_PROTOCOL_VERSION_WITHOUT_PARTS_SIZE);
@ -88,15 +83,11 @@ void Service::processQuery(const Poco::Net::HTMLForm & params, ReadBuffer & /*bo
++data.current_table_sends;
SCOPE_EXIT({--data.current_table_sends;});
StoragePtr owned_storage = storage.lock();
if (!owned_storage)
throw Exception("The table was already dropped", ErrorCodes::UNKNOWN_TABLE);
LOG_TRACE(log, "Sending part " << part_name);
try
{
auto storage_lock = owned_storage->lockStructureForShare(false, RWLockImpl::NO_QUERY);
auto storage_lock = data.lockStructureForShare(false, RWLockImpl::NO_QUERY);
MergeTreeData::DataPartPtr part = findPart(part_name);

View File

@ -20,8 +20,8 @@ namespace DataPartsExchange
class Service final : public InterserverIOEndpoint
{
public:
Service(MergeTreeData & data_, StoragePtr & storage_) : data(data_),
storage(storage_), log(&Logger::get(data.getLogName() + " (Replicated PartsService)")) {}
Service(MergeTreeData & data_)
: data(data_), log(&Logger::get(data.getLogName() + " (Replicated PartsService)")) {}
Service(const Service &) = delete;
Service & operator=(const Service &) = delete;
@ -33,8 +33,9 @@ private:
MergeTreeData::DataPartPtr findPart(const String & name);
private:
/// StorageReplicatedMergeTree::shutdown() waits for all parts exchange handlers to finish,
/// so Service will never access dangling reference to storage
MergeTreeData & data;
StorageWeakPtr storage;
Logger * log;
};

View File

@ -3785,7 +3785,15 @@ bool MergeTreeData::selectPartsAndMove()
bool MergeTreeData::areBackgroundMovesNeeded() const
{
return storage_policy->getVolumes().size() > 1;
auto policy = storage_policy;
if (policy->getVolumes().size() > 1)
return true;
if (policy->getVolumes().size() == 1 && policy->getVolumes()[0]->disks.size() > 1 && move_ttl_entries.size() > 0)
return true;
return false;
}
bool MergeTreeData::movePartsToSpace(const DataPartsVector & parts, SpacePtr space)

View File

@ -221,7 +221,9 @@ void MergeTreePartsMover::swapClonedPart(const MergeTreeData::DataPartPtr & clon
return;
}
cloned_part->renameTo(active_part->name);
/// Don't remove new directory but throw an error because it may contain part which is currently in use.
cloned_part->renameTo(active_part->name, false);
/// TODO what happen if server goes down here?
data->swapActivePart(cloned_part);

View File

@ -99,8 +99,8 @@ void ReplicatedMergeTreeAlterThread::run()
/// Temporarily cancel parts sending
ActionLock data_parts_exchange_blocker;
if (storage.data_parts_exchange_endpoint_holder)
data_parts_exchange_blocker = storage.data_parts_exchange_endpoint_holder->getBlocker().cancel();
if (storage.data_parts_exchange_endpoint)
data_parts_exchange_blocker = storage.data_parts_exchange_endpoint->blocker.cancel();
/// Temporarily cancel part fetches
auto fetches_blocker = storage.fetcher.blocker.cancel();

View File

@ -2931,10 +2931,8 @@ void StorageReplicatedMergeTree::startup()
getStorageID().getFullTableName() + " (ReplicatedMergeTreeQueue)",
getDataParts());
StoragePtr ptr = shared_from_this();
InterserverIOEndpointPtr data_parts_exchange_endpoint = std::make_shared<DataPartsExchange::Service>(*this, ptr);
data_parts_exchange_endpoint_holder = std::make_shared<InterserverIOEndpointHolder>(
data_parts_exchange_endpoint->getId(replica_path), data_parts_exchange_endpoint, global_context.getInterserverIOHandler());
data_parts_exchange_endpoint = std::make_shared<DataPartsExchange::Service>(*this);
global_context.getInterserverIOHandler().addEndpoint(data_parts_exchange_endpoint->getId(replica_path), data_parts_exchange_endpoint);
queue_task_handle = global_context.getBackgroundPool().addTask([this] { return queueTask(); });
if (areBackgroundMovesNeeded())
@ -2966,11 +2964,15 @@ void StorageReplicatedMergeTree::shutdown()
global_context.getBackgroundMovePool().removeTask(move_parts_task_handle);
move_parts_task_handle.reset();
if (data_parts_exchange_endpoint_holder)
if (data_parts_exchange_endpoint)
{
data_parts_exchange_endpoint_holder->getBlocker().cancelForever();
data_parts_exchange_endpoint_holder = nullptr;
global_context.getInterserverIOHandler().removeEndpointIfExists(data_parts_exchange_endpoint->getId(replica_path));
/// Ask all parts exchange handlers to finish asap. New ones will fail to start
data_parts_exchange_endpoint->blocker.cancelForever();
/// Wait for all of them
std::unique_lock lock(data_parts_exchange_endpoint->rwlock);
}
data_parts_exchange_endpoint.reset();
}
@ -5423,7 +5425,7 @@ ActionLock StorageReplicatedMergeTree::getActionLock(StorageActionBlockType acti
return fetcher.blocker.cancel();
if (action_type == ActionLocks::PartsSend)
return data_parts_exchange_endpoint_holder ? data_parts_exchange_endpoint_holder->getBlocker().cancel() : ActionLock();
return data_parts_exchange_endpoint ? data_parts_exchange_endpoint->blocker.cancel() : ActionLock();
if (action_type == ActionLocks::ReplicationQueue)
return queue.actions_blocker.cancel();

View File

@ -231,7 +231,7 @@ private:
std::atomic<bool> is_leader {false};
zkutil::LeaderElectionPtr leader_election;
InterserverIOEndpointHolderPtr data_parts_exchange_endpoint_holder;
InterserverIOEndpointPtr data_parts_exchange_endpoint;
MergeTreeDataSelectExecutor reader;
MergeTreeDataWriter writer;

View File

@ -36,7 +36,6 @@ const char * auto_config_build[]
"USE_INTERNAL_MEMCPY", "@USE_INTERNAL_MEMCPY@",
"USE_GLIBC_COMPATIBILITY", "@GLIBC_COMPATIBILITY@",
"USE_JEMALLOC", "@USE_JEMALLOC@",
"USE_TCMALLOC", "@USE_TCMALLOC@",
"USE_MIMALLOC", "@USE_MIMALLOC@",
"USE_UNWIND", "@USE_UNWIND@",
"USE_ICU", "@USE_ICU@",

View File

@ -67,5 +67,5 @@ sudo -u clickhouse UBSAN_OPTIONS='print_stacktrace=1' ./clickhouse-ubsan server
# How to use Memory Sanitizer
```
CC=clang-8 CXX=clang++-8 cmake -D ENABLE_HDFS=0 -D ENABLE_CAPNP=0 -D ENABLE_RDKAFKA=0 -D ENABLE_ICU=0 -D ENABLE_POCO_MONGODB=0 -D ENABLE_POCO_NETSSL=0 -D ENABLE_POCO_ODBC=0 -D ENABLE_ODBC=0 -D ENABLE_MYSQL=0 -D ENABLE_EMBEDDED_COMPILER=0 -D USE_INTERNAL_CAPNP_LIBRARY=0 -D USE_SIMDJSON=0 -D ENABLE_READLINE=0 -D SANITIZE=memory ..
CC=clang-8 CXX=clang++-8 cmake -D ENABLE_HDFS=0 -D ENABLE_CAPNP=0 -D ENABLE_RDKAFKA=0 -D ENABLE_ICU=0 -D ENABLE_POCO_MONGODB=0 -D ENABLE_POCO_NETSSL=0 -D ENABLE_POCO_ODBC=0 -D ENABLE_ODBC=0 -D ENABLE_MYSQL=0 -D ENABLE_EMBEDDED_COMPILER=0 -D USE_INTERNAL_CAPNP_LIBRARY=0 -D USE_SIMDJSON=0 -D SANITIZE=memory ..
```

View File

@ -715,3 +715,51 @@ def test_concurrent_alter_with_ttl_move(started_cluster, name, engine):
assert node1.query("SELECT COUNT() FROM {}".format(name)) == "500\n"
finally:
node1.query("DROP TABLE IF EXISTS {name}".format(name=name))
@pytest.mark.parametrize("name,positive", [
("test_double_move_while_select_negative", 0),
("test_double_move_while_select_positive", 1),
])
def test_double_move_while_select(started_cluster, name, positive):
try:
node1.query("""
CREATE TABLE {name} (
n Int64,
s String
) ENGINE = MergeTree
ORDER BY tuple()
PARTITION BY n
SETTINGS storage_policy='small_jbod_with_external'
""".format(name=name))
node1.query("INSERT INTO {name} VALUES (1, '{string}')".format(name=name, string=get_random_string(10 * 1024 * 1024)))
parts = node1.query("SELECT name FROM system.parts WHERE table = '{name}' AND active = 1".format(name=name)).splitlines()
assert len(parts) == 1
node1.query("ALTER TABLE {name} MOVE PART '{part}' TO DISK 'external'".format(name=name, part=parts[0]))
def long_select():
if positive:
node1.query("SELECT sleep(3), sleep(2), sleep(1), n FROM {name}".format(name=name))
thread = threading.Thread(target=long_select)
thread.start()
node1.query("ALTER TABLE {name} MOVE PART '{part}' TO DISK 'jbod1'".format(name=name, part=parts[0]))
# Fill jbod1 to force ClickHouse to make move of partition 1 to external.
node1.query("INSERT INTO {name} VALUES (2, '{string}')".format(name=name, string=get_random_string(9 * 1024 * 1024)))
node1.query("INSERT INTO {name} VALUES (3, '{string}')".format(name=name, string=get_random_string(9 * 1024 * 1024)))
node1.query("INSERT INTO {name} VALUES (4, '{string}')".format(name=name, string=get_random_string(9 * 1024 * 1024)))
# If SELECT locked old part on external, move shall fail.
assert node1.query("SELECT disk_name FROM system.parts WHERE table = '{name}' AND active = 1 AND name = '{part}'"
.format(name=name, part=parts[0])).splitlines() == ["jbod1" if positive else "external"]
thread.join()
assert node1.query("SELECT n FROM {name} ORDER BY n".format(name=name)).splitlines() == ["1", "2", "3", "4"]
finally:
node1.query("DROP TABLE IF EXISTS {name}".format(name=name))

View File

@ -0,0 +1,27 @@
<test>
<type>once</type>
<stop_conditions>
<any_of>
<!-- This is only for infinite running query. -->
<average_speed_not_changing_for_ms>2000</average_speed_not_changing_for_ms>
<total_time_ms>10000</total_time_ms>
</any_of>
</stop_conditions>
<substitutions>
<substitution>
<name>expr</name>
<values>
<value>number</value>
<value>toUInt32(number)</value>
<value>toUInt16(number)</value>
<value>toUInt8(number)</value>
<value>toInt32(number)</value>
<value>toFloat64(number)</value>
</values>
</substitution>
</substitutions>
<query>SELECT bitCount({expr}) FROM system.numbers</query>
</test>

View File

@ -1,2 +1 @@
default merge_ab x UInt8 0 0 0 0 0 0 0
default as_kafka x UInt8 0 0 0 0 0 0 0

View File

@ -1,26 +1,13 @@
DROP TABLE IF EXISTS merge_a;
DROP TABLE IF EXISTS merge_b;
DROP TABLE IF EXISTS merge_ab;
DROP TABLE IF EXISTS kafka;
DROP TABLE IF EXISTS as_kafka;
CREATE TABLE merge_a (x UInt8) ENGINE = StripeLog;
CREATE TABLE merge_b (x UInt8) ENGINE = StripeLog;
CREATE TABLE merge_ab AS merge(currentDatabase(), '^merge_[ab]$');
CREATE TABLE kafka (x UInt8)
ENGINE = Kafka
SETTINGS kafka_broker_list = 'kafka',
kafka_topic_list = 'topic',
kafka_group_name = 'group',
kafka_format = 'CSV';
CREATE TABLE as_kafka AS kafka ENGINE = Memory;
SELECT * FROM system.columns WHERE database = currentDatabase() AND table = 'merge_ab';
SELECT * FROM system.columns WHERE database = currentDatabase() AND table = 'as_kafka';
DROP TABLE merge_a;
DROP TABLE merge_b;
DROP TABLE merge_ab;
DROP TABLE kafka;
DROP TABLE as_kafka;

View File

@ -7,8 +7,8 @@ CLICKHOUSE_CLIENT=`echo ${CLICKHOUSE_CLIENT} | sed 's/'"--send_logs_level=${CLIC
$CLICKHOUSE_CLIENT --query="DROP TABLE IF EXISTS check;"
$CLICKHOUSE_CLIENT --query="CREATE TABLE check (x UInt64, y UInt64 DEFAULT throwIf(x > 10000000)) ENGINE = Memory;"
$CLICKHOUSE_CLIENT --query="CREATE TABLE check (x UInt64, y UInt64 DEFAULT throwIf(x > 1500000)) ENGINE = Memory;"
seq 1 11000000 | $CLICKHOUSE_CLIENT --query="INSERT INTO check(x) FORMAT TSV" 2>&1 | grep -q "Value passed to 'throwIf' function is non zero." && echo 'OK' || echo 'FAIL' ||:
seq 1 2000000 | $CLICKHOUSE_CLIENT --query="INSERT INTO check(x) FORMAT TSV" 2>&1 | grep -q "Value passed to 'throwIf' function is non zero." && echo 'OK' || echo 'FAIL' ||:
$CLICKHOUSE_CLIENT --query="DROP TABLE check;"

View File

@ -0,0 +1,24 @@
[(0,'hello'),(1,'world')]
[(0,'hello'),(1,'world')]
[(0,'hello'),(1,'world')]
[(0,'hello'),(1,'world')]
[(0,'0'),(0,'world')]
[(0,'1'),(1,'world')]
[(0,'2'),(2,'world')]
[(0,'3'),(3,'world')]
[(0,'4'),(4,'world')]
[(0,'5'),(5,'world')]
[(0,'6'),(6,'world')]
[(0,'7'),(7,'world')]
[(0,'8'),(8,'world')]
[(0,'9'),(9,'world')]
[(1,[]),(0,[]),(0,[])]
[(1,[]),(1,[]),(1,[])]
[(1,[]),(2,[]),(4,[])]
[(1,[]),(3,[]),(9,[])]
[(1,[]),(4,[]),(16,[])]
[(1,[]),(5,[]),(25,[])]
[(1,[]),(6,[]),(36,[])]
[(1,[]),(7,[]),(49,[])]
[(1,[]),(8,[]),(64,[])]
[(1,[]),(9,[]),(81,[])]

View File

@ -0,0 +1,7 @@
SELECT arrayZip([0, 1], ['hello', 'world']);
SELECT arrayZip(materialize([0, 1]), ['hello', 'world']);
SELECT arrayZip([0, 1], materialize(['hello', 'world']));
SELECT arrayZip(materialize([0, 1]), materialize(['hello', 'world']));
SELECT arrayZip([0, number], [toString(number), 'world']) FROM numbers(10);
SELECT arrayZip([1, number, number * number], [[], [], []]) FROM numbers(10);

View File

@ -0,0 +1,17 @@
111
1
0.5
0.33
0.25
0.2
0.17
0.14
0.12
0.11
1
-1
2
2
\N
-42
1

View File

@ -0,0 +1,11 @@
SELECT ifNotFinite(round(1 / number, 2), 111) FROM numbers(10);
SELECT ifNotFinite(1, 2);
SELECT ifNotFinite(-1.0, 2);
SELECT ifNotFinite(nan, 2);
SELECT ifNotFinite(-1 / 0, 2);
SELECT ifNotFinite(log(0), NULL);
SELECT ifNotFinite(sqrt(-1), -42);
SELECT ifNotFinite(1234567890123456789, -1234567890123456789); -- { serverError 386 }
SELECT ifNotFinite(NULL, 1);

View File

@ -0,0 +1,21 @@
0
1
1
2
1
2
2
3
1
2
4
0
1
8
64
32
16
8
1 10 000000000000F03F
-1 11 000000000000F0BF
inf 11 000000000000F07F

View File

@ -0,0 +1,13 @@
SELECT bitCount(number) FROM numbers(10);
SELECT avg(bitCount(number)) FROM numbers(256);
SELECT bitCount(0);
SELECT bitCount(1);
SELECT bitCount(-1);
SELECT bitCount(toInt64(-1));
SELECT bitCount(toInt32(-1));
SELECT bitCount(toInt16(-1));
SELECT bitCount(toInt8(-1));
SELECT x, bitCount(x), hex(reinterpretAsString(x)) FROM VALUES ('x Float64', (1), (-1), (inf));

View File

@ -0,0 +1,9 @@
1
\N
\N
\N
\N
---
---
\N
\N

View File

@ -0,0 +1,42 @@
SELECT id
FROM
(
SELECT 1 AS id
UNION ALL
SELECT NULL
UNION ALL
SELECT NULL
)
ALL FULL OUTER JOIN
(
SELECT 1 AS id
UNION ALL
SELECT NULL
UNION ALL
SELECT NULL
) USING (id)
ORDER BY id;
SELECT '---';
SELECT *
FROM
(
SELECT NULL AS x
)
INNER JOIN
(
SELECT NULL AS x
) USING (x);
SELECT '---';
SELECT *
FROM
(
SELECT NULL AS x
)
FULL OUTER JOIN
(
SELECT NULL AS x
) USING (x);

View File

@ -176,7 +176,8 @@ def parse_env_variables(build_type, compiler, sanitizer, package_type, image_typ
result.append("ALIEN_PKGS='" + ' '.join(['--' + pkg for pkg in alien_pkgs]) + "'")
if unbundled:
cmake_flags.append('-DUNBUNDLED=1 -DENABLE_MYSQL=0 -DENABLE_POCO_ODBC=0 -DENABLE_ODBC=0')
# TODO: fix build with ENABLE_RDKAFKA
cmake_flags.append('-DUNBUNDLED=1 -DENABLE_MYSQL=0 -DENABLE_POCO_ODBC=0 -DENABLE_ODBC=0 -DENABLE_READLINE=0 -DENABLE_RDKAFKA=0')
if split_binary:
cmake_flags.append('-DUSE_STATIC_LIBRARIES=0 -DSPLIT_SHARED_LIBRARIES=1 -DCLICKHOUSE_SPLIT_BINARY=1')

View File

@ -58,12 +58,6 @@ $ export CC=gcc-9
$ export CXX=g++-9
```
## Install Required Libraries from Packages
```bash
$ sudo apt-get install libreadline-dev
```
## Checkout ClickHouse Sources
```bash

View File

@ -11,7 +11,7 @@ $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/inst
## Install Required Compilers, Tools, and Libraries
```bash
$ brew install cmake ninja libtool gettext readline
$ brew install cmake ninja libtool gettext
```
## Checkout ClickHouse Sources

View File

@ -4,6 +4,10 @@ Building of ClickHouse is supported on Linux, FreeBSD and Mac OS X.
If you use Windows, you need to create a virtual machine with Ubuntu. To start working with a virtual machine please install VirtualBox. You can download Ubuntu from the website: https://www.ubuntu.com/#download. Please create a virtual machine from the downloaded image (you should reserve at least 4GB of RAM for it). To run a command line terminal in Ubuntu, please locate a program containing the word "terminal" in its name (gnome-terminal, konsole etc.) or just press Ctrl+Alt+T.
# If you use 32-bit system
ClickHouse cannot work or build on 32-bit system. You should acquire access to 64-bit system and you can continue reading.
# Creating a repository on GitHub
@ -96,15 +100,7 @@ Next, check the version of CMake: `cmake --version`. If it is below 3.3, you sho
# Optional External Libraries
ClickHouse uses several external libraries for building. Most of them do not need to be installed separately as they are built together with ClickHouse from the sources located in the submodules. You can check the list in `contrib`.
There is one library that is not built from sources but is supplied by the system: Readline, and thus is recommended to be installed.
Ubuntu: `sudo apt install libreadline-dev`
Mac OS X: `brew install readline`
However, these libraries are optional and ClickHouse can well be built without them. ICU is used for support of `COLLATE` in `ORDER BY` (i.e. for sorting in turkish alphabet). Readline is used for more convenient command input in clickhouse-client.
ClickHouse uses several external libraries for building. All of them do not need to be installed separately as they are built together with ClickHouse from the sources located in the submodules. You can check the list in `contrib`.
# C++ Compiler

View File

@ -21,11 +21,11 @@ If you use Oracle through the ODBC driver as a source of external dictionaries,
NLS_LANG=RUSSIAN_RUSSIA.UTF8
```
## How to export data from ClickHouse to the file?
## How Do I Export Data from ClickHouse to a File? {#how-to-export-to-file}
### Using INTO OUTFILE Clause
Add [INTO OUTFILE](../query_language/select/#into-outfile-clause) clause to your query.
Add an [INTO OUTFILE](../query_language/select/#into-outfile-clause) clause to your query.
For example:
@ -41,11 +41,11 @@ For example:
SELECT * FROM table INTO OUTFILE 'file' FORMAT CSV
```
### Using File-engine Table
### Using a File-Engine Table
See [File](../operations/table_engines/file.md).
### Using Command-line Redirection
### Using Command-Line Redirection
```sql
$ clickhouse-client --query "SELECT * from table" > result.txt

View File

@ -53,7 +53,7 @@ Only a single query is run, so everything after the semicolon is ignored.
You can specify `\G` instead of or after the semicolon. This indicates Vertical format. In this format, each value is printed on a separate line, which is convenient for wide tables. This unusual feature was added for compatibility with the MySQL CLI.
The command line is based on 'readline' (and 'history' or 'libedit', or without a library, depending on the build). In other words, it uses the familiar keyboard shortcuts and keeps a history.
The command line is based on 'replxx' (similar to 'readline'). In other words, it uses the familiar keyboard shortcuts and keeps a history.
The history is written to `~/.clickhouse-client-history`.
By default, the format used is PrettyCompact. You can change the format in the FORMAT clause of the query, or by specifying `\G` at the end of the query, using the `--format` or `--vertical` argument in the command line, or using the client configuration file.

View File

@ -968,7 +968,7 @@ To exchange data with Hadoop, you can use [HDFS table engine](../operations/tabl
## ORC {#data-format-orc}
[Apache ORC](https://orc.apache.org/) is a columnar storage format widespread in the Hadoop ecosystem. ClickHouse supports only read operations for this format.
[Apache ORC](https://orc.apache.org/) is a columnar storage format widespread in the Hadoop ecosystem. You can only insert data in this format to ClickHouse.
### Data Types Matching
@ -991,18 +991,18 @@ The table below shows supported data types and how they match ClickHouse [data t
| `STRING`, `BINARY` | [String](../data_types/string.md) |
| `DECIMAL` | [Decimal](../data_types/decimal.md) |
ClickHouse supports configurable precision of `Decimal` type. The `INSERT` query treats the ORC `DECIMAL` type as the ClickHouse `Decimal128` type.
ClickHouse supports configurable precision of the `Decimal` type. The `INSERT` query treats the ORC `DECIMAL` type as the ClickHouse `Decimal128` type.
Unsupported ORC data types: `DATE32`, `TIME32`, `FIXED_SIZE_BINARY`, `JSON`, `UUID`, `ENUM`.
Data types of a ClickHouse table columns can differ from the corresponding fields of the ORC data inserted. When inserting data, ClickHouse interprets data types according to the table above and then [cast](../query_language/functions/type_conversion_functions/#type_conversion_function-cast) the data to that data type which is set for the ClickHouse table column.
The data types of ClickHouse table columns don't have to match the corresponding ORC data fields. When inserting data, ClickHouse interprets data types according to the table above and then [casts](../query_language/functions/type_conversion_functions/#type_conversion_function-cast) the data to the data type set for the ClickHouse table column.
### Inserting Data
You can insert Parquet data from a file into ClickHouse table by the following command:
You can insert ORC data from a file into ClickHouse table by the following command:
```bash
$ cat {filename} | clickhouse-client --query="INSERT INTO {some_table} FORMAT ORC"
$ cat filename.orc | clickhouse-client --query="INSERT INTO some_table FORMAT ORC"
```
To exchange data with Hadoop, you can use [HDFS table engine](../operations/table_engines/hdfs.md).

View File

@ -172,7 +172,7 @@ $ echo 'SELECT number FROM numbers LIMIT 10' | curl 'http://localhost:8123/?data
By default, the database that is registered in the server settings is used as the default database. By default, this is the database called 'default'. Alternatively, you can always specify the database using a dot before the table name.
The username and password can be indicated in one of two ways:
The username and password can be indicated in one of three ways:
1. Using HTTP Basic Authentication. Example:
@ -186,6 +186,12 @@ $ echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
$ echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
```
3. Using X-ClickHouse-User and X-ClickHouse-Key headers. Example:
```bash
$ echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'http://localhost:8123/' -d @-
```
If the user name is not specified, the `default` name is used. If the password is not specified, the empty password is used.
You can also use the URL parameters to specify any settings for processing a single query, or entire profiles of settings. Example:http://localhost:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1

View File

@ -1,16 +1,14 @@
# How To Test Your Hardware With ClickHouse
Draft.
With this instruction you can run basic ClickHouse performance test on any server without installation of ClickHouse packages.
1. Go to "commits" page: https://github.com/ClickHouse/ClickHouse/commits/master
\1. Go to "commits" page: [https://github.com/ClickHouse/ClickHouse/commits/master](https://github.com/ClickHouse/ClickHouse/commits/master)
2. Click on the first green check mark or red cross with green "ClickHouse Build Check" and click on the "Details" link near "ClickHouse Build Check".
\2. Click on the first green check mark or red cross with green "ClickHouse Build Check" and click on the "Details" link near "ClickHouse Build Check".
3. Copy the link to "clickhouse" binary for amd64 or aarch64.
\3. Copy the link to "clickhouse" binary for amd64 or aarch64.
4. ssh to the server and download it with wget:
\4. ssh to the server and download it with wget:
```
# For amd64:
wget https://clickhouse-builds.s3.yandex.net/0/00ba767f5d2a929394ea3be193b1f79074a1c4bc/1578163263_binary/clickhouse
@ -20,7 +18,7 @@ wget https://clickhouse-builds.s3.yandex.net/0/00ba767f5d2a929394ea3be193b1f7907
chmod a+x clickhouse
```
5. Download configs:
\5. Download configs:
```
wget https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/dbms/programs/server/config.xml
wget https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/dbms/programs/server/users.xml
@ -29,16 +27,19 @@ wget https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/dbms/program
wget https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/dbms/programs/server/config.d/log_to_console.xml -O config.d/log_to_console.xml
```
6. Download benchmark files:
\6. Download benchmark files:
```
wget https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/dbms/benchmark/clickhouse/benchmark-new.sh
chmod a+x benchmark-new.sh
wget https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/dbms/benchmark/clickhouse/queries.sql
```
7. Download test data:
\7. Download test data:
According to the instruction:
https://clickhouse.yandex/docs/en/getting_started/example_datasets/metrica/
[https://clickhouse.yandex/docs/en/getting_started/example_datasets/metrica/](https://clickhouse.yandex/docs/en/getting_started/example_datasets/metrica/)
("hits" table containing 100 million rows)
```
@ -47,26 +48,29 @@ tar xvf hits_100m_obfuscated_v1.tar.xz -C .
mv hits_100m_obfuscated_v1/* .
```
8. Run the server:
\8. Run the server:
```
./clickhouse server
```
9. Check the data:
\9. Check the data:
ssh to the server in another terminal
```
./clickhouse client --query "SELECT count() FROM hits_100m_obfuscated"
100000000
```
10. Edit the benchmark-new.sh, change "clickhouse-client" to "./clickhouse client" and add "--max_memory_usage 100000000000" parameter.
\10. Edit the benchmark-new.sh, change "clickhouse-client" to "./clickhouse client" and add "--max_memory_usage 100000000000" parameter.
```
mcedit benchmark-new.sh
```
11. Run the benchmark:
\11. Run the benchmark:
```
./benchmark-new.sh hits_100m_obfuscated
```
12. Send the numbers and the info about your hardware configuration to clickhouse-feedback@yandex-team.com
\12. Send the numbers and the info about your hardware configuration to clickhouse-feedback@yandex-team.com
All the results are published here: [https://clickhouse.yandex/benchmark_hardware.html](https://clickhouse.yandex/benchmark_hardware.html)

View File

@ -78,6 +78,91 @@ round(3.55, 1) = 3.6
round(3.65, 1) = 3.6
```
**See Also**
- [roundBankers](#roundbankers)
## roundBankers {#roundbankers}
Rounds a number to a specified decimal position.
- If rounding number is a half between two numbers, the function uses banker's rounding.
Banker's rounding is a method of rounding fractional numbers. When the rounding number is a half between two numbers, it is rounded to the nearest even number. E.g. 3.5 rounds up to 4, 2.5 rounds down to 2.
- In other cases function rounds numbers to the nearest integer.
Using banker's rounding, you can reduce the effect of rounding numbers on the result of summing or subtracting these numbers.
For example, sum numbers 1.5, 2.5, 3.5, 4.5 with different rounding:
- No rounding: 1.5 + 2.5 + 3.5 + 4.5 = 12.
- Banker's rounding: 2 + 2 + 4 + 4 = 12.
- Rounding to the nearest integer: 2 + 3 + 4 + 5 = 14.
**Syntax**
```sql
roundBankers(expression [, decimal_places])
```
**Parameters**
- `expression` — A number to be rounded. Can be any [expression](../syntax.md#syntax-expressions) returning the numeric [data type](../../data_types/index.md#data_types).
- `decimal-places` — Decimal places. An integer number.
- `decimal-places > 0` — The function rounds the number to the given position right of the decimal point. E.g. `roundBankers(3.55, 1) = 3.6`.
- `decimal-places < 0` — The function rounds the number to the given position left of the decimal point. E.g. `roundBankers(24.55, -1) = 20`.
- `decimal-places = 0` — The function rounds the number to integer. In this case the argument can be omitted. E.g. `roundBankers(2.5) = 2`.
**Returned value**
A value rounded by banker's rounding method.
### Examples
**Example of use**
Query:
```sql
SELECT number / 2 AS x, roundBankers(x, 0) AS b fROM system.numbers limit 10
```
Result:
```text
┌───x─┬─b─┐
│ 0 │ 0 │
│ 0.5 │ 0 │
│ 1 │ 1 │
│ 1.5 │ 2 │
│ 2 │ 2 │
│ 2.5 │ 2 │
│ 3 │ 3 │
│ 3.5 │ 4 │
│ 4 │ 4 │
│ 4.5 │ 4 │
└─────┴───┘
```
**Examples of Banker's rounding**
```text
roundBankers(0.4) = 0
roundBankers(-3.5) = -4
roundBankers(4.5) = 4
roundBankers(3.55, 1) = 3.6
roundBankers(3.65, 1) = 3.6
roundBankers(10.35, 1) = 10.4
roundBankers(10.755, 2) = 11,76
```
**See Also**
- [round](#rounding_functions-round)
## roundToExp2(num)
Accepts a number. If the number is less than one, it returns 0. Otherwise, it rounds the number down to the nearest (whole non-negative) degree of two.

View File

@ -53,7 +53,7 @@ cat file.csv | clickhouse-client --database=test --query="INSERT INTO test FORMA
شما میتوانید از `\G` به جای سیمی کالن یا بعد از سیمی کالن استفاده کنید. این علامت، فرمت Vertical را نشان می دهد. در این فرمت، هر مقدار در یک خط جدا چاپ می شود که برای جداول عریض مناسب است. این ویژگی غیرمعمول برای سازگاری با MySQL CLI اضافه شد.
command line برا پایه 'readline' (و 'history' یا 'libedit'، یه بدون کتابخانه بسته به build) می باشد. به عبارت دیگر، این محیط از shortcut های آشنا استفاده می کند و history دستورات را نگه می دار. history ها در فایل ~/.clickhouse-client-history نوشته می شوند.
command line برا پایه 'replxx' می باشد. به عبارت دیگر، این محیط از shortcut های آشنا استفاده می کند و history دستورات را نگه می دار. history ها در فایل ~/.clickhouse-client-history نوشته می شوند.
به صورت پیش فرض فرمت خروجی PrettyCompact می باشد. شما میتوانید از طریق دستور FORMAT در یک query، یا با مشخص کردن `\G` در انتهای query، استفاده از آرگومان های `--format` یا `--vertical` یا از کانفیگ فایل کلاینت، فرمت خروجی را مشخص کنید.

View File

@ -5,6 +5,10 @@
Если вы используете Windows, вам потребуется создать виртуальную машину с Ubuntu. Для работы с виртуальной машиной, установите VirtualBox. Скачать Ubuntu можно на сайте: https://www.ubuntu.com/#download Создайте виртуальную машину из полученного образа. Выделите для неё не менее 4 GB оперативной памяти. Для запуска терминала в Ubuntu, найдите в меню программу со словом terminal (gnome-terminal, konsole или что-то в этом роде) или нажмите Ctrl+Alt+T.
# Если вы используете 32-битную систему
ClickHouse не работает и не собирается на 32-битных системах. Получите доступ к 64-битной системе и продолжайте.
# Создание репозитория на GitHub
@ -96,15 +100,7 @@ brew install cmake ninja
# Необязательные внешние библиотеки
ClickHouse использует для сборки некоторое количество внешних библиотек. Большинство из них не требуется отдельно устанавливать, так как они собираются вместе с ClickHouse, из исходников, которые расположены в submodules. Посмотреть набор этих библиотек можно в директории contrib.
Одна библиотека не собирается из исходников, а используется из системы: Readline, и её рекомендуется установить.
Ubuntu: `sudo apt install libreadline-dev`
Mac OS X: `brew install readline`
Впрочем, эти библиотеки не обязательны для работы и ClickHouse может быть собран без них. ICU используется для поддержки `COLLATE` в `ORDER BY` (например, для сортировки с учётом турецкого алфавита). Readline используется для более удобного набора команд в интерактивном режиме в clickhouse-client.
ClickHouse использует для сборки некоторое количество внешних библиотек. Но ни одну из них не требуется отдельно устанавливать, так как они собираются вместе с ClickHouse, из исходников, которые расположены в submodules. Посмотреть набор этих библиотек можно в директории contrib.
# Компилятор C++

View File

@ -16,9 +16,11 @@
Изначально делал [Андрей Чулков](https://github.com/achulkov2), ВШЭ, теперь доделывает [Ольга Хвостикова](https://github.com/stavrolia), но сроки немного сдвинуты из-за задачи 25.9. Будем надеятся на реализацию к концу ноября. Впрочем, [Андрей Чулков](https://github.com/achulkov2) скоро сможет помочь её доделать.
Upd. Доделывать будет другой человек. Хотелось бы в Q1, но приоритет не высокий.
### 1.2. Wait-free каталог баз данных.
Делает [Александр Токмаков](https://github.com/tavplubix), первый рабочий вариант в декабре 2019. Нужно для DataLens и Яндекс.Метрики.
Q1. Делает [Александр Токмаков](https://github.com/tavplubix), первый рабочий вариант в декабре 2019. Нужно для DataLens и Яндекс.Метрики.
Манипуляции с каталогом баз данных: запросы CREATE TABLE, DROP TABLE, RENAME TABLE и DATABASE, требуют синхронизации с помощью блокировок. Эта синхронизация становится весьма сложной, так как на неё полагается много внутренних структур данных.
@ -26,7 +28,7 @@
### 1.3. Неблокирующие ALTER.
И полностью immutable куски. Делает [Александр Сапин](https://github.com/alesapin). Готов приступить к задаче в конце ноября 2019. Нужно для Яндекс.Метрики.
Q1. И полностью immutable куски. Делает [Александр Сапин](https://github.com/alesapin). Готов приступить к задаче в конце ноября 2019. Нужно для Яндекс.Метрики.
### 1.4. Нетранзитивные ALTER столбцов.
@ -38,6 +40,8 @@
### 1.6. Полиморфные куски данных.
Компактные куски - Q1, куски в оперативке Q1/Q2.
Делает [Антон Попов](https://github.com/CurtizJ), первый рабочий вариант в декабре. Пререквизит чтобы снизить сложность мелких INSERT, что в свою очередь нужно для 1.12, иначе задача 1.12 не сможет нормально работать. Особенно нужно для Яндекс.Облака.
Данные в таблицах типа MergeTree в ClickHouse хранятся в виде набора независимых "кусков". Внутри куска, каждый столбец, а также индекс, хранится в отдельных файлах. Это сделано для возможности быстрых манипуляций со столбцами (пример - запрос ALTER DROP COLUMN). При вставке данных (INSERT), создаётся новый кусок. Для таблиц с большим количеством столбцов, запросы INSERT с маленьким количеством строк являются неэффективными, так как требуют создания большого количества файлов в файловой системе. Это является врождённой особенностью ClickHouse - одной из первой проблем, с которыми сталкиваются пользователи. Пользователям приходится буферизовывать данные и собирать их в более крупные пачки перед вставкой в ClickHouse.
@ -54,6 +58,8 @@
Делает [Владимир Чеботарёв](https://github.com/excitoon), Altinity. Декабрь 2019.
Q1. Закоммичено, но есть технический долг, который исправляется сейчас.
### 1.9. Использование TTL для прореживания данных.
Будет делать Сорокин Николай, ВШЭ и Яндекс.
@ -86,6 +92,8 @@
### 1.11. Виртуальная файловая система.
Q2.
Нужно для Яндекс.Облака. Делает Александр, Яндекс.Облако, а также Олег Ершов, ВШЭ и Яндекс.
ClickHouse использует для хранения данных локальную файловую систему. Существует сценарий работы, в котором размещение старых (архивных) данных было бы выгодно на удалённой файловой системе. Если файловая система POSIX совместимая, то это не составляет проблем: ClickHouse успешно работает с Ceph, GlusterFS, MooseFS. Также востребованным является сценарий использования S3 (из-за доступности в облаке) или HDFS (для интеграции с Hadoop). Но эти файловые системы не являются POSIX совместимыми. Хотя для них существуют FUSE драйверы, но скорость работы сильно страдает и поддержка неполная.
@ -94,6 +102,8 @@ ClickHouse использует небольшое подмножество фу
### 1.12. Экспериментальная реализация VFS поверх S3 и HDFS.
Q2.
Нужно для Яндекс.Облака. Требует 1.11. Желательно 1.6 и 1.18.
Делает Александр, Яндекс.Облако (сначала часть для S3), а также Олег Ершов, ВШЭ и Яндекс.
@ -103,8 +113,10 @@ ClickHouse использует небольшое подмножество фу
### 1.14. Не писать столбцы, полностью состоящие из нулей.
Антон Попов. Q1/Q2.
В очереди. Простая задача, является небольшим пререквизитом для потенциальной поддержки полуструктурированных данных.
### 1.15. Возможность иметь разный первичный ключ в разных кусках.
Сложная задача, только после 1.3.
@ -130,6 +142,9 @@ ClickHouse использует небольшое подмножество фу
Делает [Николай Кочетов](https://github.com/KochetovNicolai). Финальная стадия разработки. Включение по-умолчанию в конце декабря 2019. Удаление старого кода в начале 2020.
Upd. На данный момент исправляются проблемы с регрессиями производительности в отдельных случаях. Кажется, что все проблемы исправлены.
Включение по-умолчанию в Q1, но остаётся вторая часть задачи по корректному выделению async части.
### 2.2. Инфраструктура событий/метрик/ограничений/квот/трассировки.
В очереди. https://gist.github.com/alexey-milovidov/d62d73222d83b9319dc519cbb13aeff6
@ -152,11 +167,11 @@ ClickHouse использует небольшое подмножество фу
### 2.7. Нормализация Context.
В очереди.
В очереди. Нужно для YQL.
### 2.8. Декларативный парсер запросов.
Низкий приоритет. Задачу хочет сделать [Иван Лежанкин](https://github.com/abyss7) в свободное время, но пока ничего нет.
Средний приоритет. Нужно для YQL.
### 2.9. Логгировние в format-стиле.
@ -193,7 +208,7 @@ ClickHouse использует небольшое подмножество фу
### 3.1. Перенос документации по функциям в код.
Требует 2.12 и 2.13.
Требует 2.12 и 2.13. Хотим в Q1/Q2, средний приоритет.
### 3.2. Перенос однородных частей документации в код.
@ -201,7 +216,7 @@ ClickHouse использует небольшое подмножество фу
### 3.3. Исправить катастрофически отвратительно неприемлемый поиск по документации.
[Иван Блинков](https://github.com/blinkov/) - очень хороший человек. Сам сайт документации основан на технологиях, не удовлетворяющих требованиям задачи, и эти технологии трудно исправить.
[Иван Блинков](https://github.com/blinkov/) - очень хороший человек. Сам сайт документации основан на технологиях, не удовлетворяющих требованиям задачи, и эти технологии трудно исправить. Задачу будет делать первый встретившийся нам frontend разработчик, которого мы сможем заставить это сделать.
### 3.4. + Добавить японский язык в документацию.
@ -212,7 +227,7 @@ ClickHouse использует небольшое подмножество фу
### 4.1. Уменьшение числа потоков при распределённых запросах.
[Никита Лапков](https://github.com/laplab), весна 2020.
[Никита Лапков](https://github.com/laplab), весна 2020. Upd. Есть прототип.
### 4.2. Спекулятивное выполнение запросов на нескольких репликах.
@ -231,7 +246,7 @@ ClickHouse использует небольшое подмножество фу
### 4.4. Ограничение сетевой полосы при репликации.
Дмитрий Григорьев, ВШЭ.
Дмитрий Григорьев, ВШЭ. Нужно для Метрики.
### 4.5. Возможность продолжить передачу куска данных при репликации после сбоя.
@ -251,19 +266,20 @@ ClickHouse использует небольшое подмножество фу
### 5.1. Разделение задач на более мелкие куски в clickhouse-copier.
Нужно для Метрики, в очереди, но исполнитель не назначен, есть шанс успеть в 2019.
Q1. Нужно для Метрики, в очереди. Никита Михайлов.
### 5.2. Автонастройка лимита на оперативку и размера кэшей.
### 5.3. Встроенная ручка для Prometheus и, возможно, Solomon.
### 5.3. + Встроенная ручка для Prometheus.
Простая задача. https://github.com/Vdimir
Сделано. https://github.com/Vdimir
### 5.4. Opt-in сообщать в клиенте, если вышла новая версия.
### 5.5. LTS релизы.
### 5.5. + LTS релизы.
Требует 7.5. Задачу хочет Метрика, Облако, БК, Маркет и Altinity. Первой LTS версией уже стала версия 19.14.
Метрика, БК, Маркет уже используют более свежие версии чем LTS.
## 6. Инструментирование.
@ -271,15 +287,15 @@ ClickHouse использует небольшое подмножество фу
### 6.1. Исправления сэмплирующего профайлера запросов.
Михаил Филимонов, Altinity. Ноябрь 2019. Сделано.
Осталось ещё проверить работоспособность профайлера в первом потоке (что важно для INSERT).
Осталось ещё проверить работоспособность профайлера в первом потоке (что важно для INSERT). Иван Лежанкин. Q1.
### 6.2. Добавление memory profiler.
Сравнительно простая задача, но только для опытных разработчиков. Нужна всем.
Сравнительно простая задача, но только для опытных разработчиков. Нужна всем. Иван Лежанкин. Q1.
### 6.3. Учёт оперативки total расширить не только на запросы.
Исправление долгоживущей проблемы с дрифтом учёта оперативки. Нужна для Метрики и БК.
Исправление долгоживущей проблемы с дрифтом учёта оперативки. Нужна для Метрики и БК. Иван Лежанкин. Q1.
### 6.4. Поддержка perf events как метрик запроса.
@ -291,11 +307,11 @@ ClickHouse использует небольшое подмножество фу
Требует 2.2.
### 6.6. Стек трейс для любых исключений.
### 6.6. + Стек трейс для любых исключений.
Сейчас есть стек трейс для почти всех, но не всех исключений. Требует 7.4.
### 6.7. Таблица system.stack_trace.
### 6.7. + Таблица system.stack_trace.
Сравнительно простая задача, но только для опытных разработчиков.
@ -327,7 +343,7 @@ ClickHouse использует небольшое подмножество фу
Сейчас включено только при сборке с clang, но продакшен сборка использует gcc.
Требует 7.2 и, возможно, 7.1 (только в случае новой версии ICU).
### 7.5. Начать публиковать LTS релизы.
### 7.5. + Начать публиковать LTS релизы.
[Александр Сапин](https://github.com/alesapin).
@ -364,11 +380,17 @@ UBSan включен в функциональных тестах, но не в
При сборке с clang, -Weverything уже включено. Но в gcc есть уникальные warning-и, отсутствующие в clang.
Сделал Wolf Kreuzerkrieg.
### 7.14. Альтернатива для readline и libedit.
### 7.14. + Альтернатива для readline и libedit.
Тагир Кускаров, ВШЭ. Посмотрим на https://github.com/AmokHuginnsson/replxx
Подключение replxx вместо readline сделал Иван Лежанкин.
Для ввода запросов в интерактивном режиме в клиенте командной строки clickhouse-client используется библиотека readline или libedit.
### 7.14.1. Улучшение возможностей интерактивного режима clickhouse-client.
Тагир Кускаров, ВШЭ.
Upd. В рамках данной задачи добавляем подстветку синтаксиса и исправление проблем со вставкой больших запросов.
Для ввода запросов в интерактивном режиме в клиенте командной строки clickhouse-client использовалась библиотека readline или libedit.
Библиотеки readline и libedit обладает следующими недостатками:
- (исправлено в новых версиях readline) Очень низкая производительность вставки больших кусков текста. Вставка каждого следующего символа имеет сложность O(n = количество предыдущих символов) и при вставке 1 МБ текста, скорость падает до десятков байт в секунду.
@ -407,11 +429,13 @@ UBSan включен в функциональных тестах, но не в
Уже давно собираются универсальные tgz пакеты, но по нелепой случайности из них исчез install скрипт.
[Александр Сапин](https://github.com/alesapin). Может делегировать эту задачу кому угодно.
Upd. Сделано всё кроме инструкции на сайте. Для этого требуется создать директории testing/stable/prestable на repo.yandex.ru. Внезапно оказалось, что человек, отвечающий за это, в отпуске, и он не отвечает на вопрос, кто его заместитель. Q1.
### 7.18.1. Доделать бинарники под Mac.
Уже есть автосборка бинарников под Mac на каждый коммит и PR, но с недостатками.
[Иван Лежанкин](https://github.com/abyss7). Требует 7.1, 7.2. Рекомендуется 7.14. Сейчас не хватает по крайней мере SSL и ICU. Нужно для Яндекс.Облака.
Upd. Сделано SSL. Ориентируемся в Q1, но приоритет средний и может потеряться.
### 7.18. Поместить ссылку на собранные бинарники под Mac на сайт.
@ -480,6 +504,8 @@ Fuzzing тестирование - это тестирование случай
Также можно сделать функции с детерминированным генератором случайных чисел (аргументом передаётся seed) для воспроизводимости тестовых кейсов.
Upd. Сергей Штыков сделал функцию `randomPrintableASCII`.
### 7.24. Fuzzing лексера и парсера запросов; кодеков и форматов.
Андрей Некрашевич, ВШЭ.
@ -496,6 +522,9 @@ Fuzzing тестирование - это тестирование случай
Затем, возможно, [Иван Лежанкин](https://github.com/abyss7). Но сейчас приостановлено, так как Максим из YT должен исправить регрессию производительности в анализе индекса.
Максим из YT сказал, что сделает это после нового года.
Максим из YT сказал, что "мы планируем в январе добиться".
Нужно для CHYT и YQL.
### 7.26. Побайтовая идентичность репозитория с Аркадией.
@ -529,11 +558,11 @@ Fuzzing тестирование - это тестирование случай
### 7.33. Выкладывать патч релизы в репозиторий автоматически.
[Александр Сапин](https://github.com/alesapin). Может делегировать эту задачу кому угодно.
В очереди. Иван Лежанкин.
### 7.34. Бэкпортировать bugfix автоматически.
[Александр Сапин](https://github.com/alesapin). Может делегировать эту задачу кому угодно.
В очереди. Иван Лежанкин.
### 7.35. Начальные правила для авто-merge.
@ -564,6 +593,8 @@ Altinity.
[Ольга Хвостикова](https://github.com/stavrolia).
Уменьшение числа stream-ов сделано, а вот правильная поддержка диапазонов - нет. Будем надеяться на Q1/Q2.
### 8.4. Унификация File, HDFS, S3 под URL.
### 8.5. + Аутентификация в S3.
@ -579,7 +610,7 @@ Altinity.
В ядрах 2.6 отсутствует один системный вызов, который библиотека hdfs3 использует без необходимости.
Сделал Amos Bird.
### 8.8. Поддержка виртуальных столбцов с именем файла и путём.
### 8.8. + Поддержка виртуальных столбцов с именем файла и путём.
[Ольга Хвостикова](https://github.com/stavrolia).
@ -611,10 +642,26 @@ Altinity.
### 8.16. Поддержка формата Avro.
Павел Круглов, ВШЭ и Яндекс.
Andrew Onyshchuk. Есть pull request. Q1.
Формат Apache Avro является компактным структурированным построчным бинарным форматом данных с внешней схемой. Этот формат часто используется совместно с Kafka и поддержка его в качестве одного из форматов ввода-вывода в ClickHouse является востребованной пользователями.
### 8.16.1. Поддержка формата JSONEachRow, засунутого в массив.
Павел Круглов, ВШЭ и Яндекс.
### 8.16.2. Поддержка формата Thrift.
Павел Круглов, ВШЭ и Яндекс.
### 8.16.3. Поддержка формата MsgPack.
Павел Круглов, ВШЭ и Яндекс.
### 8.16.4. Формат Regexp.
Павел Круглов, ВШЭ и Яндекс.
### 8.17. ClickHouse как MySQL реплика.
Ильяс Адюгамов, ВШЭ.
@ -642,6 +689,7 @@ Maxim Fedotov, Wargaming + Yuri Baranov, Яндекс.
### 8.21. Поддержка произвольного количества языков для имён регионов.
Нужно для БК. Декабрь 2019.
В декабре для БК сделан минимальный вариант этой задачи.
### 8.22. Поддержка синтаксиса для переменных в стиле MySQL.
@ -689,7 +737,7 @@ ClickHouse предоставляет возможность обратитьс
### 10.4. Словарь из YDB (KikiMR).
Нужно для Метрики, а делать будет таинственный незнакомец из команды KikiMR (под вопросом).
Нужно для Метрики, а делать будет таинственный незнакомец из команды KikiMR (под вопросом). Таинственный незнакомец не подтверждает, что он будет делать эту задачу.
### 10.5. Закрытие соединений и уменьшение числа соединений для MySQL и ODBC.
@ -707,15 +755,15 @@ ClickHouse предоставляет возможность обратитьс
### 10.9. Уменьшение блокировок для cache словарей за счёт одновременных запросов одного и того же.
Нужно для БК, но мотивация задачи находится под вопросом, так как есть рабочее предположение о том, что данная задача не устраняет причину проблемы.
Никита Михайлов. Q1. Нужно для БК, но мотивация задачи находится под вопросом, так как есть рабочее предположение о том, что данная задача не устраняет причину проблемы.
### 10.10. Возможность использования старых значений из cache словаря пока они перезапрашиваются.
Нужно для БК и Метрики.
Никита Михайлов. Q1. Нужно для БК и Метрики.
### 10.11. Возможность исключительно асинхронных запросов в cache словарях.
Нужно для БК и Метрики. Требует 10.10.
Никита Михайлов. Q1. Нужно для БК и Метрики. Требует 10.10.
### 10.12. Layout direct для словарей.
@ -731,7 +779,7 @@ ClickHouse предоставляет возможность обратитьс
### 10.16. Словари на локальном SSD.
Никита Васильев, ВШЭ и Яндекс.
Никита Васильев, ВШЭ и Яндекс. Есть pull request.
Реализовать в ClickHouse специализированный движок таблиц, подходящий для быстрых key-value запросов и оптимизированный для расположения данных на SSD. Это может быть: реализация на основе RocksDB; сериализованные RowBinary данные с индексом в оперативке; секретная очень эффективная структура данных, о которой я расскажу.
@ -778,7 +826,7 @@ ClickHouse предоставляет возможность обратитьс
### 11.10. Преднастроенные HTTP handlers для запросов.
zhang2014
zhang2014, есть pull request.
Возможность описать в конфигурационном файле handler (путь в URL) для HTTP запросов к серверу, которому соответствует некоторый параметризованный запрос. Пользователь может вызвать этот обработчик и не должен передавать SQL запрос.
@ -787,15 +835,18 @@ zhang2014
### 12.1. Role Based Access Control.
[Виталий Баранов](https://github.com/vitlibar). Финальная стадия разработки, рабочая версия в декабре 2019.
[Виталий Баранов](https://github.com/vitlibar). Финальная стадия разработки, рабочая версия в начале февраля 2019.
Q1. Сейчас сделаны все интерфейсы в коде и запросы, но не сделаны варианты хранения прав кроме прототипа.
### 12.2. Управление пользователями и правами доступа с помощью SQL запросов.
[Виталий Баранов](https://github.com/vitlibar). Финальная стадия разработки, рабочая версия в декабре 2019.
Q1.
### 12.3. Подключение справочника пользователей и прав доступа из LDAP.
[Виталий Баранов](https://github.com/vitlibar). Требует 12.1.
Q1/Q2.
### 12.4. Подключение IDM системы Яндекса как справочника пользователей и прав доступа.
@ -823,6 +874,7 @@ zhang2014
### 13.3. Пулы ресурсов.
Требует 13.2 или сможем сделать более неудобную реализацию раньше.
Обсуждается вариант неудобной реализации. Пока средний приоритет, целимся на Q1/Q2.
## 14. Диалект SQL.
@ -830,9 +882,12 @@ zhang2014
### 14.1. Исправление семантики CAST для Nullable.
Нужно для DataLens. А также для внедрения в BI инструмент Looker.
Павел Потёмкин, ВШЭ.
### 14.2. Поддержка WITH для подзапросов.
Павел Потёмкин, ВШЭ.
### 14.3. Поддержка подстановок для множеств в правой части IN.
### 14.4. Поддержка подстановок для идентификаторов (имён) в SQL запросе.
@ -845,8 +900,12 @@ zhang2014
### 14.6. Глобальный scope для WITH.
Павел Потёмкин, ВШЭ.
### 14.7. Nullable для WITH ROLLUP, WITH CUBE, WITH TOTALS.
Павел Потёмкин, ВШЭ.
Простая задача.
### 14.8. Модификаторы DISTINCT, ORDER BY для агрегатных функций.
@ -893,18 +952,23 @@ zhang2014.
### 14.18. UNION DISTINCT и возможность включить его по-умолчанию.
Павел Потёмкин, ВШЭ.
Для BI систем.
### 14.19. Совместимость парсера типов данных с SQL.
Павел Потёмкин, ВШЭ.
Для BI систем.
### 14.20. Позиционные аргументы для GROUP BY и ORDER BY.
Павел Потёмкин, ВШЭ.
Тривиально и используется многими системами, но не входит в стандарт SQL.
### 14.21. Приведение типов для IN (подзапрос) и для JOIN.
Павел Потёмкин, ВШЭ.
## 15. Улучшение поддержки JOIN.
@ -912,6 +976,15 @@ zhang2014.
Артём Зуйков. Сейчас merge JOIN включается вручную опцией и всегда замедляет запросы. Хотим, чтобы он замедлял запросы только когда это неизбежно.
Кстати, смысл merge JOIN появляется только совместно с 15.2 и 15.3.
Q1.
### 15.1.1. Алгоритм two-level merge JOIN.
Александр Кузьменков. В очереди.
### 15.1.2. Тестирование реализации JOIN в Greenplum.
В очереди.
### 15.2. Прокидывание условий в OUTER JOIN.
@ -934,7 +1007,7 @@ zhang2014.
## 16. Типы данных и функции.
### 16.1. DateTime64.
### 16.1. + DateTime64.
Василий Немков, Altinity, декабрь 2019.
@ -964,6 +1037,8 @@ ClickHouse не является geospatial СУБД. Тем не менее, в
Похожая, но более сложная задача, которую ClickHouse пока не умеет решать - определение полигона среди множества полигонов, в которые попадают точки. Для примера: определение района города по географическим координатам. Для решения этой задачи нужно будет реализовать поддержку словарей с полигонами, в которых данные проиндексированы для быстрого поиска.
Upd. Андрей сделал прототип интерфейса и реализацию-заглушку внутри него.
### 17.2. GIS типы данных и операции.
Алексей Коряков, Алексей Илюхов, ВШЭ, Яндекс.Карты.
@ -1070,13 +1145,15 @@ Hold. Полезно для заказчиков внутри Яндекса, н
Начинал Олег Ершов, доделывает Никита Михайлов, помогает [Александр Кузьменков](https://github.com/akuzm). Готово.
### 21.1.1. Избавление от лишнего копирование при параллельном парсинге форматов, если возможен mmap файла целиком.
### 21.2. Параллельное форматирование форматов.
После 21.1, предположительно Никита Михайлов. Задача сильно проще чем 21.1.
### 21.3. Исправление низкой производительности анализа индекса в случае большого множества в секции IN.
Нужно всем (Zen, БК, DataLens...) Пока ещё не выбран исполнитель.
Нужно всем (Zen, БК, DataLens, TestEnv...). Антон Попов, Q1/Q2.
### 21.4. Использование ORDER BY ключа для оптимизации GROUP BY и DISTINCT.
@ -1091,12 +1168,14 @@ Hold. Полезно для заказчиков внутри Яндекса, н
### 21.5. Распараллеливание INSERT при INSERT SELECT, если это необходимо.
[Vxider](https://github.com/Vxider), ICT
Есть pull request.
### 21.6. Уменьшение числа потоков для SELECT в случае тривиального INSERT SELECT.
### 21.7. Кэш результатов запросов.
[Achimbab](https://github.com/achimbab).
Есть pull request.
### 21.8. Взаимная интеграция аллокатора и кэша.
@ -1131,6 +1210,8 @@ Amos Bird.
- Вынесение любых функций наружу any, anyLast.
- При GROUP BY по transform или if по строкам, замена строк на Enum.
Сделана замена цепочек if на multiIf, но внезапно оказалось, что это является не оптимизацией, а наоборот.
### 21.12. Алгебраические оптимизации запросов.
Руслан Камалов, Михаил Малафеев, Виктор Гришанин, ВШЭ
@ -1200,9 +1281,9 @@ Constraints позволяют задать выражение, истиннос
В ByteDance есть готовая реализация, но они её боятся из-за, возможно, низкого качества кода.
### 21.21. Чтение больших файлов с помощью mmap.
### 21.21. + Чтение больших файлов с помощью mmap.
Тривиально, почти всё готово.
Сделан вариант, но достаточно топорный. Без тестирования в продакшене включать по-умолчанию нельзя.
### 21.22. Userspace page cache.
@ -1211,6 +1292,7 @@ Constraints позволяют задать выражение, истиннос
### 21.23. Ускорение работы с вторичными индексами.
zhang2014.
Есть pull request.
## 22. Долги и недоделанные возможности.
@ -1219,9 +1301,9 @@ zhang2014.
Нужно для Яндекс.Облака. Сделал Алексей Миловидов.
### 22.2. Убрать возможность изменить настройки в native протоколе в случае readonly.
### 22.2. + Убрать возможность изменить настройки в native протоколе в случае readonly.
Алексей Миловидов или [Виталий Баранов](https://github.com/vitlibar).
N.Vartolomei.
### 22.3. Защита от абсурдно заданных пользователем кодеков.
@ -1229,25 +1311,27 @@ zhang2014.
### 22.4. Исправление оставшихся deadlocks в табличных RWLock-ах.
Александр Казаков. Нужно для Яндекс.Метрики и Datalens.
Александр Казаков. Нужно для Яндекс.Метрики и Datalens. Задача постепенно тащится и исправлениями в соседних местах стала менее актуальна.
В Q1 будет сделана или отменена с учётом 1.2. и 1.3.
### 22.5. Исправление редких срабатываний TSan в stress тестах в CI.
### 22.5. + Исправление редких срабатываний TSan в stress тестах в CI.
Александр Казаков.
### 22.6. Изменение только DEFAULT в ALTER TABLE может поменять тип столбца.
### 22.7. Row-Level Security не работает в случае наличия в запросе IN подзапросов.
### 22.7. + Row-Level Security не работает в случае наличия в запросе IN подзапросов.
[Виталий Баранов](https://github.com/vitlibar). Нужно для Метрики.
Нужно для Метрики. Иван Лежанкин.
### 22.8. Исправить десериализацию параметров для параметризованных запросов.
### 22.8. + Исправить десериализацию параметров для параметризованных запросов.
Хотел исправить Василий Немков, Altinity, но есть маленькие затруднения, наверное переделает Алексей Миловидов.
### 22.9. Разобраться с десериализацией массивов со значениями по-умолчанию в Protobuf формате в случае protobuf 3.
[Виталий Баранов](https://github.com/vitlibar). Возможно, это - фундаментальная проблема и следует её только документировать.
Кажется, отменяем, но пока ещё не всё ясно.
### 22.10. Исправление дрифта при отслеживании потребления памяти запросами.
@ -1278,11 +1362,10 @@ zhang2014.
Altinity.
### 22.16. Исправление низкой производительности кодека DoubleDelta.
### 22.16. + Исправление низкой производительности кодека DoubleDelta.
Василий Немков, Altinity - в процессе.
Мы считаем важным, что код в ClickHouse содержит разумные оптимизации, основанные на анализе производительности. Но иногда бывают досадные исключения.
Можно считать, что сделано, хотя отсутствие SIMD оптимизаций для variable length кодеков - это ужасно.
### 22.17. Консистентно работающий POPULATE для MaterializedView.
@ -1331,14 +1414,14 @@ https://github.com/ClickHouse/ClickHouse/issues/2655
Altinity.
### 22.29. Уязвимость DDL для словарей executable.
### 22.29. + Уязвимость DDL для словарей executable.
[Александр Сапин](https://github.com/alesapin)
## 23. Default Festival.
### 23.1. Включение minimalistic_part_header в ZooKeeper.
### 23.1. + Включение minimalistic_part_header в ZooKeeper.
Сильно уменьшает объём данных в ZooKeeper. Уже год в продакшене в Яндекс.Метрике.
Алексей Миловидов, ноябрь 2019.
@ -1367,13 +1450,13 @@ Altinity.
Просто аккуратно включить.
### 23.8. Включение оптимизации VALUES.
### 23.8. + Включение оптимизации VALUES.
Просто аккуратно включить.
### 23.9. Включение Processors.
[Николай Кочетов](https://github.com/KochetovNicolai).
Q1. [Николай Кочетов](https://github.com/KochetovNicolai).
### 23.10. Включение mlock бинарника.
@ -1578,12 +1661,16 @@ ucasFL, ICT.
Алгоритмы min-hash и sim-hash позволяют вычислить для текста несколько хэш-значений таких, что при небольшом изменении текста, по крайней мере один из хэшей не меняется. Вычисления можно реализовать на n-грамах и словарных шинглах. Предлагается добавить поддержку этих алгоритмов в виде функций в ClickHouse и изучить их применимость для задачи нечёткого поиска полудубликатов.
Есть pull request, есть что доделывать.
### 24.28. Другой sketch для квантилей.
Похоже на quantileTiming, но с логарифмическими корзинами.
Похоже на quantileTiming, но с логарифмическими корзинами. См. DDSketch.
### 24.29. Поддержка Arrow Flight.
Жанна Зосимова, ВШЭ.
### 24.30. ClickHouse как графовая СУБД.
Amos Bird, но его решение слишком громоздкое и пока не open-source.
@ -1613,7 +1700,7 @@ Amos Bird, но его решение слишком громоздкое и п
### 25.2. Вычитка и выкладка статьи про обфускацию данных на английском.
Эми, Александр Казаков, Алексей Миловидов, ноябрь 2019.
Эми, Александр Казаков, Алексей Миловидов, Q1.
Готово к выкладке.
### 25.3. Подготовка статьи "Секреты оптимизации производительности ClickHouse".
@ -1640,9 +1727,9 @@ Amos Bird, но его решение слишком громоздкое и п
### 25.9. Подготовка докладчиков: khvostikao, ilezhankin, nikitamikhailov, akuzm и другие.
[Ольга Хвостикова](https://github.com/stavrolia), [Иван Лежанкин](https://github.com/abyss7), Никита Михайлов, [Александр Кузьменков](https://github.com/akuzm).
[Ольга Хвостикова](https://github.com/stavrolia), [Иван Лежанкин](https://github.com/abyss7), Никита Михайлов, [Александр Кузьменков](https://github.com/akuzm), Артём Зуйков.
Уже готовые докладчики: Алексей Миловидов, [Николай Кочетов](https://github.com/KochetovNicolai), [Александр Сапин](https://github.com/alesapin).
Получаем минимум 7 докладчиков в 2020 году.
Получаем минимум 8 докладчиков в 2020 году.
### 25.10. Митапы в России и Беларуси: Москва x2 + митап для разработчиков или хакатон, Санкт-Петербург, Минск, Нижний Новгород, Екатеринбург, Новосибирск и/или Академгородок, Иннополис или Казань.
@ -1650,7 +1737,7 @@ Amos Bird, но его решение слишком громоздкое и п
### 25.11. Митапы зарубежные: восток США (Нью Йорк, возможно Raleigh), возможно северо-запад (Сиэтл), Китай (Пекин снова, возможно митап для разработчиков или хакатон), Лондон.
[Иван Блинков](https://github.com/blinkov/) - организация
[Иван Блинков](https://github.com/blinkov/) - организация. Две штуки в США запланированы.
### 25.12. Статья "научная" - про устройство хранения данных и индексов или whitepaper по архитектуре. Есть вариант подать на VLDB.

View File

@ -21,4 +21,37 @@
NLS_LANG=RUSSIAN_RUSSIA.UTF8
```
## Как экспортировать данные из ClickHouse в файл? {#how-to-export-to-file}
### Секция INTO OUTFILE
Добавьте секцию [INTO OUTFILE](../query_language/select/#into-outfile-clause) к своему запросу.
Например:
```sql
SELECT * FROM table INTO OUTFILE 'file'
```
По умолчанию, для выдачи данных ClickHouse использует формат [TabSeparated](../interfaces/formats.md#tabseparated). Чтобы выбрать [формат данных](../interfaces/formats.md), используйте [секцию FORMAT](../query_language/select/#format-clause).
Например:
```sql
SELECT * FROM table INTO OUTFILE 'file' FORMAT CSV
```
### Таблица с движком File
Смотрите [File](../operations/table_engines/file.md).
### Перенаправление в командой строке
```sql
$ clickhouse-client --query "SELECT * from table" > result.txt
```
Смотрите [clickhouse-client](../interfaces/cli.md).
[Оригинальная статья ](https://clickhouse.yandex/docs/en/faq/general/) <!--hide-->

View File

@ -28,6 +28,7 @@ ClickHouse может принимать (`INSERT`) и отдавать (`SELECT
| [PrettySpace](#prettyspace) | ✗ | ✔ |
| [Protobuf](#protobuf) | ✔ | ✔ |
| [Parquet](#data-format-parquet) | ✔ | ✔ |
| [ORC](#data-format-orc) | ✔ | ✗ |
| [RowBinary](#rowbinary) | ✔ | ✔ |
| [RowBinaryWithNamesAndTypes](#rowbinarywithnamesandtypes) | ✔ | ✔ |
| [Native](#native) | ✔ | ✔ |
@ -132,28 +133,28 @@ world
`delimiter_1${column_1:serializeAs_1}delimiter_2${column_2:serializeAs_2} ... delimiter_N`,
где `delimiter_i` - разделители между значениями (символ `$` в разделителе экранируется как `$$`),
`column_i` - имена или номера столбцов, значения которых должны быть выведены или считаны (если имя не указано - столбец пропускается),
где `delimiter_i` - разделители между значениями (символ `$` в разделителе экранируется как `$$`),
`column_i` - имена или номера столбцов, значения которых должны быть выведены или считаны (если имя не указано - столбец пропускается),
`serializeAs_i` - тип экранирования для значений соответствующего столбца. Поддерживаются следующие типы экранирования:
- `CSV`, `JSON`, `XML` (как в одноимённых форматах)
- `Escaped` (как в `TSV`)
- `Quoted` (как в `Values`)
- `Raw` (без экранирования, как в `TSVRaw`)
- `None` (тип экранирования отсутствует, см. далее)
Если для столбца не указан тип экранирования, используется `None`. `XML` и `Raw` поддерживаются только для вывода.
Так, в форматной строке
Если для столбца не указан тип экранирования, используется `None`. `XML` и `Raw` поддерживаются только для вывода.
Так, в форматной строке
`Search phrase: ${SearchPhrase:Quoted}, count: ${c:Escaped}, ad price: $$${price:JSON};`
между разделителями `Search phrase: `, `, count: `, `, ad price: $` и `;` при выводе будут подставлены (при вводе - будут ожидаться) значения столбцов `SearchPhrase`, `c` и `price`, сериализованные как `Quoted`, `Escaped` и `JSON` соответственно, например:
`Search phrase: 'bathroom interior design', count: 2166, ad price: $3;`
Настройка `format_template_rows_between_delimiter` задаёт разделитель между строками, который выводится (или ожмдается при вводе) после каждой строки, кроме последней. По умолчанию `\n`.
Настройка `format_template_resultset` задаёт путь к файлу, содержащему форматную строку для результата. Форматная строка для результата имеет синтаксис аналогичный форматной строке для строк таблицы и позволяет указать префикс, суффикс и способ вывода дополнительной информации. Вместо имён столбцов в ней указываются следующие имена подстановок:
- `data` - строки с данными в формате `format_template_row`, разделённые `format_template_rows_between_delimiter`. Эта подстановка должна быть первой подстановкой в форматной строке.
@ -165,15 +166,15 @@ world
- `time` - время выполнения запроса в секундах
- `rows_read` - сколько строк было прочитано при выполнении запроса
- `bytes_read` - сколько байт (несжатых) было прочитано при выполнении запроса
У подстановок `data`, `totals`, `min` и `max` не должны быть указаны типы экранирования (или должен быть указан `None`). Остальные подстановки - это отдельные значения, для них может быть указан любой тип экранирования.
Если строка `format_template_resultset` пустая, то по-умолчанию используется `${data}`.
Из всех перечисленных подстановок форматная строка `format_template_resultset` для ввода может содержать только `data`.
Также при вводе формат поддерживает пропуск значений столбцов и пропуск значений в префиксе и суффиксе (см. пример).
Пример вывода:
```sql
SELECT SearchPhrase, count() AS c FROM test.hits GROUP BY SearchPhrase ORDER BY c DESC LIMIT 5 FORMAT Template SETTINGS
SELECT SearchPhrase, count() AS c FROM test.hits GROUP BY SearchPhrase ORDER BY c DESC LIMIT 5 FORMAT Template SETTINGS
format_template_resultset = '/some/path/resultset.format', format_template_row = '/some/path/row.format', format_template_rows_between_delimiter = '\n '
```
`/some/path/resultset.format`:
@ -225,7 +226,7 @@ Page views: 6, User id: 4324182021466249494, Useless field: world, Duration: 185
Total rows: 2
```
```sql
INSERT INTO UserActivity FORMAT Template SETTINGS
INSERT INTO UserActivity FORMAT Template SETTINGS
format_template_resultset = '/some/path/resultset.format', format_template_row = '/some/path/row.format'
```
`/some/path/resultset.format`:
@ -238,7 +239,7 @@ Page views: ${PageViews:CSV}, User id: ${UserID:CSV}, Useless field: ${:CSV}, Du
```
`PageViews`, `UserID`, `Duration` и `Sign` внутри подстановок - имена столбцов в таблице, в которую вставляются данные. Значения после `Useless field` в строках и значение после `\nTotal rows: ` в суффиксе будут проигнорированы.
Все разделители во входных данных должны строго соответствовать разделителям в форматных строках.
## TemplateIgnoreSpaces {#templateignorespaces}
Подходит только для ввода. Отличается от формата `Template` тем, что пропускает пробельные символы между разделителями и значениями во входном потоке. Также в этом формате можно указать пустые подстановки с типом экранирования `None` (`${}` или `${:None}`), чтобы разбить разделители на несколько частей, пробелы между которыми должны игнорироваться. Такие подстановки используются только для пропуска пробелов. С помощью этого формата можно считывать `JSON`, если значения столбцов в нём всегда идут в одном порядке в каждой строке. Например, для вставки данных из примера вывода формата [JSON](#json) в таблицу со столбцами `phrase` и `cnt` можно использовать следующий запрос:
@ -941,7 +942,7 @@ ClickHouse поддерживает настраиваемую точность
Типы данных столбцов в ClickHouse могут отличаться от типов данных соответствующих полей файла в формате Parquet. При вставке данных, ClickHouse интерпретирует типы данных в соответствии с таблицей выше, а затем [приводит](../query_language/functions/type_conversion_functions/#type_conversion_function-cast) данные к тому типу, который установлен для столбца таблицы.
### Inserting and Selecting Data
### Вставка и выборка данных
Чтобы вставить в ClickHouse данные из файла в формате Parquet, выполните команду следующего вида:
@ -955,7 +956,49 @@ $ cat {filename} | clickhouse-client --query="INSERT INTO {some_table} FORMAT Pa
$ clickhouse-client --query="SELECT * FROM {some_table} FORMAT Parquet" > {some_file.pq}
```
Для обмена данными с экосистемой Hadoop можно использовать движки таблиц [HDFS](../operations/table_engines/hdfs.md) и `URL`.
Для обмена данными с экосистемой Hadoop можно использовать движки таблиц [HDFS](../operations/table_engines/hdfs.md).
## ORC {#data-format-orc}
[Apache ORC](https://orc.apache.org/) - это column-oriented формат данных, распространённый в экосистеме Hadoop. Вы можете только вставлять данные этого формата в ClickHouse.
### Соответствие типов данных
Таблица показывает поддержанные типы данных и их соответствие [типам данных](../data_types/index.md) ClickHouse для запросов `INSERT`.
| Тип данных ORC (`INSERT`) | Тип данных ClickHouse |
| -------------------- | ------------------ |
| `UINT8`, `BOOL` | [UInt8](../data_types/int_uint.md) |
| `INT8` | [Int8](../data_types/int_uint.md) |
| `UINT16` | [UInt16](../data_types/int_uint.md) |
| `INT16` | [Int16](../data_types/int_uint.md) |
| `UINT32` | [UInt32](../data_types/int_uint.md) |
| `INT32` | [Int32](../data_types/int_uint.md) |
| `UINT64` | [UInt64](../data_types/int_uint.md) |
| `INT64` | [Int64](../data_types/int_uint.md) |
| `FLOAT`, `HALF_FLOAT` | [Float32](../data_types/float.md) |
| `DOUBLE` | [Float64](../data_types/float.md) |
| `DATE32` | [Date](../data_types/date.md) |
| `DATE64`, `TIMESTAMP` | [DateTime](../data_types/datetime.md) |
| `STRING`, `BINARY` | [String](../data_types/string.md) |
| `DECIMAL` | [Decimal](../data_types/decimal.md) |
ClickHouse поддерживает настраиваемую точность для формата `Decimal`. При обработке запроса `INSERT`, ClickHouse обрабатывает тип данных Parquet `DECIMAL` как `Decimal128`.
Неподдержанные типы данных ORC: `DATE32`, `TIME32`, `FIXED_SIZE_BINARY`, `JSON`, `UUID`, `ENUM`.
Типы данных столбцов в таблицах ClickHouse могут отличаться от типов данных для соответствующих полей ORC. При вставке данных, ClickHouse интерпретирует типы данных ORC согласно таблице соответствия, а затем [приводит](../query_language/functions/type_conversion_functions/#type_conversion_function-cast) данные к типу, установленному для столбца таблицы ClickHouse.
### Вставка данных
Данные ORC можно вставить в таблицу ClickHouse командой:
```bash
$ cat filename.orc | clickhouse-client --query="INSERT INTO some_table FORMAT ORC"
```
Для обмена данных с Hadoop можно использовать [движок таблиц HDFS](../operations/table_engines/hdfs.md).
## Схема формата {#formatschema}

View File

@ -173,7 +173,7 @@ $ echo 'SELECT number FROM numbers LIMIT 10' | curl 'http://localhost:8123/?data
По умолчанию используется БД, которая прописана в настройках сервера, как БД по умолчанию. По умолчанию, это - БД default. Также вы всегда можете указать БД через точку перед именем таблицы.
Имя пользователя и пароль могут быть указаны в одном из двух вариантов:
Имя пользователя и пароль могут быть указаны в одном из трёх вариантов:
1. С использованием HTTP Basic Authentication. Пример:
@ -187,6 +187,12 @@ $ echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
$ echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
```
3. С использованием заголовков X-ClickHouse-User и X-ClickHouse-Key. Пример:
```bash
$ echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'http://localhost:8123/' -d @-
```
Если пользователь не задан,то используется `default`. Если пароль не задан, то используется пустой пароль.
Также в параметрах URL вы можете указать любые настройки, которые будут использованы для обработки одного запроса, или целые профили настроек. Пример:http://localhost:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1

View File

@ -75,6 +75,91 @@ round(3.55, 1) = 3.6
round(3.65, 1) = 3.6
```
**См. также**
- [roundBankers](#roundbankers)
## roundBankers {#roundbankers}
Округляет число до указанного десятичного разряда.
- Если округляемое число равноудалено от соседних чисел, то используется банковское округление.
Банковское округление (англ. banker's rounding) — метод округления дробных чисел. Если округляемое число равноудалёно от соседних чисел, то оно округляется до ближайшего чётного числа. К примеру, 3,5 округляется до 4, а 2,5 до 2.
- В других случаях функция округляет к ближайшему целому.
Банковское округление позволяет уменьшить влияние округления чисел на результат суммирования или вычитания этих чисел.
Пример суммирования чисел 1.5, 2.5, 3.5 и 4.5 с различным округлением:
- Без округления: 1.5 + 2.5 + 3.5 + 4.5 = 12.
- Банковское округление: 2 + 2 + 4 + 4 = 12.
- Округление до ближайшего целого: 2 + 3 + 4 + 5 = 14.
**Синтаксис**
```sql
roundBankers(expression [, decimal_places])
```
**Параметры**
- `expression` — Число для округления. Может быть любым [выражением](../syntax.md#syntax-expressions), возвращающим числовой [тип данных](../../data_types/index.md#data_types).
- `decimal-places` — Десятичный разряд. Целое число.
- `decimal-places > 0` — Функция округляет значение выражения до ближайшего чётного числа на соответствующей позиции справа от запятой. Например, `roundBankers(3.55, 1) = 3.6`.
- `decimal-places < 0` — Функция округляет значение выражения до ближайшего чётного числа на соответствующей позиции слева от запятой. Например, `roundBankers(24.55, -1) = 20`.
- `decimal-places = 0` — Функция округляет значение до целого. В этом случае аргумент можно не передавать. Например, `roundBankers(2.5) = 2`.
**Возвращаемое значение**
Округлённое значение по методу банковского округления.
**Пример использования**
Запрос:
```sql
SELECT number / 2 AS x, roundBankers(x, 0) AS b fROM system.numbers limit 10
```
Результат:
```text
┌───x─┬─b─┐
│ 0 │ 0 │
│ 0.5 │ 0 │
│ 1 │ 1 │
│ 1.5 │ 2 │
│ 2 │ 2 │
│ 2.5 │ 2 │
│ 3 │ 3 │
│ 3.5 │ 4 │
│ 4 │ 4 │
│ 4.5 │ 4 │
└─────┴───┘
```
**Примеры банковского округления**
```text
roundBankers(0.4) = 0
roundBankers(-3.5) = -4
roundBankers(4.5) = 4
roundBankers(3.55, 1) = 3.6
roundBankers(3.65, 1) = 3.6
roundBankers(10.35, 1) = 10.4
roundBankers(10.755, 2) = 11,76
```
**См. также**
- [round](#rounding_functions-round)
## roundToExp2(num)
Принимает число. Если число меньше единицы - возвращает 0. Иначе округляет число вниз до ближайшей (целой неотрицательной) степени двух.

View File

@ -1147,7 +1147,7 @@ SELECT CounterID, 2 AS table, sum(Sign) AS c
Запросы - части `UNION ALL` нельзя заключить в скобки. `ORDER BY` и `LIMIT` применяются к отдельным запросам, а не к общему результату. Если вам нужно применить какое-либо преобразование к общему результату, то вы можете разместить все запросы с `UNION ALL` в подзапросе в секции `FROM`.
### Секция INTO OUTFILE
### Секция INTO OUTFILE {#into-outfile-clause}
При указании `INTO OUTFILE filename` (где filename - строковый литерал), результат запроса будет сохранён в файл filename.
В отличие от MySQL, файл создаётся на стороне клиента. Если файл с таким именем уже существует, это приведёт к ошибке.
@ -1155,7 +1155,7 @@ SELECT CounterID, 2 AS table, sum(Sign) AS c
Формат вывода по умолчанию - TabSeparated, как и в не интерактивном режиме клиента командной строки.
### Секция FORMAT
### Секция FORMAT {#format-clause}
При указании FORMAT format вы можете получить данные в любом указанном формате.
Это может использоваться для удобства или для создания дампов.

View File

@ -59,12 +59,6 @@ export CC=gcc-9
export CXX=g++-9
```
## 安装所需的工具依赖库
```bash
sudo apt-get install libreadline-dev
```
## 拉取 ClickHouse 源码
```bash

View File

@ -12,7 +12,7 @@ ClickHouse 支持在 Mac OS X 10.12 版本中编译。若您在用更早的操
## 安装编译器,工具库
```bash
brew install cmake ninja gcc icu4c mariadb-connector-c openssl libtool gettext readline
brew install cmake ninja gcc icu4c mariadb-connector-c openssl libtool gettext
```
## 拉取 ClickHouse 源码

View File

@ -105,14 +105,6 @@ brew install cmake ninja
ClickHouse使用多个外部库进行构建。大多数外部库不需要单独安装而是和ClickHouse一起在子模块中构建。可以查看`contrib`中罗列的清单。
有一些库不是由源构建的而是由系统提供例如Readline也建议安装。
Ubuntu: `sudo apt install libreadline-dev`
Mac OS X: `brew install readline`
但是这些库本身都是可选的ClickHouse即便没有它们也可以构建。ICU用于支持`ORDER BY`中的`COLLATE`(例如,对土耳其字母进行排序)。Readline用于在clickhouse-client中更便捷的指令输入。
# C++ 编译器

View File

@ -45,7 +45,7 @@ cat file.csv | clickhouse-client --database=test --query="INSERT INTO test FORMA
您可以指定 `\G` 来替代分号或者在分号后面,这表示 `Vertical` 的格式。在这种格式下,每一个值都会打印在不同的行中,这种方式对于宽表来说很方便。这个不常见的特性是为了兼容 MySQL 命令而加的。
命令行客户端是基于 `readline` 库(`history` 库或者 `libedit` 库, 或不基于其他库, 这取决于客户端是如何编译的)。换句话说,它可以使用我们熟悉的快捷键方式来操作以及保留历史命令。
命令行客户端是基于 `replxx`。换句话说,它可以使用我们熟悉的快捷键方式来操作以及保留历史命令。
历史命令会写入在 `~/.clickhouse-client-history` 中。
默认情况下,输出的格式是 `PrettyCompact`。您可以通过 FORMAT 设置根据不同查询来修改格式,或者通过在查询末尾指定 `\G` 字符,或通过在命令行中使用 `--format` or `--vertical` 参数,或使用客户端的配置文件。

View File

@ -11,46 +11,48 @@ if (DEFINED APPLE_HAVE_CLOCK_GETTIME)
endif ()
add_library (common
src/argsToConfig.cpp
src/coverage.cpp
src/DateLUT.cpp
src/DateLUTImpl.cpp
src/preciseExp10.c
src/shift10.cpp
src/mremap.cpp
src/JSON.cpp
src/getMemoryAmount.cpp
src/demangle.cpp
src/setTerminalEcho.cpp
src/getMemoryAmount.cpp
src/getThreadNumber.cpp
src/sleep.cpp
src/argsToConfig.cpp
src/JSON.cpp
src/LineReader.cpp
src/mremap.cpp
src/phdr_cache.cpp
src/coverage.cpp
src/preciseExp10.c
src/setTerminalEcho.cpp
src/shift10.cpp
src/sleep.cpp
include/common/SimpleCache.h
include/common/Types.h
include/common/DayNum.h
include/common/constexpr_helpers.h
include/common/coverage.h
include/common/DateLUT.h
include/common/DateLUTImpl.h
include/common/DayNum.h
include/common/demangle.h
include/common/ErrorHandlers.h
include/common/find_symbols.h
include/common/getMemoryAmount.h
include/common/getThreadNumber.h
include/common/JSON.h
include/common/likely.h
include/common/LineReader.h
include/common/LocalDate.h
include/common/LocalDateTime.h
include/common/ErrorHandlers.h
include/common/preciseExp10.h
include/common/shift10.h
include/common/mremap.h
include/common/likely.h
include/common/logger_useful.h
include/common/strong_typedef.h
include/common/JSON.h
include/common/getMemoryAmount.h
include/common/demangle.h
include/common/setTerminalEcho.h
include/common/find_symbols.h
include/common/constexpr_helpers.h
include/common/getThreadNumber.h
include/common/sleep.h
include/common/SimpleCache.h
include/common/mremap.h
include/common/phdr_cache.h
include/common/coverage.h
include/common/preciseExp10.h
include/common/setTerminalEcho.h
include/common/shift10.h
include/common/SimpleCache.h
include/common/SimpleCache.h
include/common/sleep.h
include/common/strong_typedef.h
include/common/Types.h
include/ext/bit_cast.h
include/ext/chrono_io.h
@ -90,6 +92,10 @@ if(CCTZ_LIBRARY)
target_link_libraries(common PRIVATE ${CCTZ_LIBRARY})
endif()
if (ENABLE_REPLXX)
target_link_libraries(common PRIVATE replxx)
endif ()
target_link_libraries (common
PUBLIC
${Poco_Util_LIBRARY}

View File

@ -0,0 +1,57 @@
#pragma once
#include <common/Types.h>
#include <atomic>
#include <vector>
class LineReader
{
public:
class Suggest
{
protected:
using Words = std::vector<std::string>;
using WordsRange = std::pair<Words::const_iterator, Words::const_iterator>;
Words words;
std::atomic<bool> ready{false};
public:
/// Get iterators for the matched range of words if any.
WordsRange getCompletions(const String & prefix, size_t prefix_length) const;
};
LineReader(const Suggest * suggest, const String & history_file_path, char extender, char delimiter = 0); /// if delimiter != 0, then it's multiline mode
~LineReader();
/// Reads the whole line until delimiter (in multiline mode) or until the last line without extender.
/// If resulting line is empty, it means the user interrupted the input.
/// Non-empty line is appended to history - without duplication.
/// Typical delimiter is ';' (semicolon) and typical extender is '\' (backslash).
String readLine(const String & first_prompt, const String & second_prompt);
private:
enum InputStatus
{
ABORT = 0,
RESET_LINE,
INPUT_LINE,
};
String input;
String prev_line;
const String history_file_path;
const char extender;
const char delimiter;
InputStatus readOneLine(const String & prompt);
void addToHistory(const String & line);
/// Since CMake doesn't impose restrictions on includes between unrelated targets
/// it's possible that we include this file without USE_REPLXX defined.
#ifdef __clang__
[[maybe_unused]]
#endif
void * impl;
};

View File

@ -1,8 +1,10 @@
#pragma once
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <string>
#include <type_traits>
#include <algorithm>
using Int8 = int8_t;
using Int16 = int16_t;
@ -14,6 +16,8 @@ using UInt16 = uint16_t;
using UInt32 = uint32_t;
using UInt64 = uint64_t;
using String = std::string;
/// The standard library type traits, such as std::is_arithmetic, with one exception
/// (std::common_type), are "set in stone". Attempting to specialize them causes undefined behavior.
/// So instead of using the std type_traits, we use our own version which allows extension.
@ -52,4 +56,3 @@ struct is_arithmetic
template <typename T>
inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;

View File

@ -2,10 +2,6 @@
// .h autogenerated by cmake !
#cmakedefine01 USE_TCMALLOC
#cmakedefine01 USE_JEMALLOC
#cmakedefine01 USE_READLINE
#cmakedefine01 USE_LIBEDIT
#cmakedefine01 HAVE_READLINE_HISTORY
#cmakedefine01 UNBUNDLED
#cmakedefine01 WITH_COVERAGE

View File

@ -1,29 +0,0 @@
#pragma once
#if __has_include(<common/config_common.h>)
#include <common/config_common.h>
#endif
/// Different line editing libraries can be used depending on the environment.
#if USE_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#elif USE_LIBEDIT
#include <editline/readline.h>
#else
#include <string>
#include <cstring>
#include <iostream>
inline char * readline(const char * prompt)
{
std::string s;
std::cout << prompt;
std::getline(std::cin, s);
if (!std::cin.good())
return nullptr;
return strdup(s.data());
}
#define add_history(...) do {} while (0)
#define rl_bind_key(...) do {} while (0)
#endif

View File

@ -0,0 +1,167 @@
#include <common/LineReader.h>
#ifdef USE_REPLXX
# include <replxx.hxx>
#endif
#include <iostream>
#include <string_view>
#include <port/unistd.h>
#include <string.h>
namespace
{
/// Trim ending whitespace inplace
void trim(String & s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
}
/// Check if multi-line query is inserted from the paste buffer.
/// Allows delaying the start of query execution until the entirety of query is inserted.
bool hasInputData()
{
timeval timeout = {0, 0};
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
return select(1, &fds, nullptr, nullptr, &timeout) == 1;
}
constexpr char word_break_characters[] = " \t\n\r\"\\'`@$><=;|&{(.";
}
LineReader::Suggest::WordsRange LineReader::Suggest::getCompletions(const String & prefix, size_t prefix_length) const
{
if (!ready)
return std::make_pair(words.end(), words.end());
std::string_view last_word;
auto last_word_pos = prefix.find_last_of(word_break_characters);
if (std::string::npos == last_word_pos)
last_word = prefix;
else
last_word = std::string_view(prefix).substr(last_word_pos + 1, std::string::npos);
/// last_word can be empty.
return std::equal_range(
words.begin(), words.end(), last_word, [prefix_length](std::string_view s, std::string_view prefix_searched)
{
return strncmp(s.data(), prefix_searched.data(), prefix_length) < 0;
});
}
LineReader::LineReader(const Suggest * suggest, const String & history_file_path_, char extender_, char delimiter_)
: history_file_path(history_file_path_), extender(extender_), delimiter(delimiter_)
{
#ifdef USE_REPLXX
impl = new replxx::Replxx;
auto & rx = *(replxx::Replxx*)(impl);
if (!history_file_path.empty())
rx.history_load(history_file_path);
auto callback = [suggest] (const String & context, size_t context_size)
{
auto range = suggest->getCompletions(context, context_size);
return replxx::Replxx::completions_t(range.first, range.second);
};
if (suggest)
{
rx.set_completion_callback(callback);
rx.set_complete_on_empty(false);
rx.set_word_break_characters(word_break_characters);
}
#endif
/// FIXME: check extender != delimiter
}
LineReader::~LineReader()
{
#ifdef USE_REPLXX
auto & rx = *(replxx::Replxx*)(impl);
if (!history_file_path.empty())
rx.history_save(history_file_path);
delete (replxx::Replxx *)impl;
#endif
}
String LineReader::readLine(const String & first_prompt, const String & second_prompt)
{
String line;
bool is_multiline = false;
while (auto status = readOneLine(is_multiline ? second_prompt : first_prompt))
{
if (status == RESET_LINE)
{
line.clear();
is_multiline = false;
continue;
}
if (input.empty())
continue;
is_multiline = (input.back() == extender) || (delimiter && input.back() != delimiter) || hasInputData();
if (input.back() == extender)
{
input = input.substr(0, input.size() - 1);
trim(input);
if (input.empty())
continue;
}
line += (line.empty() ? "" : " ") + input;
if (!is_multiline)
{
if (line != prev_line)
{
addToHistory(line);
prev_line = line;
}
return line;
}
}
return {};
}
LineReader::InputStatus LineReader::readOneLine(const String & prompt)
{
input.clear();
#ifdef USE_REPLXX
auto & rx = *(replxx::Replxx*)(impl);
const char* cinput = rx.input(prompt);
if (cinput == nullptr)
return (errno != EAGAIN) ? ABORT : RESET_LINE;
input = cinput;
#else
std::cout << prompt;
std::getline(std::cin, input);
if (!std::cin.good())
return ABORT;
#endif
trim(input);
return INPUT_LINE;
}
void LineReader::addToHistory(const String & line)
{
#ifdef USE_REPLXX
auto & rx = *(replxx::Replxx*)(impl);
rx.history_add(line);
#endif
}

View File

@ -1,6 +1,3 @@
add_executable(clickhouse-zookeeper-cli zookeeper-cli.cpp)
target_link_libraries(clickhouse-zookeeper-cli PRIVATE clickhouse_common_zookeeper ${Poco_Foundation_LIBRARY} ${LINE_EDITING_LIBS})
if (READLINE_INCLUDE_DIR)
target_include_directories (clickhouse-zookeeper-cli SYSTEM PRIVATE ${READLINE_INCLUDE_DIR})
endif ()
INSTALL(TARGETS clickhouse-zookeeper-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT clickhouse-utils)

View File

@ -4,7 +4,7 @@
#include <sstream>
#include <Poco/ConsoleChannel.h>
#include <common/logger_useful.h>
#include <common/readline_use.h>
#include <common/LineReader.h>
#include <IO/ReadHelpers.h>
#include <IO/ReadBufferFromString.h>
@ -69,12 +69,13 @@ int main(int argc, char ** argv)
Logger::root().setLevel("trace");
zkutil::ZooKeeper zk(argv[1]);
LineReader lr(nullptr, {}, '\\');
while (char * line_ = readline(":3 "))
do
{
add_history(line_);
std::string line(line_);
free(line_);
const auto & line = lr.readLine(":3 ", ":3 ");
if (line.empty())
break;
try
{
@ -211,6 +212,7 @@ int main(int argc, char ** argv)
std::cerr << "KeeperException: " << e.displayText() << std::endl;
}
}
while (true);
}
catch (const Coordination::Exception & e)
{

View File

@ -1755,7 +1755,7 @@ var runs = ["first (cold cache)", "second", "third"];
var current_runs = ['0', '1'];
try {
var state = JSON.parse(window.location.hash.substring(1));
var state = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
current_data_size = state[0];
current_systems = state[1];

View File

@ -441,7 +441,6 @@ var results =
[
{
"system": "Xeon Gold 6230, 2 sockets, 40 threads",
"data_size": 100000000,
"time": "2020-01-01 00:00:00",
"result":
[
@ -493,7 +492,6 @@ var results =
{
"system": "Yandex Cloud Cascade Lake, 64 vCPU (32 threads), 128 GB RAM, 400 GB SSD",
"data_size": 100000000,
"time": "2020-01-11 00:00:00",
"result":
[
@ -545,7 +543,6 @@ var results =
{
"system": "Yandex Cloud Cascade Lake, 64 vCPU (32 threads), 128 GB RAM, 4 TB SSD",
"data_size": 100000000,
"time": "2020-01-13 00:00:00",
"result":
[
@ -597,7 +594,6 @@ var results =
{
"system": "Yandex Cloud Cascade Lake, 4 vCPU (2 threads), 16 GB RAM, 30 GB SSD",
"data_size": 100000000,
"time": "2020-01-13 00:00:00",
"result":
[
@ -649,7 +645,6 @@ var results =
{
"system": "Yandex Cloud Broadwell, 4 vCPU (2 threads), 16 GB RAM, 30 GB SSD",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -700,8 +695,7 @@ var results =
},
{
"system": "Dell PowerEdge R6415 DX180 AMD EPYC™ 7551P 32-Core Naples (Zen), 128 GB RAM, 2x SSD 960 GB RAID 1",
"data_size": 100000000,
"system": "Dell PowerEdge R6415 DX180 AMD EPYC™ 7551P 32-Core Naples (Zen), 128 GB RAM, 2x SSD 960 GB RAID-1",
"time": "2020-01-13 00:00:00",
"result":
[
@ -752,8 +746,7 @@ var results =
},
{
"system": "Dell PowerEdge R640 DX292 2x Xeon SP Gold 16-Core 2.10GHz, 196 GB RAM, 2x SSD 960 GB RAID 1",
"data_size": 100000000,
"system": "Dell PowerEdge R640 DX292 2x Xeon SP Gold 16-Core 2.10GHz, 196 GB RAM, 2x SSD 960 GB RAID-1",
"time": "2020-01-13 00:00:00",
"result":
[
@ -805,7 +798,6 @@ var results =
{
"system": "E5-2650 v2 @ 2.60GHz, 2 sockets, 16 threads, 8xHDD RAID-5",
"data_size": 100000000,
"time": "2020-01-12 00:00:00",
"result":
[
@ -857,7 +849,6 @@ var results =
{
"system": "Time4vps.eu VPS (KVM) Linux Ubuntu 4 Core (Skylake) 16GB RAM 160GB Disk",
"data_size": 100000000,
"time": "2020-01-13 00:00:00",
"result":
[
@ -909,7 +900,6 @@ var results =
{
"system": "Lenovo B580 Laptop (i5-3210M)",
"data_size": 100000000,
"time": "2020-01-11 00:00:00",
"result":
[
@ -961,7 +951,6 @@ var results =
{
"system": "Dell PowerEdge R730xd, 2 socket 10 cores E5-2640 v4, HW RAID5 3TBx12 SATA",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -1013,7 +1002,6 @@ var results =
{
"system": "Yandex Managed ClickHouse, s3.3xlarge, Cascade Lake 32 vCPU, 128 GB RAM, 1 TB local SSD",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -1065,7 +1053,6 @@ var results =
{
"system": "Yandex Managed ClickHouse, s3.3xlarge, Cascade Lake 32 vCPU, 128 GB RAM, 12.5 TB local HDD",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -1117,7 +1104,6 @@ var results =
{
"system": "Dell R530, 128GB DDR4, 2x480 GB SATA SSD, Perc H730 RAID-1",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -1169,7 +1155,6 @@ var results =
{
"system": "Dell R530, 128GB DDR4, 6x2TB SATA 3.5 HDD, Perc H730 RAID-10",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -1221,7 +1206,6 @@ var results =
{
"system": "Xeon 2176G, 64GB RAM, 2xSSD 960GB (SAMSUNG MZQLB960HAJR-00007), ZFS RAID-1",
"data_size": 100000000,
"time": "2020-01-14 00:00:00",
"result":
[
@ -1273,7 +1257,6 @@ var results =
{
"system": "Azure DS3v2 4vcpu 14GB RAM 1TB Standard SSD",
"data_size": 100000000,
"time": "2020-01-15 00:00:00",
"result":
[
@ -1325,7 +1308,6 @@ var results =
{
"system": "Azure DS3v2 4vcpu 14GB RAM 1TB Premium SSD",
"data_size": 100000000,
"time": "2020-01-15 00:00:00",
"result":
[
@ -1377,7 +1359,6 @@ var results =
{
"system": "AWS i3.8xlarge 32vCPU 244GiB 4x1900 NVMe SSD",
"data_size": 100000000,
"time": "2020-01-15 00:00:00",
"result":
[
@ -1429,7 +1410,6 @@ var results =
{
"system": "AWS m5d.24xlarge 96vCPU 384GiB 4x900 NVMe SSD",
"data_size": 100000000,
"time": "2020-01-15 00:00:00",
"result":
[
@ -1481,7 +1461,6 @@ var results =
{
"system": "AWS i3en.24xlarge 96vCPU 768GiB 8x7500 NVMe SSD",
"data_size": 100000000,
"time": "2020-01-15 00:00:00",
"result":
[
@ -1533,7 +1512,6 @@ var results =
{
"system": "Huawei TaiShan 2280 v2 (AArch64) 64 core (2-die), one physical HDD",
"data_size": 100000000,
"time": "2020-01-15 00:00:00",
"result":
[
@ -1582,19 +1560,165 @@ var results =
[0.340, 0.007, 0.007]
]
},
{
"system": "AWS m5ad.24xlarge 96vCPU 384GiB 4x900 NVMe SSD, AMD EPYC 7000 series 2.5 GHz",
"time": "2020-01-17 00:00:00",
"result":
[
[0.013, 0.002, 0.002],
[0.055, 0.020, 0.025],
[0.054, 0.027, 0.026],
[0.154, 0.035, 0.035],
[0.221, 0.117, 0.118],
[0.325, 0.171, 0.166],
[0.042, 0.021, 0.017],
[0.025, 0.017, 0.018],
[0.353, 0.253, 0.253],
[0.477, 0.610, 0.720],
[0.257, 0.154, 0.139],
[0.251, 0.130, 0.114],
[0.513, 0.293, 0.286],
[0.618, 0.360, 0.350],
[0.468, 0.336, 0.329],
[0.390, 0.333, 0.411],
[1.112, 0.936, 1.497],
[2.434, 1.350, 0.886],
[2.590, 2.069, 2.331],
[0.160, 0.048, 0.036],
[1.638, 0.334, 0.312],
[1.841, 0.423, 0.373],
[3.673, 1.122, 1.078],
[3.808, 0.912, 0.494],
[0.480, 0.112, 0.120],
[0.248, 0.107, 0.099],
[0.470, 0.118, 0.114],
[1.648, 0.544, 0.469],
[1.418, 0.583, 0.624],
[0.966, 1.231, 0.999],
[0.539, 0.311, 0.370],
[1.159, 0.712, 0.716],
[3.755, 2.772, 2.973],
[2.748, 2.033, 2.242],
[2.842, 2.150, 2.019],
[0.784, 0.616, 0.641],
[0.304, 0.273, 0.235],
[0.106, 0.086, 0.093],
[0.117, 0.073, 0.075],
[0.604, 0.453, 0.502],
[0.050, 0.036, 0.034],
[0.043, 0.023, 0.027],
[0.013, 0.008, 0.007]
]
},
{
"system": "Lenovo Thinkpad X1 Carbon 6th Gen i7-8550U CPU @ 1.80GHz 4 threads, 16 GiB",
"time": "2020-01-18 00:00:00",
"result":
[
[0.006, 0.002, 0.002],
[0.031, 0.019, 0.020],
[0.082, 0.078, 0.080],
[0.157, 0.093, 0.092],
[0.274, 0.214, 0.206],
[0.601, 0.513, 0.513],
[0.038, 0.045, 0.041],
[0.023, 0.018, 0.018],
[1.394, 1.378, 1.323],
[1.567, 1.496, 1.483],
[0.406, 0.328, 0.327],
[0.468, 0.414, 0.397],
[1.846, 1.753, 1.737],
[2.492, 2.423, 2.404],
[2.136, 2.064, 2.078],
[2.038, 1.971, 1.971],
[5.794, 5.679, 5.708],
[3.430, 3.498, 3.356],
[11.946, 11.738, 11.700],
[0.158, 0.105, 0.091],
[2.151, 1.551, 1.593],
[2.581, 1.990, 1.985],
[6.101, 5.390, 5.320],
[3.528, 2.341, 2.322],
[0.772, 0.699, 0.701],
[0.606, 0.583, 0.587],
[0.877, 0.723, 0.728],
[2.398, 1.916, 1.924],
[3.634, 3.272, 3.247],
[4.102, 4.082, 4.078],
[1.885, 1.784, 1.741],
[2.994, 2.691, 2.707],
[19.060, 18.852, 18.929],
[8.745, 8.476, 8.553],
[8.685, 8.406, 8.946],
[3.416, 3.426, 3.397],
[0.238, 0.234, 0.210],
[0.080, 0.071, 0.072],
[0.078, 0.066, 0.066],
[0.470, 0.407, 0.396],
[0.034, 0.030, 0.029],
[0.025, 0.021, 0.021],
[0.010, 0.007, 0.006]
]
},
{
"system": "E5645 @ 2.40GHz, 2 sockets, 12 threads, 96 GiB, 14 x 2TB HDD RAID-10",
"time": "2020-01-18 00:00:00",
"result":
[
[0.061, 0.003, 0.003],
[0.203, 0.026, 0.019],
[0.231, 0.056, 0.060],
[0.533, 0.080, 0.099],
[0.458, 0.202, 0.213],
[0.723, 0.468, 0.411],
[0.143, 0.034, 0.029],
[0.117, 0.025, 0.023],
[1.033, 0.810, 0.745],
[1.165, 0.916, 0.898],
[0.514, 0.249, 0.297],
[0.600, 0.343, 0.385],
[1.294, 1.156, 1.221],
[1.859, 1.459, 1.384],
[1.627, 1.349, 1.346],
[1.414, 1.269, 1.306],
[3.798, 3.774, 3.631],
[2.177, 2.054, 2.016],
[7.002, 6.187, 6.263],
[0.461, 0.081, 0.116],
[3.860, 1.296, 1.330],
[4.705, 1.587, 1.503],
[9.533, 3.887, 3.564],
[11.468, 1.932, 1.712],
[1.362, 0.451, 0.403],
[0.648, 0.374, 0.414],
[1.195, 0.437, 0.418],
[4.187, 1.686, 1.474],
[3.289, 2.146, 2.159],
[3.919, 4.242, 4.208],
[1.673, 1.084, 1.040],
[3.264, 1.496, 1.629],
[8.883, 8.965, 9.027],
[5.813, 5.225, 5.365],
[5.874, 5.376, 5.353],
[2.053, 1.910, 1.951],
[0.478, 0.324, 0.325],
[0.206, 0.132, 0.124],
[0.222, 0.105, 0.111],
[0.699, 0.599, 0.563],
[0.213, 0.041, 0.040],
[0.133, 0.032, 0.040],
[0.062, 0.010, 0.010]
]
},
];
</script>
<script type="text/javascript">
var data_sizes =
[
{ id: "100000000", name: "100 mln." },
];
var current_data_size = 100000000;
var systems = [];
var systems_uniq = {};
for (r in results) {
@ -1606,35 +1730,32 @@ for (r in results) {
var current_systems = [
'Xeon Gold 6230, 2 sockets, 40 threads',
'Dell PowerEdge R640 DX292 2x Xeon SP Gold 16-Core 2.10GHz, 196 GB RAM, 2x SSD 960 GB RAID 1',
'Dell PowerEdge R640 DX292 2x Xeon SP Gold 16-Core 2.10GHz, 196 GB RAM, 2x SSD 960 GB RAID-1',
'E5-2650 v2 @ 2.60GHz, 2 sockets, 16 threads, 8xHDD RAID-5'];
var runs = ["first (cold cache)", "second", "third"];
var current_runs = ['1', '2'];
try {
var state = JSON.parse(window.location.hash.substring(1));
var state = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
current_data_size = state[0];
current_systems = state[1];
current_runs = state[2];
current_systems = state[0];
current_runs = state[1];
} catch (e) {}
function update_hash() {
window.location.hash = JSON.stringify([ current_data_size, current_systems, current_runs ]);
window.location.hash = JSON.stringify([ current_systems, current_runs ]);
}
function generate_selectors(elem) {
var html = "<p id='systems_selector'>Compare: ";
var available_systems_for_current_data_size = results.
filter(function(run) { return run.data_size == current_data_size; }).
map(function(run) { return run.system; });
var available_systems = results.map(function(run) { return run.system; });
for (var i = 0; i < systems.length; i++) {
var selected = current_systems.indexOf(systems[i]) != -1;
var available = available_systems_for_current_data_size.indexOf(systems[i]) != -1;
var available = available_systems.indexOf(systems[i]) != -1;
html += "<span class='" +
(selected && available ? "selected" : "") +
@ -1642,15 +1763,6 @@ function generate_selectors(elem) {
"'>" + systems[i] + "</span> ";
}
html += "</p>";
html += "<p id='data_size_selector'>";
html += "Dataset size: ";
for (var i = 0; i < data_sizes.length; i++) {
html += "<span class='" + (data_sizes[i].id == current_data_size ? "selected" : "") + "' data-size-id='" + data_sizes[i].id + "'>" + data_sizes[i].name + "</span> ";
}
html += "</p>";
html += "<p id='runs_selector'>";
@ -1682,17 +1794,6 @@ function generate_selectors(elem) {
generate_diagram();
});
$('#data_size_selector span').click(function(event) {
var target = $(event.target || event.srcElement);
current_data_size = target.attr("data-size-id");
update_hash();
generate_selectors(elem);
generate_comparison_table();
generate_diagram();
});
$('#runs_selector span').click(function(event) {
var target = $(event.target || event.srcElement);
@ -1743,8 +1844,7 @@ var ratios = [];
function generate_comparison_table() {
ratios = [];
var filtered_results = results.filter(function(x) {
return x.data_size == current_data_size && current_systems.indexOf(x.system) != -1; });
var filtered_results = results.filter(function(x) { return current_systems.indexOf(x.system) != -1; });
var html = "";
@ -1856,8 +1956,7 @@ function generate_comparison_table() {
function calculate_totals() {
if (!current_systems.length) return;
var filtered_results = results.filter(function(x) {
return x.data_size == current_data_size && current_systems.indexOf(x.system) != -1; });
var filtered_results = results.filter(function(x) { return current_systems.indexOf(x.system) != -1; });
var total_ratios = [];
@ -1894,8 +1993,7 @@ function calculate_totals() {
function generate_diagram() {
var html = "";
var filtered_results = results.filter(function(x) {
return x.data_size == current_data_size && current_systems.indexOf(x.system) != -1; });
var filtered_results = results.filter(function(x) { return current_systems.indexOf(x.system) != -1; });
var max_ratio = 1;
var min_ratio = 0;
@ -2043,7 +2141,7 @@ Results for Xeon 2176G are from <b>Sergey Golod</b>.<br/>
Results for Azure DS3v2 are from <b>Boris Granveaud</b>.<br/>
Results for AWS are from <b>Wolf Kreuzerkrieg</b>.<br/>
Results for Huawei Taishan are from <b>Peng Gao</b> in sina.com.<br/>
Xeon Gold 6230 server is using 4 x SAMSUNG datacenter class SSD in RAID 10.<br/>
Xeon Gold 6230 server is using 4 x SAMSUNG datacenter class SSD in RAID-10.<br/>
Results for Yandex Managed ClickHouse for "cold cache" are biased and should not be compared, because cache was not flushed for every next query.<br/>
</div>