diff --git a/dbms/src/Functions/FunctionsConditional.h b/dbms/src/Functions/FunctionsConditional.h index bf45d8614e7..80cd1b4a867 100644 --- a/dbms/src/Functions/FunctionsConditional.h +++ b/dbms/src/Functions/FunctionsConditional.h @@ -1721,18 +1721,18 @@ public: if (cond_col) { - if (!( executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeLeftType(cond_col, block, arguments, result) - || executeString(cond_col, block, arguments, result) - || executeTuple(cond_col, block, arguments, result))) + if (!( executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeLeftType(cond_col, block, arguments, result) + || executeString(cond_col, block, arguments, result) + || executeTuple(cond_col, block, arguments, result))) throw Exception("Illegal columns " + arg_then.column->getName() + " and " + arg_else.column->getName() + " of second (then) and third (else) arguments of function " + getName(), diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index ebb1c8d5dfd..90638a39437 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -929,6 +929,27 @@ void ExpressionAnalyzer::addASTAliases(ASTPtr & ast, int ignore_levels) aliases[alias] = ast; } + else if (typeid_cast(ast.get())) + { + /// Set unique aliases for all subqueries. This is needed, because content of subqueries could change after recursive analysis, + /// and auto-generated column names could become incorrect. + + size_t subquery_index = 1; + while (true) + { + alias = "_subquery" + toString(subquery_index); + if (!aliases.count("_subquery" + toString(subquery_index))) + break; + ++subquery_index; + } + + std::cerr << ast->getColumnName() << "\n"; + + ast->setAlias(alias); + aliases[alias] = ast; + + std::cerr << ast->getAliasOrColumnName() << "\n"; + } } diff --git a/dbms/src/Parsers/ASTSubquery.cpp b/dbms/src/Parsers/ASTSubquery.cpp new file mode 100644 index 00000000000..10bb0825641 --- /dev/null +++ b/dbms/src/Parsers/ASTSubquery.cpp @@ -0,0 +1,13 @@ +#include + +namespace DB +{ + +String ASTSubquery::getColumnName() const +{ + /// This is a hack. We use alias, if available, because otherwise tree could change during analysis. + return alias.empty() ? getTreeID() : alias; +} + +} + diff --git a/dbms/src/Parsers/ASTSubquery.h b/dbms/src/Parsers/ASTSubquery.h index b28fe7f6004..1588b4954e9 100644 --- a/dbms/src/Parsers/ASTSubquery.h +++ b/dbms/src/Parsers/ASTSubquery.h @@ -31,7 +31,7 @@ public: return ptr; } - String getColumnName() const override { return getTreeID(); } + String getColumnName() const override; protected: void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override diff --git a/dbms/src/Parsers/ASTWithAlias.h b/dbms/src/Parsers/ASTWithAlias.h index 95200928431..f438c361b9a 100644 --- a/dbms/src/Parsers/ASTWithAlias.h +++ b/dbms/src/Parsers/ASTWithAlias.h @@ -17,9 +17,9 @@ public: using IAST::IAST; - String getAliasOrColumnName() const override { return alias.empty() ? getColumnName() : alias; } - String tryGetAlias() const override { return alias; } - void setAlias(const String & to) override { alias = to; } + String getAliasOrColumnName() const override { return alias.empty() ? getColumnName() : alias; } + String tryGetAlias() const override { return alias; } + void setAlias(const String & to) override { alias = to; } /// Calls formatImplWithoutAlias, and also outputs an alias. If necessary, encloses the entire expression in brackets. void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override final; diff --git a/dbms/tests/queries/0_stateless/00482_subqueries_and_aliases.reference b/dbms/tests/queries/0_stateless/00482_subqueries_and_aliases.reference new file mode 100644 index 00000000000..4f4b21bdaf0 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00482_subqueries_and_aliases.reference @@ -0,0 +1,4 @@ +1 +3 +4 +5 diff --git a/dbms/tests/queries/0_stateless/00482_subqueries_and_aliases.sql b/dbms/tests/queries/0_stateless/00482_subqueries_and_aliases.sql new file mode 100644 index 00000000000..52920fdfda7 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00482_subqueries_and_aliases.sql @@ -0,0 +1,5 @@ +SELECT 1 FROM system.one WHERE (1, 1) IN (SELECT 1 AS x, x); +SELECT 2 FROM system.one WHERE (1, 1) IN (SELECT 1 AS x, x) AND (1, 0) IN (SELECT 1 AS x, x); +SELECT 3 FROM system.one WHERE (1, 1) IN (SELECT 1 AS x, x) OR (1, 0) IN (SELECT 1 AS x, x); +SELECT 4 FROM system.one WHERE (1, 1) IN (SELECT 1 AS x, x) AND (1, 0) IN (SELECT 1 AS x, toUInt8(x - 1)); +SELECT 5 FROM system.one WHERE (1, 1) IN (SELECT 1 AS x, x) OR (1, 0) IN (SELECT 1 AS x, toUInt8(x - 1));