Fix simpliest case of cyclic aliases in QueryNormalizer

This commit is contained in:
alesapin 2020-03-11 16:36:33 +03:00
parent 1143c45c3f
commit e63bb9a4a7
4 changed files with 52 additions and 5 deletions

View File

@ -91,14 +91,21 @@ void QueryNormalizer::visit(ASTIdentifier & node, ASTPtr & ast, Data & data)
return; return;
} }
/// We are alias for other column (node.name), but we are alias by
/// ourselves to some other column
auto & alias_node = it_alias->second; auto & alias_node = it_alias->second;
/// Let's replace it with the corresponding tree node. String our_alias_or_name = alias_node->getAliasOrColumnName();
if (current_asts.count(alias_node.get())) std::optional<String> our_name = IdentifierSemantic::getColumnName(alias_node);
String node_alias = ast->tryGetAlias();
if (current_asts.count(alias_node.get()) /// We have loop of multiple aliases
|| (node.name == our_alias_or_name && our_name && node_alias == *our_name)) /// Our alias points to node.name, direct loop
throw Exception("Cyclic aliases", ErrorCodes::CYCLIC_ALIASES); throw Exception("Cyclic aliases", ErrorCodes::CYCLIC_ALIASES);
String my_alias = ast->tryGetAlias(); /// Let's replace it with the corresponding tree node.
if (!my_alias.empty() && my_alias != alias_node->getAliasOrColumnName()) if (!node_alias.empty() && node_alias != our_alias_or_name)
{ {
/// Avoid infinite recursion here /// Avoid infinite recursion here
auto opt_name = IdentifierSemantic::getColumnName(alias_node); auto opt_name = IdentifierSemantic::getColumnName(alias_node);
@ -108,7 +115,7 @@ void QueryNormalizer::visit(ASTIdentifier & node, ASTPtr & ast, Data & data)
{ {
/// 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 = alias_node->clone(); ast = alias_node->clone();
ast->setAlias(my_alias); ast->setAlias(node_alias);
} }
} }
else else

View File

@ -0,0 +1,24 @@
#include <gtest/gtest.h>
#include <Interpreters/QueryNormalizer.h>
#include <Parsers/IAST.h>
#include <Parsers/queryToString.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/parseQuery.h>
using namespace DB;
TEST(QueryNormalizer, SimpleCycleAlias)
{
String query = "a as b, b as a";
ParserExpressionList parser(false);
ASTPtr ast = parseQuery(parser, query, 0);
Aliases aliases;
aliases["a"] = parseQuery(parser, "b as a", 0)->children[0];
aliases["b"] = parseQuery(parser, "a as b", 0)->children[0];
Settings settings;
QueryNormalizer::Data normalizer_data(aliases, settings);
EXPECT_THROW(QueryNormalizer(normalizer_data).visit(ast), Exception);
}

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,15 @@
DROP TABLE IF EXISTS table_with_cyclic_defaults;
CREATE TABLE table_with_cyclic_defaults (a DEFAULT b, b DEFAULT a) ENGINE = Memory; --{serverError 174}
CREATE TABLE table_with_cyclic_defaults (a DEFAULT b + 1, b DEFAULT a * a) ENGINE = Memory; --{serverError 174}
CREATE TABLE table_with_cyclic_defaults (a DEFAULT b, b DEFAULT toString(c), c DEFAULT concat(a, '1')) ENGINE = Memory; --{serverError 174}
CREATE TABLE table_with_cyclic_defaults (a DEFAULT b, b DEFAULT c, c DEFAULT a * b) ENGINE = Memory; --{serverError 174}
CREATE TABLE table_with_cyclic_defaults (a String DEFAULT b, b String DEFAULT a) ENGINE = Memory; --{serverError 174}
SELECT 1;
DROP TABLE IF EXISTS table_with_cyclic_defaults;