Merge branch 'master' of https://github.com/yandex/ClickHouse into yandex_open_code_competition

This commit is contained in:
alexander kozhikhov 2019-02-02 17:28:34 +03:00
commit 9d2a0c69fc
40 changed files with 781 additions and 275 deletions

View File

@ -1,5 +1,11 @@
option(USE_INTERNAL_PROTOBUF_LIBRARY "Set to FALSE to use system protobuf instead of bundled" ${NOT_UNBUNDLED})
if(OS_FREEBSD AND SANITIZE STREQUAL "address")
# ../contrib/protobuf/src/google/protobuf/arena_impl.h:45:10: fatal error: 'sanitizer/asan_interface.h' file not found
set(MISSING_INTERNAL_PROTOBUF_LIBRARY 1)
set(USE_INTERNAL_PROTOBUF_LIBRARY 0)
endif()
if(NOT EXISTS "${ClickHouse_SOURCE_DIR}/contrib/protobuf/cmake/CMakeLists.txt")
if(USE_INTERNAL_PROTOBUF_LIBRARY)
message(WARNING "submodule contrib/protobuf is missing. to fix try run: \n git submodule update --init --recursive")

View File

@ -282,6 +282,7 @@ target_link_libraries (dbms PRIVATE ${Poco_Foundation_LIBRARY})
if (USE_ICU)
target_link_libraries (dbms PRIVATE ${ICU_LIBRARIES})
target_include_directories (dbms SYSTEM PRIVATE ${ICU_INCLUDE_DIRS})
endif ()
if (USE_CAPNP)

View File

@ -8,7 +8,7 @@
#include <Common/Exception.h>
#include <IO/ConnectionTimeouts.h>
#include <common/SetTerminalEcho.h>
#include <common/setTerminalEcho.h>
#include <ext/scope_guard.h>
#include <Poco/Util/AbstractConfiguration.h>
@ -56,10 +56,10 @@ struct ConnectionParameters
throw Exception("Specified both --password and --ask-password. Remove one of them", ErrorCodes::BAD_ARGUMENTS);
std::cout << "Password for user " << user << ": ";
SetTerminalEcho(false);
setTerminalEcho(false);
SCOPE_EXIT({
SetTerminalEcho(true);
setTerminalEcho(true);
});
std::getline(std::cin, password);
std::cout << std::endl;

View File

@ -128,6 +128,32 @@ UInt64 PerformanceTest::calculateMaxExecTime() const
return result;
}
void PerformanceTest::prepare() const
{
for (const auto & query : test_info.create_queries)
{
LOG_INFO(log, "Executing create query '" << query << "'");
connection.sendQuery(query);
}
for (const auto & query : test_info.fill_queries)
{
LOG_INFO(log, "Executing fill query '" << query << "'");
connection.sendQuery(query);
}
}
void PerformanceTest::finish() const
{
for (const auto & query : test_info.drop_queries)
{
LOG_INFO(log, "Executing drop query '" << query << "'");
connection.sendQuery(query);
}
}
std::vector<TestStats> PerformanceTest::execute()
{
std::vector<TestStats> statistics_by_run;

View File

@ -25,12 +25,15 @@ public:
Context & context_);
bool checkPreconditions() const;
void prepare() const;
std::vector<TestStats> execute();
void finish() const;
const PerformanceTestInfo & getTestInfo() const
{
return test_info;
}
bool checkSIGINT() const
{
return got_SIGINT;

View File

@ -90,6 +90,7 @@ PerformanceTestInfo::PerformanceTestInfo(
getExecutionType(config);
getStopConditions(config);
getMetrics(config);
extractAuxiliaryQueries(config);
}
void PerformanceTestInfo::applySettings(XMLConfigurationPtr config)
@ -269,4 +270,16 @@ void PerformanceTestInfo::getMetrics(XMLConfigurationPtr config)
checkMetricsInput(metrics, exec_type);
}
void PerformanceTestInfo::extractAuxiliaryQueries(XMLConfigurationPtr config)
{
if (config->has("create_query"))
create_queries = getMultipleValuesFromConfig(*config, "", "create_query");
if (config->has("fill_query"))
fill_queries = getMultipleValuesFromConfig(*config, "", "fill_query");
if (config->has("drop_query"))
drop_queries = getMultipleValuesFromConfig(*config, "", "drop_query");
}
}

View File

@ -43,6 +43,10 @@ public:
std::string profiles_file;
std::vector<TestStopConditions> stop_conditions_by_run;
Strings create_queries;
Strings fill_queries;
Strings drop_queries;
private:
void applySettings(XMLConfigurationPtr config);
void extractQueries(XMLConfigurationPtr config);
@ -50,6 +54,7 @@ private:
void getExecutionType(XMLConfigurationPtr config);
void getStopConditions(XMLConfigurationPtr config);
void getMetrics(XMLConfigurationPtr config);
void extractAuxiliaryQueries(XMLConfigurationPtr config);
};
}

View File

@ -202,11 +202,18 @@ private:
current.checkPreconditions();
LOG_INFO(log, "Preconditions for test '" << info.test_name << "' are fullfilled");
LOG_INFO(log, "Preparing for run, have " << info.create_queries.size()
<< " create queries and " << info.fill_queries.size() << " fill queries");
current.prepare();
LOG_INFO(log, "Prepared");
LOG_INFO(log, "Running test '" << info.test_name << "'");
auto result = current.execute();
LOG_INFO(log, "Test '" << info.test_name << "' finished");
LOG_INFO(log, "Running post run queries");
current.finish();
LOG_INFO(log, "Postqueries finished");
if (lite_output)
return {report_builder->buildCompactReport(info, result), current.checkSIGINT()};
else

View File

