Initial implementation of DateTime64 parsing functions;

This commit is contained in:
Vasily Nemkov 2019-10-12 10:03:38 +03:00
parent b6b080745b
commit 8648ebf75c
11 changed files with 141 additions and 152 deletions

View File

@ -35,14 +35,15 @@ static inline void readText(time_t & x, ReadBuffer & istr, const FormatSettings
} }
} }
static inline void readText(DateTime64 & x, UInt32 scale, ReadBuffer & istr, const FormatSettings & settings, const DateLUTImpl & time_zone, const DateLUTImpl & /*utc_time_zone*/) static inline void readText(DateTime64 & x, UInt32 scale, ReadBuffer & istr, const FormatSettings & settings, const DateLUTImpl & time_zone, const DateLUTImpl & utc_time_zone)
{ {
switch (settings.date_time_input_format) switch (settings.date_time_input_format)
{ {
case FormatSettings::DateTimeInputFormat::Basic: case FormatSettings::DateTimeInputFormat::Basic:
readDateTimeText(x, scale, istr, time_zone); readDateTime64Text(x, scale, istr, time_zone);
return; return;
default: case FormatSettings::DateTimeInputFormat::BestEffort:
parseDateTime64BestEffort(x, scale, istr, time_zone, utc_time_zone);
return; return;
} }
} }

View File

@ -108,5 +108,7 @@ public:
bool equals(const IDataType & rhs) const override; bool equals(const IDataType & rhs) const override;
}; };
template <> inline constexpr bool IsDataTypeDecimal<DataTypeDateTime64> = true;
} }

View File

