mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 00:22:29 +00:00
dbms: Server: add first part of a fix for column renaming in UNION ALL queries.
This commit is contained in:
parent
d98d920d05
commit
ece876f05d
@ -78,6 +78,7 @@ private:
|
||||
typedef Poco::SharedPtr<ExpressionAnalyzer> ExpressionAnalyzerPtr;
|
||||
|
||||
void init(BlockInputStreamPtr input, const NamesAndTypesList & table_column_names = NamesAndTypesList());
|
||||
void reinit(const NamesAndTypesList & table_column_names = NamesAndTypesList());
|
||||
|
||||
/// Выполнить один запрос SELECT из цепочки UNION ALL.
|
||||
void executeSingleQuery(bool should_perform_union_hint = true);
|
||||
|
@ -52,6 +52,23 @@ public:
|
||||
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, чтобы вернуть только необходимые столбцы в правильном порядке.
|
||||
void rewriteSelectExpressionList(const Names & column_names)
|
||||
{
|
||||
|
@ -103,7 +103,73 @@ void InterpreterSelectQuery::init(BlockInputStreamPtr input_, const NamesAndType
|
||||
+ "\n\nwhile expecting:\n\n" + first.dumpStructure() + "\n\ninstead",
|
||||
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_,
|
||||
@ -124,8 +190,9 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
|
||||
is_union_all_head(true),
|
||||
log(&Logger::get("InterpreterSelectQuery"))
|
||||
{
|
||||
rewriteExpressionList(required_column_names_);
|
||||
init(input_);
|
||||
rewriteExpressionList(required_column_names_);
|
||||
reinit();
|
||||
}
|
||||
|
||||
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_,
|
||||
@ -136,8 +203,9 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
|
||||
is_union_all_head(true),
|
||||
log(&Logger::get("InterpreterSelectQuery"))
|
||||
{
|
||||
rewriteExpressionList(required_column_names_);
|
||||
init(input_, table_column_names);
|
||||
rewriteExpressionList(required_column_names_);
|
||||
reinit(table_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);
|
||||
|
||||
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));
|
||||
|
Loading…
Reference in New Issue
Block a user