Merge pull request #27757 from kssenii/fix-intersect-cast

Fix intersect/except with limit
This commit is contained in:
Kseniia Sumarokova 2021-08-17 21:37:37 +03:00 committed by GitHub
commit 78105ecba7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 9 deletions

View File

@ -8,6 +8,7 @@
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTOrderByElement.h>
#include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTSelectIntersectExceptQuery.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/parseQuery.h>
@ -878,16 +879,39 @@ static bool hasWithTotalsInAnySubqueryInFromClause(const ASTSelectQuery & query)
{
if (const auto * ast_union = query_table->as<ASTSelectWithUnionQuery>())
{
/// NOTE: Child of subquery can be ASTSelectWithUnionQuery or ASTSelectQuery,
/// and after normalization, the height of the AST tree is at most 2
for (const auto & elem : ast_union->list_of_selects->children)
{
/// After normalization for union child node the height of the AST tree is at most 2.
if (const auto * child_union = elem->as<ASTSelectWithUnionQuery>())
{
for (const auto & child_elem : child_union->list_of_selects->children)
if (hasWithTotalsInAnySubqueryInFromClause(child_elem->as<ASTSelectQuery &>()))
return true;
}
/// After normalization in case there are intersect or except nodes, the height of
/// the AST tree can have any depth (each intersect/except adds a level), but the
/// number of children in those nodes is always 2.
else if (elem->as<ASTSelectIntersectExceptQuery>())
{
std::function<bool(ASTPtr)> traverse_recursively = [&](ASTPtr child_ast) -> bool
{
if (const auto * child = child_ast->as <ASTSelectQuery>())
return hasWithTotalsInAnySubqueryInFromClause(child->as<ASTSelectQuery &>());
if (const auto * child = child_ast->as<ASTSelectWithUnionQuery>())
for (const auto & subchild : child->list_of_selects->children)
if (traverse_recursively(subchild))
return true;
if (const auto * child = child_ast->as<ASTSelectIntersectExceptQuery>())
for (const auto & subchild : child->children)
if (traverse_recursively(subchild))
return true;
return false;
};
if (traverse_recursively(elem))
return true;
}
else
{
if (hasWithTotalsInAnySubqueryInFromClause(elem->as<ASTSelectQuery &>()))

View File

@ -33,18 +33,21 @@ void ASTSelectWithUnionQuery::formatQueryImpl(const FormatSettings & settings, F
auto mode_to_str = [&](auto mode)
{
if (mode == Mode::Unspecified)
return "";
else if (mode == Mode::ALL)
return " ALL";
else
return " DISTINCT";
if (mode == Mode::ALL)
return "UNION ALL";
else if (mode == Mode::DISTINCT)
return "UNION DISTINCT";
else if (mode == Mode::INTERSECT)
return "INTERSECT";
else if (mode == Mode::EXCEPT)
return "EXCEPT";
return "";
};
for (ASTs::const_iterator it = list_of_selects->children.begin(); it != list_of_selects->children.end(); ++it)
{
if (it != list_of_selects->children.begin())
settings.ostr << settings.nl_or_ws << indent_str << (settings.hilite ? hilite_keyword : "") << "UNION"
settings.ostr << settings.nl_or_ws << indent_str << (settings.hilite ? hilite_keyword : "")
<< mode_to_str((is_normalized) ? union_mode : list_of_modes[it - list_of_selects->children.begin() - 1])
<< (settings.hilite ? hilite_none : "");

View File

@ -84,6 +84,13 @@ select count() from (select number from numbers(100) intersect select number fro
30
select count() from (select number from numbers(1000000) intersect select number from numbers(200000, 600000) except select number from numbers(300000, 200000) except select number from numbers(600000, 200000));
200000
select count() from (select 1 intersect select 1) limit 100;
1
select count() from (select 1 except select 2) limit 100;
1
with (select count() from (select 1 union distinct select 2 except select 1)) as max
select count() from (select 1 union all select max) limit 100;
2
select 1 union all select 1 intersect select 1;
1
1

View File

@ -30,6 +30,11 @@ select count() from (select number from numbers(100) intersect select number fro
select count() from (select number from numbers(100) intersect select number from numbers(20, 60) except select number from numbers(30, 20) except select number from numbers(60, 20) union all select number from numbers(100, 10));
select count() from (select number from numbers(1000000) intersect select number from numbers(200000, 600000) except select number from numbers(300000, 200000) except select number from numbers(600000, 200000));
select count() from (select 1 intersect select 1) limit 100;
select count() from (select 1 except select 2) limit 100;
with (select count() from (select 1 union distinct select 2 except select 1)) as max
select count() from (select 1 union all select max) limit 100;
select 1 union all select 1 intersect select 1;
select 1 union all select 1 intersect select 2;
select * from (select 1 union all select 2 union all select 3 union all select 4 except select 3 union all select 5) order by 1;