Fix conversion between Date and DateTime when inserting in VALUES format and "input_format_values_interpret_expressions" is true #3226

This commit is contained in:
Alexey Milovidov 2018-09-26 22:43:10 +03:00
parent b6e53d22e1
commit e90484db77
4 changed files with 47 additions and 30 deletions

View File

@ -411,6 +411,11 @@ struct WhichDataType
{
TypeIndex idx;
/// For late initialization.
WhichDataType()
: idx(TypeIndex::Nothing)
{}
WhichDataType(const IDataType & data_type)
: idx(data_type.getTypeId())
{}

View File

@ -21,6 +21,8 @@
#include <DataTypes/DataTypeUUID.h>
#include <DataTypes/DataTypeWithDictionary.h>
#include <common/DateLUT.h>
namespace DB
{
@ -138,63 +140,69 @@ UInt64 stringToDateTime(const String & s)
return UInt64(date_time);
}
Field convertFieldToTypeImpl(const Field & src, const IDataType & type)
Field convertFieldToTypeImpl(const Field & src, const IDataType & type, const IDataType * from_type_hint)
{
if (type.isValueRepresentedByNumber())
WhichDataType which_type(type);
WhichDataType which_from_type;
if (from_type_hint)
which_from_type = WhichDataType(*from_type_hint);
/// Conversion between Date and DateTime and vice versa.
if (which_type.isDate() && which_from_type.isDateTime())
{
if (typeid_cast<const DataTypeUInt8 *>(&type)) return convertNumericType<UInt8>(src, type);
if (typeid_cast<const DataTypeUInt16 *>(&type)) return convertNumericType<UInt16>(src, type);
if (typeid_cast<const DataTypeUInt32 *>(&type)) return convertNumericType<UInt32>(src, type);
if (typeid_cast<const DataTypeUInt64 *>(&type)) return convertNumericType<UInt64>(src, type);
if (typeid_cast<const DataTypeInt8 *>(&type)) return convertNumericType<Int8>(src, type);
if (typeid_cast<const DataTypeInt16 *>(&type)) return convertNumericType<Int16>(src, type);
if (typeid_cast<const DataTypeInt32 *>(&type)) return convertNumericType<Int32>(src, type);
if (typeid_cast<const DataTypeInt64 *>(&type)) return convertNumericType<Int64>(src, type);
if (typeid_cast<const DataTypeFloat32 *>(&type)) return convertNumericType<Float32>(src, type);
if (typeid_cast<const DataTypeFloat64 *>(&type)) return convertNumericType<Float64>(src, type);
return UInt64(static_cast<const DataTypeDateTime &>(*from_type_hint).getTimeZone().toDayNum(src.get<UInt64>()));
}
else if (which_type.isDateTime() && which_from_type.isDate())
{
return UInt64(static_cast<const DataTypeDateTime &>(type).getTimeZone().fromDayNum(DayNum(src.get<UInt64>())));
}
else if (type.isValueRepresentedByNumber())
{
if (which_type.isUInt8()) return convertNumericType<UInt8>(src, type);
if (which_type.isUInt16()) return convertNumericType<UInt16>(src, type);
if (which_type.isUInt32()) return convertNumericType<UInt32>(src, type);
if (which_type.isUInt64()) return convertNumericType<UInt64>(src, type);
if (which_type.isInt8()) return convertNumericType<Int8>(src, type);
if (which_type.isInt16()) return convertNumericType<Int16>(src, type);
if (which_type.isInt32()) return convertNumericType<Int32>(src, type);
if (which_type.isInt64()) return convertNumericType<Int64>(src, type);
if (which_type.isFloat32()) return convertNumericType<Float32>(src, type);
if (which_type.isFloat64()) return convertNumericType<Float64>(src, type);
if (auto * ptype = typeid_cast<const DataTypeDecimal<Decimal32> *>(&type)) return convertDecimalType(src, *ptype);
if (auto * ptype = typeid_cast<const DataTypeDecimal<Decimal64> *>(&type)) return convertDecimalType(src, *ptype);
if (auto * ptype = typeid_cast<const DataTypeDecimal<Decimal128> *>(&type)) return convertDecimalType(src, *ptype);
const bool is_date = typeid_cast<const DataTypeDate *>(&type);
bool is_datetime = false;
bool is_enum = false;
bool is_uuid = false;
if (!is_date)
if (!(is_datetime = typeid_cast<const DataTypeDateTime *>(&type)))
if (!(is_uuid = typeid_cast<const DataTypeUUID *>(&type)))
if (!(is_enum = dynamic_cast<const IDataTypeEnum *>(&type)))
throw Exception{"Logical error: unknown numeric type " + type.getName(), ErrorCodes::LOGICAL_ERROR};
if (!which_type.isDateOrDateTime() && !which_type.isUUID() && !which_type.isEnum())
throw Exception{"Logical error: unknown numeric type " + type.getName(), ErrorCodes::LOGICAL_ERROR};
/// Numeric values for Enums should not be used directly in IN section
if (src.getType() == Field::Types::UInt64 && !is_enum)
if (src.getType() == Field::Types::UInt64 && !which_type.isEnum())
return src;
if (src.getType() == Field::Types::String)
{
if (is_date)
if (which_type.isDate())
{
/// Convert 'YYYY-MM-DD' Strings to Date
return UInt64(stringToDate(src.get<const String &>()));
}
else if (is_datetime)
else if (which_type.isDateTime())
{
/// Convert 'YYYY-MM-DD hh:mm:ss' Strings to DateTime
return stringToDateTime(src.get<const String &>());
}
else if (is_uuid)
else if (which_type.isUUID())
{
return stringToUUID(src.get<const String &>());
}
else if (is_enum)
else if (which_type.isEnum())
{
/// Convert String to Enum's value
return dynamic_cast<const IDataTypeEnum &>(type).castToValue(src);
}
}
}
else if (isStringOrFixedString(type))
else if (which_type.isStringOrFixedString())
{
if (src.getType() == Field::Types::String)
return src;
@ -252,9 +260,9 @@ Field convertFieldToType(const Field & from_value, const IDataType & to_type, co
if (auto * with_dict_type = typeid_cast<const DataTypeWithDictionary *>(&to_type))
return convertFieldToType(from_value, *with_dict_type->getDictionaryType(), from_type_hint);
else if (auto * nullable_type = typeid_cast<const DataTypeNullable *>(&to_type))
return convertFieldToTypeImpl(from_value, *nullable_type->getNestedType());
return convertFieldToTypeImpl(from_value, *nullable_type->getNestedType(), from_type_hint);
else
return convertFieldToTypeImpl(from_value, to_type);
return convertFieldToTypeImpl(from_value, to_type, from_type_hint);
}

View File

@ -0,0 +1 @@
2000-01-01 2000-01-01 00:00:00

View File

@ -0,0 +1,3 @@
CREATE TEMPORARY TABLE test (d Date, dt DateTime);
INSERT INTO test VALUES (toDateTime('2000-01-01 01:02:03'), toDate('2000-01-01'));
SELECT * FROM test;