@ -171,7 +171,6 @@ protected:
}; };
// TODO (vnemkov): enable only if both tx and ty are derived from DecimalBase and are essentially same type with different type-params.
template <typename T, typename U, template <typename> typename DecimalType> template <typename T, typename U, template <typename> typename DecimalType>
typename std::enable_if_t<(sizeof(T) >= sizeof(U)), DecimalType<T>> typename std::enable_if_t<(sizeof(T) >= sizeof(U)), DecimalType<T>>
decimalResultType(const DecimalType<T> & tx, const DecimalType<U> & ty, bool is_multiply, bool is_divide) decimalResultType(const DecimalType<T> & tx, const DecimalType<U> & ty, bool is_multiply, bool is_divide)
@ -209,128 +208,10 @@ const DecimalType<U> decimalResultType(const DataTypeNumber<T> &, const DecimalT
} }
////// TODO (vnemkov): make that work for DecimalBase-derived types
//template <typename T, template <typename> typename DecimalType>
//inline const DecimalType<T> * checkDecimal(const IDataType & data_type)
//{
// return typeid_cast<const DecimalType<T> *>(&data_type);
//}
//inline UInt32 getDecimalScale(const IDataType & data_type, UInt32 default_value = std::numeric_limits<UInt32>::max())
//{
// if (auto * decimal_type = checkDecimal<Decimal32>(data_type))
// return decimal_type->getScale();
// if (auto * decimal_type = checkDecimal<Decimal64>(data_type))
// return decimal_type->getScale();
// if (auto * decimal_type = checkDecimal<Decimal128>(data_type))
// return decimal_type->getScale();
// return default_value;
//}
/// ///
template <typename DataType> constexpr bool IsDataTypeDecimal = false; template <typename DataType> constexpr bool IsDataTypeDecimal = false;
template <typename DataType> constexpr bool IsDataTypeDecimalOrNumber = IsDataTypeDecimal<DataType> || IsDataTypeNumber<DataType>; template <typename DataType> constexpr bool IsDataTypeDecimalOrNumber = IsDataTypeDecimal<DataType> || IsDataTypeNumber<DataType>;
//template <typename FromDataType, typename ToDataType>
//inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
//convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to)
//{
// using FromFieldType = typename FromDataType::FieldType;
// using ToFieldType = typename ToDataType::FieldType;
// using MaxFieldType = std::conditional_t<(sizeof(FromFieldType) > sizeof(ToFieldType)), FromFieldType, ToFieldType>;
// using MaxNativeType = typename MaxFieldType::NativeType;
// MaxNativeType converted_value;
// if (scale_to > scale_from)
// {
// converted_value = DataTypeDecimal<MaxFieldType>::getScaleMultiplier(scale_to - scale_from);
// if (common::mulOverflow(static_cast<MaxNativeType>(value), converted_value, converted_value))
// throw Exception("Decimal convert overflow", ErrorCodes::DECIMAL_OVERFLOW);
// }
// else
// converted_value = value / DataTypeDecimal<MaxFieldType>::getScaleMultiplier(scale_from - scale_to);
// if constexpr (sizeof(FromFieldType) > sizeof(ToFieldType))
// {
// if (converted_value < std::numeric_limits<typename ToFieldType::NativeType>::min() ||
// converted_value > std::numeric_limits<typename ToFieldType::NativeType>::max())
// throw Exception("Decimal convert overflow", ErrorCodes::DECIMAL_OVERFLOW);
// }
// return converted_value;
//}
//template <typename FromDataType, typename ToDataType>
//inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeNumber<ToDataType>, typename ToDataType::FieldType>
//convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
//{
// using FromFieldType = typename FromDataType::FieldType;
// using ToFieldType = typename ToDataType::FieldType;
// if constexpr (std::is_floating_point_v<ToFieldType>)
// return static_cast<ToFieldType>(value) / FromDataType::getScaleMultiplier(scale);
// else
// {
// FromFieldType converted_value = convertDecimals<FromDataType, FromDataType>(value, scale, 0);
// if constexpr (sizeof(FromFieldType) > sizeof(ToFieldType) || !std::numeric_limits<ToFieldType>::is_signed)
// {
// if constexpr (std::numeric_limits<ToFieldType>::is_signed)
// {
// if (converted_value < std::numeric_limits<ToFieldType>::min() ||
// converted_value > std::numeric_limits<ToFieldType>::max())
// throw Exception("Decimal convert overflow", ErrorCodes::DECIMAL_OVERFLOW);
// }
// else
// {
// using CastIntType = std::conditional_t<std::is_same_v<ToFieldType, UInt64>, Int128, Int64>;
// if (converted_value < 0 ||
// converted_value > static_cast<CastIntType>(std::numeric_limits<ToFieldType>::max()))
// throw Exception("Decimal convert overflow", ErrorCodes::DECIMAL_OVERFLOW);
// }
// }
// return converted_value;
// }
//}
//template <typename FromDataType, typename ToDataType>
//inline std::enable_if_t<IsDataTypeNumber<FromDataType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
//convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
//{
// using FromFieldType = typename FromDataType::FieldType;
// using ToNativeType = typename ToDataType::FieldType::NativeType;
// if constexpr (std::is_floating_point_v<FromFieldType>)
// {
// if (!std::isfinite(value))
// throw Exception("Decimal convert overflow. Cannot convert infinity or NaN to decimal", ErrorCodes::DECIMAL_OVERFLOW);
// auto out = value * ToDataType::getScaleMultiplier(scale);
// if constexpr (std::is_same_v<ToNativeType, Int128>)
// {
// static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64;
// static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll;
// if (out <= static_cast<ToNativeType>(min_int128) || out >= static_cast<ToNativeType>(max_int128))
// throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW);
// }
// else
// {
// if (out <= std::numeric_limits<ToNativeType>::min() || out >= std::numeric_limits<ToNativeType>::max())
// throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW);
// }
// return out;
// }
// else
// {
// if constexpr (std::is_same_v<FromFieldType, UInt64>)
// if (value > static_cast<UInt64>(std::numeric_limits<Int64>::max()))
// return convertDecimals<DataTypeDecimal<Decimal128>, ToDataType>(value, 0, scale);
// return convertDecimals<DataTypeDecimal<Decimal64>, ToDataType>(value, 0, scale);
// }
//}
template <template <typename> typename DecimalType> template <template <typename> typename DecimalType>
DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value) DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value)
{ {
@ -352,5 +233,4 @@ extern template class DataTypeDecimalBase<Decimal64>;
extern template class DataTypeDecimalBase<Decimal128>; extern template class DataTypeDecimalBase<Decimal128>;
extern template class DataTypeDecimalBase<DateTime64>; extern template class DataTypeDecimalBase<DateTime64>;
} }

View File

@ -616,7 +616,7 @@ public:
if (!readTempString()) if (!readTempString())
return false; return false;
ReadBufferFromString buf(temp_string); ReadBufferFromString buf(temp_string);
readDateTimeText(date_time, scale, buf); readDateTime64Text(date_time, scale, buf);
return true; return true;
} }

View File

