diff --git a/dbms/include/DB/Core/ErrorCodes.h b/dbms/include/DB/Core/ErrorCodes.h index bb63b95a37f..db032d5feb1 100644 --- a/dbms/include/DB/Core/ErrorCodes.h +++ b/dbms/include/DB/Core/ErrorCodes.h @@ -266,6 +266,7 @@ namespace ErrorCodes PARTITION_ALREADY_EXISTS, PARTITION_DOESNT_EXIST, UNION_ALL_RESULT_STRUCTURES_MISMATCH, + UNION_ALL_COLUMN_ALIAS_MISMATCH, CLIENT_OUTPUT_FORMAT_SPECIFIED, POCO_EXCEPTION = 1000, diff --git a/dbms/include/DB/Parsers/ASTSelectQuery.h b/dbms/include/DB/Parsers/ASTSelectQuery.h index 99503e976ad..68702ff08ab 100644 --- a/dbms/include/DB/Parsers/ASTSelectQuery.h +++ b/dbms/include/DB/Parsers/ASTSelectQuery.h @@ -55,20 +55,27 @@ public: /// Переименовать столбцы в такие же имена, как в source. void renameColumns(const ASTSelectQuery & source) { - ASTs & to = select_expression_list->children; const ASTs & from = source.select_expression_list->children; - + ASTs & to = select_expression_list->children; + if (from.size() != to.size()) - /// XXX Временно!!! Скоро придумаем собственные сообщение + исключение. - throw Exception("FATAL ERROR", DB::ErrorCodes::UNKNOWN_IDENTIFIER); - + throw Exception("Size mismatch in UNION ALL chain", + DB::ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH); + for (size_t i = 0; i < from.size(); ++i) - { - if (from[i]->getAliasOrColumnName() != to[i]->getAliasOrColumnName()) + { + const auto & from_alias = from[i]->tryGetAlias(); + const auto & to_alias = to[i]->tryGetAlias(); + if (!to_alias.empty() && !from_alias.empty()) + if (to_alias != from_alias) + throw Exception("Column alias mismatch in UNION ALL chain", + DB::ErrorCodes::UNION_ALL_COLUMN_ALIAS_MISMATCH); + + if (to[i]->getAliasOrColumnName() != from[i]->getAliasOrColumnName()) to[i]->setAlias(from[i]->getAliasOrColumnName()); } } - + /// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке. void rewriteSelectExpressionList(const Names & column_names) { diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 0c6a15f2504..034fee14970 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -103,11 +103,11 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType + "\n\nwhile expecting:\n\n" + first.dumpStructure() + "\n\ninstead", ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH); } - + // Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе. - for (ASTPtr tree = query.next_union_all; !tree.isNull(); tree = (static_cast(*tree)).next_union_all) + for (IAST * tree = query.next_union_all.get(); tree != nullptr; tree = static_cast(tree)->next_union_all.get()) { - ASTSelectQuery & ast = static_cast(*(tree.get())); + auto & ast = static_cast(*tree); ast.renameColumns(query); } } @@ -115,13 +115,12 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType /// /// XXX Временный boilerplate код, который сотру очень скоро. Не обращать внимание. -/// на него. Дело в том, что rewriteExpressionList() может не работать правильно, -/// если мы не вызываем renameColumns() перед ним. В свою очередь renameColumns() +/// на него. Дело в том, что функция rewriteExpressionList() может работать неправильно, +/// если мы не вызываем renameColumns() до нее. В свою очередь renameColumns() /// будет работать правильно лишь в том случае, если обладает достаточно информаций, -/// то, что возможно только после построения объекта query_analyzer. -/// Но тогда, после вызова rewriteExpressionList(), InterpreterSelectQuery содержит -/// неправильнии информации. Единственный выход - заново инициализировать объект -/// InterpreterSelectQuery. +/// то, что возможно только после создания объекта query_analyzer. +/// Но тогда, после вызова rewriteExpressionList(), объект InterpreterSelectQuery хранит +/// неправильные информации. Единственный выход - заново инициализировать этот объект. /// void InterpreterSelectQuery::reinit(const NamesAndTypesList & table_column_names) { @@ -215,7 +214,7 @@ void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column for (IAST* tree = query.next_union_all.get(); tree != nullptr; tree = static_cast(tree)->next_union_all.get()) { - auto & next_query = *(static_cast(tree)); + auto & next_query = static_cast(*tree); if (next_query.distinct) return; } @@ -223,7 +222,7 @@ void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column query.rewriteSelectExpressionList(required_column_names); for (IAST* tree = query.next_union_all.get(); tree != nullptr; tree = static_cast(tree)->next_union_all.get()) { - auto & next_query = *(static_cast(tree)); + auto & next_query = static_cast(*tree); next_query.rewriteSelectExpressionList(required_column_names); } } diff --git a/dbms/tests/queries/0_stateless/00098_9_union_all.reference b/dbms/tests/queries/0_stateless/00098_9_union_all.reference new file mode 100644 index 00000000000..1191247b6d9 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_9_union_all.reference @@ -0,0 +1,2 @@ +1 +2 diff --git a/dbms/tests/queries/0_stateless/00098_9_union_all.sql b/dbms/tests/queries/0_stateless/00098_9_union_all.sql new file mode 100644 index 00000000000..de61afcb518 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_9_union_all.sql @@ -0,0 +1 @@ +SELECT * FROM (SELECT 1 UNION ALL SELECT 2 AS X) ORDER BY 1 ASC; diff --git a/dbms/tests/queries/0_stateless/00098_a_union_all.reference b/dbms/tests/queries/0_stateless/00098_a_union_all.reference new file mode 100644 index 00000000000..1191247b6d9 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_a_union_all.reference @@ -0,0 +1,2 @@ +1 +2 diff --git a/dbms/tests/queries/0_stateless/00098_a_union_all.sql b/dbms/tests/queries/0_stateless/00098_a_union_all.sql new file mode 100644 index 00000000000..23affc04cb6 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_a_union_all.sql @@ -0,0 +1 @@ +SELECT * FROM (SELECT 1 AS X UNION ALL SELECT 2) ORDER BY X ASC; diff --git a/dbms/tests/queries/0_stateless/00098_b_union_all.reference b/dbms/tests/queries/0_stateless/00098_b_union_all.reference new file mode 100644 index 00000000000..01e79c32a8c --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_b_union_all.reference @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/dbms/tests/queries/0_stateless/00098_b_union_all.sql b/dbms/tests/queries/0_stateless/00098_b_union_all.sql new file mode 100644 index 00000000000..6ab601fb1de --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_b_union_all.sql @@ -0,0 +1 @@ +SELECT * FROM (SELECT 1 UNION ALL SELECT 2 AS X UNION ALL SELECT 3 AS Y) ORDER BY 1 ASC; diff --git a/dbms/tests/queries/0_stateless/00098_c_union_all.reference b/dbms/tests/queries/0_stateless/00098_c_union_all.reference new file mode 100644 index 00000000000..4cef767ea61 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_c_union_all.reference @@ -0,0 +1,11 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +12345678902 diff --git a/dbms/tests/queries/0_stateless/00098_c_union_all.sql b/dbms/tests/queries/0_stateless/00098_c_union_all.sql new file mode 100644 index 00000000000..1211be558a4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00098_c_union_all.sql @@ -0,0 +1 @@ +SELECT X + 1 FROM (SELECT 12345678901 AS X UNION ALL SELECT number FROM system.numbers LIMIT 10) ORDER BY X ASC;