Another attempt.

This commit is contained in:
Nikolai Kochetov 2024-04-05 16:22:57 +00:00
parent 07893fab63
commit d1c42668bd
42 changed files with 146 additions and 129 deletions

View File

@ -33,13 +33,13 @@ void ArrayJoinNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_stat
getJoinExpressionsNode()->dumpTreeImpl(buffer, format_state, indent + 4);
}
bool ArrayJoinNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool ArrayJoinNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const ArrayJoinNode &>(rhs);
return is_left == rhs_typed.is_left;
}
void ArrayJoinNode::updateTreeHashImpl(HashState & state) const
void ArrayJoinNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
state.update(is_left);
}

View File

@ -93,9 +93,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & state) const override;
void updateTreeHashImpl(HashState & state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -70,20 +70,26 @@ void ColumnNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & state, size_t
}
}
bool ColumnNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool ColumnNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions compare_options) const
{
const auto & rhs_typed = assert_cast<const ColumnNode &>(rhs);
return column == rhs_typed.column;
if (column.name != rhs_typed.column.name)
return false;
return !compare_options.compare_types || column.type->equals(*rhs_typed.column.type);
}
void ColumnNode::updateTreeHashImpl(HashState & hash_state) const
void ColumnNode::updateTreeHashImpl(HashState & hash_state, CompareOptions compare_options) const
{
hash_state.update(column.name.size());
hash_state.update(column.name);
const auto & column_type_name = column.type->getName();
hash_state.update(column_type_name.size());
hash_state.update(column_type_name);
if (compare_options.compare_types)
{
const auto & column_type_name = column.type->getName();
hash_state.update(column_type_name.size());
hash_state.update(column_type_name);
}
}
QueryTreeNodePtr ColumnNode::cloneImpl() const

View File

@ -131,9 +131,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -74,13 +74,13 @@ void ApplyColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatState
expression_node->dumpTreeImpl(buffer, format_state, indent + 4);
}
bool ApplyColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool ApplyColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const ApplyColumnTransformerNode &>(rhs);
return apply_transformer_type == rhs_typed.apply_transformer_type;
}
void ApplyColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const
void ApplyColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState & hash_state, CompareOptions) const
{
hash_state.update(static_cast<size_t>(getTransformerType()));
hash_state.update(static_cast<size_t>(getApplyTransformerType()));
@ -178,7 +178,7 @@ void ExceptColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatState
}
}
bool ExceptColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool ExceptColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const ExceptColumnTransformerNode &>(rhs);
if (except_transformer_type != rhs_typed.except_transformer_type ||
@ -198,7 +198,7 @@ bool ExceptColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs) const
return column_matcher->pattern() == rhs_column_matcher->pattern();
}
void ExceptColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const
void ExceptColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState & hash_state, CompareOptions) const
{
hash_state.update(static_cast<size_t>(getTransformerType()));
hash_state.update(static_cast<size_t>(getExceptTransformerType()));
@ -302,13 +302,13 @@ void ReplaceColumnTransformerNode::dumpTreeImpl(WriteBuffer & buffer, FormatStat
}
}
bool ReplaceColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool ReplaceColumnTransformerNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const ReplaceColumnTransformerNode &>(rhs);
return is_strict == rhs_typed.is_strict && replacements_names == rhs_typed.replacements_names;
}
void ReplaceColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const
void ReplaceColumnTransformerNode::updateTreeHashImpl(IQueryTreeNode::HashState & hash_state, CompareOptions) const
{
hash_state.update(static_cast<size_t>(getTransformerType()));

View File

@ -137,9 +137,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const override;
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;
@ -214,9 +214,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const override;
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;
@ -290,9 +290,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state) const override;
void updateTreeHashImpl(IQueryTreeNode::HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -126,17 +126,29 @@ void ConstantNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state
}
}
bool ConstantNode::isEqualImpl(const IQueryTreeNode & rhs) const
void ConstantNode::convertToNullable()
{
const auto & rhs_typed = assert_cast<const ConstantNode &>(rhs);
return *constant_value == *rhs_typed.constant_value && value_string == rhs_typed.value_string;
constant_value = std::make_shared<ConstantValue>(constant_value->getValue(), makeNullableSafe(constant_value->getType()));
}
void ConstantNode::updateTreeHashImpl(HashState & hash_state) const
bool ConstantNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions compare_options) const
{
auto type_name = constant_value->getType()->getName();
hash_state.update(type_name.size());
hash_state.update(type_name);
const auto & rhs_typed = assert_cast<const ConstantNode &>(rhs);
if (value_string != rhs_typed.value_string || constant_value->getValue() != rhs_typed.constant_value->getValue())
return false;
return !compare_options.compare_types || constant_value->getType()->equals(*rhs_typed.constant_value->getType());
}
void ConstantNode::updateTreeHashImpl(HashState & hash_state, CompareOptions compare_options) const
{
if (compare_options.compare_types)
{
auto type_name = constant_value->getType()->getName();
hash_state.update(type_name.size());
hash_state.update(type_name);
}
hash_state.update(value_string.size());
hash_state.update(value_string);

View File

@ -87,17 +87,14 @@ public:
mask_id = id;
}
void convertToNullable() override
{
constant_value = std::make_shared<ConstantValue>(constant_value->getValue(), makeNullableSafe(constant_value->getType()));
}
void convertToNullable() override;
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions compare_options) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions compare_options) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -34,14 +34,4 @@ private:
DataTypePtr data_type;
};
inline bool operator==(const ConstantValue & lhs, const ConstantValue & rhs)
{
return lhs.getValue() == rhs.getValue() && lhs.getType()->equals(*rhs.getType());
}
inline bool operator!=(const ConstantValue & lhs, const ConstantValue & rhs)
{
return !(lhs == rhs);
}
}

