dbms: Server: Remove boilerplate code. [#METR-14099]

This commit is contained in:
Alexey Arno 2014-12-24 15:59:02 +03:00
parent 255c7669a9
commit b0256d0990
2 changed files with 51 additions and 88 deletions

View File

@ -77,8 +77,8 @@ public:
private: private:
typedef Poco::SharedPtr<ExpressionAnalyzer> ExpressionAnalyzerPtr; typedef Poco::SharedPtr<ExpressionAnalyzer> ExpressionAnalyzerPtr;
void init(BlockInputStreamPtr input, const NamesAndTypesList & table_column_names = NamesAndTypesList()); void init(BlockInputStreamPtr input, const Names & required_column_names = Names(), const NamesAndTypesList & table_column_names = NamesAndTypesList());
void reinit(const NamesAndTypesList & table_column_names = NamesAndTypesList()); void basic_init(bool is_first_init, BlockInputStreamPtr input = nullptr, const NamesAndTypesList & table_column_names = NamesAndTypesList());
/// Выполнить один запрос SELECT из цепочки UNION ALL. /// Выполнить один запрос SELECT из цепочки UNION ALL.
void executeSingleQuery(bool should_perform_union_hint = true); void executeSingleQuery(bool should_perform_union_hint = true);

View File

@ -33,13 +33,30 @@
namespace DB namespace DB
{ {
void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndTypesList & table_column_names) void InterpreterSelectQuery::init(BlockInputStreamPtr input, const Names & required_column_names, const NamesAndTypesList & table_column_names)
{ {
ProfileEvents::increment(ProfileEvents::SelectQuery); /// В случае цепочки UNION ALL функуция rewriteExpressionList() может выкинуть исключение,
/// если не вызвали до этого функцию renameColumns(). Поэтому сначала выполняется инициализация.
/// После вызова rewriteExpressionList(), имеется устаревшая информация для выполнения запроса.
/// Тогда необходимо сделать повторную инициализацию.
basic_init(true, input, table_column_names);
if (!required_column_names.empty())
{
rewriteExpressionList(required_column_names);
basic_init(false, input, table_column_names);
}
}
if (settings.limits.max_subquery_depth && subquery_depth > settings.limits.max_subquery_depth) void InterpreterSelectQuery::basic_init(bool is_first_init, BlockInputStreamPtr input_, const NamesAndTypesList & table_column_names)
throw Exception("Too deep subqueries. Maximum: " + toString(settings.limits.max_subquery_depth), {
ErrorCodes::TOO_DEEP_SUBQUERIES); if (is_first_init)
{
ProfileEvents::increment(ProfileEvents::SelectQuery);
if (settings.limits.max_subquery_depth && subquery_depth > settings.limits.max_subquery_depth)
throw Exception("Too deep subqueries. Maximum: " + toString(settings.limits.max_subquery_depth),
ErrorCodes::TOO_DEEP_SUBQUERIES);
}
if (query.table && typeid_cast<ASTSelectQuery *>(&*query.table)) if (query.table && typeid_cast<ASTSelectQuery *>(&*query.table))
{ {
@ -83,92 +100,42 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
if (!context.tryGetExternalTable(it.first)) if (!context.tryGetExternalTable(it.first))
context.addExternalTable(it.first, it.second); context.addExternalTable(it.first, it.second);
if (input_) if (is_first_init && input_)
streams.push_back(input_); streams.push_back(input_);
if (isFirstSelectInsideUnionAll()) if (isFirstSelectInsideUnionAll())
{ {
/// Создаем цепочку запросов SELECT и проверяем, что результаты всех запросов SELECT cовместимые. if (is_first_init)
/// NOTE Мы можем безопасно применить static_cast вместо typeid_cast,
/// потому что знаем, что в цепочке UNION ALL имеются только деревья типа SELECT.
InterpreterSelectQuery * interpreter = this;
Block first = interpreter->getSampleBlock();
for (ASTPtr tree = query.next_union_all; !tree.isNull(); tree = (static_cast<ASTSelectQuery &>(*tree)).next_union_all)
{ {
interpreter->next_select_in_union_all.reset(new InterpreterSelectQuery(tree, context, to_stage, subquery_depth, nullptr, false)); /// Создаем цепочку запросов SELECT и проверяем, что результаты всех запросов SELECT cовместимые.
interpreter = interpreter->next_select_in_union_all.get(); /// NOTE Мы можем безопасно применить static_cast вместо typeid_cast,
Block current = interpreter->getSampleBlock(); /// потому что знаем, что в цепочке UNION ALL имеются только деревья типа SELECT.
if (!blocksHaveEqualStructure(first, current)) InterpreterSelectQuery * interpreter = this;
throw Exception("Result structures mismatch in the SELECT queries of the UNION ALL chain. Found result structure:\n\n" + current.dumpStructure() Block first = interpreter->getSampleBlock();
+ "\n\nwhile expecting:\n\n" + first.dumpStructure() + "\n\ninstead", for (ASTPtr tree = query.next_union_all; !tree.isNull(); tree = (static_cast<ASTSelectQuery &>(*tree)).next_union_all)
ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH); {
} interpreter->next_select_in_union_all.reset(new InterpreterSelectQuery(tree, context, to_stage, subquery_depth, nullptr, false));
interpreter = interpreter->next_select_in_union_all.get();
Block current = interpreter->getSampleBlock();
if (!blocksHaveEqualStructure(first, current))
throw Exception("Result structures mismatch in the SELECT queries of the UNION ALL chain. Found result structure:\n\n" + current.dumpStructure()
+ "\n\nwhile expecting:\n\n" + first.dumpStructure() + "\n\ninstead",
ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH);
}
// Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе. // Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе.
for (IAST * tree = query.next_union_all.get(); tree != nullptr; tree = static_cast<ASTSelectQuery *>(tree)->next_union_all.get()) for (IAST * tree = query.next_union_all.get(); tree != nullptr; tree = static_cast<ASTSelectQuery *>(tree)->next_union_all.get())
{ {
auto & ast = static_cast<ASTSelectQuery &>(*tree); auto & ast = static_cast<ASTSelectQuery &>(*tree);
ast.renameColumns(query); ast.renameColumns(query);
} }
}
}
///
/// XXX Временный boilerplate код, который сотру очень скоро. Не обращать внимание.
/// на него. Дело в том, что функция rewriteExpressionList() может работать неправильно,
/// если мы не вызываем renameColumns() до нее. В свою очередь renameColumns()
/// будет работать правильно лишь в том случае, если обладает достаточно информаций,
/// то, что возможно только после создания объекта query_analyzer.
/// Но тогда, после вызова rewriteExpressionList(), объект InterpreterSelectQuery хранит
/// неправильные информации. Единственный выход - заново инициализировать этот объект.
///
void InterpreterSelectQuery::reinit(const NamesAndTypesList & table_column_names)
{
if (query.table && typeid_cast<ASTSelectQuery *>(&*query.table))
{
if (table_column_names.empty())
context.setColumns(InterpreterSelectQuery(query.table, context, to_stage, subquery_depth, nullptr, false).getSampleBlock().getColumnsList());
}
else
{
if (query.table && typeid_cast<const ASTFunction *>(&*query.table))
{
/// Получить табличную функцию
TableFunctionPtr table_function_ptr = context.getTableFunctionFactory().get(typeid_cast<const ASTFunction *>(&*query.table)->name, context);
/// Выполнить ее и запомнить результат
storage = table_function_ptr->execute(query.table, context);
} }
else else
{ {
String database_name; for (auto p = next_select_in_union_all.get(); p != nullptr; p = p->next_select_in_union_all.get())
String table_name; p->basic_init(true);
getDatabaseAndTableNames(database_name, table_name);
storage = context.getTable(database_name, table_name);
} }
table_lock = storage->lockStructure(false);
if (table_column_names.empty())
context.setColumns(storage->getColumnsListNonMaterialized());
} }
if (!table_column_names.empty())
context.setColumns(table_column_names);
if (context.getColumns().empty())
throw Exception("There are no available columns", ErrorCodes::THERE_IS_NO_COLUMN);
query_analyzer = new ExpressionAnalyzer(query_ptr, context, storage, subquery_depth, true);
/// Сохраняем в query context новые временные таблицы
for (auto & it : query_analyzer->getExternalTables())
if (!context.tryGetExternalTable(it.first))
context.addExternalTable(it.first, it.second);
if (isFirstSelectInsideUnionAll())
for (auto p = next_select_in_union_all.get(); p != nullptr; p = p->next_select_in_union_all.get())
p->reinit();
} }
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, QueryProcessingStage::Enum to_stage_, InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, QueryProcessingStage::Enum to_stage_,
@ -189,9 +156,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
is_union_all_head(true), is_union_all_head(true),
log(&Logger::get("InterpreterSelectQuery")) log(&Logger::get("InterpreterSelectQuery"))
{ {
init(input_); init(input_, required_column_names_);
rewriteExpressionList(required_column_names_);
reinit();
} }
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_,
@ -202,9 +167,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
is_union_all_head(true), is_union_all_head(true),
log(&Logger::get("InterpreterSelectQuery")) log(&Logger::get("InterpreterSelectQuery"))
{ {
init(input_, table_column_names); init(input_, required_column_names_, table_column_names);
rewriteExpressionList(required_column_names_);
reinit(table_column_names);
} }
void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column_names) void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column_names)