Merge pull request #42705 from kitaisreal/analyzer-small-improvements

Analyzer improve subqueries representation
This commit is contained in:
Maksim Kita 2022-11-01 13:54:12 +03:00 committed by GitHub
commit 27a72f096c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 88 additions and 189 deletions

View File

@ -1621,34 +1621,7 @@ void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & ta
table_expression_node->formatASTForErrorMessage(),
scope.scope_node->formatASTForErrorMessage());
if (query_node || union_node)
{
auto table_expression_modifiers = query_node ? query_node->getTableExpressionModifiers() : union_node->getTableExpressionModifiers();
if (table_expression_modifiers.has_value())
{
String table_expression_modifiers_error_message;
if (table_expression_modifiers->hasFinal())
{
table_expression_modifiers_error_message += "FINAL";
if (table_expression_modifiers->hasSampleSizeRatio())
table_expression_modifiers_error_message += ", SAMPLE";
}
else if (table_expression_modifiers->hasSampleSizeRatio())
{
table_expression_modifiers_error_message += "SAMPLE";
}
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
"Table expression modifiers {} are not supported for subquery {}. In scope {}",
table_expression_modifiers_error_message,
table_expression_node->formatASTForErrorMessage(),
scope.scope_node->formatASTForErrorMessage());
}
}
else if (table_node || table_function_node)
if (table_node || table_function_node)
{
auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers();
@ -4661,17 +4634,23 @@ void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_nod
auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers();
if (auto * resolved_identifier_query_node = resolved_identifier->as<QueryNode>())
auto * resolved_identifier_query_node = resolved_identifier->as<QueryNode>();
auto * resolved_identifier_union_node = resolved_identifier->as<UnionNode>();
if (resolved_identifier_query_node || resolved_identifier_union_node)
{
resolved_identifier_query_node->setIsCTE(false);
if (resolved_identifier_query_node)
resolved_identifier_query_node->setIsCTE(false);
else
resolved_identifier_union_node->setIsCTE(false);
if (table_expression_modifiers.has_value())
resolved_identifier_query_node->setTableExpressionModifiers(*table_expression_modifiers);
}
else if (auto * resolved_identifier_union_node = resolved_identifier->as<UnionNode>())
{
resolved_identifier_union_node->setIsCTE(false);
if (table_expression_modifiers.has_value())
resolved_identifier_union_node->setTableExpressionModifiers(*table_expression_modifiers);
{
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
"Table expression modifiers {} are not supported for subquery {}",
table_expression_modifiers->formatForErrorMessage(),
resolved_identifier->formatASTForErrorMessage());
}
}
else if (auto * resolved_identifier_table_node = resolved_identifier->as<TableNode>())
{

View File

@ -74,12 +74,6 @@ void QueryNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, s
buffer << ", constant_value_type: " << constant_value->getType()->getName();
}
if (table_expression_modifiers)
{
buffer << ", ";
table_expression_modifiers->dump(buffer);
}
if (hasWith())
{
buffer << '\n' << std::string(indent + 2, ' ') << "WITH\n";
@ -195,13 +189,6 @@ bool QueryNode::isEqualImpl(const IQueryTreeNode & rhs) const
else if (!constant_value && rhs_typed.constant_value)
return false;
if (table_expression_modifiers && rhs_typed.table_expression_modifiers && table_expression_modifiers != rhs_typed.table_expression_modifiers)
return false;
else if (table_expression_modifiers && !rhs_typed.table_expression_modifiers)
return false;
else if (!table_expression_modifiers && rhs_typed.table_expression_modifiers)
return false;
return is_subquery == rhs_typed.is_subquery &&
is_cte == rhs_typed.is_cte &&
cte_name == rhs_typed.cte_name &&
@ -250,9 +237,6 @@ void QueryNode::updateTreeHashImpl(HashState & state) const
state.update(constant_value_type_name.size());
state.update(constant_value_type_name);
}
if (table_expression_modifiers)
table_expression_modifiers->updateTreeHash(state);
}
QueryTreeNodePtr QueryNode::cloneImpl() const
@ -270,7 +254,6 @@ QueryTreeNodePtr QueryNode::cloneImpl() const
result_query_node->cte_name = cte_name;
result_query_node->projection_columns = projection_columns;
result_query_node->constant_value = constant_value;
result_query_node->table_expression_modifiers = table_expression_modifiers;
return result_query_node;
}

View File

