From 06255a9b9f3714da8f59cda09d962d3b840e6c76 Mon Sep 17 00:00:00 2001 From: Vasily Nemkov Date: Tue, 22 Oct 2019 10:43:14 +0300 Subject: [PATCH] DateTime64 toStartOfInterval fix --- dbms/src/Columns/ColumnDecimal.h | 1 + dbms/src/Functions/toStartOfInterval.cpp | 72 ++++++++++++++++++------ 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/dbms/src/Columns/ColumnDecimal.h b/dbms/src/Columns/ColumnDecimal.h index 35ce26c8996..8aafcb8d947 100644 --- a/dbms/src/Columns/ColumnDecimal.h +++ b/dbms/src/Columns/ColumnDecimal.h @@ -64,6 +64,7 @@ private: friend class COWHelper; public: + using value_type = T; using Container = DecimalPaddedPODArray; private: diff --git a/dbms/src/Functions/toStartOfInterval.cpp b/dbms/src/Functions/toStartOfInterval.cpp index 21e500602e1..c3a52bf7100 100644 --- a/dbms/src/Functions/toStartOfInterval.cpp +++ b/dbms/src/Functions/toStartOfInterval.cpp @@ -126,6 +126,24 @@ namespace } }; + template + class DateTime64TransformWrapper + { + public: + DateTime64TransformWrapper(UInt32 scale_) + : scale_multiplier(decimalScaleMultiplier(scale_)), + fractional_divider(decimalFractionalDivider(scale_)) + {} + + UInt32 execute(DateTime64 t, UInt64 v, const DateLUTImpl & time_zone) const + { + const auto components = decimalSplitWithScaleMultiplier(t, scale_multiplier); + return Transform::execute(static_cast(components.whole), v, time_zone); + } + private: + UInt32 scale_multiplier = 1; + UInt32 fractional_divider = 1; + }; } @@ -233,26 +251,34 @@ private: ColumnPtr dispatchForColumns( const ColumnWithTypeAndName & time_column, const ColumnWithTypeAndName & interval_column, const DateLUTImpl & time_zone) { - if (WhichDataType(time_column.type.get()).isDateTime()) + const auto & from_datatype = *time_column.type.get(); + const auto which_type = WhichDataType(from_datatype); + if (which_type.isDateTime()) { const auto * time_column_vec = checkAndGetColumn(time_column.column.get()); if (time_column_vec) - return dispatchForIntervalColumn(*time_column_vec, interval_column, time_zone); + return dispatchForIntervalColumn(assert_cast(from_datatype), *time_column_vec, interval_column, time_zone); } - if (WhichDataType(time_column.type.get()).isDate()) + if (which_type.isDate()) { const auto * time_column_vec = checkAndGetColumn(time_column.column.get()); if (time_column_vec) - return dispatchForIntervalColumn(*time_column_vec, interval_column, time_zone); + return dispatchForIntervalColumn(assert_cast(from_datatype), *time_column_vec, interval_column, time_zone); + } + if (which_type.isDateTime64()) + { + const auto * time_column_vec = checkAndGetColumn(time_column.column.get()); + if (time_column_vec) + return dispatchForIntervalColumn(assert_cast(from_datatype), *time_column_vec, interval_column, time_zone); } throw Exception( "Illegal column for first argument of function " + getName() + ". Must contain dates or dates with time", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } - template + template ColumnPtr dispatchForIntervalColumn( - const ColumnVector & time_column, const ColumnWithTypeAndName & interval_column, const DateLUTImpl & time_zone) + const FromDataType & from, const ColumnType & time_column, const ColumnWithTypeAndName & interval_column, const DateLUTImpl & time_zone) { const auto * interval_type = checkAndGetDataType(interval_column.type.get()); if (!interval_type) @@ -270,36 +296,46 @@ private: switch (interval_type->getKind()) { case DataTypeInterval::Second: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Minute: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Hour: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Day: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Week: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Month: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Quarter: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); case DataTypeInterval::Year: - return execute(time_column, num_units, time_zone); + return execute(from, time_column, num_units, time_zone); } __builtin_unreachable(); } - template - ColumnPtr execute(const ColumnVector & time_column, UInt64 num_units, const DateLUTImpl & time_zone) + template + ColumnPtr execute(const FromDataType & from_datatype, const ColumnType & time_column, UInt64 num_units, const DateLUTImpl & time_zone) { const auto & time_data = time_column.getData(); size_t size = time_column.size(); auto result = ColumnVector::create(); auto & result_data = result->getData(); result_data.resize(size); - for (size_t i = 0; i != size; ++i) - result_data[i] = Transform::execute(time_data[i], num_units, time_zone); + + if constexpr (std::is_same_v) + { + const auto transform = DateTime64TransformWrapper>{from_datatype.getScale()}; + for (size_t i = 0; i != size; ++i) + result_data[i] = transform.execute(time_data[i], num_units, time_zone); + } + else + { + for (size_t i = 0; i != size; ++i) + result_data[i] = Transform::execute(time_data[i], num_units, time_zone); + } return result; } };