dbms: development [#METR-11370].

This commit is contained in:
Alexey Milovidov 2014-06-13 03:21:38 +04:00
parent 607485d82a
commit 1ba07d65ad
8 changed files with 165 additions and 84 deletions

View File

@ -135,6 +135,7 @@ private:
AggregateDescriptions aggregate_descriptions;
std::unordered_map<String, SetPtr> sets_with_subqueries;
Joins joins;
typedef std::unordered_map<String, ASTPtr> Aliases;
Aliases aliases;
@ -158,8 +159,18 @@ private:
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();
/** Найти обычные (не ARRAY) JOIN-ы, записать их в joins.
* Удалить из множества столбцов required_columns те, которые будут присоединены (JOIN).
* То есть, столбцы, являющиеся результатом подзапроса в секции JOIN,
* но не входящие в ключи JOIN-а (USING).
*/
void findJoins(NameSet & required_columns);
/** Создать словарь алиасов.
*/
void createAliasesDict(ASTPtr & ast, int ignore_levels = 0);

View File

@ -16,12 +16,29 @@ namespace DB
class InterpreterSelectQuery
{
public:
InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete, size_t subquery_depth_ = 0, BlockInputStreamPtr input = nullptr);
InterpreterSelectQuery(
ASTPtr query_ptr_,
const Context & context_,
QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete,
size_t subquery_depth_ = 0,
BlockInputStreamPtr input = nullptr);
InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, const Names & required_column_names,
QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete, size_t subquery_depth_ = 0, BlockInputStreamPtr input = nullptr);
InterpreterSelectQuery(
ASTPtr query_ptr_,
const Context & context_,
const Names & required_column_names, bool ignore_unknown_required_columns_,
QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete,
size_t subquery_depth_ = 0,
BlockInputStreamPtr input = nullptr);
InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, const Names & required_column_names, const NamesAndTypesList & table_column_names, QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete, size_t subquery_depth_ = 0, BlockInputStreamPtr input = nullptr);
InterpreterSelectQuery(
ASTPtr query_ptr_,
const Context & context_,
const Names & required_column_names, bool ignore_unknown_required_columns_,
const NamesAndTypesList & table_column_names,
QueryProcessingStage::Enum to_stage_ = QueryProcessingStage::Complete,
size_t subquery_depth_ = 0,
BlockInputStreamPtr input = nullptr);
/// Выполнить запрос, получить поток блоков для чтения
BlockInputStreamPtr execute();

View File

@ -44,7 +44,22 @@ public:
ASTJoin(StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */
String getID() const { return "Join"; };
String getID() const
{
String res;
{
WriteBufferFromString wb(res);
if (locality == Global)
writeString("Global", wb);
writeString(strictness == Any ? "Any" : "All", wb);
writeString(kind == Inner ? "Inner" : "Left", wb);
writeString("Join", wb);
}
return res;
};
ASTPtr clone() const
{

View File

@ -52,7 +52,7 @@ public:
}
/// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке.
void rewriteSelectExpressionList(const Names & column_names)
void rewriteSelectExpressionList(const Names & column_names, bool ignore_unknown = false)
{
ASTPtr result = new ASTExpressionList;
ASTs asts = select_expression_list->children;
@ -80,11 +80,10 @@ public:
done = 1;
}
}
if (!done)
if (!done && !ignore_unknown)
throw Exception("Error while rewriting expressioin list for select query."
" Could not find alias: " + column_names[i],
DB::ErrorCodes::UNKNOWN_IDENTIFIER);
}
for (auto & child : children)

View File

