dbms: Server: rewrite expression lists in each SELECT query of the UNION ALL chain, if needed. [#METR-14099]

This commit is contained in:
Alexey Arno 2014-12-19 15:48:09 +03:00
parent a362a666eb
commit 282e6f3a5b
6 changed files with 786 additions and 763 deletions

View File

@ -79,6 +79,12 @@ private:
/// Выполнить один запрос SELECT из цепочки UNION ALL.
void executeSingleQuery(bool should_perform_union_hint = true);
/** Оставить в каждом запросе цепочки UNION ALL только нужные столбцы секции SELECT.
* Однако, если используется хоть один DISTINCT в цепочке, то все столбцы считаются нужными,
* так как иначе DISTINCT работал бы по-другому.
*/
void rewriteExpressionList(const Names & required_column_names);
/// Является ли это первым запросом цепочки UNION ALL имеющей длниу >= 2.
bool isFirstSelectInsideUnionAll() const;

View File

@ -88,9 +88,9 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
if (isFirstSelectInsideUnionAll())
{
// Создаем цепочку запросов SELECT и проверяем, что результаты всех запросов SELECT cовместимые.
// NOTE Мы можем безопасно применить static_cast вместо typeid_cast,
// потому что знаем, что в цепочке UNION ALL имеются только деревья типа SELECT.
/// Создаем цепочку запросов SELECT и проверяем, что результаты всех запросов SELECT cовместимые.
/// NOTE Мы можем безопасно применить static_cast вместо typeid_cast,
/// потому что знаем, что в цепочке UNION ALL имеются только деревья типа SELECT.
InterpreterSelectQuery * interpreter = this;
Block first = interpreter->getSampleBlock();
for (ASTPtr tree = query.next_union_all; !tree.isNull(); tree = (static_cast<ASTSelectQuery &>(*tree)).next_union_all)
@ -123,12 +123,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
is_union_all_head(true),
log(&Logger::get("InterpreterSelectQuery"))
{
/** Оставляем в запросе в секции SELECT только нужные столбцы.
* Но если используется DISTINCT, то все столбцы считаются нужными, так как иначе DISTINCT работал бы по-другому.
*/
if (!query.distinct)
query.rewriteSelectExpressionList(required_column_names_);
rewriteExpressionList(required_column_names_);
init(input_);
}
@ -140,15 +135,31 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
is_union_all_head(true),
log(&Logger::get("InterpreterSelectQuery"))
{
/** Оставляем в запросе в секции SELECT только нужные столбцы.
* Но если используется DISTINCT, то все столбцы считаются нужными, так как иначе DISTINCT работал бы по-другому.
*/
if (!query.distinct)
query.rewriteSelectExpressionList(required_column_names_);
rewriteExpressionList(required_column_names_);
init(input_, table_column_names);
}
void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column_names)
{
if (query.distinct)
return;
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));
if (next_query.distinct)
return;
}
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));
next_query.rewriteSelectExpressionList(required_column_names);
}
}
bool InterpreterSelectQuery::isFirstSelectInsideUnionAll() const
{
return is_union_all_head && !query.next_union_all.isNull();

View File

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

View File

@ -0,0 +1 @@
SELECT DomainID FROM (SELECT 1 AS DomainID, 'abc' AS Domain UNION ALL SELECT 2 AS DomainID, 'def' AS Domain) ORDER BY DomainID ASC

View File

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

View File

@ -0,0 +1 @@
SELECT DomainID FROM (SELECT DISTINCT 1 AS DomainID, 'abc' AS Domain UNION ALL SELECT 2 AS DomainID, 'def' AS Domain) ORDER BY DomainID ASC