aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Interpreters/DuplicateOrderByVisitor.cpp
blob: 409e91259fc6712b7f8dd3df1fb43689eb0b4d55 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <Interpreters/DuplicateOrderByVisitor.h>
#include <Functions/FunctionFactory.h>
#include <AggregateFunctions/AggregateFunctionFactory.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTSetQuery.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ASTOrderByElement.h>
#include <Common/typeid_cast.h>


namespace DB
{

namespace ErrorCodes
{
    extern const int UNKNOWN_TYPE_OF_AST_NODE;
}


namespace
{

/// Checks if SELECT has stateful functions
class ASTFunctionStatefulData
{
public:
    using TypeToVisit = ASTFunction;

    ContextPtr context;
    bool & is_stateful;
    void visit(ASTFunction & ast_function, ASTPtr &)
    {
        auto aggregate_function_properties = AggregateFunctionFactory::instance().tryGetProperties(ast_function.name);

        if (aggregate_function_properties && aggregate_function_properties->is_order_dependent)
        {
            is_stateful = true;
            return;
        }

        const auto & function = FunctionFactory::instance().tryGet(ast_function.name, context);

        if (function && function->isStateful())
        {
            is_stateful = true;
            return;
        }
    }
};

using ASTFunctionStatefulMatcher = OneTypeMatcher<ASTFunctionStatefulData>;
using ASTFunctionStatefulVisitor = InDepthNodeVisitor<ASTFunctionStatefulMatcher, true>;

}


void DuplicateOrderByFromSubqueriesData::visit(ASTSelectQuery & select_query, ASTPtr &)
{
    if (done)
        return;
    done = true;

    if (select_query.orderBy())
    {
        /// If we have limits then the ORDER BY is non-removable.
        if (select_query.limitBy()
            || select_query.limitByOffset()
            || select_query.limitByLength()
            || select_query.limitLength()
            || select_query.limitOffset())
        {
            return;
        }

        /// If ORDER BY contains filling (in addition to sorting) it is non-removable.
        for (const auto & child : select_query.orderBy()->children)
        {
            auto * ast = child->as<ASTOrderByElement>();
            if (!ast || ast->children.empty())
                throw Exception(ErrorCodes::UNKNOWN_TYPE_OF_AST_NODE, "Bad ORDER BY expression AST");

            if (ast->with_fill)
                return;
        }

        select_query.setExpression(ASTSelectQuery::Expression::ORDER_BY, nullptr);
    }
}

void DuplicateOrderByData::visit(ASTSelectQuery & select_query, ASTPtr &)
{
    if (select_query.orderBy() || select_query.groupBy())
    {
        for (auto & elem : select_query.children)
        {
            if (elem->as<ASTExpressionList>())
            {
                bool is_stateful = false;
                ASTFunctionStatefulVisitor::Data data{context, is_stateful};
                ASTFunctionStatefulVisitor(data).visit(elem);
                if (is_stateful)
                    return;
            }
        }

        if (auto select_table_ptr = select_query.tables())
        {
            if (auto * select_table = select_table_ptr->as<ASTTablesInSelectQuery>())
            {
                if (!select_table->children.empty())
                {
                    DuplicateOrderByFromSubqueriesVisitor::Data data{false};
                    DuplicateOrderByFromSubqueriesVisitor(data).visit(select_table->children[0]);
                }
            }
        }
    }
}

}