@ -173,7 +173,7 @@ BlockInputStreamPtr getVirtualColumnsBlocks(ASTPtr query, const Block & input, c
new_select.children.push_back(new_select.where_expression);
/// Возвращаем результат выполнения нового запроса на блоке виртуальных функций
InterpreterSelectQuery interpreter(new_query, context, columns, input.getColumnsList(),
InterpreterSelectQuery interpreter(new_query, context, columns, false, input.getColumnsList(),
QueryProcessingStage::Complete, 0, new OneBlockInputStream(input));
return interpreter.execute();

View File

@ -1376,42 +1376,7 @@ Sets ExpressionAnalyzer::getSetsWithSubqueries()
Joins ExpressionAnalyzer::getJoinsWithSubqueries()
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
if (select_query->join)
{
std::cerr << "Found JOIN" << std::endl;
auto & node = dynamic_cast<ASTJoin &>(*select_query->join);
auto & join_keys_expr_list = dynamic_cast<ASTExpressionList &>(*node.using_expr_list);
size_t num_join_keys = join_keys_expr_list.children.size();
Names join_key_names(num_join_keys);
for (size_t i = 0; i < num_join_keys; ++i)
join_key_names[i] = join_keys_expr_list.children[i]->getColumnName();
JoinPtr join = new Join(join_key_names, settings.limits);
/** Для подзапроса в секции JOIN не действуют ограничения на максимальный размер результата.
* Так как результат этого поздапроса - ещё не результат всего запроса.
* Вместо этого работают ограничения max_rows_in_set, max_bytes_in_set, set_overflow_mode.
* TODO: отдельные ограничения для JOIN.
*/
Context subquery_context = context;
Settings subquery_settings = context.getSettings();
subquery_settings.limits.max_result_rows = 0;
subquery_settings.limits.max_result_bytes = 0;
/// Вычисление extremes не имеет смысла и не нужно (если его делать, то в результате всего запроса могут взяться extremes подзапроса).
subquery_settings.extremes = 0;
subquery_context.setSettings(subquery_settings);
InterpreterSelectQuery interpreter(node.subquery->children[0], subquery_context, QueryProcessingStage::Complete, subquery_depth + 1);
join->setSource(interpreter.execute());
return Joins(1, join);
}
return Joins();
return joins;
}
@ -1548,6 +1513,7 @@ void ExpressionAnalyzer::removeUnusedColumns()
}
getRequiredColumnsImpl(ast, required, ignored);
findJoins(required);
/// Вставляем в список требуемых столбцов столбцы, нужные для вычисления ARRAY JOIN.
NameSet array_join_sources;
@ -1591,6 +1557,65 @@ void ExpressionAnalyzer::removeUnusedColumns()
}
}
void ExpressionAnalyzer::findJoins(NameSet & required_columns)
{
if (!select_query || !select_query->join)
return;
std::cerr << "Found JOIN" << std::endl;
auto & node = dynamic_cast<ASTJoin &>(*select_query->join);
auto & join_keys_expr_list = dynamic_cast<ASTExpressionList &>(*node.using_expr_list);
size_t num_join_keys = join_keys_expr_list.children.size();
Names join_key_names(num_join_keys);
NameSet join_key_names_set;
for (size_t i = 0; i < num_join_keys; ++i)
{
String name = join_keys_expr_list.children[i]->getColumnName();
join_key_names[i] = name;
if (!join_key_names_set.insert(name).second)
throw Exception("Duplicate column in USING list", ErrorCodes::DUPLICATE_COLUMN);
}
JoinPtr join = new Join(join_key_names, settings.limits);
/** Для подзапроса в секции JOIN не действуют ограничения на максимальный размер результата.
* Так как результат этого поздапроса - ещё не результат всего запроса.
* Вместо этого работают ограничения max_rows_in_set, max_bytes_in_set, set_overflow_mode.
* TODO: отдельные ограничения для JOIN.
*/
Context subquery_context = context;
Settings subquery_settings = context.getSettings();
subquery_settings.limits.max_result_rows = 0;
subquery_settings.limits.max_result_bytes = 0;
/// Вычисление extremes не имеет смысла и не нужно (если его делать, то в результате всего запроса могут взяться extremes подзапроса).
subquery_settings.extremes = 0;
subquery_context.setSettings(subquery_settings);
InterpreterSelectQuery interpreter(
node.subquery->children[0], subquery_context,
/// Будем использовать в подзапросе только столбцы, которые есть в required_columns.
Names(required_columns.begin(), required_columns.end()), true,
QueryProcessingStage::Complete, subquery_depth + 1);
Block right_table_sample = interpreter.getSampleBlock();
join->setSource(interpreter.execute());
joins.push_back(join);
/// Удаляем из required_columns столбцы, которые есть в подзапросе, но нет в USING-е.
for (NameSet::iterator it = required_columns.begin(); it != required_columns.end();)
{
if (right_table_sample.has(*it) && !join_key_names_set.count(*it))
required_columns.erase(it++);
else
++it;
}
}
Names ExpressionAnalyzer::getRequiredColumns()
{
if (!unknown_required_columns.empty())
@ -1605,6 +1630,14 @@ Names ExpressionAnalyzer::getRequiredColumns()
void ExpressionAnalyzer::getRequiredColumnsImpl(ASTPtr ast, NameSet & required_columns, NameSet & ignored_names)
{
/** Найдём все идентификаторы в запросе.
* Будем искать их рекурсивно, обходя в глубину AST.
* При этом:
* - для лямбда функций не будем брать формальные параметры;
* - не опускаемся в подзапросы (там свои идентификаторы);
* - некоторое исключение для секции ARRAY JOIN (в ней идентификаторы немного другие).
*/
if (ASTIdentifier * node = dynamic_cast<ASTIdentifier *>(&*ast))
{
if (node->kind == ASTIdentifier::Column
@ -1629,7 +1662,7 @@ void ExpressionAnalyzer::getRequiredColumnsImpl(ASTPtr ast, NameSet & required_c
if (!lambda_args_tuple || lambda_args_tuple->name != "tuple")
throw Exception("First argument of lambda must be a tuple", ErrorCodes::TYPE_MISMATCH);
/// Не нужно добавлять параметры лямбда-выражения в required_columns.
/// Не нужно добавлять формальные параметры лямбда-выражения в required_columns.
Names added_ignored;
for (size_t i = 0 ; i < lambda_args_tuple->arguments->children.size(); ++i)
{
@ -1655,12 +1688,12 @@ void ExpressionAnalyzer::getRequiredColumnsImpl(ASTPtr ast, NameSet & required_c
ASTSelectQuery * select = dynamic_cast<ASTSelectQuery *>(&*ast);
for (size_t i = 0; i < ast->children.size(); ++i)
/// Рекурсивный обход выражения.
for (auto & child : ast->children)
{
ASTPtr child = ast->children[i];
/// Не пойдем в секцию ARRAY JOIN, потому что там нужно смотреть на имена не-ARRAY-JOIN-енных столбцов.
/// Туда removeUnusedColumns отправит нас отдельно.
/** Не пойдем в секцию ARRAY JOIN, потому что там нужно смотреть на имена не-ARRAY-JOIN-енных столбцов.
* Туда removeUnusedColumns отправит нас отдельно.
*/
if (!dynamic_cast<ASTSubquery *>(&*child) && !dynamic_cast<ASTSelectQuery *>(&*child) &&
!(select && child == select->array_join_expression_list))
getRequiredColumnsImpl(child, required_columns, ignored_names);

View File

@ -96,7 +96,8 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
init(input_);
}
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, const Names & required_column_names_,
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_,
const Names & required_column_names_, bool ignore_unknown_required_columns_,
QueryProcessingStage::Enum to_stage_, size_t subquery_depth_, BlockInputStreamPtr input_)
: query_ptr(query_ptr_), query(dynamic_cast<ASTSelectQuery &>(*query_ptr)),
context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_),
@ -106,12 +107,13 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
* Но если используется DISTINCT, то все столбцы считаются нужными, так как иначе DISTINCT работал бы по-другому.
*/
if (!query.distinct)
query.rewriteSelectExpressionList(required_column_names_);
query.rewriteSelectExpressionList(required_column_names_, ignore_unknown_required_columns_);
init(input_);
}
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, const Names & required_column_names_,
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_,
const Names & required_column_names_, bool ignore_unknown_required_columns_,
const NamesAndTypesList & table_column_names, QueryProcessingStage::Enum to_stage_, size_t subquery_depth_, BlockInputStreamPtr input_)
: query_ptr(query_ptr_), query(dynamic_cast<ASTSelectQuery &>(*query_ptr)),
context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_),
@ -121,7 +123,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
* Но если используется DISTINCT, то все столбцы считаются нужными, так как иначе DISTINCT работал бы по-другому.
*/
if (!query.distinct)
query.rewriteSelectExpressionList(required_column_names_);
query.rewriteSelectExpressionList(required_column_names_, ignore_unknown_required_columns_);
init(input_, table_column_names);
}
@ -439,7 +441,7 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(BlockInpu
subquery_context.setSettings(subquery_settings);
interpreter_subquery = new InterpreterSelectQuery(
query.table, subquery_context, required_columns, QueryProcessingStage::Complete, subquery_depth + 1);
query.table, subquery_context, required_columns, false, QueryProcessingStage::Complete, subquery_depth + 1);
}
/// если в настройках установлен default_sample != 1, то все запросы выполняем с сэмплингом

