diff --git a/dbms/src/Core/callOnTypeIndex.h b/dbms/src/Core/callOnTypeIndex.h index 00e8a64c848..bc09e7fd1ac 100644 --- a/dbms/src/Core/callOnTypeIndex.h +++ b/dbms/src/Core/callOnTypeIndex.h @@ -3,7 +3,6 @@ #include #include -#include namespace DB { @@ -151,6 +150,8 @@ class DataTypeDate; class DataTypeString; class DataTypeFixedString; class DataTypeUUID; +class DataTypeDateTime; +class DataTypeDateTime64; template class DataTypeEnum; template class DataTypeNumber; template class DataTypeDecimal; diff --git a/dbms/src/DataTypes/DataTypeDateTime.cpp b/dbms/src/DataTypes/DataTypeDateTime.cpp index 985a044340a..07fbe46c52e 100644 --- a/dbms/src/DataTypes/DataTypeDateTime.cpp +++ b/dbms/src/DataTypes/DataTypeDateTime.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include namespace { @@ -34,49 +34,23 @@ static inline void readText(time_t & x, ReadBuffer & istr, const FormatSettings return; } } - -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) - { - case FormatSettings::DateTimeInputFormat::Basic: - readDateTime64Text(x, scale, istr, time_zone); - return; - case FormatSettings::DateTimeInputFormat::BestEffort: - parseDateTime64BestEffort(x, scale, istr, time_zone, utc_time_zone); - return; - } -} } namespace DB { -template -bool protobufReadDateTime(ProtobufReader & protobuf, T & date_time) -{ - return protobuf.readDateTime(date_time); -} - -template <> -bool protobufReadDateTime(ProtobufReader & protobuf, DateTime64 & date_time) -{ - // TODO (vnemkov): protobuf.readDecimal ? - return protobuf.readDateTime(date_time.value); -} - -TimezoneMixin::TimezoneMixin(const std::string & time_zone_name) +TimezoneMixin::TimezoneMixin(const String & time_zone_name) : has_explicit_time_zone(!time_zone_name.empty()), time_zone(DateLUT::instance(time_zone_name)), utc_time_zone(DateLUT::instance("UTC")) {} -DataTypeDateTime::DataTypeDateTime(const std::string & time_zone_name) +DataTypeDateTime::DataTypeDateTime(const String & time_zone_name) : TimezoneMixin(time_zone_name) { } -std::string DataTypeDateTime::doGetName() const +String DataTypeDateTime::doGetName() const { if (!has_explicit_time_zone) return "DateTime"; @@ -210,149 +184,6 @@ bool DataTypeDateTime::equals(const IDataType & rhs) const return typeid(rhs) == typeid(*this); } -DataTypeDateTime64::DataTypeDateTime64(UInt32 scale_, const std::string & time_zone_name) - : DataTypeDecimalBase(maxDecimalPrecision() - scale_, scale_), - TimezoneMixin(time_zone_name) -{ -} - -std::string DataTypeDateTime64::doGetName() const -{ - if (!has_explicit_time_zone) - return std::string(getFamilyName()) + "(" + std::to_string(this->scale) + ")"; - - WriteBufferFromOwnString out; - out << "DateTime64(" << this->scale << ", " << quote << time_zone.getTimeZone() << ")"; - return out.str(); -} - -void DataTypeDateTime64::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & /*settings*/) const -{ - writeDateTimeText(assert_cast(column).getData()[row_num], scale, ostr, time_zone); -} - -void DataTypeDateTime64::deserializeText(IColumn & /*column*/, ReadBuffer & /*istr*/, const FormatSettings &) const -{} - -void DataTypeDateTime64::deserializeWholeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const -{ - deserializeTextEscaped(column, istr, settings); -} - -void DataTypeDateTime64::serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const -{ - serializeText(column, row_num, ostr, settings); -} - -void DataTypeDateTime64::deserializeTextEscaped(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const -{ - DateTime64 x; - ::readText(x, scale, istr, settings, time_zone, utc_time_zone); - assert_cast(column).getData().push_back(x); -} - -void DataTypeDateTime64::serializeTextQuoted(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const -{ - writeChar('\'', ostr); - serializeText(column, row_num, ostr, settings); - writeChar('\'', ostr); -} - -void DataTypeDateTime64::deserializeTextQuoted(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const -{ - DateTime64 x; - if (checkChar('\'', istr)) /// Cases: '2017-08-31 18:36:48' or '1504193808' - { - ::readText(x, scale, istr, settings, time_zone, utc_time_zone); - assertChar('\'', istr); - } - else /// Just 1504193808 or 01504193808 - { - readIntText(x, istr); - } - assert_cast(column).getData().push_back(x); /// It's important to do this at the end - for exception safety. -} - -void DataTypeDateTime64::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const -{ - writeChar('"', ostr); - serializeText(column, row_num, ostr, settings); - writeChar('"', ostr); -} - -void DataTypeDateTime64::deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const -{ - DateTime64 x; - if (checkChar('"', istr)) - { - ::readText(x, scale, istr, settings, time_zone, utc_time_zone); - assertChar('"', istr); - } - else - { - readIntText(x, istr); - } - assert_cast(column).getData().push_back(x); -} - -void DataTypeDateTime64::serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const -{ - writeChar('"', ostr); - serializeText(column, row_num, ostr, settings); - writeChar('"', ostr); -} - -void DataTypeDateTime64::deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const -{ - DateTime64 x; - - if (istr.eof()) - throwReadAfterEOF(); - - char maybe_quote = *istr.position(); - - if (maybe_quote == '\'' || maybe_quote == '\"') - ++istr.position(); - - ::readText(x, scale, istr, settings, time_zone, utc_time_zone); - - if (maybe_quote == '\'' || maybe_quote == '\"') - assertChar(maybe_quote, istr); - - assert_cast(column).getData().push_back(x); -} - -void DataTypeDateTime64::serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const -{ - if (value_index) - return; - value_index = static_cast(protobuf.writeDateTime64(assert_cast(column).getData()[row_num], scale)); -} - -void DataTypeDateTime64::deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const -{ - row_added = false; - DateTime64 t; - if (!protobuf.readDateTime64(t, scale)) - return; - - auto & container = assert_cast(column).getData(); - if (allow_add_row) - { - container.emplace_back(t); - row_added = true; - } - else - container.back() = t; -} - -bool DataTypeDateTime64::equals(const IDataType & rhs) const -{ - if (auto * ptype = typeid_cast(&rhs)) - return this->scale == ptype->getScale(); - return false; -} - namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; @@ -374,61 +205,9 @@ static DataTypePtr create(const ASTPtr & arguments) return std::make_shared(arg->value.get()); } -enum class ArgumentKind -{ - Optional, - Mandatory -}; - -template -std::conditional_t, T> -getArgument(const ASTPtr & arguments, size_t argument_index, const char * argument_name, const std::string context_data_type_name) -{ - using NearestResultType = NearestFieldType; - const auto fieldType = Field::TypeToEnum::value; - const ASTLiteral * argument = nullptr; - - auto exceptionMessage = [=](const String & message) - { - return std::string("Parameter #") + std::to_string(argument_index) + " '" - + argument_name + "' for " + context_data_type_name - + message - + ", expected: " + Field::Types::toString(fieldType) + " literal."; - }; - - if (!arguments || arguments->children.size() <= argument_index - || !(argument = arguments->children[argument_index]->as())) - { - if constexpr (Kind == ArgumentKind::Optional) - return {}; - else - throw Exception(exceptionMessage(" is missing"), - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - } - - if (argument->value.getType() != fieldType) - throw Exception(exceptionMessage(String(" has wrong type: ") + argument->value.getTypeName()), - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - - return argument->value.get(); -} - -static DataTypePtr create64(const ASTPtr & arguments) -{ - if (!arguments || arguments->size() == 0) - return std::make_shared(DataTypeDateTime64::default_scale); - - const auto scale = getArgument(arguments, 0, "scale", "DateType64"); - const auto timezone = getArgument(arguments, !!scale, "timezone", "DateType64"); - - return std::make_shared(scale.value_or(DataTypeDateTime64::default_scale), timezone.value_or(String{})); -} - void registerDataTypeDateTime(DataTypeFactory & factory) { factory.registerDataType("DateTime", create, DataTypeFactory::CaseInsensitive); - factory.registerDataType("DateTime64", create64, DataTypeFactory::CaseInsensitive); - factory.registerAlias("TIMESTAMP", "DateTime", DataTypeFactory::CaseInsensitive); } diff --git a/dbms/src/DataTypes/DataTypeDateTime.h b/dbms/src/DataTypes/DataTypeDateTime.h index 0ec045ae1c0..ab170bed340 100644 --- a/dbms/src/DataTypes/DataTypeDateTime.h +++ b/dbms/src/DataTypes/DataTypeDateTime.h @@ -2,23 +2,16 @@ #include #include -#include class DateLUTImpl; -//template class> -//struct is_instance : public std::false_type {}; - -//template class U> -//struct is_instance, U> : public std::true_type {}; - namespace DB { class TimezoneMixin { public: - explicit TimezoneMixin(const std::string & time_zone_name = ""); + explicit TimezoneMixin(const String & time_zone_name = ""); const DateLUTImpl & getTimeZone() const { return time_zone; } @@ -51,10 +44,10 @@ protected: class DataTypeDateTime final : public DataTypeNumberBase, public TimezoneMixin { public: - explicit DataTypeDateTime(const std::string & time_zone_name = ""); + explicit DataTypeDateTime(const String & time_zone_name = ""); const char * getFamilyName() const override { return "DateTime"; } - std::string doGetName() const override; + String doGetName() const override; TypeIndex getTypeId() const override { return TypeIndex::DateTime; } void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; @@ -76,39 +69,5 @@ public: bool equals(const IDataType & rhs) const override; }; -/** DateTime64 is same as DateTime, but it stores values as UInt64 and has configurable sub-second part. - * - * `scale` determines number of decimal places for sub-second part of the DateTime64. - */ -class DataTypeDateTime64 final : public DataTypeDecimalBase, public TimezoneMixin -{ -public: - static constexpr UInt8 default_scale = 3; - - explicit DataTypeDateTime64(UInt32 scale_, const std::string & time_zone_name = ""); - - const char * getFamilyName() const override { return "DateTime64"; } - std::string doGetName() const override; - TypeIndex getTypeId() const override { return TypeIndex::DateTime64; } - - void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; - void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; - void deserializeWholeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override; - void serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; - void deserializeTextEscaped(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; - void serializeTextQuoted(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; - void deserializeTextQuoted(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; - void serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; - void deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; - void serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; - void deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override; - void serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const override; - void deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const override; - - bool equals(const IDataType & rhs) const override; -}; - -template <> inline constexpr bool IsDataTypeDecimal = true; - } diff --git a/dbms/src/DataTypes/DataTypeDateTime64.cpp b/dbms/src/DataTypes/DataTypeDateTime64.cpp new file mode 100644 index 00000000000..e9e63b8cab2 --- /dev/null +++ b/dbms/src/DataTypes/DataTypeDateTime64.cpp @@ -0,0 +1,251 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ +using namespace DB; + +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) + { + case FormatSettings::DateTimeInputFormat::Basic: + readDateTime64Text(x, scale, istr, time_zone); + return; + case FormatSettings::DateTimeInputFormat::BestEffort: + parseDateTime64BestEffort(x, scale, istr, time_zone, utc_time_zone); + return; + } +} +} + +namespace DB +{ + +DataTypeDateTime64::DataTypeDateTime64(UInt32 scale_, const std::string & time_zone_name) + : DataTypeDecimalBase(maxDecimalPrecision() - scale_, scale_), + TimezoneMixin(time_zone_name) +{ +} + +std::string DataTypeDateTime64::doGetName() const +{ + if (!has_explicit_time_zone) + return std::string(getFamilyName()) + "(" + std::to_string(this->scale) + ")"; + + WriteBufferFromOwnString out; + out << "DateTime64(" << this->scale << ", " << quote << time_zone.getTimeZone() << ")"; + return out.str(); +} + +void DataTypeDateTime64::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & /*settings*/) const +{ + writeDateTimeText(assert_cast(column).getData()[row_num], scale, ostr, time_zone); +} + +void DataTypeDateTime64::deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings &) const +{ + DateTime64 result; + readDateTime64Text(result, this->getScale(), istr, time_zone); + assert_cast(column).getData().push_back(result); +} + +void DataTypeDateTime64::deserializeWholeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +{ + deserializeTextEscaped(column, istr, settings); +} + +void DataTypeDateTime64::serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const +{ + serializeText(column, row_num, ostr, settings); +} + +void DataTypeDateTime64::deserializeTextEscaped(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +{ + DateTime64 x; + ::readText(x, scale, istr, settings, time_zone, utc_time_zone); + assert_cast(column).getData().push_back(x); +} + +void DataTypeDateTime64::serializeTextQuoted(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const +{ + writeChar('\'', ostr); + serializeText(column, row_num, ostr, settings); + writeChar('\'', ostr); +} + +void DataTypeDateTime64::deserializeTextQuoted(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +{ + DateTime64 x; + if (checkChar('\'', istr)) /// Cases: '2017-08-31 18:36:48' or '1504193808' + { + ::readText(x, scale, istr, settings, time_zone, utc_time_zone); + assertChar('\'', istr); + } + else /// Just 1504193808 or 01504193808 + { + readIntText(x, istr); + } + assert_cast(column).getData().push_back(x); /// It's important to do this at the end - for exception safety. +} + +void DataTypeDateTime64::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const +{ + writeChar('"', ostr); + serializeText(column, row_num, ostr, settings); + writeChar('"', ostr); +} + +void DataTypeDateTime64::deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +{ + DateTime64 x; + if (checkChar('"', istr)) + { + ::readText(x, scale, istr, settings, time_zone, utc_time_zone); + assertChar('"', istr); + } + else + { + readIntText(x, istr); + } + assert_cast(column).getData().push_back(x); +} + +void DataTypeDateTime64::serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const +{ + writeChar('"', ostr); + serializeText(column, row_num, ostr, settings); + writeChar('"', ostr); +} + +void DataTypeDateTime64::deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const +{ + DateTime64 x; + + if (istr.eof()) + throwReadAfterEOF(); + + char maybe_quote = *istr.position(); + + if (maybe_quote == '\'' || maybe_quote == '\"') + ++istr.position(); + + ::readText(x, scale, istr, settings, time_zone, utc_time_zone); + + if (maybe_quote == '\'' || maybe_quote == '\"') + assertChar(maybe_quote, istr); + + assert_cast(column).getData().push_back(x); +} + +void DataTypeDateTime64::serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const +{ + if (value_index) + return; + value_index = static_cast(protobuf.writeDateTime64(assert_cast(column).getData()[row_num], scale)); +} + +void DataTypeDateTime64::deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const +{ + row_added = false; + DateTime64 t; + if (!protobuf.readDateTime64(t, scale)) + return; + + auto & container = assert_cast(column).getData(); + if (allow_add_row) + { + container.emplace_back(t); + row_added = true; + } + else + container.back() = t; +} + +bool DataTypeDateTime64::equals(const IDataType & rhs) const +{ + if (auto * ptype = typeid_cast(&rhs)) + return this->scale == ptype->getScale(); + return false; +} + +namespace ErrorCodes +{ + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; +} + +enum class ArgumentKind +{ + Optional, + Mandatory +}; + +template +std::conditional_t, T> +getArgument(const ASTPtr & arguments, size_t argument_index, const char * argument_name, const std::string context_data_type_name) +{ + using NearestResultType = NearestFieldType; + const auto fieldType = Field::TypeToEnum::value; + const ASTLiteral * argument = nullptr; + + auto exceptionMessage = [=](const String & message) + { + return std::string("Parameter #") + std::to_string(argument_index) + " '" + + argument_name + "' for " + context_data_type_name + + message + + ", expected: " + Field::Types::toString(fieldType) + " literal."; + }; + + if (!arguments || arguments->children.size() <= argument_index + || !(argument = arguments->children[argument_index]->as())) + { + if constexpr (Kind == ArgumentKind::Optional) + return {}; + else + throw Exception(exceptionMessage(" is missing"), + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + } + + if (argument->value.getType() != fieldType) + throw Exception(exceptionMessage(String(" has wrong type: ") + argument->value.getTypeName()), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return argument->value.get(); +} + +static DataTypePtr create64(const ASTPtr & arguments) +{ + if (!arguments || arguments->size() == 0) + return std::make_shared(DataTypeDateTime64::default_scale); + + const auto scale = getArgument(arguments, 0, "scale", "DateType64"); + const auto timezone = getArgument(arguments, !!scale, "timezone", "DateType64"); + + return std::make_shared(scale.value_or(DataTypeDateTime64::default_scale), timezone.value_or(String{})); +} + +void registerDataTypeDateTime64(DataTypeFactory & factory) +{ + factory.registerDataType("DateTime64", create64, DataTypeFactory::CaseInsensitive); +} + +} diff --git a/dbms/src/DataTypes/DataTypeDateTime64.h b/dbms/src/DataTypes/DataTypeDateTime64.h new file mode 100644 index 00000000000..d73f8d4825c --- /dev/null +++ b/dbms/src/DataTypes/DataTypeDateTime64.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +class DateLUTImpl; + +namespace DB +{ + +/** DateTime64 is same as DateTime, but it stores values as UInt64 and has configurable sub-second part. + * + * `scale` determines number of decimal places for sub-second part of the DateTime64. + */ +class DataTypeDateTime64 final : public DataTypeDecimalBase, public TimezoneMixin +{ +public: + static constexpr UInt8 default_scale = 3; + + explicit DataTypeDateTime64(UInt32 scale_, const std::string & time_zone_name = ""); + + const char * getFamilyName() const override { return "DateTime64"; } + std::string doGetName() const override; + TypeIndex getTypeId() const override { return TypeIndex::DateTime64; } + + void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; + void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; + void deserializeWholeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override; + void serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; + void deserializeTextEscaped(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; + void serializeTextQuoted(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; + void deserializeTextQuoted(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; + void serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; + void deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override; + void serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; + void deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override; + void serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const override; + void deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const override; + + bool equals(const IDataType & rhs) const override; +}; + +template <> inline constexpr bool IsDataTypeDecimal = true; + +} + diff --git a/dbms/src/DataTypes/DataTypeFactory.cpp b/dbms/src/DataTypes/DataTypeFactory.cpp index c3f6e14fedb..64cf8745c5c 100644 --- a/dbms/src/DataTypes/DataTypeFactory.cpp +++ b/dbms/src/DataTypes/DataTypeFactory.cpp @@ -161,6 +161,7 @@ void registerDataTypeNumbers(DataTypeFactory & factory); void registerDataTypeDecimal(DataTypeFactory & factory); void registerDataTypeDate(DataTypeFactory & factory); void registerDataTypeDateTime(DataTypeFactory & factory); +void registerDataTypeDateTime64(DataTypeFactory & factory); void registerDataTypeString(DataTypeFactory & factory); void registerDataTypeFixedString(DataTypeFactory & factory); void registerDataTypeEnum(DataTypeFactory & factory); @@ -183,6 +184,7 @@ DataTypeFactory::DataTypeFactory() registerDataTypeDecimal(*this); registerDataTypeDate(*this); registerDataTypeDateTime(*this); + registerDataTypeDateTime64(*this); registerDataTypeString(*this); registerDataTypeFixedString(*this); registerDataTypeEnum(*this); diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 23f9880e83a..b27ed681f84 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -594,7 +594,9 @@ struct ConvertThroughParsing { if constexpr (std::is_same_v) { - readDateTimeText(vec_to[i], vec_to.getScale(), read_buffer, local_time_zone); + DateTime64 value; + readDateTime64Text(value, vec_to.getScale(), read_buffer, *local_time_zone); + vec_to[i] = value; } else if constexpr (IsDataTypeDecimal) ToDataType::readText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale()); diff --git a/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp b/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp index be5d69e190d..b49ceeedab3 100644 --- a/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp +++ b/dbms/src/Functions/extractTimeZoneFromFunctionArguments.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/dbms/src/Functions/now.cpp b/dbms/src/Functions/now.cpp index cdc17e9c570..4a8ed28e334 100644 --- a/dbms/src/Functions/now.cpp +++ b/dbms/src/Functions/now.cpp @@ -16,14 +16,6 @@ namespace ErrorCodes extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; } -DateTime64::NativeType nowSubsecond(UInt32 scale) -{ - timespec spec; - clock_gettime(CLOCK_REALTIME, &spec); - - return decimalFromComponents(spec.tv_sec, spec.tv_nsec, scale).value; -} - /// Get the current time. (It is a constant, it is evaluated once for the entire query.) class FunctionNow : public IFunction { @@ -51,65 +43,8 @@ public: } }; -class FunctionNow64 : public IFunction -{ -public: - static constexpr auto name = "now64"; - static FunctionPtr create(const Context &) { return std::make_shared(); } - - String getName() const override - { - return name; - } - - bool isVariadic() const override { return true; } - size_t getNumberOfArguments() const override { return 0; } - ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return ColumnNumbers{0}; } - bool isDeterministic() const override { return false; } - - // Return type depends on argument value. - DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override - { - UInt32 scale = DataTypeDateTime64::default_scale; - - // Type check is similar to the validateArgumentType, trying to keep error codes and messages as close to the said function as possible. - if (arguments.size() >= 1) - { - const auto & argument = arguments[0]; - if (!isInteger(argument.type) || !isColumnConst(*argument.column)) - throw Exception("Illegal type " + argument.type->getName() + - " of 0" + - " argument of function " + getName() + - ". Expected const integer.", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - - scale = argument.column->get64(0); - } - - return std::make_shared(scale); - } - - void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override - { - UInt32 scale = DataTypeDateTime64::default_scale; - if (arguments.size() == 1) - { - const IColumn * scale_column = block.getByPosition(arguments[0]).column.get(); - if (!isColumnConst(*scale_column)) - throw Exception("Unsupported argument type: " + scale_column->getName() + - + " for function " + getName() + ". Expected const integer.", - ErrorCodes::ILLEGAL_COLUMN); - - scale = scale_column->get64(0); - } - - block.getByPosition(result).column = DataTypeDateTime64(scale).createColumnConst(input_rows_count, nowSubsecond(scale)); - } -}; - void registerFunctionNow(FunctionFactory & factory) { - factory.registerFunction(FunctionFactory::CaseInsensitive); factory.registerFunction(FunctionFactory::CaseInsensitive); } diff --git a/dbms/src/Functions/now64.cpp b/dbms/src/Functions/now64.cpp new file mode 100644 index 00000000000..9e2be3bed26 --- /dev/null +++ b/dbms/src/Functions/now64.cpp @@ -0,0 +1,88 @@ +#include + +#include +#include +#include + +#include + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int ILLEGAL_COLUMN; + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; +} + +DateTime64::NativeType nowSubsecond(UInt32 scale) +{ + timespec spec; + clock_gettime(CLOCK_REALTIME, &spec); + + return decimalFromComponents(spec.tv_sec, spec.tv_nsec, scale).value; +} + +class FunctionNow64 : public IFunction +{ +public: + static constexpr auto name = "now64"; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + bool isVariadic() const override { return true; } + size_t getNumberOfArguments() const override { return 0; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return ColumnNumbers{0}; } + bool isDeterministic() const override { return false; } + + // Return type depends on argument value. + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + UInt32 scale = DataTypeDateTime64::default_scale; + + // Type check is similar to the validateArgumentType, trying to keep error codes and messages as close to the said function as possible. + if (arguments.size() >= 1) + { + const auto & argument = arguments[0]; + if (!isInteger(argument.type) || !isColumnConst(*argument.column)) + throw Exception("Illegal type " + argument.type->getName() + + " of 0" + + " argument of function " + getName() + + ". Expected const integer.", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + scale = argument.column->get64(0); + } + + return std::make_shared(scale); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + UInt32 scale = DataTypeDateTime64::default_scale; + if (arguments.size() == 1) + { + const IColumn * scale_column = block.getByPosition(arguments[0]).column.get(); + if (!isColumnConst(*scale_column)) + throw Exception("Unsupported argument type: " + scale_column->getName() + + + " for function " + getName() + ". Expected const integer.", + ErrorCodes::ILLEGAL_COLUMN); + + scale = scale_column->get64(0); + } + + block.getByPosition(result).column = DataTypeDateTime64(scale).createColumnConst(input_rows_count, nowSubsecond(scale)); + } +}; + +void registerFunctionNow64(FunctionFactory & factory) +{ + factory.registerFunction(FunctionFactory::CaseInsensitive); +} + +} diff --git a/dbms/src/Functions/registerFunctionsDateTime.cpp b/dbms/src/Functions/registerFunctionsDateTime.cpp index adb2b240c91..a8489dbc5c1 100644 --- a/dbms/src/Functions/registerFunctionsDateTime.cpp +++ b/dbms/src/Functions/registerFunctionsDateTime.cpp @@ -37,6 +37,7 @@ void registerFunctionToRelativeMinuteNum(FunctionFactory &); void registerFunctionToRelativeSecondNum(FunctionFactory &); void registerFunctionToTime(FunctionFactory &); void registerFunctionNow(FunctionFactory &); +void registerFunctionNow64(FunctionFactory &); void registerFunctionToday(FunctionFactory &); void registerFunctionYesterday(FunctionFactory &); void registerFunctionTimeSlot(FunctionFactory &); @@ -101,6 +102,7 @@ void registerFunctionsDateTime(FunctionFactory & factory) registerFunctionToRelativeSecondNum(factory); registerFunctionToTime(factory); registerFunctionNow(factory); + registerFunctionNow64(factory); registerFunctionToday(factory); registerFunctionYesterday(factory); registerFunctionTimeSlot(factory); diff --git a/dbms/src/IO/WriteHelpers.h b/dbms/src/IO/WriteHelpers.h index e7155dae4bc..0421c3b9540 100644 --- a/dbms/src/IO/WriteHelpers.h +++ b/dbms/src/IO/WriteHelpers.h @@ -30,6 +30,7 @@ #include #include +#include namespace DB