mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
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:
parent
b6e53d22e1
commit
e90484db77
@ -411,6 +411,11 @@ struct WhichDataType
|
||||
{
|
||||
TypeIndex idx;
|
||||
|
||||
/// For late initialization.
|
||||
WhichDataType()
|
||||
: idx(TypeIndex::Nothing)
|
||||
{}
|
||||
|
||||
WhichDataType(const IDataType & data_type)
|
||||
: idx(data_type.getTypeId())
|
||||
{}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
2000-01-01 2000-01-01 00:00:00
|
@ -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;
|
Loading…
Reference in New Issue
Block a user