2020-07-13 10:34:25 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <Interpreters/InDepthNodeVisitor.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTOrderByElement.h>
|
|
|
|
#include <Parsers/ASTSelectQuery.h>
|
2020-11-27 11:29:39 +00:00
|
|
|
#include <Parsers/ASTExpressionList.h>
|
2020-07-13 10:34:25 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2021-11-26 15:49:40 +00:00
|
|
|
class ASTIdentifier;
|
|
|
|
|
2020-07-13 10:34:25 +00:00
|
|
|
class RedundantFunctionsInOrderByMatcher
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
struct Data
|
|
|
|
{
|
|
|
|
std::unordered_set<String> & keys;
|
2021-06-01 12:20:52 +00:00
|
|
|
ContextPtr context;
|
2020-07-13 10:34:25 +00:00
|
|
|
bool redundant = true;
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
void preventErase()
|
|
|
|
{
|
|
|
|
redundant = false;
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static void visit(const ASTPtr & ast, Data & data)
|
|
|
|
{
|
|
|
|
if (const auto * func = ast->as<ASTFunction>())
|
|
|
|
visit(*func, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void visit(const ASTFunction & ast_function, Data & data)
|
|
|
|
{
|
|
|
|
if (data.done)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool is_lambda = (ast_function.name == "lambda");
|
|
|
|
|
|
|
|
const auto & arguments = ast_function.arguments;
|
|
|
|
bool has_arguments = arguments && !arguments->children.empty();
|
|
|
|
|
|
|
|
if (is_lambda || !has_arguments)
|
|
|
|
{
|
|
|
|
data.preventErase();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If we meet function as argument then we have already checked
|
|
|
|
/// arguments of it and if it can be erased
|
|
|
|
for (const auto & arg : arguments->children)
|
|
|
|
{
|
|
|
|
/// Allow functions: visit them later
|
|
|
|
if (arg->as<ASTFunction>())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/// Allow known identifiers: they are present in ORDER BY before current item
|
|
|
|
if (auto * identifier = arg->as<ASTIdentifier>())
|
|
|
|
if (data.keys.count(getIdentifierName(identifier)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/// Reject erase others
|
|
|
|
data.preventErase();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto function = FunctionFactory::instance().tryGet(ast_function.name, data.context);
|
|
|
|
if (!function || !function->isDeterministicInScopeOfQuery())
|
|
|
|
{
|
|
|
|
data.preventErase();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool needChildVisit(const ASTPtr & node, const ASTPtr &)
|
|
|
|
{
|
2020-11-27 11:29:39 +00:00
|
|
|
/// Visit functions and their arguments, that are stored in ASTExpressionList.
|
|
|
|
return node->as<ASTFunction>() || node->as<ASTExpressionList>();
|
2020-07-13 10:34:25 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using RedundantFunctionsInOrderByVisitor = ConstInDepthNodeVisitor<RedundantFunctionsInOrderByMatcher, true>;
|
|
|
|
|
|
|
|
}
|