@ -46,6 +46,7 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToDate>(); factory.registerFunction<FunctionToDate>();
factory.registerFunction<FunctionToDateTime>(); factory.registerFunction<FunctionToDateTime>();
factory.registerFunction<FunctionToDateTime64>();
factory.registerFunction<FunctionToUUID>(); factory.registerFunction<FunctionToUUID>();
factory.registerFunction<FunctionToString>(); factory.registerFunction<FunctionToString>();
factory.registerFunction<FunctionToFixedString>(); factory.registerFunction<FunctionToFixedString>();
@ -65,6 +66,7 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToFloat64OrZero>(); factory.registerFunction<FunctionToFloat64OrZero>();
factory.registerFunction<FunctionToDateOrZero>(); factory.registerFunction<FunctionToDateOrZero>();
factory.registerFunction<FunctionToDateTimeOrZero>(); factory.registerFunction<FunctionToDateTimeOrZero>();
factory.registerFunction<FunctionToDateTime64OrZero>();
factory.registerFunction<FunctionToDecimal32OrZero>(); factory.registerFunction<FunctionToDecimal32OrZero>();
factory.registerFunction<FunctionToDecimal64OrZero>(); factory.registerFunction<FunctionToDecimal64OrZero>();
@ -82,6 +84,7 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToFloat64OrNull>(); factory.registerFunction<FunctionToFloat64OrNull>();
factory.registerFunction<FunctionToDateOrNull>(); factory.registerFunction<FunctionToDateOrNull>();
factory.registerFunction<FunctionToDateTimeOrNull>(); factory.registerFunction<FunctionToDateTimeOrNull>();
factory.registerFunction<FunctionToDateTime64OrNull>();
factory.registerFunction<FunctionToDecimal32OrNull>(); factory.registerFunction<FunctionToDecimal32OrNull>();
factory.registerFunction<FunctionToDecimal64OrNull>(); factory.registerFunction<FunctionToDecimal64OrNull>();
@ -90,6 +93,9 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionParseDateTimeBestEffort>(); factory.registerFunction<FunctionParseDateTimeBestEffort>();
factory.registerFunction<FunctionParseDateTimeBestEffortOrZero>(); factory.registerFunction<FunctionParseDateTimeBestEffortOrZero>();
factory.registerFunction<FunctionParseDateTimeBestEffortOrNull>(); factory.registerFunction<FunctionParseDateTimeBestEffortOrNull>();
factory.registerFunction<FunctionParseDateTime64BestEffort>();
factory.registerFunction<FunctionParseDateTime64BestEffortOrZero>();
factory.registerFunction<FunctionParseDateTime64BestEffortOrNull>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalSecond, PositiveMonotonicity>>(); factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalSecond, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalMinute, PositiveMonotonicity>>(); factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalMinute, PositiveMonotonicity>>();

View File

