mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 09:32:01 +00:00
fix union all supertype column
This commit is contained in:
parent
d4f474cd19
commit
28c1a60eb7
67
dbms/src/Columns/getLeastSuperColumn.cpp
Normal file
67
dbms/src/Columns/getLeastSuperColumn.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <Columns/getLeastSuperColumn.h>
|
||||||
|
#include <Columns/IColumn.h>
|
||||||
|
#include <Columns/ColumnConst.h>
|
||||||
|
#include <DataTypes/getLeastSupertype.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int LOGICAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sameConstants(const IColumn & a, const IColumn & b)
|
||||||
|
{
|
||||||
|
return static_cast<const ColumnConst &>(a).getField() == static_cast<const ColumnConst &>(b).getField();
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnWithTypeAndName getLeastSuperColumn(std::vector<const ColumnWithTypeAndName *> columns)
|
||||||
|
{
|
||||||
|
if (columns.empty())
|
||||||
|
throw Exception("Logical error: no src columns for supercolumn", ErrorCodes::LOGICAL_ERROR);
|
||||||
|
|
||||||
|
ColumnWithTypeAndName result = *columns[0];
|
||||||
|
|
||||||
|
/// Determine common type.
|
||||||
|
|
||||||
|
size_t num_const = 0;
|
||||||
|
DataTypes types(columns.size());
|
||||||
|
for (size_t i = 0; i < columns.size(); ++i)
|
||||||
|
{
|
||||||
|
types[i] = columns[i]->type;
|
||||||
|
if (columns[i]->column->isColumnConst())
|
||||||
|
++num_const;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.type = getLeastSupertype(types);
|
||||||
|
|
||||||
|
/// Create supertype column saving constness if possible.
|
||||||
|
|
||||||
|
bool save_constness = false;
|
||||||
|
if (columns.size() == num_const)
|
||||||
|
{
|
||||||
|
save_constness = true;
|
||||||
|
for (size_t i = 1; i < columns.size(); ++i)
|
||||||
|
{
|
||||||
|
const ColumnWithTypeAndName & first = *columns[0];
|
||||||
|
const ColumnWithTypeAndName & other = *columns[i];
|
||||||
|
|
||||||
|
if (!sameConstants(*first.column, *other.column))
|
||||||
|
{
|
||||||
|
save_constness = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save_constness)
|
||||||
|
result.column = result.type->createColumnConst(1, static_cast<const ColumnConst &>(*columns[0]->column).getField());
|
||||||
|
else
|
||||||
|
result.column = result.type->createColumn();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
dbms/src/Columns/getLeastSuperColumn.h
Normal file
12
dbms/src/Columns/getLeastSuperColumn.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/ColumnWithTypeAndName.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
/// getLeastSupertype + related column changes
|
||||||
|
ColumnWithTypeAndName getLeastSuperColumn(std::vector<const ColumnWithTypeAndName *> columns);
|
||||||
|
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
#include <DataStreams/NullBlockInputStream.h>
|
#include <DataStreams/NullBlockInputStream.h>
|
||||||
#include <DataStreams/ConcatBlockInputStream.h>
|
#include <DataStreams/ConcatBlockInputStream.h>
|
||||||
#include <DataStreams/ConvertingBlockInputStream.h>
|
#include <DataStreams/ConvertingBlockInputStream.h>
|
||||||
#include <DataTypes/getLeastSupertype.h>
|
#include <Columns/getLeastSuperColumn.h>
|
||||||
#include <Columns/ColumnConst.h>
|
#include <Columns/ColumnConst.h>
|
||||||
#include <Common/typeid_cast.h>
|
#include <Common/typeid_cast.h>
|
||||||
#include <Parsers/queryToString.h>
|
#include <Parsers/queryToString.h>
|
||||||
@ -114,39 +114,13 @@ InterpreterSelectWithUnionQuery::InterpreterSelectWithUnionQuery(
|
|||||||
|
|
||||||
for (size_t column_num = 0; column_num < num_columns; ++column_num)
|
for (size_t column_num = 0; column_num < num_columns; ++column_num)
|
||||||
{
|
{
|
||||||
|
std::vector<const ColumnWithTypeAndName *> columns;
|
||||||
|
columns.reserve(num_selects);
|
||||||
|
for (size_t i = 0; i < num_selects; ++i)
|
||||||
|
columns.push_back(&headers[i].getByPosition(column_num));
|
||||||
|
|
||||||
ColumnWithTypeAndName & result_elem = result_header.getByPosition(column_num);
|
ColumnWithTypeAndName & result_elem = result_header.getByPosition(column_num);
|
||||||
|
result_elem = getLeastSuperColumn(columns);
|
||||||
/// Determine common type.
|
|
||||||
|
|
||||||
DataTypes types(num_selects);
|
|
||||||
for (size_t query_num = 0; query_num < num_selects; ++query_num)
|
|
||||||
types[query_num] = headers[query_num].getByPosition(column_num).type;
|
|
||||||
|
|
||||||
result_elem.type = getLeastSupertype(types);
|
|
||||||
|
|
||||||
/// If there are different constness or different values of constants, the result must be non-constant.
|
|
||||||
|
|
||||||
if (result_elem.column->isColumnConst())
|
|
||||||
{
|
|
||||||
bool need_materialize = false;
|
|
||||||
for (size_t query_num = 1; query_num < num_selects; ++query_num)
|
|
||||||
{
|
|
||||||
const ColumnWithTypeAndName & source_elem = headers[query_num].getByPosition(column_num);
|
|
||||||
|
|
||||||
if (!source_elem.column->isColumnConst()
|
|
||||||
|| (static_cast<const ColumnConst &>(*result_elem.column).getField()
|
|
||||||
!= static_cast<const ColumnConst &>(*source_elem.column).getField()))
|
|
||||||
{
|
|
||||||
need_materialize = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (need_materialize)
|
|
||||||
result_elem.column = result_elem.type->createColumn();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// BTW, result column names are from first SELECT.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
UInt64 Nullable(String)
|
||||||
|
UInt64 Nullable(String)
|
||||||
|
Decimal(18, 8) Nullable(String)
|
||||||
|
Decimal(18, 8) Nullable(String)
|
||||||
|
v2
|
||||||
|
v1 \N
|
||||||
|
v1 w1
|
||||||
|
key1 value1
|
30
dbms/tests/queries/0_stateless/00864_union_all_supertype.sql
Normal file
30
dbms/tests/queries/0_stateless/00864_union_all_supertype.sql
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
select toTypeName(key), toTypeName(value) from (
|
||||||
|
select 1 as key, '' as value
|
||||||
|
union all
|
||||||
|
select toUInt64(2) as key, toNullable('') as value
|
||||||
|
);
|
||||||
|
|
||||||
|
select toTypeName(key), toTypeName(value) from (
|
||||||
|
select toDecimal64(2, 8) as key, toNullable('') as value
|
||||||
|
union all
|
||||||
|
select toDecimal32(2, 4) as key, toFixedString('', 1) as value
|
||||||
|
);
|
||||||
|
|
||||||
|
select * from (
|
||||||
|
select 'v1' as c1, null as c2
|
||||||
|
union all
|
||||||
|
select 'v2' as c1, '' as c2
|
||||||
|
) ALL FULL JOIN (
|
||||||
|
select 'v1' as c1, 'w1' as c2
|
||||||
|
) using c1,c2;
|
||||||
|
|
||||||
|
select key, s1.value, s2.value
|
||||||
|
from (
|
||||||
|
select 'key1' as key, 'value1' as value
|
||||||
|
) s1
|
||||||
|
all left join (
|
||||||
|
select 'key1' as key, '' as value
|
||||||
|
union all
|
||||||
|
select 'key2' as key, toNullable('') as value
|
||||||
|
) s2
|
||||||
|
using key;
|
Loading…
Reference in New Issue
Block a user