@ -176,24 +176,6 @@ public:
is_group_by_with_grouping_sets = is_group_by_with_grouping_sets_value;
}
/// Return true if query node has table expression modifiers, false otherwise
bool hasTableExpressionModifiers() const
{
return table_expression_modifiers.has_value();
}
/// Get table expression modifiers
const std::optional<TableExpressionModifiers> & getTableExpressionModifiers() const
{
return table_expression_modifiers;
}
/// Set table expression modifiers
void setTableExpressionModifiers(TableExpressionModifiers table_expression_modifiers_value)
{
table_expression_modifiers = std::move(table_expression_modifiers_value);
}
/// Returns true if query node WITH section is not empty, false otherwise
bool hasWith() const
{
@ -602,7 +584,6 @@ private:
std::string cte_name;
NamesAndTypes projection_columns;
ConstantValuePtr constant_value;
std::optional<TableExpressionModifiers> table_expression_modifiers;
SettingsChanges settings_changes;
static constexpr size_t with_child_index = 0;

View File

@ -145,12 +145,10 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectWithUnionExpression(const ASTPtr &
if (select_lists.children.size() == 1)
return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name);
auto union_node = std::make_shared<UnionNode>();
auto union_node = std::make_shared<UnionNode>(select_with_union_query_typed.union_mode);
union_node->setIsSubquery(is_subquery);
union_node->setIsCTE(!cte_name.empty());
union_node->setCTEName(cte_name);
union_node->setUnionMode(select_with_union_query_typed.union_mode);
union_node->setUnionModes(select_with_union_query_typed.list_of_modes);
union_node->setOriginalAST(select_with_union_query);
size_t select_lists_children_size = select_lists.children.size();
@ -173,23 +171,22 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr
if (select_lists.size() == 1)
return buildSelectExpression(select_lists[0], is_subquery, cte_name);
auto union_node = std::make_shared<UnionNode>();
union_node->setIsSubquery(is_subquery);
union_node->setIsCTE(!cte_name.empty());
union_node->setCTEName(cte_name);
SelectUnionMode union_mode;
if (select_intersect_except_query_typed.final_operator == ASTSelectIntersectExceptQuery::Operator::INTERSECT_ALL)
union_node->setUnionMode(SelectUnionMode::INTERSECT_ALL);
union_mode = SelectUnionMode::INTERSECT_ALL;
else if (select_intersect_except_query_typed.final_operator == ASTSelectIntersectExceptQuery::Operator::INTERSECT_DISTINCT)
union_node->setUnionMode(SelectUnionMode::INTERSECT_DISTINCT);
union_mode = SelectUnionMode::INTERSECT_DISTINCT;
else if (select_intersect_except_query_typed.final_operator == ASTSelectIntersectExceptQuery::Operator::EXCEPT_ALL)
union_node->setUnionMode(SelectUnionMode::EXCEPT_ALL);
union_mode = SelectUnionMode::EXCEPT_ALL;
else if (select_intersect_except_query_typed.final_operator == ASTSelectIntersectExceptQuery::Operator::EXCEPT_DISTINCT)
union_node->setUnionMode(SelectUnionMode::EXCEPT_DISTINCT);
union_mode = SelectUnionMode::EXCEPT_DISTINCT;
else
throw Exception(ErrorCodes::LOGICAL_ERROR, "UNION type is not initialized");
union_node->setUnionModes(SelectUnionModes(select_lists.size() - 1, union_node->getUnionMode()));
auto union_node = std::make_shared<UnionNode>(union_mode);
union_node->setIsSubquery(is_subquery);
union_node->setIsCTE(!cte_name.empty());
union_node->setCTEName(cte_name);
union_node->setOriginalAST(select_intersect_except_query);
size_t select_lists_size = select_lists.size();
@ -676,14 +673,10 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTPtr & tables_in_select
if (table_expression_modifiers)
{
if (auto * query_node = node->as<QueryNode>())
query_node->setTableExpressionModifiers(*table_expression_modifiers);
else if (auto * union_node = node->as<UnionNode>())
union_node->setTableExpressionModifiers(*table_expression_modifiers);
else
throw Exception(ErrorCodes::LOGICAL_ERROR,
"Unexpected table expression subquery node. Expected union or query. Actual {}",
node->formatASTForErrorMessage());
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
"Table expression modifiers {} are not supported for subquery {}",
table_expression_modifiers->formatForErrorMessage(),
node->formatASTForErrorMessage());
}
table_expressions.push_back(std::move(node));

View File

@ -5,6 +5,7 @@
#include <IO/WriteBuffer.h>
#include <IO/WriteHelpers.h>
#include <IO/Operators.h>
#include <IO/WriteBufferFromString.h>
namespace DB
{
@ -39,4 +40,27 @@ void TableExpressionModifiers::updateTreeHash(SipHash & hash_state) const
}
}
String TableExpressionModifiers::formatForErrorMessage() const
{
WriteBufferFromOwnString buffer;
if (has_final)
buffer << "FINAL";
if (sample_size_ratio)
{
if (has_final)
buffer << ' ';
buffer << "SAMPLE " << ASTSampleRatio::toString(*sample_size_ratio);
}
if (sample_offset_ratio)
{
if (has_final || sample_size_ratio)
buffer << ' ';
buffer << "OFFSET " << ASTSampleRatio::toString(*sample_offset_ratio);
}
return buffer.str();
}
}