@ -120,17 +120,7 @@ void CreatingSetsBlockInputStream::createOne(SubqueryForSet & subquery)
if (!done_with_join)
{
for (const auto & name_with_alias : subquery.joined_block_aliases)
{
if (block.has(name_with_alias.first))
{
auto pos = block.getPositionByName(name_with_alias.first);
auto column = block.getByPosition(pos);
block.erase(pos);
column.name = name_with_alias.second;
block.insert(std::move(column));
}
}
subquery.renameColumns(block);
if (subquery.joined_block_actions)
subquery.joined_block_actions->execute(block);

View File

@ -36,6 +36,7 @@ endif ()
if (USE_ICU)
target_link_libraries (clickhouse_functions PRIVATE ${ICU_LIBRARIES})
target_include_directories(clickhouse_functions SYSTEM PRIVATE ${ICU_INCLUDE_DIRS})
endif ()
if (USE_VECTORCLASS)

View File

@ -1,111 +0,0 @@
#include <IO/InterserverWriteBuffer.h>
#include <IO/WriteBufferFromOStream.h>
#include <Poco/Version.h>
#include <Poco/URI.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <common/logger_useful.h>
namespace DB
{
namespace ErrorCodes
{
extern const int CANNOT_WRITE_TO_OSTREAM;
extern const int RECEIVED_ERROR_FROM_REMOTE_IO_SERVER;
}
InterserverWriteBuffer::InterserverWriteBuffer(const std::string & host_, int port_,
const std::string & endpoint_,
const std::string & path_,
bool compress_,
size_t buffer_size_,
const Poco::Timespan & connection_timeout,
const Poco::Timespan & send_timeout,
const Poco::Timespan & receive_timeout)
: WriteBuffer(nullptr, 0), host(host_), port(port_), path(path_)
{
std::string encoded_path;
Poco::URI::encode(path, "&#", encoded_path);
std::string encoded_endpoint;
Poco::URI::encode(endpoint_, "&#", encoded_endpoint);
std::string compress_str = compress_ ? "true" : "false";
std::string encoded_compress;
Poco::URI::encode(compress_str, "&#", encoded_compress);
std::stringstream uri;
uri << "http://" << host << ":" << port
<< "/?endpoint=" << encoded_endpoint
<< "&compress=" << encoded_compress
<< "&path=" << encoded_path;
std::string uri_str = Poco::URI(uri.str()).getPathAndQuery();
session.setHost(host);
session.setPort(port);
session.setKeepAlive(true);
/// set the timeout
#if POCO_CLICKHOUSE_PATCH || POCO_VERSION >= 0x02000000
session.setTimeout(connection_timeout, send_timeout, receive_timeout);
#else
session.setTimeout(connection_timeout);
static_cast <void> (send_timeout);
static_cast <void> (receive_timeout);
#endif
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, uri_str, Poco::Net::HTTPRequest::HTTP_1_1);
request.setChunkedTransferEncoding(true);
ostr = &session.sendRequest(request);
impl = std::make_unique<WriteBufferFromOStream>(*ostr, buffer_size_);
set(impl->buffer().begin(), impl->buffer().size());
}
InterserverWriteBuffer::~InterserverWriteBuffer()
{
try
{
finalize();
}
catch (...)
{
tryLogCurrentException(__PRETTY_FUNCTION__);
}
}
void InterserverWriteBuffer::nextImpl()
{
if (!offset() || finalized)
return;
/// For correct work with AsynchronousWriteBuffer, which replaces buffers.
impl->set(buffer().begin(), buffer().size());
impl->position() = pos;
impl->next();
}
void InterserverWriteBuffer::finalize()
{
if (finalized)
return;
next();
finalized = true;
}
void InterserverWriteBuffer::cancel()
{
finalized = true;
}
}

View File

@ -1,54 +0,0 @@
#pragma once
#include <IO/WriteBuffer.h>
#include <IO/HashingWriteBuffer.h>
#include <Poco/Net/HTTPClientSession.h>
namespace DB
{
namespace
{
constexpr auto DEFAULT_REMOTE_WRITE_BUFFER_CONNECTION_TIMEOUT = 1;
constexpr auto DEFAULT_REMOTE_WRITE_BUFFER_RECEIVE_TIMEOUT = 1800;
constexpr auto DEFAULT_REMOTE_WRITE_BUFFER_SEND_TIMEOUT = 1800;
}
/** Allows you to write a file to a remote server.
*/
class InterserverWriteBuffer final : public WriteBuffer
{
public:
InterserverWriteBuffer(const std::string & host_, int port_,
const std::string & endpoint_,
const std::string & path_,
bool compress_ = false,
size_t buffer_size_ = DBMS_DEFAULT_BUFFER_SIZE,
const Poco::Timespan & connection_timeout = Poco::Timespan(DEFAULT_REMOTE_WRITE_BUFFER_CONNECTION_TIMEOUT, 0),
const Poco::Timespan & send_timeout = Poco::Timespan(DEFAULT_REMOTE_WRITE_BUFFER_SEND_TIMEOUT, 0),
const Poco::Timespan & receive_timeout = Poco::Timespan(DEFAULT_REMOTE_WRITE_BUFFER_RECEIVE_TIMEOUT, 0));
~InterserverWriteBuffer() override;
void finalize();
void cancel();
private:
void nextImpl() override;
private:
std::string host;
int port;
std::string path;
Poco::Net::HTTPClientSession session;
std::ostream * ostr; /// this is owned by session
std::unique_ptr<WriteBuffer> impl;
/// Sent all the data and renamed the file
bool finalized = false;
};
}

View File

