未验证 提交 b4c2c490 编写于 作者: A alexey-milovidov 提交者: GitHub

Merge pull request #11873 from ClickHouse/initial-explain

Initial explain
#include <Core/SortDescription.h>
#include <Core/Block.h>
#include <IO/Operators.h>
namespace DB
{
void dumpSortDescription(const SortDescription & description, const Block & header, WriteBuffer & out)
{
bool first = true;
for (const auto & desc : description)
{
if (!first)
out << ", ";
first = false;
if (!desc.column_name.empty())
out << desc.column_name;
else
{
if (desc.column_number < header.columns())
out << header.getByPosition(desc.column_number).name;
else
out << "?";
out << " (pos " << desc.column_number << ")";
}
if (desc.direction > 0)
out << " ASC";
else
out << " DESC";
if (desc.with_fill)
out << " WITH FILL";
}
}
}
......@@ -71,4 +71,9 @@ struct SortColumnDescription
/// Description of the sorting rule for several columns.
using SortDescription = std::vector<SortColumnDescription>;
class Block;
/// Outputs user-readable description into `out`.
void dumpSortDescription(const SortDescription & description, const Block & header, WriteBuffer & out);
}
......@@ -20,6 +20,7 @@ SRCS(
NamesAndTypes.cpp
Settings.cpp
SettingsCollection.cpp
SortDescription.cpp
)
END()
#include <Interpreters/AggregateDescription.h>
#include <Common/FieldVisitors.h>
#include <IO/Operators.h>
namespace DB
{
void AggregateDescription::explain(WriteBuffer & out, size_t indent) const
{
String prefix(indent, ' ');
out << prefix << column_name << '\n';
auto dump_params = [&](const Array & arr)
{
bool first = true;
for (const auto & param : arr)
{
if (!first)
out << ", ";
first = false;
out << applyVisitor(FieldVisitorToString(), param);
}
};
if (function)
{
/// Double whitespace is intentional.
out << prefix << " Function: " << function->getName();
const auto & params = function->getParameters();
if (!params.empty())
{
out << "(";
dump_params(params);
out << ")";
}
out << "(";
bool first = true;
for (const auto & type : function->getArgumentTypes())
{
if (!first)
out << ", ";
first = false;
out << type->getName();
}
out << ") → " << function->getReturnType()->getName() << "\n";
}
else
out << prefix << " Function: nullptr\n";
if (!parameters.empty())
{
out << prefix << " Parameters: ";
dump_params(parameters);
out << '\n';
}
out << prefix << " Arguments: ";
if (argument_names.empty())
out << "none\n";
else
{
bool first = true;
for (const auto & arg : argument_names)
{
if (!first)
out << ", ";
first = false;
out << arg;
}
out << "\n";
}
out << prefix << " Argument positions: ";
if (arguments.empty())
out << "none\n";
else
{
bool first = true;
for (auto arg : arguments)
{
if (!first)
out << ", ";
first = false;
out << arg;
}
out << '\n';
}
}
}
......@@ -15,6 +15,8 @@ struct AggregateDescription
ColumnNumbers arguments;
Names argument_names; /// used if no `arguments` are specified.
String column_name; /// What name to use for a column with aggregate function values
void explain(WriteBuffer & out, size_t indent) const; /// Get description for EXPLAIN query.
};
using AggregateDescriptions = std::vector<AggregateDescription>;
......
......@@ -30,6 +30,7 @@
#include <AggregateFunctions/AggregateFunctionState.h>
#include <AggregateFunctions/AggregateFunctionResample.h>
#include <Disks/StoragePolicy.h>
#include <IO/Operators.h>
namespace ProfileEvents
......@@ -151,6 +152,42 @@ Block Aggregator::Params::getHeader(
return materializeBlock(res);
}
void Aggregator::Params::explain(WriteBuffer & out, size_t indent) const
{
Strings res;
const auto & header = src_header ? src_header
: intermediate_header;
String prefix(indent, ' ');
{
/// Dump keys.
out << prefix << "Keys: ";
bool first = true;
for (auto key : keys)
{
if (!first)
out << ", ";
first = false;
if (key >= header.columns())
out << "unknown position " << key;
else
out << header.getByPosition(key).name;
}
out << '\n';
}
if (!aggregates.empty())
{
out << prefix << "Aggregates:\n";
for (const auto & aggregate : aggregates)
aggregate.explain(out, indent + 4);
}
}
Aggregator::Aggregator(const Params & params_)
: params(params_),
......
......@@ -923,6 +923,9 @@ public:
{
return getHeader(src_header, intermediate_header, keys, aggregates, final);
}
/// Returns keys and aggregated for EXPLAIN query
void explain(WriteBuffer & out, size_t indent) const;
};
Aggregator(const Params & params_);
......
......@@ -10,16 +10,25 @@
#include <Parsers/DumpASTNode.h>
#include <Parsers/queryToString.h>
#include <Parsers/ASTExplainQuery.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ASTSelectQuery.h>
#include <IO/WriteBufferFromOStream.h>
#include <Storages/StorageView.h>
#include <sstream>
#include <Processors/QueryPlan/QueryPlan.h>
#include <Processors/printPipeline.h>
namespace DB
{
namespace ErrorCodes
{
extern const int INCORRECT_QUERY;
extern const int INVALID_SETTING_VALUE;
extern const int UNKNOWN_SETTING;
extern const int LOGICAL_ERROR;
}
namespace
{
struct ExplainAnalyzedSyntaxMatcher
......@@ -79,10 +88,133 @@ Block InterpreterExplainQuery::getSampleBlock()
return block;
}
/// Split str by line feed and write as separate row to ColumnString.
static void fillColumn(IColumn & column, const std::string & str)
{
size_t start = 0;
size_t end = 0;
size_t size = str.size();
while (end < size)
{
if (str[end] == '\n')
{
column.insertData(str.data() + start, end - start);
start = end + 1;
}
++end;
}
if (start < end)
column.insertData(str.data() + start, end - start);
}
namespace
{
/// Settings. Different for each explain type.
struct QueryPlanSettings
{
QueryPlan::ExplainPlanOptions query_plan_options;
constexpr static char name[] = "PLAN";
std::unordered_map<std::string, std::reference_wrapper<bool>> boolean_settings =
{
{"header", query_plan_options.header},
{"description", query_plan_options.description},
{"actions", query_plan_options.actions}
};
};
struct QueryPipelineSettings
{
QueryPlan::ExplainPipelineOptions query_pipeline_options;
bool graph = false;
bool compact = true;
constexpr static char name[] = "PIPELINE";
std::unordered_map<std::string, std::reference_wrapper<bool>> boolean_settings =
{
{"header", query_pipeline_options.header},
{"graph", graph},
{"compact", compact},
};
};
template <typename Settings>
struct ExplainSettings : public Settings
{
using Settings::boolean_settings;
bool has(const std::string & name_) const
{
return boolean_settings.count(name_) > 0;
}
void setBooleanSetting(const std::string & name_, bool value)
{
auto it = boolean_settings.find(name_);
if (it == boolean_settings.end())
throw Exception("Unknown setting for ExplainSettings: " + name_, ErrorCodes::LOGICAL_ERROR);
it->second.get() = value;
}
std::string getSettingsList() const
{
std::string res;
for (const auto & setting : boolean_settings)
{
if (!res.empty())
res += ", ";
res += setting.first;
}
return res;
}
};
template <typename Settings>
ExplainSettings<Settings> checkAndGetSettings(const ASTPtr & ast_settings)
{
if (!ast_settings)
return {};
ExplainSettings<Settings> settings;
const auto & set_query = ast_settings->as<ASTSetQuery &>();
for (const auto & change : set_query.changes)
{
if (!settings.has(change.name))
throw Exception("Unknown setting \"" + change.name + "\" for EXPLAIN " + Settings::name + " query. "
"Supported settings: " + settings.getSettingsList(), ErrorCodes::UNKNOWN_SETTING);
if (change.value.getType() != Field::Types::UInt64)
throw Exception("Invalid type " + std::string(change.value.getTypeName()) + " for setting \"" + change.name +
"\" only boolean settings are supported", ErrorCodes::INVALID_SETTING_VALUE);
auto value = change.value.get<UInt64>();
if (value > 1)
throw Exception("Invalid value " + std::to_string(value) + " for setting \"" + change.name +
"\". Only boolean settings are supported", ErrorCodes::INVALID_SETTING_VALUE);
settings.setBooleanSetting(change.name, value);
}
return settings;
}
}
BlockInputStreamPtr InterpreterExplainQuery::executeImpl()
{
const auto & ast = query->as<ASTExplainQuery &>();
Block sample_block = getSampleBlock();
MutableColumns res_columns = sample_block.cloneEmptyColumns();
......@@ -90,17 +222,63 @@ BlockInputStreamPtr InterpreterExplainQuery::executeImpl()
if (ast.getKind() == ASTExplainQuery::ParsedAST)
{
dumpAST(ast, ss);
if (ast.getSettings())
throw Exception("Settings are not supported for EXPLAIN AST query.", ErrorCodes::UNKNOWN_SETTING);
dumpAST(*ast.getExplainedQuery(), ss);
}
else if (ast.getKind() == ASTExplainQuery::AnalyzedSyntax)
{
if (ast.getSettings())
throw Exception("Settings are not supported for EXPLAIN SYNTAX query.", ErrorCodes::UNKNOWN_SETTING);
ExplainAnalyzedSyntaxVisitor::Data data{.context = context};
ExplainAnalyzedSyntaxVisitor(data).visit(query);
ast.children.at(0)->format(IAST::FormatSettings(ss, false));
ast.getExplainedQuery()->format(IAST::FormatSettings(ss, false));
}
else if (ast.getKind() == ASTExplainQuery::QueryPlan)
{
if (!dynamic_cast<const ASTSelectWithUnionQuery *>(ast.getExplainedQuery().get()))
throw Exception("Only SELECT is supported for EXPLAIN query", ErrorCodes::INCORRECT_QUERY);
auto settings = checkAndGetSettings<QueryPlanSettings>(ast.getSettings());
QueryPlan plan;
InterpreterSelectWithUnionQuery interpreter(ast.getExplainedQuery(), context, SelectQueryOptions());
interpreter.buildQueryPlan(plan);
WriteBufferFromOStream buffer(ss);
plan.explainPlan(buffer, settings.query_plan_options);
}
else if (ast.getKind() == ASTExplainQuery::QueryPipeline)
{
if (!dynamic_cast<const ASTSelectWithUnionQuery *>(ast.getExplainedQuery().get()))
throw Exception("Only SELECT is supported for EXPLAIN query", ErrorCodes::INCORRECT_QUERY);
auto settings = checkAndGetSettings<QueryPipelineSettings>(ast.getSettings());
QueryPlan plan;
InterpreterSelectWithUnionQuery interpreter(ast.getExplainedQuery(), context, SelectQueryOptions());
interpreter.buildQueryPlan(plan);
auto pipeline = plan.buildQueryPipeline();
WriteBufferFromOStream buffer(ss);
if (settings.graph)
{
if (settings.compact)
printPipelineCompact(pipeline->getProcessors(), buffer, settings.query_pipeline_options.header);
else
printPipeline(pipeline->getProcessors(), buffer);
}
else
{
plan.explainPipeline(buffer, settings.query_pipeline_options);
}
}
res_columns[0]->insert(ss.str());
fillColumn(*res_columns[0], ss.str());
return std::make_shared<OneBlockInputStream>(sample_block.cloneWithColumns(std::move(res_columns)));
}
......
......@@ -54,7 +54,7 @@
#include <Processors/QueryPlan/CubeStep.h>
#include <Processors/QueryPlan/FillingStep.h>
#include <Processors/QueryPlan/ExtremesStep.h>
#include <Processors/QueryPlan/OffsetsStep.h>
#include <Processors/QueryPlan/OffsetStep.h>
#include <Processors/QueryPlan/FinishSortingStep.h>
#include <Processors/QueryPlan/QueryPlan.h>
......@@ -962,7 +962,7 @@ void InterpreterSelectQuery::executeImpl(QueryPlan & query_plan, const BlockInpu
*/
if (!expressions.first_stage && !expressions.need_aggregate && !(query.group_by_with_totals && !aggregate_final))
executeMergeSorted(query_plan, "before ORDER BY");
executeMergeSorted(query_plan, "for ORDER BY");
else /// Otherwise, just sort.
executeOrder(query_plan, query_info.input_order_info);
}
......@@ -1589,7 +1589,7 @@ void InterpreterSelectQuery::executeOrder(QueryPlan & query_plan, InputOrderInfo
limit,
SizeLimits(settings.max_rows_to_sort, settings.max_bytes_to_sort, settings.sort_overflow_mode));
partial_sorting->setStepDescription("Sort each block before ORDER BY");
partial_sorting->setStepDescription("Sort each block for ORDER BY");
query_plan.addStep(std::move(partial_sorting));
/// Merge the sorted blocks.
......@@ -1600,11 +1600,11 @@ void InterpreterSelectQuery::executeOrder(QueryPlan & query_plan, InputOrderInfo
settings.max_bytes_before_external_sort, context->getTemporaryVolume(),
settings.min_free_disk_space_for_temporary_data);
merge_sorting_step->setStepDescription("Merge sorted blocks before ORDER BY");
merge_sorting_step->setStepDescription("Merge sorted blocks for ORDER BY");
query_plan.addStep(std::move(merge_sorting_step));
/// If there are several streams, we merge them into one
executeMergeSorted(query_plan, output_order_descr, limit, "before ORDER BY");
executeMergeSorted(query_plan, output_order_descr, limit, "for ORDER BY");
}
......@@ -1785,7 +1785,7 @@ void InterpreterSelectQuery::executeOffset(QueryPlan & query_plan)
UInt64 limit_offset;
std::tie(limit_length, limit_offset) = getLimitLengthAndOffset(query, *context);
auto offsets_step = std::make_unique<OffsetsStep>(query_plan.getCurrentDataStream(), limit_offset);
auto offsets_step = std::make_unique<OffsetStep>(query_plan.getCurrentDataStream(), limit_offset);
query_plan.addStep(std::move(offsets_step));
}
}
......
......@@ -18,6 +18,7 @@ SRCS(
ActionsVisitor.cpp
addMissingDefaults.cpp
addTypeConversionToAST.cpp
AggregateDescription.cpp
Aggregator.cpp
AnyInputOptimize.cpp
ArithmeticOperationsInAgrFuncOptimize.cpp
......
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/ASTQueryWithOutput.h>
namespace DB
......@@ -8,45 +8,78 @@ namespace DB
/// AST, EXPLAIN or other query with meaning of explanation query instead of execution
class ASTExplainQuery : public IAST
class ASTExplainQuery : public ASTQueryWithOutput
{
public:
enum ExplainKind
{
ParsedAST,
AnalyzedSyntax,
ParsedAST, /// 'EXPLAIN AST SELECT ...'
AnalyzedSyntax, /// 'EXPLAIN SYNTAX SELECT ...'
QueryPlan, /// 'EXPLAIN SELECT ...'
QueryPipeline, /// 'EXPLAIN PIPELINE ...'
};
ASTExplainQuery(ExplainKind kind_)
: kind(kind_)
{}
ASTExplainQuery(ExplainKind kind_, bool old_syntax_)
: kind(kind_), old_syntax(old_syntax_)
{
}
String getID(char delim) const override { return "Explain" + (delim + toString(kind)); }
String getID(char delim) const override { return "Explain" + (delim + toString(kind, old_syntax)); }
ExplainKind getKind() const { return kind; }
ASTPtr clone() const override
{
auto res = std::make_shared<ASTExplainQuery>(*this);
res->children.clear();
res->children.push_back(children[0]->clone());
cloneOutputOptions(*res);
return res;
}
void setExplainedQuery(ASTPtr query_)
{
children.emplace_back(query_);
query = std::move(query_);
}
void setSettings(ASTPtr settings_)
{
children.emplace_back(settings_);
ast_settings = std::move(settings_);
}
const ASTPtr & getExplainedQuery() const { return query; }
const ASTPtr & getSettings() const { return ast_settings; }
protected:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << toString(kind) << (settings.hilite ? hilite_none : "") << " ";
children.at(0)->formatImpl(settings, state, frame);
settings.ostr << (settings.hilite ? hilite_keyword : "") << toString(kind, old_syntax) << (settings.hilite ? hilite_none : "");
if (ast_settings)
{
settings.ostr << ' ';
ast_settings->formatImpl(settings, state, frame);
}
settings.ostr << settings.nl_or_ws;
query->formatImpl(settings, state, frame);
}
private:
ExplainKind kind;
bool old_syntax; /// "EXPLAIN AST" -> "AST", "EXPLAIN SYNTAX" -> "ANALYZE"
ASTPtr query;
ASTPtr ast_settings;
static String toString(ExplainKind kind)
static String toString(ExplainKind kind, bool old_syntax)
{
switch (kind)
{
case ParsedAST: return "AST";
case AnalyzedSyntax: return "ANALYZE";
case ParsedAST: return old_syntax ? "AST" : "EXPLAIN AST";
case AnalyzedSyntax: return old_syntax ? "ANALYZE" : "EXPLAIN SYNTAX";
case QueryPlan: return "EXPLAIN";
case QueryPipeline: return "EXPLAIN PIPELINE";
}
__builtin_unreachable();
......
#include <Parsers/ParserExplainQuery.h>
#include <Parsers/ASTExplainQuery.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ParserSelectWithUnionQuery.h>
#include <Parsers/ParserSetQuery.h>
namespace DB
{
bool ParserExplainQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
ASTExplainQuery::ExplainKind kind;
bool old_syntax = false;
ParserKeyword s_ast("AST");
ParserKeyword s_analyze("ANALYZE");
ParserKeyword s_explain("EXPLAIN");
ParserKeyword s_syntax("SYNTAX");
ParserKeyword s_pipeline("PIPELINE");
ParserKeyword s_plan("PLAN");
if (enable_debug_queries && s_ast.ignore(pos, expected))
{
old_syntax = true;
kind = ASTExplainQuery::ExplainKind::ParsedAST;
}
else if (enable_debug_queries && s_analyze.ignore(pos, expected))
{
old_syntax = true;
kind = ASTExplainQuery::ExplainKind::AnalyzedSyntax;
}
else if (s_explain.ignore(pos, expected))
{
kind = ASTExplainQuery::QueryPlan;
if (s_ast.ignore(pos, expected))
kind = ASTExplainQuery::ExplainKind::ParsedAST;
else if (s_syntax.ignore(pos, expected))
kind = ASTExplainQuery::ExplainKind::AnalyzedSyntax;
else if (s_pipeline.ignore(pos, expected))
kind = ASTExplainQuery::ExplainKind::QueryPipeline;
else if (s_plan.ignore(pos, expected))
kind = ASTExplainQuery::ExplainKind::QueryPlan;
}
else
return false;
auto explain_query = std::make_shared<ASTExplainQuery>(kind, old_syntax);
{
ASTPtr settings;
ParserSetQuery parser_settings(true);
auto begin = pos;
if (parser_settings.parse(pos, settings, expected))
explain_query->setSettings(std::move(settings));
else
pos = begin;
}
ParserSelectWithUnionQuery select_p;
ASTPtr query;
if (!select_p.parse(pos, query, expected))
return false;
explain_query->setExplainedQuery(std::move(query));
node = std::move(explain_query);
return true;
}
}
#pragma once
#include <Parsers/IParserBase.h>
namespace DB
{
class ParserExplainQuery : public IParserBase
{
public:
explicit ParserExplainQuery(bool enable_debug_queries_ = false)
: enable_debug_queries(enable_debug_queries_)
{
}
protected:
const char * getName() const override { return "EXPLAIN"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
private:
bool enable_debug_queries;
};
}
......@@ -19,6 +19,7 @@
#include <Parsers/ParserShowCreateAccessEntityQuery.h>
#include <Parsers/ParserShowGrantsQuery.h>
#include <Parsers/ParserShowPrivilegesQuery.h>
#include <Parsers/ParserExplainQuery.h>
namespace DB
......@@ -44,21 +45,13 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
ParserShowCreateAccessEntityQuery show_create_access_entity_p;
ParserShowGrantsQuery show_grants_p;
ParserShowPrivilegesQuery show_privileges_p;
ParserExplainQuery explain_p(enable_debug_queries);
ASTPtr query;
ParserKeyword s_ast("AST");
ParserKeyword s_analyze("ANALYZE");
bool explain_ast = false;
bool analyze_syntax = false;
if (enable_explain && s_ast.ignore(pos, expected))
explain_ast = true;
if (enable_explain && s_analyze.ignore(pos, expected))
analyze_syntax = true;
bool parsed = select_p.parse(pos, query, expected)
bool parsed =
explain_p.parse(pos, query, expected)
|| select_p.parse(pos, query, expected)
|| show_create_access_entity_p.parse(pos, query, expected) /// should be before `show_tables_p`
|| show_tables_p.parse(pos, query, expected)
|| table_p.parse(pos, query, expected)
......@@ -116,19 +109,17 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
query_with_output.children.push_back(query_with_output.settings_ast);
}
if (explain_ast)
{
node = std::make_shared<ASTExplainQuery>(ASTExplainQuery::ParsedAST);
node->children.push_back(query);
}
else if (analyze_syntax)
if (auto * ast = query->as<ASTExplainQuery>())
{
node = std::make_shared<ASTExplainQuery>(ASTExplainQuery::AnalyzedSyntax);
node->children.push_back(query);
/// Set default format TSV, because output is a single string column.
if (!ast->format)
{
ast->format = std::make_shared<ASTIdentifier>("TSV");
ast->children.push_back(ast->format);
}
}
else
node = query;
node = std::move(query);
return true;
}
......
......@@ -11,8 +11,9 @@ namespace DB
class ParserQueryWithOutput : public IParserBase
{
public:
ParserQueryWithOutput(bool enable_explain_ = false)
: enable_explain(enable_explain_)
/// enable_debug_queries flag enables queries 'AST SELECT' and 'ANALYZE SELECT'
explicit ParserQueryWithOutput(bool enable_debug_queries_ = false)
: enable_debug_queries(enable_debug_queries_)
{}
protected:
......@@ -21,7 +22,7 @@ protected:
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
private:
bool enable_explain;
bool enable_debug_queries;
};
}
......@@ -84,6 +84,7 @@ SRCS(
ParserDictionaryAttributeDeclaration.cpp
ParserDropAccessEntityQuery.cpp
ParserDropQuery.cpp
ParserExplainQuery.cpp
ParserGrantQuery.cpp
ParserInsertQuery.cpp
ParserKillQueryQuery.cpp
......
......@@ -15,6 +15,8 @@ namespace ErrorCodes
extern const int NOT_IMPLEMENTED;
}
class IQueryPlanStep;
class IProcessor;
using ProcessorPtr = std::shared_ptr<IProcessor>;
using Processors = std::vector<ProcessorPtr>;
......@@ -288,6 +290,16 @@ public:
void enableQuota() { has_quota = true; }
bool hasQuota() const { return has_quota; }
/// Step of QueryPlan from which processor was created.
void setQueryPlanStep(IQueryPlanStep * step, size_t group = 0)
{
query_plan_step = step;
query_plan_step_group = group;
}
IQueryPlanStep * getQueryPlanStep() const { return query_plan_step; }
size_t getQueryPlanStepGroup() const { return query_plan_step_group; }
protected:
virtual void onCancel() {}
......@@ -299,6 +311,9 @@ private:
size_t stream_number = NO_STREAM;
bool has_quota = false;
IQueryPlanStep * query_plan_step = nullptr;
size_t query_plan_step_group = 0;
};
......
......@@ -69,7 +69,8 @@ void QueryPipeline::init(Pipe pipe)
init(std::move(pipes));
}
static OutputPort * uniteExtremes(const std::vector<OutputPort *> & ports, const Block & header, Processors & processors)
static OutputPort * uniteExtremes(const std::vector<OutputPort *> & ports, const Block & header,
QueryPipeline::ProcessorsContainer & processors)
{
/// Here we calculate extremes for extremes in case we unite several pipelines.
/// Example: select number from numbers(2) union all select number from numbers(3)
......@@ -90,14 +91,15 @@ static OutputPort * uniteExtremes(const std::vector<OutputPort *> & ports, const
connect(resize->getOutputs().front(), extremes->getInputPort());
connect(extremes->getOutputPort(), sink->getPort());
processors.emplace_back(std::move(resize));
processors.emplace_back(std::move(extremes));
processors.emplace_back(std::move(sink));
processors.emplace(std::move(resize));
processors.emplace(std::move(extremes));
processors.emplace(std::move(sink));
return extremes_port;
}
static OutputPort * uniteTotals(const std::vector<OutputPort *> & ports, const Block & header, Processors & processors)
static OutputPort * uniteTotals(const std::vector<OutputPort *> & ports, const Block & header,
QueryPipeline::ProcessorsContainer & processors)
{
/// Calculate totals fro several streams.
/// Take totals from first sources which has any, skip others.
......@@ -115,8 +117,8 @@ static OutputPort * uniteTotals(const std::vector<OutputPort *> & ports, const B
connect(concat->getOutputs().front(), limit->getInputPort());
processors.emplace_back(std::move(concat));
processors.emplace_back(std::move(limit));
processors.emplace(std::move(concat));
processors.emplace(std::move(limit));
return totals_port;
}
......@@ -167,8 +169,7 @@ void QueryPipeline::init(Pipes pipes)
}
streams.addStream(&pipe.getPort(), pipe.maxParallelStreams());
auto cur_processors = std::move(pipe).detachProcessors();
processors.insert(processors.end(), cur_processors.begin(), cur_processors.end());
processors.emplace(std::move(pipe).detachProcessors());
}
if (!totals.empty())
......@@ -242,7 +243,7 @@ void QueryPipeline::addSimpleTransformImpl(const TProcessorGetter & getter)
{
connect(*stream, transform->getInputs().front());
stream = &transform->getOutputs().front();
processors.emplace_back(std::move(transform));
processors.emplace(std::move(transform));
}
};
......@@ -293,7 +294,7 @@ void QueryPipeline::setSinks(const ProcessorGetterWithStreamKind & getter)
transform = std::make_shared<NullSink>(stream->getHeader());
connect(*stream, transform->getInputs().front());
processors.emplace_back(std::move(transform));
processors.emplace(std::move(transform));
};
for (auto & stream : streams)
......@@ -339,7 +340,7 @@ void QueryPipeline::addPipe(Processors pipe)
header = output.getHeader();
}
processors.insert(processors.end(), pipe.begin(), pipe.end());
processors.emplace(pipe);
current_header = std::move(header);
}
......@@ -352,7 +353,7 @@ void QueryPipeline::addDelayedStream(ProcessorPtr source)
IProcessor::PortNumbers delayed_streams = { streams.size() };
streams.addStream(&source->getOutputs().front(), 0);
processors.emplace_back(std::move(source));
processors.emplace(std::move(source));
auto processor = std::make_shared<DelayedPortsProcessor>(current_header, streams.size(), delayed_streams);
addPipe({ std::move(processor) });
......@@ -383,7 +384,7 @@ void QueryPipeline::resize(size_t num_streams, bool force, bool strict)
for (auto & output : resize->getOutputs())
streams.addStream(&output, 0);
processors.emplace_back(std::move(resize));
processors.emplace(std::move(resize));
}
void QueryPipeline::enableQuotaForCurrentStreams()
......@@ -412,7 +413,7 @@ void QueryPipeline::addTotalsHavingTransform(ProcessorPtr transform)
streams.assign({ &outputs.front() });
totals_having_port = &outputs.back();
current_header = outputs.front().getHeader();
processors.emplace_back(std::move(transform));
processors.emplace(std::move(transform));
}
void QueryPipeline::addDefaultTotals()
......@@ -434,7 +435,7 @@ void QueryPipeline::addDefaultTotals()
auto source = std::make_shared<SourceFromSingleChunk>(current_header, Chunk(std::move(columns), 1));
totals_having_port = &source->getPort();
processors.emplace_back(source);
processors.emplace(std::move(source));
}
void QueryPipeline::addTotals(ProcessorPtr source)
......@@ -448,7 +449,7 @@ void QueryPipeline::addTotals(ProcessorPtr source)
assertBlocksHaveEqualStructure(current_header, source->getOutputs().front().getHeader(), "QueryPipeline");
totals_having_port = &source->getOutputs().front();
processors.emplace_back(std::move(source));
processors.emplace(std::move(source));
}
void QueryPipeline::dropTotalsAndExtremes()
......@@ -457,7 +458,7 @@ void QueryPipeline::dropTotalsAndExtremes()
{
auto null_sink = std::make_shared<NullSink>(port->getHeader());
connect(*port, null_sink->getPort());
processors.emplace_back(std::move(null_sink));
processors.emplace(std::move(null_sink));
port = nullptr;
};
......@@ -486,7 +487,7 @@ void QueryPipeline::addExtremesTransform()
stream = &transform->getOutputPort();
extremes.push_back(&transform->getExtremesPort());
processors.emplace_back(std::move(transform));
processors.emplace(std::move(transform));
}
if (extremes.size() == 1)
......@@ -510,8 +511,8 @@ void QueryPipeline::addCreatingSetsTransform(ProcessorPtr transform)
connect(*streams.back(), concat->getInputs().back());
streams.assign({ &concat->getOutputs().front() });
processors.emplace_back(std::move(transform));
processors.emplace_back(std::move(concat));
processors.emplace(std::move(transform));
processors.emplace(std::move(concat));
}
void QueryPipeline::setOutputFormat(ProcessorPtr output)
......@@ -538,17 +539,17 @@ void QueryPipeline::setOutputFormat(ProcessorPtr output)
{
auto null_source = std::make_shared<NullSource>(totals.getHeader());
totals_having_port = &null_source->getPort();
processors.emplace_back(std::move(null_source));
processors.emplace(std::move(null_source));
}
if (!extremes_port)
{
auto null_source = std::make_shared<NullSource>(extremes.getHeader());
extremes_port = &null_source->getPort();
processors.emplace_back(std::move(null_source));
processors.emplace(std::move(null_source));
}
processors.emplace_back(std::move(output));
processors.emplace(std::move(output));
connect(*streams.front(), main);
connect(*totals_having_port, totals);
......@@ -587,6 +588,7 @@ void QueryPipeline::unitePipelines(
{
auto & pipeline = *pipeline_ptr;
pipeline.checkInitialized();
pipeline.processors.setCollectedProcessors(processors.getCollectedProcessors());
if (!pipeline.isCompleted())
{
......@@ -604,7 +606,7 @@ void QueryPipeline::unitePipelines(
connect(*pipeline.extremes_port, converting->getInputPort());
extremes.push_back(&converting->getOutputPort());
processors.push_back(std::move(converting));
processors.emplace(std::move(converting));
}
/// Take totals only from first port.
......@@ -615,10 +617,13 @@ void QueryPipeline::unitePipelines(
connect(*pipeline.totals_having_port, converting->getInputPort());
totals.push_back(&converting->getOutputPort());
processors.push_back(std::move(converting));
processors.emplace(std::move(converting));
}
processors.insert(processors.end(), pipeline.processors.begin(), pipeline.processors.end());
auto * collector = processors.setCollectedProcessors(nullptr);
processors.emplace(pipeline.processors.detach());
processors.setCollectedProcessors(collector);
streams.addStreams(pipeline.streams);
table_locks.insert(table_locks.end(), std::make_move_iterator(pipeline.table_locks.begin()), std::make_move_iterator(pipeline.table_locks.end()));
......@@ -649,7 +654,7 @@ void QueryPipeline::unitePipelines(
void QueryPipeline::setProgressCallback(const ProgressCallback & callback)
{
for (auto & processor : processors)
for (auto & processor : processors.get())
{
if (auto * source = dynamic_cast<ISourceWithProgress *>(processor.get()))
source->setProgressCallback(callback);
......@@ -663,7 +668,7 @@ void QueryPipeline::setProcessListElement(QueryStatus * elem)
{
process_list_element = elem;
for (auto & processor : processors)
for (auto & processor : processors.get())
{
if (auto * source = dynamic_cast<ISourceWithProgress *>(processor.get()))
source->setProcessListElement(elem);
......@@ -775,7 +780,7 @@ Pipe QueryPipeline::getPipe() &&
Pipes QueryPipeline::getPipes() &&
{
Pipe pipe(std::move(processors), streams.at(0), totals_having_port, extremes_port);
Pipe pipe(processors.detach(), streams.at(0), totals_having_port, extremes_port);
pipe.max_parallel_streams = streams.maxParallelStreams();
for (auto & lock : table_locks)
......@@ -807,7 +812,7 @@ PipelineExecutorPtr QueryPipeline::execute()
if (!isCompleted())
throw Exception("Cannot execute pipeline because it is not completed.", ErrorCodes::LOGICAL_ERROR);
return std::make_shared<PipelineExecutor>(processors, process_list_element);
return std::make_shared<PipelineExecutor>(processors.get(), process_list_element);
}
QueryPipeline & QueryPipeline::operator= (QueryPipeline && rhs)
......@@ -837,4 +842,49 @@ QueryPipeline & QueryPipeline::operator= (QueryPipeline && rhs)
return *this;
}
void QueryPipeline::ProcessorsContainer::emplace(ProcessorPtr processor)
{
if (collected_processors)
collected_processors->emplace_back(processor);
processors.emplace_back(std::move(processor));
}
void QueryPipeline::ProcessorsContainer::emplace(Processors processors_)
{
for (auto & processor : processors_)
emplace(std::move(processor));
}
Processors * QueryPipeline::ProcessorsContainer::setCollectedProcessors(Processors * collected_processors_)
{
if (collected_processors && collected_processors_)
throw Exception("Cannot set collected processors to QueryPipeline because "
"another one object was already created for current pipeline." , ErrorCodes::LOGICAL_ERROR);
std::swap(collected_processors, collected_processors_);
return collected_processors_;
}
QueryPipelineProcessorsCollector::QueryPipelineProcessorsCollector(QueryPipeline & pipeline_, IQueryPlanStep * step_)
: pipeline(pipeline_), step(step_)
{
pipeline.processors.setCollectedProcessors(&processors);
}
QueryPipelineProcessorsCollector::~QueryPipelineProcessorsCollector()
{
pipeline.processors.setCollectedProcessors(nullptr);
}
Processors QueryPipelineProcessorsCollector::detachProcessors(size_t group)
{
for (auto & processor : processors)
processor->setQueryPlanStep(step, group);
Processors res;
res.swap(processors);
return res;
}
}
......@@ -18,6 +18,8 @@ class Context;
class IOutputFormat;
class QueryPipelineProcessorsCollector;
class QueryPipeline
{
private:
......@@ -69,6 +71,27 @@ private:
};
public:
class ProcessorsContainer
{
public:
bool empty() const { return processors.empty(); }
void emplace(ProcessorPtr processor);
void emplace(Processors processors_);
Processors * getCollectedProcessors() const { return collected_processors; }
Processors * setCollectedProcessors(Processors * collected_processors);
Processors & get() { return processors; }
const Processors & get() const { return processors; }
Processors detach() { return std::move(processors); }
private:
/// All added processors.
Processors processors;
/// If is set, all newly created processors will be added to this too.
/// It is needed for debug. See QueryPipelineProcessorsCollector below.
Processors * collected_processors = nullptr;
};
QueryPipeline() = default;
QueryPipeline(QueryPipeline &&) = default;
~QueryPipeline() = default;
......@@ -136,6 +159,8 @@ public:
void enableQuotaForCurrentStreams();
/// Unite several pipelines together. Result pipeline would have common_header structure.
/// If collector is used, it will collect only newly-added processors, but not processors from pipelines.
void unitePipelines(std::vector<std::unique_ptr<QueryPipeline>> pipelines, const Block & common_header);
PipelineExecutorPtr execute();
......@@ -180,6 +205,9 @@ public:
Pipe getPipe() &&;
Pipes getPipes() &&;
/// Get internal processors.
const Processors & getProcessors() const { return processors.get(); }
private:
/// Destruction order: processors, header, locks, temporary storages, local contexts
......@@ -193,8 +221,7 @@ private:
/// Common header for each stream.
Block current_header;
/// All added processors.
Processors processors;
ProcessorsContainer processors;
/// Port for each independent "stream".
Streams streams;
......@@ -222,6 +249,24 @@ private:
void addSimpleTransformImpl(const TProcessorGetter & getter);
void initRowsBeforeLimit();
friend class QueryPipelineProcessorsCollector;
};
/// This is a small class which collects newly added processors to QueryPipeline.
/// Pipeline must live longer that this class.
class QueryPipelineProcessorsCollector
{
public:
explicit QueryPipelineProcessorsCollector(QueryPipeline & pipeline_, IQueryPlanStep * step_ = nullptr);
~QueryPipelineProcessorsCollector();
Processors detachProcessors(size_t group = 0);
private:
QueryPipeline & pipeline;
IQueryPlanStep * step;
Processors processors;
};
}
......@@ -24,6 +24,7 @@ AddingDelayedSourceStep::AddingDelayedSourceStep(
void AddingDelayedSourceStep::transformPipeline(QueryPipeline & pipeline)
{
source->setQueryPlanStep(this);
pipeline.addDelayedStream(source);
}
......
......@@ -27,7 +27,7 @@ AggregatingStep::AggregatingStep(
bool storage_has_evenly_distributed_read_,
InputOrderInfoPtr group_by_info_,
SortDescription group_by_sort_description_)
: ITransformingStep(input_stream_, params_.getHeader(final_), getTraits())
: ITransformingStep(input_stream_, params_.getHeader(final_), getTraits(), false)
, params(std::move(params_))
, final(std::move(final_))
, max_block_size(max_block_size_)
......@@ -41,6 +41,8 @@ AggregatingStep::AggregatingStep(
void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
{
QueryPipelineProcessorsCollector collector(pipeline, this);
/// Forget about current totals and extremes. They will be calculated again after aggregation if needed.
pipeline.dropTotalsAndExtremes();
......@@ -76,6 +78,8 @@ void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
return std::make_shared<AggregatingInOrderTransform>(header, transform_params, group_by_sort_description, max_block_size, many_data, counter++);
});
aggregating_in_order = collector.detachProcessors(0);
for (auto & column_description : group_by_sort_description)
{
if (!column_description.column_name.empty())
......@@ -92,6 +96,7 @@ void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
max_block_size);
pipeline.addPipe({ std::move(transform) });
aggregating_sorted = collector.detachProcessors(1);
}
else
{
......@@ -99,6 +104,8 @@ void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
{
return std::make_shared<AggregatingInOrderTransform>(header, transform_params, group_by_sort_description, max_block_size);
});
aggregating_in_order = collector.detachProcessors(0);
}
pipeline.addSimpleTransform([&](const Block & header)
......@@ -106,6 +113,8 @@ void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
return std::make_shared<FinalizingSimpleTransform>(header, transform_params);
});
finalizing = collector.detachProcessors(2);
pipeline.enableQuotaForCurrentStreams();
return;
}
......@@ -127,6 +136,8 @@ void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
});
pipeline.resize(1);
aggregating = collector.detachProcessors(0);
}
else
{
......@@ -136,9 +147,29 @@ void AggregatingStep::transformPipeline(QueryPipeline & pipeline)
{
return std::make_shared<AggregatingTransform>(header, transform_params);
});
aggregating = collector.detachProcessors(0);
}
pipeline.enableQuotaForCurrentStreams();
}
void AggregatingStep::describeActions(FormatSettings & settings) const
{
params.explain(settings.out, settings.offset);
}
void AggregatingStep::describePipeline(FormatSettings & settings) const
{
if (!aggregating.empty())
IQueryPlanStep::describePipeline(aggregating, settings);
else
{
/// Processors are printed in reverse order.
IQueryPlanStep::describePipeline(finalizing, settings);
IQueryPlanStep::describePipeline(aggregating_sorted, settings);
IQueryPlanStep::describePipeline(aggregating_in_order, settings);
}
}
}
......@@ -29,6 +29,9 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings &) const override;
void describePipeline(FormatSettings & settings) const override;
private:
Aggregator::Params params;
bool final;
......@@ -40,6 +43,13 @@ private:
InputOrderInfoPtr group_by_info;
SortDescription group_by_sort_description;
Processors aggregating_in_order;
Processors aggregating_sorted;
Processors finalizing;
Processors aggregating;
};
}
......
#include <Processors/QueryPlan/ConvertingStep.h>
#include <Processors/QueryPipeline.h>
#include <Processors/Transforms/ConvertingTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -30,4 +31,40 @@ void ConvertingStep::transformPipeline(QueryPipeline & pipeline)
});
}
void ConvertingStep::describeActions(FormatSettings & settings) const
{
const auto & header = input_streams[0].header;
auto conversion = ConvertingTransform(header, result_header, ConvertingTransform::MatchColumnsMode::Name)
.getConversion();
auto dump_description = [&](const ColumnWithTypeAndName & elem, bool is_const)
{
settings.out << elem.name << ' ' << elem.type->getName() << (is_const ? " Const" : "") << '\n';
};
String prefix(settings.offset, ' ');
for (size_t i = 0; i < conversion.size(); ++i)
{
const auto & from = header.getByPosition(conversion[i]);
const auto & to = result_header.getByPosition(i);
bool from_const = from.column && isColumnConst(*from.column);
bool to_const = to.column && isColumnConst(*to.column);
settings.out << prefix;
if (from.name == to.name && from.type->equals(*to.type) && from_const == to_const)
dump_description(from, from_const);
else
{
dump_description(to, to_const);
settings.out << " ← ";
dump_description(from, from_const);
}
settings.out << '\n';
}
}
}
......@@ -14,6 +14,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
Block result_header;
};
......
#include <Processors/QueryPlan/CreatingSetsStep.h>
#include <Processors/QueryPipeline.h>
#include <Processors/Transforms/CreatingSetsTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -37,4 +38,20 @@ void CreatingSetsStep::transformPipeline(QueryPipeline & pipeline)
pipeline.addCreatingSetsTransform(std::move(creating_sets));
}
void CreatingSetsStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
for (const auto & set : subqueries_for_sets)
{
settings.out << prefix;
if (set.second.set)
settings.out << "Set: ";
else if (set.second.join)
settings.out << "Join: ";
settings.out << set.first << '\n';
}
}
}
......@@ -20,6 +20,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SubqueriesForSets subqueries_for_sets;
SizeLimits network_transfer_limits;
......
#include <Processors/QueryPlan/DistinctStep.h>
#include <Processors/Transforms/DistinctTransform.h>
#include <Processors/QueryPipeline.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -68,4 +69,27 @@ void DistinctStep::transformPipeline(QueryPipeline & pipeline)
});
}
void DistinctStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Columns: ";
if (columns.empty())
settings.out << "none";
else
{
bool first = true;
for (const auto & column : columns)
{
if (!first)
settings.out << ", ";
first = false;
settings.out << column;
}
}
settings.out << '\n';
}
}
......@@ -20,6 +20,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SizeLimits set_size_limits;
UInt64 limit_hint;
......
......@@ -3,6 +3,7 @@
#include <Processors/QueryPipeline.h>
#include <Processors/Transforms/InflatingExpressionTransform.h>
#include <Interpreters/ExpressionActions.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -37,6 +38,25 @@ void ExpressionStep::transformPipeline(QueryPipeline & pipeline)
});
}
static void doDescribeActions(const ExpressionActionsPtr & expression, IQueryPlanStep::FormatSettings & settings)
{
String prefix(settings.offset, ' ');
bool first = true;
for (const auto & action : expression->getActions())
{
settings.out << prefix << (first ? "Actions: "
: " ");
first = false;
settings.out << action.toString() << '\n';
}
}
void ExpressionStep::describeActions(FormatSettings & settings) const
{
doDescribeActions(expression, settings);
}
InflatingExpressionStep::InflatingExpressionStep(const DataStream & input_stream_, ExpressionActionsPtr expression_)
: ITransformingStep(
input_stream_,
......@@ -64,4 +84,9 @@ void InflatingExpressionStep::transformPipeline(QueryPipeline & pipeline)
});
}
void InflatingExpressionStep::describeActions(FormatSettings & settings) const
{
doDescribeActions(expression, settings);
}
}
......@@ -21,6 +21,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
ExpressionActionsPtr expression;
};
......@@ -36,6 +38,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
ExpressionActionsPtr expression;
};
......
#include <Processors/QueryPlan/FillingStep.h>
#include <Processors/Transforms/FillingTransform.h>
#include <Processors/QueryPipeline.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -36,4 +37,11 @@ void FillingStep::transformPipeline(QueryPipeline & pipeline)
});
}
void FillingStep::describeActions(FormatSettings & settings) const
{
settings.out << String(settings.offset, ' ');
dumpSortDescription(sort_description, input_streams.front().header, settings.out);
settings.out << '\n';
}
}
......@@ -15,6 +15,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SortDescription sort_description;
};
......
......@@ -2,6 +2,7 @@
#include <Processors/Transforms/FilterTransform.h>
#include <Processors/QueryPipeline.h>
#include <Interpreters/ExpressionActions.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -42,4 +43,19 @@ void FilterStep::transformPipeline(QueryPipeline & pipeline)
});
}
void FilterStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Filter column: " << filter_column_name << '\n';
bool first = true;
for (const auto & action : expression->getActions())
{
settings.out << prefix << (first ? "Actions: "
: " ");
first = false;
settings.out << action.toString() << '\n';
}
}
}
......@@ -20,6 +20,8 @@ public:
String getName() const override { return "Filter"; }
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
ExpressionActionsPtr expression;
String filter_column_name;
......
......@@ -4,6 +4,7 @@
#include <Processors/Merges/MergingSortedTransform.h>
#include <Processors/Transforms/PartialSortingTransform.h>
#include <Processors/Transforms/FinishSortingTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -68,4 +69,20 @@ void FinishSortingStep::transformPipeline(QueryPipeline & pipeline)
}
}
void FinishSortingStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Prefix sort description: ";
dumpSortDescription(prefix_description, input_streams.front().header, settings.out);
settings.out << '\n';
settings.out << prefix << "Result sort description: ";
dumpSortDescription(result_description, input_streams.front().header, settings.out);
settings.out << '\n';
if (limit)
settings.out << prefix << "Limit " << limit << '\n';
}
}
......@@ -20,6 +20,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SortDescription prefix_description;
SortDescription result_description;
......
#include <Processors/QueryPlan/IQueryPlanStep.h>
#include <Processors/IProcessor.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -16,4 +18,94 @@ const DataStream & IQueryPlanStep::getOutputStream() const
return *output_stream;
}
static void doDescribeHeader(const Block & header, size_t count, IQueryPlanStep::FormatSettings & settings)
{
String prefix(settings.offset, settings.indent_char);
prefix += "Header";
if (count > 1)
prefix += " × " + std::to_string(count) + " ";
prefix += ": ";
settings.out << prefix;
if (!header)
{
settings.out << " empty\n";
return;
}
prefix.assign(prefix.size(), settings.indent_char);
bool first = true;
for (const auto & elem : header)
{
if (!first)
settings.out << prefix;
first = false;
elem.dumpStructure(settings.out);
settings.out << '\n';
}
}
static void doDescribeProcessor(const IProcessor & processor, size_t count, IQueryPlanStep::FormatSettings & settings)
{
settings.out << String(settings.offset, settings.indent_char) << processor.getName();
if (count > 1)
settings.out << " × " << std::to_string(count);
size_t num_inputs = processor.getInputs().size();
size_t num_outputs = processor.getOutputs().size();
if (num_inputs != 1 || num_outputs != 1)
settings.out << " " << std::to_string(num_inputs) << " → " << std::to_string(num_outputs);
settings.out << '\n';
if (settings.write_header)
{
const Block * last_header = nullptr;
size_t num_equal_headers = 0;
for (const auto & port : processor.getOutputs())
{
if (last_header && !blocksHaveEqualStructure(*last_header, port.getHeader()))
{
doDescribeHeader(*last_header, num_equal_headers, settings);
num_equal_headers = 0;
}
++num_equal_headers;
last_header = &port.getHeader();
}
if (last_header)
doDescribeHeader(*last_header, num_equal_headers, settings);
}
settings.offset += settings.indent;
}
void IQueryPlanStep::describePipeline(const Processors & processors, FormatSettings & settings)
{
const IProcessor * prev = nullptr;
size_t count = 0;
for (auto it = processors.rbegin(); it != processors.rend(); ++it)
{
if (prev && prev->getName() != (*it)->getName())
{
doDescribeProcessor(*prev, count, settings);
count = 0;
}
++count;
prev = it->get();
}
if (prev)
doDescribeProcessor(*prev, count, settings);
}
}
......@@ -8,6 +8,10 @@ class QueryPipeline;
using QueryPipelinePtr = std::unique_ptr<QueryPipeline>;
using QueryPipelines = std::vector<QueryPipelinePtr>;
class IProcessor;
using ProcessorPtr = std::shared_ptr<IProcessor>;
using Processors = std::vector<ProcessorPtr>;
/// Description of data stream.
/// Single logical data stream may relate to many ports of pipeline.
class DataStream
......@@ -57,12 +61,29 @@ public:
const std::string & getStepDescription() const { return step_description; }
void setStepDescription(std::string description) { step_description = std::move(description); }
struct FormatSettings
{
WriteBuffer & out;
size_t offset = 0;
const size_t indent = 2;
const char indent_char = ' ';
const bool write_header = false;
};
/// Get detailed description of step actions. This is shown in EXPLAIN query with options `actions = 1`.
virtual void describeActions(FormatSettings & /*settings*/) const {}
/// Get description of processors added in current step. Should be called after updatePipeline().
virtual void describePipeline(FormatSettings & /*settings*/) const {}
protected:
DataStreams input_streams;
std::optional<DataStream> output_stream;
/// Text description about what current step does.
std::string step_description;
static void describePipeline(const Processors & processors, FormatSettings & settings);
};
using QueryPlanStepPtr = std::unique_ptr<IQueryPlanStep>;
......
......@@ -12,8 +12,15 @@ ISourceStep::ISourceStep(DataStream output_stream_)
QueryPipelinePtr ISourceStep::updatePipeline(QueryPipelines)
{
auto pipeline = std::make_unique<QueryPipeline>();
QueryPipelineProcessorsCollector collector(*pipeline, this);
initializePipeline(*pipeline);
processors = collector.detachProcessors();
return pipeline;
}
void ISourceStep::describePipeline(FormatSettings & settings) const
{
IQueryPlanStep::describePipeline(processors, settings);
}
}
......@@ -13,6 +13,12 @@ public:
QueryPipelinePtr updatePipeline(QueryPipelines pipelines) override;
virtual void initializePipeline(QueryPipeline & pipeline) = 0;
void describePipeline(FormatSettings & settings) const override;
private:
/// We collect processors got after pipeline transformation.
Processors processors;
};
}
......@@ -4,7 +4,8 @@
namespace DB
{
ITransformingStep::ITransformingStep(DataStream input_stream, Block output_header, DataStreamTraits traits)
ITransformingStep::ITransformingStep(DataStream input_stream, Block output_header, DataStreamTraits traits, bool collect_processors_)
: collect_processors(collect_processors_)
{
output_stream = DataStream{.header = std::move(output_header)};
......@@ -19,7 +20,15 @@ ITransformingStep::ITransformingStep(DataStream input_stream, Block output_heade
QueryPipelinePtr ITransformingStep::updatePipeline(QueryPipelines pipelines)
{
transformPipeline(*pipelines.front());
if (collect_processors)
{
QueryPipelineProcessorsCollector collector(*pipelines.front(), this);
transformPipeline(*pipelines.front());
processors = collector.detachProcessors();
}
else
transformPipeline(*pipelines.front());
return std::move(pipelines.front());
}
......@@ -38,4 +47,9 @@ void ITransformingStep::updateDistinctColumns(const Block & res_header, NameSet
}
}
void ITransformingStep::describePipeline(FormatSettings & settings) const
{
IQueryPlanStep::describePipeline(processors, settings);
}
}
......@@ -25,15 +25,22 @@ public:
bool preserves_number_of_streams;
};
ITransformingStep(DataStream input_stream, Block output_header, DataStreamTraits traits);
ITransformingStep(DataStream input_stream, Block output_header, DataStreamTraits traits, bool collect_processors_ = true);
QueryPipelinePtr updatePipeline(QueryPipelines pipelines) override;
virtual void transformPipeline(QueryPipeline & pipeline) = 0;
void describePipeline(FormatSettings & settings) const override;
protected:
/// Clear distinct_columns if res_header doesn't contain all of them.
static void updateDistinctColumns(const Block & res_header, NameSet & distinct_columns);
private:
/// We collect processors got after pipeline transformation.
Processors processors;
bool collect_processors;
};
}
#include <Processors/QueryPlan/LimitByStep.h>
#include <Processors/Transforms/LimitByTransform.h>
#include <Processors/QueryPipeline.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -39,4 +40,30 @@ void LimitByStep::transformPipeline(QueryPipeline & pipeline)
});
}
void LimitByStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Columns: ";
if (columns.empty())
settings.out << "none\n";
else
{
bool first = true;
for (const auto & column : columns)
{
if (!first)
settings.out << ", ";
first = false;
settings.out << column;
}
settings.out << '\n';
}
settings.out << prefix << "Length " << group_length << '\n';
settings.out << prefix << "Offset " << group_offset << '\n';
}
}
......@@ -16,6 +16,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
size_t group_length;
size_t group_offset;
......@@ -23,5 +25,3 @@ private:
};
}
#include <Processors/QueryPlan/LimitStep.h>
#include <Processors/QueryPipeline.h>
#include <Processors/LimitTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -36,4 +37,30 @@ void LimitStep::transformPipeline(QueryPipeline & pipeline)
pipeline.addPipe({std::move(transform)});
}
void LimitStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Limit " << limit << '\n';
settings.out << prefix << "Offset " << offset << '\n';
if (with_ties || always_read_till_end)
{
settings.out << prefix;
String str;
if (with_ties)
settings.out << "WITH TIES";
if (always_read_till_end)
{
if (!with_ties)
settings.out << ", ";
settings.out << "Reads all data";
}
settings.out << '\n';
}
}
}
......@@ -21,6 +21,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
size_t limit;
size_t offset;
......
#include <Processors/QueryPlan/MergeSortingStep.h>
#include <Processors/QueryPipeline.h>
#include <Processors/Transforms/MergeSortingTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -50,4 +51,15 @@ void MergeSortingStep::transformPipeline(QueryPipeline & pipeline)
});
}
void MergeSortingStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Sort description: ";
dumpSortDescription(description, input_streams.front().header, settings.out);
settings.out << '\n';
if (limit)
settings.out << prefix << "Limit " << limit << '\n';
}
}
......@@ -25,6 +25,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SortDescription description;
size_t max_merged_block_size;
......
......@@ -65,4 +65,9 @@ void MergingAggregatedStep::transformPipeline(QueryPipeline & pipeline)
pipeline.enableQuotaForCurrentStreams();
}
void MergingAggregatedStep::describeActions(FormatSettings & settings) const
{
return params->params.explain(settings.out, settings.offset);
}
}
......@@ -23,6 +23,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
AggregatingTransformParamsPtr params;
bool memory_efficient_aggregation;
......
#include <Processors/QueryPlan/MergingSortedStep.h>
#include <Processors/QueryPipeline.h>
#include <Processors/Merges/MergingSortedTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -45,4 +46,12 @@ void MergingSortedStep::transformPipeline(QueryPipeline & pipeline)
}
}
void MergingSortedStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Sort description: ";
dumpSortDescription(sort_description, input_streams.front().header, settings.out);
settings.out << '\n';
}
}
......@@ -21,6 +21,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SortDescription sort_description;
size_t max_block_size;
......
#include <Processors/QueryPlan/OffsetsStep.h>
#include <Processors/QueryPlan/OffsetStep.h>
#include <Processors/OffsetTransform.h>
#include <Processors/QueryPipeline.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -15,13 +16,13 @@ static ITransformingStep::DataStreamTraits getTraits()
};
}
OffsetsStep::OffsetsStep(const DataStream & input_stream_, size_t offset_)
OffsetStep::OffsetStep(const DataStream & input_stream_, size_t offset_)
: ITransformingStep(input_stream_, input_stream_.header, getTraits())
, offset(offset_)
{
}
void OffsetsStep::transformPipeline(QueryPipeline & pipeline)
void OffsetStep::transformPipeline(QueryPipeline & pipeline)
{
auto transform = std::make_shared<OffsetTransform>(
pipeline.getHeader(), offset, pipeline.getNumStreams());
......@@ -29,4 +30,9 @@ void OffsetsStep::transformPipeline(QueryPipeline & pipeline)
pipeline.addPipe({std::move(transform)});
}
void OffsetStep::describeActions(FormatSettings & settings) const
{
settings.out << String(settings.offset, ' ') << "Offset " << offset << '\n';
}
}
......@@ -6,15 +6,17 @@ namespace DB
{
/// Executes OFFSET (without LIMIT). See OffsetTransform.
class OffsetsStep : public ITransformingStep
class OffsetStep : public ITransformingStep
{
public:
OffsetsStep(const DataStream & input_stream_, size_t offset_);
OffsetStep(const DataStream & input_stream_, size_t offset_);
String getName() const override { return "Offsets"; }
String getName() const override { return "Offset"; }
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
size_t offset;
};
......
......@@ -2,6 +2,7 @@
#include <Processors/QueryPipeline.h>
#include <Processors/Transforms/PartialSortingTransform.h>
#include <Processors/Transforms/LimitsCheckingTransform.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -52,4 +53,12 @@ void PartialSortingStep::transformPipeline(QueryPipeline & pipeline)
});
}
void PartialSortingStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Sort description: ";
dumpSortDescription(sort_description, input_streams.front().header, settings.out);
settings.out << '\n';
}
}
......@@ -20,6 +20,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
SortDescription sort_description;
UInt64 limit;
......
#include <Processors/QueryPlan/QueryPlan.h>
#include <Processors/QueryPlan/IQueryPlanStep.h>
#include <Processors/QueryPipeline.h>
#include <IO/WriteBuffer.h>
#include <IO/Operators.h>
#include <stack>
namespace DB
......@@ -11,6 +13,7 @@ namespace ErrorCodes
extern const int LOGICAL_ERROR;
}
QueryPlan::QueryPlan() = default;
QueryPlan::~QueryPlan() = default;
void QueryPlan::checkInitialized() const
......@@ -173,4 +176,135 @@ void QueryPlan::addInterpreterContext(std::shared_ptr<Context> context)
interpreter_context.emplace_back(std::move(context));
}
static void explainStep(
const IQueryPlanStep & step,
IQueryPlanStep::FormatSettings & settings,
const QueryPlan::ExplainPlanOptions & options)
{
std::string prefix(settings.offset, ' ');
settings.out << prefix;
settings.out << step.getName();
const auto & description = step.getStepDescription();
if (options.description && !description.empty())
settings.out <<" (" << description << ')';
settings.out.write('\n');
if (options.header)
{
settings.out << prefix;
if (!step.hasOutputStream())
settings.out << "No header";
else if (!step.getOutputStream().header)
settings.out << "Empty header";
else
{
settings.out << "Header: ";
bool first = true;
for (const auto & elem : step.getOutputStream().header)
{
if (!first)
settings.out << "\n" << prefix << " ";
first = false;
elem.dumpStructure(settings.out);
}
}
settings.out.write('\n');
}
if (options.actions)
step.describeActions(settings);
}
void QueryPlan::explainPlan(WriteBuffer & buffer, const ExplainPlanOptions & options)
{
checkInitialized();
IQueryPlanStep::FormatSettings settings{.out = buffer, .write_header = options.header};
struct Frame
{
Node * node;
bool is_description_printed = false;
size_t next_child = 0;
};
std::stack<Frame> stack;
stack.push(Frame{.node = root});
while (!stack.empty())
{
auto & frame = stack.top();
if (!frame.is_description_printed)
{
settings.offset = (stack.size() - 1) * settings.indent;
explainStep(*frame.node->step, settings, options);
frame.is_description_printed = true;
}
if (frame.next_child < frame.node->children.size())
{
stack.push(Frame{frame.node->children[frame.next_child]});
++frame.next_child;
}
else
stack.pop();
}
}
static void explainPipelineStep(IQueryPlanStep & step, IQueryPlanStep::FormatSettings & settings)
{
settings.out << String(settings.offset, settings.indent_char) << "(" << step.getName() << ")\n";
size_t current_offset = settings.offset;
step.describePipeline(settings);
if (current_offset == settings.offset)
settings.offset += settings.indent;
}
void QueryPlan::explainPipeline(WriteBuffer & buffer, const ExplainPipelineOptions & options)
{
checkInitialized();
IQueryPlanStep::FormatSettings settings{.out = buffer, .write_header = options.header};
struct Frame
{
Node * node;
size_t offset = 0;
bool is_description_printed = false;
size_t next_child = 0;
};
std::stack<Frame> stack;
stack.push(Frame{.node = root});
while (!stack.empty())
{
auto & frame = stack.top();
if (!frame.is_description_printed)
{
settings.offset = frame.offset;
explainPipelineStep(*frame.node->step, settings);
frame.offset = settings.offset;
frame.is_description_printed = true;
}
if (frame.next_child < frame.node->children.size())
{
stack.push(Frame{frame.node->children[frame.next_child], frame.offset});
++frame.next_child;
}
else
stack.pop();
}
}
}
......@@ -15,6 +15,7 @@ class QueryPipeline;
using QueryPipelinePtr = std::unique_ptr<QueryPipeline>;
class Context;
class WriteBuffer;
/// A tree of query steps.
/// The goal of QueryPlan is to build QueryPipeline.
......@@ -22,6 +23,7 @@ class Context;
class QueryPlan
{
public:
QueryPlan();
~QueryPlan();
void unitePlans(QueryPlanStepPtr step, std::vector<QueryPlan> plans);
......@@ -33,6 +35,25 @@ public:
QueryPipelinePtr buildQueryPipeline();
struct ExplainPlanOptions
{
/// Add output header to step.
bool header = false;
/// Add description of step.
bool description = true;
/// Add detailed information about step actions.
bool actions = false;
};
struct ExplainPipelineOptions
{
/// Show header of output ports.
bool header = false;
};
void explainPlan(WriteBuffer & buffer, const ExplainPlanOptions & options);
void explainPipeline(WriteBuffer & buffer, const ExplainPipelineOptions & options);
/// Set upper limit for the recommend number of threads. Will be applied to the newly-created pipelines.
/// TODO: make it in a better way.
void setMaxThreads(size_t max_threads_) { max_threads = max_threads_; }
......
......@@ -68,6 +68,7 @@ ReadFromStorageStep::ReadFromStorageStep(
}
pipeline = std::make_unique<QueryPipeline>();
QueryPipelineProcessorsCollector collector(*pipeline, this);
/// Table lock is stored inside pipeline here.
pipeline->addTableLock(table_lock);
......@@ -124,6 +125,8 @@ ReadFromStorageStep::ReadFromStorageStep(
pipeline->addInterpreterContext(std::move(context));
pipeline->addStorageHolder(std::move(storage));
processors = collector.detachProcessors();
output_stream = DataStream{.header = pipeline->getHeader(), .has_single_port = pipeline->getNumStreams() == 1};
}
......@@ -134,4 +137,9 @@ QueryPipelinePtr ReadFromStorageStep::updatePipeline(QueryPipelines)
return std::move(pipeline);
}
void ReadFromStorageStep::describePipeline(FormatSettings & settings) const
{
IQueryPlanStep::describePipeline(processors, settings);
}
}
......@@ -38,6 +38,8 @@ public:
QueryPipelinePtr updatePipeline(QueryPipelines) override;
void describePipeline(FormatSettings & settings) const override;
private:
TableLockHolder table_lock;
StorageMetadataPtr metadata_snapshot;
......@@ -52,6 +54,7 @@ private:
size_t max_streams;
QueryPipelinePtr pipeline;
Processors processors;
};
}
......@@ -2,6 +2,8 @@
#include <Processors/Transforms/DistinctTransform.h>
#include <Processors/QueryPipeline.h>
#include <Processors/Transforms/TotalsHavingTransform.h>
#include <Interpreters/ExpressionActions.h>
#include <IO/Operators.h>
namespace DB
{
......@@ -46,4 +48,37 @@ void TotalsHavingStep::transformPipeline(QueryPipeline & pipeline)
pipeline.addTotalsHavingTransform(std::move(totals_having));
}
static String totalsModeToString(TotalsMode totals_mode, double auto_include_threshold)
{
switch (totals_mode)
{
case TotalsMode::BEFORE_HAVING:
return "before_having";
case TotalsMode::AFTER_HAVING_INCLUSIVE:
return "after_having_inclusive";
case TotalsMode::AFTER_HAVING_EXCLUSIVE:
return "after_having_exclusive";
case TotalsMode::AFTER_HAVING_AUTO:
return "after_having_auto threshold " + std::to_string(auto_include_threshold);
}
__builtin_unreachable();
}
void TotalsHavingStep::describeActions(FormatSettings & settings) const
{
String prefix(settings.offset, ' ');
settings.out << prefix << "Filter column: " << filter_column_name << '\n';
settings.out << prefix << "Mode: " << totalsModeToString(totals_mode, auto_include_threshold) << '\n';
bool first = true;
for (const auto & action : expression->getActions())
{
settings.out << prefix << (first ? "Actions: "
: " ");
first = false;
settings.out << action.toString() << '\n';
}
}
}
......@@ -26,6 +26,8 @@ public:
void transformPipeline(QueryPipeline & pipeline) override;
void describeActions(FormatSettings & settings) const override;
private:
bool overflow_row;
ExpressionActionsPtr expression;
......
......@@ -21,9 +21,12 @@ UnionStep::UnionStep(DataStreams input_streams_, Block result_header, size_t max
QueryPipelinePtr UnionStep::updatePipeline(QueryPipelines pipelines)
{
auto pipeline = std::make_unique<QueryPipeline>();
QueryPipelineProcessorsCollector collector(*pipeline, this);
if (pipelines.empty())
{
pipeline->init(Pipe(std::make_shared<NullSource>(output_stream->header)));
processors = collector.detachProcessors();
return pipeline;
}
......@@ -37,7 +40,13 @@ QueryPipelinePtr UnionStep::updatePipeline(QueryPipelines pipelines)
pipeline->setMaxThreads(std::min<UInt64>(num_pipelines, max_threads));
}
processors = collector.detachProcessors();
return pipeline;
}
void UnionStep::describePipeline(FormatSettings & settings) const
{
IQueryPlanStep::describePipeline(processors, settings);
}
}
......@@ -15,9 +15,12 @@ public:
QueryPipelinePtr updatePipeline(QueryPipelines pipelines) override;
void describePipeline(FormatSettings & settings) const override;
private:
Block header;
size_t max_threads;
Processors processors;
};
}
......@@ -35,6 +35,8 @@ public:
String getName() const override { return "Converting"; }
const ColumnNumbers & getConversion() const { return conversion; }
protected:
void transform(Chunk & chunk) override;
......
#include <Processors/printPipeline.h>
#include <Processors/QueryPlan/IQueryPlanStep.h>
#include <set>
#include <map>
namespace DB
{
void printPipelineCompact(const Processors & processors, WriteBuffer & out, bool with_header)
{
struct Node;
/// Group by processors name, QueryPlanStep and group in this step.
struct Key
{
size_t group;
IQueryPlanStep * step;
std::string name;
auto getTuple() const { return std::forward_as_tuple(group, step, name); }
bool operator<(const Key & other) const
{
return getTuple() < other.getTuple();
}
};
/// Group ports by header.
struct EdgeData
{
Block header;
size_t count;
};
using Edge = std::vector<EdgeData>;
struct Node
{
size_t id = 0;
std::map<Node *, Edge> edges = {};
std::vector<const IProcessor *> agents = {};
};
std::map<Key, Node> graph;
auto get_key = [](const IProcessor & processor)
{
return Key{processor.getQueryPlanStepGroup(), processor.getQueryPlanStep(), processor.getName()};
};
/// Fill nodes.
for (const auto & processor : processors)
{
auto res = graph.emplace(get_key(*processor), Node());
auto & node = res.first->second;
node.agents.emplace_back(processor.get());
if (res.second)
node.id = graph.size();
}
Block empty_header;
/// Fill edges.
for (const auto & processor : processors)
{
auto & from = graph[get_key(*processor)];
for (auto & port : processor->getOutputs())
{
if (!port.isConnected())
continue;
auto & to = graph[get_key(port.getInputPort().getProcessor())];
auto & edge = from.edges[&to];
/// Use empty header for each edge if with_header is false.
const auto & header = with_header ? port.getHeader()
: empty_header;
/// Group by header.
bool found = false;
for (auto & item : edge)
{
if (blocksHaveEqualStructure(header, item.header))
{
found = true;
++item.count;
break;
}
}
if (!found)
edge.emplace_back(EdgeData{header, 1});
}
}
/// Group processors by it's QueryPlanStep.
std::map<IQueryPlanStep *, std::vector<const Node *>> steps_map;
for (const auto & item : graph)
steps_map[item.first.step].emplace_back(&item.second);
out << "digraph\n{\n";
out << " rankdir=\"LR\";\n";
out << " { node [shape = box]\n";
/// Nodes // TODO quoting and escaping
size_t next_step = 0;
for (const auto & item : steps_map)
{
/// Use separate clusters for each step.
if (item.first != nullptr)
{
out << " subgraph cluster_" << next_step << " {\n";
out << " label =\"" << item.first->getName() << "\";\n";
out << " style=filled;\n";
out << " color=lightgrey;\n";
out << " node [style=filled,color=white];\n";
out << " { rank = same;\n";
++next_step;
}
for (const auto & node : item.second)
{
const auto & processor = node->agents.front();
out << " n" << node->id << " [label=\"" << processor->getName();
if (node->agents.size() > 1)
out << " × " << node->agents.size();
const auto & description = processor->getDescription();
if (!description.empty())
out << ' ' << description;
out << "\"];\n";
}
if (item.first != nullptr)
{
out << " }\n";
out << " }\n";
}
}
out << " }\n";
/// Edges
for (const auto & item : graph)
{
for (const auto & edge : item.second.edges)
{
for (const auto & data : edge.second)
{
out << " n" << item.second.id << " -> " << "n" << edge.first->id << " [label=\"";
if (data.count > 1)
out << "× " << data.count;
if (with_header)
{
for (const auto & elem : data.header)
{
out << "\n";
elem.dumpStructure(out);
}
}
out << "\"];\n";
}
}
}
out << "}\n";
}
}
......@@ -15,6 +15,8 @@ template <typename Processors, typename Statuses>
void printPipeline(const Processors & processors, const Statuses & statuses, WriteBuffer & out)
{
out << "digraph\n{\n";
out << " rankdir=\"LR\";\n";
out << " { node [shape = box]\n";
auto get_proc_id = [](const IProcessor & proc) -> UInt64
{
......@@ -26,7 +28,7 @@ void printPipeline(const Processors & processors, const Statuses & statuses, Wri
/// Nodes // TODO quoting and escaping
for (const auto & processor : processors)
{
out << "n" << get_proc_id(*processor) << "[label=\"" << processor->getName() << processor->getDescription();
out << " n" << get_proc_id(*processor) << "[label=\"" << processor->getName() << processor->getDescription();
if (statuses_iter != statuses.end())
{
......@@ -37,6 +39,8 @@ void printPipeline(const Processors & processors, const Statuses & statuses, Wri
out << "\"];\n";
}
out << " }\n";
/// Edges
for (const auto & processor : processors)
{
......@@ -48,7 +52,7 @@ void printPipeline(const Processors & processors, const Statuses & statuses, Wri
const IProcessor & curr = *processor;
const IProcessor & next = port.getInputPort().getProcessor();
out << "n" << get_proc_id(curr) << " -> n" << get_proc_id(next) << ";\n";
out << " n" << get_proc_id(curr) << " -> n" << get_proc_id(next) << ";\n";
}
}
out << "}\n";
......@@ -60,4 +64,10 @@ void printPipeline(const Processors & processors, WriteBuffer & out)
printPipeline(processors, std::vector<IProcessor::Status>(), out);
}
/// Prints pipeline in compact representation.
/// Group processors by it's name, QueryPlanStep and QueryPlanStepGroup.
/// If QueryPlanStep wasn't set for processor, representation may be not correct.
/// If with_header is set, prints block header for each edge.
void printPipelineCompact(const Processors & processors, WriteBuffer & out, bool with_header);
}
......@@ -105,6 +105,7 @@ SRCS(
OffsetTransform.cpp
Pipe.cpp
Port.cpp
printPipeline.cpp
QueryPipeline.cpp
ResizeProcessor.cpp
Sources/DelayedSource.cpp
......@@ -157,7 +158,7 @@ SRCS(
QueryPlan/MergeSortingStep.cpp
QueryPlan/MergingAggregatedStep.cpp
QueryPlan/MergingSortedStep.cpp
QueryPlan/OffsetsStep.cpp
QueryPlan/OffsetStep.cpp
QueryPlan/PartialSortingStep.cpp
QueryPlan/UnionStep.cpp
QueryPlan/ReadFromPreparedSource.cpp
......
......@@ -4,61 +4,582 @@
1
2000-01-01 1 test string 1 1
-------Forbid push down-------
SELECT count()\nFROM \n(\n SELECT \n [number] AS a,\n [number * 2] AS b\n FROM system.numbers\n LIMIT 1\n) AS t\nARRAY JOIN \n a,\n b\nWHERE NOT ignore(a + b)
SELECT count()
FROM
(
SELECT
[number] AS a,
[number * 2] AS b
FROM system.numbers
LIMIT 1
) AS t
ARRAY JOIN
a,
b
WHERE NOT ignore(a + b)
1
SELECT \n a,\n b\nFROM \n(\n SELECT 1 AS a\n)\nANY LEFT JOIN \n(\n SELECT \n 1 AS a,\n 1 AS b\n) USING (a)\nWHERE b = 0
SELECT \n a,\n b\nFROM \n(\n SELECT \n 1 AS a,\n 1 AS b\n)\nANY RIGHT JOIN \n(\n SELECT 1 AS a\n) USING (a)\nWHERE b = 0
SELECT \n a,\n b\nFROM \n(\n SELECT 1 AS a\n)\nANY FULL OUTER JOIN \n(\n SELECT \n 1 AS a,\n 1 AS b\n) USING (a)\nWHERE b = 0
SELECT \n a,\n b\nFROM \n(\n SELECT \n 1 AS a,\n 1 AS b\n)\nANY FULL OUTER JOIN \n(\n SELECT 1 AS a\n) USING (a)\nWHERE b = 0
SELECT
a,
b
FROM
(
SELECT 1 AS a
)
ANY LEFT JOIN
(
SELECT
1 AS a,
1 AS b
) USING (a)
WHERE b = 0
SELECT
a,
b
FROM
(
SELECT
1 AS a,
1 AS b
)
ANY RIGHT JOIN
(
SELECT 1 AS a
) USING (a)
WHERE b = 0
SELECT
a,
b
FROM
(
SELECT 1 AS a
)
ANY FULL OUTER JOIN
(
SELECT
1 AS a,
1 AS b
) USING (a)
WHERE b = 0
SELECT
a,
b
FROM
(
SELECT
1 AS a,
1 AS b
)
ANY FULL OUTER JOIN
(
SELECT 1 AS a
) USING (a)
WHERE b = 0
-------Need push down-------
SELECT toString(value) AS value\nFROM \n(\n SELECT 1 AS value\n)
SELECT toString(value) AS value
FROM
(
SELECT 1 AS value
)
1
SELECT id\nFROM \n(\n SELECT 1 AS id\n UNION ALL\n SELECT 2 AS `--predicate_optimizer_0`\n WHERE 0\n)\nWHERE id = 1
SELECT id
FROM
(
SELECT 1 AS id
UNION ALL
SELECT 2 AS `--predicate_optimizer_0`
WHERE 0
)
WHERE id = 1
1
SELECT id\nFROM \n(\n SELECT arrayJoin([1, 2, 3]) AS id\n WHERE id = 1\n)\nWHERE id = 1
SELECT id
FROM
(
SELECT arrayJoin([1, 2, 3]) AS id
WHERE id = 1
)
WHERE id = 1
1
SELECT id\nFROM \n(\n SELECT arrayJoin([1, 2, 3]) AS id\n WHERE id = 1\n)\nWHERE id = 1
SELECT id
FROM
(
SELECT arrayJoin([1, 2, 3]) AS id
WHERE id = 1
)
WHERE id = 1
1
SELECT \n id,\n subquery\nFROM \n(\n SELECT \n 1 AS id,\n CAST(1, \'UInt8\') AS subquery\n)
SELECT
id,
subquery
FROM
(
SELECT
1 AS id,
CAST(1, \'UInt8\') AS subquery
)
1 1
SELECT \n a,\n b\nFROM \n(\n SELECT \n toUInt64(sum(id) AS b) AS a,\n b\n FROM test_00597\n HAVING a = 3\n)\nWHERE a = 3
SELECT
a,
b
FROM
(
SELECT
toUInt64(sum(id) AS b) AS a,
b
FROM test_00597
HAVING a = 3
)
WHERE a = 3
3 3
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n name,\n value,\n min(id) AS id\n FROM test_00597\n GROUP BY \n date,\n name,\n value\n HAVING id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
name,
value,
min(id) AS id
FROM test_00597
GROUP BY
date,
name,
value
HAVING id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n a,\n b\nFROM \n(\n SELECT \n toUInt64(sum(id) AS b) AS a,\n b\n FROM test_00597 AS table_alias\n HAVING b = 3\n) AS outer_table_alias\nWHERE b = 3
SELECT
a,
b
FROM
(
SELECT
toUInt64(sum(id) AS b) AS a,
b
FROM test_00597 AS table_alias
HAVING b = 3
) AS outer_table_alias
WHERE b = 3
3 3
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n )\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n ) AS b\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
) AS b
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n )\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n) AS b\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
) AS b
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n ) AS a\n WHERE id = 1\n) AS b\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
) AS a
WHERE id = 1
) AS b
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n id,\n date,\n value\nFROM \n(\n SELECT \n id,\n date,\n min(value) AS value\n FROM test_00597\n WHERE id = 1\n GROUP BY \n id,\n date\n)\nWHERE id = 1
SELECT
id,
date,
value
FROM
(
SELECT
id,
date,
min(value) AS value
FROM test_00597
WHERE id = 1
GROUP BY
id,
date
)
WHERE id = 1
1 2000-01-01 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n UNION ALL\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
UNION ALL
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value,\n date,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n)\nANY LEFT JOIN \n(\n SELECT id\n FROM test_00597\n) USING (id)\nWHERE id = 1
SELECT
date,
id,
name,
value,
date,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
ANY LEFT JOIN
(
SELECT id
FROM test_00597
) USING (id)
WHERE id = 1
2000-01-01 1 test string 1 1 2000-01-01 test string 1 1
SELECT \n id,\n date,\n name,\n value\nFROM \n(\n SELECT toInt8(1) AS id\n)\nANY LEFT JOIN \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n) AS test_00597 USING (id)\nWHERE value = 1
SELECT
id,
date,
name,
value
FROM
(
SELECT toInt8(1) AS id
)
ANY LEFT JOIN
(
SELECT
date,
id,
name,
value
FROM test_00597
) AS test_00597 USING (id)
WHERE value = 1
1 2000-01-01 test string 1 1
SELECT value\nFROM \n(\n SELECT toInt8(1) AS id\n)\nANY LEFT JOIN test_00597 AS b USING (id)\nWHERE value = 1
SELECT value
FROM
(
SELECT toInt8(1) AS id
)
ANY LEFT JOIN test_00597 AS b USING (id)
WHERE value = 1
1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value,\n date,\n name,\n value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n )\n ANY LEFT JOIN \n (\n SELECT id\n FROM test_00597\n ) USING (id)\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value,
date,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
ANY LEFT JOIN
(
SELECT id
FROM test_00597
) USING (id)
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value,\n b.date,\n b.name,\n b.value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n)\nANY LEFT JOIN \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n) AS b USING (id)\nWHERE b.id = 1
SELECT
date,
id,
name,
value,
b.date,
b.name,
b.value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
)
ANY LEFT JOIN
(
SELECT
date,
id,
name,
value
FROM test_00597
) AS b USING (id)
WHERE b.id = 1
2000-01-01 1 test string 1 1 2000-01-01 test string 1 1
SELECT \n id,\n date,\n name,\n value\nFROM \n(\n SELECT \n toInt8(1) AS id,\n toDate(\'2000-01-01\') AS date\n FROM system.numbers\n LIMIT 1\n)\nANY LEFT JOIN \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n) AS b USING (date, id)\nWHERE b.date = toDate(\'2000-01-01\')
SELECT
id,
date,
name,
value
FROM
(
SELECT
toInt8(1) AS id,
toDate(\'2000-01-01\') AS date
FROM system.numbers
LIMIT 1
)
ANY LEFT JOIN
(
SELECT
date,
id,
name,
value
FROM test_00597
) AS b USING (date, id)
WHERE b.date = toDate(\'2000-01-01\')
1 2000-01-01 test string 1 1
SELECT \n date,\n id,\n name,\n value,\n `b.date`,\n `b.id`,\n `b.name`,\n `b.value`\nFROM \n(\n SELECT \n date,\n id,\n name,\n value,\n b.date,\n b.id,\n b.name,\n b.value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n ) AS a\n ANY LEFT JOIN \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n ) AS b ON id = b.id\n WHERE id = 1\n)\nWHERE id = 1
SELECT
date,
id,
name,
value,
`b.date`,
`b.id`,
`b.name`,
`b.value`
FROM
(
SELECT
date,
id,
name,
value,
b.date,
b.id,
b.name,
b.value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
) AS a
ANY LEFT JOIN
(
SELECT
date,
id,
name,
value
FROM test_00597
) AS b ON id = b.id
WHERE id = 1
)
WHERE id = 1
2000-01-01 1 test string 1 1 2000-01-01 1 test string 1 1
SELECT \n date,\n id,\n name,\n value,\n r.date,\n r.name,\n r.value\nFROM \n(\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n)\nSEMI LEFT JOIN \n(\n SELECT \n date,\n id,\n name,\n value\n FROM \n (\n SELECT \n date,\n id,\n name,\n value\n FROM test_00597\n WHERE id = 1\n )\n WHERE id = 1\n) AS r USING (id)\nWHERE r.id = 1
SELECT
date,
id,
name,
value,
r.date,
r.name,
r.value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
)
SEMI LEFT JOIN
(
SELECT
date,
id,
name,
value
FROM
(
SELECT
date,
id,
name,
value
FROM test_00597
WHERE id = 1
)
WHERE id = 1
) AS r USING (id)
WHERE r.id = 1
2000-01-01 1 test string 1 1 2000-01-01 test string 1 1
......@@ -35,18 +35,74 @@ comma nullable
1 1 1 1
2 2 1 2
cross
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nALL INNER JOIN t2_00826 ON a = t2_00826.a\nWHERE a = t2_00826.a
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.a
WHERE a = t2_00826.a
cross nullable
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nALL INNER JOIN t2_00826 ON a = t2_00826.a\nWHERE a = t2_00826.a
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.a
WHERE a = t2_00826.a
cross nullable vs not nullable
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nALL INNER JOIN t2_00826 ON a = t2_00826.b\nWHERE a = t2_00826.b
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.b
WHERE a = t2_00826.b
cross self
SELECT \n a,\n b,\n y.a,\n y.b\nFROM t1_00826 AS x\nALL INNER JOIN t1_00826 AS y ON (a = y.a) AND (b = y.b)\nWHERE (a = y.a) AND (b = y.b)
SELECT
a,
b,
y.a,
y.b
FROM t1_00826 AS x
ALL INNER JOIN t1_00826 AS y ON (a = y.a) AND (b = y.b)
WHERE (a = y.a) AND (b = y.b)
cross one table expr
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nCROSS JOIN t2_00826\nWHERE a = b
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
CROSS JOIN t2_00826
WHERE a = b
cross multiple ands
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)\nWHERE (a = t2_00826.a) AND (b = t2_00826.b)
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND (b = t2_00826.b)
cross and inside and
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (a = t2_00826.a) AND (a = t2_00826.a) AND (b = t2_00826.b)\nWHERE (a = t2_00826.a) AND ((a = t2_00826.a) AND ((a = t2_00826.a) AND (b = t2_00826.b)))
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (a = t2_00826.a) AND (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND ((a = t2_00826.a) AND ((a = t2_00826.a) AND (b = t2_00826.b)))
cross split conjunction
SELECT \n a,\n b,\n t2_00826.a,\n t2_00826.b\nFROM t1_00826\nALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)\nWHERE (a = t2_00826.a) AND (b = t2_00826.b) AND (a >= 1) AND (t2_00826.b > 0)
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND (b = t2_00826.b) AND (a >= 1) AND (t2_00826.b > 0)
SELECT a\nFROM t1_00849\nCROSS JOIN t2_00849
SELECT a\nFROM t1_00849\nALL INNER JOIN t2_00849 ON a = t2_00849.a\nWHERE a = t2_00849.a
SELECT a\nFROM t1_00849\nALL INNER JOIN t2_00849 ON b = t2_00849.b\nWHERE b = t2_00849.b
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`\n) AS `--.s`\nALL INNER JOIN t3_00849 ON `--t1_00849.a` = a\nWHERE (`--t1_00849.a` = `--t2_00849.a`) AND (`--t1_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n a AS `--t1_00849.a`,\n b AS `--t1_00849.b`,\n t2_00849.a,\n t2_00849.b AS `--t2_00849.b`\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t1_00849.b` = `--t2_00849.b`\n) AS `--.s`\nALL INNER JOIN t3_00849 ON `--t1_00849.b` = b\nWHERE (`--t1_00849.b` = `--t2_00849.b`) AND (`--t1_00849.b` = b)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `--t2_00849.a`,\n `t2_00849.b`,\n a AS `--t3_00849.a`,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`\n ) AS `--.s`\n ALL INNER JOIN t3_00849 ON `--t1_00849.a` = `--t3_00849.a`\n) AS `--.s`\nALL INNER JOIN t4_00849 ON `--t1_00849.a` = a\nWHERE (`--t1_00849.a` = `--t2_00849.a`) AND (`--t1_00849.a` = `--t3_00849.a`) AND (`--t1_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n `--t1_00849.b`,\n `t2_00849.a`,\n `--t2_00849.b`,\n a,\n b AS `--t3_00849.b`\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b AS `--t1_00849.b`,\n t2_00849.a,\n t2_00849.b AS `--t2_00849.b`\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t1_00849.b` = `--t2_00849.b`\n ) AS `--.s`\n ALL INNER JOIN t3_00849 ON `--t1_00849.b` = `--t3_00849.b`\n) AS `--.s`\nALL INNER JOIN t4_00849 ON `--t1_00849.b` = b\nWHERE (`--t1_00849.b` = `--t2_00849.b`) AND (`--t1_00849.b` = `--t3_00849.b`) AND (`--t1_00849.b` = b)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `--t2_00849.a`,\n `t2_00849.b`,\n a AS `--t3_00849.a`,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t2_00849.a` = `--t1_00849.a`\n ) AS `--.s`\n ALL INNER JOIN t3_00849 ON `--t2_00849.a` = `--t3_00849.a`\n) AS `--.s`\nALL INNER JOIN t4_00849 ON `--t2_00849.a` = a\nWHERE (`--t2_00849.a` = `--t1_00849.a`) AND (`--t2_00849.a` = `--t3_00849.a`) AND (`--t2_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `--t2_00849.a`,\n `t2_00849.b`,\n a AS `--t3_00849.a`,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n CROSS JOIN t2_00849\n ) AS `--.s`\n ALL INNER JOIN t3_00849 ON (`--t3_00849.a` = `--t1_00849.a`) AND (`--t3_00849.a` = `--t2_00849.a`)\n) AS `--.s`\nALL INNER JOIN t4_00849 ON `--t3_00849.a` = a\nWHERE (`--t3_00849.a` = `--t1_00849.a`) AND (`--t3_00849.a` = `--t2_00849.a`) AND (`--t3_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `--t2_00849.a`,\n `t2_00849.b`,\n a AS `--t3_00849.a`,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n CROSS JOIN t2_00849\n ) AS `--.s`\n CROSS JOIN t3_00849\n) AS `--.s`\nALL INNER JOIN t4_00849 ON (a = `--t1_00849.a`) AND (a = `--t2_00849.a`) AND (a = `--t3_00849.a`)\nWHERE (a = `--t1_00849.a`) AND (a = `--t2_00849.a`) AND (a = `--t3_00849.a`)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `--t2_00849.a`,\n `t2_00849.b`,\n a AS `--t3_00849.a`,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`\n ) AS `--.s`\n ALL INNER JOIN t3_00849 ON `--t2_00849.a` = `--t3_00849.a`\n) AS `--.s`\nALL INNER JOIN t4_00849 ON `--t3_00849.a` = a\nWHERE (`--t1_00849.a` = `--t2_00849.a`) AND (`--t2_00849.a` = `--t3_00849.a`) AND (`--t3_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `t2_00849.a`,\n `t2_00849.b`,\n a,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a,\n t2_00849.b\n FROM t1_00849\n CROSS JOIN t2_00849\n ) AS `--.s`\n CROSS JOIN t3_00849\n) AS `--.s`\nCROSS JOIN t4_00849
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n `--t1_00849.a`,\n b,\n `t2_00849.a`,\n `t2_00849.b`,\n a,\n t3_00849.b\n FROM \n (\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a,\n t2_00849.b\n FROM t1_00849\n CROSS JOIN t2_00849\n ) AS `--.s`\n CROSS JOIN t3_00849\n) AS `--.s`\nCROSS JOIN t4_00849
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a,\n t2_00849.b\n FROM t1_00849\n CROSS JOIN t2_00849\n) AS `--.s`\nCROSS JOIN t3_00849
SELECT `--t1_00849.a` AS `t1_00849.a`\nFROM \n(\n SELECT \n a AS `--t1_00849.a`,\n b,\n t2_00849.a AS `--t2_00849.a`,\n t2_00849.b\n FROM t1_00849\n ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`\n) AS `--.s`\nCROSS JOIN t3_00849
SELECT a
FROM t1_00849
CROSS JOIN t2_00849
SELECT a
FROM t1_00849
ALL INNER JOIN t2_00849 ON a = t2_00849.a
WHERE a = t2_00849.a
SELECT a
FROM t1_00849
ALL INNER JOIN t2_00849 ON b = t2_00849.b
WHERE b = t2_00849.b
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`
) AS `--.s`
ALL INNER JOIN t3_00849 ON `--t1_00849.a` = a
WHERE (`--t1_00849.a` = `--t2_00849.a`) AND (`--t1_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
a AS `--t1_00849.a`,
b AS `--t1_00849.b`,
t2_00849.a,
t2_00849.b AS `--t2_00849.b`
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t1_00849.b` = `--t2_00849.b`
) AS `--.s`
ALL INNER JOIN t3_00849 ON `--t1_00849.b` = b
WHERE (`--t1_00849.b` = `--t2_00849.b`) AND (`--t1_00849.b` = b)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`--t2_00849.a`,
`t2_00849.b`,
a AS `--t3_00849.a`,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`
) AS `--.s`
ALL INNER JOIN t3_00849 ON `--t1_00849.a` = `--t3_00849.a`
) AS `--.s`
ALL INNER JOIN t4_00849 ON `--t1_00849.a` = a
WHERE (`--t1_00849.a` = `--t2_00849.a`) AND (`--t1_00849.a` = `--t3_00849.a`) AND (`--t1_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
`--t1_00849.b`,
`t2_00849.a`,
`--t2_00849.b`,
a,
b AS `--t3_00849.b`
FROM
(
SELECT
a AS `--t1_00849.a`,
b AS `--t1_00849.b`,
t2_00849.a,
t2_00849.b AS `--t2_00849.b`
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t1_00849.b` = `--t2_00849.b`
) AS `--.s`
ALL INNER JOIN t3_00849 ON `--t1_00849.b` = `--t3_00849.b`
) AS `--.s`
ALL INNER JOIN t4_00849 ON `--t1_00849.b` = b
WHERE (`--t1_00849.b` = `--t2_00849.b`) AND (`--t1_00849.b` = `--t3_00849.b`) AND (`--t1_00849.b` = b)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`--t2_00849.a`,
`t2_00849.b`,
a AS `--t3_00849.a`,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t2_00849.a` = `--t1_00849.a`
) AS `--.s`
ALL INNER JOIN t3_00849 ON `--t2_00849.a` = `--t3_00849.a`
) AS `--.s`
ALL INNER JOIN t4_00849 ON `--t2_00849.a` = a
WHERE (`--t2_00849.a` = `--t1_00849.a`) AND (`--t2_00849.a` = `--t3_00849.a`) AND (`--t2_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`--t2_00849.a`,
`t2_00849.b`,
a AS `--t3_00849.a`,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
CROSS JOIN t2_00849
) AS `--.s`
ALL INNER JOIN t3_00849 ON (`--t3_00849.a` = `--t1_00849.a`) AND (`--t3_00849.a` = `--t2_00849.a`)
) AS `--.s`
ALL INNER JOIN t4_00849 ON `--t3_00849.a` = a
WHERE (`--t3_00849.a` = `--t1_00849.a`) AND (`--t3_00849.a` = `--t2_00849.a`) AND (`--t3_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`--t2_00849.a`,
`t2_00849.b`,
a AS `--t3_00849.a`,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
CROSS JOIN t2_00849
) AS `--.s`
CROSS JOIN t3_00849
) AS `--.s`
ALL INNER JOIN t4_00849 ON (a = `--t1_00849.a`) AND (a = `--t2_00849.a`) AND (a = `--t3_00849.a`)
WHERE (a = `--t1_00849.a`) AND (a = `--t2_00849.a`) AND (a = `--t3_00849.a`)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`--t2_00849.a`,
`t2_00849.b`,
a AS `--t3_00849.a`,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`
) AS `--.s`
ALL INNER JOIN t3_00849 ON `--t2_00849.a` = `--t3_00849.a`
) AS `--.s`
ALL INNER JOIN t4_00849 ON `--t3_00849.a` = a
WHERE (`--t1_00849.a` = `--t2_00849.a`) AND (`--t2_00849.a` = `--t3_00849.a`) AND (`--t3_00849.a` = a)
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`t2_00849.a`,
`t2_00849.b`,
a,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a,
t2_00849.b
FROM t1_00849
CROSS JOIN t2_00849
) AS `--.s`
CROSS JOIN t3_00849
) AS `--.s`
CROSS JOIN t4_00849
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
`--t1_00849.a`,
b,
`t2_00849.a`,
`t2_00849.b`,
a,
t3_00849.b
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a,
t2_00849.b
FROM t1_00849
CROSS JOIN t2_00849
) AS `--.s`
CROSS JOIN t3_00849
) AS `--.s`
CROSS JOIN t4_00849
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a,
t2_00849.b
FROM t1_00849
CROSS JOIN t2_00849
) AS `--.s`
CROSS JOIN t3_00849
SELECT `--t1_00849.a` AS `t1_00849.a`
FROM
(
SELECT
a AS `--t1_00849.a`,
b,
t2_00849.a AS `--t2_00849.a`,
t2_00849.b
FROM t1_00849
ALL INNER JOIN t2_00849 ON `--t1_00849.a` = `--t2_00849.a`
) AS `--.s`
CROSS JOIN t3_00849
SELECT * FROM t1, t2
1 1 1 1
1 1 1 \N
......
SELECT a\nFROM t1\nCROSS JOIN t2
SELECT a\nFROM t1\nALL INNER JOIN t2 ON a = t2.a\nWHERE a = t2.a
SELECT a\nFROM t1\nALL INNER JOIN t2 ON b = t2.b\nWHERE b = t2.b
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`\n) AS `--.s`\nALL INNER JOIN t3 ON `--t1.a` = a\nWHERE (`--t1.a` = `--t2.a`) AND (`--t1.a` = a)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n b AS `--t1.b`,\n a AS `--t1.a`,\n t2.b AS `--t2.b`\n FROM t1\n ALL INNER JOIN t2 ON `--t1.b` = `--t2.b`\n) AS `--.s`\nALL INNER JOIN t3 ON `--t1.b` = b\nWHERE (`--t1.b` = `--t2.b`) AND (`--t1.b` = b)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n `--t1.a`,\n `--t2.a`,\n a AS `--t3.a`\n FROM \n (\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`\n ) AS `--.s`\n ALL INNER JOIN t3 ON `--t1.a` = `--t3.a`\n) AS `--.s`\nALL INNER JOIN t4 ON `--t1.a` = a\nWHERE (`--t1.a` = `--t2.a`) AND (`--t1.a` = `--t3.a`) AND (`--t1.a` = a)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n `--t1.b`,\n `--t1.a`,\n `--t2.b`,\n b AS `--t3.b`\n FROM \n (\n SELECT \n b AS `--t1.b`,\n a AS `--t1.a`,\n t2.b AS `--t2.b`\n FROM t1\n ALL INNER JOIN t2 ON `--t1.b` = `--t2.b`\n ) AS `--.s`\n ALL INNER JOIN t3 ON `--t1.b` = `--t3.b`\n) AS `--.s`\nALL INNER JOIN t4 ON `--t1.b` = b\nWHERE (`--t1.b` = `--t2.b`) AND (`--t1.b` = `--t3.b`) AND (`--t1.b` = b)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n `--t1.a`,\n `--t2.a`,\n a AS `--t3.a`\n FROM \n (\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n ALL INNER JOIN t2 ON `--t2.a` = `--t1.a`\n ) AS `--.s`\n ALL INNER JOIN t3 ON `--t2.a` = `--t3.a`\n) AS `--.s`\nALL INNER JOIN t4 ON `--t2.a` = a\nWHERE (`--t2.a` = `--t1.a`) AND (`--t2.a` = `--t3.a`) AND (`--t2.a` = a)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n `--t1.a`,\n `--t2.a`,\n a AS `--t3.a`\n FROM \n (\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n CROSS JOIN t2\n ) AS `--.s`\n ALL INNER JOIN t3 ON (`--t3.a` = `--t1.a`) AND (`--t3.a` = `--t2.a`)\n) AS `--.s`\nALL INNER JOIN t4 ON `--t3.a` = a\nWHERE (`--t3.a` = `--t1.a`) AND (`--t3.a` = `--t2.a`) AND (`--t3.a` = a)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n `--t1.a`,\n `--t2.a`,\n a AS `--t3.a`\n FROM \n (\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n CROSS JOIN t2\n ) AS `--.s`\n CROSS JOIN t3\n) AS `--.s`\nALL INNER JOIN t4 ON (a = `--t1.a`) AND (a = `--t2.a`) AND (a = `--t3.a`)\nWHERE (a = `--t1.a`) AND (a = `--t2.a`) AND (a = `--t3.a`)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n `--t1.a`,\n `--t2.a`,\n a AS `--t3.a`\n FROM \n (\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`\n ) AS `--.s`\n ALL INNER JOIN t3 ON `--t2.a` = `--t3.a`\n) AS `--.s`\nALL INNER JOIN t4 ON `--t3.a` = a\nWHERE (`--t1.a` = `--t2.a`) AND (`--t2.a` = `--t3.a`) AND (`--t3.a` = a)
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT `--t1.a`\n FROM \n (\n SELECT a AS `--t1.a`\n FROM t1\n CROSS JOIN t2\n ) AS `--.s`\n CROSS JOIN t3\n) AS `--.s`\nCROSS JOIN t4
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT `--t1.a`\n FROM \n (\n SELECT a AS `--t1.a`\n FROM t1\n CROSS JOIN t2\n ) AS `--.s`\n CROSS JOIN t3\n) AS `--.s`\nCROSS JOIN t4
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT a AS `--t1.a`\n FROM t1\n CROSS JOIN t2\n) AS `--.s`\nCROSS JOIN t3
SELECT `--t1.a` AS `t1.a`\nFROM \n(\n SELECT \n a AS `--t1.a`,\n t2.a AS `--t2.a`\n FROM t1\n ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`\n) AS `--.s`\nCROSS JOIN t3
SELECT a
FROM t1
CROSS JOIN t2
SELECT a
FROM t1
ALL INNER JOIN t2 ON a = t2.a
WHERE a = t2.a
SELECT a
FROM t1
ALL INNER JOIN t2 ON b = t2.b
WHERE b = t2.b
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`
) AS `--.s`
ALL INNER JOIN t3 ON `--t1.a` = a
WHERE (`--t1.a` = `--t2.a`) AND (`--t1.a` = a)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
b AS `--t1.b`,
a AS `--t1.a`,
t2.b AS `--t2.b`
FROM t1
ALL INNER JOIN t2 ON `--t1.b` = `--t2.b`
) AS `--.s`
ALL INNER JOIN t3 ON `--t1.b` = b
WHERE (`--t1.b` = `--t2.b`) AND (`--t1.b` = b)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
`--t1.a`,
`--t2.a`,
a AS `--t3.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`
) AS `--.s`
ALL INNER JOIN t3 ON `--t1.a` = `--t3.a`
) AS `--.s`
ALL INNER JOIN t4 ON `--t1.a` = a
WHERE (`--t1.a` = `--t2.a`) AND (`--t1.a` = `--t3.a`) AND (`--t1.a` = a)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
`--t1.b`,
`--t1.a`,
`--t2.b`,
b AS `--t3.b`
FROM
(
SELECT
b AS `--t1.b`,
a AS `--t1.a`,
t2.b AS `--t2.b`
FROM t1
ALL INNER JOIN t2 ON `--t1.b` = `--t2.b`
) AS `--.s`
ALL INNER JOIN t3 ON `--t1.b` = `--t3.b`
) AS `--.s`
ALL INNER JOIN t4 ON `--t1.b` = b
WHERE (`--t1.b` = `--t2.b`) AND (`--t1.b` = `--t3.b`) AND (`--t1.b` = b)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
`--t1.a`,
`--t2.a`,
a AS `--t3.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
ALL INNER JOIN t2 ON `--t2.a` = `--t1.a`
) AS `--.s`
ALL INNER JOIN t3 ON `--t2.a` = `--t3.a`
) AS `--.s`
ALL INNER JOIN t4 ON `--t2.a` = a
WHERE (`--t2.a` = `--t1.a`) AND (`--t2.a` = `--t3.a`) AND (`--t2.a` = a)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
`--t1.a`,
`--t2.a`,
a AS `--t3.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
CROSS JOIN t2
) AS `--.s`
ALL INNER JOIN t3 ON (`--t3.a` = `--t1.a`) AND (`--t3.a` = `--t2.a`)
) AS `--.s`
ALL INNER JOIN t4 ON `--t3.a` = a
WHERE (`--t3.a` = `--t1.a`) AND (`--t3.a` = `--t2.a`) AND (`--t3.a` = a)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
`--t1.a`,
`--t2.a`,
a AS `--t3.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
CROSS JOIN t2
) AS `--.s`
CROSS JOIN t3
) AS `--.s`
ALL INNER JOIN t4 ON (a = `--t1.a`) AND (a = `--t2.a`) AND (a = `--t3.a`)
WHERE (a = `--t1.a`) AND (a = `--t2.a`) AND (a = `--t3.a`)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
`--t1.a`,
`--t2.a`,
a AS `--t3.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`
) AS `--.s`
ALL INNER JOIN t3 ON `--t2.a` = `--t3.a`
) AS `--.s`
ALL INNER JOIN t4 ON `--t3.a` = a
WHERE (`--t1.a` = `--t2.a`) AND (`--t2.a` = `--t3.a`) AND (`--t3.a` = a)
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT `--t1.a`
FROM
(
SELECT a AS `--t1.a`
FROM t1
CROSS JOIN t2
) AS `--.s`
CROSS JOIN t3
) AS `--.s`
CROSS JOIN t4
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT `--t1.a`
FROM
(
SELECT a AS `--t1.a`
FROM t1
CROSS JOIN t2
) AS `--.s`
CROSS JOIN t3
) AS `--.s`
CROSS JOIN t4
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT a AS `--t1.a`
FROM t1
CROSS JOIN t2
) AS `--.s`
CROSS JOIN t3
SELECT `--t1.a` AS `t1.a`
FROM
(
SELECT
a AS `--t1.a`,
t2.a AS `--t2.a`
FROM t1
ALL INNER JOIN t2 ON `--t1.a` = `--t2.a`
) AS `--.s`
CROSS JOIN t3
SELECT * FROM t1, t2
1 1 1 1
1 1 1 \N
......
SELECT 1\nWHERE 0
SELECT 1
SELECT 1\nWHERE 0
SELECT 1\nWHERE 1 IN (\n(\n SELECT arrayJoin([1, 2, 3])\n) AS subquery)
SELECT 1\nWHERE NOT ignore()
WHERE 0
SELECT 1
SELECT 1
WHERE 0
SELECT 1
WHERE 1 IN (
(
SELECT arrayJoin([1, 2, 3])
) AS subquery)
SELECT 1
WHERE NOT ignore()
SELECT \n k,\n v,\n d,\n i\nFROM \n(\n SELECT \n t.1 AS k,\n t.2 AS v,\n runningDifference(v) AS d,\n runningDifference(cityHash64(t.1)) AS i\n FROM \n (\n SELECT arrayJoin([(\'a\', 1), (\'a\', 2), (\'a\', 3), (\'b\', 11), (\'b\', 13), (\'b\', 15)]) AS t\n )\n)\nWHERE i = 0
SELECT
k,
v,
d,
i
FROM
(
SELECT
t.1 AS k,
t.2 AS v,
runningDifference(v) AS d,
runningDifference(cityHash64(t.1)) AS i
FROM
(
SELECT arrayJoin([(\'a\', 1), (\'a\', 2), (\'a\', 3), (\'b\', 11), (\'b\', 13), (\'b\', 15)]) AS t
)
)
WHERE i = 0
a 1 0 0
a 2 1 0
a 3 1 0
b 13 2 0
b 15 2 0
SELECT \n co,\n co2,\n co3,\n num\nFROM \n(\n SELECT \n co,\n co2,\n co3,\n count() AS num\n FROM \n (\n SELECT \n 1 AS co,\n 2 AS co2,\n 3 AS co3\n )\n GROUP BY \n co,\n co2,\n co3\n WITH CUBE\n HAVING (co2 != 2) AND (co != 0)\n)\nWHERE (co != 0) AND (co2 != 2)
SELECT
co,
co2,
co3,
num
FROM
(
SELECT
co,
co2,
co3,
count() AS num
FROM
(
SELECT
1 AS co,
2 AS co2,
3 AS co3
)
GROUP BY
co,
co2,
co3
WITH CUBE
HAVING (co2 != 2) AND (co != 0)
)
WHERE (co != 0) AND (co2 != 2)
1 0 3 1
1 0 0 1
SELECT alias AS name\nFROM \n(\n SELECT name AS alias\n FROM system.settings\n WHERE alias = \'enable_optimize_predicate_expression\'\n)\nANY INNER JOIN \n(\n SELECT name\n FROM system.settings\n) USING (name)\nWHERE name = \'enable_optimize_predicate_expression\'
SELECT alias AS name
FROM
(
SELECT name AS alias
FROM system.settings
WHERE alias = \'enable_optimize_predicate_expression\'
)
ANY INNER JOIN
(
SELECT name
FROM system.settings
) USING (name)
WHERE name = \'enable_optimize_predicate_expression\'
enable_optimize_predicate_expression
1 val11 val21 val31
SELECT ccc\nFROM \n(\n SELECT 1 AS ccc\n WHERE 0\n UNION ALL\n SELECT ccc\n FROM \n (\n SELECT 2 AS ccc\n )\n ANY INNER JOIN \n (\n SELECT 2 AS ccc\n ) USING (ccc)\n WHERE ccc > 1\n)\nWHERE ccc > 1
SELECT ccc
FROM
(
SELECT 1 AS ccc
WHERE 0
UNION ALL
SELECT ccc
FROM
(
SELECT 2 AS ccc
)
ANY INNER JOIN
(
SELECT 2 AS ccc
) USING (ccc)
WHERE ccc > 1
)
WHERE ccc > 1
2
SELECT \n ts,\n id,\n id_b,\n b.ts,\n b.id,\n id_c\nFROM \n(\n SELECT \n ts,\n id,\n id_b\n FROM A\n WHERE ts <= toDateTime(\'1970-01-01 03:00:00\')\n) AS a\nALL LEFT JOIN B AS b ON b.id = id_b\nWHERE ts <= toDateTime(\'1970-01-01 03:00:00\')
SELECT \n ts AS `--a.ts`,\n id AS `--a.id`,\n id_b AS `--a.id_b`,\n b.ts AS `--b.ts`,\n b.id AS `--b.id`,\n id_c AS `--b.id_c`\nFROM \n(\n SELECT \n ts,\n id,\n id_b\n FROM A\n WHERE ts <= toDateTime(\'1970-01-01 03:00:00\')\n) AS a\nALL LEFT JOIN B AS b ON `--b.id` = `--a.id_b`\nWHERE `--a.ts` <= toDateTime(\'1970-01-01 03:00:00\')
SELECT
ts,
id,
id_b,
b.ts,
b.id,
id_c
FROM
(
SELECT
ts,
id,
id_b
FROM A
WHERE ts <= toDateTime(\'1970-01-01 03:00:00\')
) AS a
ALL LEFT JOIN B AS b ON b.id = id_b
WHERE ts <= toDateTime(\'1970-01-01 03:00:00\')
SELECT
ts AS `--a.ts`,
id AS `--a.id`,
id_b AS `--a.id_b`,
b.ts AS `--b.ts`,
b.id AS `--b.id`,
id_c AS `--b.id_c`
FROM
(
SELECT
ts,
id,
id_b
FROM A
WHERE ts <= toDateTime(\'1970-01-01 03:00:00\')
) AS a
ALL LEFT JOIN B AS b ON `--b.id` = `--a.id_b`
WHERE `--a.ts` <= toDateTime(\'1970-01-01 03:00:00\')
2 3
3 4
4 5
......@@ -22,8 +128,33 @@ SELECT \n ts AS `--a.ts`,\n id AS `--a.id`,\n id_b AS `--a.id_b`,\n
4 0
2 3
4 5
SELECT dummy\nFROM \n(\n SELECT dummy\n FROM system.one\n WHERE arrayMap(x -> (x + 1), [dummy]) = [1]\n)\nWHERE arrayMap(x -> (x + 1), [dummy]) = [1]
SELECT dummy
FROM
(
SELECT dummy
FROM system.one
WHERE arrayMap(x -> (x + 1), [dummy]) = [1]
)
WHERE arrayMap(x -> (x + 1), [dummy]) = [1]
0
SELECT \n id,\n value,\n value_1\nFROM \n(\n SELECT \n 1 AS id,\n 2 AS value\n)\nALL INNER JOIN \n(\n SELECT \n 1 AS id,\n 3 AS value_1\n) USING (id)\nWHERE arrayMap(x -> ((x + value) + value_1), [1]) = [6]
SELECT
id,
value,
value_1
FROM
(
SELECT
1 AS id,
2 AS value
)
ALL INNER JOIN
(
SELECT
1 AS id,
3 AS value_1
) USING (id)
WHERE arrayMap(x -> ((x + value) + value_1), [1]) = [6]
1 2 3
SELECT dummy\nFROM system.one\nWHERE (dummy > 0) AND (dummy < 0)
SELECT dummy
FROM system.one
WHERE (dummy > 0) AND (dummy < 0)
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT *\n FROM default.test\n HAVING id = 1\n) AS test_view\nWHERE id = 1
SELECT \n date,\n id,\n name,\n value\nFROM \n(\n SELECT *\n FROM default.test\n HAVING id = 2\n) AS test_view\nWHERE id = 2
SELECT id\nFROM \n(\n SELECT *\n FROM default.test\n HAVING id = 1\n) AS test_view\nWHERE id = 1
SELECT id\nFROM \n(\n SELECT *\n FROM default.test\n HAVING id = 1\n) AS s\nWHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT *
FROM default.test
HAVING id = 1
) AS test_view
WHERE id = 1
SELECT
date,
id,
name,
value
FROM
(
SELECT *
FROM default.test
HAVING id = 2
) AS test_view
WHERE id = 2
SELECT id
FROM
(
SELECT *
FROM default.test
HAVING id = 1
) AS test_view
WHERE id = 1
SELECT id
FROM
(
SELECT *
FROM default.test
HAVING id = 1
) AS s
WHERE id = 1
SELECT \n k,\n r.k,\n name\nFROM n\nALL INNER JOIN r ON k = r.k\nWHERE (k = r.k) AND (name = \'A\')
SELECT \n k,\n r.k,\n name\nFROM n\nALL INNER JOIN r ON k = r.k\nWHERE (k = r.k) AND (name LIKE \'A%\')
SELECT \n k,\n r.k,\n name\nFROM n\nALL INNER JOIN r ON k = r.k\nWHERE (k = r.k) AND (name NOT LIKE \'A%\')
SELECT
k,
r.k,
name
FROM n
ALL INNER JOIN r ON k = r.k
WHERE (k = r.k) AND (name = \'A\')
SELECT
k,
r.k,
name
FROM n
ALL INNER JOIN r ON k = r.k
WHERE (k = r.k) AND (name LIKE \'A%\')
SELECT
k,
r.k,
name
FROM n
ALL INNER JOIN r ON k = r.k
WHERE (k = r.k) AND (name NOT LIKE \'A%\')
......@@ -10,6 +10,8 @@
24
27
2
SELECT uniqExactIf(number % 10, (number % 5) = 2)\nFROM numbers(10000)
SELECT uniqExactIf(number % 10, (number % 5) = 2)
FROM numbers(10000)
9
SELECT sumDistinctIf(number % 10, (number % 5) = 2)\nFROM numbers(10000)
SELECT sumDistinctIf(number % 10, (number % 5) = 2)
FROM numbers(10000)
SELECT \n sum(n + 1),\n sum(1 + n),\n sum(n - 1),\n sum(1 - n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(n) * 2,\n 2 * sum(n),\n sum(n) / 2,\n sum(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(n) + 1,\n 1 + min(n),\n min(n) - 1,\n 1 - min(n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(n) * 2,\n 2 * min(n),\n min(n) / 2,\n min(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(n) + 1,\n 1 + max(n),\n max(n) - 1,\n 1 - max(n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(n) * 2,\n 2 * max(n),\n max(n) / 2,\n max(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(n + -1),\n sum(-1 + n),\n sum(n - -1),\n sum(-1 - n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(n) * -2,\n -2 * sum(n),\n sum(n) / -2,\n sum(-1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(n) + -1,\n -1 + min(n),\n min(n) - -1,\n -1 - min(n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(n) * -2,\n -2 * max(n),\n max(n) / -2,\n min(-1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(n) + -1,\n -1 + max(n),\n max(n) - -1,\n -1 - max(n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(n) * -2,\n -2 * min(n),\n min(n) / -2,\n max(-1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(abs(2) + 1),\n sum(abs(2) + n),\n sum(n - abs(2)),\n sum(1 - abs(2))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(abs(2)) * 2,\n sum(abs(2) * n),\n sum(n / abs(2)),\n sum(1 / abs(2))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(abs(2)) + 1,\n min(abs(2) + n),\n min(n - abs(2)),\n 1 - min(abs(2))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(abs(2)) * 2,\n min(abs(2) * n),\n min(n / abs(2)),\n min(1 / abs(2))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(abs(2)) + 1,\n max(abs(2) + n),\n max(n - abs(2)),\n 1 - max(abs(2))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(abs(2)) * 2,\n max(abs(2) * n),\n max(n / abs(2)),\n max(1 / abs(2))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(abs(n) + 1),\n sum(abs(n) + n),\n sum(n - abs(n)),\n sum(1 - abs(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(abs(n)) * 2,\n sum(abs(n) * n),\n sum(n / abs(n)),\n sum(1 / abs(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(abs(n)) + 1,\n min(abs(n) + n),\n min(n - abs(n)),\n 1 - min(abs(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(abs(n)) * 2,\n min(abs(n) * n),\n min(n / abs(n)),\n min(1 / abs(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(abs(n)) + 1,\n max(abs(n) + n),\n max(n - abs(n)),\n 1 - max(abs(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(abs(n)) * 2,\n max(abs(n) * n),\n max(n / abs(n)),\n max(1 / abs(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum((n * n) + 1),\n sum(1 + (n * n)),\n sum((n * n) - 1),\n sum(1 - (n * n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(n * n) * 2,\n sum((2 * n) * n),\n sum(n * n) / 2,\n sum((1 / n) * n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(n * n) + 1,\n 1 + min(n * n),\n min(n * n) - 1,\n 1 - min(n * n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n min(n * n) * 2,\n min((2 * n) * n),\n min(n * n) / 2,\n min((1 / n) * n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(n * n) + 1,\n 1 + max(n * n),\n max(n * n) - 1,\n 1 - max(n * n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n max(n * n) * 2,\n max((2 * n) * n),\n max(n * n) / 2,\n max((1 / n) * n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum((1 + n) + 1),\n sum((1 + 1) + n),\n sum((1 + n) - 1),\n sum((1 + 1) - n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum(1 + (n * 2)),\n sum(1 + (2 * n)),\n sum(1 + (n / 2)),\n sum(1 + (1 / n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (1 + min(n)) + 1,\n min((1 + 1) + n),\n (1 + min(n)) - 1,\n min((1 + 1) - n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n 1 + min(n * 2),\n 1 + min(2 * n),\n 1 + min(n / 2),\n 1 + min(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (1 + max(n)) + 1,\n max((1 + 1) + n),\n (1 + max(n)) - 1,\n max((1 + 1) - n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n 1 + max(n * 2),\n 1 + max(2 * n),\n 1 + max(n / 2),\n 1 + max(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n sum((n + -1) + -1),\n sum((-1 + n) + -1),\n sum((n - -1) + -1),\n sum((-1 - n) + -1)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (sum(n) * -2) * -1,\n (-2 * sum(n)) * -1,\n (sum(n) / -2) / -1,\n sum(-1 / n) / -1\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (min(n) + -1) + -1,\n (-1 + min(n)) + -1,\n (min(n) - -1) + -1,\n (-1 - min(n)) + -1\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (min(n) * -2) * -1,\n (-2 * min(n)) * -1,\n (min(n) / -2) / -1,\n max(-1 / n) / -1\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (max(n) + -1) + -1,\n (-1 + max(n)) + -1,\n (max(n) - -1) + -1,\n (-1 - max(n)) + -1\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT \n (max(n) * -2) * -1,\n (-2 * max(n)) * -1,\n (max(n) / -2) / -1,\n min(-1 / n) / -1\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT ((sum(n + 1) + sum(1 + n)) + sum(n - 1)) + sum(1 - n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT (((sum(n) * 2) + (2 * sum(n))) + (sum(n) / 2)) + sum(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT (((min(n) + 1) + (1 + min(n))) + (min(n) - 1)) + (1 - min(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT (((min(n) * 2) + (2 * min(n))) + (min(n) / 2)) + min(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT (((max(n) + 1) + (1 + max(n))) + (max(n) - 1)) + (1 - max(n))\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT (((max(n) * 2) + (2 * max(n))) + (max(n) / 2)) + max(1 / n)\nFROM \n(\n SELECT number AS n\n FROM numbers(10)\n)
SELECT
sum(n + 1),
sum(1 + n),
sum(n - 1),
sum(1 - n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(n) * 2,
2 * sum(n),
sum(n) / 2,
sum(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(n) + 1,
1 + min(n),
min(n) - 1,
1 - min(n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(n) * 2,
2 * min(n),
min(n) / 2,
min(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(n) + 1,
1 + max(n),
max(n) - 1,
1 - max(n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(n) * 2,
2 * max(n),
max(n) / 2,
max(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(n + -1),
sum(-1 + n),
sum(n - -1),
sum(-1 - n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(n) * -2,
-2 * sum(n),
sum(n) / -2,
sum(-1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(n) + -1,
-1 + min(n),
min(n) - -1,
-1 - min(n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(n) * -2,
-2 * max(n),
max(n) / -2,
min(-1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(n) + -1,
-1 + max(n),
max(n) - -1,
-1 - max(n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(n) * -2,
-2 * min(n),
min(n) / -2,
max(-1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(abs(2) + 1),
sum(abs(2) + n),
sum(n - abs(2)),
sum(1 - abs(2))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(abs(2)) * 2,
sum(abs(2) * n),
sum(n / abs(2)),
sum(1 / abs(2))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(abs(2)) + 1,
min(abs(2) + n),
min(n - abs(2)),
1 - min(abs(2))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(abs(2)) * 2,
min(abs(2) * n),
min(n / abs(2)),
min(1 / abs(2))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(abs(2)) + 1,
max(abs(2) + n),
max(n - abs(2)),
1 - max(abs(2))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(abs(2)) * 2,
max(abs(2) * n),
max(n / abs(2)),
max(1 / abs(2))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(abs(n) + 1),
sum(abs(n) + n),
sum(n - abs(n)),
sum(1 - abs(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(abs(n)) * 2,
sum(abs(n) * n),
sum(n / abs(n)),
sum(1 / abs(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(abs(n)) + 1,
min(abs(n) + n),
min(n - abs(n)),
1 - min(abs(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(abs(n)) * 2,
min(abs(n) * n),
min(n / abs(n)),
min(1 / abs(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(abs(n)) + 1,
max(abs(n) + n),
max(n - abs(n)),
1 - max(abs(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(abs(n)) * 2,
max(abs(n) * n),
max(n / abs(n)),
max(1 / abs(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum((n * n) + 1),
sum(1 + (n * n)),
sum((n * n) - 1),
sum(1 - (n * n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(n * n) * 2,
sum((2 * n) * n),
sum(n * n) / 2,
sum((1 / n) * n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(n * n) + 1,
1 + min(n * n),
min(n * n) - 1,
1 - min(n * n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
min(n * n) * 2,
min((2 * n) * n),
min(n * n) / 2,
min((1 / n) * n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(n * n) + 1,
1 + max(n * n),
max(n * n) - 1,
1 - max(n * n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
max(n * n) * 2,
max((2 * n) * n),
max(n * n) / 2,
max((1 / n) * n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum((1 + n) + 1),
sum((1 + 1) + n),
sum((1 + n) - 1),
sum((1 + 1) - n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum(1 + (n * 2)),
sum(1 + (2 * n)),
sum(1 + (n / 2)),
sum(1 + (1 / n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(1 + min(n)) + 1,
min((1 + 1) + n),
(1 + min(n)) - 1,
min((1 + 1) - n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
1 + min(n * 2),
1 + min(2 * n),
1 + min(n / 2),
1 + min(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(1 + max(n)) + 1,
max((1 + 1) + n),
(1 + max(n)) - 1,
max((1 + 1) - n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
1 + max(n * 2),
1 + max(2 * n),
1 + max(n / 2),
1 + max(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
sum((n + -1) + -1),
sum((-1 + n) + -1),
sum((n - -1) + -1),
sum((-1 - n) + -1)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(sum(n) * -2) * -1,
(-2 * sum(n)) * -1,
(sum(n) / -2) / -1,
sum(-1 / n) / -1
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(min(n) + -1) + -1,
(-1 + min(n)) + -1,
(min(n) - -1) + -1,
(-1 - min(n)) + -1
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(min(n) * -2) * -1,
(-2 * min(n)) * -1,
(min(n) / -2) / -1,
max(-1 / n) / -1
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(max(n) + -1) + -1,
(-1 + max(n)) + -1,
(max(n) - -1) + -1,
(-1 - max(n)) + -1
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT
(max(n) * -2) * -1,
(-2 * max(n)) * -1,
(max(n) / -2) / -1,
min(-1 / n) / -1
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT ((sum(n + 1) + sum(1 + n)) + sum(n - 1)) + sum(1 - n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT (((sum(n) * 2) + (2 * sum(n))) + (sum(n) / 2)) + sum(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT (((min(n) + 1) + (1 + min(n))) + (min(n) - 1)) + (1 - min(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT (((min(n) * 2) + (2 * min(n))) + (min(n) / 2)) + min(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT (((max(n) + 1) + (1 + max(n))) + (max(n) - 1)) + (1 - max(n))
FROM
(
SELECT number AS n
FROM numbers(10)
)
SELECT (((max(n) * 2) + (2 * max(n))) + (max(n) / 2)) + max(1 / n)
FROM
(
SELECT number AS n
FROM numbers(10)
)
55 55 35 -35
90 90 22.5 inf
1 1 -1 1
......
......@@ -22,11 +22,35 @@
3465736.595946905
3465735.2096525617
3465735.9027997428
SELECT max(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n number % 2,\n number % 3,\n ((number % 2) + (number % 3)) % 2\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY number % 5\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number % 2) * (number % 3),\n number % 3\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n number % 3,\n number % 2\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number % 2) % 3,\n number % 2\nORDER BY k ASC
SELECT max(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
number % 2,
number % 3,
((number % 2) + (number % 3)) % 2
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY number % 5
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
(number % 2) * (number % 3),
number % 3
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
number % 3,
number % 2
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
(number % 2) % 3,
number % 2
ORDER BY k ASC
6931467.646716369
6931468.33986355
6931469.0330107305
......@@ -51,8 +75,35 @@ SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number
3465736.595946905
3465735.2096525617
3465735.9027997428
SELECT max(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n number % 2,\n number % 3,\n ((number % 2) + (number % 3)) % 2\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n number % 5,\n (number % 5) * (number % 5)\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number % 2) * (number % 3),\n number % 3\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number % 2) * (number % 3),\n number % 3,\n number % 2\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number % 2) % 3,\n number % 2\nORDER BY k ASC
SELECT max(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
number % 2,
number % 3,
((number % 2) + (number % 3)) % 2
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
number % 5,
(number % 5) * (number % 5)
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
(number % 2) * (number % 3),
number % 3
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
(number % 2) * (number % 3),
number % 3,
number % 2
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
(number % 2) % 3,
number % 2
ORDER BY k ASC
......@@ -7,9 +7,23 @@
0
1
4
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n number % 3,\n number % 2\nHAVING avg(log(2) * number) > 3465735.3\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nWHERE ((number % 5) * (number % 5)) < 5\nGROUP BY number % 5\nORDER BY k ASC
SELECT (number % 5) * (number % 5) AS k\nFROM numbers(10000000)\nWHERE ((number % 5) * (number % 5)) < 5\nGROUP BY number % 5\nORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
number % 3,
number % 2
HAVING avg(log(2) * number) > 3465735.3
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
WHERE ((number % 5) * (number % 5)) < 5
GROUP BY number % 5
ORDER BY k ASC
SELECT (number % 5) * (number % 5) AS k
FROM numbers(10000000)
WHERE ((number % 5) * (number % 5)) < 5
GROUP BY number % 5
ORDER BY k ASC
3465735.9027997246
3465735.902799725
3465736.595946905
......@@ -19,6 +33,25 @@ SELECT (number % 5) * (number % 5) AS k\nFROM numbers(10000000)\nWHERE ((number
0
1
4
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nGROUP BY \n (number % 2) * (number % 3),\n number % 3,\n number % 2\nHAVING avg(log(2) * number) > 3465735.3\nORDER BY k ASC
SELECT avg(log(2) * number) AS k\nFROM numbers(10000000)\nWHERE ((number % 5) * (number % 5)) < 5\nGROUP BY \n number % 5,\n (number % 5) * (number % 5)\nORDER BY k ASC
SELECT (number % 5) * (number % 5) AS k\nFROM numbers(10000000)\nWHERE ((number % 5) * (number % 5)) < 5\nGROUP BY \n number % 5,\n (number % 5) * (number % 5)\nORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
GROUP BY
(number % 2) * (number % 3),
number % 3,
number % 2
HAVING avg(log(2) * number) > 3465735.3
ORDER BY k ASC
SELECT avg(log(2) * number) AS k
FROM numbers(10000000)
WHERE ((number % 5) * (number % 5)) < 5
GROUP BY
number % 5,
(number % 5) * (number % 5)
ORDER BY k ASC
SELECT (number % 5) * (number % 5) AS k
FROM numbers(10000000)
WHERE ((number % 5) * (number % 5)) < 5
GROUP BY
number % 5,
(number % 5) * (number % 5)
ORDER BY k ASC
SELECT number\nFROM \n(\n SELECT number\n FROM \n (\n SELECT DISTINCT number\n FROM numbers(3)\n )\n)\nORDER BY number ASC
SELECT number
FROM
(
SELECT number
FROM
(
SELECT DISTINCT number
FROM numbers(3)
)
)
ORDER BY number ASC
0
1
2
SELECT DISTINCT number\nFROM \n(\n SELECT DISTINCT number\n FROM \n (\n SELECT DISTINCT number\n FROM numbers(3)\n ORDER BY number ASC\n )\n ORDER BY number ASC\n)\nORDER BY number ASC
SELECT DISTINCT number
FROM
(
SELECT DISTINCT number
FROM
(
SELECT DISTINCT number
FROM numbers(3)
ORDER BY number ASC
)
ORDER BY number ASC
)
ORDER BY number ASC
0
1
2
SELECT number\nFROM \n(\n SELECT DISTINCT number\n FROM \n (\n SELECT DISTINCT number % 2 AS number\n FROM numbers(3)\n )\n)\nORDER BY number ASC
SELECT number
FROM
(
SELECT DISTINCT number
FROM
(
SELECT DISTINCT number % 2 AS number
FROM numbers(3)
)
)
ORDER BY number ASC
0
1
SELECT DISTINCT number\nFROM \n(\n SELECT DISTINCT number\n FROM \n (\n SELECT DISTINCT number % 2 AS number\n FROM numbers(3)\n ORDER BY number ASC\n )\n ORDER BY number ASC\n)\nORDER BY number ASC
SELECT DISTINCT number
FROM
(
SELECT DISTINCT number
FROM
(
SELECT DISTINCT number % 2 AS number
FROM numbers(3)
ORDER BY number ASC
)
ORDER BY number ASC
)
ORDER BY number ASC
0
1
......@@ -47,10 +47,39 @@
24
0
0
SELECT \n number % 2 AS a,\n number % 3 AS b\nFROM numbers(10000000)\nGROUP BY \n number % 2,\n number % 3\nORDER BY \n min(number % 2) AS a ASC,\n max(number % 3) AS b ASC
SELECT \n number % 2 AS a,\n number % 3 AS b\nFROM numbers(10000000)\nGROUP BY \n number % 2,\n number % 3\nORDER BY \n any(number % 2) AS a ASC,\n anyLast(number % 3) AS b ASC
SELECT (number % 5) * (number % 7) AS a\nFROM numbers(10000000)\nGROUP BY \n number % 7,\n number % 5\nORDER BY max((number % 5) * (number % 7)) AS a ASC
SELECT foo\nFROM \n(\n SELECT number AS foo\n FROM numbers(1)\n GROUP BY number\n)
SELECT
number % 2 AS a,
number % 3 AS b
FROM numbers(10000000)
GROUP BY
number % 2,
number % 3
ORDER BY
min(number % 2) AS a ASC,
max(number % 3) AS b ASC
SELECT
number % 2 AS a,
number % 3 AS b
FROM numbers(10000000)
GROUP BY
number % 2,
number % 3
ORDER BY
any(number % 2) AS a ASC,
anyLast(number % 3) AS b ASC
SELECT (number % 5) * (number % 7) AS a
FROM numbers(10000000)
GROUP BY
number % 7,
number % 5
ORDER BY max((number % 5) * (number % 7)) AS a ASC
SELECT foo
FROM
(
SELECT number AS foo
FROM numbers(1)
GROUP BY number
)
0 0
0 1
0 2
......@@ -99,7 +128,36 @@ SELECT foo\nFROM \n(\n SELECT number AS foo\n FROM numbers(1)\n GROUP B
20
24
0
SELECT \n min(number % 2) AS a,\n max(number % 3) AS b\nFROM numbers(10000000)\nGROUP BY \n number % 2,\n number % 3\nORDER BY \n a ASC,\n b ASC
SELECT \n any(number % 2) AS a,\n anyLast(number % 3) AS b\nFROM numbers(10000000)\nGROUP BY \n number % 2,\n number % 3\nORDER BY \n a ASC,\n b ASC
SELECT max((number % 5) * (number % 7)) AS a\nFROM numbers(10000000)\nGROUP BY \n number % 7,\n number % 5\nORDER BY a ASC
SELECT foo\nFROM \n(\n SELECT anyLast(number) AS foo\n FROM numbers(1)\n GROUP BY number\n)
SELECT
min(number % 2) AS a,
max(number % 3) AS b
FROM numbers(10000000)
GROUP BY
number % 2,
number % 3
ORDER BY
a ASC,
b ASC
SELECT
any(number % 2) AS a,
anyLast(number % 3) AS b
FROM numbers(10000000)
GROUP BY
number % 2,
number % 3
ORDER BY
a ASC,
b ASC
SELECT max((number % 5) * (number % 7)) AS a
FROM numbers(10000000)
GROUP BY
number % 7,
number % 5
ORDER BY a ASC
SELECT foo
FROM
(
SELECT anyLast(number) AS foo
FROM numbers(1)
GROUP BY number
)
9
SELECT any(number) + (any(number) * 2)\nFROM numbers(3, 10)
SELECT any(number) + (any(number) * 2)
FROM numbers(3, 10)
SELECT \n k,\n groupArrayMovingSum(v)\nFROM \n(\n SELECT \n k,\n dt,\n v\n FROM moving_sum_num\n ORDER BY \n k ASC,\n dt ASC\n)\nGROUP BY k\nORDER BY k ASC
SELECT
k,
groupArrayMovingSum(v)
FROM
(
SELECT
k,
dt,
v
FROM moving_sum_num
ORDER BY
k ASC,
dt ASC
)
GROUP BY k
ORDER BY k ASC
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册