dbms: Server: add first part of a fix for column renaming in UNION ALL queries.

This commit is contained in:
Alexey Arno 2014-12-23 18:33:36 +03:00
parent d98d920d05
commit ece876f05d
3 changed files with 91 additions and 6 deletions

View File

@ -78,6 +78,7 @@ 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 NamesAndTypesList & table_column_names = NamesAndTypesList());
void reinit(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

@ -52,6 +52,23 @@ public:
return false; return false;
} }
/// Переименовать столбцы в такие же имена, как в source.
void renameColumns(const ASTSelectQuery & source)
{
ASTs & to = select_expression_list->children;
const ASTs & from = source.select_expression_list->children;
if (from.size() != to.size())
/// XXX Временно!!! Скоро придумаем собственные сообщение + исключение.
throw Exception("FATAL ERROR", DB::ErrorCodes::UNKNOWN_IDENTIFIER);
for (size_t i = 0; i < from.size(); ++i)
{
if (from[i]->getAliasOrColumnName() != to[i]->getAliasOrColumnName())
to[i]->setAlias(from[i]->getAliasOrColumnName());
}
}
/// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке. /// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке.
void rewriteSelectExpressionList(const Names & column_names) void rewriteSelectExpressionList(const Names & column_names)
{ {

View File

@ -85,7 +85,7 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
if (input_) if (input_)
streams.push_back(input_); streams.push_back(input_);
if (isFirstSelectInsideUnionAll()) if (isFirstSelectInsideUnionAll())
{ {
/// Создаем цепочку запросов SELECT и проверяем, что результаты всех запросов SELECT cовместимые. /// Создаем цепочку запросов SELECT и проверяем, что результаты всех запросов SELECT cовместимые.
@ -103,9 +103,75 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
+ "\n\nwhile expecting:\n\n" + first.dumpStructure() + "\n\ninstead", + "\n\nwhile expecting:\n\n" + first.dumpStructure() + "\n\ninstead",
ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH); ErrorCodes::UNION_ALL_RESULT_STRUCTURES_MISMATCH);
} }
// Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе.
for (ASTPtr tree = query.next_union_all; !tree.isNull(); tree = (static_cast<ASTSelectQuery &>(*tree)).next_union_all)
{
ASTSelectQuery & ast = static_cast<ASTSelectQuery &>(*(tree.get()));
ast.renameColumns(query);
}
} }
} }
///
/// XXX Временный boilerplate код, который сотру очень скоро. Не обращать внимание.
/// на него. Дело в том, что rewriteExpressionList() может не работать правильно,
/// если мы не вызываем renameColumns() перед ним. В свою очередь renameColumns()
/// будет работать правильно лишь в том случае, если обладает достаточно информаций,
/// то, что возможно только после построения объекта query_analyzer.
/// Но тогда, после вызова rewriteExpressionList(), InterpreterSelectQuery содержит
/// неправильнии информации. Единственный выход - заново инициализировать объект
/// 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
{
String database_name;
String table_name;
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_,
size_t subquery_depth_, BlockInputStreamPtr input_, bool is_union_all_head_) size_t subquery_depth_, BlockInputStreamPtr input_, bool is_union_all_head_)
: query_ptr(query_ptr_), query(typeid_cast<ASTSelectQuery &>(*query_ptr)), : query_ptr(query_ptr_), query(typeid_cast<ASTSelectQuery &>(*query_ptr)),
@ -124,8 +190,9 @@ 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"))
{ {
rewriteExpressionList(required_column_names_);
init(input_); init(input_);
rewriteExpressionList(required_column_names_);
reinit();
} }
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_,
@ -135,9 +202,10 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_), context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_),
is_union_all_head(true), is_union_all_head(true),
log(&Logger::get("InterpreterSelectQuery")) log(&Logger::get("InterpreterSelectQuery"))
{ {
rewriteExpressionList(required_column_names_);
init(input_, table_column_names); init(input_, 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)
@ -153,7 +221,6 @@ void InterpreterSelectQuery::rewriteExpressionList(const Names & required_column
} }
query.rewriteSelectExpressionList(required_column_names); query.rewriteSelectExpressionList(required_column_names);
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 & next_query = *(static_cast<ASTSelectQuery *>(tree)); auto & next_query = *(static_cast<ASTSelectQuery *>(tree));
@ -527,7 +594,7 @@ QueryProcessingStage::Enum InterpreterSelectQuery::executeFetchColumns(BlockInpu
Names required_columns = query_analyzer->getRequiredColumns(); Names required_columns = query_analyzer->getRequiredColumns();
if (query.table && typeid_cast<ASTSelectQuery *>(&*query.table)) if (query.table && typeid_cast<ASTSelectQuery *>(&*query.table))
{ {
/** Для подзапроса не действуют ограничения на максимальный размер результата. /** Для подзапроса не действуют ограничения на максимальный размер результата.
* Так как результат поздапроса - ещё не результат всего запроса. * Так как результат поздапроса - ещё не результат всего запроса.
*/ */