mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 23:52:03 +00:00
reorganized adding of MULTIPLE_ARRAY_JOIN action [#CONV-7967]
This commit is contained in:
parent
0e96233d2b
commit
f504fd2193
@ -48,7 +48,9 @@ public:
|
||||
DataTypePtr result_type;
|
||||
|
||||
/// Для MULTIPLE_ARRAY_JOIN
|
||||
NameToNameMap array_joined_columns; /// Имена исходных столбцов -> имена столбцов результатов ARRAY JOIN
|
||||
std::string nested_table_name;
|
||||
std::string nested_table_alias;
|
||||
NameSet array_joined_columns; /// Имена столбцов без префикса 'NestedTableName.'
|
||||
|
||||
/// Для ADD_COLUMN.
|
||||
ColumnPtr added_column;
|
||||
@ -118,11 +120,15 @@ public:
|
||||
return a;
|
||||
}
|
||||
|
||||
static Action multipleArrayJoin(const NameToNameMap & array_joined_columns_)
|
||||
static Action multipleArrayJoin(const std::string & nested_table_name,
|
||||
const std::string & nested_table_alias,
|
||||
const NameSet & array_joined_columns)
|
||||
{
|
||||
Action a;
|
||||
a.type = MULTIPLE_ARRAY_JOIN;
|
||||
a.array_joined_columns = array_joined_columns_;
|
||||
a.nested_table_name = nested_table_name;
|
||||
a.nested_table_alias = nested_table_alias;
|
||||
a.array_joined_columns = array_joined_columns;
|
||||
return a;
|
||||
}
|
||||
|
||||
@ -135,6 +141,11 @@ public:
|
||||
private:
|
||||
friend class ExpressionActions;
|
||||
|
||||
/// Проверяет является ли данный столбец результатом ARRAY JOIN
|
||||
bool isArrayJoinedColumnName(const String & name) const;
|
||||
/// Возвращает исходное имя столбца до применения к нему ARRAY JOIN
|
||||
String getOriginalNestedName(const String & name) const;
|
||||
|
||||
std::vector<Action> getPrerequisites(Block & sample_block);
|
||||
void prepare(Block & sample_block);
|
||||
void execute(Block & block) const;
|
||||
|
@ -112,6 +112,9 @@ private:
|
||||
typedef std::set<const IAST *> SetOfASTs;
|
||||
typedef std::map<ASTPtr, ASTPtr> MapOfASTs;
|
||||
|
||||
/// Столбцы, которые должны быть преобразованы из-за секции ARRAY JOIN
|
||||
NameSet array_joined_columns;
|
||||
|
||||
/** Для getActionsImpl.
|
||||
* Стек из ExpressionActions, соответствующих вложенным лямбда-выражениям.
|
||||
* Новое действие нужно добавлять на самый высокий возможный уровень.
|
||||
@ -239,7 +242,9 @@ private:
|
||||
/// Превратить перечисление значений или подзапрос в ASTSet. node - функция in или notIn.
|
||||
void makeSet(ASTFunction * node, const Block & sample_block);
|
||||
|
||||
void getArrayJoinedColumnsImpl(ASTPtr ast, NameToNameMap & array_joined_columns);
|
||||
void getArrayJoinedColumns();
|
||||
void getArrayJoinedColumnsImpl(ASTPtr ast);
|
||||
void addMultipleArrayJoinAction(ExpressionActions & actions);
|
||||
|
||||
void getActionsImpl(ASTPtr ast, bool no_subqueries, bool only_consts, ScopeStack & actions_stack);
|
||||
|
||||
|
@ -12,8 +12,8 @@ Names ExpressionActions::Action::getNeededColumns() const
|
||||
Names res = argument_names;
|
||||
res.insert(res.end(), prerequisite_names.begin(), prerequisite_names.end());
|
||||
|
||||
for (NameToNameMap::const_iterator it = array_joined_columns.begin(); it != array_joined_columns.end(); ++it)
|
||||
res.push_back(it->first);
|
||||
for (NameSet::const_iterator it = array_joined_columns.begin(); it != array_joined_columns.end(); ++it)
|
||||
res.push_back(DataTypeNested::concatenateNestedName(nested_table_alias, *it));
|
||||
|
||||
for (size_t i = 0; i < projection.size(); ++i)
|
||||
{
|
||||
@ -25,7 +25,28 @@ Names ExpressionActions::Action::getNeededColumns() const
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ExpressionActions::Action::isArrayJoinedColumnName(const String & name) const
|
||||
{
|
||||
std::string nested_table = DataTypeNested::extractNestedTableName(name);
|
||||
std::string nested_column = DataTypeNested::extractNestedColumnName(name);
|
||||
return nested_column == nested_table_alias || (nested_table == nested_table_alias && array_joined_columns.count(nested_column));
|
||||
}
|
||||
|
||||
String ExpressionActions::Action::getOriginalNestedName(const String & name) const
|
||||
{
|
||||
std::string nested_table = DataTypeNested::extractNestedTableName(name);
|
||||
std::string nested_column = DataTypeNested::extractNestedColumnName(name);
|
||||
|
||||
if (nested_column == nested_table_alias)
|
||||
return nested_table_name;
|
||||
|
||||
if (nested_table == nested_table_alias && array_joined_columns.count(nested_column))
|
||||
return DataTypeNested::concatenateNestedName(nested_table_name, nested_column);
|
||||
|
||||
throw Exception("Can't produce original nested name for column: " + name, ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
ExpressionActions::Action ExpressionActions::Action::applyFunction(FunctionPtr function_,
|
||||
const std::vector<std::string> & argument_names_,
|
||||
std::string result_name_)
|
||||
@ -156,8 +177,7 @@ void ExpressionActions::Action::prepare(Block & sample_block)
|
||||
const ColumnWithNameAndType & current = sample_block.getByPosition(i);
|
||||
const DataTypeArray * array_type = dynamic_cast<const DataTypeArray *>(&*current.type);
|
||||
|
||||
NameToNameMap::const_iterator array_joined_names = array_joined_columns.find(current.name);
|
||||
if (array_joined_columns.end() != array_joined_names)
|
||||
if (isArrayJoinedColumnName(current.name))
|
||||
{
|
||||
if (!array_type)
|
||||
throw Exception("ARRAY JOIN requires array argument", ErrorCodes::TYPE_MISMATCH);
|
||||
@ -167,17 +187,10 @@ void ExpressionActions::Action::prepare(Block & sample_block)
|
||||
ColumnWithNameAndType result;
|
||||
result.column = NULL;
|
||||
result.type = array_type->getNestedType();
|
||||
result.name = array_joined_names->second;
|
||||
|
||||
/// Если для столбцов из секции ARRAY JOIN указали алиас, то не будем удалять исходные
|
||||
/// столбцы из блока. Они могут быть использованы функциями, работающими с массивом целиком.
|
||||
if (array_joined_names->first != array_joined_names->second)
|
||||
sample_block.insert(result);
|
||||
else
|
||||
{
|
||||
sample_block.erase(i);
|
||||
sample_block.insert(i, result);
|
||||
}
|
||||
result.name = current.name;
|
||||
|
||||
sample_block.erase(i);
|
||||
sample_block.insert(i, result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,7 +263,7 @@ void ExpressionActions::Action::execute(Block & block) const
|
||||
{
|
||||
const ColumnWithNameAndType & current = block.getByPosition(i);
|
||||
|
||||
if (current.name == source_name || array_joined_columns.count(current.name))
|
||||
if (isArrayJoinedColumnName(current.name))
|
||||
{
|
||||
if (!dynamic_cast<const DataTypeArray *>(&*current.type))
|
||||
throw Exception("arrayJoin of not array: " + current.name, ErrorCodes::TYPE_MISMATCH);
|
||||
@ -279,8 +292,7 @@ void ExpressionActions::Action::execute(Block & block) const
|
||||
{
|
||||
ColumnWithNameAndType & current = block.getByPosition(i);
|
||||
|
||||
NameToNameMap::const_iterator array_joined_names = array_joined_columns.find(current.name);
|
||||
if (current.name == source_name || array_joined_columns.end() != array_joined_names)
|
||||
if (isArrayJoinedColumnName(current.name))
|
||||
{
|
||||
ColumnPtr array_ptr = current.column;
|
||||
if (array_ptr->isConst())
|
||||
@ -289,17 +301,10 @@ void ExpressionActions::Action::execute(Block & block) const
|
||||
ColumnWithNameAndType result;
|
||||
result.column = dynamic_cast<const ColumnArray &>(*array_ptr).getDataPtr();
|
||||
result.type = dynamic_cast<const DataTypeArray &>(*current.type).getNestedType();
|
||||
result.name = type == MULTIPLE_ARRAY_JOIN ? array_joined_names->second : result_name;
|
||||
result.name = type == MULTIPLE_ARRAY_JOIN ? current.name : result_name;
|
||||
|
||||
/// Если для столбцов из секции ARRAY JOIN указали алиас, то не будем удалять исходные
|
||||
/// столбцы из блока. Они могут быть использованы функциями, работающими с массивом целиком.
|
||||
if (type == MULTIPLE_ARRAY_JOIN && array_joined_names->first != array_joined_names->second)
|
||||
block.insert(result);
|
||||
else
|
||||
{
|
||||
block.erase(i);
|
||||
block.insert(i, result);
|
||||
}
|
||||
block.erase(i);
|
||||
block.insert(i, result);
|
||||
}
|
||||
else
|
||||
current.column = current.column->replicate(any_array->getOffsets());
|
||||
@ -372,12 +377,13 @@ std::string ExpressionActions::Action::toString() const
|
||||
ss << result_name << "(" << result_type->getName() << ")" << "= " << "arrayJoin" << " ( " << source_name << " )";
|
||||
break;
|
||||
case MULTIPLE_ARRAY_JOIN:
|
||||
ss << "ARRAY JOIN {";
|
||||
for (NameToNameMap::const_iterator it = array_joined_columns.begin(); it != array_joined_columns.end(); ++it)
|
||||
ss << "ARRAY JOIN " << nested_table_name << (nested_table_name != nested_table_alias ? " AS " + nested_table_alias : "");
|
||||
ss << "{";
|
||||
for (NameSet::const_iterator it = array_joined_columns.begin(); it != array_joined_columns.end(); ++it)
|
||||
{
|
||||
if (it != array_joined_columns.begin())
|
||||
ss << ", ";
|
||||
ss << it->first << " = " << it->second;
|
||||
ss << *it;
|
||||
}
|
||||
ss << "}";
|
||||
break;
|
||||
@ -462,8 +468,8 @@ void ExpressionActions::addImpl(Action action, NameSet & current_names, Names &
|
||||
|
||||
if (action.result_name != "")
|
||||
new_names.push_back(action.result_name);
|
||||
for (NameToNameMap::const_iterator it = action.array_joined_columns.begin(); it != action.array_joined_columns.end(); ++it)
|
||||
new_names.push_back(it->second);
|
||||
for (NameSet::const_iterator it = action.array_joined_columns.begin(); it != action.array_joined_columns.end(); ++it)
|
||||
new_names.push_back(DataTypeNested::concatenateNestedName(action.nested_table_alias, *it));
|
||||
|
||||
Actions prerequisites = action.getPrerequisites(sample_block);
|
||||
|
||||
@ -620,13 +626,15 @@ std::string ExpressionActions::getID() const
|
||||
ss << actions[i].result_name;
|
||||
if (actions[i].type == Action::MULTIPLE_ARRAY_JOIN)
|
||||
{
|
||||
for (NameToNameMap::const_iterator it = actions[i].array_joined_columns.begin();
|
||||
ss << actions[i].nested_table_alias << ".{";
|
||||
for (NameSet::const_iterator it = actions[i].array_joined_columns.begin();
|
||||
it != actions[i].array_joined_columns.end(); ++it)
|
||||
{
|
||||
if (it != actions[i].array_joined_columns.begin())
|
||||
ss << ", ";
|
||||
ss << it->second;
|
||||
ss << *it;
|
||||
}
|
||||
ss << "}";
|
||||
}
|
||||
}
|
||||
|
||||
@ -720,10 +728,10 @@ void ExpressionActions::optimizeArrayJoin()
|
||||
if (actions[i].result_name != "")
|
||||
array_joined_columns.insert(actions[i].result_name);
|
||||
|
||||
for (NameToNameMap::const_iterator it = actions[i].array_joined_columns.begin();
|
||||
for (NameSet::const_iterator it = actions[i].array_joined_columns.begin();
|
||||
it != actions[i].array_joined_columns.end(); ++it)
|
||||
{
|
||||
array_joined_columns.insert(it->second);
|
||||
array_joined_columns.insert(DataTypeNested::concatenateNestedName(actions[i].nested_table_alias, *it));
|
||||
}
|
||||
|
||||
array_join_dependencies.insert(needed.begin(), needed.end());
|
||||
|
@ -60,11 +60,14 @@ void ExpressionAnalyzer::init()
|
||||
|
||||
removeUnusedColumns();
|
||||
|
||||
getArrayJoinedColumns();
|
||||
|
||||
/// Найдем агрегатные функции.
|
||||
if (select_query && (select_query->group_expression_list || select_query->having_expression))
|
||||
has_aggregation = true;
|
||||
|
||||
ExpressionActions temp_actions(columns, settings);
|
||||
addMultipleArrayJoinAction(temp_actions);
|
||||
getAggregatesImpl(ast, temp_actions);
|
||||
|
||||
if (has_aggregation)
|
||||
@ -389,16 +392,6 @@ void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_as
|
||||
throw Exception("Requested Sign column while sign-rewrite is on.", ErrorCodes::QUERY_SECTION_DOESNT_MAKE_SENSE);
|
||||
}
|
||||
}
|
||||
|
||||
/// на случай если подставили алиас
|
||||
node = dynamic_cast<ASTIdentifier *>(&*ast);
|
||||
|
||||
if (node && node->kind == ASTIdentifier::Column && isArrayJoinedColumnName(node->name))
|
||||
{
|
||||
String original_name = getOriginalNestedName(node->name);
|
||||
node->alias = node->name;
|
||||
node->name = original_name;
|
||||
}
|
||||
}
|
||||
else if (ASTExpressionList * node = dynamic_cast<ASTExpressionList *>(&*ast))
|
||||
{
|
||||
@ -568,22 +561,59 @@ void ExpressionAnalyzer::getRootActionsImpl(ASTPtr ast, bool no_subqueries, bool
|
||||
}
|
||||
|
||||
|
||||
void ExpressionAnalyzer::getArrayJoinedColumnsImpl(ASTPtr ast, NameToNameMap & array_joined_columns)
|
||||
void ExpressionAnalyzer::getArrayJoinedColumns()
|
||||
{
|
||||
assertSelect();
|
||||
|
||||
if (!select_query->array_join_identifier)
|
||||
return;
|
||||
|
||||
getArrayJoinedColumnsImpl(ast);
|
||||
}
|
||||
|
||||
|
||||
void ExpressionAnalyzer::getArrayJoinedColumnsImpl(ASTPtr ast)
|
||||
{
|
||||
if (ASTIdentifier * node = dynamic_cast<ASTIdentifier *>(&*ast))
|
||||
{
|
||||
if (node->kind == ASTIdentifier::Column && isArrayJoinedColumnName(node->name))
|
||||
array_joined_columns[node->name] = node->alias;
|
||||
array_joined_columns.insert(DataTypeNested::extractNestedColumnName(node->name));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
|
||||
if (!dynamic_cast<ASTSelectQuery *>(&**it))
|
||||
getArrayJoinedColumnsImpl(*it, array_joined_columns);
|
||||
getArrayJoinedColumnsImpl(*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ExpressionAnalyzer::addMultipleArrayJoinAction(ExpressionActions & actions)
|
||||
{
|
||||
String nested_table_name = select_query->array_join_identifier->getColumnName();
|
||||
String nested_table_alias = select_query->array_join_identifier->getAlias();
|
||||
|
||||
bool added_columns = false;
|
||||
|
||||
const NamesAndTypesList & input_columns = actions.getRequiredColumnsWithTypes();
|
||||
for (NamesAndTypesList::const_iterator it = input_columns.begin(); it != input_columns.end(); ++it)
|
||||
{
|
||||
String nested_table = DataTypeNested::extractNestedTableName(it->first);
|
||||
String nested_column = DataTypeNested::extractNestedColumnName(it->first);
|
||||
|
||||
if (nested_column == nested_table_name || (nested_table == nested_table_name && array_joined_columns.count(nested_column)))
|
||||
{
|
||||
added_columns = true;
|
||||
String array_joined_name = DataTypeNested::concatenateNestedName(nested_table_alias, nested_column);
|
||||
actions.add(ExpressionActions::Action::copyColumn(it->first, array_joined_name));
|
||||
}
|
||||
}
|
||||
|
||||
if (added_columns)
|
||||
actions.add(ExpressionActions::Action::multipleArrayJoin(nested_table_name, nested_table_alias, array_joined_columns));
|
||||
}
|
||||
|
||||
|
||||
void ExpressionAnalyzer::getActionsImpl(ASTPtr ast, bool no_subqueries, bool only_consts, ScopeStack & actions_stack)
|
||||
{
|
||||
/// Если результат вычисления уже есть в блоке.
|
||||
@ -890,14 +920,15 @@ bool ExpressionAnalyzer::appendArrayJoin(ExpressionActionsChain & chain)
|
||||
initChain(chain, columns);
|
||||
ExpressionActionsChain::Step & step = chain.steps.back();
|
||||
|
||||
NameToNameMap array_joined_columns;
|
||||
getArrayJoinedColumnsImpl(ast, array_joined_columns);
|
||||
getArrayJoinedColumnsImpl(ast);
|
||||
|
||||
if (!array_joined_columns.empty())
|
||||
{
|
||||
step.actions->add(ExpressionActions::Action::multipleArrayJoin(array_joined_columns));
|
||||
for (NameToNameMap::const_iterator it = array_joined_columns.begin(); it != array_joined_columns.end(); ++it)
|
||||
step.required_output.push_back(it->second);
|
||||
addMultipleArrayJoinAction(*step.actions);
|
||||
|
||||
String nested_table_alias = select_query->array_join_identifier->getAlias();
|
||||
for (NameSet::const_iterator it = array_joined_columns.begin(); it != array_joined_columns.end(); ++it)
|
||||
step.required_output.push_back(DataTypeNested::concatenateNestedName(nested_table_alias, *it));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user