Fixed infinite recursion in expression analyzer. [#CLICKHOUSE-3125]

This commit is contained in:
Vitaliy Lyudvichenko 2017-10-11 16:33:27 +03:00 committed by alexey-milovidov
parent 942a4df2bd
commit 7bc58340b0
3 changed files with 28 additions and 11 deletions

View File

@ -1014,7 +1014,7 @@ void ExpressionAnalyzer::normalizeTreeImpl(
* For example, in the table there is a column "domain(URL)", and we requested domain(URL). * For example, in the table there is a column "domain(URL)", and we requested domain(URL).
*/ */
String function_string = func_node->getColumnName(); String function_string = func_node->getColumnName();
NamesAndTypesList::const_iterator it = findColumn(function_string); auto it = findColumn(function_string);
if (columns.end() != it) if (columns.end() != it)
{ {
ast = std::make_shared<ASTIdentifier>(func_node->range, function_string); ast = std::make_shared<ASTIdentifier>(func_node->range, function_string);
@ -1051,27 +1051,37 @@ void ExpressionAnalyzer::normalizeTreeImpl(
if (identifier_node->kind == ASTIdentifier::Column) if (identifier_node->kind == ASTIdentifier::Column)
{ {
/// If it is an alias, but not a parent alias (for constructs like "SELECT column + 1 AS column"). /// If it is an alias, but not a parent alias (for constructs like "SELECT column + 1 AS column").
Aliases::const_iterator jt = aliases.find(identifier_node->name); auto it_alias = aliases.find(identifier_node->name);
if (jt != aliases.end() && current_alias != identifier_node->name) if (it_alias != aliases.end() && current_alias != identifier_node->name)
{ {
/// Let's replace it with the corresponding tree node. /// Let's replace it with the corresponding tree node.
if (current_asts.count(jt->second.get())) if (current_asts.count(it_alias->second.get()))
throw Exception("Cyclic aliases", ErrorCodes::CYCLIC_ALIASES); throw Exception("Cyclic aliases", ErrorCodes::CYCLIC_ALIASES);
if (!my_alias.empty() && my_alias != jt->second->getAliasOrColumnName())
if (!my_alias.empty() && my_alias != it_alias->second->getAliasOrColumnName())
{
/// Avoid infinite recursion here
auto replace_to_identifier = typeid_cast<ASTIdentifier *>(it_alias->second.get());
bool is_cycle = replace_to_identifier &&
replace_to_identifier->kind == ASTIdentifier::Column &&
replace_to_identifier->name == identifier_node->name;
if (!is_cycle)
{ {
/// In a construct like "a AS b", where a is an alias, you must set alias b to the result of substituting alias a. /// In a construct like "a AS b", where a is an alias, you must set alias b to the result of substituting alias a.
ast = jt->second->clone(); ast = it_alias->second->clone();
ast->setAlias(my_alias); ast->setAlias(my_alias);
replaced = true;
}
} }
else else
{ {
ast = jt->second; ast = it_alias->second;
}
replaced = true; replaced = true;
} }
} }
} }
}
else if (ASTExpressionList * node = typeid_cast<ASTExpressionList *>(ast.get())) else if (ASTExpressionList * node = typeid_cast<ASTExpressionList *>(ast.get()))
{ {
/// Replace * with a list of columns. /// Replace * with a list of columns.

View File

@ -1,2 +1,5 @@
1 1
1 1
0 0
0 0 0
0 0 0

View File

@ -3,3 +3,7 @@ CREATE TABLE test.nested (n Nested(x UInt8)) ENGINE = Memory;
INSERT INTO test.nested VALUES ([1, 2]); INSERT INTO test.nested VALUES ([1, 2]);
SELECT 1 AS x FROM remote('127.0.0.1', test.nested) ARRAY JOIN n.x; SELECT 1 AS x FROM remote('127.0.0.1', test.nested) ARRAY JOIN n.x;
DROP TABLE test.nested; DROP TABLE test.nested;
SELECT dummy AS dummy, dummy AS b FROM system.one;
SELECT dummy AS dummy, dummy AS b, b AS c FROM system.one;
SELECT b AS c, dummy AS b, dummy AS dummy FROM system.one;