mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-11 08:52:06 +00:00
359 lines
12 KiB
C++
359 lines
12 KiB
C++
#include <IO/WriteBufferFromString.h>
|
|
#include <IO/Operators.h>
|
|
#include <Common/typeid_cast.h>
|
|
|
|
#include <DataTypes/getMostSubtype.h>
|
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
#include <DataTypes/DataTypeTuple.h>
|
|
#include <DataTypes/DataTypeNullable.h>
|
|
#include <DataTypes/DataTypeNothing.h>
|
|
#include <DataTypes/DataTypeString.h>
|
|
#include <DataTypes/DataTypeDate.h>
|
|
#include <DataTypes/DataTypesNumber.h>
|
|
|
|
|
|
namespace DB
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
{
|
|
extern const int NO_COMMON_TYPE;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
String getExceptionMessagePrefix(const DataTypes & types)
|
|
{
|
|
WriteBufferFromOwnString res;
|
|
res << "There is no subtype for types ";
|
|
|
|
bool first = true;
|
|
for (const auto & type : types)
|
|
{
|
|
if (!first)
|
|
res << ", ";
|
|
first = false;
|
|
|
|
res << type->getName();
|
|
}
|
|
|
|
return res.str();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
DataTypePtr getMostSubtype(const DataTypes & types, bool throw_if_result_is_nothing, bool force_support_conversion)
|
|
{
|
|
auto get_nothing_or_throw = [throw_if_result_is_nothing, & types](const std::string & reason)
|
|
{
|
|
if (throw_if_result_is_nothing)
|
|
throw Exception::createDeprecated(getExceptionMessagePrefix(types) + reason, ErrorCodes::NO_COMMON_TYPE);
|
|
return std::make_shared<DataTypeNothing>();
|
|
};
|
|
|
|
/// Trivial cases
|
|
|
|
if (types.empty())
|
|
{
|
|
if (throw_if_result_is_nothing)
|
|
throw Exception(ErrorCodes::NO_COMMON_TYPE, "There is no common type for empty type list");
|
|
return std::make_shared<DataTypeNothing>();
|
|
}
|
|
|
|
if (types.size() == 1)
|
|
{
|
|
if (throw_if_result_is_nothing && typeid_cast<const DataTypeNothing *>(types[0].get()))
|
|
throw Exception(ErrorCodes::NO_COMMON_TYPE, "There is no common type for type Nothing");
|
|
return types[0];
|
|
}
|
|
|
|
/// All types are equal
|
|
{
|
|
bool all_equal = true;
|
|
for (size_t i = 1, size = types.size(); i < size; ++i)
|
|
{
|
|
if (!types[i]->equals(*types[0]))
|
|
{
|
|
all_equal = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (all_equal)
|
|
return types[0];
|
|
}
|
|
|
|
/// Recursive rules
|
|
|
|
/// If there are Nothing types, result is Nothing
|
|
{
|
|
for (const auto & type : types)
|
|
if (typeid_cast<const DataTypeNothing *>(type.get()))
|
|
return get_nothing_or_throw(" because some of them are Nothing");
|
|
}
|
|
|
|
/// For Arrays
|
|
{
|
|
bool have_array = false;
|
|
bool all_arrays = true;
|
|
|
|
DataTypes nested_types;
|
|
nested_types.reserve(types.size());
|
|
|
|
for (const auto & type : types)
|
|
{
|
|
if (const auto * type_array = typeid_cast<const DataTypeArray *>(type.get()))
|
|
{
|
|
have_array = true;
|
|
nested_types.emplace_back(type_array->getNestedType());
|
|
}
|
|
else
|
|
all_arrays = false;
|
|
}
|
|
|
|
if (have_array)
|
|
{
|
|
if (!all_arrays)
|
|
return get_nothing_or_throw(" because some of them are Array and some of them are not");
|
|
|
|
return std::make_shared<DataTypeArray>(getMostSubtype(nested_types, false, force_support_conversion));
|
|
}
|
|
}
|
|
|
|
/// For tuples
|
|
{
|
|
bool have_tuple = false;
|
|
bool all_tuples = true;
|
|
size_t tuple_size = 0;
|
|
|
|
std::vector<DataTypes> nested_types;
|
|
|
|
for (const auto & type : types)
|
|
{
|
|
if (const auto * type_tuple = typeid_cast<const DataTypeTuple *>(type.get()))
|
|
{
|
|
if (!have_tuple)
|
|
{
|
|
tuple_size = type_tuple->getElements().size();
|
|
nested_types.resize(tuple_size);
|
|
for (size_t elem_idx = 0; elem_idx < tuple_size; ++elem_idx)
|
|
nested_types[elem_idx].reserve(types.size());
|
|
}
|
|
else if (tuple_size != type_tuple->getElements().size())
|
|
return get_nothing_or_throw(" because Tuples have different sizes");
|
|
|
|
have_tuple = true;
|
|
|
|
for (size_t elem_idx = 0; elem_idx < tuple_size; ++elem_idx)
|
|
nested_types[elem_idx].emplace_back(type_tuple->getElements()[elem_idx]);
|
|
}
|
|
else
|
|
all_tuples = false;
|
|
}
|
|
|
|
if (have_tuple)
|
|
{
|
|
if (!all_tuples)
|
|
return get_nothing_or_throw(" because some of them are Tuple and some of them are not");
|
|
|
|
DataTypes common_tuple_types(tuple_size);
|
|
for (size_t elem_idx = 0; elem_idx < tuple_size; ++elem_idx)
|
|
common_tuple_types[elem_idx] =
|
|
getMostSubtype(nested_types[elem_idx], throw_if_result_is_nothing, force_support_conversion);
|
|
|
|
return std::make_shared<DataTypeTuple>(common_tuple_types);
|
|
}
|
|
}
|
|
|
|
/// For Nullable
|
|
{
|
|
bool all_nullable = true;
|
|
bool have_nullable = false;
|
|
|
|
DataTypes nested_types;
|
|
nested_types.reserve(types.size());
|
|
|
|
for (const auto & type : types)
|
|
{
|
|
if (const auto * type_nullable = typeid_cast<const DataTypeNullable *>(type.get()))
|
|
{
|
|
have_nullable = true;
|
|
nested_types.emplace_back(type_nullable->getNestedType());
|
|
}
|
|
else
|
|
{
|
|
all_nullable = false;
|
|
nested_types.emplace_back(type);
|
|
}
|
|
}
|
|
|
|
if (have_nullable)
|
|
{
|
|
if (all_nullable || force_support_conversion)
|
|
return std::make_shared<DataTypeNullable>(getMostSubtype(nested_types, false, force_support_conversion));
|
|
|
|
return getMostSubtype(nested_types, throw_if_result_is_nothing, force_support_conversion);
|
|
}
|
|
}
|
|
|
|
/// Non-recursive rules
|
|
|
|
/// For String and FixedString, the common type is FixedString.
|
|
/// For different FixedStrings, the common type is Nothing.
|
|
/// No other types are compatible with Strings. TODO Enums?
|
|
{
|
|
bool have_string = false;
|
|
bool all_strings = true;
|
|
|
|
DataTypePtr fixed_string_type = nullptr;
|
|
|
|
for (const auto & type : types)
|
|
{
|
|
if (isFixedString(type))
|
|
{
|
|
have_string = true;
|
|
if (!fixed_string_type)
|
|
fixed_string_type = type;
|
|
else if (!type->equals(*fixed_string_type))
|
|
return get_nothing_or_throw(" because some of them are FixedStrings with different length");
|
|
}
|
|
else if (isString(type))
|
|
have_string = true;
|
|
else
|
|
all_strings = false;
|
|
}
|
|
|
|
if (have_string)
|
|
{
|
|
if (!all_strings)
|
|
return get_nothing_or_throw(" because some of them are String/FixedString and some of them are not");
|
|
|
|
return fixed_string_type ? fixed_string_type : std::make_shared<DataTypeString>();
|
|
}
|
|
}
|
|
|
|
/// For Date and DateTime, the common type is Date. No other types are compatible.
|
|
{
|
|
bool have_date_or_datetime = false;
|
|
bool all_date_or_datetime = true;
|
|
|
|
for (const auto & type : types)
|
|
{
|
|
if (isDate(type) || isDateTime(type) || isDateTime64(type))
|
|
have_date_or_datetime = true;
|
|
else
|
|
all_date_or_datetime = false;
|
|
}
|
|
|
|
if (have_date_or_datetime)
|
|
{
|
|
if (!all_date_or_datetime)
|
|
return get_nothing_or_throw(" because some of them are Date/DateTime and some of them are not");
|
|
|
|
return std::make_shared<DataTypeDate>();
|
|
}
|
|
}
|
|
|
|
/// For numeric types, the most complicated part.
|
|
{
|
|
bool all_numbers = true;
|
|
|
|
size_t min_bits_of_signed_integer = 0;
|
|
size_t min_bits_of_unsigned_integer = 0;
|
|
size_t min_mantissa_bits_of_floating = 0;
|
|
|
|
auto minimize = [](size_t & what, size_t value)
|
|
{
|
|
if (what == 0 || value < what)
|
|
what = value;
|
|
};
|
|
|
|
for (const auto & type : types)
|
|
{
|
|
if (typeid_cast<const DataTypeUInt8 *>(type.get()))
|
|
minimize(min_bits_of_unsigned_integer, 8);
|
|
else if (typeid_cast<const DataTypeUInt16 *>(type.get()))
|
|
minimize(min_bits_of_unsigned_integer, 16);
|
|
else if (typeid_cast<const DataTypeUInt32 *>(type.get()))
|
|
minimize(min_bits_of_unsigned_integer, 32);
|
|
else if (typeid_cast<const DataTypeUInt64 *>(type.get()))
|
|
minimize(min_bits_of_unsigned_integer, 64);
|
|
else if (typeid_cast<const DataTypeInt8 *>(type.get()))
|
|
minimize(min_bits_of_signed_integer, 8);
|
|
else if (typeid_cast<const DataTypeInt16 *>(type.get()))
|
|
minimize(min_bits_of_signed_integer, 16);
|
|
else if (typeid_cast<const DataTypeInt32 *>(type.get()))
|
|
minimize(min_bits_of_signed_integer, 32);
|
|
else if (typeid_cast<const DataTypeInt64 *>(type.get()))
|
|
minimize(min_bits_of_signed_integer, 64);
|
|
else if (typeid_cast<const DataTypeFloat32 *>(type.get()))
|
|
minimize(min_mantissa_bits_of_floating, 24);
|
|
else if (typeid_cast<const DataTypeFloat64 *>(type.get()))
|
|
minimize(min_mantissa_bits_of_floating, 53);
|
|
else
|
|
all_numbers = false;
|
|
}
|
|
|
|
if (min_bits_of_signed_integer || min_bits_of_unsigned_integer || min_mantissa_bits_of_floating)
|
|
{
|
|
if (!all_numbers)
|
|
return get_nothing_or_throw(" because some of them are numbers and some of them are not");
|
|
|
|
/// If the result must be floating.
|
|
if (!min_bits_of_signed_integer && !min_bits_of_unsigned_integer)
|
|
{
|
|
if (min_mantissa_bits_of_floating <= 24)
|
|
return std::make_shared<DataTypeFloat32>();
|
|
else if (min_mantissa_bits_of_floating <= 53)
|
|
return std::make_shared<DataTypeFloat64>();
|
|
else
|
|
throw Exception(ErrorCodes::NO_COMMON_TYPE,
|
|
"Logical error: {} but as all data types are floats, "
|
|
"we must have found maximum float type", getExceptionMessagePrefix(types));
|
|
}
|
|
|
|
/// If there are signed and unsigned types of same bit-width, the result must be unsigned number.
|
|
if (min_bits_of_unsigned_integer &&
|
|
(min_bits_of_signed_integer == 0 || min_bits_of_unsigned_integer <= min_bits_of_signed_integer))
|
|
{
|
|
if (min_bits_of_unsigned_integer <= 8)
|
|
return std::make_shared<DataTypeUInt8>();
|
|
else if (min_bits_of_unsigned_integer <= 16)
|
|
return std::make_shared<DataTypeUInt16>();
|
|
else if (min_bits_of_unsigned_integer <= 32)
|
|
return std::make_shared<DataTypeUInt32>();
|
|
else if (min_bits_of_unsigned_integer <= 64)
|
|
return std::make_shared<DataTypeUInt64>();
|
|
else
|
|
throw Exception(ErrorCodes::NO_COMMON_TYPE,
|
|
"Logical error: {} but as all data types are integers, "
|
|
"we must have found maximum unsigned integer type",
|
|
getExceptionMessagePrefix(types));
|
|
}
|
|
|
|
/// All signed.
|
|
{
|
|
if (min_bits_of_signed_integer <= 8)
|
|
return std::make_shared<DataTypeInt8>();
|
|
else if (min_bits_of_signed_integer <= 16)
|
|
return std::make_shared<DataTypeInt16>();
|
|
else if (min_bits_of_signed_integer <= 32)
|
|
return std::make_shared<DataTypeInt32>();
|
|
else if (min_bits_of_signed_integer <= 64)
|
|
return std::make_shared<DataTypeInt64>();
|
|
else
|
|
throw Exception(ErrorCodes::NO_COMMON_TYPE,
|
|
"Logical error: {} but as all data types are integers, "
|
|
"we must have found maximum signed integer type", getExceptionMessagePrefix(types));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// All other data types (UUID, AggregateFunction, Enum...) are compatible only if they are the same (checked in trivial cases).
|
|
return get_nothing_or_throw("");
|
|
}
|
|
|
|
}
|