View File

@ -58,6 +58,9 @@ public:
/// Update tree hash
void updateTreeHash(SipHash & hash_state) const;
/// Format for error message
String formatForErrorMessage() const;
private:
bool has_final = false;
std::optional<Rational> sample_size_ratio;

View File

@ -30,11 +30,18 @@ namespace DB
namespace ErrorCodes
{
extern const int TYPE_MISMATCH;
extern const int BAD_ARGUMENTS;
}
UnionNode::UnionNode()
UnionNode::UnionNode(SelectUnionMode union_mode_)
: IQueryTreeNode(children_size)
, union_mode(union_mode_)
{
if (union_mode == SelectUnionMode::UNION_DEFAULT ||
union_mode == SelectUnionMode::EXCEPT_DEFAULT ||
union_mode == SelectUnionMode::INTERSECT_DEFAULT)
throw Exception(ErrorCodes::BAD_ARGUMENTS, "UNION mode {} must be normalized", toString(union_mode));
children[queries_child_index] = std::make_shared<ListNode>();
}
@ -101,28 +108,8 @@ void UnionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, s
buffer << ", constant_value_type: " << constant_value->getType()->getName();
}
if (table_expression_modifiers)
{
buffer << ", ";
table_expression_modifiers->dump(buffer);
}
buffer << ", union_mode: " << toString(union_mode);
size_t union_modes_size = union_modes.size();
buffer << '\n' << std::string(indent + 2, ' ') << "UNION MODES " << union_modes_size << '\n';
for (size_t i = 0; i < union_modes_size; ++i)
{
buffer << std::string(indent + 4, ' ');
auto query_union_mode = union_modes[i];
buffer << toString(query_union_mode);
if (i + 1 != union_modes_size)
buffer << '\n';
}
buffer << '\n' << std::string(indent + 2, ' ') << "QUERIES\n";
getQueriesNode()->dumpTreeImpl(buffer, format_state, indent + 4);
}
@ -137,15 +124,8 @@ bool UnionNode::isEqualImpl(const IQueryTreeNode & rhs) const
else if (!constant_value && rhs_typed.constant_value)
return false;
if (table_expression_modifiers && rhs_typed.table_expression_modifiers && table_expression_modifiers != rhs_typed.table_expression_modifiers)
return false;
else if (table_expression_modifiers && !rhs_typed.table_expression_modifiers)
return false;
else if (!table_expression_modifiers && rhs_typed.table_expression_modifiers)
return false;
return is_subquery == rhs_typed.is_subquery && is_cte == rhs_typed.is_cte && cte_name == rhs_typed.cte_name &&
union_mode == rhs_typed.union_mode && union_modes == rhs_typed.union_modes;
union_mode == rhs_typed.union_mode;
}
void UnionNode::updateTreeHashImpl(HashState & state) const
@ -158,10 +138,6 @@ void UnionNode::updateTreeHashImpl(HashState & state) const
state.update(static_cast<size_t>(union_mode));
state.update(union_modes.size());
for (const auto & query_union_mode : union_modes)
state.update(static_cast<size_t>(query_union_mode));
if (constant_value)
{
auto constant_dump = applyVisitor(FieldVisitorToString(), constant_value->getValue());
@ -172,23 +148,16 @@ void UnionNode::updateTreeHashImpl(HashState & state) const
state.update(constant_value_type_name.size());
state.update(constant_value_type_name);
}
if (table_expression_modifiers)
table_expression_modifiers->updateTreeHash(state);
}
QueryTreeNodePtr UnionNode::cloneImpl() const
{
auto result_union_node = std::make_shared<UnionNode>();
auto result_union_node = std::make_shared<UnionNode>(union_mode);
result_union_node->is_subquery = is_subquery;
result_union_node->is_cte = is_cte;
result_union_node->cte_name = cte_name;
result_union_node->union_mode = union_mode;
result_union_node->union_modes = union_modes;
result_union_node->union_modes_set = union_modes_set;
result_union_node->constant_value = constant_value;
result_union_node->table_expression_modifiers = table_expression_modifiers;
return result_union_node;
}
@ -197,14 +166,7 @@ ASTPtr UnionNode::toASTImpl() const
{
auto select_with_union_query = std::make_shared<ASTSelectWithUnionQuery>();
select_with_union_query->union_mode = union_mode;
if (union_mode != SelectUnionMode::UNION_DEFAULT &&
union_mode != SelectUnionMode::EXCEPT_DEFAULT &&
union_mode != SelectUnionMode::INTERSECT_DEFAULT)
select_with_union_query->is_normalized = true;
select_with_union_query->list_of_modes = union_modes;
select_with_union_query->set_of_modes = union_modes_set;
select_with_union_query->is_normalized = true;
select_with_union_query->children.push_back(getQueriesNode()->toAST());
select_with_union_query->list_of_selects = select_with_union_query->children.back();

View File

@ -19,6 +19,7 @@ namespace ErrorCodes
}
/** Union node represents union of queries in query tree.
* Union node must be initialized with normalized union mode.
*
* Example: (SELECT id FROM test_table) UNION ALL (SELECT id FROM test_table_2);
* Example: (SELECT id FROM test_table) UNION DISTINCT (SELECT id FROM test_table_2);
@ -41,7 +42,8 @@ using UnionNodePtr = std::shared_ptr<UnionNode>;
class UnionNode final : public IQueryTreeNode
{
public:
explicit UnionNode();
/// Construct union node with normalized union mode
explicit UnionNode(SelectUnionMode union_mode_);
/// Returns true if union node is subquery, false otherwise
bool isSubquery() const
@ -85,25 +87,6 @@ public:
return union_mode;
}
/// Set union mode value
void setUnionMode(SelectUnionMode union_mode_value)
{
union_mode = union_mode_value;
}
/// Get union modes
const SelectUnionModes & getUnionModes() const
{
return union_modes;
}
/// Set union modes value
void setUnionModes(const SelectUnionModes & union_modes_value)
{
union_modes = union_modes_value;
union_modes_set = SelectUnionModesSet(union_modes.begin(), union_modes.end());
}
/// Get union node queries
const ListNode & getQueries() const
{
@ -128,24 +111,6 @@ public:
return children[queries_child_index];
}
/// Return true if union node has table expression modifiers, false otherwise
bool hasTableExpressionModifiers() const
{
return table_expression_modifiers.has_value();
}
/// Get table expression modifiers
const std::optional<TableExpressionModifiers> & getTableExpressionModifiers() const
{
return table_expression_modifiers;
}
/// Set table expression modifiers
void setTableExpressionModifiers(TableExpressionModifiers table_expression_modifiers_value)
{
table_expression_modifiers = std::move(table_expression_modifiers_value);
}
/// Compute union node projection columns
NamesAndTypes computeProjectionColumns() const;
@ -189,10 +154,7 @@ private:
bool is_cte = false;
std::string cte_name;
SelectUnionMode union_mode;
SelectUnionModes union_modes;
SelectUnionModesSet union_modes_set;
ConstantValuePtr constant_value;
std::optional<TableExpressionModifiers> table_expression_modifiers;
static constexpr size_t queries_child_index = 0;
static constexpr size_t children_size = queries_child_index + 1;

View File

@ -98,11 +98,6 @@ static ASTPtr convertIntoTableExpressionAST(const QueryTreeNodePtr & table_expre
if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)
{
if (auto * query_node = table_expression_node->as<QueryNode>())
table_expression_modifiers = query_node->getTableExpressionModifiers();
else if (auto * union_node = table_expression_node->as<UnionNode>())
table_expression_modifiers = union_node->getTableExpressionModifiers();
result_table_expression->subquery = result_table_expression->children.back();
}
else if (node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::IDENTIFIER)

View File

@ -0,0 +1,17 @@
SET allow_experimental_analyzer = 1;
SELECT * FROM (SELECT 1) FINAL; -- { serverError 1 }
SELECT * FROM (SELECT 1) SAMPLE 1/2; -- { serverError 1 }
SELECT * FROM (SELECT 1) FINAL SAMPLE 1/2; -- { serverError 1 }
WITH cte_subquery AS (SELECT 1) SELECT * FROM cte_subquery FINAL; -- { serverError 1 }
WITH cte_subquery AS (SELECT 1) SELECT * FROM cte_subquery SAMPLE 1/2; -- { serverError 1 }
WITH cte_subquery AS (SELECT 1) SELECT * FROM cte_subquery FINAL SAMPLE 1/2; -- { serverError 1 }
SELECT * FROM (SELECT 1 UNION ALL SELECT 1) FINAL; -- { serverError 1 }
SELECT * FROM (SELECT 1 UNION ALL SELECT 1) SAMPLE 1/2; -- { serverError 1 }
SELECT * FROM (SELECT 1 UNION ALL SELECT 1) FINAL SAMPLE 1/2; -- { serverError 1 }
WITH cte_subquery AS (SELECT 1 UNION ALL SELECT 1) SELECT * FROM cte_subquery FINAL; -- { serverError 1 }
WITH cte_subquery AS (SELECT 1 UNION ALL SELECT 1) SELECT * FROM cte_subquery SAMPLE 1/2; -- { serverError 1 }
WITH cte_subquery AS (SELECT 1 UNION ALL SELECT 1) SELECT * FROM cte_subquery FINAL SAMPLE 1/2; -- { serverError 1 }