reorganized adding of MULTIPLE_ARRAY_JOIN action [#CONV-7967]

This commit is contained in:
Vyacheslav Alipov 2013-08-01 13:29:32 +00:00
parent 0e96233d2b
commit f504fd2193
4 changed files with 114 additions and 59 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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());

View File

@ -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;