mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 17:41:59 +00:00
Another attempt.
This commit is contained in:
parent
07893fab63
commit
d1c42668bd
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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*/);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -60,3 +60,5 @@
|
||||
(7)
|
||||
(8)
|
||||
(9)
|
||||
a b
|
||||
a b
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user