fix JOIN right table keys nullability

This commit is contained in:
chertus 2019-10-29 22:39:42 +03:00
parent 12b57aedf0
commit deb2406b30
4 changed files with 75 additions and 24 deletions

View File

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

View File

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

View File

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

View File

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