mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-28 02:21:59 +00:00
Merge pull request #63993 from ClickHouse/experiment-do-not-add-identifiers-to-expr-map
Check what would be broken if do not add all the identifiers to functions map.
This commit is contained in:
commit
523634b1c7
@ -586,6 +586,85 @@ private:
|
|||||||
std::unordered_map<std::string, QueryTreeNodes> alias_name_to_expressions;
|
std::unordered_map<std::string, QueryTreeNodes> alias_name_to_expressions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ScopeAliases
|
||||||
|
{
|
||||||
|
/// Alias name to query expression node
|
||||||
|
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_expression_node_before_group_by;
|
||||||
|
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_expression_node_after_group_by;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QueryTreeNodePtr> * alias_name_to_expression_node = nullptr;
|
||||||
|
|
||||||
|
/// Alias name to lambda node
|
||||||
|
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_lambda_node;
|
||||||
|
|
||||||
|
/// Alias name to table expression node
|
||||||
|
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_table_expression_node;
|
||||||
|
|
||||||
|
/// Expressions like `x as y` where we can't say whether it's a function, expression or table.
|
||||||
|
std::unordered_map<std::string, Identifier> transitive_aliases;
|
||||||
|
|
||||||
|
/// Nodes with duplicated aliases
|
||||||
|
std::unordered_set<QueryTreeNodePtr> nodes_with_duplicated_aliases;
|
||||||
|
std::vector<QueryTreeNodePtr> cloned_nodes_with_duplicated_aliases;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QueryTreeNodePtr> & getAliasMap(IdentifierLookupContext lookup_context)
|
||||||
|
{
|
||||||
|
switch (lookup_context)
|
||||||
|
{
|
||||||
|
case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node;
|
||||||
|
case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node;
|
||||||
|
case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class FindOption
|
||||||
|
{
|
||||||
|
FIRST_NAME,
|
||||||
|
FULL_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string & getKey(const Identifier & identifier, FindOption find_option)
|
||||||
|
{
|
||||||
|
switch (find_option)
|
||||||
|
{
|
||||||
|
case FindOption::FIRST_NAME: return identifier.front();
|
||||||
|
case FindOption::FULL_NAME: return identifier.getFullName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option)
|
||||||
|
{
|
||||||
|
auto & alias_map = getAliasMap(lookup.lookup_context);
|
||||||
|
const std::string * key = &getKey(lookup.identifier, find_option);
|
||||||
|
|
||||||
|
auto it = alias_map.find(*key);
|
||||||
|
|
||||||
|
if (it != alias_map.end())
|
||||||
|
return &it->second;
|
||||||
|
|
||||||
|
if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
while (it == alias_map.end())
|
||||||
|
{
|
||||||
|
auto jt = transitive_aliases.find(*key);
|
||||||
|
if (jt == transitive_aliases.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
key = &(getKey(jt->second, find_option));
|
||||||
|
it = alias_map.find(*key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const
|
||||||
|
{
|
||||||
|
return const_cast<ScopeAliases *>(this)->find(lookup, find_option);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Projection names is name of query tree node that is used in projection part of query node.
|
/** Projection names is name of query tree node that is used in projection part of query node.
|
||||||
* Example: SELECT id FROM test_table;
|
* Example: SELECT id FROM test_table;
|
||||||
* `id` is projection name of column node
|
* `id` is projection name of column node
|
||||||
@ -731,7 +810,7 @@ struct IdentifierResolveScope
|
|||||||
else if (parent_scope)
|
else if (parent_scope)
|
||||||
join_use_nulls = parent_scope->join_use_nulls;
|
join_use_nulls = parent_scope->join_use_nulls;
|
||||||
|
|
||||||
alias_name_to_expression_node = &alias_name_to_expression_node_before_group_by;
|
aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryTreeNodePtr scope_node;
|
QueryTreeNodePtr scope_node;
|
||||||
@ -746,17 +825,7 @@ struct IdentifierResolveScope
|
|||||||
/// Argument can be expression like constant, column, function or table expression
|
/// Argument can be expression like constant, column, function or table expression
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> expression_argument_name_to_node;
|
std::unordered_map<std::string, QueryTreeNodePtr> expression_argument_name_to_node;
|
||||||
|
|
||||||
/// Alias name to query expression node
|
ScopeAliases aliases;
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_expression_node_before_group_by;
|
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_expression_node_after_group_by;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> * alias_name_to_expression_node = nullptr;
|
|
||||||
|
|
||||||
/// Alias name to lambda node
|
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_lambda_node;
|
|
||||||
|
|
||||||
/// Alias name to table expression node
|
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> alias_name_to_table_expression_node;
|
|
||||||
|
|
||||||
/// Table column name to column node. Valid only during table ALIAS columns resolve.
|
/// Table column name to column node. Valid only during table ALIAS columns resolve.
|
||||||
ColumnNameToColumnNodeMap column_name_to_column_node;
|
ColumnNameToColumnNodeMap column_name_to_column_node;
|
||||||
@ -767,10 +836,6 @@ struct IdentifierResolveScope
|
|||||||
/// Window name to window node
|
/// Window name to window node
|
||||||
std::unordered_map<std::string, QueryTreeNodePtr> window_name_to_window_node;
|
std::unordered_map<std::string, QueryTreeNodePtr> window_name_to_window_node;
|
||||||
|
|
||||||
/// Nodes with duplicated aliases
|
|
||||||
std::unordered_set<QueryTreeNodePtr> nodes_with_duplicated_aliases;
|
|
||||||
std::vector<QueryTreeNodePtr> cloned_nodes_with_duplicated_aliases;
|
|
||||||
|
|
||||||
/// Current scope expression in resolve process stack
|
/// Current scope expression in resolve process stack
|
||||||
ExpressionsStack expressions_in_resolve_process_stack;
|
ExpressionsStack expressions_in_resolve_process_stack;
|
||||||
|
|
||||||
@ -889,7 +954,7 @@ struct IdentifierResolveScope
|
|||||||
bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction();
|
bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction();
|
||||||
expressions_in_resolve_process_stack.push(node);
|
expressions_in_resolve_process_stack.push(node);
|
||||||
if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction())
|
if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction())
|
||||||
alias_name_to_expression_node = &alias_name_to_expression_node_before_group_by;
|
aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popExpressionNode()
|
void popExpressionNode()
|
||||||
@ -897,7 +962,7 @@ struct IdentifierResolveScope
|
|||||||
bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction();
|
bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction();
|
||||||
expressions_in_resolve_process_stack.pop();
|
expressions_in_resolve_process_stack.pop();
|
||||||
if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction())
|
if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction())
|
||||||
alias_name_to_expression_node = &alias_name_to_expression_node_after_group_by;
|
aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dump identifier resolve scope
|
/// Dump identifier resolve scope
|
||||||
@ -916,16 +981,16 @@ struct IdentifierResolveScope
|
|||||||
for (const auto & [alias_name, node] : expression_argument_name_to_node)
|
for (const auto & [alias_name, node] : expression_argument_name_to_node)
|
||||||
buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n';
|
buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n';
|
||||||
|
|
||||||
buffer << "Alias name to expression node table size " << alias_name_to_expression_node->size() << '\n';
|
buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n';
|
||||||
for (const auto & [alias_name, node] : *alias_name_to_expression_node)
|
for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node)
|
||||||
buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n';
|
buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n';
|
||||||
|
|
||||||
buffer << "Alias name to function node table size " << alias_name_to_lambda_node.size() << '\n';
|
buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n';
|
||||||
for (const auto & [alias_name, node] : alias_name_to_lambda_node)
|
for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node)
|
||||||
buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n';
|
buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n';
|
||||||
|
|
||||||
buffer << "Alias name to table expression node table size " << alias_name_to_table_expression_node.size() << '\n';
|
buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n';
|
||||||
for (const auto & [alias_name, node] : alias_name_to_table_expression_node)
|
for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node)
|
||||||
buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n';
|
buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n';
|
||||||
|
|
||||||
buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n';
|
buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n';
|
||||||
@ -936,8 +1001,8 @@ struct IdentifierResolveScope
|
|||||||
for (const auto & [window_name, node] : window_name_to_window_node)
|
for (const auto & [window_name, node] : window_name_to_window_node)
|
||||||
buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n';
|
buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n';
|
||||||
|
|
||||||
buffer << "Nodes with duplicated aliases size " << nodes_with_duplicated_aliases.size() << '\n';
|
buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n';
|
||||||
for (const auto & node : nodes_with_duplicated_aliases)
|
for (const auto & node : aliases.nodes_with_duplicated_aliases)
|
||||||
buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n';
|
buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n';
|
||||||
|
|
||||||
buffer << "Expression resolve process stack " << '\n';
|
buffer << "Expression resolve process stack " << '\n';
|
||||||
@ -996,8 +1061,8 @@ struct IdentifierResolveScope
|
|||||||
class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor<QueryExpressionsAliasVisitor>
|
class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor<QueryExpressionsAliasVisitor>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit QueryExpressionsAliasVisitor(IdentifierResolveScope & scope_)
|
explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_)
|
||||||
: scope(scope_)
|
: aliases(aliases_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void visitImpl(QueryTreeNodePtr & node)
|
void visitImpl(QueryTreeNodePtr & node)
|
||||||
@ -1034,10 +1099,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
void addDuplicatingAlias(const QueryTreeNodePtr & node)
|
void addDuplicatingAlias(const QueryTreeNodePtr & node)
|
||||||
{
|
{
|
||||||
scope.nodes_with_duplicated_aliases.emplace(node);
|
aliases.nodes_with_duplicated_aliases.emplace(node);
|
||||||
auto cloned_node = node->clone();
|
auto cloned_node = node->clone();
|
||||||
scope.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node);
|
aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node);
|
||||||
scope.nodes_with_duplicated_aliases.emplace(cloned_node);
|
aliases.nodes_with_duplicated_aliases.emplace(cloned_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node)
|
void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node)
|
||||||
@ -1053,29 +1118,29 @@ private:
|
|||||||
|
|
||||||
if (is_lambda_node)
|
if (is_lambda_node)
|
||||||
{
|
{
|
||||||
if (scope.alias_name_to_expression_node->contains(alias))
|
if (aliases.alias_name_to_expression_node->contains(alias))
|
||||||
addDuplicatingAlias(node);
|
addDuplicatingAlias(node);
|
||||||
|
|
||||||
auto [_, inserted] = scope.alias_name_to_lambda_node.insert(std::make_pair(alias, node));
|
auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node));
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
addDuplicatingAlias(node);
|
addDuplicatingAlias(node);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope.alias_name_to_lambda_node.contains(alias))
|
if (aliases.alias_name_to_lambda_node.contains(alias))
|
||||||
addDuplicatingAlias(node);
|
addDuplicatingAlias(node);
|
||||||
|
|
||||||
auto [_, inserted] = scope.alias_name_to_expression_node->insert(std::make_pair(alias, node));
|
auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node));
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
addDuplicatingAlias(node);
|
addDuplicatingAlias(node);
|
||||||
|
|
||||||
/// If node is identifier put it also in scope alias name to lambda node map
|
/// If node is identifier put it into transitive aliases map.
|
||||||
if (node->getNodeType() == QueryTreeNodeType::IDENTIFIER)
|
if (const auto * identifier = typeid_cast<const IdentifierNode *>(node.get()))
|
||||||
scope.alias_name_to_lambda_node.insert(std::make_pair(alias, node));
|
aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier()));
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentifierResolveScope & scope;
|
ScopeAliases & aliases;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor<TableExpressionsAliasVisitor>
|
class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor<TableExpressionsAliasVisitor>
|
||||||
@ -1122,7 +1187,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const auto & node_alias = node->getAlias();
|
const auto & node_alias = node->getAlias();
|
||||||
auto [_, inserted] = scope.alias_name_to_table_expression_node.emplace(node_alias, node);
|
auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node);
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
|
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
|
||||||
"Multiple table expressions with same alias {}. In scope {}",
|
"Multiple table expressions with same alias {}. In scope {}",
|
||||||
@ -1193,7 +1258,7 @@ public:
|
|||||||
}
|
}
|
||||||
case QueryTreeNodeType::TABLE_FUNCTION:
|
case QueryTreeNodeType::TABLE_FUNCTION:
|
||||||
{
|
{
|
||||||
QueryExpressionsAliasVisitor expressions_alias_visitor(scope);
|
QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases);
|
||||||
resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/);
|
resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1868,7 +1933,7 @@ void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection(
|
|||||||
|
|
||||||
if (allow_expression_identifiers)
|
if (allow_expression_identifiers)
|
||||||
{
|
{
|
||||||
for (const auto & [name, expression] : *scope.alias_name_to_expression_node)
|
for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node)
|
||||||
{
|
{
|
||||||
assert(expression);
|
assert(expression);
|
||||||
auto expression_identifier = Identifier(name);
|
auto expression_identifier = Identifier(name);
|
||||||
@ -1898,13 +1963,13 @@ void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection(
|
|||||||
{
|
{
|
||||||
if (allow_function_identifiers)
|
if (allow_function_identifiers)
|
||||||
{
|
{
|
||||||
for (const auto & [name, _] : *scope.alias_name_to_expression_node)
|
for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node)
|
||||||
valid_identifiers_result.insert(Identifier(name));
|
valid_identifiers_result.insert(Identifier(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow_table_expression_identifiers)
|
if (allow_table_expression_identifiers)
|
||||||
{
|
{
|
||||||
for (const auto & [name, _] : scope.alias_name_to_table_expression_node)
|
for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node)
|
||||||
valid_identifiers_result.insert(Identifier(name));
|
valid_identifiers_result.insert(Identifier(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2793,21 +2858,7 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(cons
|
|||||||
|
|
||||||
bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope)
|
bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope)
|
||||||
{
|
{
|
||||||
const auto & identifier_bind_part = identifier_lookup.identifier.front();
|
return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr;
|
||||||
|
|
||||||
auto get_alias_name_to_node_map = [&]() -> const std::unordered_map<std::string, QueryTreeNodePtr> &
|
|
||||||
{
|
|
||||||
if (identifier_lookup.isExpressionLookup())
|
|
||||||
return *scope.alias_name_to_expression_node;
|
|
||||||
else if (identifier_lookup.isFunctionLookup())
|
|
||||||
return scope.alias_name_to_lambda_node;
|
|
||||||
|
|
||||||
return scope.alias_name_to_table_expression_node;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto & alias_name_to_node_map = get_alias_name_to_node_map();
|
|
||||||
|
|
||||||
return alias_name_to_node_map.contains(identifier_bind_part);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolve identifier from scope aliases.
|
/** Resolve identifier from scope aliases.
|
||||||
@ -2857,23 +2908,13 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const Identifier
|
|||||||
{
|
{
|
||||||
const auto & identifier_bind_part = identifier_lookup.identifier.front();
|
const auto & identifier_bind_part = identifier_lookup.identifier.front();
|
||||||
|
|
||||||
auto get_alias_name_to_node_map = [&]() -> std::unordered_map<std::string, QueryTreeNodePtr> &
|
auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME);
|
||||||
{
|
if (it == nullptr)
|
||||||
if (identifier_lookup.isExpressionLookup())
|
|
||||||
return *scope.alias_name_to_expression_node;
|
|
||||||
else if (identifier_lookup.isFunctionLookup())
|
|
||||||
return scope.alias_name_to_lambda_node;
|
|
||||||
|
|
||||||
return scope.alias_name_to_table_expression_node;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto & alias_name_to_node_map = get_alias_name_to_node_map();
|
|
||||||
auto it = alias_name_to_node_map.find(identifier_bind_part);
|
|
||||||
|
|
||||||
if (it == alias_name_to_node_map.end())
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!it->second)
|
QueryTreeNodePtr & alias_node = *it;
|
||||||
|
|
||||||
|
if (!alias_node)
|
||||||
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
||||||
"Node with alias {} is not valid. In scope {}",
|
"Node with alias {} is not valid. In scope {}",
|
||||||
identifier_bind_part,
|
identifier_bind_part,
|
||||||
@ -2893,14 +2934,14 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const Identifier
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node_type = it->second->getNodeType();
|
auto node_type = alias_node->getNodeType();
|
||||||
|
|
||||||
/// Resolve expression if necessary
|
/// Resolve expression if necessary
|
||||||
if (node_type == QueryTreeNodeType::IDENTIFIER)
|
if (node_type == QueryTreeNodeType::IDENTIFIER)
|
||||||
{
|
{
|
||||||
scope.pushExpressionNode(it->second);
|
scope.pushExpressionNode(alias_node);
|
||||||
|
|
||||||
auto & alias_identifier_node = it->second->as<IdentifierNode &>();
|
auto & alias_identifier_node = alias_node->as<IdentifierNode &>();
|
||||||
auto identifier = alias_identifier_node.getIdentifier();
|
auto identifier = alias_identifier_node.getIdentifier();
|
||||||
auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings);
|
auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings);
|
||||||
if (!lookup_result.resolved_identifier)
|
if (!lookup_result.resolved_identifier)
|
||||||
@ -2916,43 +2957,27 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const Identifier
|
|||||||
getHintsErrorMessageSuffix(hints));
|
getHintsErrorMessageSuffix(hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
it->second = lookup_result.resolved_identifier;
|
alias_node = lookup_result.resolved_identifier;
|
||||||
|
|
||||||
/** During collection of aliases if node is identifier and has alias, we cannot say if it is
|
|
||||||
* column or function node. Check QueryExpressionsAliasVisitor documentation for clarification.
|
|
||||||
*
|
|
||||||
* If we resolved identifier node as expression, we must remove identifier node alias from
|
|
||||||
* function alias map.
|
|
||||||
* If we resolved identifier node as function, we must remove identifier node alias from
|
|
||||||
* expression alias map.
|
|
||||||
*/
|
|
||||||
if (identifier_lookup.isExpressionLookup())
|
|
||||||
scope.alias_name_to_lambda_node.erase(identifier_bind_part);
|
|
||||||
else if (identifier_lookup.isFunctionLookup())
|
|
||||||
scope.alias_name_to_expression_node->erase(identifier_bind_part);
|
|
||||||
|
|
||||||
scope.popExpressionNode();
|
scope.popExpressionNode();
|
||||||
}
|
}
|
||||||
else if (node_type == QueryTreeNodeType::FUNCTION)
|
else if (node_type == QueryTreeNodeType::FUNCTION)
|
||||||
{
|
{
|
||||||
resolveExpressionNode(it->second, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/);
|
resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/);
|
||||||
}
|
}
|
||||||
else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)
|
else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)
|
||||||
{
|
{
|
||||||
if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution)
|
if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution)
|
||||||
resolveExpressionNode(it->second, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/);
|
resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryTreeNodePtr result = it->second;
|
if (identifier_lookup.identifier.isCompound() && alias_node)
|
||||||
|
|
||||||
if (identifier_lookup.identifier.isCompound() && result)
|
|
||||||
{
|
{
|
||||||
if (identifier_lookup.isExpressionLookup())
|
if (identifier_lookup.isExpressionLookup())
|
||||||
{
|
{
|
||||||
return tryResolveIdentifierFromCompoundExpression(
|
return tryResolveIdentifierFromCompoundExpression(
|
||||||
identifier_lookup.identifier,
|
identifier_lookup.identifier,
|
||||||
1 /*identifier_bind_size*/,
|
1 /*identifier_bind_size*/,
|
||||||
it->second,
|
alias_node,
|
||||||
{} /* compound_expression_source */,
|
{} /* compound_expression_source */,
|
||||||
scope,
|
scope,
|
||||||
identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */);
|
identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */);
|
||||||
@ -2967,7 +2992,7 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const Identifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return alias_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolve identifier from table columns.
|
/** Resolve identifier from table columns.
|
||||||
@ -4128,10 +4153,11 @@ IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLook
|
|||||||
* SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id)
|
* SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id)
|
||||||
* In the example, identifier `id` should be resolved into one from USING (id) column.
|
* In the example, identifier `id` should be resolved into one from USING (id) column.
|
||||||
*/
|
*/
|
||||||
auto alias_it = scope.alias_name_to_expression_node->find(identifier_lookup.identifier.getFullName());
|
|
||||||
if (alias_it != scope.alias_name_to_expression_node->end() && alias_it->second->getNodeType() == QueryTreeNodeType::COLUMN)
|
auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME);
|
||||||
|
if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN)
|
||||||
{
|
{
|
||||||
const auto & column_node = alias_it->second->as<ColumnNode &>();
|
const auto & column_node = (*alias_it)->as<ColumnNode &>();
|
||||||
if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN)
|
if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN)
|
||||||
prefer_column_name_to_alias = true;
|
prefer_column_name_to_alias = true;
|
||||||
}
|
}
|
||||||
@ -5264,7 +5290,7 @@ ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_nod
|
|||||||
scope.scope_node->formatASTForErrorMessage());
|
scope.scope_node->formatASTForErrorMessage());
|
||||||
|
|
||||||
/// Initialize aliases in lambda scope
|
/// Initialize aliases in lambda scope
|
||||||
QueryExpressionsAliasVisitor visitor(scope);
|
QueryExpressionsAliasVisitor visitor(scope.aliases);
|
||||||
visitor.visit(lambda_to_resolve.getExpression());
|
visitor.visit(lambda_to_resolve.getExpression());
|
||||||
|
|
||||||
/** Replace lambda arguments with new arguments.
|
/** Replace lambda arguments with new arguments.
|
||||||
@ -5284,8 +5310,8 @@ ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_nod
|
|||||||
const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName()
|
const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName()
|
||||||
: lambda_argument_column->getColumnName();
|
: lambda_argument_column->getColumnName();
|
||||||
|
|
||||||
bool has_expression_node = scope.alias_name_to_expression_node->contains(lambda_argument_name);
|
bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name);
|
||||||
bool has_alias_node = scope.alias_name_to_lambda_node.contains(lambda_argument_name);
|
bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name);
|
||||||
|
|
||||||
if (has_expression_node || has_alias_node)
|
if (has_expression_node || has_alias_node)
|
||||||
{
|
{
|
||||||
@ -5961,7 +5987,7 @@ ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, Identifi
|
|||||||
function_names = AggregateFunctionFactory::instance().getAllRegisteredNames();
|
function_names = AggregateFunctionFactory::instance().getAllRegisteredNames();
|
||||||
possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end());
|
possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end());
|
||||||
|
|
||||||
for (auto & [name, lambda_node] : scope.alias_name_to_lambda_node)
|
for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node)
|
||||||
{
|
{
|
||||||
if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA)
|
if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA)
|
||||||
possible_function_names.push_back(name);
|
possible_function_names.push_back(name);
|
||||||
@ -6295,7 +6321,7 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
|
|||||||
result_projection_names.push_back(node_alias);
|
result_projection_names.push_back(node_alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_duplicated_alias = scope.nodes_with_duplicated_aliases.contains(node);
|
bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node);
|
||||||
if (is_duplicated_alias)
|
if (is_duplicated_alias)
|
||||||
scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION});
|
scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION});
|
||||||
|
|
||||||
@ -6319,14 +6345,14 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
|
|||||||
*
|
*
|
||||||
* To resolve b we need to resolve a.
|
* To resolve b we need to resolve a.
|
||||||
*/
|
*/
|
||||||
auto it = scope.alias_name_to_expression_node->find(node_alias);
|
auto it = scope.aliases.alias_name_to_expression_node->find(node_alias);
|
||||||
if (it != scope.alias_name_to_expression_node->end())
|
if (it != scope.aliases.alias_name_to_expression_node->end())
|
||||||
node = it->second;
|
node = it->second;
|
||||||
|
|
||||||
if (allow_lambda_expression)
|
if (allow_lambda_expression)
|
||||||
{
|
{
|
||||||
it = scope.alias_name_to_lambda_node.find(node_alias);
|
it = scope.aliases.alias_name_to_lambda_node.find(node_alias);
|
||||||
if (it != scope.alias_name_to_lambda_node.end())
|
if (it != scope.aliases.alias_name_to_lambda_node.end())
|
||||||
node = it->second;
|
node = it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6352,17 +6378,9 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
|
|||||||
result_projection_names.push_back(projection_name_it->second);
|
result_projection_names.push_back(projection_name_it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolved_identifier_node && !node_alias.empty())
|
|
||||||
scope.alias_name_to_lambda_node.erase(node_alias);
|
|
||||||
|
|
||||||
if (!resolved_identifier_node && allow_lambda_expression)
|
if (!resolved_identifier_node && allow_lambda_expression)
|
||||||
{
|
|
||||||
resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier;
|
resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier;
|
||||||
|
|
||||||
if (resolved_identifier_node && !node_alias.empty())
|
|
||||||
scope.alias_name_to_expression_node->erase(node_alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resolved_identifier_node && allow_table_expression)
|
if (!resolved_identifier_node && allow_table_expression)
|
||||||
{
|
{
|
||||||
resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier;
|
resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier;
|
||||||
@ -6601,14 +6619,14 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
|
|||||||
*/
|
*/
|
||||||
if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls)
|
if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls)
|
||||||
{
|
{
|
||||||
auto it = scope.alias_name_to_expression_node->find(node_alias);
|
auto it = scope.aliases.alias_name_to_expression_node->find(node_alias);
|
||||||
if (it != scope.alias_name_to_expression_node->end())
|
if (it != scope.aliases.alias_name_to_expression_node->end())
|
||||||
it->second = node;
|
it->second = node;
|
||||||
|
|
||||||
if (allow_lambda_expression)
|
if (allow_lambda_expression)
|
||||||
{
|
{
|
||||||
it = scope.alias_name_to_lambda_node.find(node_alias);
|
it = scope.aliases.alias_name_to_lambda_node.find(node_alias);
|
||||||
if (it != scope.alias_name_to_lambda_node.end())
|
if (it != scope.aliases.alias_name_to_lambda_node.end())
|
||||||
it->second = node;
|
it->second = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6981,8 +6999,8 @@ void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_nod
|
|||||||
resolved_identifier = resolved_identifier->clone();
|
resolved_identifier = resolved_identifier->clone();
|
||||||
|
|
||||||
/// Update alias name to table expression map
|
/// Update alias name to table expression map
|
||||||
auto table_expression_it = scope.alias_name_to_table_expression_node.find(from_table_identifier_alias);
|
auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias);
|
||||||
if (table_expression_it != scope.alias_name_to_table_expression_node.end())
|
if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end())
|
||||||
table_expression_it->second = resolved_identifier;
|
table_expression_it->second = resolved_identifier;
|
||||||
|
|
||||||
auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers();
|
auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers();
|
||||||
@ -7181,7 +7199,7 @@ void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table
|
|||||||
alias_column_resolve_scope.context = scope.context;
|
alias_column_resolve_scope.context = scope.context;
|
||||||
|
|
||||||
/// Initialize aliases in alias column scope
|
/// Initialize aliases in alias column scope
|
||||||
QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope);
|
QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases);
|
||||||
visitor.visit(alias_column_to_resolve->getExpression());
|
visitor.visit(alias_column_to_resolve->getExpression());
|
||||||
|
|
||||||
resolveExpressionNode(alias_column_resolve_scope.scope_node,
|
resolveExpressionNode(alias_column_resolve_scope.scope_node,
|
||||||
@ -7551,7 +7569,7 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif
|
|||||||
for (auto & array_join_expression : array_join_nodes)
|
for (auto & array_join_expression : array_join_nodes)
|
||||||
{
|
{
|
||||||
auto array_join_expression_alias = array_join_expression->getAlias();
|
auto array_join_expression_alias = array_join_expression->getAlias();
|
||||||
if (!array_join_expression_alias.empty() && scope.alias_name_to_expression_node->contains(array_join_expression_alias))
|
if (!array_join_expression_alias.empty() && scope.aliases.alias_name_to_expression_node->contains(array_join_expression_alias))
|
||||||
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
|
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
|
||||||
"ARRAY JOIN expression {} with duplicate alias {}. In scope {}",
|
"ARRAY JOIN expression {} with duplicate alias {}. In scope {}",
|
||||||
array_join_expression->formatASTForErrorMessage(),
|
array_join_expression->formatASTForErrorMessage(),
|
||||||
@ -7645,8 +7663,8 @@ void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, Identif
|
|||||||
array_join_nodes = std::move(array_join_column_expressions);
|
array_join_nodes = std::move(array_join_column_expressions);
|
||||||
for (auto & array_join_column_expression : array_join_nodes)
|
for (auto & array_join_column_expression : array_join_nodes)
|
||||||
{
|
{
|
||||||
auto it = scope.alias_name_to_expression_node->find(array_join_column_expression->getAlias());
|
auto it = scope.aliases.alias_name_to_expression_node->find(array_join_column_expression->getAlias());
|
||||||
if (it != scope.alias_name_to_expression_node->end())
|
if (it != scope.aliases.alias_name_to_expression_node->end())
|
||||||
{
|
{
|
||||||
auto & array_join_column_expression_typed = array_join_column_expression->as<ColumnNode &>();
|
auto & array_join_column_expression_typed = array_join_column_expression->as<ColumnNode &>();
|
||||||
auto array_join_column = std::make_shared<ColumnNode>(array_join_column_expression_typed.getColumn(),
|
auto array_join_column = std::make_shared<ColumnNode>(array_join_column_expression_typed.getColumn(),
|
||||||
@ -7943,7 +7961,7 @@ void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node,
|
|||||||
if (alias_name.empty())
|
if (alias_name.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto [it, inserted] = scope.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node);
|
auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node);
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
|
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
|
||||||
"Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.",
|
"Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.",
|
||||||
@ -8012,7 +8030,7 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY");
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY");
|
||||||
|
|
||||||
/// Initialize aliases in query node scope
|
/// Initialize aliases in query node scope
|
||||||
QueryExpressionsAliasVisitor visitor(scope);
|
QueryExpressionsAliasVisitor visitor(scope.aliases);
|
||||||
|
|
||||||
if (query_node_typed.hasWith())
|
if (query_node_typed.hasWith())
|
||||||
visitor.visit(query_node_typed.getWithNode());
|
visitor.visit(query_node_typed.getWithNode());
|
||||||
@ -8130,7 +8148,7 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
table_expressions_visitor.visit(query_node_typed.getJoinTree());
|
table_expressions_visitor.visit(query_node_typed.getJoinTree());
|
||||||
|
|
||||||
initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope);
|
initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope);
|
||||||
scope.alias_name_to_table_expression_node.clear();
|
scope.aliases.alias_name_to_table_expression_node.clear();
|
||||||
|
|
||||||
resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor);
|
resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor);
|
||||||
}
|
}
|
||||||
@ -8180,10 +8198,10 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
/// Clone is needed cause aliases share subtrees.
|
/// Clone is needed cause aliases share subtrees.
|
||||||
/// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type
|
/// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type
|
||||||
/// See 03023_group_by_use_nulls_analyzer_crashes
|
/// See 03023_group_by_use_nulls_analyzer_crashes
|
||||||
for (auto & [key, node] : scope.alias_name_to_expression_node_before_group_by)
|
for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by)
|
||||||
scope.alias_name_to_expression_node_after_group_by[key] = node->clone();
|
scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone();
|
||||||
|
|
||||||
scope.alias_name_to_expression_node = &scope.alias_name_to_expression_node_after_group_by;
|
scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query_node_typed.hasHaving())
|
if (query_node_typed.hasHaving())
|
||||||
@ -8255,7 +8273,7 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
* After scope nodes are resolved, we can compare node with duplicate alias with
|
* After scope nodes are resolved, we can compare node with duplicate alias with
|
||||||
* node from scope alias table.
|
* node from scope alias table.
|
||||||
*/
|
*/
|
||||||
for (const auto & node_with_duplicated_alias : scope.cloned_nodes_with_duplicated_aliases)
|
for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases)
|
||||||
{
|
{
|
||||||
auto node = node_with_duplicated_alias;
|
auto node = node_with_duplicated_alias;
|
||||||
auto node_alias = node->getAlias();
|
auto node_alias = node->getAlias();
|
||||||
@ -8266,8 +8284,8 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
|
|
||||||
bool has_node_in_alias_table = false;
|
bool has_node_in_alias_table = false;
|
||||||
|
|
||||||
auto it = scope.alias_name_to_expression_node->find(node_alias);
|
auto it = scope.aliases.alias_name_to_expression_node->find(node_alias);
|
||||||
if (it != scope.alias_name_to_expression_node->end())
|
if (it != scope.aliases.alias_name_to_expression_node->end())
|
||||||
{
|
{
|
||||||
has_node_in_alias_table = true;
|
has_node_in_alias_table = true;
|
||||||
|
|
||||||
@ -8280,8 +8298,8 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
scope.scope_node->formatASTForErrorMessage());
|
scope.scope_node->formatASTForErrorMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
it = scope.alias_name_to_lambda_node.find(node_alias);
|
it = scope.aliases.alias_name_to_lambda_node.find(node_alias);
|
||||||
if (it != scope.alias_name_to_lambda_node.end())
|
if (it != scope.aliases.alias_name_to_lambda_node.end())
|
||||||
{
|
{
|
||||||
has_node_in_alias_table = true;
|
has_node_in_alias_table = true;
|
||||||
|
|
||||||
@ -8326,10 +8344,10 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
|
|||||||
|
|
||||||
/// Remove aliases from expression and lambda nodes
|
/// Remove aliases from expression and lambda nodes
|
||||||
|
|
||||||
for (auto & [_, node] : *scope.alias_name_to_expression_node)
|
for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node)
|
||||||
node->removeAlias();
|
node->removeAlias();
|
||||||
|
|
||||||
for (auto & [_, node] : scope.alias_name_to_lambda_node)
|
for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node)
|
||||||
node->removeAlias();
|
node->removeAlias();
|
||||||
|
|
||||||
query_node_typed.resolveProjectionColumns(std::move(projection_columns));
|
query_node_typed.resolveProjectionColumns(std::move(projection_columns));
|
||||||
|
@ -17,3 +17,4 @@ Alias conflict with identifier inside expression
|
|||||||
Alias setting prefer_column_name_to_alias
|
Alias setting prefer_column_name_to_alias
|
||||||
0
|
0
|
||||||
Value
|
Value
|
||||||
|
/a/b/c
|
||||||
|
@ -48,3 +48,5 @@ WITH id AS value SELECT value FROM test_table;
|
|||||||
SET prefer_column_name_to_alias = 0;
|
SET prefer_column_name_to_alias = 0;
|
||||||
|
|
||||||
DROP TABLE test_table;
|
DROP TABLE test_table;
|
||||||
|
|
||||||
|
WITH path('clickhouse.com/a/b/c') AS x SELECT x AS path;
|
||||||
|
@ -93,3 +93,11 @@ SELECT arrayMap(lambda(tuple(x), x + 1), [1, 2, 3]), lambda2(tuple(x), x + 1), 1
|
|||||||
|
|
||||||
DROP TABLE test_table_tuple;
|
DROP TABLE test_table_tuple;
|
||||||
DROP TABLE test_table;
|
DROP TABLE test_table;
|
||||||
|
|
||||||
|
WITH x -> (lambda(x) + 1) AS lambda
|
||||||
|
SELECT lambda(1); -- {serverError UNSUPPORTED_METHOD }
|
||||||
|
|
||||||
|
WITH
|
||||||
|
x -> (lambda1(x) + 1) AS lambda,
|
||||||
|
lambda AS lambda1
|
||||||
|
SELECT lambda(1); -- {serverError UNSUPPORTED_METHOD }
|
||||||
|
Loading…
Reference in New Issue
Block a user