#include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int BAD_ARGUMENTS; extern const int NO_COMMON_TYPE; } namespace { String getExceptionMessagePrefix(const DataTypes & types) { WriteBufferFromOwnString res; res << "There is no supertype for types "; bool first = true; for (const auto & type : types) { if (!first) res << ", "; first = false; res << type->getName(); } return res.str(); } } DataTypePtr getLeastSupertype(const DataTypes & types) { /// Trivial cases if (types.empty()) return std::make_shared(); if (types.size() == 1) 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, skip them { DataTypes non_nothing_types; non_nothing_types.reserve(types.size()); for (const auto & type : types) if (!typeid_cast(type.get())) non_nothing_types.emplace_back(type); if (non_nothing_types.size() < types.size()) return getLeastSupertype(non_nothing_types); } /// 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 DataTypeArray * type_array = typeid_cast(type.get())) { have_array = true; nested_types.emplace_back(type_array->getNestedType()); } else all_arrays = false; } if (have_array) { if (!all_arrays) throw Exception(getExceptionMessagePrefix(types) + " because some of them are Array and some of them are not", ErrorCodes::NO_COMMON_TYPE); return std::make_shared(getLeastSupertype(nested_types)); } } /// For tuples { bool have_tuple = false; bool all_tuples = true; size_t tuple_size = 0; std::vector nested_types; for (const auto & type : types) { if (const DataTypeTuple * type_tuple = typeid_cast(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()) throw Exception(getExceptionMessagePrefix(types) + " because Tuples have different sizes", ErrorCodes::NO_COMMON_TYPE); 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) throw Exception(getExceptionMessagePrefix(types) + " because some of them are Tuple and some of them are not", ErrorCodes::NO_COMMON_TYPE); DataTypes common_tuple_types(tuple_size); for (size_t elem_idx = 0; elem_idx < tuple_size; ++elem_idx) common_tuple_types[elem_idx] = getLeastSupertype(nested_types[elem_idx]); return std::make_shared(common_tuple_types); } } /// For Nullable { bool have_nullable = false; DataTypes nested_types; nested_types.reserve(types.size()); for (const auto & type : types) { if (const DataTypeNullable * type_nullable = typeid_cast(type.get())) { have_nullable = true; if (!type_nullable->onlyNull()) nested_types.emplace_back(type_nullable->getNestedType()); } else nested_types.emplace_back(type); } if (have_nullable) { return std::make_shared(getLeastSupertype(nested_types)); } } /// Non-recursive rules std::unordered_set type_ids; for (const auto & type : types) type_ids.insert(type->getTypeId()); /// For String and FixedString, or for different FixedStrings, the common type is String. /// No other types are compatible with Strings. TODO Enums? { UInt32 have_string = type_ids.count(TypeIndex::String); UInt32 have_fixed_string = type_ids.count(TypeIndex::FixedString); if (have_string || have_fixed_string) { bool all_strings = type_ids.size() == (have_string + have_fixed_string); if (!all_strings) throw Exception(getExceptionMessagePrefix(types) + " because some of them are String/FixedString and some of them are not", ErrorCodes::NO_COMMON_TYPE); return std::make_shared(); } } /// For Date and DateTime, the common type is DateTime. No other types are compatible. { UInt32 have_date = type_ids.count(TypeIndex::Date); UInt32 have_datetime = type_ids.count(TypeIndex::DateTime); if (have_date || have_datetime) { bool all_date_or_datetime = type_ids.size() == (have_date + have_datetime); if (!all_date_or_datetime) throw Exception(getExceptionMessagePrefix(types) + " because some of them are Date/DateTime and some of them are not", ErrorCodes::NO_COMMON_TYPE); return std::make_shared(); } } /// Decimals { UInt32 have_decimal32 = type_ids.count(TypeIndex::Decimal32); UInt32 have_decimal64 = type_ids.count(TypeIndex::Decimal64); UInt32 have_decimal128 = type_ids.count(TypeIndex::Decimal128); if (have_decimal32 || have_decimal64 || have_decimal128) { bool all_are_decimals = type_ids.size() == (have_decimal32 + have_decimal64 + have_decimal128); if (!all_are_decimals) throw Exception(getExceptionMessagePrefix(types) + " because some of them are Decimals and some are not", ErrorCodes::NO_COMMON_TYPE); UInt32 max_scale = 0; for (const auto & type : types) { UInt32 scale = getDecimalScale(*type); if (scale > max_scale) max_scale = scale; } if (have_decimal128) return std::make_shared>(DataTypeDecimal::maxPrecision(), max_scale); if (have_decimal64) return std::make_shared>(DataTypeDecimal::maxPrecision(), max_scale); return std::make_shared>(DataTypeDecimal::maxPrecision(), max_scale); } } /// For numeric types, the most complicated part. { bool all_numbers = true; size_t max_bits_of_signed_integer = 0; size_t max_bits_of_unsigned_integer = 0; size_t max_mantissa_bits_of_floating = 0; auto maximize = [](size_t & what, size_t value) { if (value > what) what = value; }; for (const auto & type : types) { if (typeid_cast(type.get())) maximize(max_bits_of_unsigned_integer, 8); else if (typeid_cast(type.get())) maximize(max_bits_of_unsigned_integer, 16); else if (typeid_cast(type.get())) maximize(max_bits_of_unsigned_integer, 32); else if (typeid_cast(type.get())) maximize(max_bits_of_unsigned_integer, 64); else if (typeid_cast(type.get())) maximize(max_bits_of_signed_integer, 8); else if (typeid_cast(type.get())) maximize(max_bits_of_signed_integer, 16); else if (typeid_cast(type.get())) maximize(max_bits_of_signed_integer, 32); else if (typeid_cast(type.get())) maximize(max_bits_of_signed_integer, 64); else if (typeid_cast(type.get())) maximize(max_mantissa_bits_of_floating, 24); else if (typeid_cast(type.get())) maximize(max_mantissa_bits_of_floating, 53); else all_numbers = false; } if (max_bits_of_signed_integer || max_bits_of_unsigned_integer || max_mantissa_bits_of_floating) { if (!all_numbers) throw Exception(getExceptionMessagePrefix(types) + " because some of them are numbers and some of them are not", ErrorCodes::NO_COMMON_TYPE); /// If there are signed and unsigned types of same bit-width, the result must be signed number with at least one more bit. /// Example, common of Int32, UInt32 = Int64. size_t min_bit_width_of_integer = std::max(max_bits_of_signed_integer, max_bits_of_unsigned_integer); /// If unsigned is not covered by signed. if (max_bits_of_signed_integer && max_bits_of_unsigned_integer >= max_bits_of_signed_integer) ++min_bit_width_of_integer; /// If the result must be floating. if (max_mantissa_bits_of_floating) { size_t min_mantissa_bits = std::max(min_bit_width_of_integer, max_mantissa_bits_of_floating); if (min_mantissa_bits <= 24) return std::make_shared(); else if (min_mantissa_bits <= 53) return std::make_shared(); else throw Exception(getExceptionMessagePrefix(types) + " because some of them are integers and some are floating point," " but there is no floating point type, that can exactly represent all required integers", ErrorCodes::NO_COMMON_TYPE); } /// If the result must be signed integer. if (max_bits_of_signed_integer) { if (min_bit_width_of_integer <= 8) return std::make_shared(); else if (min_bit_width_of_integer <= 16) return std::make_shared(); else if (min_bit_width_of_integer <= 32) return std::make_shared(); else if (min_bit_width_of_integer <= 64) return std::make_shared(); else throw Exception(getExceptionMessagePrefix(types) + " because some of them are signed integers and some are unsigned integers," " but there is no signed integer type, that can exactly represent all required unsigned integer values", ErrorCodes::NO_COMMON_TYPE); } /// All unsigned. { if (min_bit_width_of_integer <= 8) return std::make_shared(); else if (min_bit_width_of_integer <= 16) return std::make_shared(); else if (min_bit_width_of_integer <= 32) return std::make_shared(); else if (min_bit_width_of_integer <= 64) return std::make_shared(); else throw Exception("Logical error: " + getExceptionMessagePrefix(types) + " but as all data types are unsigned integers, we must have found maximum unsigned integer type", ErrorCodes::NO_COMMON_TYPE); } } } /// All other data types (UUID, AggregateFunction, Enum...) are compatible only if they are the same (checked in trivial cases). throw Exception(getExceptionMessagePrefix(types), ErrorCodes::NO_COMMON_TYPE); } }