ClickHouse/dbms/include/DB/Interpreters/ExpressionAnalyzer.h
2014-06-24 23:53:48 +04:00

239 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <DB/Parsers/IAST.h>
#include <DB/Parsers/ASTFunction.h>
#include <DB/Parsers/ASTExpressionList.h>
#include <DB/Parsers/ASTSelectQuery.h>
#include <DB/Interpreters/Context.h>
#include <DB/Interpreters/Aggregator.h>
#include <DB/Interpreters/ExpressionActions.h>
#include <DB/Interpreters/Set.h>
#include <DB/Interpreters/Join.h>
namespace DB
{
/** Превращает выражение из синтаксического дерева в последовательность действий для его выполнения.
*
* NOTE: если ast - запрос SELECT из таблицы, структура этой таблицы не должна меняться во все время жизни ExpressionAnalyzer-а.
*/
class ExpressionAnalyzer : private boost::noncopyable
{
public:
ExpressionAnalyzer(const ASTPtr & ast_, const Context & context_, size_t subquery_depth_ = 0, bool do_global_ = false)
: ast(ast_), context(context_), settings(context.getSettings()),
subquery_depth(subquery_depth_), columns(context.getColumns()), storage(getTable()), do_global(do_global_)
{
init();
}
ExpressionAnalyzer(const ASTPtr & ast_, const Context & context_, StoragePtr storage_, size_t subquery_depth_ = 0, bool do_global_ = false)
: ast(ast_), context(context_), settings(context.getSettings()),
subquery_depth(subquery_depth_), columns(context.getColumns()), storage(storage_ ? storage_ : getTable()), do_global(do_global_)
{
init();
}
/// columns - список известных столбцов (которых можно достать из таблицы).
ExpressionAnalyzer(const ASTPtr & ast_, const Context & context_, const NamesAndTypesList & columns_, size_t subquery_depth_ = 0, bool do_global_ = false)
: ast(ast_), context(context_), settings(context.getSettings()),
subquery_depth(subquery_depth_), columns(columns_), storage(getTable()), do_global(do_global_)
{
init();
}
/// Есть ли в выражении агрегатные функции или секция GROUP BY или HAVING.
bool hasAggregation() { return has_aggregation; }
/// Получить список ключей агрегирования и описаний агрегатных функций, если в запросе есть GROUP BY.
void getAggregateInfo(Names & key_names, AggregateDescriptions & aggregates);
/** Получить набор столбцов, которых достаточно прочитать из таблицы для вычисления выражения.
* Не учитываются столбцы, добавляемые из другой таблицы путём JOIN-а.
*/
Names getRequiredColumns();
/** Эти методы позволяют собрать цепочку преобразований над блоком, получающую значения в нужных секциях запроса.
*
* Пример использования:
* ExpressionActionsChain chain;
* analyzer.appendWhere(chain);
* chain.addStep();
* analyzer.appendSelect(chain);
* analyzer.appendOrderBy(chain);
* chain.finalize();
*
* Если указано only_types=true, не выполняет подзапросы в соответствующих частях запроса. Полученные таким
* образом действия не следует выполнять, они нужны только чтобы получить список столбцов с их типами.
*/
/// До агрегации:
bool appendArrayJoin(ExpressionActionsChain & chain, bool only_types);
bool appendJoin(ExpressionActionsChain & chain, bool only_types);
bool appendWhere(ExpressionActionsChain & chain, bool only_types);
bool appendGroupBy(ExpressionActionsChain & chain, bool only_types);
void appendAggregateFunctionsArguments(ExpressionActionsChain & chain, bool only_types);
/// После агрегации:
bool appendHaving(ExpressionActionsChain & chain, bool only_types);
void appendSelect(ExpressionActionsChain & chain, bool only_types);
bool appendOrderBy(ExpressionActionsChain & chain, bool only_types);
/// Удаляет все столбцы кроме выбираемых SELECT, упорядочивает оставшиеся столбцы и переименовывает их в алиасы.
void appendProjectResult(ExpressionActionsChain & chain, bool only_types);
/// Если ast не запрос SELECT, просто получает все действия для вычисления выражения.
/// Если project_result, в выходном блоке останутся только вычисленные значения в нужном порядке, переименованные в алиасы.
/// Иначе, из блока будут удаляться только временные столбцы.
ExpressionActionsPtr getActions(bool project_result);
/// Действия, которые можно сделать над пустым блоком: добавление констант и применение функций, зависящих только от констант.
/// Не выполняет подзапросы.
ExpressionActionsPtr getConstActions();
/** Множества, для создания которых нужно будет выполнить подзапрос.
* Только множества, нужные для выполнения действий, возвращенных из уже вызванных append* или getActions.
* То есть, нужно вызвать getSubquerySets после всех вызовов append* или getActions и создать все возвращенные множества перед выполнением действий.
*/
Sets getSetsWithSubqueries();
Joins getJoinsWithSubqueries();
/// Если ast - запрос SELECT, получает имена (алиасы) и типы столбцов из секции SELECT.
Block getSelectSampleBlock();
/// Все новые временные таблицы, полученные при выполнении подзапросов GLOBAL IN.
Tables external_tables;
std::unordered_map<String, BlockInputStreamPtr> external_data;
size_t external_table_id = 1;
/// Создаем какие сможем Set из секции In для использования индекса по ним
void makeSetsForIndex();
private:
ASTPtr ast;
ASTSelectQuery * select_query;
const Context & context;
Settings settings;
size_t subquery_depth;
/// Столбцы, которые упоминаются в выражении, но не были заданы в конструкторе.
NameSet unknown_required_columns;
/** Исходные столбцы.
* Сначала сюда помещаются все доступные столбцы таблицы. Затем (при разборе запроса) удаляются неиспользуемые столбцы.
*/
NamesAndTypesList columns;
/// Столбцы после ARRAY JOIN и/или агрегации.
NamesAndTypesList aggregated_columns;
/// Таблица, из которой делается запрос.
const StoragePtr storage;
bool has_aggregation = false;
NamesAndTypesList aggregation_keys;
AggregateDescriptions aggregate_descriptions;
std::unordered_map<String, SetPtr> sets_with_subqueries;
Joins joins;
/// NOTE: Пока поддерживается только один JOIN на запрос.
NameSet join_key_names_set;
NamesAndTypesList columns_added_by_join;
typedef std::unordered_map<String, ASTPtr> Aliases;
Aliases aliases;
typedef std::set<const IAST *> SetOfASTs;
typedef std::map<ASTPtr, ASTPtr> MapOfASTs;
/// Какой столбец нужно по-ARRAY-JOIN-ить, чтобы получить указанный.
/// Например, для SELECT s.v ... ARRAY JOIN a AS s сюда попадет "s.v" -> "a.v".
NameToNameMap array_join_result_to_source;
/// Для секции ARRAY JOIN отображение из алиаса в полное имя столбца.
/// Например, для ARRAY JOIN [1,2] AS b сюда попадет "b" -> "array(1,2)".
NameToNameMap array_join_alias_to_name;
/// Нужно ли подготавливать к выполнению глобальные подзапросы при анализировании запроса.
bool do_global;
void init();
static NamesAndTypesList::iterator findColumn(const String & name, NamesAndTypesList & cols);
NamesAndTypesList::iterator findColumn(const String & name) { return findColumn(name, columns); }
/** Из списка всех доступных столбцов таблицы (columns) удалить все ненужные.
* Заодно, сформировать множество неизвестных столбцов (unknown_required_columns).
*/
void removeUnusedColumns();
/** Найти столбцы, получаемые путём JOIN-а.
*/
void collectJoinedColumns(NameSet & joined_columns, NamesAndTypesList & joined_columns_name_type);
/** Создать словарь алиасов.
*/
void createAliasesDict(ASTPtr & ast, int ignore_levels = 0);
/** Для узлов-звёздочек - раскрыть их в список всех столбцов.
* Для узлов-литералов - подставить алиасы.
*/
void normalizeTree();
void normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias);
/// Находит в запросе использования внешних таблиц. Заполняет external_tables.
void findExternalTables(ASTPtr & ast);
/// Превратить перечисление значений или подзапрос в ASTSet. node - функция in или notIn.
void makeSet(ASTFunction * node, const Block & sample_block);
/// Запустить подзапрос в секции GLOBAL IN, создать временную таблицу типа Memory и запомнить эту пару в переменной external_tables.
void addExternalStorage(ASTFunction * node);
void getArrayJoinedColumns();
void getArrayJoinedColumnsImpl(ASTPtr ast);
void addMultipleArrayJoinAction(ExpressionActionsPtr & actions);
void addJoinAction(ExpressionActionsPtr & actions, bool only_types);
struct ScopeStack;
void getActionsImpl(ASTPtr ast, bool no_subqueries, bool only_consts, ScopeStack & actions_stack);
void getRootActionsImpl(ASTPtr ast, bool no_subqueries, bool only_consts, ExpressionActionsPtr & actions);
void getActionsBeforeAggregationImpl(ASTPtr ast, ExpressionActionsPtr & actions, bool no_subqueries);
/// Добавить агрегатные функции в aggregate_descriptions.
/// Установить has_aggregation = true, если есть хоть одна агрегатная функция.
void getAggregatesImpl(ASTPtr ast, ExpressionActionsPtr & actions);
/** Получить множество нужных столбцов для чтения из таблицы.
* При этом, столбцы, указанные в ignored_names, считаются ненужными. И параметр ignored_names может модифицироваться.
* Множество столбцов available_joined_columns - столбцы, доступные из JOIN-а, они не нужны для чтения из основной таблицы.
* Положить в required_joined_columns множество столбцов, доступных из JOIN-а и востребованных.
*/
void getRequiredColumnsImpl(ASTPtr ast,
NameSet & required_columns, NameSet & ignored_names,
const NameSet & available_joined_columns, NameSet & required_joined_columns);
/// Получить таблицу, из которой идет запрос
StoragePtr getTable();
/// columns - столбцы, присутствующие до начала преобразований.
void initChain(ExpressionActionsChain & chain, NamesAndTypesList & columns);
void assertSelect();
void assertAggregation();
void assertArrayJoin();
/** Создать Set из явного перечисления значений в запросе.
* Если create_ordered_set = true - создать структуру данных, подходящую для использования индекса.
*/
void makeExplicitSet(ASTFunction * node, const Block & sample_block, bool create_ordered_set);
void makeSetsForIndexImpl(ASTPtr & node, const Block & sample_block);
};
}