fix union all supertype column

This commit is contained in:
chertus 2019-05-31 15:36:44 +03:00
parent d4f474cd19
commit 28c1a60eb7
5 changed files with 124 additions and 33 deletions

View 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;
}
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <Core/ColumnWithTypeAndName.h>
namespace DB
{
/// getLeastSupertype + related column changes
ColumnWithTypeAndName getLeastSuperColumn(std::vector<const ColumnWithTypeAndName *> columns);
}

View File

@ -6,7 +6,7 @@
#include <DataStreams/NullBlockInputStream.h>
#include <DataStreams/ConcatBlockInputStream.h>
#include <DataStreams/ConvertingBlockInputStream.h>
#include <DataTypes/getLeastSupertype.h>
#include <Columns/getLeastSuperColumn.h>
#include <Columns/ColumnConst.h>
#include <Common/typeid_cast.h>
#include <Parsers/queryToString.h>
@ -114,39 +114,13 @@ InterpreterSelectWithUnionQuery::InterpreterSelectWithUnionQuery(
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);
/// 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.
result_elem = getLeastSuperColumn(columns);
}
}
}

View File

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

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