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;
|
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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
/** Для подзапроса не действуют ограничения на максимальный размер результата.
|
/** Для подзапроса не действуют ограничения на максимальный размер результата.
|
||||||
* Так как результат поздапроса - ещё не результат всего запроса.
|
* Так как результат поздапроса - ещё не результат всего запроса.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user