dbms: Server: second part of the fix for column renaming in UNION ALL queries. [#METR-14099]

This commit is contained in:
Alexey Arno 2014-12-23 20:20:42 +03:00
parent ece876f05d
commit 9c9db14d95
11 changed files with 48 additions and 19 deletions

View File

@ -266,6 +266,7 @@ namespace ErrorCodes
PARTITION_ALREADY_EXISTS, PARTITION_ALREADY_EXISTS,
PARTITION_DOESNT_EXIST, PARTITION_DOESNT_EXIST,
UNION_ALL_RESULT_STRUCTURES_MISMATCH, UNION_ALL_RESULT_STRUCTURES_MISMATCH,
UNION_ALL_COLUMN_ALIAS_MISMATCH,
CLIENT_OUTPUT_FORMAT_SPECIFIED, CLIENT_OUTPUT_FORMAT_SPECIFIED,
POCO_EXCEPTION = 1000, POCO_EXCEPTION = 1000,

View File

@ -55,16 +55,23 @@ public:
/// Переименовать столбцы в такие же имена, как в source. /// Переименовать столбцы в такие же имена, как в source.
void renameColumns(const ASTSelectQuery & source) void renameColumns(const ASTSelectQuery & source)
{ {
ASTs & to = select_expression_list->children;
const ASTs & from = source.select_expression_list->children; const ASTs & from = source.select_expression_list->children;
ASTs & to = select_expression_list->children;
if (from.size() != to.size()) if (from.size() != to.size())
/// XXX Временно!!! Скоро придумаем собственные сообщение + исключение. throw Exception("Size mismatch in UNION ALL chain",
throw Exception("FATAL ERROR", DB::ErrorCodes::UNKNOWN_IDENTIFIER); DB::ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH);
for (size_t i = 0; i < from.size(); ++i) 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()); to[i]->setAlias(from[i]->getAliasOrColumnName());
} }
} }

View File

@ -105,9 +105,9 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
} }
// Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе. // Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе.
for (ASTPtr tree = query.next_union_all; !tree.isNull(); tree = (static_cast<ASTSelectQuery &>(*tree)).next_union_all) for (IAST * tree = query.next_union_all.get(); tree != nullptr; tree = static_cast<ASTSelectQuery *>(tree)->next_union_all.get())
{ {
ASTSelectQuery & ast = static_cast<ASTSelectQuery &>(*(tree.get())); auto & ast = static_cast<ASTSelectQuery &>(*tree);
ast.renameColumns(query); ast.renameColumns(query);
} }
} }
@ -115,13 +115,12 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
/// ///
/// XXX Временный boilerplate код, который сотру очень скоро. Не обращать внимание. /// XXX Временный boilerplate код, который сотру очень скоро. Не обращать внимание.
/// на него. Дело в том, что rewriteExpressionList() может не работать правильно, /// на него. Дело в том, что функция rewriteExpressionList() может работать неправильно,
/// если мы не вызываем renameColumns() перед ним. В свою очередь renameColumns() /// если мы не вызываем renameColumns() до нее. В свою очередь renameColumns()
/// будет работать правильно лишь в том случае, если обладает достаточно информаций, /// будет работать правильно лишь в том случае, если обладает достаточно информаций,
/// то, что возможно только после построения объекта query_analyzer. /// то, что возможно только после создания объекта query_analyzer.
/// Но тогда, после вызова rewriteExpressionList(), InterpreterSelectQuery содержит /// Но тогда, после вызова rewriteExpressionList(), объект InterpreterSelectQuery хранит
/// неправильнии информации. Единственный выход - заново инициализировать объект /// неправильные информации. Единственный выход - заново инициализировать этот объект.
/// InterpreterSelectQuery.
/// ///
void InterpreterSelectQuery::reinit(const NamesAndTypesList & table_column_names) 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<ASTSelectQuery *>(tree)->next_union_all.get()) for (IAST* tree = query.next_union_all.get(); tree != nullptr; tree = static_cast<ASTSelectQuery *>(tree)->next_union_all.get())
{ {
auto & next_query = *(static_cast<ASTSelectQuery *>(tree)); auto & next_query = static_cast<ASTSelectQuery &>(*tree);
if (next_query.distinct) if (next_query.distinct)
return; return;
} }
@ -223,7 +222,7 @@ void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column
query.rewriteSelectExpressionList(required_column_names); query.rewriteSelectExpressionList(required_column_names);
for (IAST* tree = query.next_union_all.get(); tree != nullptr; tree = static_cast<ASTSelectQuery *>(tree)->next_union_all.get()) for (IAST* tree = query.next_union_all.get(); tree != nullptr; tree = static_cast<ASTSelectQuery *>(tree)->next_union_all.get())
{ {
auto & next_query = *(static_cast<ASTSelectQuery *>(tree)); auto & next_query = static_cast<ASTSelectQuery &>(*tree);
next_query.rewriteSelectExpressionList(required_column_names); next_query.rewriteSelectExpressionList(required_column_names);
} }
} }

View File

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

View File

@ -0,0 +1 @@
SELECT * FROM (SELECT 1 UNION ALL SELECT 2 AS X) ORDER BY 1 ASC;

View File

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

View File

@ -0,0 +1 @@
SELECT * FROM (SELECT 1 AS X UNION ALL SELECT 2) ORDER BY X ASC;

View File

@ -0,0 +1,3 @@
1
2
3

View File

@ -0,0 +1 @@
SELECT * FROM (SELECT 1 UNION ALL SELECT 2 AS X UNION ALL SELECT 3 AS Y) ORDER BY 1 ASC;

View File

@ -0,0 +1,11 @@
1
2
3
4
5
6
7
8
9
10
12345678902

View File

@ -0,0 +1 @@
SELECT X + 1 FROM (SELECT 12345678901 AS X UNION ALL SELECT number FROM system.numbers LIMIT 10) ORDER BY X ASC;