mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
Update explain query tree representation
This commit is contained in:
parent
dd28b58864
commit
603c4febc3
@ -28,13 +28,18 @@ QueryTreeNodePtr ColumnNode::getColumnSource() const
|
||||
return lock;
|
||||
}
|
||||
|
||||
void ColumnNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void ColumnNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "COLUMN ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << column.name << " : " << column.type->getName() << " source ";
|
||||
buffer << std::string(indent, ' ') << "COLUMN id: " << state.getNodeId(this);
|
||||
|
||||
if (hasAlias())
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << ", column_name: " << column.name << ", result_type: " << column.type->getName();
|
||||
|
||||
auto column_source_ptr = column_source.lock();
|
||||
writePointerHex(column_source_ptr.get(), buffer);
|
||||
if (column_source_ptr)
|
||||
buffer << ", source_id: " << state.getNodeId(column_source_ptr.get());
|
||||
}
|
||||
|
||||
bool ColumnNode::isEqualImpl(const IQueryTreeNode & rhs) const
|
||||
|
@ -67,8 +67,6 @@ public:
|
||||
return QueryTreeNodeType::COLUMN;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
return column.name;
|
||||
@ -79,11 +77,13 @@ public:
|
||||
return column.type;
|
||||
}
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & hash_state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -57,16 +57,15 @@ ApplyColumnTransformerNode::ApplyColumnTransformerNode(QueryTreeNodePtr expressi
|
||||
children[expression_child_index] = std::move(expression_node_);
|
||||
}
|
||||
|
||||
void ApplyColumnTransformerNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void ApplyColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "APPLY COLUMN TRANSFORMER ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << toString(apply_transformer_type) << '\n';
|
||||
buffer << std::string(indent, ' ') << "APPLY COLUMN TRANSFORMER id: " << format_state.getNodeId(this);
|
||||
buffer << ", apply_transformer_type: " << toString(apply_transformer_type);
|
||||
|
||||
buffer << std::string(indent + 2, ' ') << "EXPRESSION" << '\n';
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "EXPRESSION" << '\n';
|
||||
|
||||
const auto & expression_node = getExpressionNode();
|
||||
expression_node->dumpTree(buffer, indent + 4);
|
||||
expression_node->dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
bool ApplyColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs) const
|
||||
@ -136,25 +135,28 @@ const char * toString(ExceptColumnTransformerType type)
|
||||
}
|
||||
}
|
||||
|
||||
void ExceptColumnTransformerNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void ExceptColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "EXCEPT COLUMN TRANSFORMER ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << toString(except_transformer_type) << ' ';
|
||||
buffer << std::string(indent, ' ') << "EXCEPT COLUMN TRANSFORMER id: " << format_state.getNodeId(this);
|
||||
buffer << ", except_transformer_type: " << toString(except_transformer_type);
|
||||
|
||||
if (column_matcher)
|
||||
{
|
||||
buffer << column_matcher->pattern();
|
||||
buffer << ", pattern: " << column_matcher->pattern();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t except_column_names_size = except_column_names.size();
|
||||
for (size_t i = 0; i < except_column_names_size; ++i)
|
||||
else
|
||||
{
|
||||
buffer << except_column_names[i];
|
||||
buffer << ", identifiers: ";
|
||||
|
||||
if (i + 1 != except_column_names_size)
|
||||
buffer << ", ";
|
||||
size_t except_column_names_size = except_column_names.size();
|
||||
for (size_t i = 0; i < except_column_names_size; ++i)
|
||||
{
|
||||
buffer << except_column_names[i];
|
||||
|
||||
if (i + 1 != except_column_names_size)
|
||||
buffer << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,15 +261,13 @@ QueryTreeNodePtr ReplaceColumnTransformerNode::findReplacementExpression(const s
|
||||
return replacement_expressions_nodes[replacement_index];
|
||||
}
|
||||
|
||||
void ReplaceColumnTransformerNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void ReplaceColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "REPLACE TRANSFORMER ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << '\n';
|
||||
buffer << std::string(indent, ' ') << "REPLACE COLUMN TRANSFORMER id: " << format_state.getNodeId(this);
|
||||
|
||||
auto & replacements_nodes = getReplacements().getNodes();
|
||||
size_t replacements_size = replacements_nodes.size();
|
||||
buffer << std::string(indent + 2, ' ') << "REPLACEMENTS " << replacements_size << '\n';
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "REPLACEMENTS " << replacements_size << '\n';
|
||||
|
||||
for (size_t i = 0; i < replacements_size; ++i)
|
||||
{
|
||||
@ -275,7 +275,7 @@ void ReplaceColumnTransformerNode::dumpTree(WriteBuffer & buffer, size_t indent)
|
||||
buffer << std::string(indent + 4, ' ') << "REPLACEMENT NAME " << replacement_name;
|
||||
buffer << " EXPRESSION" << '\n';
|
||||
const auto & expression_node = replacements_nodes[i];
|
||||
expression_node->dumpTree(buffer, indent + 6);
|
||||
expression_node->dumpTreeImpl(buffer, format_state, indent + 6);
|
||||
|
||||
if (i + 1 != replacements_size)
|
||||
buffer << '\n';
|
||||
|
@ -129,13 +129,13 @@ public:
|
||||
return ColumnTransfomerType::APPLY;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
protected:
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
@ -218,13 +218,13 @@ public:
|
||||
return ColumnTransfomerType::EXCEPT;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
protected:
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
@ -294,13 +294,13 @@ public:
|
||||
*/
|
||||
QueryTreeNodePtr findReplacementExpression(const std::string & expression_name);
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
protected:
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -26,11 +26,15 @@ ConstantNode::ConstantNode(Field value_)
|
||||
, type(applyVisitor(FieldToDataType(), value))
|
||||
{}
|
||||
|
||||
void ConstantNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void ConstantNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "CONSTANT ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << value.dump() << " : " << type->getName();
|
||||
buffer << std::string(indent, ' ') << "CONSTANT id: " << format_state.getNodeId(this);
|
||||
|
||||
if (hasAlias())
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << ", value: " << value.dump();
|
||||
buffer << ", result_type: " << type->getName();
|
||||
}
|
||||
|
||||
bool ConstantNode::isEqualImpl(const IQueryTreeNode & rhs) const
|
||||
|
@ -34,8 +34,6 @@ public:
|
||||
return QueryTreeNodeType::CONSTANT;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
return value_string_dump;
|
||||
@ -47,6 +45,8 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & hash_state) const override;
|
||||
|
@ -30,24 +30,30 @@ void FunctionNode::resolveAsAggregateFunction(AggregateFunctionPtr aggregate_fun
|
||||
function_name = aggregate_function->getName();
|
||||
}
|
||||
|
||||
void FunctionNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void FunctionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "FUNCTION ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << function_name << (result_type ? (" : " + result_type->getName()) : "");
|
||||
buffer << std::string(indent, ' ') << "FUNCTION id: " << format_state.getNodeId(this);
|
||||
|
||||
if (hasAlias())
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << ", function_name: " << function_name;
|
||||
|
||||
if (result_type)
|
||||
buffer << ", result_type: " + result_type->getName();
|
||||
|
||||
const auto & parameters = getParameters();
|
||||
if (!parameters.getNodes().empty())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "PARAMETERS\n";
|
||||
parameters.dumpTree(buffer, indent + 4);
|
||||
parameters.dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
const auto & arguments = getArguments();
|
||||
if (!arguments.getNodes().empty())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "ARGUMENTS\n";
|
||||
arguments.dumpTree(buffer, indent + 4);
|
||||
arguments.dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,8 +152,6 @@ public:
|
||||
return QueryTreeNodeType::FUNCTION;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
DataTypePtr getResultType() const override
|
||||
{
|
||||
return result_type;
|
||||
@ -161,11 +159,13 @@ public:
|
||||
|
||||
String getName() const override;
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & hash_state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -38,10 +38,22 @@ const char * toString(QueryTreeNodeType type)
|
||||
String IQueryTreeNode::dumpTree() const
|
||||
{
|
||||
WriteBufferFromOwnString buff;
|
||||
dumpTree(buff, 0);
|
||||
dumpTree(buff);
|
||||
return buff.str();
|
||||
}
|
||||
|
||||
size_t IQueryTreeNode::FormatState::getNodeId(const IQueryTreeNode * node)
|
||||
{
|
||||
auto [it, _] = node_to_id.emplace(node, node_to_id.size());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void IQueryTreeNode::dumpTree(WriteBuffer & buffer) const
|
||||
{
|
||||
FormatState state;
|
||||
dumpTreeImpl(buffer, state, 0);
|
||||
}
|
||||
|
||||
bool IQueryTreeNode::isEqual(const IQueryTreeNode & rhs) const
|
||||
{
|
||||
if (getNodeType() != rhs.getNodeType())
|
||||
|
@ -84,13 +84,7 @@ public:
|
||||
String dumpTree() const;
|
||||
|
||||
/// Dump query tree to buffer
|
||||
void dumpTree(WriteBuffer & buffer) const
|
||||
{
|
||||
dumpTree(buffer, 0);
|
||||
}
|
||||
|
||||
/// Dump query tree to buffer starting with indent
|
||||
virtual void dumpTree(WriteBuffer & buffer, size_t indent) const = 0;
|
||||
void dumpTree(WriteBuffer & buffer) const;
|
||||
|
||||
/** Is tree equal to other tree with node root.
|
||||
*
|
||||
@ -179,7 +173,7 @@ public:
|
||||
if (original_ast)
|
||||
return formatOriginalASTForErrorMessage();
|
||||
|
||||
return formatConvertedASTForErrorMessage();
|
||||
return formatConvertedASTForErrorMessage();
|
||||
}
|
||||
|
||||
/// Get query tree node children
|
||||
@ -194,11 +188,26 @@ public:
|
||||
return children;
|
||||
}
|
||||
|
||||
class FormatState
|
||||
{
|
||||
public:
|
||||
size_t getNodeId(const IQueryTreeNode * node);
|
||||
|
||||
private:
|
||||
std::unordered_map<const IQueryTreeNode *, size_t> node_to_id;
|
||||
};
|
||||
|
||||
/** Dump query tree to buffer starting with indent.
|
||||
*
|
||||
* Node must also dump its children.
|
||||
*/
|
||||
virtual void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const = 0;
|
||||
|
||||
/** Subclass must compare its internal state with rhs node and do not compare its children with rhs node children.
|
||||
* Caller must compare node and rhs node children.
|
||||
*
|
||||
* This method is not protected because if subclass node has weak pointers to other query tree nodes it must use it
|
||||
* as part of its isEqualImpl method. In child classes this method should be protected.
|
||||
* as part of its isEqualImpl method.
|
||||
*/
|
||||
virtual bool isEqualImpl(const IQueryTreeNode & rhs) const = 0;
|
||||
|
||||
@ -206,11 +215,12 @@ public:
|
||||
* Caller must update tree hash for node children.
|
||||
*
|
||||
* This method is not protected because if subclass node has weak pointers to other query tree nodes it must use it
|
||||
* as part of its updateTreeHashImpl method. In child classes this method should be protected.
|
||||
* as part of its updateTreeHashImpl method.
|
||||
*/
|
||||
virtual void updateTreeHashImpl(HashState & hash_state) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/** Subclass node must convert itself to AST.
|
||||
* Subclass must convert children to AST.
|
||||
*/
|
||||
|
@ -10,11 +10,14 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
void IdentifierNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void IdentifierNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "IDENTIFIER ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << identifier.getFullName();
|
||||
buffer << std::string(indent, ' ') << "IDENTIFIER id: " << format_state.getNodeId(this);
|
||||
|
||||
if (hasAlias())
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << ", identifier: " << identifier.getFullName();
|
||||
}
|
||||
|
||||
bool IdentifierNode::isEqualImpl(const IQueryTreeNode & rhs) const
|
||||
|
@ -32,18 +32,18 @@ public:
|
||||
return QueryTreeNodeType::IDENTIFIER;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
return identifier.getFullName();
|
||||
}
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -27,21 +27,27 @@ LambdaNode::LambdaNode(Names argument_names_, QueryTreeNodePtr expression_)
|
||||
children[expression_child_index] = std::move(expression_);
|
||||
}
|
||||
|
||||
void LambdaNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void LambdaNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
auto result_type = getExpression()->getResultType();
|
||||
|
||||
buffer << std::string(indent, ' ') << "LAMBDA ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << (result_type ? (" : " + result_type->getName()) : "") << '\n';
|
||||
buffer << std::string(indent, ' ') << "LAMBDA id: " << format_state.getNodeId(this);
|
||||
|
||||
buffer << std::string(indent + 2, ' ') << "ARGUMENTS " << '\n';
|
||||
getArguments().dumpTree(buffer, indent + 4);
|
||||
if (hasAlias())
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << '\n';
|
||||
if (result_type)
|
||||
buffer << ", result_type: " << result_type->getName();
|
||||
|
||||
buffer << std::string(indent + 2, ' ') << "EXPRESSION " << '\n';
|
||||
getExpression()->dumpTree(buffer, indent + 4);
|
||||
const auto & arguments = getArguments();
|
||||
if (!arguments.getNodes().empty())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "ARGUMENTS " << '\n';
|
||||
getArguments().dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "EXPRESSION " << '\n';
|
||||
getExpression()->dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
String LambdaNode::getName() const
|
||||
|
@ -88,8 +88,6 @@ public:
|
||||
return QueryTreeNodeType::LAMBDA;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override;
|
||||
|
||||
DataTypePtr getResultType() const override
|
||||
@ -97,11 +95,13 @@ public:
|
||||
return getExpression()->getResultType();
|
||||
}
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -11,17 +11,17 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
void ListNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void ListNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "LIST id: " << format_state.getNodeId(this);
|
||||
|
||||
size_t children_size = children.size();
|
||||
buffer << std::string(indent, ' ') << "LIST ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << children_size << '\n';
|
||||
buffer << ", nodes: " << children_size << '\n';
|
||||
|
||||
for (size_t i = 0; i < children_size; ++i)
|
||||
{
|
||||
const auto & node = children[i];
|
||||
node->dumpTree(buffer, indent + 2);
|
||||
node->dumpTreeImpl(buffer, format_state, indent + 2);
|
||||
|
||||
if (i + 1 != children_size)
|
||||
buffer << '\n';
|
||||
|
@ -33,15 +33,15 @@ public:
|
||||
return QueryTreeNodeType::LIST;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override;
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState &) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -119,23 +119,22 @@ bool MatcherNode::isMatchingColumn(const std::string & column_name)
|
||||
return columns_identifiers_set.find(column_name) != columns_identifiers_set.end();
|
||||
}
|
||||
|
||||
void MatcherNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void MatcherNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "MATCHER ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << std::string(indent, ' ') << "MATCHER id: " << format_state.getNodeId(this);
|
||||
|
||||
buffer << ", matcher_type: " << toString(matcher_type);
|
||||
|
||||
if (!qualified_identifier.empty())
|
||||
buffer << ' ' << qualified_identifier.getFullName();
|
||||
|
||||
buffer << ' ' << toString(matcher_type);
|
||||
buffer << ", qualified_identifier: " << qualified_identifier.getFullName();
|
||||
|
||||
if (columns_matcher)
|
||||
{
|
||||
buffer << ' ' << columns_matcher->pattern();
|
||||
buffer << ", columns_pattern: " << columns_matcher->pattern();
|
||||
}
|
||||
else if (matcher_type == MatcherNodeType::COLUMNS_LIST)
|
||||
{
|
||||
buffer << ' ';
|
||||
buffer << ", columns_identifiers: ";
|
||||
size_t columns_identifiers_size = columns_identifiers.size();
|
||||
for (size_t i = 0; i < columns_identifiers_size; ++i)
|
||||
{
|
||||
@ -150,7 +149,7 @@ void MatcherNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
if (!column_transformers_list.getNodes().empty())
|
||||
{
|
||||
buffer << '\n';
|
||||
column_transformers_list.dumpTree(buffer, indent + 2);
|
||||
column_transformers_list.dumpTreeImpl(buffer, format_state, indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,15 +141,15 @@ public:
|
||||
return QueryTreeNodeType::ASTERISK;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override;
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & hash_state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
|
||||
String getName() override { return "MultiIfToIf"; }
|
||||
|
||||
String getDescription() override { return "Optimize multiIf to if for single argument"; }
|
||||
String getDescription() override { return "Optimize multiIf to if for single argument."; }
|
||||
|
||||
void run(QueryTreeNodePtr query_tree_node, ContextPtr context) override;
|
||||
|
||||
|
@ -22,44 +22,45 @@ QueryNode::QueryNode()
|
||||
children[projection_child_index] = std::make_shared<ListNode>();
|
||||
}
|
||||
|
||||
void QueryNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void QueryNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "QUERY ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << std::string(indent, ' ') << "QUERY id: " << format_state.getNodeId(this);
|
||||
|
||||
if (hasAlias())
|
||||
buffer << " alias : " << getAlias();
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << " subquery : " << is_subquery;
|
||||
buffer << " cte : " << is_cte;
|
||||
buffer << " cte_name : " << cte_name;
|
||||
buffer << ", is_subquery: " << is_subquery;
|
||||
buffer << ", is_cte: " << is_cte;
|
||||
|
||||
if (!cte_name.empty())
|
||||
buffer << ", cte_name: " << cte_name;
|
||||
|
||||
if (!getWith().getNodes().empty())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "WITH\n";
|
||||
getWith().dumpTree(buffer, indent + 4);
|
||||
getWith().dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
buffer << '\n';
|
||||
buffer << std::string(indent + 2, ' ') << "PROJECTION\n";
|
||||
getProjection().dumpTree(buffer, indent + 4);
|
||||
getProjection().dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
|
||||
if (getFrom())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "JOIN TREE\n";
|
||||
getFrom()->dumpTree(buffer, indent + 4);
|
||||
getFrom()->dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
if (getPrewhere())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "PREWHERE\n";
|
||||
getPrewhere()->dumpTree(buffer, indent + 4);
|
||||
getPrewhere()->dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
|
||||
if (getWhere())
|
||||
{
|
||||
buffer << '\n' << std::string(indent + 2, ' ') << "WHERE\n";
|
||||
getWhere()->dumpTree(buffer, indent + 4);
|
||||
getWhere()->dumpTreeImpl(buffer, format_state, indent + 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,13 +122,13 @@ public:
|
||||
return QueryTreeNodeType::QUERY;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
protected:
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState &) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -21,11 +21,14 @@ TableNode::TableNode(StoragePtr storage_, ContextPtr context)
|
||||
{
|
||||
}
|
||||
|
||||
void TableNode::dumpTree(WriteBuffer & buffer, size_t indent) const
|
||||
void TableNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const
|
||||
{
|
||||
buffer << std::string(indent, ' ') << "TABLE ";
|
||||
writePointerHex(this, buffer);
|
||||
buffer << ' ' << storage_id.getFullNameNotQuoted();
|
||||
buffer << std::string(indent, ' ') << "TABLE id: " << format_state.getNodeId(this);
|
||||
|
||||
if (hasAlias())
|
||||
buffer << ", alias: " << getAlias();
|
||||
|
||||
buffer << ", table_name: " << storage_id.getFullNameNotQuoted();
|
||||
}
|
||||
|
||||
bool TableNode::isEqualImpl(const IQueryTreeNode & rhs) const
|
||||
|
@ -66,15 +66,15 @@ public:
|
||||
return QueryTreeNodeType::TABLE;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override;
|
||||
|
||||
String getName() const override;
|
||||
|
||||
protected:
|
||||
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
|
||||
|
||||
void updateTreeHashImpl(HashState & state) const override;
|
||||
|
||||
protected:
|
||||
ASTPtr toASTImpl() const override;
|
||||
|
||||
QueryTreeNodePtr cloneImpl() const override;
|
||||
|
@ -16,10 +16,8 @@ public:
|
||||
return QueryTreeNodeType::TABLE;
|
||||
}
|
||||
|
||||
void dumpTree(WriteBuffer & buffer, size_t indent) const override
|
||||
void dumpTreeImpl(WriteBuffer &, FormatState &, size_t) const override
|
||||
{
|
||||
(void)(buffer);
|
||||
(void)(indent);
|
||||
}
|
||||
|
||||
bool isEqualImpl(const IQueryTreeNode &) const override
|
||||
@ -27,9 +25,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateTreeHashImpl(HashState & hash_state) const override
|
||||
void updateTreeHashImpl(HashState &) const override
|
||||
{
|
||||
(void)(hash_state);
|
||||
}
|
||||
|
||||
ASTPtr toASTImpl() const override
|
||||
|
@ -165,15 +165,17 @@ struct QueryASTSettings
|
||||
struct QueryTreeSettings
|
||||
{
|
||||
bool run_passes = false;
|
||||
bool dump_passes = false;
|
||||
bool dump_ast = false;
|
||||
Int64 passes = -1;
|
||||
bool ast = false;
|
||||
|
||||
constexpr static char name[] = "QUERYTREE";
|
||||
constexpr static char name[] = "QUERY TREE";
|
||||
|
||||
std::unordered_map<std::string, std::reference_wrapper<bool>> boolean_settings =
|
||||
{
|
||||
{"run_passes", run_passes},
|
||||
{"ast", ast}
|
||||
{"dump_passes", dump_passes},
|
||||
{"dump_ast", dump_ast}
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::reference_wrapper<Int64>> integer_settings =
|
||||
@ -381,30 +383,25 @@ QueryPipeline InterpreterExplainQuery::executeImpl()
|
||||
auto query_tree_pass_manager = QueryTreePassManager(getContext());
|
||||
addQueryTreePasses(query_tree_pass_manager);
|
||||
|
||||
if (settings.passes < 0)
|
||||
size_t pass_index = settings.passes < 0 ? query_tree_pass_manager.getPasses().size() : static_cast<size_t>(settings.passes);
|
||||
|
||||
if (settings.dump_passes)
|
||||
{
|
||||
query_tree_pass_manager.dump(buf);
|
||||
buf << '\n';
|
||||
query_tree_pass_manager.run(query_tree);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pass_index = static_cast<size_t>(settings.passes);
|
||||
query_tree_pass_manager.dump(buf, pass_index);
|
||||
if (pass_index > 0)
|
||||
buf << '\n';
|
||||
|
||||
query_tree_pass_manager.run(query_tree, pass_index);
|
||||
}
|
||||
|
||||
query_tree->dumpTree(buf, 0);
|
||||
query_tree_pass_manager.run(query_tree, pass_index);
|
||||
|
||||
query_tree->dumpTree(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
query_tree->dumpTree(buf, 0);
|
||||
query_tree->dumpTree(buf);
|
||||
}
|
||||
|
||||
if (settings.ast)
|
||||
if (settings.dump_ast)
|
||||
{
|
||||
buf << '\n';
|
||||
query_tree->toAST()->format(IAST::FormatSettings(buf, false));
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
{
|
||||
ParsedAST, /// 'EXPLAIN AST SELECT ...'
|
||||
AnalyzedSyntax, /// 'EXPLAIN SYNTAX SELECT ...'
|
||||
QueryTree, /// 'EXPLAIN QUERYTREE SELECT ...'
|
||||
QueryTree, /// 'EXPLAIN QUERY TREE SELECT ...'
|
||||
QueryPlan, /// 'EXPLAIN SELECT ...'
|
||||
QueryPipeline, /// 'EXPLAIN PIPELINE ...'
|
||||
QueryEstimates, /// 'EXPLAIN ESTIMATE ...'
|
||||
@ -110,7 +110,7 @@ private:
|
||||
{
|
||||
case ParsedAST: return "EXPLAIN AST";
|
||||
case AnalyzedSyntax: return "EXPLAIN SYNTAX";
|
||||
case QueryTree: return "EXPLAIN QUERYTREE";
|
||||
case QueryTree: return "EXPLAIN QUERY TREE";
|
||||
case QueryPlan: return "EXPLAIN";
|
||||
case QueryPipeline: return "EXPLAIN PIPELINE";
|
||||
case QueryEstimates: return "EXPLAIN ESTIMATE";
|
||||
|
@ -19,7 +19,7 @@ bool ParserExplainQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
|
||||
ParserKeyword s_ast("AST");
|
||||
ParserKeyword s_explain("EXPLAIN");
|
||||
ParserKeyword s_syntax("SYNTAX");
|
||||
ParserKeyword s_query_tree("QUERYTREE");
|
||||
ParserKeyword s_query_tree("QUERY TREE");
|
||||
ParserKeyword s_pipeline("PIPELINE");
|
||||
ParserKeyword s_plan("PLAN");
|
||||
ParserKeyword s_estimates("ESTIMATE");
|
||||
|
Loading…
Reference in New Issue
Block a user