mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Merge pull request #27516 from vdimir/fix-join-const-nullable
Fix Nullable const columns in JOIN
This commit is contained in:
commit
f0a7c6ec94
@ -187,6 +187,7 @@ public:
|
|||||||
* So LC(Nullable(T)) would return true, LC(U) -- false.
|
* So LC(Nullable(T)) would return true, LC(U) -- false.
|
||||||
*/
|
*/
|
||||||
bool nestedIsNullable() const { return isColumnNullable(*dictionary.getColumnUnique().getNestedColumn()); }
|
bool nestedIsNullable() const { return isColumnNullable(*dictionary.getColumnUnique().getNestedColumn()); }
|
||||||
|
bool nestedCanBeInsideNullable() const { return dictionary.getColumnUnique().getNestedColumn()->canBeInsideNullable(); }
|
||||||
void nestedToNullable() { dictionary.getColumnUnique().nestedToNullable(); }
|
void nestedToNullable() { dictionary.getColumnUnique().nestedToNullable(); }
|
||||||
void nestedRemoveNullable() { dictionary.getColumnUnique().nestedRemoveNullable(); }
|
void nestedRemoveNullable() { dictionary.getColumnUnique().nestedRemoveNullable(); }
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Columns/ColumnLowCardinality.h>
|
#include <Columns/ColumnLowCardinality.h>
|
||||||
#include <Columns/ColumnNullable.h>
|
#include <Columns/ColumnNullable.h>
|
||||||
|
#include <Columns/ColumnConst.h>
|
||||||
|
|
||||||
#include <DataStreams/materializeBlock.h>
|
#include <DataStreams/materializeBlock.h>
|
||||||
|
|
||||||
@ -105,25 +106,57 @@ DataTypePtr convertTypeToNullable(const DataTypePtr & type)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert column to nullable. If column LowCardinality or Const, convert nested column.
|
||||||
|
/// Returns nullptr if conversion cannot be performed.
|
||||||
|
static ColumnPtr tryConvertColumnToNullable(const ColumnPtr & col)
|
||||||
|
{
|
||||||
|
if (isColumnNullable(*col) || col->canBeInsideNullable())
|
||||||
|
return makeNullable(col);
|
||||||
|
|
||||||
|
if (col->lowCardinality())
|
||||||
|
{
|
||||||
|
auto mut_col = IColumn::mutate(std::move(col));
|
||||||
|
ColumnLowCardinality * col_lc = assert_cast<ColumnLowCardinality *>(mut_col.get());
|
||||||
|
if (col_lc->nestedIsNullable())
|
||||||
|
{
|
||||||
|
return mut_col;
|
||||||
|
}
|
||||||
|
else if (col_lc->nestedCanBeInsideNullable())
|
||||||
|
{
|
||||||
|
col_lc->nestedToNullable();
|
||||||
|
return mut_col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (const ColumnConst * col_const = checkAndGetColumn<ColumnConst>(*col))
|
||||||
|
{
|
||||||
|
const auto & nested = col_const->getDataColumnPtr();
|
||||||
|
if (nested->isNullable() || nested->canBeInsideNullable())
|
||||||
|
{
|
||||||
|
return makeNullable(col);
|
||||||
|
}
|
||||||
|
else if (nested->lowCardinality())
|
||||||
|
{
|
||||||
|
ColumnPtr nested_nullable = tryConvertColumnToNullable(nested);
|
||||||
|
if (nested_nullable)
|
||||||
|
return ColumnConst::create(nested_nullable, col_const->size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void convertColumnToNullable(ColumnWithTypeAndName & column)
|
void convertColumnToNullable(ColumnWithTypeAndName & column)
|
||||||
{
|
{
|
||||||
column.type = convertTypeToNullable(column.type);
|
|
||||||
|
|
||||||
if (!column.column)
|
if (!column.column)
|
||||||
|
{
|
||||||
|
column.type = convertTypeToNullable(column.type);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (column.column->lowCardinality())
|
|
||||||
{
|
|
||||||
/// Convert nested to nullable, not LowCardinality itself
|
|
||||||
auto mut_col = IColumn::mutate(std::move(column.column));
|
|
||||||
ColumnLowCardinality * col_as_lc = assert_cast<ColumnLowCardinality *>(mut_col.get());
|
|
||||||
if (!col_as_lc->nestedIsNullable())
|
|
||||||
col_as_lc->nestedToNullable();
|
|
||||||
column.column = std::move(mut_col);
|
|
||||||
}
|
}
|
||||||
else if (column.column->canBeInsideNullable())
|
|
||||||
|
ColumnPtr nullable_column = tryConvertColumnToNullable(column.column);
|
||||||
|
if (nullable_column)
|
||||||
{
|
{
|
||||||
column.column = makeNullable(column.column);
|
column.type = convertTypeToNullable(column.type);
|
||||||
|
column.column = std::move(nullable_column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
tests/queries/0_stateless/02007_join_use_nulls.reference
Normal file
8
tests/queries/0_stateless/02007_join_use_nulls.reference
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
1 2 3 1 3
|
||||||
|
1 UInt8 2 UInt8 3 Nullable(UInt8)
|
||||||
|
1 LowCardinality(UInt8) 2 LowCardinality(UInt8) 3 LowCardinality(Nullable(UInt8))
|
||||||
|
1 LowCardinality(UInt8) 2 LowCardinality(UInt8) 1 LowCardinality(Nullable(UInt8))
|
||||||
|
1 UInt8 2 UInt8 3 Nullable(UInt8)
|
||||||
|
1 UInt8 2 UInt8 1 Nullable(UInt8) 3 Nullable(UInt8)
|
||||||
|
1 LowCardinality(UInt8) 2 LowCardinality(UInt8) 3 LowCardinality(Nullable(UInt8))
|
||||||
|
1 LowCardinality(UInt8) 2 LowCardinality(UInt8) 1 LowCardinality(Nullable(UInt8)) 3 LowCardinality(Nullable(UInt8))
|
11
tests/queries/0_stateless/02007_join_use_nulls.sql
Normal file
11
tests/queries/0_stateless/02007_join_use_nulls.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
SET join_use_nulls = 1;
|
||||||
|
|
||||||
|
SELECT *, d.* FROM ( SELECT 1 AS id, 2 AS value ) a SEMI LEFT JOIN ( SELECT 1 AS id, 3 AS values ) AS d USING id;
|
||||||
|
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.values, toTypeName(d.values) FROM ( SELECT 1 AS id, 2 AS value ) a SEMI LEFT JOIN ( SELECT 1 AS id, 3 AS values ) AS d USING id;
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.values, toTypeName(d.values) FROM ( SELECT toLowCardinality(1) AS id, toLowCardinality(2) AS value ) a SEMI LEFT JOIN ( SELECT toLowCardinality(1) AS id, toLowCardinality(3) AS values ) AS d USING id;
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.id, toTypeName(d.id) FROM ( SELECT toLowCardinality(1) AS id, toLowCardinality(2) AS value ) a SEMI LEFT JOIN ( SELECT toLowCardinality(1) AS id, toLowCardinality(3) AS values ) AS d USING id;
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.values, toTypeName(d.values) FROM ( SELECT 1 AS id, 2 AS value ) a SEMI LEFT JOIN ( SELECT 1 AS id, 3 AS values ) AS d USING id;
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.id, toTypeName(d.id) , d.values, toTypeName(d.values) FROM ( SELECT 1 AS id, 2 AS value ) a SEMI LEFT JOIN ( SELECT 1 AS id, 3 AS values ) AS d USING id;
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.values, toTypeName(d.values) FROM ( SELECT toLowCardinality(1) AS id, toLowCardinality(2) AS value ) a SEMI LEFT JOIN ( SELECT toLowCardinality(1) AS id, toLowCardinality(3) AS values ) AS d USING id;
|
||||||
|
SELECT id, toTypeName(id), value, toTypeName(value), d.id, toTypeName(d.id) , d.values, toTypeName(d.values) FROM ( SELECT toLowCardinality(1) AS id, toLowCardinality(2) AS value ) a SEMI LEFT JOIN ( SELECT toLowCardinality(1) AS id, toLowCardinality(3) AS values ) AS d USING id;
|
Loading…
Reference in New Issue
Block a user