#include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int TYPE_MISMATCH; } /** Проверка попадания Field from, имеющим тип From в диапазон значений типа To. * From и To - числовые типы. Могут быть типами с плавающей запятой. * From - это одно из UInt64, Int64, Float64, * тогда как To может быть также 8, 16, 32 битным. * * Если попадает в диапазон, то from конвертируется в Field ближайшего к To типа. * Если не попадает - возвращается Field(Null). */ template static Field convertNumericTypeImpl(const Field & from) { From value = from.get(); if (static_cast(value) != static_cast(To(value))) return {}; return Field(typename NearestFieldType::Type(value)); } template static Field convertNumericType(const Field & from, const IDataType & type) { if (from.getType() == Field::Types::UInt64) return convertNumericTypeImpl(from); if (from.getType() == Field::Types::Int64) return convertNumericTypeImpl(from); if (from.getType() == Field::Types::Float64) return convertNumericTypeImpl(from); throw Exception("Type mismatch in IN or VALUES section: " + type.getName() + " expected, " + Field::Types::toString(from.getType()) + " got", ErrorCodes::TYPE_MISMATCH); } Field convertFieldToType(const Field & src, const IDataType & type) { if (type.isNumeric()) { if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); if (typeid_cast(&type)) return convertNumericType(src, type); const bool is_date = typeid_cast(&type); bool is_datetime = false; bool is_enum8 = false; bool is_enum16 = false; if (!is_date) if (!(is_datetime = typeid_cast(&type))) if (!(is_enum8 = typeid_cast(&type))) if (!(is_enum16 = typeid_cast(&type))) throw Exception{ "Logical error: unknown numeric type " + type.getName(), ErrorCodes::LOGICAL_ERROR }; const auto is_enum = is_enum8 || is_enum16; /// Numeric values for Enums should not be used directly in IN section if (src.getType() == Field::Types::UInt64 && !is_enum) return src; if (src.getType() == Field::Types::String) { /// Возможность сравнивать даты и даты-с-временем со строкой. const String & str = src.get(); ReadBufferFromString in(str); if (is_date) { DayNum_t date{}; readDateText(date, in); if (!in.eof()) throw Exception("String is too long for Date: " + str); return Field(UInt64(date)); } else if (is_datetime) { time_t date_time{}; readDateTimeText(date_time, in); if (!in.eof()) throw Exception("String is too long for DateTime: " + str); return Field(UInt64(date_time)); } else if (is_enum8) return Field(UInt64(static_cast(type).getValue(str))); else if (is_enum16) return Field(UInt64(static_cast(type).getValue(str))); } throw Exception("Type mismatch in IN or VALUES section: " + type.getName() + " expected, " + Field::Types::toString(src.getType()) + " got", ErrorCodes::TYPE_MISMATCH); } else if (const DataTypeArray * type_array = typeid_cast(&type)) { if (src.getType() != Field::Types::Array) throw Exception("Type mismatch in IN or VALUES section: " + type.getName() + " expected, " + Field::Types::toString(src.getType()) + " got", ErrorCodes::TYPE_MISMATCH); const IDataType & nested_type = *type_array->getNestedType(); const Array & src_arr = src.get(); size_t src_arr_size = src_arr.size(); Array res(src_arr_size); for (size_t i = 0; i < src_arr_size; ++i) { res[i] = convertFieldToType(src_arr[i], nested_type); if (res[i].isNull()) return {}; } return res; } else { if (src.getType() == Field::Types::UInt64 || src.getType() == Field::Types::Int64 || src.getType() == Field::Types::Float64 || src.getType() == Field::Types::Null || src.getType() == Field::Types::Array || (src.getType() == Field::Types::String && !typeid_cast(&type) && !typeid_cast(&type))) throw Exception("Type mismatch in IN or VALUES section: " + type.getName() + " expected, " + Field::Types::toString(src.getType()) + " got", ErrorCodes::TYPE_MISMATCH); } return src; } }