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_DOESNT_EXIST,
UNION_ALL_RESULT_STRUCTURES_MISMATCH,
UNION_ALL_COLUMN_ALIAS_MISMATCH,
CLIENT_OUTPUT_FORMAT_SPECIFIED,
POCO_EXCEPTION = 1000,

View File

@ -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)
{

View File

@ -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<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);
}
}
@ -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<ASTSelectQuery *>(tree)->next_union_all.get())
{
auto & next_query = *(static_cast<ASTSelectQuery *>(tree));
auto & next_query = static_cast<ASTSelectQuery &>(*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<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);
}
}

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;