mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
Merge pull request #7530 from 4ertus2/joins
Fix right table key nullability (join_use_keys = 0)
This commit is contained in:
commit
0f68c5a12a
@ -204,21 +204,6 @@ void AnalyzedJoin::addJoinedColumnsAndCorrectNullability(Block & sample_block) c
|
||||
|
||||
bool make_nullable = join_use_nulls && left_or_full_join;
|
||||
|
||||
if (!make_nullable)
|
||||
{
|
||||
/// Keys from right table are usually not stored in Join, but copied from the left one.
|
||||
/// So, if left key is nullable, let's make right key nullable too.
|
||||
/// Note: for some join types it's not needed and, probably, may be removed.
|
||||
/// Note: changing this code, take into account the implementation in Join.cpp.
|
||||
auto it = std::find(key_names_right.begin(), key_names_right.end(), col.name);
|
||||
if (it != key_names_right.end())
|
||||
{
|
||||
auto pos = it - key_names_right.begin();
|
||||
const auto & left_key_name = key_names_left[pos];
|
||||
make_nullable = sample_block.getByName(left_key_name).type->isNullable();
|
||||
}
|
||||
}
|
||||
|
||||
if (make_nullable && res_type->canBeInsideNullable())
|
||||
res_type = makeNullable(res_type);
|
||||
|
||||
|
@ -94,7 +94,7 @@ public:
|
||||
void addOnKeys(ASTPtr & left_table_ast, ASTPtr & right_table_ast);
|
||||
|
||||
bool hasUsing() const { return table_join.using_expression_list != nullptr; }
|
||||
bool hasOn() const { return !hasUsing(); }
|
||||
bool hasOn() const { return table_join.on_expression != nullptr; }
|
||||
|
||||
NameSet getQualifiedColumnsSet() const;
|
||||
NameSet getOriginalColumnsSet() const;
|
||||
|
@ -37,11 +37,52 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/// Converts column to nullable if needed. No backward convertion.
|
||||
static ColumnPtr filterWithBlanks(ColumnPtr src_column, const IColumn::Filter & filter, bool inverse_filter = false)
|
||||
{
|
||||
ColumnPtr column = src_column->convertToFullColumnIfConst();
|
||||
MutableColumnPtr mut_column = column->cloneEmpty();
|
||||
mut_column->reserve(column->size());
|
||||
|
||||
if (inverse_filter)
|
||||
{
|
||||
for (size_t row = 0; row < filter.size(); ++row)
|
||||
{
|
||||
if (filter[row])
|
||||
mut_column->insertDefault();
|
||||
else
|
||||
mut_column->insertFrom(*column, row);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t row = 0; row < filter.size(); ++row)
|
||||
{
|
||||
if (filter[row])
|
||||
mut_column->insertFrom(*column, row);
|
||||
else
|
||||
mut_column->insertDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return mut_column;
|
||||
}
|
||||
|
||||
static ColumnWithTypeAndName correctNullability(ColumnWithTypeAndName && column, bool nullable)
|
||||
{
|
||||
if (nullable)
|
||||
{
|
||||
JoinCommon::convertColumnToNullable(column);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// We have to replace values masked by NULLs with defaults.
|
||||
if (column.column)
|
||||
if (auto * nullable_column = checkAndGetColumn<ColumnNullable>(*column.column))
|
||||
column.column = filterWithBlanks(column.column, nullable_column->getNullMapColumn().getData(), true);
|
||||
|
||||
JoinCommon::removeColumnNullability(column);
|
||||
}
|
||||
|
||||
return std::move(column);
|
||||
}
|
||||
|
||||
@ -57,6 +98,9 @@ static ColumnWithTypeAndName correctNullability(ColumnWithTypeAndName && column,
|
||||
column.column = std::move(mutable_column);
|
||||
}
|
||||
}
|
||||
else
|
||||
JoinCommon::removeColumnNullability(column);
|
||||
|
||||
return std::move(column);
|
||||
}
|
||||
|
||||
@ -769,7 +813,7 @@ void Join::joinBlockImpl(
|
||||
for (size_t i = 0; i < existing_columns; ++i)
|
||||
block.safeGetByPosition(i).column = block.safeGetByPosition(i).column->filter(row_filter, -1);
|
||||
|
||||
/// Add join key columns from right block if they has different name.
|
||||
/// Add join key columns from right block if needed.
|
||||
for (size_t i = 0; i < right_table_keys.columns(); ++i)
|
||||
{
|
||||
const auto & right_key = right_table_keys.getByPosition(i);
|
||||
@ -791,7 +835,7 @@ void Join::joinBlockImpl(
|
||||
null_map_filter.getData().swap(row_filter);
|
||||
const IColumn::Filter & filter = null_map_filter.getData();
|
||||
|
||||
/// Add join key columns from right block if they has different name.
|
||||
/// Add join key columns from right block if needed.
|
||||
for (size_t i = 0; i < right_table_keys.columns(); ++i)
|
||||
{
|
||||
const auto & right_key = right_table_keys.getByPosition(i);
|
||||
@ -800,20 +844,10 @@ void Join::joinBlockImpl(
|
||||
if (required_right_keys.count(right_key.name) && !block.has(right_key.name))
|
||||
{
|
||||
const auto & col = block.getByName(left_name);
|
||||
ColumnPtr column = col.column->convertToFullColumnIfConst();
|
||||
MutableColumnPtr mut_column = column->cloneEmpty();
|
||||
mut_column->reserve(column->size());
|
||||
|
||||
for (size_t row = 0; row < filter.size(); ++row)
|
||||
{
|
||||
if (filter[row])
|
||||
mut_column->insertFrom(*column, row);
|
||||
else
|
||||
mut_column->insertDefault();
|
||||
}
|
||||
|
||||
bool is_nullable = nullable_right_side || right_key.type->isNullable();
|
||||
block.insert(correctNullability({std::move(mut_column), col.type, right_key.name}, is_nullable, null_map_filter));
|
||||
|
||||
ColumnPtr thin_column = filterWithBlanks(col.column, filter);
|
||||
block.insert(correctNullability({thin_column, col.type, right_key.name}, is_nullable, null_map_filter));
|
||||
|
||||
if constexpr (is_all_join)
|
||||
right_keys_to_replicate.push_back(block.getPositionByName(right_key.name));
|
||||
|
@ -32,6 +32,22 @@ void convertColumnsToNullable(Block & block, size_t starting_pos)
|
||||
convertColumnToNullable(block.getByPosition(i));
|
||||
}
|
||||
|
||||
/// @warning It assumes that every NULL has default value in nested column (or it does not matter)
|
||||
void removeColumnNullability(ColumnWithTypeAndName & column)
|
||||
{
|
||||
if (!column.type->isNullable())
|
||||
return;
|
||||
|
||||
column.type = static_cast<const DataTypeNullable &>(*column.type).getNestedType();
|
||||
if (column.column)
|
||||
{
|
||||
auto * nullable_column = checkAndGetColumn<ColumnNullable>(*column.column);
|
||||
ColumnPtr nested_column = nullable_column->getNestedColumnPtr();
|
||||
MutableColumnPtr mutable_column = (*std::move(nested_column)).mutate();
|
||||
column.column = std::move(mutable_column);
|
||||
}
|
||||
}
|
||||
|
||||
ColumnRawPtrs temporaryMaterializeColumns(const Block & block, const Names & names, Columns & materialized)
|
||||
{
|
||||
ColumnRawPtrs ptrs;
|
||||
|
@ -15,6 +15,7 @@ namespace JoinCommon
|
||||
|
||||
void convertColumnToNullable(ColumnWithTypeAndName & column);
|
||||
void convertColumnsToNullable(Block & block, size_t starting_pos = 0);
|
||||
void removeColumnNullability(ColumnWithTypeAndName & column);
|
||||
ColumnRawPtrs temporaryMaterializeColumns(const Block & block, const Names & names, Columns & materialized);
|
||||
void removeLowCardinalityInplace(Block & block);
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
\N test 0 1 Nullable(String) Nullable(String)
|
||||
bar bar 1 2 Nullable(String) Nullable(String)
|
||||
\N 0 1 Nullable(String) Nullable(String)
|
||||
foo \N 2 0 Nullable(String) Nullable(String)
|
||||
\N test 0 1 Nullable(String) Nullable(String)
|
||||
bar bar 1 2 Nullable(String) Nullable(String)
|
||||
\N 0 1 Nullable(String) Nullable(String)
|
||||
foo \N 2 0 Nullable(String) Nullable(String)
|
||||
\N test 0 1 Nullable(String) String
|
||||
bar bar 1 2 Nullable(String) String
|
||||
\N 0 1 Nullable(String) String
|
||||
foo 2 0 Nullable(String) String
|
||||
\N test 0 1 Nullable(String) String
|
||||
bar bar 1 2 Nullable(String) String
|
||||
\N 0 1 Nullable(String) String
|
||||
foo 2 0 Nullable(String) String
|
||||
foo \N 2 0 String Nullable(String)
|
||||
bar bar 1 2 String Nullable(String)
|
||||
test 0 1 String Nullable(String)
|
||||
|
Loading…
Reference in New Issue
Block a user