@ -3,6 +3,7 @@
#include <Parsers/IAST.h>
#include <Interpreters/PreparedSets.h>
#include <Interpreters/ExpressionActions.h>
#include <Interpreters/SubqueryForSet.h>
namespace DB
@ -11,32 +12,6 @@ namespace DB
class Context;
class ASTFunction;
class Join;
using JoinPtr = std::shared_ptr<Join>;
/// Information on what to do when executing a subquery in the [GLOBAL] IN/JOIN section.
struct SubqueryForSet
{
/// The source is obtained using the InterpreterSelectQuery subquery.
BlockInputStreamPtr source;
/// If set, build it from result.
SetPtr set;
JoinPtr join;
/// Apply this actions to joined block.
ExpressionActionsPtr joined_block_actions;
/// Rename column from joined block from this list.
NamesWithAliases joined_block_aliases;
/// If set, put the result into the table.
/// This is a temporary table for transferring to remote servers for distributed query processing.
StoragePtr table;
};
/// ID of subquery -> what to do with it.
using SubqueriesForSets = std::unordered_map<String, SubqueryForSet>;
/// The case of an explicit enumeration of values.
SetPtr makeExplicitSet(
const ASTFunction * node, const Block & sample_block, bool create_ordered_set,

View File

@ -0,0 +1,129 @@
#include <Common/typeid_cast.h>
#include <Interpreters/CrossToInnerJoinVisitor.h>
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Interpreters/IdentifierSemantic.h>
#include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ParserTablesInSelectQuery.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/parseQuery.h>
#include <IO/WriteHelpers.h>
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
/// TODO: array join aliases?
struct CheckColumnsVisitorData
{
using TypeToVisit = ASTIdentifier;
const std::vector<DatabaseAndTableWithAlias> & tables;
size_t visited;
size_t found;
size_t allMatch() const { return visited == found; }
void visit(ASTIdentifier & node, ASTPtr &)
{
++visited;
for (const auto & t : tables)
if (IdentifierSemantic::canReferColumnToTable(node, t))
++found;
}
};
static bool extractTableName(const ASTTableExpression & expr, std::vector<DatabaseAndTableWithAlias> & names)
{
/// Subselects are not supported.
if (!expr.database_and_table_name)
return false;
names.emplace_back(DatabaseAndTableWithAlias(expr));
return true;
}
static ASTPtr getCrossJoin(ASTSelectQuery & select, std::vector<DatabaseAndTableWithAlias> & table_names)
{
if (!select.tables)
return {};
auto tables = typeid_cast<const ASTTablesInSelectQuery *>(select.tables.get());
if (!tables)
return {};
size_t num_tables = tables->children.size();
if (num_tables != 2)
return {};
auto left = typeid_cast<const ASTTablesInSelectQueryElement *>(tables->children[0].get());
auto right = typeid_cast<const ASTTablesInSelectQueryElement *>(tables->children[1].get());
if (!left || !right || !right->table_join)
return {};
if (auto join = typeid_cast<const ASTTableJoin *>(right->table_join.get()))
{
if (join->kind == ASTTableJoin::Kind::Cross ||
join->kind == ASTTableJoin::Kind::Comma)
{
if (!join->children.empty())
throw Exception("Logical error: CROSS JOIN has expressions", ErrorCodes::LOGICAL_ERROR);
auto & left_expr = typeid_cast<const ASTTableExpression &>(*left->table_expression);
auto & right_expr = typeid_cast<const ASTTableExpression &>(*right->table_expression);
table_names.reserve(2);
if (extractTableName(left_expr, table_names) &&
extractTableName(right_expr, table_names))
return right->table_join;
}
}
return {};
}
std::vector<ASTPtr *> CrossToInnerJoinMatcher::visit(ASTPtr & ast, Data & data)
{
if (auto * t = typeid_cast<ASTSelectQuery *>(ast.get()))
visit(*t, ast, data);
return {};
}
void CrossToInnerJoinMatcher::visit(ASTSelectQuery & select, ASTPtr & ast, Data & data)
{
using CheckColumnsMatcher = OneTypeMatcher<CheckColumnsVisitorData>;
using CheckColumnsVisitor = InDepthNodeVisitor<CheckColumnsMatcher, true>;
std::vector<DatabaseAndTableWithAlias> table_names;
ASTPtr ast_join = getCrossJoin(select, table_names);
if (!ast_join)
return;
/// check Identifier names from where expression
CheckColumnsVisitor::Data columns_data{table_names, 0, 0};
CheckColumnsVisitor(columns_data).visit(select.where_expression);
if (!columns_data.allMatch())
return;
auto & join = typeid_cast<ASTTableJoin &>(*ast_join);
join.kind = ASTTableJoin::Kind::Inner;
join.strictness = ASTTableJoin::Strictness::All; /// TODO: do we need it?
join.on_expression.swap(select.where_expression);
join.children.push_back(join.on_expression);
ast = ast->clone(); /// rewrite AST in right manner
data.done = true;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <Interpreters/InDepthNodeVisitor.h>
namespace DB
{
class ASTSelectQuery;
/// AST transformer. It replaces cross joins with equivalented inner join if possible.
class CrossToInnerJoinMatcher
{
public:
struct Data
{
bool done = false;
};
static constexpr const char * label = "JoinToSubqueryTransform";
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return true; }
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
private:
static void visit(ASTSelectQuery & select, ASTPtr & ast, Data & data);
};
using CrossToInnerJoinVisitor = InDepthNodeVisitor<CrossToInnerJoinMatcher, true>;
}

View File

@ -27,7 +27,7 @@ struct DatabaseAndTableWithAlias
DatabaseAndTableWithAlias() = default;
DatabaseAndTableWithAlias(const ASTPtr & identifier_node, const String & current_database = "");
DatabaseAndTableWithAlias(const ASTIdentifier & identifier, const String & current_database = "");
DatabaseAndTableWithAlias(const ASTTableExpression & table_expression, const String & current_database);
DatabaseAndTableWithAlias(const ASTTableExpression & table_expression, const String & current_database = "");
/// "alias." or "table." if alias is empty
String getQualifiedNamePrefix() const;

View File

@ -22,7 +22,6 @@
#include <Columns/IColumn.h>
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
#include <Interpreters/ExpressionAnalyzer.h>
#include <Interpreters/ExpressionActions.h>
#include <Interpreters/InJoinSubqueriesPreprocessor.h>
@ -39,7 +38,6 @@
#include <Storages/StorageMemory.h>
#include <Storages/StorageJoin.h>
#include <DataStreams/LazyBlockInputStream.h>
#include <DataStreams/copyData.h>
#include <Dictionaries/IDictionary.h>
@ -568,9 +566,6 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty
if (!subquery_for_set.join)
{
JoinPtr join = std::make_shared<Join>(analyzedJoin().key_names_right, settings.join_use_nulls,
settings.size_limits_for_join, join_params.kind, join_params.strictness);
/** For GLOBAL JOINs (in the case, for example, of the push method for executing GLOBAL subqueries), the following occurs
* - in the addExternalStorage function, the JOIN (SELECT ...) subquery is replaced with JOIN _data1,
* in the subquery_for_set object this subquery is exposed as source and the temporary table _data1 as the `table`.
@ -587,39 +582,23 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty
else if (table_to_join.database_and_table_name)
table = table_to_join.database_and_table_name;
const JoinedColumnsList & columns_from_joined_table = analyzedJoin().columns_from_joined_table;
Names original_columns;
for (const auto & column : analyzedJoin().columns_from_joined_table)
for (const auto & column : columns_from_joined_table)
if (required_columns_from_joined_table.count(column.name_and_type.name))
original_columns.emplace_back(column.original_name);
auto interpreter = interpretSubquery(table, context, subquery_depth, original_columns);
subquery_for_set.source = std::make_shared<LazyBlockInputStream>(
interpreter->getSampleBlock(),
[interpreter]() mutable { return interpreter->execute().in; });
}
/// Alias duplicating columns as qualified.
for (const auto & column : analyzedJoin().columns_from_joined_table)
if (required_columns_from_joined_table.count(column.name_and_type.name))
subquery_for_set.joined_block_aliases.emplace_back(column.original_name, column.name_and_type.name);
auto sample_block = subquery_for_set.source->getHeader();
for (const auto & name_with_alias : subquery_for_set.joined_block_aliases)
{
if (sample_block.has(name_with_alias.first))
{
auto pos = sample_block.getPositionByName(name_with_alias.first);
auto column = sample_block.getByPosition(pos);
sample_block.erase(pos);
column.name = name_with_alias.second;
sample_block.insert(std::move(column));
}
subquery_for_set.makeSource(interpreter, columns_from_joined_table, required_columns_from_joined_table);
}
Block sample_block = subquery_for_set.renamedSampleBlock();
joined_block_actions->execute(sample_block);
/// TODO You do not need to set this up when JOIN is only needed on remote servers.
subquery_for_set.join = join;
subquery_for_set.join = std::make_shared<Join>(analyzedJoin().key_names_right, settings.join_use_nulls,
settings.size_limits_for_join, join_params.kind, join_params.strictness);
subquery_for_set.join->setSampleBlock(sample_block);
subquery_for_set.joined_block_actions = joined_block_actions;
}

View File

@ -380,8 +380,9 @@ InterpreterSelectQuery::AnalysisResult InterpreterSelectQuery::analyzeExpression
if (query_analyzer->appendJoin(chain, dry_run || !res.first_stage))
{
res.has_join = true;
res.before_join = chain.getLastActions();
if (!res.hasJoin())
throw Exception("No expected JOIN", ErrorCodes::LOGICAL_ERROR);
chain.addStep();
}
@ -548,7 +549,7 @@ void InterpreterSelectQuery::executeImpl(Pipeline & pipeline, const BlockInputSt
if (expressions.first_stage)
{
if (expressions.has_join)
if (expressions.hasJoin())
{
const ASTTableJoin & join = static_cast<const ASTTableJoin &>(*query.join()->table_join);
if (join.kind == ASTTableJoin::Kind::Full || join.kind == ASTTableJoin::Kind::Right)

View File

@ -132,7 +132,7 @@ private:
struct AnalysisResult
{
bool has_join = false;
bool hasJoin() const { return before_join.get(); }
bool has_where = false;
bool need_aggregate = false;
bool has_having = false;

View File

@ -185,8 +185,8 @@ BlockIO InterpreterSystemQuery::execute()
case Type::STOP_REPLICATED_SENDS:
startStopAction(context, query, ActionLocks::PartsSend, false);
break;
case Type::START_REPLICATEDS_SENDS:
startStopAction(context, query, ActionLocks::PartsSend, false);
case Type::START_REPLICATED_SENDS:
startStopAction(context, query, ActionLocks::PartsSend, true);
break;
case Type::STOP_REPLICATION_QUEUES:
startStopAction(context, query, ActionLocks::ReplicationQueue, false);

View File

@ -298,6 +298,7 @@ struct Settings
M(SettingBool, enable_unaligned_array_join, false, "Allow ARRAY JOIN with multiple arrays that have different sizes. When this settings is enabled, arrays will be resized to the longest one.") \
M(SettingBool, low_cardinality_allow_in_native_format, true, "Use LowCardinality type in Native format. Otherwise, convert LowCardinality columns to ordinary for select query, and convert ordinary columns to required LowCardinality for insert query.") \
M(SettingBool, allow_experimental_multiple_joins_emulation, false, "Emulate multiple joins using subselects") \
M(SettingBool, allow_experimental_cross_to_join_conversion, false, "Convert CROSS JOIN to INNER JOIN if possible") \
#define DECLARE(TYPE, NAME, DEFAULT, DESCRIPTION) \
TYPE NAME {DEFAULT};

View File

@ -0,0 +1,49 @@
#include <Interpreters/SubqueryForSet.h>
#include <Interpreters/AnalyzedJoin.h>
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
#include <DataStreams/LazyBlockInputStream.h>
namespace DB
{
void SubqueryForSet::makeSource(std::shared_ptr<InterpreterSelectWithUnionQuery> & interpreter,
const std::list<JoinedColumn> & columns_from_joined_table,
const NameSet & required_columns_from_joined_table)
{
source = std::make_shared<LazyBlockInputStream>(interpreter->getSampleBlock(),
[interpreter]() mutable { return interpreter->execute().in; });
for (const auto & column : columns_from_joined_table)
if (required_columns_from_joined_table.count(column.name_and_type.name))
joined_block_aliases.emplace_back(column.original_name, column.name_and_type.name);
sample_block = source->getHeader();
for (const auto & name_with_alias : joined_block_aliases)
{
if (sample_block.has(name_with_alias.first))
{
auto pos = sample_block.getPositionByName(name_with_alias.first);
auto column = sample_block.getByPosition(pos);
sample_block.erase(pos);
column.name = name_with_alias.second;
sample_block.insert(std::move(column));
}
}
}
void SubqueryForSet::renameColumns(Block & block)
{
for (const auto & name_with_alias : joined_block_aliases)
{
if (block.has(name_with_alias.first))
{
auto pos = block.getPositionByName(name_with_alias.first);
auto column = block.getByPosition(pos);
block.erase(pos);
column.name = name_with_alias.second;
block.insert(std::move(column));
}
}
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <Parsers/IAST.h>
#include <Interpreters/PreparedSets.h>
#include <Interpreters/ExpressionActions.h>
namespace DB
{
class Join;
using JoinPtr = std::shared_ptr<Join>;
class InterpreterSelectWithUnionQuery;
struct JoinedColumn;
/// Information on what to do when executing a subquery in the [GLOBAL] IN/JOIN section.
struct SubqueryForSet
{
/// The source is obtained using the InterpreterSelectQuery subquery.
BlockInputStreamPtr source;
/// If set, build it from result.
SetPtr set;
JoinPtr join;
/// Apply this actions to joined block.
ExpressionActionsPtr joined_block_actions;
/// If set, put the result into the table.
/// This is a temporary table for transferring to remote servers for distributed query processing.
StoragePtr table;
void makeSource(std::shared_ptr<InterpreterSelectWithUnionQuery> & interpreter,
const std::list<JoinedColumn> & columns_from_joined_table,
const NameSet & required_columns_from_joined_table);
Block renamedSampleBlock() const { return sample_block; }
void renameColumns(Block & block);
private:
NamesWithAliases joined_block_aliases; /// Rename column from joined block from this list.
Block sample_block; /// source->getHeader() + column renames
};
/// ID of subquery -> what to do with it.
using SubqueriesForSets = std::unordered_map<String, SubqueryForSet>;
}

View File

@ -22,6 +22,7 @@
#include <Parsers/queryToString.h>
#include <Interpreters/JoinToSubqueryTransformVisitor.h>
#include <Interpreters/CrossToInnerJoinVisitor.h>
#include <Interpreters/Quota.h>
#include <Interpreters/InterpreterFactory.h>
#include <Interpreters/ProcessList.h>
@ -199,6 +200,14 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
logQuery(queryToString(*ast), context);
}
if (settings.allow_experimental_cross_to_join_conversion)
{
CrossToInnerJoinVisitor::Data cross_to_inner;
CrossToInnerJoinVisitor(cross_to_inner).visit(ast);
if (cross_to_inner.done)
logQuery(queryToString(*ast), context);
}
/// Check the limits.
checkASTSizeLimits(*ast, settings);

View File

@ -59,7 +59,7 @@ const char * ASTSystemQuery::typeToString(Type type)
return "START FETCHES";
case Type::STOP_REPLICATED_SENDS:
return "STOP REPLICATED SENDS";
case Type::START_REPLICATEDS_SENDS:
case Type::START_REPLICATED_SENDS:
return "START REPLICATED SENDS";
case Type::STOP_REPLICATION_QUEUES:
return "STOP REPLICATION QUEUES";
@ -97,7 +97,7 @@ void ASTSystemQuery::formatImpl(const FormatSettings & settings, FormatState &,
|| type == Type::STOP_FETCHES
|| type == Type::START_FETCHES
|| type == Type::STOP_REPLICATED_SENDS
|| type == Type::START_REPLICATEDS_SENDS
|| type == Type::START_REPLICATED_SENDS
|| type == Type::STOP_REPLICATION_QUEUES
|| type == Type::START_REPLICATION_QUEUES)
{

View File

@ -36,7 +36,7 @@ public:
STOP_FETCHES,
START_FETCHES,
STOP_REPLICATED_SENDS,
START_REPLICATEDS_SENDS,
START_REPLICATED_SENDS,
STOP_REPLICATION_QUEUES,
START_REPLICATION_QUEUES,
FLUSH_LOGS,

View File

@ -58,7 +58,7 @@ bool ParserSystemQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected &
case Type::STOP_FETCHES:
case Type::START_FETCHES:
case Type::STOP_REPLICATED_SENDS:
case Type::START_REPLICATEDS_SENDS:
case Type::START_REPLICATED_SENDS:
case Type::STOP_REPLICATION_QUEUES:
case Type::START_REPLICATION_QUEUES:
parseDatabaseAndTableName(pos, expected, res->target_database, res->target_table);

View File

@ -128,7 +128,7 @@ else
TEST_DICT=${TEST_DICT=1}
CLICKHOUSE_CLIENT_QUERY="${CLICKHOUSE_CLIENT} --config ${CLICKHOUSE_CONFIG_CLIENT} --port $CLICKHOUSE_PORT_TCP -m -n -q"
$CLICKHOUSE_CLIENT_QUERY 'SELECT * from system.build_options; SELECT * FROM system.clusters;'
CLICKHOUSE_TEST="env PATH=$PATH:$BIN_DIR ${TEST_DIR}clickhouse-test --binary ${BIN_DIR}${CLICKHOUSE_BINARY} --configclient $CLICKHOUSE_CONFIG_CLIENT --configserver $CLICKHOUSE_CONFIG --tmp $DATA_DIR/tmp --queries $QUERIES_DIR $TEST_OPT0 $TEST_OPT"
CLICKHOUSE_TEST="env ${TEST_DIR}clickhouse-test --binary ${BIN_DIR}${CLICKHOUSE_BINARY} --configclient $CLICKHOUSE_CONFIG_CLIENT --configserver $CLICKHOUSE_CONFIG --tmp $DATA_DIR/tmp --queries $QUERIES_DIR $TEST_OPT0 $TEST_OPT"
CLICKHOUSE_PERFORMANCE_TEST="${BIN_DIR}clickhouse-performance-test --port $CLICKHOUSE_PORT_TCP --recursive $CUR_DIR/performance --skip-tags=long"
if [ "${TEST_RUN_STRESS}" ]; then
# Running test in parallel will fail some results (tests can create/fill/drop same tables)

View File

@ -228,6 +228,8 @@ sudo -u clickhouse ClickHouse/build/dbms/programs/clickhouse server --config-fil
Разработка тестов: https://clickhouse.yandex/docs/ru/development/tests/
Список задач: https://github.com/yandex/ClickHouse/blob/master/dbms/tests/instructions/easy_tasks_sorted_ru.md
# Тестовые данные

View File

@ -0,0 +1,342 @@
# Простые задачи
## Пустой параметр --password в клиенте должен быть эквивалентен --ask-password.
То есть означать предложение ввести пароль в интерактивном режиме.
`dbms/programs/client/ConnectionParameters.h`
\* кстати, сейчас функциональность реализована плохо: ввод пароля не поддерживает корректную обработку backspace.
## Недостатки юзабилити: у clickhouse-client отсутствует сокращённая опция -C, как вариант --config-file; Недостатки юзабилити, если пользователь не может прочитать конфиг клиента.
`dbms/programs/client/Client.cpp`
Также делаем `chmod 000 /etc/clickhouse-client/config.xml` и смотрим, что получится.
## Оператор NOT BETWEEN.
`SELECT * FROM system.numbers WHERE number NOT BETWEEN 5 AND 10 LIMIT 10`
`ExpressionListParsers.cpp`: `ParserBetweenExpression::parseImpl`
## HTTP заголовок query_id.
`programs/server/HTTPHandler.cpp` - смотрим метод `executeQuery`
`src/Interpreters/executeQuery.h`
`src/Interpreters/executeQuery.cpp` - смотрим колбэк на выставление Content-Type
## Уменьшать max_memory_usage и размеры кэшей при старте, если на сервере мало оперативки.
Смотрим, сколько на сервере оперативки. Если `max_memory_usage`, `max_memory_usage_for_all_queries` ограничены, но больше 90% (настройка) от имеющейся оперативки, то уменьшать их и выводить предупреждение в лог. Аналогично для кэшей: `mark_cache`, `uncompressed_cache`.
`programs/server/Server.cpp` - инициализация сервера, установка размера кэшей
`getMemoryAmount.h` - информация о доступной оперативке
`context.setSetting` - для выставления `max_memory_usage` и других.
## Битовые операции для FixedString.
bitAnd, bitOr, bitNot, bitXor для значения типа FixedString, интерпретируемого как набор бит.
Сделайте сначала в C++ побитовые функции для работы с куском памяти:
```
void memoryBitAnd(const char * a, const char * b, char * result, size_t size);
```
Потом используйте их в вашей функции.
## Функция arrayWithConstant.
`arrayWithConstant(3, 'hello') = ['hello', 'hello', 'hello']`
Смотрите метод `IColumn::replicate` для размножения значений столбца.
## Функция flatten для превращения массивов массивов в массив элементов.
`flatten([[1, 2, 3], [4, 5]]) = [1, 2, 3, 4, 5]`
`ColumnArray` - внимательно изучаем, как устроены массивы в ClickHouse.
## Добавить generic вариант функций least, greatest.
`SELECT least(123, 456)` - работает.
`SELECT least('123', '456')` - не работает. Надо сделать.
Делаем с помощью `IColumn::compareAt` для одинаковых типов и с помощью `castColumn`, `getLeastSuperType` для разных.
## При ATTACH кусков, проверять владельца файлов.
Смотрим, что все файлы в прикрепляемых кусках от правильного пользователя.
## COLLATE должно работать для Nullable(String).
В ClickHouse есть возможность указать collation для сортировки строк. Это не работает для `Nullable(String)`.
## Проверить возможность использования pdqsort вместо std::sort для полной comparison-based сортировки.
В случае, когда есть ORDER BY без LIMIT, это может позволить слегка увеличить производительность.
## Запретить чтение значений типа AggregateFunction по-умолчанию и добавить настройку.
Состояния агрегатных функций могут быть записаны в дамп и считаны из него. Но десериализация состояний агрегатных функций небезопасна. Аккуратно выбранные пользовательские данные могут привести к segfault или порче памяти. Поэтому нужно просто сделать настройку, которая запрещает читать AggregateFunction из пользовательских данных.
## Опции progress и time для clickhouse-local (по аналогии с clickhouse-client).
Возможность выводить время выполнения запроса, а также красивый прогресс-бар для каждого запроса.
## Usability: clickhouse-server должен поддерживать --help.
## В статистику jemalloc добавить информацию по arenas.
В `system.asynchronous_metrics` - суммарный размер арен.
## Добавить агрегатную функцию topKWeighted.
`SELECT topKWeighted(value, weight)` - учитывать каждое значение с весом.
## Функция isValidUTF8, toValidUTF8.
`isValidUTF8` возвращает 1, если строка содержит набор байт в кодировке UTF-8.
`toValidUTF8` - заменяет последовательности байт, не соответствующие кодировке UTF-8, на replacement character.
# Более сложные задачи
## CREATE TABLE AS table_function()
Возможность создать таблицу с таким же типом и структурой, как табличная функция.
`ParserCreateQuery.cpp`, `InterpreterCreateQuery`, `Context::executeTableFunction`
## Layout внешних словарей "direct".
Как cache, но без кэша — всегда прямой запрос в источник.
## Подсказки в фабриках на основе edit distance.
Всевозможные объекты: функции, агрегатные функции, типы данных, движки таблиц, и т. п. достаются по имени из фабрик. Часто пользователь допускает опечатку. Например, вместо `SELECT count(*)` может быть написано `SELECT cunt(*)`. В случае опечатки, необходимо в текст сообщения добавлять указание на ближайшие варианты. Для реализации можно использовать расстояние Левенштейна и полный перебор, или (лучше) - триграмный индекс. Подсказки выдаём, если указанное имя отличается от существующего на 1..2 буквы. Сортируем возможные варианты в порядке похожести. Для того, чтобы это работало во всех фабриках, может быть, потребуется обобщить их.
## Учитывать порядок столбцов в заголовке в форматах CSV и TSV.
В заголовке CSV, TSV могут быть указаны имена столбцов. Сейчас они полностью игнорируются. Надо учитывать, под настройкой.
## Функции randomFixedString, randomBinaryString, fuzzBits, fuzzBytes.
## Функции для geoHash.
Geohash - способ преобразования географических координат в строку, так что отображение обладает свойством локальности. https://en.wikipedia.org/wiki/Geohash В качестве библиотеки следует использовать эту: https://github.com/yinqiwen/geohash-int Необходимо добавить функции для перевода в обе стороны, а также для числового и текстового вариантов.
## Агрегатные функции для статистических тестов (e.g. тест нормальности распределения) и статистик (e.g. энтропия).
Энтропию следует считать по гистограмме. Пример расчёта гистограммы смотрите в реализации функции `quantileExact`.
https://github.com/yandex/ClickHouse/issues/3266
## Функции создания и обновления состояния агрегатной функции по одному кортежу аргументов.
В ClickHouse есть понятие - состояние вычисления агрегатной функции. Состояния агрегатных функций можно записывать в таблицы, складывать, финализировать и т. п. https://clickhouse.yandex/docs/ru/data_types/nested_data_structures/aggregatefunction/
Получить состояние агрегатной функции можно с помощью комбинатора State: https://clickhouse.yandex/docs/ru/query_language/agg_functions/combinators/#-state Но хотелось бы добавить ещё более простой способ получения состояния агрегатной функции.
Например:
`createAggregationState('groupArray')` - создать пустое (начальное) состояние агрегатной функции.
`createAggregationState('groupArray', 1)` - создать состояние агрегатной функции, в котором агрегировано одно значение 1.
`createAggregationState('argMax', ('hello', 123))` - то же самое для агрегатных функций, принимающих несколько аргументов.
## Корректное сравнение Date и DateTime.
https://github.com/yandex/ClickHouse/issues/2011
Нужно сравнивать Date и DateTime так, как будто Date расширено до DateTime на начало суток в том же часовом поясе.
## LEFT ONLY JOIN
## Функции makeDate, makeDateTime.
`makeDate(year, month, day)`
`makeDateTime(year, month, day, hour, minute, second, [timezone])`
## Функции changeYear, changeMonth, ...
`changeYear(datetime, 2019)`
## Исправить мерцание прогресс-бара в clickhouse-client.
Это заметно при работе с серверами с большим пингом.
Прогресс бар не должен мерцать.
Наверное, надо просто вместо очистки строки, перемещать курсор в начало, не очищая её.
## Функция format для вставки значений в строку-шаблон.
`format('Hello {2} World {1}', x, y)`
## Добавить поддержку hyperscan.
https://github.com/intel/hyperscan
Реализовать на основе этой библиотеки функцию для матчинга сразу большого количества регулярных выражений.
## Функция rowNumberForKey.
Возвращает инкрементальное число для повторно встречающихся значений key.
## Агрегатная функция groupConcat.
`groupConcat(x, ',')` - собрать из переданных значений x строку, разделённую запятыми.
## Функции DATE_ADD, DATE_SUB как синонимы для совместимости с SQL.
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add
## Функции positionReverse, positionUTF8Reverse, positionCaseInsensitiveReverse, positionCaseInsensitiveUTF8Reverse.
position с конца строки.
## Функция indexOf должна поддерживать Enum-ы без cast-а.
`indexOf(arr, 'hello')`, `indexOf(arr, 1)` должны работать, если arr имеет тип `Array(Enum8('hello' = 1, 'world' = 2))`
## Комбинатор агрегатных функций Distinct.
Пример: `avgDistinct(x)` - вычислить среднее по всем различным переданным значениям.
## Проверка набора инструкций при старте сервера.
Если сервер собран с поддержкой SSE 4.2, 4.1, 4, SSSE 3, SSE 3, то как можно ближе к началу работы, запускаем функцию, которая выполняет нужную инструкцию в качестве теста (asm volatile вставка), а до этого ставим обработчик сигнала SIGILL, который в случае невозможности выполнить инструкцию, сделает siglongjmp, позволит нам вывести понятное сообщение в лог и завершить работу. Замечание: /proc/cpuinfo зачастую не содержит актуальную информацию.
## Добавить сжатие Brotli для HTTP интерфейса.
`Content-Encoding: br`
## Метрики количества ошибок.
Добавляем счётчики всех ошибок (ErrorCodes) по аналогии с ProfileEvents. Кроме количества запоминаем также время последней ошибки, стек трейс, сообщение. Добавляем системную таблицу system.errors. Отправка в Graphite.
## Добавить Lizard, LZSSE и density в качестве вариантов алгоритмов сжатия.
Экспериментальные алгоритмы сжатия. Сейчас ClickHouse поддерживает только lz4 и zstd.
## Запрос CREATE OR REPLACE TABLE/VIEW.
Атомарно (под блокировкой) удаляет таблицу перед созданием новой, если такая была.
## Приведение типов для IN (subquery).
`SELECT 1 IN (SELECT -1 UNION ALL SELECT 1)`
- сейчас не работает.
## Возможность задать смещение для LIMIT BY.
https://clickhouse.yandex/docs/ru/query_language/select/#limit-n-by
`LIMIT 100, 10 BY RegionID` - выдать не более 10 строк для каждого RegionID, но пропустив первые 100 строк.
## Возможность вставки значений типа AggregateFunction в виде кортежа значений аргументов, а не бинарного дампа состояния, под настройкой.
Во входных данных в запросе INSERT должна быть возможность передать значение типа AggregateFunction не в виде сериализованного состояния, а в виде аргументов, которые будут агрегированы, для формирования этого состояния.
## Возможность использовать ALIAS столбцы при INSERT.
https://clickhouse.yandex/docs/en/query_language/create/#create-table
`INSERT INTO table (column1, column2, ...)`
- если column - это ALIAS столбец, и если выражение для ALIAS тривиально (просто ссылается на другой столбец), то разрешить использовать его вместо другого столбца в запросе INSERT.
## Запрос ALTER TABLE LOCK/UNLOCK PARTITION.
Запретить модификацию данных в партиции. На партицию ставится флаг, что она заблокирована. В неё нельзя делать INSERT и ALTER. С файлов снимается доступ на запись.
## Поддержка произвольных константных выражений в LIMIT.
Возможность писать `LIMIT 1 + 2`. То же самое для `LIMIT BY`.
## Добавить информацию об exp-smoothed количестве ошибок соединений с репликами в таблицу system.clusters.
У нас есть счётчик ошибок соединения с серверами для failover. Надо сделать его видимым для пользователя.
## Настройка join_use_nulls: поддержка для LEFT ARRAY JOIN.
## Внешние словари из Redis/Aerospike/Couchbase/Cassandra (на выбор).
Подключить одну из key-value БД как источник.
## Движок таблиц Mongo, табличная функция mongo.
Возможность легко импортировать данные из MongoDB.
## Возможность использования нескольких потоков для INSERT при INSERT SELECT.
При INSERT SELECT, запрос SELECT может выполняться параллельно, но все данные будут передаваться на вставку в INSERT в один поток. Хотя некоторые таблицы (семейства MergeTree) поддерживают параллельную вставку. Необходимо сделать настройку для максимального количества потоков для INSERT.
## Корректная обработка multiline значений в Pretty форматах.
SELECT 'hello\nworld' AS x, 123 AS y
```
┌─x──────────┬───y─┐
│ hello
world │ 123 │
└────────────┴─────┘
```
А надо так:
```
┌─x─────┬───y─┐
│ hello…│ 123 │
│…world │ │
└───────┴─────┘
```
## Писать логи ClickHouse в ClickHouse.
Пишем текстовые логи ClickHouse в системную таблицу в структурированном виде.
См. SystemLog.h, cpp.
## Работоспособность внешних данных на время сессии.
https://clickhouse.yandex/docs/en/operations/table_engines/external_data/
Не работает, если открыть clickhouse-client в интерактивном режиме и делать несколько запросов.
## Настройка для возможности получить частичный результат при cancel-е.
Хотим по Ctrl+C получить те данные, которые успели обработаться.
## Раскрытие кортежей в функциях высшего порядка.
## Табличная функция loop.
`SELECT * FROM loop(database, table)`
Читает данные из таблицы в бесконечном цикле.
## Настройка, позволяющая обратиться ко всем репликам кластера, как к разным шардам.
## Возможность ATTACH партиции с меньшим или большим количеством столбцов.
## Поддержка неконстантного аргумента с тайм-зоной у некоторых функций для работы с датой и временем.
## Возможность задавать параметры соединений для табличных функций, движков таблиц и для реплик из отдельных разделов конфигурации.
## Настройка rollup_use_nulls.
## Настройка cast_keep_nullable.
## Функция bitEquals для сравнения произвольных типов данных побитово.
## Функция serialize для implementation specific non portable non backwards compatible сериализации любого типа данных в набор байт.
## Функция arrayEnumerateUniqDeep
Как arrayEnumerateUniq, но смотрит на самые глубокие элементы вложенных массивов.
## Функция bitEquals и оператор <=>.
## Параллельный ALTER MODIFY COLUMN.

View File

@ -2,9 +2,10 @@
<name>trim_whitespaces</name>
<type>loop</type>
<preconditions>
<table_exists>whitespaces</table_exists>
</preconditions>
<create_query>CREATE TABLE IF NOT EXISTS whitespaces(value String) ENGINE = MergeTree() PARTITION BY tuple() ORDER BY tuple()</create_query>
<fill_query> INSERT INTO whitespaces SELECT value FROM (SELECT arrayStringConcat(groupArray(' ')) AS spaces, concat(spaces, toString(any(number)), spaces) AS value FROM numbers(100000000) GROUP BY pow(number, intHash32(number) % 4) % 12345678)</fill_query>
<fill_query> INSERT INTO whitespaces SELECT value FROM (SELECT arrayStringConcat(groupArray(' ')) AS spaces, concat(spaces, toString(any(number)), spaces) AS value FROM numbers(100000000) GROUP BY pow(number, intHash32(number) % 4) % 12345678)</fill_query>
<fill_query> INSERT INTO whitespaces SELECT value FROM (SELECT arrayStringConcat(groupArray(' ')) AS spaces, concat(spaces, toString(any(number)), spaces) AS value FROM numbers(100000000) GROUP BY pow(number, intHash32(number) % 4) % 12345678)</fill_query>
<stop_conditions>
<all_of>
@ -32,4 +33,6 @@
</substitutions>
<query>SELECT count() FROM whitespaces WHERE NOT ignore({func})</query>
<drop_query>DROP TABLE IF EXISTS whitespaces</drop_query>
</test>

View File

@ -1,17 +0,0 @@
CREATE TABLE whitespaces
(
value String
)
ENGINE = MergeTree()
PARTITION BY tuple()
ORDER BY tuple()
INSERT INTO whitespaces SELECT value
FROM
(
SELECT
arrayStringConcat(groupArray(' ')) AS spaces,
concat(spaces, toString(any(number)), spaces) AS value
FROM numbers(100000000)
GROUP BY pow(number, intHash32(number) % 4) % 12345678
) -- repeat something like this multiple times and/or just copy whitespaces table into itself

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,23 @@
cross
1 1 1 1
2 2 2 \N
cross nullable
1 1 1 1
cross nullable vs not nullable
1 1 1 1
Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n
Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n
Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n TableExpression (children 1)\n Identifier t2\n
Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n TableExpression (children 1)\n Identifier t2\n
cross
1 1 1 1
2 2 2 \N
cross nullable
1 1 1 1
cross nullable vs not nullable
1 1 1 1
comma
1 1 1 1
2 2 2 \N
comma nullable
1 1 1 1

View File

@ -0,0 +1,42 @@
USE test;
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1 (a Int8, b Nullable(Int8)) ENGINE = Memory;
CREATE TABLE t2 (a Int8, b Nullable(Int8)) ENGINE = Memory;
INSERT INTO t1 values (1,1), (2,2);
INSERT INTO t2 values (1,1);
INSERT INTO t2 (a) values (2), (3);
SELECT 'cross';
SELECT * FROM t1 cross join t2 where t1.a = t2.a;
SELECT 'cross nullable';
SELECT * FROM t1 cross join t2 where t1.b = t2.b;
SELECT 'cross nullable vs not nullable';
SELECT * FROM t1 cross join t2 where t1.a = t2.b;
SET enable_debug_queries = 1;
AST SELECT * FROM t1 cross join t2 where t1.a = t2.a;
AST SELECT * FROM t1, t2 where t1.a = t2.a;
SET allow_experimental_cross_to_join_conversion = 1;
AST SELECT * FROM t1 cross join t2 where t1.a = t2.a;
AST SELECT * FROM t1, t2 where t1.a = t2.a;
SELECT 'cross';
SELECT * FROM t1 cross join t2 where t1.a = t2.a;
SELECT 'cross nullable';
SELECT * FROM t1 cross join t2 where t1.b = t2.b;
SELECT 'cross nullable vs not nullable';
SELECT * FROM t1 cross join t2 where t1.a = t2.b;
SELECT 'comma';
SELECT * FROM t1, t2 where t1.a = t2.a;
SELECT 'comma nullable';
SELECT * FROM t1, t2 where t1.b = t2.b;
DROP TABLE t1;
DROP TABLE t2;

View File

@ -32,6 +32,7 @@
- [Prometheus](https://prometheus.io/)
- [clickhouse_exporter](https://github.com/f1yegor/clickhouse_exporter)
- [PromHouse](https://github.com/Percona-Lab/PromHouse)
- [clickhouse_exporter](https://github.com/hot-wifi/clickhouse_exporter) (uses [Go client](https://github.com/kshvakov/clickhouse/))
- [Nagios](https://www.nagios.org/)
- [check_clickhouse](https://github.com/exogroup/check_clickhouse/)
- Logging

View File

@ -31,6 +31,7 @@
- [Prometheus](https://prometheus.io/)
- [clickhouse_exporter](https://github.com/f1yegor/clickhouse_exporter)
- [PromHouse](https://github.com/Percona-Lab/PromHouse)
- [clickhouse_exporter](https://github.com/hot-wifi/clickhouse_exporter) (использует [Go client](https://github.com/kshvakov/clickhouse/))
- [Nagios](https://www.nagios.org/)
- [check_clickhouse](https://github.com/exogroup/check_clickhouse/)
- Логирование

View File

@ -19,7 +19,7 @@ add_library (common ${LINK_MODE}
src/JSON.cpp
src/getMemoryAmount.cpp
src/demangle.cpp
src/SetTerminalEcho.cpp
src/setTerminalEcho.cpp
include/common/Types.h
include/common/DayNum.h
@ -37,7 +37,7 @@ add_library (common ${LINK_MODE}
include/common/JSON.h
include/common/getMemoryAmount.h
include/common/demangle.h
include/common/SetTerminalEcho.h
include/common/setTerminalEcho.h
include/common/find_symbols.h
include/common/constexpr_helpers.h

View File

@ -1,4 +1,4 @@
#pragma once
/// Enable or disable echoing of typed characters. Throws std::runtime_error on error.
void SetTerminalEcho(bool enable);
void setTerminalEcho(bool enable);

View File

@ -1,6 +1,6 @@
// https://stackoverflow.com/questions/1413445/reading-a-password-from-stdcin
#include <common/SetTerminalEcho.h>
#include <common/setTerminalEcho.h>
#include <stdexcept>
#include <cstring>
#include <string>
@ -13,13 +13,13 @@
#include <errno.h>
#endif
void SetTerminalEcho(bool enable)
void setTerminalEcho(bool enable)
{
#ifdef WIN32
auto handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;
if (!GetConsoleMode(handle, &mode))
throw std::runtime_error(std::string("SetTerminalEcho failed get: ") + std::to_string(GetLastError()));
throw std::runtime_error(std::string("setTerminalEcho failed get: ") + std::to_string(GetLastError()));
if (!enable)
mode &= ~ENABLE_ECHO_INPUT;
@ -27,11 +27,11 @@ void SetTerminalEcho(bool enable)
mode |= ENABLE_ECHO_INPUT;
if (!SetConsoleMode(handle, mode))
throw std::runtime_error(std::string("SetTerminalEcho failed set: ") + std::to_string(GetLastError()));
throw std::runtime_error(std::string("setTerminalEcho failed set: ") + std::to_string(GetLastError()));
#else
struct termios tty;
if (tcgetattr(STDIN_FILENO, &tty))
throw std::runtime_error(std::string("SetTerminalEcho failed get: ") + strerror(errno));
throw std::runtime_error(std::string("setTerminalEcho failed get: ") + strerror(errno));
if (!enable)
tty.c_lflag &= ~ECHO;
else
@ -39,6 +39,6 @@ void SetTerminalEcho(bool enable)
auto ret = tcsetattr(STDIN_FILENO, TCSANOW, &tty);
if (ret)
throw std::runtime_error(std::string("SetTerminalEcho failed set: ") + strerror(errno));
throw std::runtime_error(std::string("setTerminalEcho failed set: ") + strerror(errno));
#endif
}