@ -498,7 +498,7 @@ struct ConvertThroughParsing
const DateLUTImpl * utc_time_zone [[maybe_unused]] = nullptr; const DateLUTImpl * utc_time_zone [[maybe_unused]] = nullptr;
/// For conversion to DateTime type, second argument with time zone could be specified. /// For conversion to DateTime type, second argument with time zone could be specified.
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>) if constexpr (std::is_same_v<ToDataType, DataTypeDateTime> || std::is_same_v<ToDataType, DataTypeDateTime64>)
{ {
local_time_zone = &extractTimeZoneFromFunctionArguments(block, arguments, 1, 0); local_time_zone = &extractTimeZoneFromFunctionArguments(block, arguments, 1, 0);
@ -523,10 +523,17 @@ struct ConvertThroughParsing
size_t size = input_rows_count; size_t size = input_rows_count;
typename ColVecTo::MutablePtr col_to = nullptr; typename ColVecTo::MutablePtr col_to = nullptr;
if constexpr (IsDataTypeDecimal<ToDataType>) if constexpr (IsDataTypeDecimal<ToDataType> || std::is_same_v<ToDataType, DataTypeDateTime64>)
{ {
UInt32 scale = additions; UInt32 scale = additions;
ToDataType check_bounds_in_ctor(ToDataType::maxPrecision(), scale); if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
{
ToDataType check_bounds_in_ctor(scale, local_time_zone ? local_time_zone->getTimeZone() : String{});
}
else
{
ToDataType check_bounds_in_ctor(ToDataType::maxPrecision(), scale);
}
col_to = ColVecTo::create(size, scale); col_to = ColVecTo::create(size, scale);
} }
else else
@ -570,13 +577,26 @@ struct ConvertThroughParsing
{ {
if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffort) if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffort)
{ {
time_t res; if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
parseDateTimeBestEffort(res, read_buffer, *local_time_zone, *utc_time_zone); {
vec_to[i] = res; DateTime64 res;
parseDateTime64BestEffort(res, vec_to.getScale(), read_buffer, *local_time_zone, *utc_time_zone);
vec_to[i] = res;
}
else
{
time_t res;
parseDateTimeBestEffort(res, read_buffer, *local_time_zone, *utc_time_zone);
vec_to[i] = res;
}
} }
else else
{ {
if constexpr (IsDataTypeDecimal<ToDataType>) if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
{
readDateTimeText(vec_to[i], vec_to.getScale(), read_buffer, local_time_zone);
}
else if constexpr (IsDataTypeDecimal<ToDataType>)
ToDataType::readText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale()); ToDataType::readText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale());
else else
parseImpl<ToDataType>(vec_to[i], read_buffer, local_time_zone); parseImpl<ToDataType>(vec_to[i], read_buffer, local_time_zone);
@ -591,13 +611,28 @@ struct ConvertThroughParsing
if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffort) if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffort)
{ {
time_t res; if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
parsed = tryParseDateTimeBestEffort(res, read_buffer, *local_time_zone, *utc_time_zone); {
vec_to[i] = res; DateTime64 res;
parsed = tryParseDateTime64BestEffort(res, vec_to.getScale(), read_buffer, *local_time_zone, *utc_time_zone);
vec_to[i] = res;
}
else
{
time_t res;
parsed = tryParseDateTimeBestEffort(res, read_buffer, *local_time_zone, *utc_time_zone);
vec_to[i] = res;
}
} }
else else
{ {
if constexpr (IsDataTypeDecimal<ToDataType>) if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
{
DateTime64 value;
parsed = tryReadDateTime64Text(value, vec_to.getScale(), read_buffer, *local_time_zone);
vec_to[i] = value;
}
else if constexpr (IsDataTypeDecimal<ToDataType>)
parsed = ToDataType::tryReadText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale()); parsed = ToDataType::tryReadText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale());
else else
parsed = tryParseImpl<ToDataType>(vec_to[i], read_buffer, local_time_zone); parsed = tryParseImpl<ToDataType>(vec_to[i], read_buffer, local_time_zone);
@ -746,6 +781,7 @@ struct ConvertImpl<DataTypeFixedString, DataTypeString, Name>
/// Declared early because used below. /// Declared early because used below.
struct NameToDate { static constexpr auto name = "toDate"; }; struct NameToDate { static constexpr auto name = "toDate"; };
struct NameToDateTime { static constexpr auto name = "toDateTime"; }; struct NameToDateTime { static constexpr auto name = "toDateTime"; };
struct NameToDateTime64 { static constexpr auto name = "toDateTime64"; };
struct NameToString { static constexpr auto name = "toString"; }; struct NameToString { static constexpr auto name = "toString"; };
struct NameToDecimal32 { static constexpr auto name = "toDecimal32"; }; struct NameToDecimal32 { static constexpr auto name = "toDecimal32"; };
struct NameToDecimal64 { static constexpr auto name = "toDecimal64"; }; struct NameToDecimal64 { static constexpr auto name = "toDecimal64"; };
@ -936,9 +972,18 @@ private:
if constexpr (IsDataTypeDecimal<RightDataType>) if constexpr (IsDataTypeDecimal<RightDataType>)
{ {
if (arguments.size() != 2) if constexpr (std::is_same_v<RightDataType, DataTypeDateTime64>)
{
// account for optional timezone argument
if (arguments.size() != 2 && arguments.size() != 3)
throw Exception{"Function " + getName() + " expects 2 or 3 arguments for DataTypeDateTime64.",
ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION};
}
else if (arguments.size() != 2)
{
throw Exception{"Function " + getName() + " expects 2 arguments for Decimal.", throw Exception{"Function " + getName() + " expects 2 arguments for Decimal.",
ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION}; ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION};
}
const ColumnWithTypeAndName & scale_column = block.getByPosition(arguments[1]); const ColumnWithTypeAndName & scale_column = block.getByPosition(arguments[1]);
UInt32 scale = extractToDecimalScale(scale_column); UInt32 scale = extractToDecimalScale(scale_column);
@ -985,7 +1030,8 @@ public:
static constexpr bool to_decimal = static constexpr bool to_decimal =
std::is_same_v<ToDataType, DataTypeDecimal<Decimal32>> || std::is_same_v<ToDataType, DataTypeDecimal<Decimal32>> ||
std::is_same_v<ToDataType, DataTypeDecimal<Decimal64>> || std::is_same_v<ToDataType, DataTypeDecimal<Decimal64>> ||
std::is_same_v<ToDataType, DataTypeDecimal<Decimal128>>; std::is_same_v<ToDataType, DataTypeDecimal<Decimal128>> ||
std::is_same_v<ToDataType, DataTypeDateTime64>;
static FunctionPtr create(const Context &) { return std::make_shared<FunctionConvertFromString>(); } static FunctionPtr create(const Context &) { return std::make_shared<FunctionConvertFromString>(); }
@ -1409,8 +1455,7 @@ using FunctionToFloat32 = FunctionConvert<DataTypeFloat32, NameToFloat32, ToNumb
using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, ToNumberMonotonicity<Float64>>; using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, ToNumberMonotonicity<Float64>>;
using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToNumberMonotonicity<UInt16>>; using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToNumberMonotonicity<UInt16>>;
using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToNumberMonotonicity<UInt32>>; using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToNumberMonotonicity<UInt32>>;
// TODO (vnemkov): enable and test toDateTime64 function using FunctionToDateTime64 = FunctionConvert<DataTypeDateTime, NameToDateTime64, UnknownMonotonicity>;
//using FunctionToDateTime64 = FunctionConvert<DataTypeDateTime, NameToDateTime, UnknownMonotonicity>;
using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToNumberMonotonicity<UInt128>>; using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToNumberMonotonicity<UInt128>>;
using FunctionToString = FunctionConvert<DataTypeString, NameToString, ToStringMonotonicity>; using FunctionToString = FunctionConvert<DataTypeString, NameToString, ToStringMonotonicity>;
using FunctionToUnixTimestamp = FunctionConvert<DataTypeUInt32, NameToUnixTimestamp, ToNumberMonotonicity<UInt32>>; using FunctionToUnixTimestamp = FunctionConvert<DataTypeUInt32, NameToUnixTimestamp, ToNumberMonotonicity<UInt32>>;
@ -1433,6 +1478,7 @@ template <> struct FunctionTo<DataTypeFloat32> { using Type = FunctionToFloat32;
template <> struct FunctionTo<DataTypeFloat64> { using Type = FunctionToFloat64; }; template <> struct FunctionTo<DataTypeFloat64> { using Type = FunctionToFloat64; };
template <> struct FunctionTo<DataTypeDate> { using Type = FunctionToDate; }; template <> struct FunctionTo<DataTypeDate> { using Type = FunctionToDate; };
template <> struct FunctionTo<DataTypeDateTime> { using Type = FunctionToDateTime; }; template <> struct FunctionTo<DataTypeDateTime> { using Type = FunctionToDateTime; };
template <> struct FunctionTo<DataTypeDateTime64> { using Type = FunctionToDateTime64; };
template <> struct FunctionTo<DataTypeUUID> { using Type = FunctionToUUID; }; template <> struct FunctionTo<DataTypeUUID> { using Type = FunctionToUUID; };
template <> struct FunctionTo<DataTypeString> { using Type = FunctionToString; }; template <> struct FunctionTo<DataTypeString> { using Type = FunctionToString; };
template <> struct FunctionTo<DataTypeFixedString> { using Type = FunctionToFixedString; }; template <> struct FunctionTo<DataTypeFixedString> { using Type = FunctionToFixedString; };
@ -1457,6 +1503,7 @@ struct NameToFloat32OrZero { static constexpr auto name = "toFloat32OrZero"; };
struct NameToFloat64OrZero { static constexpr auto name = "toFloat64OrZero"; }; struct NameToFloat64OrZero { static constexpr auto name = "toFloat64OrZero"; };
struct NameToDateOrZero { static constexpr auto name = "toDateOrZero"; }; struct NameToDateOrZero { static constexpr auto name = "toDateOrZero"; };
struct NameToDateTimeOrZero { static constexpr auto name = "toDateTimeOrZero"; }; struct NameToDateTimeOrZero { static constexpr auto name = "toDateTimeOrZero"; };
struct NameToDateTime64OrZero { static constexpr auto name = "toDateTime64OrZero"; };
struct NameToDecimal32OrZero { static constexpr auto name = "toDecimal32OrZero"; }; struct NameToDecimal32OrZero { static constexpr auto name = "toDecimal32OrZero"; };
struct NameToDecimal64OrZero { static constexpr auto name = "toDecimal64OrZero"; }; struct NameToDecimal64OrZero { static constexpr auto name = "toDecimal64OrZero"; };
struct NameToDecimal128OrZero { static constexpr auto name = "toDecimal128OrZero"; }; struct NameToDecimal128OrZero { static constexpr auto name = "toDecimal128OrZero"; };
@ -1473,6 +1520,7 @@ using FunctionToFloat32OrZero = FunctionConvertFromString<DataTypeFloat32, NameT
using FunctionToFloat64OrZero = FunctionConvertFromString<DataTypeFloat64, NameToFloat64OrZero, ConvertFromStringExceptionMode::Zero>; using FunctionToFloat64OrZero = FunctionConvertFromString<DataTypeFloat64, NameToFloat64OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDateOrZero = FunctionConvertFromString<DataTypeDate, NameToDateOrZero, ConvertFromStringExceptionMode::Zero>; using FunctionToDateOrZero = FunctionConvertFromString<DataTypeDate, NameToDateOrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDateTimeOrZero = FunctionConvertFromString<DataTypeDateTime, NameToDateTimeOrZero, ConvertFromStringExceptionMode::Zero>; using FunctionToDateTimeOrZero = FunctionConvertFromString<DataTypeDateTime, NameToDateTimeOrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDateTime64OrZero = FunctionConvertFromString<DataTypeDateTime64, NameToDateTime64OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDecimal32OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal32>, NameToDecimal32OrZero, ConvertFromStringExceptionMode::Zero>; using FunctionToDecimal32OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal32>, NameToDecimal32OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDecimal64OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrZero, ConvertFromStringExceptionMode::Zero>; using FunctionToDecimal64OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDecimal128OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrZero, ConvertFromStringExceptionMode::Zero>; using FunctionToDecimal128OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrZero, ConvertFromStringExceptionMode::Zero>;
@ -1489,6 +1537,7 @@ struct NameToFloat32OrNull { static constexpr auto name = "toFloat32OrNull"; };
struct NameToFloat64OrNull { static constexpr auto name = "toFloat64OrNull"; }; struct NameToFloat64OrNull { static constexpr auto name = "toFloat64OrNull"; };
struct NameToDateOrNull { static constexpr auto name = "toDateOrNull"; }; struct NameToDateOrNull { static constexpr auto name = "toDateOrNull"; };
struct NameToDateTimeOrNull { static constexpr auto name = "toDateTimeOrNull"; }; struct NameToDateTimeOrNull { static constexpr auto name = "toDateTimeOrNull"; };
struct NameToDateTime64OrNull { static constexpr auto name = "toDateTime64OrNull"; };
struct NameToDecimal32OrNull { static constexpr auto name = "toDecimal32OrNull"; }; struct NameToDecimal32OrNull { static constexpr auto name = "toDecimal32OrNull"; };
struct NameToDecimal64OrNull { static constexpr auto name = "toDecimal64OrNull"; }; struct NameToDecimal64OrNull { static constexpr auto name = "toDecimal64OrNull"; };
struct NameToDecimal128OrNull { static constexpr auto name = "toDecimal128OrNull"; }; struct NameToDecimal128OrNull { static constexpr auto name = "toDecimal128OrNull"; };
@ -1505,6 +1554,7 @@ using FunctionToFloat32OrNull = FunctionConvertFromString<DataTypeFloat32, NameT
using FunctionToFloat64OrNull = FunctionConvertFromString<DataTypeFloat64, NameToFloat64OrNull, ConvertFromStringExceptionMode::Null>; using FunctionToFloat64OrNull = FunctionConvertFromString<DataTypeFloat64, NameToFloat64OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDateOrNull = FunctionConvertFromString<DataTypeDate, NameToDateOrNull, ConvertFromStringExceptionMode::Null>; using FunctionToDateOrNull = FunctionConvertFromString<DataTypeDate, NameToDateOrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDateTimeOrNull = FunctionConvertFromString<DataTypeDateTime, NameToDateTimeOrNull, ConvertFromStringExceptionMode::Null>; using FunctionToDateTimeOrNull = FunctionConvertFromString<DataTypeDateTime, NameToDateTimeOrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDateTime64OrNull = FunctionConvertFromString<DataTypeDateTime64, NameToDateTime64OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDecimal32OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal32>, NameToDecimal32OrNull, ConvertFromStringExceptionMode::Null>; using FunctionToDecimal32OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal32>, NameToDecimal32OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDecimal64OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrNull, ConvertFromStringExceptionMode::Null>; using FunctionToDecimal64OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDecimal128OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrNull, ConvertFromStringExceptionMode::Null>; using FunctionToDecimal128OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrNull, ConvertFromStringExceptionMode::Null>;
@ -1512,6 +1562,10 @@ using FunctionToDecimal128OrNull = FunctionConvertFromString<DataTypeDecimal<Dec
struct NameParseDateTimeBestEffort { static constexpr auto name = "parseDateTimeBestEffort"; }; struct NameParseDateTimeBestEffort { static constexpr auto name = "parseDateTimeBestEffort"; };
struct NameParseDateTimeBestEffortOrZero { static constexpr auto name = "parseDateTimeBestEffortOrZero"; }; struct NameParseDateTimeBestEffortOrZero { static constexpr auto name = "parseDateTimeBestEffortOrZero"; };
struct NameParseDateTimeBestEffortOrNull { static constexpr auto name = "parseDateTimeBestEffortOrNull"; }; struct NameParseDateTimeBestEffortOrNull { static constexpr auto name = "parseDateTimeBestEffortOrNull"; };
struct NameParseDateTime64BestEffort { static constexpr auto name = "parseDateTime64BestEffort"; };
struct NameParseDateTime64BestEffortOrZero { static constexpr auto name = "parseDateTime64BestEffortOrZero"; };
struct NameParseDateTime64BestEffortOrNull { static constexpr auto name = "parseDateTime64BestEffortOrNull"; };
using FunctionParseDateTimeBestEffort = FunctionConvertFromString< using FunctionParseDateTimeBestEffort = FunctionConvertFromString<
DataTypeDateTime, NameParseDateTimeBestEffort, ConvertFromStringExceptionMode::Throw, ConvertFromStringParsingMode::BestEffort>; DataTypeDateTime, NameParseDateTimeBestEffort, ConvertFromStringExceptionMode::Throw, ConvertFromStringParsingMode::BestEffort>;
@ -1520,6 +1574,12 @@ using FunctionParseDateTimeBestEffortOrZero = FunctionConvertFromString<
using FunctionParseDateTimeBestEffortOrNull = FunctionConvertFromString< using FunctionParseDateTimeBestEffortOrNull = FunctionConvertFromString<
DataTypeDateTime, NameParseDateTimeBestEffortOrNull, ConvertFromStringExceptionMode::Null, ConvertFromStringParsingMode::BestEffort>; DataTypeDateTime, NameParseDateTimeBestEffortOrNull, ConvertFromStringExceptionMode::Null, ConvertFromStringParsingMode::BestEffort>;
using FunctionParseDateTime64BestEffort = FunctionConvertFromString<
DataTypeDateTime64, NameParseDateTime64BestEffort, ConvertFromStringExceptionMode::Throw, ConvertFromStringParsingMode::BestEffort>;
using FunctionParseDateTime64BestEffortOrZero = FunctionConvertFromString<
DataTypeDateTime64, NameParseDateTime64BestEffortOrZero, ConvertFromStringExceptionMode::Zero, ConvertFromStringParsingMode::BestEffort>;
using FunctionParseDateTime64BestEffortOrNull = FunctionConvertFromString<
DataTypeDateTime64, NameParseDateTime64BestEffortOrNull, ConvertFromStringExceptionMode::Null, ConvertFromStringParsingMode::BestEffort>;
class PreparedFunctionCast : public PreparedFunctionImpl class PreparedFunctionCast : public PreparedFunctionImpl
{ {

View File

@ -630,12 +630,8 @@ inline ReturnType readDateTimeTextImpl(time_t & datetime, ReadBuffer & buf, cons
return readDateTimeTextFallback<ReturnType>(datetime, buf, date_lut); return readDateTimeTextFallback<ReturnType>(datetime, buf, date_lut);
} }
inline void readDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance()) template <typename ReturnType>
{ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, ReadBuffer & buf, const DateLUTImpl & date_lut)
readDateTimeTextImpl<void>(datetime, buf, date_lut);
}
inline void readDateTimeText(DateTime64 & datetime64, UInt32 scale, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
{ {
DB::DecimalComponents<DateTime64::NativeType> c; DB::DecimalComponents<DateTime64::NativeType> c;
readDateTimeTextImpl<void>(c.whole, buf, date_lut); readDateTimeTextImpl<void>(c.whole, buf, date_lut);
@ -645,7 +641,7 @@ inline void readDateTimeText(DateTime64 & datetime64, UInt32 scale, ReadBuffer &
{ {
if (separator != '.') if (separator != '.')
{ {
throw Exception("Cannot parse DateTime64 from text.", ErrorCodes::CANNOT_PARSE_DATETIME); return ReturnType(false);
} }
} }
@ -655,6 +651,18 @@ inline void readDateTimeText(DateTime64 & datetime64, UInt32 scale, ReadBuffer &
c.fractional *= common::exp10_i64(scale - fractional_length); c.fractional *= common::exp10_i64(scale - fractional_length);
datetime64 = decimalFromComponents<DateTime64>(c, scale); datetime64 = decimalFromComponents<DateTime64>(c, scale);
return ReturnType(false);
}
inline void readDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
{
readDateTimeTextImpl<void>(datetime, buf, date_lut);
}
inline void readDateTime64Text(DateTime64 & datetime64, UInt32 scale, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
{
readDateTimeTextImpl<void>(datetime64, scale, buf, date_lut);
} }
inline bool tryReadDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance()) inline bool tryReadDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
@ -662,6 +670,11 @@ inline bool tryReadDateTimeText(time_t & datetime, ReadBuffer & buf, const DateL
return readDateTimeTextImpl<bool>(datetime, buf, date_lut); return readDateTimeTextImpl<bool>(datetime, buf, date_lut);
} }
inline bool tryReadDateTime64Text(DateTime64 & datetime64, UInt32 scale, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
{
return readDateTimeTextImpl<bool>(datetime64, scale, buf, date_lut);
}
inline void readDateTimeText(LocalDateTime & datetime, ReadBuffer & buf) inline void readDateTimeText(LocalDateTime & datetime, ReadBuffer & buf)
{ {
char s[19]; char s[19];

View File

@ -6,6 +6,7 @@
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <IO/parseDateTimeBestEffort.h> #include <IO/parseDateTimeBestEffort.h>
#include <limits>
namespace DB namespace DB
{ {
@ -66,7 +67,7 @@ inline void readDecimalNumber(T & res, const char * src)
template <typename ReturnType> template <typename ReturnType>
ReturnType parseDateTimeBestEffortImpl(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone) ReturnType parseDateTimeBestEffortImpl(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone, Int64 * fractional = nullptr)
{ {
auto on_error = [](const std::string & message [[maybe_unused]], int code [[maybe_unused]]) auto on_error = [](const std::string & message [[maybe_unused]], int code [[maybe_unused]])
{ {
@ -360,7 +361,12 @@ ReturnType parseDateTimeBestEffortImpl(time_t & res, ReadBuffer & in, const Date
++in.position(); ++in.position();
/// Just ignore fractional part of second. /// Just ignore fractional part of second.
readDigits(digits, sizeof(digits), in); num_digits = readDigits(digits, sizeof(digits), in);
if (fractional)
{
using FractionalType = typename std::decay<decltype(*fractional)>::type;
readDecimalNumber<std::numeric_limits<FractionalType>::digits10>(*fractional, digits);
}
} }
else if (c == '+' || c == '-') else if (c == '+' || c == '-')
{ {
@ -535,4 +541,24 @@ bool tryParseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl
return parseDateTimeBestEffortImpl<bool>(res, in, local_time_zone, utc_time_zone); return parseDateTimeBestEffortImpl<bool>(res, in, local_time_zone, utc_time_zone);
} }
void parseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
{
DateTime64::NativeType whole;
DateTime64::NativeType fractional;
parseDateTimeBestEffortImpl<void>(whole, in, local_time_zone, utc_time_zone, &fractional);
res = decimalFromComponents<DateTime64>(whole, fractional, scale);
}
bool tryParseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
{
DateTime64::NativeType whole;
DateTime64::NativeType fractional;
const auto result = parseDateTimeBestEffortImpl<bool>(whole, in, local_time_zone, utc_time_zone, &fractional);
res = decimalFromComponents<DateTime64>(whole, fractional, scale);
return result;
}
} }

View File

@ -1,6 +1,8 @@
#include <stddef.h> #include <stddef.h>
#include <time.h> #include <time.h>
#include <Core/Types.h>
class DateLUTImpl; class DateLUTImpl;
namespace DB namespace DB
@ -55,5 +57,7 @@ class ReadBuffer;
void parseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone); void parseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
bool tryParseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone); bool tryParseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
void parseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
bool tryParseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
} }

View File

@ -151,7 +151,7 @@ DateTime64::NativeType stringToDateTime64(const String & s, UInt32 scale)
ReadBufferFromString in(s); ReadBufferFromString in(s);
DateTime64 datetime64 {0}; DateTime64 datetime64 {0};
readDateTimeText(datetime64, scale, in); readDateTime64Text(datetime64, scale, in);
if (!in.eof()) if (!in.eof())
throw Exception("String is too long for DateTime64: " + s, ErrorCodes::TOO_LARGE_STRING_SIZE); throw Exception("String is too long for DateTime64: " + s, ErrorCodes::TOO_LARGE_STRING_SIZE);

View File

@ -30,7 +30,6 @@ toStartOfMinute({datetime})
toStartOfFiveMinute({datetime}) toStartOfFiveMinute({datetime})
toStartOfTenMinutes({datetime}) toStartOfTenMinutes({datetime})
toStartOfFifteenMinutes({datetime}) toStartOfFifteenMinutes({datetime})
# Do not work with DateTime64
toStartOfInterval({datetime}, INTERVAL 1 year) toStartOfInterval({datetime}, INTERVAL 1 year)
toStartOfInterval({datetime}, INTERVAL 1 month) toStartOfInterval({datetime}, INTERVAL 1 month)
toStartOfInterval({datetime}, INTERVAL 1 day) toStartOfInterval({datetime}, INTERVAL 1 day)
@ -52,7 +51,6 @@ timeSlot({datetime})
toYYYYMM({datetime}) toYYYYMM({datetime})
toYYYYMMDD({datetime}) toYYYYMMDD({datetime})
toYYYYMMDDhhmmss({datetime}) toYYYYMMDDhhmmss({datetime})
# -- Illegal type DateTime64 of argument of function addYears
addYears({datetime}, 1) addYears({datetime}, 1)
addMonths({datetime}, 1) addMonths({datetime}, 1)
addWeeks({datetime}, 1) addWeeks({datetime}, 1)
@ -61,7 +59,6 @@ addHours({datetime}, 1)
addMinutes({datetime}, 1) addMinutes({datetime}, 1)
addSeconds({datetime}, 1) addSeconds({datetime}, 1)
addQuarters({datetime}, 1) addQuarters({datetime}, 1)
# -- Illegal type DateTime64 of argument of function subtractYears.
subtractYears({datetime}, 1) subtractYears({datetime}, 1)
subtractMonths({datetime}, 1) subtractMonths({datetime}, 1)
subtractWeeks({datetime}, 1) subtractWeeks({datetime}, 1)