View File

@ -16,6 +16,7 @@ StoragePtr StorageView::create(const String & table_name_, const String & databa
return (new StorageView(table_name_, database_name_, context_, query_, columns_))->thisPtr();
}
StorageView::StorageView(const String & table_name_, const String & database_name_,
Context & context_, ASTPtr & query_, NamesAndTypesListPtr columns_):
table_name(table_name_), database_name(database_name_), context(context_), columns(columns_)
@ -46,9 +47,12 @@ StorageView::StorageView(const String & table_name_, const String & database_nam
" Could not retrieve table name from select query.",
DB::ErrorCodes::LOGICAL_ERROR);
context.getGlobalContext().addDependency(DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(database_name, table_name));
context.getGlobalContext().addDependency(
DatabaseAndTableName(select_database_name, select_table_name),
DatabaseAndTableName(database_name, table_name));
}
BlockInputStreams StorageView::read(
const Names & column_names,
ASTPtr query,
@ -57,16 +61,16 @@ BlockInputStreams StorageView::read(
size_t max_block_size,
unsigned threads)
{
ASTPtr view_query = getInnerQuery();
InterpreterSelectQuery result (view_query, context, column_names);
BlockInputStreams answer;
answer.push_back(result.execute());
return answer;
return BlockInputStreams(1,
InterpreterSelectQuery(getInnerQuery(), context, column_names, false).execute());
}
void StorageView::drop() {
context.getGlobalContext().removeDependency(DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(database_name, table_name));
void StorageView::drop()
{
context.getGlobalContext().removeDependency(
DatabaseAndTableName(select_database_name, select_table_name),
DatabaseAndTableName(database_name, table_name));
}