mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 15:42:02 +00:00
Fixed code review issues
This commit is contained in:
parent
561d585100
commit
d083200d65
@ -285,7 +285,7 @@ void ReplaceColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatStat
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "REPLACE COLUMN TRANSFORMER id: " << format_state.getNodeId(this);
|
||||
|
||||
auto & replacements_nodes = getReplacements().getNodes();
|
||||
const auto & replacements_nodes = getReplacements().getNodes();
|
||||
size_t replacements_size = replacements_nodes.size();
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "REPLACEMENTS " << replacements_size << '\n';
|
||||
|
||||
@ -312,7 +312,7 @@ void ReplaceColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState
|
||||
{
|
||||
hash_state.update(static_cast<size_t>(getTransformerType()));
|
||||
|
||||
auto & replacement_expressions_nodes = getReplacements().getNodes();
|
||||
const auto & replacement_expressions_nodes = getReplacements().getNodes();
|
||||
size_t replacements_size = replacement_expressions_nodes.size();
|
||||
hash_state.update(replacements_size);
|
||||
|
||||
@ -338,7 +338,7 @@ ASTPtr ReplaceColumnTransformerNode::toASTImpl() const
|
||||
{
|
||||
auto ast_replace_transformer = std::make_shared<ASTColumnsReplaceTransformer>();
|
||||
|
||||
auto & replacement_expressions_nodes = getReplacements().getNodes();
|
||||
const auto & replacement_expressions_nodes = getReplacements().getNodes();
|
||||
size_t replacements_size = replacement_expressions_nodes.size();
|
||||
|
||||
ast_replace_transformer->children.reserve(replacements_size);
|
||||
|
@ -47,12 +47,12 @@ class AggregateFunctionsArithmericOperationsVisitor : public InDepthQueryTreeVis
|
||||
{
|
||||
public:
|
||||
/// Traverse tree bottom to top
|
||||
bool shouldTraverseTopToBottom() const
|
||||
static bool shouldTraverseTopToBottom()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void visitImpl(QueryTreeNodePtr & node)
|
||||
static void visitImpl(QueryTreeNodePtr & node)
|
||||
{
|
||||
auto * aggregate_function_node = node->as<FunctionNode>();
|
||||
if (!aggregate_function_node || !aggregate_function_node->isAggregateFunction())
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
return;
|
||||
|
||||
/// Check that query has only single node in projection
|
||||
auto projection_nodes = query_node->getProjection().getNodes();
|
||||
auto & projection_nodes = query_node->getProjection().getNodes();
|
||||
if (projection_nodes.size() != 1)
|
||||
return;
|
||||
|
||||
@ -43,7 +43,8 @@ public:
|
||||
if (!function_node)
|
||||
return;
|
||||
|
||||
if (Poco::toLower(function_node->getFunctionName()) != "countdistinct" && Poco::toLower(function_node->getFunctionName()) != "uniqexact")
|
||||
auto lower_function_name = Poco::toLower(function_node->getFunctionName());
|
||||
if (lower_function_name != "countdistinct" && lower_function_name != "uniqexact")
|
||||
return;
|
||||
|
||||
/// Check that `countDistinct` function has single COLUMN argument
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
function_name_lowercase = Poco::toLower(function_name);
|
||||
}
|
||||
|
||||
/// Replace countDistinct with countIfDistinct with countDistinctIf implementation
|
||||
/// Replace countIfDistinct with countDistinctIf implementation
|
||||
if (function_name_lowercase == "countifdistinct")
|
||||
{
|
||||
resolveAggregateOrWindowFunctionNode(*function_node, count_distinct_implementation_function_name + "If");
|
||||
@ -55,7 +55,7 @@ public:
|
||||
function_name_lowercase = Poco::toLower(function_name);
|
||||
}
|
||||
|
||||
/// Swap aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal
|
||||
/// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal
|
||||
if (function_name_lowercase.ends_with("ifdistinct"))
|
||||
{
|
||||
size_t prefix_length = function_name_lowercase.size() - strlen("ifdistinct");
|
||||
@ -93,10 +93,13 @@ public:
|
||||
static constexpr std::array<std::string_view, 4> suffixes_to_replace = {"MergeState", "Merge", "State", "If"};
|
||||
for (const auto & suffix : suffixes_to_replace)
|
||||
{
|
||||
if (!function_name_lowercase.ends_with(suffix))
|
||||
auto suffix_string_value = String(suffix);
|
||||
auto suffix_to_check = suffix_string_value + "OrNull";
|
||||
|
||||
if (!function_name.ends_with(suffix_to_check))
|
||||
continue;
|
||||
|
||||
auto updated_function_name = function_name_lowercase.substr(0, function_name_size - suffix.size()) + "OrNull" + String(suffix);
|
||||
auto updated_function_name = function_name.substr(0, function_name_size - suffix_to_check.size()) + "OrNull" + suffix_string_value;
|
||||
resolveAggregateOrWindowFunctionNode(*function_node, updated_function_name);
|
||||
function_name = function_node->getFunctionName();
|
||||
function_name_lowercase = Poco::toLower(function_name);
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
if (!function_node)
|
||||
return;
|
||||
|
||||
auto function_arguments_nodes = function_node->getArguments().getNodes();
|
||||
auto & function_arguments_nodes = function_node->getArguments().getNodes();
|
||||
size_t function_arguments_nodes_size = function_arguments_nodes.size();
|
||||
|
||||
if (function_arguments_nodes.empty() || function_arguments_nodes_size > 2)
|
||||
@ -67,7 +67,7 @@ public:
|
||||
{
|
||||
if (function_name == "length")
|
||||
{
|
||||
/// Replace `length(array_argument)` with `array_argument.length`
|
||||
/// Replace `length(array_argument)` with `array_argument.size0`
|
||||
column.name += ".size0";
|
||||
|
||||
node = std::make_shared<ColumnNode>(column, column_source);
|
||||
@ -78,15 +78,11 @@ public:
|
||||
column.name += ".size0";
|
||||
column.type = std::make_shared<DataTypeUInt64>();
|
||||
|
||||
auto equals_function = std::make_shared<FunctionNode>("equals");
|
||||
resolveOrdinaryFunctionNode(*equals_function, "equals");
|
||||
resolveOrdinaryFunctionNode(*function_node, "equals");
|
||||
|
||||
auto & equals_function_arguments = equals_function->getArguments().getNodes();
|
||||
equals_function_arguments.reserve(2);
|
||||
equals_function_arguments.push_back(std::make_shared<ColumnNode>(column, column_source));
|
||||
equals_function_arguments.push_back(std::make_shared<ConstantNode>(static_cast<UInt64>(0)));
|
||||
|
||||
node = std::move(equals_function);
|
||||
function_arguments_nodes.clear();
|
||||
function_arguments_nodes.push_back(std::make_shared<ColumnNode>(column, column_source));
|
||||
function_arguments_nodes.push_back(std::make_shared<ConstantNode>(static_cast<UInt64>(0)));
|
||||
}
|
||||
else if (function_name == "notEmpty")
|
||||
{
|
||||
@ -94,15 +90,11 @@ public:
|
||||
column.name += ".size0";
|
||||
column.type = std::make_shared<DataTypeUInt64>();
|
||||
|
||||
auto not_equals_function = std::make_shared<FunctionNode>("notEquals");
|
||||
resolveOrdinaryFunctionNode(*not_equals_function, "notEquals");
|
||||
resolveOrdinaryFunctionNode(*function_node, "notEquals");
|
||||
|
||||
auto & not_equals_function_arguments = not_equals_function->getArguments().getNodes();
|
||||
not_equals_function_arguments.reserve(2);
|
||||
not_equals_function_arguments.push_back(std::make_shared<ColumnNode>(column, column_source));
|
||||
not_equals_function_arguments.push_back(std::make_shared<ConstantNode>(static_cast<UInt64>(0)));
|
||||
|
||||
node = std::move(not_equals_function);
|
||||
function_arguments_nodes.clear();
|
||||
function_arguments_nodes.push_back(std::make_shared<ColumnNode>(column, column_source));
|
||||
function_arguments_nodes.push_back(std::make_shared<ConstantNode>(static_cast<UInt64>(0)));
|
||||
}
|
||||
}
|
||||
else if (column_type.isNullable())
|
||||
@ -120,24 +112,18 @@ public:
|
||||
column.name += ".null";
|
||||
column.type = std::make_shared<DataTypeUInt8>();
|
||||
|
||||
auto not_function = std::make_shared<FunctionNode>("not");
|
||||
resolveOrdinaryFunctionNode(*not_function, "not");
|
||||
resolveOrdinaryFunctionNode(*function_node, "not");
|
||||
|
||||
auto & not_function_arguments = not_function->getArguments().getNodes();
|
||||
not_function_arguments.push_back(std::make_shared<ColumnNode>(column, column_source));
|
||||
|
||||
node = std::move(not_function);
|
||||
function_arguments_nodes = {std::make_shared<ColumnNode>(column, column_source)};
|
||||
}
|
||||
}
|
||||
else if (column_type.isMap())
|
||||
{
|
||||
const auto & data_type_map = assert_cast<const DataTypeMap &>(*column.type);
|
||||
|
||||
if (function_name == "mapKeys")
|
||||
{
|
||||
/// Replace `mapKeys(map_argument)` with `map_argument.keys`
|
||||
column.name += ".keys";
|
||||
column.type = data_type_map.getKeyType();
|
||||
column.type = function_node->getResultType();
|
||||
|
||||
node = std::make_shared<ColumnNode>(column, column_source);
|
||||
}
|
||||
@ -145,7 +131,7 @@ public:
|
||||
{
|
||||
/// Replace `mapValues(map_argument)` with `map_argument.values`
|
||||
column.name += ".values";
|
||||
column.type = data_type_map.getValueType();
|
||||
column.type = function_node->getResultType();
|
||||
|
||||
node = std::make_shared<ColumnNode>(column, column_source);
|
||||
}
|
||||
@ -183,9 +169,7 @@ public:
|
||||
|
||||
column.name += '.';
|
||||
column.name += subcolumn_name;
|
||||
|
||||
size_t subcolumn_position = data_type_tuple.getPositionByName(subcolumn_name);
|
||||
column.type = data_type_tuple.getElement(subcolumn_position);
|
||||
column.type = function_node->getResultType();
|
||||
|
||||
node = std::make_shared<ColumnNode>(column, column_source);
|
||||
}
|
||||
@ -198,15 +182,9 @@ public:
|
||||
column.type = data_type_map.getKeyType();
|
||||
|
||||
auto has_function_argument = std::make_shared<ColumnNode>(column, column_source);
|
||||
auto has_function = std::make_shared<FunctionNode>("has");
|
||||
resolveOrdinaryFunctionNode(*has_function, "has");
|
||||
resolveOrdinaryFunctionNode(*function_node, "has");
|
||||
|
||||
auto & has_function_arguments = has_function->getArguments().getNodes();
|
||||
has_function_arguments.reserve(2);
|
||||
has_function_arguments.push_back(std::move(has_function_argument));
|
||||
has_function_arguments.push_back(std::move(function_arguments_nodes[1]));
|
||||
|
||||
node = std::move(has_function);
|
||||
function_arguments_nodes[0] = std::move(has_function_argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace
|
||||
class IfConstantConditionVisitor : public InDepthQueryTreeVisitor<IfConstantConditionVisitor>
|
||||
{
|
||||
public:
|
||||
void visitImpl(QueryTreeNodePtr & node)
|
||||
static void visitImpl(QueryTreeNodePtr & node)
|
||||
{
|
||||
auto * function_node = node->as<FunctionNode>();
|
||||
if (!function_node || (function_node->getFunctionName() != "if" && function_node->getFunctionName() != "multiIf"))
|
||||
|
@ -7,6 +7,7 @@ namespace DB
|
||||
|
||||
/** Convert `if` with constant condition or `multiIf` with single constant condition into true condition argument value
|
||||
* or false condition argument value.
|
||||
*
|
||||
* Example: SELECT if(1, true_value, false_value);
|
||||
* Result: SELECT true_value;
|
||||
*
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
return;
|
||||
|
||||
auto result_type = function_node->getResultType();
|
||||
function_node->resolveAsFunction(if_function_ptr, result_type);
|
||||
function_node->resolveAsFunction(if_function_ptr, std::move(result_type));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -5,7 +5,8 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Convert `multiIf` with single argument into `if`.
|
||||
/** Convert `multiIf` with single condition into `if`.
|
||||
*
|
||||
* Example: SELECT multiIf(x, 1, 0);
|
||||
* Result: SELECT if(x, 1, 0);
|
||||
*/
|
||||
@ -14,7 +15,7 @@ class MultiIfToIfPass final : public IQueryTreePass
|
||||
public:
|
||||
String getName() override { return "MultiIfToIf"; }
|
||||
|
||||
String getDescription() override { return "Optimize multiIf to if for single argument."; }
|
||||
String getDescription() override { return "Optimize multiIf with single condition to if."; }
|
||||
|
||||
void run(QueryTreeNodePtr query_tree_node, ContextPtr context) override;
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace
|
||||
class NormalizeCountVariantsVisitor : public InDepthQueryTreeVisitor<NormalizeCountVariantsVisitor>
|
||||
{
|
||||
public:
|
||||
void visitImpl(QueryTreeNodePtr & node)
|
||||
static void visitImpl(QueryTreeNodePtr & node)
|
||||
{
|
||||
auto * function_node = node->as<FunctionNode>();
|
||||
if (!function_node || !function_node->isAggregateFunction() || (function_node->getFunctionName() != "count" && function_node->getFunctionName() != "sum"))
|
||||
|
@ -7,7 +7,7 @@ namespace DB
|
||||
|
||||
/** Remove single literal argument from `count`. Convert `sum` with single `1` literal argument into `count`.
|
||||
*
|
||||
* Example: SELECT count(1)
|
||||
* Example: SELECT count(1);
|
||||
* Result: SELECT count();
|
||||
*
|
||||
* Example: SELECT sum(1);
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
|
||||
auto & query_limit_by_nodes = query_node->getLimitBy().getNodes();
|
||||
|
||||
for (auto & limit_by_node : query_node->getLimitBy().getNodes())
|
||||
for (auto & limit_by_node : query_limit_by_nodes)
|
||||
{
|
||||
auto [_, inserted] = unique_expressions_nodes_set.emplace(limit_by_node.get());
|
||||
if (inserted)
|
||||
@ -79,8 +79,6 @@ public:
|
||||
|
||||
query_limit_by_nodes = std::move(result_nodes);
|
||||
}
|
||||
|
||||
unique_expressions_nodes_set.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -6,6 +6,7 @@ namespace DB
|
||||
{
|
||||
|
||||
/** Eliminate duplicate columns from ORDER BY and LIMIT BY.
|
||||
*
|
||||
* Example: SELECT * FROM test_table ORDER BY id, id;
|
||||
* Result: SELECT * FROM test_table ORDER BY id;
|
||||
*
|
||||
|
@ -15,7 +15,7 @@ namespace
|
||||
class OrderByTupleEliminationVisitor : public InDepthQueryTreeVisitor<OrderByTupleEliminationVisitor>
|
||||
{
|
||||
public:
|
||||
void visitImpl(QueryTreeNodePtr & node)
|
||||
static void visitImpl(QueryTreeNodePtr & node)
|
||||
{
|
||||
auto * query_node = node->as<QueryNode>();
|
||||
if (!query_node || !query_node->hasOrderBy())
|
||||
|
@ -6,6 +6,7 @@ namespace DB
|
||||
{
|
||||
|
||||
/** Eliminate tuples from ORDER BY.
|
||||
*
|
||||
* Example: SELECT * FROM test_table ORDER BY (a, b);
|
||||
* Result: SELECT * FROM test_table ORDER BY a, b;
|
||||
*/
|
||||
|
@ -16,29 +16,34 @@ namespace DB
|
||||
* as aggregate or non aggregate function.
|
||||
* 4. All lambda expressions that are function arguments are resolved. Next passes can expect that LambaNode expression is resolved, and lambda has concrete arguments.
|
||||
* 5. All standalone lambda expressions are resolved. Next passes can expect that there will be no standalone LambaNode expressions in query.
|
||||
* 6. Constants are folded. Example: SELECT plus(1, 1). After step will be: SELECT 2.
|
||||
* 6. Constants are folded. Example: SELECT plus(1, 1).
|
||||
* Motivation for this, there are places in query tree that must contain constant:
|
||||
* Function parameters Example: SELECT quantile(0.5)(x).
|
||||
* Functions in which result type depends on constant expression. Example: cast(x, 'type_name').
|
||||
* Expressions that are part of LIMIT. Example: SELECT * FROM test_table LIMIT expr.
|
||||
* Function parameters. Example: SELECT quantile(0.5)(x).
|
||||
* Functions in which result type depends on constant expression argument. Example: cast(x, 'type_name').
|
||||
* Expressions that are part of LIMIT BY LIMIT, LIMIT BY OFFSET, LIMIT, OFFSET. Example: SELECT * FROM test_table LIMIT expr.
|
||||
* Window function window frame OFFSET begin and OFFSET end.
|
||||
*
|
||||
* 7. All scalar subqueries are evaluated.
|
||||
* TODO: Scalar subqueries must be evaluated only if they are part of query tree where we must have constant. This is currently not done
|
||||
* because execution layer does not support scalar subqueries execution.
|
||||
*
|
||||
* 8. For query node projection columns are calculated. Later passes cannot change type, display name of projection column, and cannot add or remove
|
||||
* 8. For query node.
|
||||
*
|
||||
* Projection columns are calculated. Later passes cannot change type, display name of projection column, and cannot add or remove
|
||||
* columns in projection section.
|
||||
* WITH and WINDOW sections are removed.
|
||||
*
|
||||
* 9. Query is validated. Parts that are validated:
|
||||
*
|
||||
* Constness of function parameters.
|
||||
* Constness of LIMIT and OFFSET.
|
||||
* Window functions frame. Constness of window functions frame begin OFFSET, end OFFSET.
|
||||
* In SELECT, ORDER BY only columns that are specified in GROUP BY keys after GROUP BY are used.
|
||||
* In query only columns that are specified in GROUP BY keys after GROUP BY are used.
|
||||
* GROUPING function arguments are specified in GROUP BY keys.
|
||||
* No GROUPING function if there is no GROUP BY.
|
||||
* No aggregate functions in JOIN TREE, WHERE, PREWHERE, GROUP BY and inside another aggregate functions.
|
||||
* GROUP BY modifiers CUBE, ROLLUP, GROUPING SETS and WITH TOTALS.
|
||||
* Table expression modifiers are validated for table and table function nodes in JOIN TREE.
|
||||
* Table expression modifiers are disabled for subqueries in JOIN TREE.
|
||||
* For JOIN, ARRAY JOIN subqueries and table functions must have alias (Can be changed using joined_subquery_requires_alias setting).
|
||||
*
|
||||
@ -53,7 +58,7 @@ namespace DB
|
||||
*
|
||||
* For function `in` and its variations arguments are resolved, but sets are not build.
|
||||
* If left and right arguments are constants constant folding is performed.
|
||||
* If right argument resolved as table function, or table, and table is not of type Set, it is replaced with query that read only ordinary columns from underlying
|
||||
* If right argument resolved as table, and table is not of type Set, it is replaced with query that read only ordinary columns from underlying
|
||||
* storage.
|
||||
* Example: SELECT id FROM test_table WHERE id IN test_table_other;
|
||||
* Result: SELECT id FROM test_table WHERE id IN (SELECT test_table_column FROM test_table_other);
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include <Analyzer/Passes/SumIfToCountIfPass.h>
|
||||
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
|
||||
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
||||
#include <AggregateFunctions/IAggregateFunction.h>
|
||||
|
||||
@ -73,7 +76,7 @@ public:
|
||||
if (!nested_function || nested_function->getFunctionName() != "if")
|
||||
return;
|
||||
|
||||
auto nested_if_function_arguments_nodes = nested_function->getArguments().getNodes();
|
||||
auto & nested_if_function_arguments_nodes = nested_function->getArguments().getNodes();
|
||||
if (nested_if_function_arguments_nodes.size() != 3)
|
||||
return;
|
||||
|
||||
@ -106,8 +109,13 @@ public:
|
||||
/// Rewrite `sum(if(cond, 0, 1))` into `countIf(not(cond))`.
|
||||
if (if_true_condition_value == 0 && if_false_condition_value == 1)
|
||||
{
|
||||
auto condition_result_type = nested_if_function_arguments_nodes[0]->getResultType();
|
||||
DataTypePtr not_function_result_type = std::make_shared<DataTypeUInt8>();
|
||||
if (condition_result_type->isNullable())
|
||||
not_function_result_type = makeNullable(not_function_result_type);
|
||||
|
||||
auto not_function = std::make_shared<FunctionNode>("not");
|
||||
resolveOrdinaryFunctionNode(*not_function, "not");
|
||||
not_function->resolveAsFunction(FunctionFactory::instance().get("not", context), std::move(not_function_result_type));
|
||||
|
||||
auto & not_function_arguments = not_function->getArguments().getNodes();
|
||||
not_function_arguments.push_back(std::move(nested_if_function_arguments_nodes[0]));
|
||||
@ -121,13 +129,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
inline void resolveOrdinaryFunctionNode(FunctionNode & function_node, const String & function_name) const
|
||||
{
|
||||
auto function_result_type = function_node.getResultType();
|
||||
auto function = FunctionFactory::instance().get(function_name, context);
|
||||
function_node.resolveAsFunction(function, std::move(function_result_type));
|
||||
}
|
||||
|
||||
static inline void resolveAggregateFunctionNode(FunctionNode & function_node, const String & aggregate_function_name)
|
||||
{
|
||||
auto function_result_type = function_node.getResultType();
|
||||
|
@ -24,7 +24,7 @@ bool isUniqFunction(const String & function_name)
|
||||
class UniqInjectiveFunctionsEliminationVisitor : public InDepthQueryTreeVisitor<UniqInjectiveFunctionsEliminationVisitor>
|
||||
{
|
||||
public:
|
||||
void visitImpl(QueryTreeNodePtr & node)
|
||||
static void visitImpl(QueryTreeNodePtr & node)
|
||||
{
|
||||
auto * function_node = node->as<FunctionNode>();
|
||||
if (!function_node || !function_node->isAggregateFunction() || !isUniqFunction(function_node->getFunctionName()))
|
||||
@ -48,7 +48,7 @@ public:
|
||||
continue;
|
||||
|
||||
/// Replace injective function with its single argument
|
||||
uniq_function_argument_node = std::move(uniq_function_argument_node_argument_nodes[0]);
|
||||
uniq_function_argument_node = uniq_function_argument_node_argument_nodes[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -374,7 +374,7 @@ QueryPipeline InterpreterExplainQuery::executeImpl()
|
||||
case ASTExplainQuery::QueryTree:
|
||||
{
|
||||
if (ast.getExplainedQuery()->as<ASTSelectWithUnionQuery>() == nullptr)
|
||||
throw Exception(ErrorCodes::INCORRECT_QUERY, "Only SELECT is supported for EXPLAIN QUERYTREE query");
|
||||
throw Exception(ErrorCodes::INCORRECT_QUERY, "Only SELECT is supported for EXPLAIN QUERY TREE query");
|
||||
|
||||
auto settings = checkAndGetSettings<QueryTreeSettings>(ast.getSettings());
|
||||
auto query_tree = buildQueryTree(ast.getExplainedQuery(), getContext());
|
||||
|
@ -112,8 +112,11 @@ void ASTColumnsListMatcher::formatImpl(const FormatSettings & settings, FormatSt
|
||||
settings.ostr << ")";
|
||||
|
||||
/// Format column transformers
|
||||
for (const auto & child : children)
|
||||
size_t children_size = children.size();
|
||||
|
||||
for (size_t i = 1; i < children_size; ++i)
|
||||
{
|
||||
const auto & child = children[i];
|
||||
settings.ostr << ' ';
|
||||
child->formatImpl(settings, state, frame);
|
||||
}
|
||||
@ -174,8 +177,11 @@ void ASTQualifiedColumnsRegexpMatcher::formatImpl(const FormatSettings & setting
|
||||
settings.ostr << ")";
|
||||
|
||||
/// Format column transformers
|
||||
for (const auto & child : children)
|
||||
size_t children_size = children.size();
|
||||
|
||||
for (size_t i = 1; i < children_size; ++i)
|
||||
{
|
||||
const auto & child = children[i];
|
||||
settings.ostr << ' ';
|
||||
child->formatImpl(settings, state, frame);
|
||||
}
|
||||
@ -223,9 +229,8 @@ void ASTQualifiedColumnsListMatcher::formatImpl(const FormatSettings & settings,
|
||||
for (ASTs::const_iterator it = column_list->children.begin(); it != column_list->children.end(); ++it)
|
||||
{
|
||||
if (it != column_list->children.begin())
|
||||
{
|
||||
settings.ostr << ", ";
|
||||
}
|
||||
|
||||
(*it)->formatImpl(settings, state, frame);
|
||||
}
|
||||
settings.ostr << ")";
|
||||
|
@ -92,9 +92,7 @@ bool ParserExplainQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
|
||||
if (select_p.parse(pos, query, expected))
|
||||
explain_query->setExplainedQuery(std::move(query));
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (kind == ASTExplainQuery::ExplainKind::CurrentTransaction)
|
||||
{
|
||||
|
@ -4,4 +4,4 @@ endif()
|
||||
|
||||
if (ENABLE_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -111,29 +111,34 @@ QueryPlan buildQueryPlanForTableExpression(QueryTreeNodePtr table_expression,
|
||||
auto & query_context = planner_context->getQueryContext();
|
||||
|
||||
auto from_stage = storage->getQueryProcessingStage(query_context, select_query_options.to_stage, storage_snapshot, table_expression_query_info);
|
||||
const auto & columns_names = table_expression_data.getColumnsNames();
|
||||
Names column_names(columns_names.begin(), columns_names.end());
|
||||
const auto & columns_names_set = table_expression_data.getColumnsNames();
|
||||
Names columns_names(columns_names_set.begin(), columns_names_set.end());
|
||||
|
||||
/** The current user must have the SELECT privilege.
|
||||
* We do not check access rights for table functions because they have beein already checked in ITablefunction::execute().
|
||||
* We do not check access rights for table functions because they have been already checked in ITableFunction::execute().
|
||||
*/
|
||||
if (table_node)
|
||||
checkAccessRights(*table_node, column_names, planner_context->getQueryContext());
|
||||
{
|
||||
auto column_names_with_aliases = columns_names;
|
||||
const auto & alias_columns_names = table_expression_data.getAliasColumnsNames();
|
||||
column_names_with_aliases.insert(column_names_with_aliases.end(), alias_columns_names.begin(), alias_columns_names.end());
|
||||
checkAccessRights(*table_node, column_names_with_aliases, planner_context->getQueryContext());
|
||||
}
|
||||
|
||||
if (column_names.empty())
|
||||
if (columns_names.empty())
|
||||
{
|
||||
auto column_names_and_types = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::All).withSubcolumns());
|
||||
auto additional_column_to_read = column_names_and_types.front();
|
||||
|
||||
const auto & column_identifier = planner_context->getGlobalPlannerContext()->createColumnIdentifier(additional_column_to_read, table_expression);
|
||||
column_names.push_back(additional_column_to_read.name);
|
||||
columns_names.push_back(additional_column_to_read.name);
|
||||
table_expression_data.addColumn(additional_column_to_read, column_identifier);
|
||||
}
|
||||
|
||||
size_t max_block_size = query_context->getSettingsRef().max_block_size;
|
||||
size_t max_streams = query_context->getSettingsRef().max_threads;
|
||||
|
||||
bool need_rewrite_query_with_final = storage->needRewriteQueryWithFinal(column_names);
|
||||
bool need_rewrite_query_with_final = storage->needRewriteQueryWithFinal(columns_names);
|
||||
if (need_rewrite_query_with_final)
|
||||
{
|
||||
if (table_expression_query_info.table_expression_modifiers)
|
||||
@ -154,12 +159,12 @@ QueryPlan buildQueryPlanForTableExpression(QueryTreeNodePtr table_expression,
|
||||
}
|
||||
}
|
||||
|
||||
storage->read(query_plan, column_names, storage_snapshot, table_expression_query_info, query_context, from_stage, max_block_size, max_streams);
|
||||
storage->read(query_plan, columns_names, storage_snapshot, table_expression_query_info, query_context, from_stage, max_block_size, max_streams);
|
||||
|
||||
/// Create step which reads from empty source if storage has no data.
|
||||
if (!query_plan.isInitialized())
|
||||
{
|
||||
auto source_header = storage_snapshot->getSampleBlockForColumns(column_names);
|
||||
auto source_header = storage_snapshot->getSampleBlockForColumns(columns_names);
|
||||
Pipe pipe(std::make_shared<NullSource>(source_header));
|
||||
auto read_from_pipe = std::make_unique<ReadFromPreparedSource>(std::move(pipe));
|
||||
read_from_pipe->setStepDescription("Read from NullSource");
|
||||
@ -181,11 +186,15 @@ QueryPlan buildQueryPlanForTableExpression(QueryTreeNodePtr table_expression,
|
||||
|
||||
auto rename_actions_dag = std::make_shared<ActionsDAG>(query_plan.getCurrentDataStream().header.getColumnsWithTypeAndName());
|
||||
|
||||
for (const auto & [column_name, column_identifier] : table_expression_data.getColumnNameToIdentifier())
|
||||
for (auto & output_node : rename_actions_dag->getOutputs())
|
||||
{
|
||||
auto position = query_plan.getCurrentDataStream().header.getPositionByName(column_name);
|
||||
const auto * node_to_rename = rename_actions_dag->getOutputs()[position];
|
||||
rename_actions_dag->getOutputs()[position] = &rename_actions_dag->addAlias(*node_to_rename, column_identifier);
|
||||
const auto * column_identifier = table_expression_data.getColumnIdentifierOrNull(output_node->result_name);
|
||||
|
||||
if (!column_identifier)
|
||||
continue;
|
||||
|
||||
const auto * node_to_rename = output_node;
|
||||
output_node = &rename_actions_dag->addAlias(*node_to_rename, *column_identifier);
|
||||
}
|
||||
|
||||
auto rename_step = std::make_unique<ExpressionStep>(query_plan.getCurrentDataStream(), rename_actions_dag);
|
||||
@ -267,13 +276,13 @@ QueryPlan buildQueryPlanForJoinNode(QueryTreeNodePtr join_tree_node,
|
||||
const auto & join_node_using_column_node_type = join_node_using_column_node.getColumnType();
|
||||
if (!left_inner_column.getColumnType()->equals(*join_node_using_column_node_type))
|
||||
{
|
||||
auto left_inner_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(left_inner_column_node);
|
||||
const auto & left_inner_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(left_inner_column_node);
|
||||
left_plan_column_name_to_cast_type.emplace(left_inner_column_identifier, join_node_using_column_node_type);
|
||||
}
|
||||
|
||||
if (!right_inner_column.getColumnType()->equals(*join_node_using_column_node_type))
|
||||
{
|
||||
auto right_inner_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(right_inner_column_node);
|
||||
const auto & right_inner_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(right_inner_column_node);
|
||||
right_plan_column_name_to_cast_type.emplace(right_inner_column_identifier, join_node_using_column_node_type);
|
||||
}
|
||||
}
|
||||
@ -468,18 +477,12 @@ QueryPlan buildQueryPlanForJoinNode(QueryTreeNodePtr join_tree_node,
|
||||
for (auto & join_using_node : using_list.getNodes())
|
||||
{
|
||||
auto & join_using_column_node = join_using_node->as<ColumnNode &>();
|
||||
if (!join_using_column_node.getExpression() ||
|
||||
join_using_column_node.getExpression()->getNodeType() != QueryTreeNodeType::LIST)
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
||||
"JOIN {} column in USING does not have inner columns",
|
||||
join_node.formatASTForErrorMessage());
|
||||
|
||||
auto & using_join_columns_list = join_using_column_node.getExpression()->as<ListNode &>();
|
||||
auto & using_join_columns_list = join_using_column_node.getExpressionOrThrow()->as<ListNode &>();
|
||||
auto & using_join_left_join_column_node = using_join_columns_list.getNodes().at(0);
|
||||
auto & using_join_right_join_column_node = using_join_columns_list.getNodes().at(1);
|
||||
|
||||
auto left_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(using_join_left_join_column_node);
|
||||
auto right_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(using_join_right_join_column_node);
|
||||
const auto & left_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(using_join_left_join_column_node);
|
||||
const auto & right_column_identifier = planner_context->getColumnNodeIdentifierOrThrow(using_join_right_join_column_node);
|
||||
|
||||
table_join_clause.key_names_left.push_back(left_column_identifier);
|
||||
table_join_clause.key_names_right.push_back(right_column_identifier);
|
||||
@ -627,13 +630,13 @@ QueryPlan buildQueryPlanForArrayJoinNode(QueryTreeNodePtr table_expression,
|
||||
{
|
||||
auto & array_join_node = table_expression->as<ArrayJoinNode &>();
|
||||
|
||||
auto left_plan = buildQueryPlanForJoinTreeNode(array_join_node.getTableExpression(),
|
||||
auto plan = buildQueryPlanForJoinTreeNode(array_join_node.getTableExpression(),
|
||||
select_query_info,
|
||||
select_query_options,
|
||||
planner_context);
|
||||
auto left_plan_output_columns = left_plan.getCurrentDataStream().header.getColumnsWithTypeAndName();
|
||||
auto plan_output_columns = plan.getCurrentDataStream().header.getColumnsWithTypeAndName();
|
||||
|
||||
ActionsDAGPtr array_join_action_dag = std::make_shared<ActionsDAG>(left_plan_output_columns);
|
||||
ActionsDAGPtr array_join_action_dag = std::make_shared<ActionsDAG>(plan_output_columns);
|
||||
PlannerActionsVisitor actions_visitor(planner_context);
|
||||
|
||||
NameSet array_join_columns;
|
||||
@ -652,16 +655,16 @@ QueryPlan buildQueryPlanForArrayJoinNode(QueryTreeNodePtr table_expression,
|
||||
}
|
||||
|
||||
array_join_action_dag->projectInput();
|
||||
auto array_join_actions = std::make_unique<ExpressionStep>(left_plan.getCurrentDataStream(), array_join_action_dag);
|
||||
auto array_join_actions = std::make_unique<ExpressionStep>(plan.getCurrentDataStream(), array_join_action_dag);
|
||||
array_join_actions->setStepDescription("ARRAY JOIN actions");
|
||||
left_plan.addStep(std::move(array_join_actions));
|
||||
plan.addStep(std::move(array_join_actions));
|
||||
|
||||
auto array_join_action = std::make_shared<ArrayJoinAction>(array_join_columns, array_join_node.isLeft(), planner_context->getQueryContext());
|
||||
auto array_join_step = std::make_unique<ArrayJoinStep>(left_plan.getCurrentDataStream(), std::move(array_join_action));
|
||||
auto array_join_step = std::make_unique<ArrayJoinStep>(plan.getCurrentDataStream(), std::move(array_join_action));
|
||||
array_join_step->setStepDescription("ARRAY JOIN");
|
||||
left_plan.addStep(std::move(array_join_step));
|
||||
plan.addStep(std::move(array_join_step));
|
||||
|
||||
return left_plan;
|
||||
return plan;
|
||||
}
|
||||
|
||||
}
|
||||
@ -675,13 +678,13 @@ QueryPlan buildQueryPlanForJoinTreeNode(QueryTreeNodePtr join_tree_node,
|
||||
|
||||
switch (join_tree_node_type)
|
||||
{
|
||||
case QueryTreeNodeType::QUERY:
|
||||
[[fallthrough]];
|
||||
case QueryTreeNodeType::UNION:
|
||||
[[fallthrough]];
|
||||
case QueryTreeNodeType::TABLE:
|
||||
[[fallthrough]];
|
||||
case QueryTreeNodeType::TABLE_FUNCTION:
|
||||
[[fallthrough]];
|
||||
case QueryTreeNodeType::QUERY:
|
||||
[[fallthrough]];
|
||||
case QueryTreeNodeType::UNION:
|
||||
{
|
||||
return buildQueryPlanForTableExpression(join_tree_node, select_query_info, select_query_options, planner_context);
|
||||
}
|
||||
@ -696,7 +699,7 @@ QueryPlan buildQueryPlanForJoinTreeNode(QueryTreeNodePtr join_tree_node,
|
||||
default:
|
||||
{
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
||||
"Expected query, table, table function, join or array join query node. Actual {}",
|
||||
"Expected table, table function, query, union, join or array join query node. Actual {}",
|
||||
join_tree_node->formatASTForErrorMessage());
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ void JoinClause::dump(WriteBuffer & buffer) const
|
||||
buffer << " left_condition_nodes: " + dump_dag_nodes(left_filter_condition_nodes);
|
||||
|
||||
if (!right_filter_condition_nodes.empty())
|
||||
buffer << " left_condition_nodes: " + dump_dag_nodes(right_filter_condition_nodes);
|
||||
buffer << " right_condition_nodes: " + dump_dag_nodes(right_filter_condition_nodes);
|
||||
}
|
||||
|
||||
String JoinClause::dump() const
|
||||
@ -190,7 +190,7 @@ void buildJoinClause(ActionsDAGPtr join_expression_dag,
|
||||
throw Exception(ErrorCodes::INVALID_JOIN_ON_EXPRESSION,
|
||||
"JOIN {} ON expression {} with constants is not supported",
|
||||
join_node.formatASTForErrorMessage(),
|
||||
join_expressions_actions_node->function->getName());
|
||||
join_expressions_actions_node->result_name);
|
||||
}
|
||||
else if (left_expression_side_optional && !right_expression_side_optional)
|
||||
{
|
||||
@ -210,7 +210,7 @@ void buildJoinClause(ActionsDAGPtr join_expression_dag,
|
||||
const ActionsDAG::Node * left_key = left_child;
|
||||
const ActionsDAG::Node * right_key = right_child;
|
||||
|
||||
if (left_expression_side_optional == JoinTableSide::Right)
|
||||
if (left_expression_side == JoinTableSide::Right)
|
||||
{
|
||||
left_key = right_child;
|
||||
right_key = left_child;
|
||||
@ -254,7 +254,6 @@ void buildJoinClause(ActionsDAGPtr join_expression_dag,
|
||||
join_node.formatASTForErrorMessage());
|
||||
|
||||
auto expression_side = *expression_side_optional;
|
||||
|
||||
join_clause.addCondition(expression_side, join_expressions_actions_node);
|
||||
}
|
||||
|
||||
@ -269,7 +268,7 @@ JoinClausesAndActions buildJoinClausesAndActions(const ColumnsWithTypeAndName &
|
||||
/** In ActionsDAG if input node has constant representation additional constant column is added.
|
||||
* That way we cannot simply check that node has INPUT type during resolution of expression join table side.
|
||||
* Put all nodes after actions dag initialization in set.
|
||||
* To check if actions dag node is input column, we set contains node.
|
||||
* To check if actions dag node is input column, we check if set contains it.
|
||||
*/
|
||||
const auto & join_expression_actions_nodes = join_expression_actions->getNodes();
|
||||
|
||||
@ -375,9 +374,7 @@ JoinClausesAndActions buildJoinClausesAndActions(const ColumnsWithTypeAndName &
|
||||
else
|
||||
dag_filter_condition_node = left_filter_condition_nodes[0];
|
||||
|
||||
join_clause.getLeftFilterConditionNodes().clear();
|
||||
join_clause.addCondition(JoinTableSide::Left, dag_filter_condition_node);
|
||||
|
||||
join_clause.getLeftFilterConditionNodes() = {dag_filter_condition_node};
|
||||
join_expression_actions->addOrReplaceInOutputs(*dag_filter_condition_node);
|
||||
|
||||
add_necessary_name_if_needed(JoinTableSide::Left, dag_filter_condition_node->result_name);
|
||||
@ -393,9 +390,7 @@ JoinClausesAndActions buildJoinClausesAndActions(const ColumnsWithTypeAndName &
|
||||
else
|
||||
dag_filter_condition_node = right_filter_condition_nodes[0];
|
||||
|
||||
join_clause.getRightFilterConditionNodes().clear();
|
||||
join_clause.addCondition(JoinTableSide::Right, dag_filter_condition_node);
|
||||
|
||||
join_clause.getRightFilterConditionNodes() = {dag_filter_condition_node};
|
||||
join_expression_actions->addOrReplaceInOutputs(*dag_filter_condition_node);
|
||||
|
||||
add_necessary_name_if_needed(JoinTableSide::Right, dag_filter_condition_node->result_name);
|
||||
@ -541,7 +536,8 @@ void trySetStorageInTableJoin(const QueryTreeNodePtr & table_expression, std::sh
|
||||
else if (auto * table_function = table_expression->as<TableFunctionNode>())
|
||||
storage = table_function->getStorage();
|
||||
|
||||
if (auto storage_join = std::dynamic_pointer_cast<StorageJoin>(storage); storage_join)
|
||||
auto storage_join = std::dynamic_pointer_cast<StorageJoin>(storage);
|
||||
if (storage_join)
|
||||
{
|
||||
table_join->setStorageJoin(storage_join);
|
||||
return;
|
||||
@ -581,7 +577,9 @@ std::shared_ptr<DirectKeyValueJoin> tryDirectJoin(const std::shared_ptr<TableJoi
|
||||
clauses[0].key_names_left.size() == 1 &&
|
||||
clauses[0].key_names_right.size() == 1 &&
|
||||
!clauses[0].on_filter_condition_left &&
|
||||
!clauses[0].on_filter_condition_right;
|
||||
!clauses[0].on_filter_condition_right &&
|
||||
clauses[0].analyzer_left_filter_condition_column_name.empty() &&
|
||||
clauses[0].analyzer_right_filter_condition_column_name.empty();
|
||||
|
||||
if (!only_one_key)
|
||||
return {};
|
||||
@ -604,7 +602,7 @@ std::shared_ptr<DirectKeyValueJoin> tryDirectJoin(const std::shared_ptr<TableJoi
|
||||
* CREATE DICTIONARY test_dictionary (id UInt64, value String) PRIMARY KEY id SOURCE(CLICKHOUSE(TABLE 'test_dictionary_table')) LIFETIME(0);
|
||||
* SELECT t1.id FROM test_table AS t1 INNER JOIN test_dictionary AS t2 ON t1.id = t2.id;
|
||||
*
|
||||
* Unique execution name for `id` column in right table expression `test_dictionary AS t2` for example can be `t2.id_0`.
|
||||
* Unique execution name for `id` column from right table expression `test_dictionary AS t2` for example can be `t2.id_0`.
|
||||
* Storage column name is `id`.
|
||||
*
|
||||
* Here we create header for right table expression with original storage column names.
|
||||
@ -652,7 +650,7 @@ std::shared_ptr<IJoin> chooseJoinAlgorithm(std::shared_ptr<TableJoin> & table_jo
|
||||
if (!table_join->oneDisjunct() && !table_join->isEnabledAlgorithm(JoinAlgorithm::HASH))
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Only `hash` join supports multiple ORs for keys in JOIN ON section");
|
||||
|
||||
/// Direct JOIN with special storages that support key value access. For example JOIN with Dictionary.
|
||||
/// Direct JOIN with special storages that support key value access. For example JOIN with Dictionary
|
||||
if (table_join->isEnabledAlgorithm(JoinAlgorithm::DIRECT))
|
||||
{
|
||||
JoinPtr direct_join = tryDirectJoin(table_join, right_table_expression, right_table_expression_header, planner_context);
|
||||
|
@ -31,7 +31,7 @@ namespace DB
|
||||
* Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 ON toString(t1.id) = toString(t2.id).
|
||||
* toString(t1.id) = toString(t2.id) is JOIN keys section. Where toString(t1.id) is left key, and toString(t2.id) is right key.
|
||||
*
|
||||
* During query planning JOIN ON section must be represented using join clause structure. It is important to split
|
||||
* During query planning JOIN ON section represented using join clause structure. It is important to split
|
||||
* keys and conditions. And for each action detect from which stream it can be performed.
|
||||
*
|
||||
* We have 2 streams, left stream and right stream.
|
||||
@ -79,26 +79,16 @@ public:
|
||||
return left_key_nodes;
|
||||
}
|
||||
|
||||
/// Get right key nodes
|
||||
const ActionsDAG::NodeRawConstPtrs & getRightKeyNodes() const
|
||||
{
|
||||
return right_key_nodes;
|
||||
}
|
||||
|
||||
/// Get left key nodes
|
||||
ActionsDAG::NodeRawConstPtrs & getLeftKeyNodes()
|
||||
{
|
||||
return left_key_nodes;
|
||||
}
|
||||
|
||||
bool hasASOF() const
|
||||
/// Get right key nodes
|
||||
const ActionsDAG::NodeRawConstPtrs & getRightKeyNodes() const
|
||||
{
|
||||
return !asof_conditions.empty();
|
||||
}
|
||||
|
||||
const std::vector<ASOFCondition> & getASOFConditions() const
|
||||
{
|
||||
return asof_conditions;
|
||||
return right_key_nodes;
|
||||
}
|
||||
|
||||
/// Get right key nodes
|
||||
@ -107,23 +97,36 @@ public:
|
||||
return right_key_nodes;
|
||||
}
|
||||
|
||||
/// Returns true if JOIN clause has ASOF conditions, false otherwise
|
||||
bool hasASOF() const
|
||||
{
|
||||
return !asof_conditions.empty();
|
||||
}
|
||||
|
||||
/// Get ASOF conditions
|
||||
const std::vector<ASOFCondition> & getASOFConditions() const
|
||||
{
|
||||
return asof_conditions;
|
||||
}
|
||||
|
||||
/// Get left filter condition nodes
|
||||
const ActionsDAG::NodeRawConstPtrs & getLeftFilterConditionNodes() const
|
||||
{
|
||||
return left_filter_condition_nodes;
|
||||
}
|
||||
|
||||
/// Get left filter condition nodes
|
||||
ActionsDAG::NodeRawConstPtrs & getLeftFilterConditionNodes()
|
||||
{
|
||||
return left_filter_condition_nodes;
|
||||
}
|
||||
|
||||
/// Get right filter condition nodes
|
||||
const ActionsDAG::NodeRawConstPtrs & getRightFilterConditionNodes() const
|
||||
{
|
||||
return right_filter_condition_nodes;
|
||||
}
|
||||
|
||||
ActionsDAG::NodeRawConstPtrs & getLeftFilterConditionNodes()
|
||||
{
|
||||
return left_filter_condition_nodes;
|
||||
}
|
||||
|
||||
/// Get right filter condition nodes
|
||||
ActionsDAG::NodeRawConstPtrs & getRightFilterConditionNodes()
|
||||
{
|
||||
@ -183,7 +186,7 @@ std::optional<bool> tryExtractConstantFromJoinNode(const QueryTreeNodePtr & join
|
||||
|
||||
/** Choose JOIN algorithm for table join, right table expression, right table expression header and planner context.
|
||||
* Table join structure can be modified during JOIN algorithm choosing for special JOIN algorithms.
|
||||
* For example JOIN with Dictionary enigne, or JOIN with JOIN engine.
|
||||
* For example JOIN with Dictionary engine, or JOIN with JOIN engine.
|
||||
*/
|
||||
std::shared_ptr<IJoin> chooseJoinAlgorithm(std::shared_ptr<TableJoin> & table_join,
|
||||
const QueryTreeNodePtr & right_table_expression,
|
||||
|
@ -24,7 +24,7 @@ namespace
|
||||
|
||||
std::pair<Field, DataTypePtr> extractWithFillValue(const QueryTreeNodePtr & node)
|
||||
{
|
||||
auto constant_value = node->getConstantValue();
|
||||
const auto & constant_value = node->getConstantValue();
|
||||
|
||||
std::pair<Field, DataTypePtr> result;
|
||||
result.first = constant_value.getValue();
|
||||
@ -38,7 +38,7 @@ std::pair<Field, DataTypePtr> extractWithFillValue(const QueryTreeNodePtr & node
|
||||
|
||||
std::pair<Field, std::optional<IntervalKind>> extractWithFillStepValue(const QueryTreeNodePtr & node)
|
||||
{
|
||||
auto constant_value = node->getConstantValue();
|
||||
const auto & constant_value = node->getConstantValue();
|
||||
|
||||
const auto & constant_node_result_type = constant_value.getType();
|
||||
if (const auto * type_interval = typeid_cast<const DataTypeInterval *>(constant_node_result_type.get()))
|
||||
@ -76,7 +76,8 @@ FillColumnDescription extractWithFillDescription(const SortNode & sort_node)
|
||||
}
|
||||
else
|
||||
{
|
||||
fill_column_description.fill_step = Field(sort_node.getSortDirection() == SortDirection::ASCENDING ? 1 : -1);
|
||||
auto direction_value = sort_node.getSortDirection() == SortDirection::ASCENDING ? static_cast<Int64>(1) : static_cast<Int64>(-1);
|
||||
fill_column_description.fill_step = Field(direction_value);
|
||||
}
|
||||
|
||||
if (applyVisitor(FieldVisitorAccurateEquals(), fill_column_description.fill_step, Field{0}))
|
||||
|
@ -85,8 +85,10 @@ std::vector<WindowDescription> extractWindowDescriptions(const QueryTreeNodes &
|
||||
}
|
||||
|
||||
const auto & arguments_nodes = window_function_node_typed.getArguments().getNodes();
|
||||
window_function.argument_names.reserve(arguments_nodes.size());
|
||||
window_function.argument_types.reserve(arguments_nodes.size());
|
||||
size_t arguments_nodes_size = arguments_nodes.size();
|
||||
|
||||
window_function.argument_names.reserve(arguments_nodes_size);
|
||||
window_function.argument_types.reserve(arguments_nodes_size);
|
||||
|
||||
for (const auto & argument_node : arguments_nodes)
|
||||
{
|
||||
|
@ -9,10 +9,10 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Extract and sort window description from query.
|
||||
/// Extract window descriptions from window function nodes
|
||||
std::vector<WindowDescription> extractWindowDescriptions(const QueryTreeNodes & window_function_nodes, const PlannerContext & planner_context);
|
||||
|
||||
/** Try to sort window description in such an order that the window with the longest
|
||||
/** Try to sort window descriptions in such an order that the window with the longest
|
||||
* sort description goes first, and all window that use its prefixes follow.
|
||||
*/
|
||||
void sortWindowDescriptions(std::vector<WindowDescription> & window_descriptions);
|
||||
|
@ -22,7 +22,7 @@ class TableExpressionData
|
||||
public:
|
||||
using ColumnNameToColumnIdentifier = std::unordered_map<std::string, ColumnIdentifier>;
|
||||
|
||||
using ColumnIdentifierToColumnName = std::unordered_map<std::string, ColumnIdentifier>;
|
||||
using ColumnIdentifierToColumnName = std::unordered_map<ColumnIdentifier, std::string>;
|
||||
|
||||
/// Return true if column with name exists, false otherwise
|
||||
bool hasColumn(const std::string & column_name) const
|
||||
@ -32,6 +32,8 @@ public:
|
||||
|
||||
/** Add column in table expression data.
|
||||
* Column identifier must be created using global planner context.
|
||||
*
|
||||
* Logical error exception is thrown if column already exists.
|
||||
*/
|
||||
void addColumn(const NameAndTypePair & column, const ColumnIdentifier & column_identifier)
|
||||
{
|
||||
@ -64,13 +66,13 @@ public:
|
||||
alias_columns_names.insert(column_name);
|
||||
}
|
||||
|
||||
/// Get alias column names
|
||||
/// Get alias columns names
|
||||
const NameSet & getAliasColumnsNames() const
|
||||
{
|
||||
return alias_columns_names;
|
||||
}
|
||||
|
||||
/// Get column names
|
||||
/// Get columns names
|
||||
const NameSet & getColumnsNames() const
|
||||
{
|
||||
return columns_names;
|
||||
@ -146,7 +148,7 @@ public:
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
/** Cache value of storage is remote method call.
|
||||
/** Returns true if storage is remote, false otherwise.
|
||||
*
|
||||
* Valid only for table and table function node.
|
||||
*/
|
||||
@ -155,29 +157,29 @@ public:
|
||||
return is_remote;
|
||||
}
|
||||
|
||||
/// Set is remote value
|
||||
/// Set is storage remote value
|
||||
void setIsRemote(bool is_remote_value)
|
||||
{
|
||||
is_remote = is_remote_value;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Valid for table, table function, query table expression nodes
|
||||
/// Valid for table, table function, query, union table expression nodes
|
||||
NamesAndTypesList columns;
|
||||
|
||||
/// Valid for table, table function, query table expression nodes
|
||||
/// Valid for table, table function, query, union table expression nodes
|
||||
NameSet columns_names;
|
||||
|
||||
/// Valid only for table table expression node
|
||||
NameSet alias_columns_names;
|
||||
|
||||
/// Valid for table, table function, query table expression nodes
|
||||
/// Valid for table, table function, query, union table expression nodes
|
||||
ColumnNameToColumnIdentifier column_name_to_column_identifier;
|
||||
|
||||
/// Valid for table, table function, query table expression nodes
|
||||
/// Valid for table, table function, query, union table expression nodes
|
||||
ColumnIdentifierToColumnName column_identifier_to_column_name;
|
||||
|
||||
/// Cached value if table expression receives data from remote server
|
||||
/// Is storage remote
|
||||
bool is_remote = false;
|
||||
};
|
||||
|
||||
|
@ -32,6 +32,7 @@ String dumpQueryPlan(QueryPlan & query_plan)
|
||||
{
|
||||
WriteBufferFromOwnString query_plan_buffer;
|
||||
query_plan.explainPlan(query_plan_buffer, QueryPlan::ExplainPlanOptions{true, true, true, true});
|
||||
|
||||
return query_plan_buffer.str();
|
||||
}
|
||||
|
||||
@ -40,6 +41,7 @@ String dumpQueryPipeline(QueryPlan & query_plan)
|
||||
QueryPlan::ExplainPipelineOptions explain_pipeline;
|
||||
WriteBufferFromOwnString query_pipeline_buffer;
|
||||
query_plan.explainPipeline(query_pipeline_buffer, explain_pipeline);
|
||||
|
||||
return query_pipeline_buffer.str();
|
||||
}
|
||||
|
||||
@ -47,26 +49,26 @@ Block buildCommonHeaderForUnion(const Blocks & queries_headers)
|
||||
{
|
||||
size_t num_selects = queries_headers.size();
|
||||
Block common_header = queries_headers.front();
|
||||
size_t num_columns = common_header.columns();
|
||||
size_t columns_size = common_header.columns();
|
||||
|
||||
for (size_t query_num = 1; query_num < num_selects; ++query_num)
|
||||
for (size_t query_number = 1; query_number < num_selects; ++query_number)
|
||||
{
|
||||
if (queries_headers.at(query_num).columns() != num_columns)
|
||||
if (queries_headers.at(query_number).columns() != columns_size)
|
||||
throw Exception(ErrorCodes::TYPE_MISMATCH,
|
||||
"Different number of columns in UNION elements: {} and {}",
|
||||
common_header.dumpNames(),
|
||||
queries_headers[query_num].dumpNames());
|
||||
queries_headers[query_number].dumpNames());
|
||||
}
|
||||
|
||||
std::vector<const ColumnWithTypeAndName *> columns(num_selects);
|
||||
|
||||
for (size_t column_num = 0; column_num < num_columns; ++column_num)
|
||||
for (size_t column_number = 0; column_number < columns_size; ++column_number)
|
||||
{
|
||||
for (size_t i = 0; i < num_selects; ++i)
|
||||
columns[i] = &queries_headers[i].getByPosition(column_num);
|
||||
columns[i] = &queries_headers[i].getByPosition(column_number);
|
||||
|
||||
ColumnWithTypeAndName & result_elem = common_header.getByPosition(column_num);
|
||||
result_elem = getLeastSuperColumn(columns);
|
||||
ColumnWithTypeAndName & result_element = common_header.getByPosition(column_number);
|
||||
result_element = getLeastSuperColumn(columns);
|
||||
}
|
||||
|
||||
return common_header;
|
||||
@ -175,20 +177,18 @@ ActionsDAGPtr buildActionsDAGFromExpressionNode(const QueryTreeNodePtr & express
|
||||
ActionsDAGPtr action_dag = std::make_shared<ActionsDAG>(input_columns);
|
||||
PlannerActionsVisitor actions_visitor(planner_context);
|
||||
auto expression_dag_index_nodes = actions_visitor.visit(action_dag, expression_node);
|
||||
action_dag->getOutputs().clear();
|
||||
|
||||
for (auto & expression_dag_index_node : expression_dag_index_nodes)
|
||||
action_dag->getOutputs().push_back(expression_dag_index_node);
|
||||
action_dag->getOutputs() = std::move(expression_dag_index_nodes);
|
||||
|
||||
return action_dag;
|
||||
}
|
||||
|
||||
bool sortDescriptionIsPrefix(const SortDescription & prefix, const SortDescription & full)
|
||||
{
|
||||
if (prefix.size() > full.size())
|
||||
size_t prefix_size = prefix.size();
|
||||
if (prefix_size > full.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < prefix.size(); ++i)
|
||||
for (size_t i = 0; i < prefix_size; ++i)
|
||||
{
|
||||
if (full[i] != prefix[i])
|
||||
return false;
|
||||
@ -204,7 +204,7 @@ bool queryHasArrayJoinInJoinTree(const QueryTreeNodePtr & query_node)
|
||||
std::vector<QueryTreeNodePtr> join_tree_nodes_to_process;
|
||||
join_tree_nodes_to_process.push_back(query_node_typed.getJoinTree());
|
||||
|
||||
while (join_tree_nodes_to_process.empty())
|
||||
while (!join_tree_nodes_to_process.empty())
|
||||
{
|
||||
auto join_tree_node_to_process = join_tree_nodes_to_process.back();
|
||||
join_tree_nodes_to_process.pop_back();
|
||||
@ -253,7 +253,7 @@ bool queryHasWithTotalsInAnySubqueryInJoinTree(const QueryTreeNodePtr & query_no
|
||||
std::vector<QueryTreeNodePtr> join_tree_nodes_to_process;
|
||||
join_tree_nodes_to_process.push_back(query_node_typed.getJoinTree());
|
||||
|
||||
while (join_tree_nodes_to_process.empty())
|
||||
while (!join_tree_nodes_to_process.empty())
|
||||
{
|
||||
auto join_tree_node_to_process = join_tree_nodes_to_process.back();
|
||||
join_tree_nodes_to_process.pop_back();
|
||||
|
@ -48,7 +48,7 @@ ActionsDAGPtr buildActionsDAGFromExpressionNode(const QueryTreeNodePtr & express
|
||||
/// Returns true if prefix sort description is prefix of full sort descriptor, false otherwise
|
||||
bool sortDescriptionIsPrefix(const SortDescription & prefix, const SortDescription & full);
|
||||
|
||||
/// Returns true if query node JOIN TREE contains ARRAY JOIN node
|
||||
/// Returns true if query node JOIN TREE contains ARRAY JOIN node, false otherwise
|
||||
bool queryHasArrayJoinInJoinTree(const QueryTreeNodePtr & query_node);
|
||||
|
||||
/** Returns true if query node JOIN TREE contains QUERY node with WITH TOTALS, false otherwise.
|
||||
|
@ -490,12 +490,8 @@ MergeTreeDataSelectSamplingData MergeTreeDataSelectExecutor::getSampling(
|
||||
{
|
||||
const auto & table_expression_modifiers = *select_query_info.table_expression_modifiers;
|
||||
final = table_expression_modifiers.hasFinal();
|
||||
|
||||
if (table_expression_modifiers.hasSampleSizeRatio())
|
||||
sample_size_ratio = table_expression_modifiers.getSampleSizeRatio();
|
||||
|
||||
if (table_expression_modifiers.hasSampleOffsetRatio())
|
||||
sample_offset_ratio = table_expression_modifiers.getSampleSizeRatio();
|
||||
sample_size_ratio = table_expression_modifiers.getSampleSizeRatio();
|
||||
sample_offset_ratio = table_expression_modifiers.getSampleOffsetRatio();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user