View File

@ -142,7 +142,7 @@ void FunctionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state
}
}
bool FunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool FunctionNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions compare_options) const
{
const auto & rhs_typed = assert_cast<const FunctionNode &>(rhs);
if (function_name != rhs_typed.function_name || isAggregateFunction() != rhs_typed.isAggregateFunction()
@ -150,6 +150,9 @@ bool FunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const
|| nulls_action != rhs_typed.nulls_action)
return false;
if (!compare_options.compare_types)
return true;
if (isResolved() != rhs_typed.isResolved())
return false;
if (!isResolved())
@ -168,7 +171,7 @@ bool FunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const
return true;
}
void FunctionNode::updateTreeHashImpl(HashState & hash_state) const
void FunctionNode::updateTreeHashImpl(HashState & hash_state, CompareOptions compare_options) const
{
hash_state.update(function_name.size());
hash_state.update(function_name);
@ -177,6 +180,9 @@ void FunctionNode::updateTreeHashImpl(HashState & hash_state) const
hash_state.update(isWindowFunction());
hash_state.update(nulls_action);
if (!compare_options.compare_types)
return;
if (!isResolved())
return;

View File

@ -208,9 +208,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions compare_options) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions compare_options) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -11,37 +11,37 @@ namespace DB
* Example of usage:
* std::unordered_map<QueryTreeNodeConstRawPtrWithHash, std::string> map;
*/
template <typename QueryTreeNodePtrType, bool compare_aliases = true>
template <typename QueryTreeNodePtrType, bool compare_aliases = true, bool compare_types = true>
struct QueryTreeNodeWithHash
{
QueryTreeNodeWithHash(QueryTreeNodePtrType node_) /// NOLINT
: node(std::move(node_))
, hash(node->getTreeHash({.compare_aliases = compare_aliases}))
, hash(node->getTreeHash({.compare_aliases = compare_aliases, .compare_types = compare_types}))
{}
QueryTreeNodePtrType node = nullptr;
CityHash_v1_0_2::uint128 hash;
};
template <typename T, bool compare_aliases>
inline bool operator==(const QueryTreeNodeWithHash<T, compare_aliases> & lhs, const QueryTreeNodeWithHash<T, compare_aliases> & rhs)
template <typename T, bool compare_aliases, bool compare_types>
inline bool operator==(const QueryTreeNodeWithHash<T, compare_aliases, compare_types> & lhs, const QueryTreeNodeWithHash<T, compare_aliases, compare_types> & rhs)
{
return lhs.hash == rhs.hash && lhs.node->isEqual(*rhs.node, {.compare_aliases = compare_aliases});
return lhs.hash == rhs.hash && lhs.node->isEqual(*rhs.node, {.compare_aliases = compare_aliases, .compare_types = compare_types});
}
template <typename T, bool compare_aliases>
inline bool operator!=(const QueryTreeNodeWithHash<T, compare_aliases> & lhs, const QueryTreeNodeWithHash<T, compare_aliases> & rhs)
template <typename T, bool compare_aliases, bool compare_types>
inline bool operator!=(const QueryTreeNodeWithHash<T, compare_aliases, compare_types> & lhs, const QueryTreeNodeWithHash<T, compare_aliases, compare_types> & rhs)
{
return !(lhs == rhs);
}
using QueryTreeNodePtrWithHash = QueryTreeNodeWithHash<QueryTreeNodePtr>;
using QueryTreeNodePtrWithHashWithoutAlias = QueryTreeNodeWithHash<QueryTreeNodePtr, /*compare_aliases*/ false>;
using QueryTreeNodePtrWithHashIgnoreTypes = QueryTreeNodeWithHash<QueryTreeNodePtr, /*compare_aliases*/ true, /*compare_types*/ false>;
using QueryTreeNodeRawPtrWithHash = QueryTreeNodeWithHash<IQueryTreeNode *>;
using QueryTreeNodeConstRawPtrWithHash = QueryTreeNodeWithHash<const IQueryTreeNode *>;
using QueryTreeNodePtrWithHashSet = std::unordered_set<QueryTreeNodePtrWithHash>;
using QueryTreeNodePtrWithHashWithoutAliasSet = std::unordered_set<QueryTreeNodePtrWithHashWithoutAlias>;
using QueryTreeNodePtrWithHashIgnoreTypesSet = std::unordered_set<QueryTreeNodePtrWithHashIgnoreTypes>;
using QueryTreeNodeConstRawPtrWithHashSet = std::unordered_set<QueryTreeNodeConstRawPtrWithHash>;
template <typename Value>
@ -52,10 +52,10 @@ using QueryTreeNodeConstRawPtrWithHashMap = std::unordered_map<QueryTreeNodeCons
}
template <typename T, bool compare_aliases>
struct std::hash<DB::QueryTreeNodeWithHash<T, compare_aliases>>
template <typename T, bool compare_aliases, bool compare_types>
struct std::hash<DB::QueryTreeNodeWithHash<T, compare_aliases, compare_types>>
{
size_t operator()(const DB::QueryTreeNodeWithHash<T, compare_aliases> & node_with_hash) const
size_t operator()(const DB::QueryTreeNodeWithHash<T, compare_aliases, compare_types> & node_with_hash) const
{
return node_with_hash.hash.low64;
}

View File

@ -107,7 +107,7 @@ bool IQueryTreeNode::isEqual(const IQueryTreeNode & rhs, CompareOptions compare_
}
if (lhs_node_to_compare->getNodeType() != rhs_node_to_compare->getNodeType() ||
!lhs_node_to_compare->isEqualImpl(*rhs_node_to_compare))
!lhs_node_to_compare->isEqualImpl(*rhs_node_to_compare, compare_options))
return false;
if (compare_options.compare_aliases && lhs_node_to_compare->alias != rhs_node_to_compare->alias)
@ -207,7 +207,7 @@ IQueryTreeNode::Hash IQueryTreeNode::getTreeHash(CompareOptions compare_options)
hash_state.update(node_to_process->alias);
}
node_to_process->updateTreeHashImpl(hash_state);
node_to_process->updateTreeHashImpl(hash_state, compare_options);
hash_state.update(node_to_process->children.size());

