ClickHouse/src/Interpreters/TableJoin.cpp

813 lines
27 KiB
C++
Raw Normal View History

#include <Interpreters/TableJoin.h>
2018-11-02 18:53:23 +00:00
#include <Common/Exception.h>
2021-10-02 07:13:14 +00:00
#include <base/types.h>
#include <Common/StringUtils/StringUtils.h>
#include <Interpreters/ActionsDAG.h>
2018-11-02 18:53:23 +00:00
#include <Core/Block.h>
2020-09-08 10:40:53 +00:00
#include <Core/ColumnsWithTypeAndName.h>
#include <Core/Settings.h>
2020-04-12 03:20:15 +00:00
#include <DataTypes/DataTypeNullable.h>
2021-06-29 09:22:53 +00:00
#include <Dictionaries/DictionaryStructure.h>
#include <Interpreters/DictionaryReader.h>
#include <Interpreters/ExternalDictionariesLoader.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/queryToString.h>
2021-06-28 14:12:15 +00:00
#include <Storages/IStorage.h>
2021-06-29 09:22:53 +00:00
#include <Storages/StorageDictionary.h>
#include <Storages/StorageJoin.h>
2022-04-27 15:05:45 +00:00
#include <Common/logger_useful.h>
#include <algorithm>
#include <string>
#include <type_traits>
#include <vector>
2018-11-02 18:53:23 +00:00
namespace DB
{
namespace ErrorCodes
{
extern const int TYPE_MISMATCH;
2021-06-29 09:22:53 +00:00
extern const int LOGICAL_ERROR;
extern const int NOT_IMPLEMENTED;
}
namespace
{
std::string formatTypeMap(const TableJoin::NameToTypeMap & target, const TableJoin::NameToTypeMap & source)
{
std::vector<std::string> text;
for (const auto & [k, v] : target)
{
auto src_type_it = source.find(k);
std::string src_type_name = src_type_it != source.end() ? src_type_it->second->getName() : "";
text.push_back(fmt::format("{} : {} -> {}", k, src_type_name, v->getName()));
}
return fmt::format("{}", fmt::join(text, ", "));
}
}
2021-09-06 10:59:18 +00:00
namespace
{
2021-09-09 09:47:08 +00:00
struct BothSidesTag {};
struct LeftSideTag {};
struct RightSideTag {};
template <typename SideTag = BothSidesTag, typename OnExpr, typename Func>
2021-09-06 10:59:18 +00:00
bool forAllKeys(OnExpr & expressions, Func callback)
{
2021-09-09 09:47:08 +00:00
static_assert(std::is_same_v<SideTag, BothSidesTag> ||
std::is_same_v<SideTag, LeftSideTag> ||
std::is_same_v<SideTag, RightSideTag>);
2021-09-06 10:59:18 +00:00
for (auto & expr : expressions)
{
2021-09-09 09:47:08 +00:00
if constexpr (std::is_same_v<SideTag, BothSidesTag>)
assert(expr.key_names_left.size() == expr.key_names_right.size());
size_t sz = !std::is_same_v<SideTag, RightSideTag> ? expr.key_names_left.size() : expr.key_names_right.size();
for (size_t i = 0; i < sz; ++i)
2021-09-06 10:59:18 +00:00
{
2021-09-09 09:47:08 +00:00
bool cont;
if constexpr (std::is_same_v<SideTag, BothSidesTag>)
cont = callback(expr.key_names_left[i], expr.key_names_right[i]);
if constexpr (std::is_same_v<SideTag, LeftSideTag>)
cont = callback(expr.key_names_left[i]);
if constexpr (std::is_same_v<SideTag, RightSideTag>)
cont = callback(expr.key_names_right[i]);
2021-09-06 10:59:18 +00:00
if (!cont)
return false;
}
}
return true;
}
}
TableJoin::TableJoin(const Settings & settings, VolumePtr tmp_volume_)
: size_limits(SizeLimits{settings.max_rows_in_join, settings.max_bytes_in_join, settings.join_overflow_mode})
, default_max_bytes(settings.default_max_bytes_in_join)
, join_use_nulls(settings.join_use_nulls)
, max_joined_block_rows(settings.max_joined_block_size_rows)
, join_algorithm(settings.join_algorithm)
, partial_merge_join_rows_in_right_blocks(settings.partial_merge_join_rows_in_right_blocks)
, partial_merge_join_left_table_buffer_bytes(settings.partial_merge_join_left_table_buffer_bytes)
, max_files_to_merge(settings.join_on_disk_max_files_to_merge)
, temporary_files_codec(settings.temporary_files_codec)
, tmp_volume(tmp_volume_)
{
}
2019-09-09 19:43:37 +00:00
2021-11-08 12:44:13 +00:00
void TableJoin::resetKeys()
{
2021-11-08 12:44:13 +00:00
clauses.clear();
key_asts_left.clear();
key_asts_right.clear();
2021-11-08 12:44:13 +00:00
left_type_map.clear();
right_type_map.clear();
}
void TableJoin::resetCollected()
{
clauses.clear();
columns_from_joined_table.clear();
columns_added_by_join.clear();
original_names.clear();
renames.clear();
left_type_map.clear();
right_type_map.clear();
}
void TableJoin::addUsingKey(const ASTPtr & ast)
{
2021-09-06 10:59:18 +00:00
addKey(ast->getColumnName(), renamedRightColumnName(ast->getAliasOrColumnName()), ast);
}
void TableJoin::addDisjunct()
{
clauses.emplace_back();
2019-07-30 18:39:37 +00:00
if (getStorageJoin() && clauses.size() > 1)
throw Exception("StorageJoin with ORs is not supported", ErrorCodes::NOT_IMPLEMENTED);
}
void TableJoin::addOnKeys(ASTPtr & left_table_ast, ASTPtr & right_table_ast)
{
2021-09-06 10:59:18 +00:00
addKey(left_table_ast->getColumnName(), right_table_ast->getAliasOrColumnName(), left_table_ast, right_table_ast);
}
/// @return how many times right key appears in ON section.
size_t TableJoin::rightKeyInclusion(const String & name) const
{
if (hasUsing())
return 0;
size_t count = 0;
2021-09-06 10:59:18 +00:00
for (const auto & clause : clauses)
count += std::count(clause.key_names_right.begin(), clause.key_names_right.end(), name);
return count;
}
void TableJoin::deduplicateAndQualifyColumnNames(const NameSet & left_table_columns, const String & right_table_prefix)
2019-07-30 18:39:37 +00:00
{
NameSet joined_columns;
NamesAndTypesList dedup_columns;
for (auto & column : columns_from_joined_table)
{
if (joined_columns.contains(column.name))
2019-07-30 18:39:37 +00:00
continue;
joined_columns.insert(column.name);
dedup_columns.push_back(column);
auto & inserted = dedup_columns.back();
2020-04-12 03:20:15 +00:00
/// Also qualify unusual column names - that does not look like identifiers.
if (left_table_columns.contains(column.name) || !isValidIdentifierBegin(column.name.at(0)))
2019-07-30 18:39:37 +00:00
inserted.name = right_table_prefix + column.name;
original_names[inserted.name] = column.name;
if (inserted.name != column.name)
renames[column.name] = inserted.name;
}
columns_from_joined_table.swap(dedup_columns);
}
2022-03-21 15:01:34 +00:00
String TableJoin::getOriginalName(const String & column_name) const
{
auto it = original_names.find(column_name);
if (it != original_names.end())
return it->second;
return column_name;
}
NamesWithAliases TableJoin::getNamesWithAliases(const NameSet & required_columns) const
2019-07-30 18:39:37 +00:00
{
NamesWithAliases out;
2022-03-21 15:01:34 +00:00
out.reserve(required_columns.size());
for (const auto & name : required_columns)
2019-02-13 19:00:52 +00:00
{
2022-03-21 15:01:34 +00:00
auto original_name = getOriginalName(name);
out.emplace_back(original_name, name);
2019-02-13 19:00:52 +00:00
}
2019-07-30 18:39:37 +00:00
return out;
2018-11-02 18:53:23 +00:00
}
ASTPtr TableJoin::leftKeysList() const
{
ASTPtr keys_list = std::make_shared<ASTExpressionList>();
keys_list->children = key_asts_left;
2021-09-06 10:59:18 +00:00
for (const auto & clause : clauses)
{
2021-09-06 10:59:18 +00:00
if (clause.on_filter_condition_left)
keys_list->children.push_back(clause.on_filter_condition_left);
}
return keys_list;
}
ASTPtr TableJoin::rightKeysList() const
{
ASTPtr keys_list = std::make_shared<ASTExpressionList>();
if (hasOn())
keys_list->children = key_asts_right;
2021-09-06 10:59:18 +00:00
for (const auto & clause : clauses)
{
if (clause.on_filter_condition_right)
keys_list->children.push_back(clause.on_filter_condition_right);
}
return keys_list;
}
Names TableJoin::requiredJoinedNames() const
{
2021-09-10 14:52:44 +00:00
Names key_names_right = getAllNames(JoinTableSide::Right);
NameSet required_columns_set(key_names_right.begin(), key_names_right.end());
for (const auto & joined_column : columns_added_by_join)
required_columns_set.insert(joined_column.name);
2021-11-08 12:44:13 +00:00
/*
* In case of `SELECT count() FROM ... JOIN .. ON NULL` required columns set for right table is empty.
* But we have to get at least one column from right table to know the number of rows.
*/
if (required_columns_set.empty() && !columns_from_joined_table.empty())
return {columns_from_joined_table.begin()->name};
return Names(required_columns_set.begin(), required_columns_set.end());
}
NameSet TableJoin::requiredRightKeys() const
2019-09-10 18:39:10 +00:00
{
2019-09-11 15:57:09 +00:00
NameSet required;
2021-09-09 09:47:08 +00:00
forAllKeys<RightSideTag>(clauses, [this, &required](const auto & name)
{
auto rename = renamedRightColumnName(name);
2019-09-11 15:57:09 +00:00
for (const auto & column : columns_added_by_join)
if (rename == column.name)
2019-09-11 15:57:09 +00:00
required.insert(name);
2021-09-06 10:59:18 +00:00
return true;
});
2019-09-10 18:39:10 +00:00
return required;
}
NamesWithAliases TableJoin::getRequiredColumns(const Block & sample, const Names & action_required_columns) const
{
NameSet required_columns(action_required_columns.begin(), action_required_columns.end());
for (auto & column : requiredJoinedNames())
if (!sample.has(column))
required_columns.insert(column);
return getNamesWithAliases(required_columns);
}
Block TableJoin::getRequiredRightKeys(const Block & right_table_keys, std::vector<String> & keys_sources) const
{
NameSet required_keys = requiredRightKeys();
Block required_right_keys;
2021-09-09 09:47:08 +00:00
if (required_keys.empty())
return required_right_keys;
2021-09-06 10:59:18 +00:00
forAllKeys(clauses, [&](const auto & left_key_name, const auto & right_key_name)
{
if (required_keys.contains(right_key_name) && !required_right_keys.has(right_key_name))
{
const auto & right_key = right_table_keys.getByName(right_key_name);
required_right_keys.insert(right_key);
2021-09-06 10:59:18 +00:00
keys_sources.push_back(left_key_name);
}
2021-09-06 10:59:18 +00:00
return true;
});
return required_right_keys;
}
bool TableJoin::leftBecomeNullable(const DataTypePtr & column_type) const
{
return forceNullableLeft() && JoinCommon::canBecomeNullable(column_type);
}
bool TableJoin::rightBecomeNullable(const DataTypePtr & column_type) const
{
return forceNullableRight() && JoinCommon::canBecomeNullable(column_type);
}
2020-04-13 17:03:11 +00:00
void TableJoin::addJoinedColumn(const NameAndTypePair & joined_column)
{
columns_added_by_join.emplace_back(joined_column);
}
NamesAndTypesList TableJoin::correctedColumnsAddedByJoin() const
{
NamesAndTypesList result;
for (const auto & col : columns_added_by_join)
{
DataTypePtr type = col.type;
if (hasUsing())
{
if (auto it = right_type_map.find(col.name); it != right_type_map.end())
type = it->second;
}
if (rightBecomeNullable(type))
type = JoinCommon::convertTypeToNullable(type);
result.emplace_back(col.name, type);
}
return result;
}
void TableJoin::addJoinedColumnsAndCorrectTypes(NamesAndTypesList & left_columns, bool correct_nullability)
{
addJoinedColumnsAndCorrectTypesImpl(left_columns, correct_nullability);
}
void TableJoin::addJoinedColumnsAndCorrectTypes(ColumnsWithTypeAndName & left_columns, bool correct_nullability)
{
addJoinedColumnsAndCorrectTypesImpl(left_columns, correct_nullability);
}
template <typename TColumns>
void TableJoin::addJoinedColumnsAndCorrectTypesImpl(TColumns & left_columns, bool correct_nullability)
{
static_assert(std::is_same_v<typename TColumns::value_type, ColumnWithTypeAndName> ||
std::is_same_v<typename TColumns::value_type, NameAndTypePair>);
constexpr bool has_column = std::is_same_v<typename TColumns::value_type, ColumnWithTypeAndName>;
for (auto & col : left_columns)
{
if (hasUsing())
{
/*
* Join with `USING` semantic allows to have columns with changed types in result table.
* But `JOIN ON` should preserve types from original table.
* So we need to know changed types in result tables before further analysis (e.g. analyzeAggregation)
* For `JOIN ON expr1 == expr2` we will infer common type later in makeTableJoin,
* when part of plan built and types of expression will be known.
*/
2021-06-29 09:22:53 +00:00
inferJoinKeyCommonType(left_columns, columns_from_joined_table, !isSpecialStorage());
if (auto it = left_type_map.find(col.name); it != left_type_map.end())
{
col.type = it->second;
if constexpr (has_column)
col.column = nullptr;
}
}
if (correct_nullability && leftBecomeNullable(col.type))
{
col.type = JoinCommon::convertTypeToNullable(col.type);
if constexpr (has_column)
col.column = nullptr;
}
}
for (const auto & col : correctedColumnsAddedByJoin())
if constexpr (has_column)
left_columns.emplace_back(nullptr, col.type, col.name);
else
left_columns.emplace_back(col.name, col.type);
}
bool TableJoin::sameStrictnessAndKind(ASTTableJoin::Strictness strictness_, ASTTableJoin::Kind kind_) const
{
if (strictness_ == strictness() && kind_ == kind())
return true;
/// Compatibility: old ANY INNER == new SEMI LEFT
if (strictness_ == ASTTableJoin::Strictness::Semi && isLeft(kind_) &&
strictness() == ASTTableJoin::Strictness::RightAny && isInner(kind()))
return true;
if (strictness() == ASTTableJoin::Strictness::Semi && isLeft(kind()) &&
strictness_ == ASTTableJoin::Strictness::RightAny && isInner(kind_))
return true;
return false;
}
2021-09-06 10:59:18 +00:00
bool TableJoin::oneDisjunct() const
{
2021-11-08 12:44:13 +00:00
return clauses.size() == 1;
2021-09-06 10:59:18 +00:00
}
bool TableJoin::allowMergeJoin() const
{
bool is_any = (strictness() == ASTTableJoin::Strictness::Any);
bool is_all = (strictness() == ASTTableJoin::Strictness::All);
bool is_semi = (strictness() == ASTTableJoin::Strictness::Semi);
bool all_join = is_all && (isInner(kind()) || isLeft(kind()) || isRight(kind()) || isFull(kind()));
bool special_left = isLeft(kind()) && (is_any || is_semi);
2021-06-25 12:03:10 +00:00
2021-09-06 10:59:18 +00:00
return (all_join || special_left) && oneDisjunct();
}
bool TableJoin::needStreamWithNonJoinedRows() const
{
if (strictness() == ASTTableJoin::Strictness::Asof ||
strictness() == ASTTableJoin::Strictness::Semi)
return false;
return isRightOrFull(kind());
}
2021-06-29 09:22:53 +00:00
static std::optional<String> getDictKeyName(const String & dict_name , ContextPtr context)
2020-04-09 20:00:57 +00:00
{
2021-06-29 09:22:53 +00:00
auto dictionary = context->getExternalDictionariesLoader().getDictionary(dict_name, context);
if (!dictionary)
return {};
if (const auto & structure = dictionary->getStructure(); structure.id)
return structure.id->name;
return {};
}
bool TableJoin::tryInitDictJoin(const Block & sample_block, ContextPtr context)
2020-04-09 20:00:57 +00:00
{
using Strictness = ASTTableJoin::Strictness;
bool allowed_inner = isInner(kind()) && strictness() == Strictness::All;
bool allowed_left = isLeft(kind()) && (strictness() == Strictness::Any ||
strictness() == Strictness::All ||
strictness() == Strictness::Semi ||
strictness() == Strictness::Anti);
2020-04-13 17:03:11 +00:00
/// Support ALL INNER, [ANY | ALL | SEMI | ANTI] LEFT
if (!allowed_inner && !allowed_left)
2020-04-13 17:03:11 +00:00
return false;
2021-09-06 10:59:18 +00:00
if (clauses.size() != 1 || clauses[0].key_names_right.size() != 1)
2020-04-09 20:00:57 +00:00
return false;
2021-09-09 09:47:08 +00:00
const auto & right_key = getOnlyClause().key_names_right[0];
2021-09-06 10:59:18 +00:00
/// TODO: support 'JOIN ... ON expr(dict_key) = table_key'
2021-09-06 10:59:18 +00:00
auto it_key = original_names.find(right_key);
if (it_key == original_names.end())
return false;
2021-06-29 09:22:53 +00:00
if (!right_storage_dictionary)
return false;
2021-06-29 10:11:01 +00:00
auto dict_name = right_storage_dictionary->getDictionaryName();
2021-06-29 09:22:53 +00:00
auto dict_key = getDictKeyName(dict_name, context);
if (!dict_key.has_value() || *dict_key != it_key->second)
return false; /// JOIN key != Dictionary key
2021-06-29 09:22:53 +00:00
Names src_names;
NamesAndTypesList dst_columns;
2020-04-22 06:01:33 +00:00
for (const auto & col : sample_block)
2020-04-09 20:00:57 +00:00
{
2021-09-06 10:59:18 +00:00
if (col.name == right_key)
2020-04-09 20:00:57 +00:00
continue; /// do not extract key column
auto it = original_names.find(col.name);
if (it != original_names.end())
{
String original = it->second;
src_names.push_back(original);
dst_columns.push_back({col.name, col.type});
}
else
{
/// Can't extract column from dictionary table
/// TODO: Sometimes it should be possible to recunstruct required column,
/// e.g. if it's an expression depending on dictionary attributes
return false;
}
2020-04-09 20:00:57 +00:00
}
2021-06-29 09:22:53 +00:00
dictionary_reader = std::make_shared<DictionaryReader>(dict_name, src_names, dst_columns, context);
2020-04-09 20:00:57 +00:00
return true;
}
2021-09-10 14:52:44 +00:00
static void renameIfNeeded(String & name, const NameToNameMap & renames)
{
2021-09-14 18:26:53 +00:00
if (const auto it = renames.find(name); it != renames.end())
name = it->second;
}
std::pair<ActionsDAGPtr, ActionsDAGPtr>
TableJoin::createConvertingActions(const ColumnsWithTypeAndName & left_sample_columns, const ColumnsWithTypeAndName & right_sample_columns)
{
inferJoinKeyCommonType(left_sample_columns, right_sample_columns, !isSpecialStorage());
2021-09-14 18:26:53 +00:00
NameToNameMap left_key_column_rename;
NameToNameMap right_key_column_rename;
auto left_converting_actions = applyKeyConvertToTable(left_sample_columns, left_type_map, left_key_column_rename, forceNullableLeft());
auto right_converting_actions = applyKeyConvertToTable(right_sample_columns, right_type_map, right_key_column_rename, forceNullableRight());
2021-09-14 18:26:53 +00:00
{
auto log_actions = [](const String & side, const ActionsDAGPtr & dag)
{
if (dag)
{
/// Just debug message
std::vector<std::string> input_cols;
for (const auto & col : dag->getRequiredColumns())
input_cols.push_back(col.name + ": " + col.type->getName());
std::vector<std::string> output_cols;
for (const auto & col : dag->getResultColumns())
output_cols.push_back(col.name + ": " + col.type->getName());
LOG_DEBUG(&Poco::Logger::get("TableJoin"), "{} JOIN converting actions: [{}] -> [{}]",
side, fmt::join(input_cols, ", "), fmt::join(output_cols, ", "));
}
else
{
LOG_DEBUG(&Poco::Logger::get("TableJoin"), "{} JOIN converting actions: empty", side);
}
};
log_actions("Left", left_converting_actions);
log_actions("Right", right_converting_actions);
}
2021-09-14 18:26:53 +00:00
forAllKeys(clauses, [&](auto & left_key, auto & right_key)
{
2021-09-10 14:52:44 +00:00
renameIfNeeded(left_key, left_key_column_rename);
renameIfNeeded(right_key, right_key_column_rename);
2021-09-14 18:26:53 +00:00
return true;
});
return {left_converting_actions, right_converting_actions};
}
template <typename LeftNamesAndTypes, typename RightNamesAndTypes>
void TableJoin::inferJoinKeyCommonType(const LeftNamesAndTypes & left, const RightNamesAndTypes & right, bool allow_right)
{
if (!left_type_map.empty() || !right_type_map.empty())
return;
NameToTypeMap left_types;
for (const auto & col : left)
left_types[col.name] = col.type;
NameToTypeMap right_types;
for (const auto & col : right)
right_types[renamedRightColumnName(col.name)] = col.type;
if (strictness() == ASTTableJoin::Strictness::Asof)
{
if (clauses.size() != 1)
throw DB::Exception("ASOF join over multiple keys is not supported", ErrorCodes::NOT_IMPLEMENTED);
auto asof_key_type = right_types.find(clauses.back().key_names_right.back());
if (asof_key_type != right_types.end() && asof_key_type->second->isNullable())
throw DB::Exception("ASOF join over right table Nullable column is not implemented", ErrorCodes::NOT_IMPLEMENTED);
}
2021-09-06 10:59:18 +00:00
forAllKeys(clauses, [&](const auto & left_key_name, const auto & right_key_name)
{
2021-09-06 10:59:18 +00:00
auto ltype = left_types.find(left_key_name);
auto rtype = right_types.find(right_key_name);
if (ltype == left_types.end() || rtype == right_types.end())
{
/// Name mismatch, give up
left_type_map.clear();
right_type_map.clear();
return false;
}
if (JoinCommon::typesEqualUpToNullability(ltype->second, rtype->second))
2021-09-10 14:52:44 +00:00
return true;
2021-09-14 18:26:53 +00:00
DataTypePtr common_type;
try
{
2021-09-14 18:26:53 +00:00
/// TODO(vdimir): use getMostSubtype if possible
common_type = DB::getLeastSupertype(DataTypes{ltype->second, rtype->second});
}
catch (DB::Exception & ex)
{
throw DB::Exception(ErrorCodes::TYPE_MISMATCH,
"Can't infer common type for joined columns: {}: {} at left, {}: {} at right ({})",
left_key_name, ltype->second->getName(),
right_key_name, rtype->second->getName(),
ex.message());
}
bool right_side_changed = !common_type->equals(*rtype->second);
if (right_side_changed && !allow_right)
2021-09-14 18:26:53 +00:00
{
throw DB::Exception(ErrorCodes::TYPE_MISMATCH,
"Can't change type for right table: {}: {} -> {}",
2021-09-14 18:26:53 +00:00
right_key_name, rtype->second->getName(), common_type->getName());
}
left_type_map[left_key_name] = right_type_map[right_key_name] = common_type;
2021-09-06 10:59:18 +00:00
return true;
});
if (!left_type_map.empty() || !right_type_map.empty())
{
LOG_TRACE(
&Poco::Logger::get("TableJoin"),
"Infer supertype for joined columns. Left: [{}], Right: [{}]",
formatTypeMap(left_type_map, left_types),
formatTypeMap(right_type_map, right_types));
}
}
2022-02-18 13:40:57 +00:00
static ActionsDAGPtr changeKeyTypes(const ColumnsWithTypeAndName & cols_src,
const TableJoin::NameToTypeMap & type_mapping,
bool add_new_cols,
NameToNameMap & key_column_rename)
{
ColumnsWithTypeAndName cols_dst = cols_src;
bool has_some_to_do = false;
for (auto & col : cols_dst)
{
if (auto it = type_mapping.find(col.name); it != type_mapping.end() && col.type != it->second)
{
col.type = it->second;
col.column = nullptr;
has_some_to_do = true;
}
}
if (!has_some_to_do)
return nullptr;
2022-02-18 13:40:57 +00:00
return ActionsDAG::makeConvertingActions(cols_src, cols_dst, ActionsDAG::MatchColumnsMode::Name, true, add_new_cols, &key_column_rename);
}
static ActionsDAGPtr changeTypesToNullable(const ColumnsWithTypeAndName & cols_src, const NameSet & exception_cols)
{
ColumnsWithTypeAndName cols_dst = cols_src;
bool has_some_to_do = false;
for (auto & col : cols_dst)
{
if (exception_cols.contains(col.name))
continue;
col.type = JoinCommon::convertTypeToNullable(col.type);
col.column = nullptr;
has_some_to_do = true;
}
2022-02-18 13:40:57 +00:00
if (!has_some_to_do)
return nullptr;
return ActionsDAG::makeConvertingActions(cols_src, cols_dst, ActionsDAG::MatchColumnsMode::Name, true, false, nullptr);
}
ActionsDAGPtr TableJoin::applyKeyConvertToTable(
const ColumnsWithTypeAndName & cols_src,
const NameToTypeMap & type_mapping,
NameToNameMap & key_column_rename,
bool make_nullable) const
{
2022-02-18 13:40:57 +00:00
/// Create DAG to convert key columns
ActionsDAGPtr dag_stage1 = changeKeyTypes(cols_src, type_mapping, !hasUsing(), key_column_rename);
2022-02-18 13:40:57 +00:00
/// Create DAG to make columns nullable if needed
if (make_nullable)
{
/// Do not need to make nullable temporary columns that would be used only as join keys, but now shown to user
NameSet cols_not_nullable;
for (const auto & t : key_column_rename)
cols_not_nullable.insert(t.second);
ColumnsWithTypeAndName input_cols = dag_stage1 ? dag_stage1->getResultColumns() : cols_src;
ActionsDAGPtr dag_stage2 = changeTypesToNullable(input_cols, cols_not_nullable);
/// Merge dags if we got two ones
if (dag_stage1)
return ActionsDAG::merge(std::move(*dag_stage1), std::move(*dag_stage2));
else
return dag_stage2;
}
return dag_stage1;
}
2022-01-21 05:36:36 +00:00
void TableJoin::setStorageJoin(std::shared_ptr<IKeyValueStorage> storage)
{
right_kv_storage = storage;
}
2021-06-29 09:22:53 +00:00
void TableJoin::setStorageJoin(std::shared_ptr<StorageJoin> storage)
{
if (right_storage_dictionary)
throw DB::Exception(ErrorCodes::LOGICAL_ERROR, "StorageJoin and Dictionary join are mutually exclusive");
right_storage_join = storage;
}
void TableJoin::setStorageJoin(std::shared_ptr<StorageDictionary> storage)
{
if (right_storage_join)
throw DB::Exception(ErrorCodes::LOGICAL_ERROR, "StorageJoin and Dictionary join are mutually exclusive");
right_storage_dictionary = storage;
}
String TableJoin::renamedRightColumnName(const String & name) const
{
if (const auto it = renames.find(name); it != renames.end())
return it->second;
return name;
}
2021-09-10 14:52:44 +00:00
void TableJoin::addKey(const String & left_name, const String & right_name, const ASTPtr & left_ast, const ASTPtr & right_ast)
{
2021-09-10 14:52:44 +00:00
clauses.back().key_names_left.emplace_back(left_name);
key_asts_left.emplace_back(left_ast);
2021-09-10 14:52:44 +00:00
clauses.back().key_names_right.emplace_back(right_name);
key_asts_right.emplace_back(right_ast ? right_ast : left_ast);
}
2021-09-06 10:59:18 +00:00
static void addJoinConditionWithAnd(ASTPtr & current_cond, const ASTPtr & new_cond)
{
2021-09-06 10:59:18 +00:00
if (current_cond == nullptr)
/// no conditions, set new one
current_cond = new_cond;
else if (const auto * func = current_cond->as<ASTFunction>(); func && func->name == "and")
/// already have `and` in condition, just add new argument
func->arguments->children.push_back(new_cond);
else
2021-09-10 14:52:44 +00:00
/// already have some conditions, unite it with `and`
2021-09-06 10:59:18 +00:00
current_cond = makeASTFunction("and", current_cond, new_cond);
}
void TableJoin::addJoinCondition(const ASTPtr & ast, bool is_left)
{
2021-09-10 14:52:44 +00:00
auto & cond_ast = is_left ? clauses.back().on_filter_condition_left : clauses.back().on_filter_condition_right;
LOG_TRACE(&Poco::Logger::get("TableJoin"), "Adding join condition for {} table: {} -> {}",
(is_left ? "left" : "right"), ast ? queryToString(ast) : "NULL", cond_ast ? queryToString(cond_ast) : "NULL");
addJoinConditionWithAnd(cond_ast, ast);
}
2021-08-06 14:15:11 +00:00
std::unordered_map<String, String> TableJoin::leftToRightKeyRemap() const
{
std::unordered_map<String, String> left_to_right_key_remap;
if (hasUsing())
{
const auto & required_right_keys = requiredRightKeys();
2021-09-06 10:59:18 +00:00
forAllKeys(clauses, [&](const auto & left_key_name, const auto & right_key_name)
2021-08-06 14:15:11 +00:00
{
if (!required_right_keys.contains(right_key_name))
left_to_right_key_remap[left_key_name] = right_key_name;
2021-09-06 10:59:18 +00:00
return true;
});
2021-08-06 14:15:11 +00:00
}
return left_to_right_key_remap;
}
2021-09-06 10:59:18 +00:00
Names TableJoin::getAllNames(JoinTableSide side) const
{
2021-09-06 10:59:18 +00:00
Names res;
2021-09-10 14:52:44 +00:00
auto func = [&res](const auto & name) { res.emplace_back(name); return true; };
if (side == JoinTableSide::Left)
forAllKeys<LeftSideTag>(clauses, func);
else
forAllKeys<RightSideTag>(clauses, func);
return res;
}
2021-09-09 09:47:08 +00:00
void TableJoin::assertHasOneOnExpr() const
{
2021-09-09 09:47:08 +00:00
if (!oneDisjunct())
{
std::vector<String> text;
for (const auto & onexpr : clauses)
text.push_back(onexpr.formatDebug());
throw DB::Exception(ErrorCodes::LOGICAL_ERROR, "Expected to have only one join clause, got {}: [{}], query: '{}'",
clauses.size(), fmt::join(text, " | "), queryToString(table_join));
}
}
2021-11-08 12:44:13 +00:00
void TableJoin::resetToCross()
{
2021-11-08 12:44:13 +00:00
this->resetKeys();
this->table_join.kind = ASTTableJoin::Kind::Cross;
}
2022-04-20 11:51:35 +00:00
bool TableJoin::allowParallelHashJoin() const
{
2022-07-04 13:19:46 +00:00
if (dictionary_reader || !join_algorithm.isSet(JoinAlgorithm::PARALLEL_HASH))
return false;
if (table_join.kind != ASTTableJoin::Kind::Left && table_join.kind != ASTTableJoin::Kind::Inner)
return false;
2022-04-21 04:14:36 +00:00
if (isSpecialStorage() || !oneDisjunct())
return false;
return true;
}
2018-11-02 18:53:23 +00:00
}