2020-06-17 09:32:43 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <Functions/FunctionFactory.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Interpreters/InDepthNodeVisitor.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTLiteral.h>
|
|
|
|
#include <Parsers/ASTSelectQuery.h>
|
|
|
|
#include <Parsers/ASTSetQuery.h>
|
|
|
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
|
|
|
#include <Parsers/IAST.h>
|
|
|
|
#include <Common/typeid_cast.h>
|
2020-10-13 05:30:56 +00:00
|
|
|
#include <Parsers/ASTSubquery.h>
|
2020-06-17 09:32:43 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2020-06-19 18:04:57 +00:00
|
|
|
/// Recursive traversal and check for optimizeAggregateFunctionsOfGroupByKeys
|
2020-06-17 09:32:43 +00:00
|
|
|
struct KeepAggregateFunctionMatcher
|
|
|
|
{
|
|
|
|
struct Data
|
|
|
|
{
|
2020-11-12 19:50:01 +00:00
|
|
|
const NameSet & group_by_keys;
|
|
|
|
bool keep_aggregator;
|
2020-06-17 09:32:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using Visitor = InDepthNodeVisitor<KeepAggregateFunctionMatcher, true>;
|
|
|
|
|
|
|
|
static bool needChildVisit(const ASTPtr & node, const ASTPtr &)
|
|
|
|
{
|
|
|
|
return !(node->as<ASTFunction>());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void visit(ASTFunction & function_node, Data & data)
|
|
|
|
{
|
2020-11-12 19:50:01 +00:00
|
|
|
if (function_node.arguments->children.empty())
|
2020-06-17 09:32:43 +00:00
|
|
|
{
|
|
|
|
data.keep_aggregator = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!data.group_by_keys.count(function_node.getColumnName()))
|
|
|
|
{
|
|
|
|
Visitor(data).visit(function_node.arguments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void visit(ASTIdentifier & ident, Data & data)
|
|
|
|
{
|
2020-11-12 19:50:01 +00:00
|
|
|
/// if variable of a function is not in GROUP BY keys, this function should not be deleted
|
|
|
|
if (!data.group_by_keys.count(ident.getColumnName()))
|
2020-06-17 09:32:43 +00:00
|
|
|
data.keep_aggregator = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void visit(const ASTPtr & ast, Data & data)
|
|
|
|
{
|
|
|
|
if (data.keep_aggregator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (auto * function_node = ast->as<ASTFunction>())
|
|
|
|
{
|
|
|
|
visit(*function_node, data);
|
|
|
|
}
|
|
|
|
else if (auto * ident = ast->as<ASTIdentifier>())
|
|
|
|
{
|
|
|
|
visit(*ident, data);
|
|
|
|
}
|
|
|
|
else if (!ast->as<ASTExpressionList>())
|
|
|
|
{
|
|
|
|
data.keep_aggregator = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-12 19:50:01 +00:00
|
|
|
using KeepAggregateFunctionVisitor = KeepAggregateFunctionMatcher::Visitor;
|
2020-06-17 09:32:43 +00:00
|
|
|
|
|
|
|
class SelectAggregateFunctionOfGroupByKeysMatcher
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
struct Data
|
|
|
|
{
|
2020-11-12 19:50:01 +00:00
|
|
|
const NameSet & group_by_keys;
|
2020-06-17 09:32:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool needChildVisit(const ASTPtr & node, const ASTPtr &)
|
|
|
|
{
|
2020-10-13 05:48:16 +00:00
|
|
|
/// Don't descent into table functions and subqueries and special case for ArrayJoin.
|
2020-11-12 19:50:01 +00:00
|
|
|
return !node->as<ASTSubquery>() && !node->as<ASTTableExpression>()
|
|
|
|
&& !node->as<ASTSelectWithUnionQuery>() && !node->as<ASTArrayJoin>();
|
2020-06-17 09:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void visit(ASTPtr & ast, Data & data)
|
|
|
|
{
|
2020-06-19 18:04:57 +00:00
|
|
|
/// Check if function is min/max/any
|
2020-06-17 09:32:43 +00:00
|
|
|
auto * function_node = ast->as<ASTFunction>();
|
|
|
|
if (function_node && (function_node->name == "min" || function_node->name == "max" ||
|
|
|
|
function_node->name == "any" || function_node->name == "anyLast"))
|
|
|
|
{
|
2020-11-12 19:50:01 +00:00
|
|
|
KeepAggregateFunctionVisitor::Data keep_data{data.group_by_keys, false};
|
2020-12-04 02:15:44 +00:00
|
|
|
if (function_node->arguments) KeepAggregateFunctionVisitor(keep_data).visit(function_node->arguments);
|
2020-06-17 09:32:43 +00:00
|
|
|
|
2020-06-19 18:04:57 +00:00
|
|
|
/// Place argument of an aggregate function instead of function
|
2020-12-04 02:15:44 +00:00
|
|
|
if (!keep_data.keep_aggregator && function_node->arguments && !function_node->arguments->children.empty())
|
2020-06-17 09:32:43 +00:00
|
|
|
{
|
2020-06-19 18:04:57 +00:00
|
|
|
String alias = function_node->alias;
|
2020-06-17 09:32:43 +00:00
|
|
|
ast = (function_node->arguments->children[0])->clone();
|
2020-06-19 18:04:57 +00:00
|
|
|
ast->setAlias(alias);
|
2020-06-17 09:32:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using SelectAggregateFunctionOfGroupByKeysVisitor = InDepthNodeVisitor<SelectAggregateFunctionOfGroupByKeysMatcher, true>;
|
|
|
|
|
|
|
|
}
|