View File

@ -97,6 +97,7 @@ public:
struct CompareOptions
{
bool compare_aliases = true;
bool compare_types = true;
};
/** Is tree equal to other tree with node root.
@ -104,7 +105,7 @@ public:
* With default compare options aliases of query tree nodes are compared during isEqual call.
* Original ASTs of query tree nodes are not compared during isEqual call.
*/
bool isEqual(const IQueryTreeNode & rhs, CompareOptions compare_options = { .compare_aliases = true }) const;
bool isEqual(const IQueryTreeNode & rhs, CompareOptions compare_options = { .compare_aliases = true, .compare_types = true }) const;
using Hash = CityHash_v1_0_2::uint128;
using HashState = SipHash;
@ -114,7 +115,7 @@ public:
* Alias of query tree node is part of query tree hash.
* Original AST is not part of query tree hash.
*/
Hash getTreeHash(CompareOptions compare_options = { .compare_aliases = true }) const;
Hash getTreeHash(CompareOptions compare_options = { .compare_aliases = true, .compare_types = true }) const;
/// Get a deep copy of the query tree
QueryTreeNodePtr clone() const;
@ -264,12 +265,12 @@ protected:
/** Subclass must compare its internal state with rhs node internal state and do not compare children or weak pointers to other
* query tree nodes.
*/
virtual bool isEqualImpl(const IQueryTreeNode & rhs) const = 0;
virtual bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions compare_options) const = 0;
/** Subclass must update tree hash with its internal state and do not update tree hash for children or weak pointers to other
* query tree nodes.
*/
virtual void updateTreeHashImpl(HashState & hash_state) const = 0;
virtual void updateTreeHashImpl(HashState & hash_state, CompareOptions compare_options) const = 0;
/** Subclass must clone its internal state and do not clone children or weak pointers to other
* query tree nodes.

View File

@ -38,13 +38,13 @@ void IdentifierNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_sta
}
}
bool IdentifierNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool IdentifierNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const IdentifierNode &>(rhs);
return identifier == rhs_typed.identifier && table_expression_modifiers == rhs_typed.table_expression_modifiers;
}
void IdentifierNode::updateTreeHashImpl(HashState & state) const
void IdentifierNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
const auto & identifier_name = identifier.getFullName();
state.update(identifier_name.size());

View File

@ -53,9 +53,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & state) const override;
void updateTreeHashImpl(HashState & state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -28,13 +28,13 @@ void InterpolateNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_st
getInterpolateExpression()->dumpTreeImpl(buffer, format_state, indent + 4);
}
bool InterpolateNode::isEqualImpl(const IQueryTreeNode &) const
bool InterpolateNode::isEqualImpl(const IQueryTreeNode &, CompareOptions) const
{
/// No state in interpolate node
return true;
}
void InterpolateNode::updateTreeHashImpl(HashState &) const
void InterpolateNode::updateTreeHashImpl(HashState &, CompareOptions) const
{
/// No state in interpolate node
}

View File

@ -53,9 +53,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -81,13 +81,13 @@ void JoinNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, si
}
}
bool JoinNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool JoinNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const JoinNode &>(rhs);
return locality == rhs_typed.locality && strictness == rhs_typed.strictness && kind == rhs_typed.kind;
}
void JoinNode::updateTreeHashImpl(HashState & state) const
void JoinNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
state.update(locality);
state.update(strictness);

View File

@ -142,9 +142,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & state) const override;
void updateTreeHashImpl(HashState & state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -46,13 +46,13 @@ void LambdaNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state,
getExpression()->dumpTreeImpl(buffer, format_state, indent + 4);
}
bool LambdaNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool LambdaNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const LambdaNode &>(rhs);
return argument_names == rhs_typed.argument_names;
}
void LambdaNode::updateTreeHashImpl(HashState & state) const
void LambdaNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
state.update(argument_names.size());
for (const auto & argument_name : argument_names)

View File

@ -97,9 +97,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & state) const override;
void updateTreeHashImpl(HashState & state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -38,13 +38,13 @@ void ListNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, si
}
}
bool ListNode::isEqualImpl(const IQueryTreeNode &) const
bool ListNode::isEqualImpl(const IQueryTreeNode &, CompareOptions) const
{
/// No state
return true;
}
void ListNode::updateTreeHashImpl(HashState &) const
void ListNode::updateTreeHashImpl(HashState &, CompareOptions) const
{
/// No state
}

View File

@ -51,9 +51,9 @@ public:
const_iterator end() const { return children.end(); }
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState &) const override;
void updateTreeHashImpl(HashState &, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -160,7 +160,7 @@ void MatcherNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state,
}
}
bool MatcherNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool MatcherNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const MatcherNode &>(rhs);
if (matcher_type != rhs_typed.matcher_type ||
@ -181,7 +181,7 @@ bool MatcherNode::isEqualImpl(const IQueryTreeNode & rhs) const
return columns_matcher->pattern() == rhs_columns_matcher->pattern();
}
void MatcherNode::updateTreeHashImpl(HashState & hash_state) const
void MatcherNode::updateTreeHashImpl(HashState & hash_state, CompareOptions) const
{
hash_state.update(static_cast<size_t>(matcher_type));

View File

@ -135,9 +135,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -776,7 +776,7 @@ struct IdentifierResolveScope
/// Table expression node to data
std::unordered_map<QueryTreeNodePtr, TableExpressionData> table_expression_node_to_data;
QueryTreeNodePtrWithHashWithoutAliasSet nullable_group_by_keys;
QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys;
/// Here we count the number of nullable GROUP BY keys we met resolving expression.
/// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube`
/// both `number` and `tuple(number)` would be in nullable_group_by_keys.
@ -6155,12 +6155,6 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
return resolved_expression_it->second;
}
bool is_nullable_group_by_key = scope.nullable_group_by_keys.contains(node);
if (is_nullable_group_by_key)
++scope.found_nullable_group_by_key_in_scope;
SCOPE_EXIT(scope.found_nullable_group_by_key_in_scope -= is_nullable_group_by_key);
String node_alias = node->getAlias();
ProjectionNames result_projection_names;
@ -6452,10 +6446,14 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size);
if (is_nullable_group_by_key && scope.found_nullable_group_by_key_in_scope == 1 && !scope.expressions_in_resolve_process_stack.hasAggregateFunction())
if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction())
{
node = node->clone();
node->convertToNullable();
auto it = scope.nullable_group_by_keys.find(node);
if (it != scope.nullable_group_by_keys.end())
{
node = it->node->clone();
node->convertToNullable();
}
}
/** Update aliases after expression node was resolved.
@ -8028,6 +8026,9 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
if (query_node_typed.hasGroupBy())
resolveGroupByNode(query_node_typed, scope);
if (scope.group_by_use_nulls)
resolved_expressions.clear();
if (query_node_typed.hasHaving())
resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/);

View File

@ -247,7 +247,7 @@ void QueryNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, s
}
}
bool QueryNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool QueryNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const QueryNode &>(rhs);
@ -266,7 +266,7 @@ bool QueryNode::isEqualImpl(const IQueryTreeNode & rhs) const
settings_changes == rhs_typed.settings_changes;
}
void QueryNode::updateTreeHashImpl(HashState & state) const
void QueryNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
state.update(is_subquery);
state.update(is_cte);

View File

@ -589,9 +589,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState &) const override;
void updateTreeHashImpl(HashState &, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -71,7 +71,7 @@ void SortNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, si
}
}
bool SortNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool SortNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const SortNode &>(rhs);
if (sort_direction != rhs_typed.sort_direction ||
@ -89,7 +89,7 @@ bool SortNode::isEqualImpl(const IQueryTreeNode & rhs) const
return collator->getLocale() == rhs_typed.collator->getLocale();
}
void SortNode::updateTreeHashImpl(HashState & hash_state) const
void SortNode::updateTreeHashImpl(HashState & hash_state, CompareOptions) const
{
hash_state.update(sort_direction);
/// use some determined value if `nulls_sort_direction` is `nullopt`

View File

@ -131,9 +131,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -82,7 +82,7 @@ void TableFunctionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_
}
}
bool TableFunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool TableFunctionNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const TableFunctionNode &>(rhs);
if (table_function_name != rhs_typed.table_function_name)
@ -97,7 +97,7 @@ bool TableFunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const
return table_expression_modifiers == rhs_typed.table_expression_modifiers;
}
void TableFunctionNode::updateTreeHashImpl(HashState & state) const
void TableFunctionNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
state.update(table_function_name.size());
state.update(table_function_name);

View File

@ -155,9 +155,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & state) const override;
void updateTreeHashImpl(HashState & state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -52,14 +52,14 @@ void TableNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, s
}
}
bool TableNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool TableNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const TableNode &>(rhs);
return storage_id == rhs_typed.storage_id && table_expression_modifiers == rhs_typed.table_expression_modifiers &&
temporary_table_name == rhs_typed.temporary_table_name;
}
void TableNode::updateTreeHashImpl(HashState & state) const
void TableNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
if (!temporary_table_name.empty())
{

View File

@ -100,9 +100,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & state) const override;
void updateTreeHashImpl(HashState & state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -145,7 +145,7 @@ void UnionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, s
getQueriesNode()->dumpTreeImpl(buffer, format_state, indent + 4);
}
bool UnionNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool UnionNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const UnionNode &>(rhs);
@ -153,7 +153,7 @@ bool UnionNode::isEqualImpl(const IQueryTreeNode & rhs) const
union_mode == rhs_typed.union_mode;
}
void UnionNode::updateTreeHashImpl(HashState & state) const
void UnionNode::updateTreeHashImpl(HashState & state, CompareOptions) const
{
state.update(is_subquery);
state.update(is_cte);

View File

@ -143,9 +143,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState &) const override;
void updateTreeHashImpl(HashState &, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -80,14 +80,14 @@ void WindowNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state,
}
}
bool WindowNode::isEqualImpl(const IQueryTreeNode & rhs) const
bool WindowNode::isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const
{
const auto & rhs_typed = assert_cast<const WindowNode &>(rhs);
return window_frame == rhs_typed.window_frame && parent_window_name == rhs_typed.parent_window_name;
}
void WindowNode::updateTreeHashImpl(HashState & hash_state) const
void WindowNode::updateTreeHashImpl(HashState & hash_state, CompareOptions) const
{
hash_state.update(window_frame.is_default);
hash_state.update(window_frame.type);

View File

@ -169,9 +169,9 @@ public:
void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;
protected:
bool isEqualImpl(const IQueryTreeNode & rhs) const override;
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;
void updateTreeHashImpl(HashState & hash_state) const override;
void updateTreeHashImpl(HashState & hash_state, CompareOptions) const override;
QueryTreeNodePtr cloneImpl() const override;

View File

@ -22,12 +22,12 @@ public:
{
}
bool isEqualImpl(const IQueryTreeNode &) const override
bool isEqualImpl(const IQueryTreeNode &, CompareOptions) const override
{
return true;
}
void updateTreeHashImpl(HashState &) const override
void updateTreeHashImpl(HashState &, CompareOptions) const override
{
}

View File

@ -60,3 +60,5 @@
(7)
(8)
(9)
a b
a b

View File

@ -7,3 +7,5 @@ select tuple(array(number)) as x FROM numbers(10) GROUP BY number, array(number)
SELECT tuple(number) AS x FROM numbers(10) GROUP BY GROUPING SETS (number) order by x;
SELECT ignore(toFixedString('Lambda as function parameter', 28), toNullable(28), ignore(8)), sum(marks) FROM system.parts GROUP BY GROUPING SETS ((2)) FORMAT Null settings optimize_injective_functions_in_group_by=1, optimize_group_by_function_keys=1, group_by_use_nulls=1; -- { serverError ILLEGAL_AGGREGATION }
SELECT toLowCardinality(materialize('a' AS key)), 'b' AS value GROUP BY key WITH CUBE SETTINGS group_by_use_nulls = 1;