From 23b53ee2f9855925f664af67c00a0a7b1552fb81 Mon Sep 17 00:00:00 2001 From: Martijn Bakker Date: Mon, 1 Apr 2019 17:18:13 +0100 Subject: [PATCH] able to insert DateTime64 objects into the table --- dbms/src/DataTypes/DataTypeDateTime.cpp | 71 +++++++++++++++++-- dbms/src/DataTypes/DataTypeDateTime.h | 18 ++++- .../0_stateless/00921_datetime64.reference | 3 + .../queries/0_stateless/00921_datetime64.sql | 15 ++++ 4 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00921_datetime64.reference create mode 100644 dbms/tests/queries/0_stateless/00921_datetime64.sql diff --git a/dbms/src/DataTypes/DataTypeDateTime.cpp b/dbms/src/DataTypes/DataTypeDateTime.cpp index 9f229ffdd95..502f4562dbb 100644 --- a/dbms/src/DataTypes/DataTypeDateTime.cpp +++ b/dbms/src/DataTypes/DataTypeDateTime.cpp @@ -16,6 +16,7 @@ #include +#include namespace DB { @@ -47,6 +48,23 @@ DataTypeDateTimeBase::DataTypeDateTimeBase(const std::string & time_ { } +DataTypeDateTime64::Precision parsePrecision(const std::string & precision_name) +{ + if (precision_name == "MILLI") + return DataTypeDateTime64::Precision::Millis; + else if (precision_name == "MICRO") + return DataTypeDateTime64::Precision::Micros; + return DataTypeDateTime64::Precision::Nanos; +} + +DataTypeDateTime64::DataTypeDateTime64(const std::string & time_zone_name, const std::string & precision_name) + : DataTypeDateTimeBase(time_zone_name), + precision(parsePrecision(precision_name)) +{ +} + + + template const char * DataTypeDateTimeBase::getFamilyName() const { @@ -76,6 +94,43 @@ void DataTypeDateTimeBase::serializeText(const IColumn & column, siz writeDateTimeText(static_cast::Column &>(column).getData()[row_num], ostr, time_zone); } +void DataTypeDateTime64::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const +{ + time_t base_time; + auto full_time = static_cast(column).getData()[row_num]; + UInt32 time_fraction; + int pad_length = 0; + + switch(precision) { + case DataTypeDateTime64::Precision::Millis: { + base_time = full_time / MILLIS_PER_SECOND; + time_fraction = full_time % MILLIS_PER_SECOND; + pad_length = 3; + break; + } + case DataTypeDateTime64::Precision::Micros: { + base_time = full_time / MICROS_PER_SECOND; + time_fraction = full_time % MICROS_PER_SECOND; + pad_length = 6; + break; + } + case DataTypeDateTime64::Precision::Nanos: { + base_time = full_time / NANOS_PER_SECOND; + time_fraction = full_time % NANOS_PER_SECOND; + pad_length = 9; + break; + } + } + + writeDateTimeText(base_time, ostr, time_zone); + writeText(".", 1, ostr); + + /// TODO make this efficient + std::stringstream ss; + ss << std::setfill('0') << std::setw(pad_length) << time_fraction; + writeText(ss.str(), ostr); +} + template void DataTypeDateTimeBase::serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const { @@ -258,14 +313,18 @@ static DataTypePtr create64(const ASTPtr & arguments) if (!arguments) return std::make_shared(); - if (arguments->children.size() != 1) - throw Exception("DateTime64 data type can optionally have only one argument - time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + if (arguments->children.size() != 2) + throw Exception("DateTime64 data type can optionally have 2 arguments - precision and time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - const auto * arg = arguments->children[0]->as(); - if (!arg || arg->value.getType() != Field::Types::String) - throw Exception("Parameter for DateTime64 data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + const auto * timezone_arg = arguments->children[0]->as(); + if (!timezone_arg || timezone_arg->value.getType() != Field::Types::String) + throw Exception("Timezone parameter for DateTime64 data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - return std::make_shared(arg->value.get()); + const auto * precision_arg = arguments->children[1]->as(); + if (!precision_arg || precision_arg->value.getType() != Field::Types::String) + throw Exception("Precision parameter for DateTime64 data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(timezone_arg->value.get(), precision_arg->value.get()); } void registerDataTypeDateTime(DataTypeFactory & factory) diff --git a/dbms/src/DataTypes/DataTypeDateTime.h b/dbms/src/DataTypes/DataTypeDateTime.h index ba6116a2222..5e0d0d6085c 100644 --- a/dbms/src/DataTypes/DataTypeDateTime.h +++ b/dbms/src/DataTypes/DataTypeDateTime.h @@ -57,7 +57,7 @@ public: const DateLUTImpl & getTimeZone() const { return time_zone; } -private: +protected: bool has_explicit_time_zone; const DateLUTImpl & time_zone; const DateLUTImpl & utc_time_zone; @@ -68,7 +68,21 @@ struct DataTypeDateTime : DataTypeDateTimeBase { }; struct DataTypeDateTime64 : DataTypeDateTimeBase { - using DataTypeDateTimeBase::DataTypeDateTimeBase; + enum class Precision { + Millis, + Micros, + Nanos, + }; + static constexpr UInt32 MILLIS_PER_SECOND = 1000; + static constexpr UInt32 MICROS_PER_SECOND = 1000 * 1000; + static constexpr UInt32 NANOS_PER_SECOND = 1000 * 1000 * 1000; + + DataTypeDateTime64(const std::string & time_zone_name = "", const std::string & precision_name = ""); + + void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override; + +private: + const Precision precision; }; } diff --git a/dbms/tests/queries/0_stateless/00921_datetime64.reference b/dbms/tests/queries/0_stateless/00921_datetime64.reference new file mode 100644 index 00000000000..c866f4b76b8 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00921_datetime64.reference @@ -0,0 +1,3 @@ +2 1970-01-01 01:00:01.000000001 1 0 +2 1970-01-01 01:00:01.000000003 3 3 +2 1970-01-01 01:00:01.000000005 5 3 diff --git a/dbms/tests/queries/0_stateless/00921_datetime64.sql b/dbms/tests/queries/0_stateless/00921_datetime64.sql new file mode 100644 index 00000000000..82938dbf5ed --- /dev/null +++ b/dbms/tests/queries/0_stateless/00921_datetime64.sql @@ -0,0 +1,15 @@ +USE test; + +DROP TABLE IF EXISTS A; +DROP TABLE IF EXISTS B; + +CREATE TABLE A(k UInt32, t DateTime64, a Float64) ENGINE = MergeTree() ORDER BY (k, t); +INSERT INTO A(k,t,a) VALUES (2,1000000001,1),(2,1000000003,3),(2,1000000005,5); + +CREATE TABLE B(k UInt32, t DateTime64, b Float64) ENGINE = MergeTree() ORDER BY (k, t); +INSERT INTO B(k,t,b) VALUES (2,1000000003,3); + +SELECT k, t, a, b FROM A ASOF LEFT JOIN B USING(k,t) ORDER BY (k,t); + +DROP TABLE B; +DROP TABLE A;