From f9de6fa927f8ad1c172f01a4a38db755f8cf8d05 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Fri, 23 Sep 2022 17:34:56 +0800 Subject: [PATCH 01/12] support extract duration Signed-off-by: birdstorm --- dbms/src/Common/MyDuration.h | 15 +- dbms/src/Common/MyTime.cpp | 5 + dbms/src/Flash/Coprocessor/DAGUtils.cpp | 2 +- dbms/src/Functions/FunctionsDuration.cpp | 1 + dbms/src/Functions/FunctionsDuration.h | 224 ++++++++++++++++++ .../fullstack-test/expr/extract_duration.test | 30 +++ 6 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 tests/fullstack-test/expr/extract_duration.test diff --git a/dbms/src/Common/MyDuration.h b/dbms/src/Common/MyDuration.h index 730d31b232b..60e885aeeb0 100644 --- a/dbms/src/Common/MyDuration.h +++ b/dbms/src/Common/MyDuration.h @@ -48,11 +48,22 @@ class MyDuration static constexpr Int64 MAX_NANOS = MAX_HOUR_PART * NANOS_PER_HOUR + MAX_MINUTE_PART * NANOS_PER_MINUTE + MAX_SECOND_PART * NANOS_PER_SECOND + MAX_MICRO_PART * NANOS_PER_MICRO; static_assert(MAX_NANOS > 0); + static const int8_t DefaultFsp = 6; + Int64 nanos; UInt8 fsp; public: MyDuration() = default; + explicit MyDuration(Int64 nanos_) + : nanos(nanos_) + , fsp(DefaultFsp) + { + if (nanos_ > MAX_NANOS || nanos_ < -MAX_NANOS) + { + throw Exception(fmt::format("nanos must >= {} and <= {}", -MAX_NANOS, MAX_NANOS), ErrorCodes::ARGUMENT_OUT_OF_BOUND); + } + } MyDuration(Int64 nanos_, UInt8 fsp_) : nanos(nanos_) , fsp(fsp_) @@ -61,13 +72,13 @@ class MyDuration { throw Exception(fmt::format("nanos must >= {} and <= {}", -MAX_NANOS, MAX_NANOS), ErrorCodes::ARGUMENT_OUT_OF_BOUND); } - if (fsp > 6) + if (fsp > 6 || fsp < 0) throw Exception("fsp must >= 0 and <= 6", ErrorCodes::ARGUMENT_OUT_OF_BOUND); } MyDuration(Int32 neg, Int32 hour, Int32 minute, Int32 second, Int32 microsecond, UInt8 fsp) : MyDuration(neg * (hour * NANOS_PER_HOUR + minute * NANOS_PER_MINUTE + second * NANOS_PER_SECOND + microsecond * NANOS_PER_MICRO), fsp) { - if (fsp > 6) + if (fsp > 6 || fsp < 0) throw Exception("fsp must >= 0 and <= 6", ErrorCodes::ARGUMENT_OUT_OF_BOUND); if (minute > MAX_MINUTE_PART || minute < 0) throw Exception("minute must >= 0 and <= 59", ErrorCodes::ARGUMENT_OUT_OF_BOUND); diff --git a/dbms/src/Common/MyTime.cpp b/dbms/src/Common/MyTime.cpp index 4ddd313edda..598568f42cc 100644 --- a/dbms/src/Common/MyTime.cpp +++ b/dbms/src/Common/MyTime.cpp @@ -1008,6 +1008,11 @@ Field parseMyDateTimeFromFloat(const String & str, int8_t fsp, CheckTimeFunc che return parseMyDateTimeAndJudgeIsDate(str, fsp, checkTimeFunc, true).first; } +Field parseMyDuration(const String & str, int8_t fsp) +{ + +} + String MyDateTime::toString(int fsp) const { const static String format = "%Y-%m-%d %H:%i:%s"; diff --git a/dbms/src/Flash/Coprocessor/DAGUtils.cpp b/dbms/src/Flash/Coprocessor/DAGUtils.cpp index 1c4a8e521e9..3efaf50cbb6 100755 --- a/dbms/src/Flash/Coprocessor/DAGUtils.cpp +++ b/dbms/src/Flash/Coprocessor/DAGUtils.cpp @@ -584,7 +584,7 @@ const std::unordered_map scalar_func_map({ {tipb::ScalarFuncSig::FromUnixTime1Arg, "fromUnixTime"}, {tipb::ScalarFuncSig::FromUnixTime2Arg, "fromUnixTime"}, {tipb::ScalarFuncSig::ExtractDatetime, "extractMyDateTime"}, - //{tipb::ScalarFuncSig::ExtractDuration, "cast"}, + {tipb::ScalarFuncSig::ExtractDuration, "extractMyDuration"}, //{tipb::ScalarFuncSig::AddDateStringString, "cast"}, {tipb::ScalarFuncSig::AddDateStringInt, "date_add"}, diff --git a/dbms/src/Functions/FunctionsDuration.cpp b/dbms/src/Functions/FunctionsDuration.cpp index 9ccafd2794d..751b46d90b4 100644 --- a/dbms/src/Functions/FunctionsDuration.cpp +++ b/dbms/src/Functions/FunctionsDuration.cpp @@ -215,5 +215,6 @@ void registerFunctionsDuration(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); + factory.registerFunction(); } } // namespace DB diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index 5bc54d425f4..77c947f54d3 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -88,4 +88,228 @@ class FunctionMyDurationToSec : public IFunction void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) const override; }; +struct ExtractMyDurationImpl +{ + static Int64 signMultiplier(const MyDuration & duration) + { + return duration.isNeg() ? -1 : 1; + } + + static Int64 extractHour(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * duration.hours(); + } + + static Int64 extractMinute(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * duration.minutes(); + } + + static Int64 extractSecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * duration.seconds(); + } + + static Int64 extractMicrosecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * duration.microSecond(); + } + + static Int64 extractSecondMicrosecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.seconds() * 1000000LL + duration.microSecond()); + } + + static Int64 extractMinuteMicrosecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.minutes() * 100000000LL + duration.seconds() * 1000000LL + duration.microSecond()); + } + + static Int64 extractMinuteSecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.minutes() * 100LL + duration.seconds()); + } + + static Int64 extractHourMicrosecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.hours() * 10000000000LL + duration.minutes() * 100000000LL + duration.seconds() * 1000000LL + duration.microSecond()); + } + + static Int64 extractHourSecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.hours() * 10000LL + duration.minutes() * 100LL + duration.seconds()); + } + + static Int64 extractHourMinute(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.hours() * 100LL + duration.minutes()); + } +}; + +class FunctionExtractMyDuration : public IFunction +{ +public: + static constexpr auto name = "extractMyDuration"; + + static FunctionPtr create(const Context &) { return std::make_shared(); }; + + String getName() const override { return name; } + + size_t getNumberOfArguments() const override { return 2; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!arguments[0]->isString()) + throw TiFlashException(fmt::format("First argument for function {} (unit) must be String", getName()), Errors::Coprocessor::BadRequest); + + // TODO: Support Extract from string, see https://github.com/pingcap/tidb/issues/22700 + // if (!(arguments[1]->isString() || arguments[1]->isDateOrDateTime())) + if (!arguments[1]->isMyTime()) + throw TiFlashException( + fmt::format("Illegal type {} of second argument of function {}. Must be Duration.", arguments[1]->getName(), getName()), + Errors::Coprocessor::BadRequest); + + return std::make_shared(); + } + + bool useDefaultImplementationForConstants() const override { return true; } + ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0}; } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) const override + { + const auto * unit_column = checkAndGetColumnConst(block.getByPosition(arguments[0]).column.get()); + if (!unit_column) + throw TiFlashException( + fmt::format("First argument for function {} must be constant String", getName()), + Errors::Coprocessor::BadRequest); + + String unit = Poco::toLower(unit_column->getValue()); + + auto col_from = block.getByPosition(arguments[1]).column; + + size_t rows = block.rows(); + auto col_to = ColumnInt64::create(rows); + auto & vec_to = col_to->getData(); + + if (unit == "hour") + dispatch(col_from, vec_to); + else if (unit == "minute") + dispatch(col_from, vec_to); + else if (unit == "second") + dispatch(col_from, vec_to); + else if (unit == "microsecond") + dispatch(col_from, vec_to); + else if (unit == "second_microsecond") + dispatch(col_from, vec_to); + else if (unit == "minute_microsecond") + dispatch(col_from, vec_to); + else if (unit == "minute_second") + dispatch(col_from, vec_to); + else if (unit == "hour_microsecond") + dispatch(col_from, vec_to); + else if (unit == "hour_second") + dispatch(col_from, vec_to); + else if (unit == "hour_minute") + dispatch(col_from, vec_to); + else + throw TiFlashException(fmt::format("Function {} does not support '{}' unit", getName(), unit), Errors::Coprocessor::BadRequest); + + block.getByPosition(result).column = std::move(col_to); + } + +private: + using Func = Int64 (*)(Int64); + + template + static void dispatch(const ColumnPtr col_from, PaddedPODArray & vec_to) + { + if (const auto * from = checkAndGetColumn(col_from.get()); from) + { + const auto & data = from->getChars(); + const auto & offsets = from->getOffsets(); + if (checkColumnConst(from)) + { + StringRef string_ref(data.data(), offsets[0] - 1); + constantString(string_ref, from->size(), vec_to); + } + else + { + vectorString(data, offsets, vec_to); + } + } + else if (const auto * from = checkAndGetColumn(col_from.get()); from) + { + const auto & data = from->getData(); + if (checkColumnConst(from)) + { + constantDuration(from->getUInt(0), from->size(), vec_to); + } + else + { + vectorDuration(data, vec_to); + } + } + } + + template + static void constantString(const StringRef & from, size_t size, PaddedPODArray & vec_to) + { + vec_to.resize(size); + auto from_value = get(parseMyDuration(from.toString())); + for (size_t i = 0; i < size; ++i) + { + vec_to[i] = F(from_value); + } + } + + template + static void vectorString( + const ColumnString::Chars_t & vec_from, + const ColumnString::Offsets & offsets_from, + PaddedPODArray & vec_to) + { + vec_to.resize(offsets_from.size() + 1); + size_t current_offset = 0; + for (size_t i = 0; i < offsets_from.size(); i++) + { + size_t next_offset = offsets_from[i]; + size_t string_size = next_offset - current_offset - 1; + StringRef string_value(&vec_from[current_offset], string_size); + auto nano = get(parseMyDuration(string_value.toString())); + vec_to[i] = F(nano); + current_offset = next_offset; + } + } + + template + static void constantDuration(const Int64 & from, size_t size, PaddedPODArray & vec_to) + { + vec_to.resize(size); + for (size_t i = 0; i < size; ++i) + { + vec_to[i] = F(from); + } + } + + template + static void vectorDuration(const ColumnInt64::Container & vec_from, PaddedPODArray & vec_to) + { + vec_to.resize(vec_from.size()); + for (size_t i = 0; i < vec_from.size(); i++) + { + vec_to[i] = F(vec_from[i]); + } + } +}; + } // namespace DB \ No newline at end of file diff --git a/tests/fullstack-test/expr/extract_duration.test b/tests/fullstack-test/expr/extract_duration.test new file mode 100644 index 00000000000..e529533ccd7 --- /dev/null +++ b/tests/fullstack-test/expr/extract_duration.test @@ -0,0 +1,30 @@ +# Copyright 2022 PingCAP, Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +mysql> drop table if exists test.t +mysql> create table test.t (a time) +mysql> insert into test.t values('838:34:56.123456') +mysql> insert into test.t values('-838:34:56.123456') +mysql> alter table test.t set tiflash replica 1 +func> wait_table test t + +mysql> set session tidb_isolation_read_engines='tiflash'; select a from test.t where extract(hour from a) = 838 and extract(minute from a) = 34 and extract(second from a) = 56 and extract(microsecond from a) = 123456; +a +838:34:56.123456 + +mysql> set session tidb_isolation_read_engines='tiflash'; select a from test.t where extract(second_microsecond from a) = -56123456 and extract(minute_microsecond from a) = -3456123456 and extract(minute_second from a) = -3456 and extract(hour_microsecond from a) = -8383456123456 and extract(hour_second from a) = -8383456 and extract(hour_minute from a) = -83834; +a +-838:34:56.123456 + +mysql> drop table if exists test.t \ No newline at end of file From 783357023129dd4f9d40eb5a1c6a2a2db864183a Mon Sep 17 00:00:00 2001 From: birdstorm Date: Tue, 27 Sep 2022 11:46:31 +0800 Subject: [PATCH 02/12] minor fix Signed-off-by: birdstorm --- dbms/src/Common/MyDuration.cpp | 42 +++++++++++++++++++ dbms/src/Common/MyDuration.h | 2 + dbms/src/Common/MyTime.cpp | 5 --- dbms/src/Functions/FunctionsDuration.h | 12 +++--- .../fullstack-test/expr/extract_duration.test | 2 +- 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/dbms/src/Common/MyDuration.cpp b/dbms/src/Common/MyDuration.cpp index d0ecf6e2f0a..085509f2ad3 100644 --- a/dbms/src/Common/MyDuration.cpp +++ b/dbms/src/Common/MyDuration.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include @@ -56,6 +57,47 @@ Int32 MyDuration::microSecond() const return std::abs(nanos) / NANOS_PER_MICRO % 1000000; } + +std::pair matchDuration(const String & str, int8_t fsp) +{ + if (fsp < 0 || fsp > 6) + return {MyDuration(), false}; + + if (str.empty()) + return {MyDuration(), false}; + + bool negative = false; + String rest; + if (str[0] == '-') + { + negative = true; + rest = str.substr(1); + } + else + rest = str; + + UInt64 hhmmss[3] = {0}; + UInt64 frac = 0; + + Int64 d = (hhmmss[0] * 3600 + hhmmss[1] * 60 + hhmmss[2]) * 1000000000 + frac * 1000; + if (negative) + d = -d; + MyDuration duration(d, fsp); + return {duration, true}; +} + +Field parseMyDuration(const String & str, int8_t fsp) +{ + auto matched = matchDuration(str, fsp); + if (matched.second) + { + MyDuration duration = matched.first; + return duration.nanoSecond(); + } + // try fall-back to datetime + return 0ll; +} + String MyDuration::toString() const { auto [sign, hour, minute, second, microsecond] = splitDuration(); diff --git a/dbms/src/Common/MyDuration.h b/dbms/src/Common/MyDuration.h index 60e885aeeb0..2664d8ffcff 100644 --- a/dbms/src/Common/MyDuration.h +++ b/dbms/src/Common/MyDuration.h @@ -100,4 +100,6 @@ class MyDuration String toString() const; }; + +Field parseMyDuration(const String & str, int8_t fsp); } // namespace DB diff --git a/dbms/src/Common/MyTime.cpp b/dbms/src/Common/MyTime.cpp index 598568f42cc..4ddd313edda 100644 --- a/dbms/src/Common/MyTime.cpp +++ b/dbms/src/Common/MyTime.cpp @@ -1008,11 +1008,6 @@ Field parseMyDateTimeFromFloat(const String & str, int8_t fsp, CheckTimeFunc che return parseMyDateTimeAndJudgeIsDate(str, fsp, checkTimeFunc, true).first; } -Field parseMyDuration(const String & str, int8_t fsp) -{ - -} - String MyDateTime::toString(int fsp) const { const static String format = "%Y-%m-%d %H:%i:%s"; diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index 77c947f54d3..a85efc86219 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -252,7 +252,7 @@ class FunctionExtractMyDuration : public IFunction const auto & data = from->getData(); if (checkColumnConst(from)) { - constantDuration(from->getUInt(0), from->size(), vec_to); + constantDuration(from->getInt(0), from->size(), vec_to); } else { @@ -265,10 +265,11 @@ class FunctionExtractMyDuration : public IFunction static void constantString(const StringRef & from, size_t size, PaddedPODArray & vec_to) { vec_to.resize(size); - auto from_value = get(parseMyDuration(from.toString())); + auto from_value = get(parseMyDuration(from.toString(), 6)); + const auto & const_value = F(from_value); for (size_t i = 0; i < size; ++i) { - vec_to[i] = F(from_value); + vec_to[i] = const_value; } } @@ -285,7 +286,7 @@ class FunctionExtractMyDuration : public IFunction size_t next_offset = offsets_from[i]; size_t string_size = next_offset - current_offset - 1; StringRef string_value(&vec_from[current_offset], string_size); - auto nano = get(parseMyDuration(string_value.toString())); + auto nano = get(parseMyDuration(string_value.toString(), 6)); vec_to[i] = F(nano); current_offset = next_offset; } @@ -295,9 +296,10 @@ class FunctionExtractMyDuration : public IFunction static void constantDuration(const Int64 & from, size_t size, PaddedPODArray & vec_to) { vec_to.resize(size); + const auto & const_value = F(from); for (size_t i = 0; i < size; ++i) { - vec_to[i] = F(from); + vec_to[i] = const_value; } } diff --git a/tests/fullstack-test/expr/extract_duration.test b/tests/fullstack-test/expr/extract_duration.test index e529533ccd7..413fef28790 100644 --- a/tests/fullstack-test/expr/extract_duration.test +++ b/tests/fullstack-test/expr/extract_duration.test @@ -27,4 +27,4 @@ mysql> set session tidb_isolation_read_engines='tiflash'; select a from test.t w a -838:34:56.123456 -mysql> drop table if exists test.t \ No newline at end of file +mysql> drop table if exists test.t From 07c29da5f681f0117c02fd2c334e74f66183b6fb Mon Sep 17 00:00:00 2001 From: birdstorm Date: Fri, 28 Oct 2022 13:44:19 +0800 Subject: [PATCH 03/12] format Signed-off-by: birdstorm --- dbms/src/Functions/FunctionsDuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index a85efc86219..1d206335ca1 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -192,7 +192,7 @@ class FunctionExtractMyDuration : public IFunction throw TiFlashException( fmt::format("First argument for function {} must be constant String", getName()), Errors::Coprocessor::BadRequest); - + String unit = Poco::toLower(unit_column->getValue()); auto col_from = block.getByPosition(arguments[1]).column; From 6016de652a311c12f3119b2eb50fc48bd43ad05e Mon Sep 17 00:00:00 2001 From: birdstorm Date: Fri, 28 Oct 2022 19:00:26 +0800 Subject: [PATCH 04/12] add tests Signed-off-by: birdstorm --- dbms/src/Common/MyDuration.cpp | 6 +- dbms/src/Common/MyDuration.h | 1 + dbms/src/Functions/FunctionsDateTime.h | 11 -- dbms/src/Functions/FunctionsDuration.h | 3 - .../tests/gtest_datetime_extract.cpp | 4 +- .../tests/gtest_duration_extract.cpp | 103 ++++++++++++++++++ 6 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 dbms/src/Functions/tests/gtest_duration_extract.cpp diff --git a/dbms/src/Common/MyDuration.cpp b/dbms/src/Common/MyDuration.cpp index 085509f2ad3..24ff70311d1 100644 --- a/dbms/src/Common/MyDuration.cpp +++ b/dbms/src/Common/MyDuration.cpp @@ -44,17 +44,17 @@ Int32 MyDuration::hours() const Int32 MyDuration::minutes() const { - return std::abs(nanos) / NANOS_PER_MINUTE % 60; + return (std::abs(nanos) / NANOS_PER_MINUTE) % 60; } Int32 MyDuration::seconds() const { - return std::abs(nanos) / NANOS_PER_SECOND % 60; + return (std::abs(nanos) / NANOS_PER_SECOND) % 60; } Int32 MyDuration::microSecond() const { - return std::abs(nanos) / NANOS_PER_MICRO % 1000000; + return (std::abs(nanos) / NANOS_PER_MICRO) % 1000000; } diff --git a/dbms/src/Common/MyDuration.h b/dbms/src/Common/MyDuration.h index 2664d8ffcff..5c000ddbafb 100644 --- a/dbms/src/Common/MyDuration.h +++ b/dbms/src/Common/MyDuration.h @@ -16,6 +16,7 @@ #include #include +#include #include namespace DB diff --git a/dbms/src/Functions/FunctionsDateTime.h b/dbms/src/Functions/FunctionsDateTime.h index fa33a54f811..ef6bcce81aa 100644 --- a/dbms/src/Functions/FunctionsDateTime.h +++ b/dbms/src/Functions/FunctionsDateTime.h @@ -2802,17 +2802,6 @@ class FunctionExtractMyDateTime : public IFunction dispatch(col_from, vec_to); else if (unit == "year_month") dispatch(col_from, vec_to); - /// TODO: support ExtractDuration - // else if (unit == "hour"); - // else if (unit == "minute"); - // else if (unit == "second"); - // else if (unit == "microsecond"); - // else if (unit == "second_microsecond"); - // else if (unit == "minute_microsecond"); - // else if (unit == "minute_second"); - // else if (unit == "hour_microsecond"); - // else if (unit == "hour_second"); - // else if (unit == "hour_minute"); else throw TiFlashException(fmt::format("Function {} does not support '{}' unit", getName(), unit), Errors::Coprocessor::BadRequest); diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index 1d206335ca1..a78398ee045 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -172,8 +171,6 @@ class FunctionExtractMyDuration : public IFunction if (!arguments[0]->isString()) throw TiFlashException(fmt::format("First argument for function {} (unit) must be String", getName()), Errors::Coprocessor::BadRequest); - // TODO: Support Extract from string, see https://github.com/pingcap/tidb/issues/22700 - // if (!(arguments[1]->isString() || arguments[1]->isDateOrDateTime())) if (!arguments[1]->isMyTime()) throw TiFlashException( fmt::format("Illegal type {} of second argument of function {}. Must be Duration.", arguments[1]->getName(), getName()), diff --git a/dbms/src/Functions/tests/gtest_datetime_extract.cpp b/dbms/src/Functions/tests/gtest_datetime_extract.cpp index 1f6e585b002..d0ff74ac3e9 100644 --- a/dbms/src/Functions/tests/gtest_datetime_extract.cpp +++ b/dbms/src/Functions/tests/gtest_datetime_extract.cpp @@ -89,7 +89,7 @@ try size_t res_col_idx = 2; func_builder_ptr->build({unit_ctn, datetime_ctn})->execute(block, arg_cols_idx, res_col_idx); const IColumn * ctn_res = block.getByPosition(res_col_idx).column.get(); - const ColumnInt64 * col_res = checkAndGetColumn(ctn_res); + const auto * col_res = checkAndGetColumn(ctn_res); Field res_field; col_res->get(0, res_field); @@ -149,7 +149,7 @@ try size_t res_col_idx = 2; func_builder_ptr->build({unit_ctn, datetime_ctn})->execute(block, arg_cols_idx, res_col_idx); const IColumn * ctn_res = block.getByPosition(res_col_idx).column.get(); - const ColumnInt64 * col_res = checkAndGetColumn(ctn_res); + const auto * col_res = checkAndGetColumn(ctn_res); Field res_field; col_res->get(0, res_field); diff --git a/dbms/src/Functions/tests/gtest_duration_extract.cpp b/dbms/src/Functions/tests/gtest_duration_extract.cpp new file mode 100644 index 00000000000..8da54aff0f5 --- /dev/null +++ b/dbms/src/Functions/tests/gtest_duration_extract.cpp @@ -0,0 +1,103 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#include + +#pragma GCC diagnostic pop + +namespace DB +{ +namespace tests +{ +// TODO: rewrite using executeFunction() +class TestDurationExtract : public DB::tests::FunctionTest +{ +}; + +TEST_F(TestDurationExtract, ExtractFromMyDuration) +try +{ + const Context context = TiFlashTestEnv::getContext(); + + auto & factory = FunctionFactory::instance(); + + std::vector units{ + "hour", + "minute", + "second", + "microsecond", + "second_microsecond", + "minute_microsecond", + "minute_second", + "hour_microsecond", + "hour_second", + "hour_minute", + }; + MyDuration duration_value(1, 838, 34, 56, 123456, 6); + std::vector results{838, 34, 56, 123456, 56123456, 3456123456, 3456, 8383456123456, 8383456, 83834}; + + for (size_t i = 0; i < units.size(); ++i) + { + const auto & unit = units[i]; + Block block; + + MutableColumnPtr col_units = ColumnString::create(); + col_units->insert(Field(unit.c_str(), unit.size())); + col_units = ColumnConst::create(col_units->getPtr(), 1); + + auto col_duration = ColumnInt64::create(); + col_duration->insert(Field(duration_value.nanoSecond())); + ColumnWithTypeAndName unit_ctn = ColumnWithTypeAndName(std::move(col_units), std::make_shared(), "unit"); + ColumnWithTypeAndName duration_ctn + = ColumnWithTypeAndName(std::move(col_duration), std::make_shared(), "duration_value"); + + block.insert(unit_ctn); + block.insert(duration_ctn); + // for result from extract + block.insert({}); + + // test extract + auto func_builder_ptr = factory.tryGet("extractMyDuration", context); + ASSERT_TRUE(func_builder_ptr != nullptr); + + ColumnNumbers arg_cols_idx{0, 1}; + size_t res_col_idx = 2; + func_builder_ptr->build({unit_ctn, duration_ctn})->execute(block, arg_cols_idx, res_col_idx); + const IColumn * ctn_res = block.getByPosition(res_col_idx).column.get(); + const auto * col_res = checkAndGetColumn(ctn_res); + + Field res_field; + col_res->get(0, res_field); + Int64 s = res_field.get(); + EXPECT_EQ(results[i], s); + } +} +CATCH + +} // namespace tests +} // namespace DB From a21f33ed0710d7445a9917ee30ddfd53ae7862e7 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Wed, 9 Nov 2022 11:07:43 +0800 Subject: [PATCH 05/12] remove unused logic Signed-off-by: birdstorm --- dbms/src/Common/MyDuration.cpp | 41 ---------------------- dbms/src/Common/MyDuration.h | 2 -- dbms/src/Functions/FunctionsDuration.h | 47 +------------------------- 3 files changed, 1 insertion(+), 89 deletions(-) diff --git a/dbms/src/Common/MyDuration.cpp b/dbms/src/Common/MyDuration.cpp index 24ff70311d1..74f25541c4d 100644 --- a/dbms/src/Common/MyDuration.cpp +++ b/dbms/src/Common/MyDuration.cpp @@ -57,47 +57,6 @@ Int32 MyDuration::microSecond() const return (std::abs(nanos) / NANOS_PER_MICRO) % 1000000; } - -std::pair matchDuration(const String & str, int8_t fsp) -{ - if (fsp < 0 || fsp > 6) - return {MyDuration(), false}; - - if (str.empty()) - return {MyDuration(), false}; - - bool negative = false; - String rest; - if (str[0] == '-') - { - negative = true; - rest = str.substr(1); - } - else - rest = str; - - UInt64 hhmmss[3] = {0}; - UInt64 frac = 0; - - Int64 d = (hhmmss[0] * 3600 + hhmmss[1] * 60 + hhmmss[2]) * 1000000000 + frac * 1000; - if (negative) - d = -d; - MyDuration duration(d, fsp); - return {duration, true}; -} - -Field parseMyDuration(const String & str, int8_t fsp) -{ - auto matched = matchDuration(str, fsp); - if (matched.second) - { - MyDuration duration = matched.first; - return duration.nanoSecond(); - } - // try fall-back to datetime - return 0ll; -} - String MyDuration::toString() const { auto [sign, hour, minute, second, microsecond] = splitDuration(); diff --git a/dbms/src/Common/MyDuration.h b/dbms/src/Common/MyDuration.h index 5c000ddbafb..047fdfdd74e 100644 --- a/dbms/src/Common/MyDuration.h +++ b/dbms/src/Common/MyDuration.h @@ -101,6 +101,4 @@ class MyDuration String toString() const; }; - -Field parseMyDuration(const String & str, int8_t fsp); } // namespace DB diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index a78398ee045..2fb8d2c31fe 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -230,21 +230,7 @@ class FunctionExtractMyDuration : public IFunction template static void dispatch(const ColumnPtr col_from, PaddedPODArray & vec_to) { - if (const auto * from = checkAndGetColumn(col_from.get()); from) - { - const auto & data = from->getChars(); - const auto & offsets = from->getOffsets(); - if (checkColumnConst(from)) - { - StringRef string_ref(data.data(), offsets[0] - 1); - constantString(string_ref, from->size(), vec_to); - } - else - { - vectorString(data, offsets, vec_to); - } - } - else if (const auto * from = checkAndGetColumn(col_from.get()); from) + if (const auto * from = checkAndGetColumn(col_from.get()); from) { const auto & data = from->getData(); if (checkColumnConst(from)) @@ -258,37 +244,6 @@ class FunctionExtractMyDuration : public IFunction } } - template - static void constantString(const StringRef & from, size_t size, PaddedPODArray & vec_to) - { - vec_to.resize(size); - auto from_value = get(parseMyDuration(from.toString(), 6)); - const auto & const_value = F(from_value); - for (size_t i = 0; i < size; ++i) - { - vec_to[i] = const_value; - } - } - - template - static void vectorString( - const ColumnString::Chars_t & vec_from, - const ColumnString::Offsets & offsets_from, - PaddedPODArray & vec_to) - { - vec_to.resize(offsets_from.size() + 1); - size_t current_offset = 0; - for (size_t i = 0; i < offsets_from.size(); i++) - { - size_t next_offset = offsets_from[i]; - size_t string_size = next_offset - current_offset - 1; - StringRef string_value(&vec_from[current_offset], string_size); - auto nano = get(parseMyDuration(string_value.toString(), 6)); - vec_to[i] = F(nano); - current_offset = next_offset; - } - } - template static void constantDuration(const Int64 & from, size_t size, PaddedPODArray & vec_to) { From f13ec000da26576ae1af0ee921281e5c3fdb5a86 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Wed, 9 Nov 2022 11:48:10 +0800 Subject: [PATCH 06/12] format Signed-off-by: birdstorm --- dbms/src/Common/MyDuration.cpp | 1 - dbms/src/Common/MyDuration.h | 1 - 2 files changed, 2 deletions(-) diff --git a/dbms/src/Common/MyDuration.cpp b/dbms/src/Common/MyDuration.cpp index 74f25541c4d..97aa995a9ce 100644 --- a/dbms/src/Common/MyDuration.cpp +++ b/dbms/src/Common/MyDuration.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include diff --git a/dbms/src/Common/MyDuration.h b/dbms/src/Common/MyDuration.h index 047fdfdd74e..60e885aeeb0 100644 --- a/dbms/src/Common/MyDuration.h +++ b/dbms/src/Common/MyDuration.h @@ -16,7 +16,6 @@ #include #include -#include #include namespace DB From 8b164540f5638ad7f4994a9bfe9669e743dc9718 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Wed, 9 Nov 2022 15:36:48 +0800 Subject: [PATCH 07/12] resolve comments Signed-off-by: birdstorm --- dbms/src/Common/MyDuration.h | 4 +- dbms/src/Flash/tests/gtest_log_search.cpp | 2 +- dbms/src/Functions/FunctionsDuration.h | 21 +------- .../tests/gtest_duration_extract.cpp | 45 +++------------- dbms/src/TestUtils/FunctionTestUtils.h | 54 +++++++++++++++++++ 5 files changed, 65 insertions(+), 61 deletions(-) diff --git a/dbms/src/Common/MyDuration.h b/dbms/src/Common/MyDuration.h index 60e885aeeb0..8c454d23d9f 100644 --- a/dbms/src/Common/MyDuration.h +++ b/dbms/src/Common/MyDuration.h @@ -56,8 +56,8 @@ class MyDuration public: MyDuration() = default; explicit MyDuration(Int64 nanos_) - : nanos(nanos_) - , fsp(DefaultFsp) + : nanos(nanos_) + , fsp(DefaultFsp) { if (nanos_ > MAX_NANOS || nanos_ < -MAX_NANOS) { diff --git a/dbms/src/Flash/tests/gtest_log_search.cpp b/dbms/src/Flash/tests/gtest_log_search.cpp index 99cc1aa63aa..aa898c23399 100644 --- a/dbms/src/Flash/tests/gtest_log_search.cpp +++ b/dbms/src/Flash/tests/gtest_log_search.cpp @@ -41,7 +41,7 @@ inline Int64 getTimezoneAndOffset(int tz_sign, int tz_hour, int tz_min) inline void getTimezoneString(char * tzs, int tz_sign, int tz_hour, int tz_min) { - sprintf(tzs, "%c%02d:%02d", tz_sign > 0 ? '+' : '-', tz_hour, tz_min); + snprintf(tzs, 6, "%c%02d:%02d", tz_sign > 0 ? '+' : '-', tz_hour, tz_min); } TEST_F(LogSearchTest, LogSearch) diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index 2fb8d2c31fe..a6383a81e60 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -233,25 +234,7 @@ class FunctionExtractMyDuration : public IFunction if (const auto * from = checkAndGetColumn(col_from.get()); from) { const auto & data = from->getData(); - if (checkColumnConst(from)) - { - constantDuration(from->getInt(0), from->size(), vec_to); - } - else - { - vectorDuration(data, vec_to); - } - } - } - - template - static void constantDuration(const Int64 & from, size_t size, PaddedPODArray & vec_to) - { - vec_to.resize(size); - const auto & const_value = F(from); - for (size_t i = 0; i < size; ++i) - { - vec_to[i] = const_value; + vectorDuration(data, vec_to); } } diff --git a/dbms/src/Functions/tests/gtest_duration_extract.cpp b/dbms/src/Functions/tests/gtest_duration_extract.cpp index 8da54aff0f5..88dd5c9e99d 100644 --- a/dbms/src/Functions/tests/gtest_duration_extract.cpp +++ b/dbms/src/Functions/tests/gtest_duration_extract.cpp @@ -13,11 +13,8 @@ // limitations under the License. #include -#include #include -#include #include -#include #include #include @@ -26,7 +23,6 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" -#include #pragma GCC diagnostic pop @@ -42,10 +38,6 @@ class TestDurationExtract : public DB::tests::FunctionTest TEST_F(TestDurationExtract, ExtractFromMyDuration) try { - const Context context = TiFlashTestEnv::getContext(); - - auto & factory = FunctionFactory::instance(); - std::vector units{ "hour", "minute", @@ -64,37 +56,12 @@ try for (size_t i = 0; i < units.size(); ++i) { const auto & unit = units[i]; - Block block; - - MutableColumnPtr col_units = ColumnString::create(); - col_units->insert(Field(unit.c_str(), unit.size())); - col_units = ColumnConst::create(col_units->getPtr(), 1); - - auto col_duration = ColumnInt64::create(); - col_duration->insert(Field(duration_value.nanoSecond())); - ColumnWithTypeAndName unit_ctn = ColumnWithTypeAndName(std::move(col_units), std::make_shared(), "unit"); - ColumnWithTypeAndName duration_ctn - = ColumnWithTypeAndName(std::move(col_duration), std::make_shared(), "duration_value"); - - block.insert(unit_ctn); - block.insert(duration_ctn); - // for result from extract - block.insert({}); - - // test extract - auto func_builder_ptr = factory.tryGet("extractMyDuration", context); - ASSERT_TRUE(func_builder_ptr != nullptr); - - ColumnNumbers arg_cols_idx{0, 1}; - size_t res_col_idx = 2; - func_builder_ptr->build({unit_ctn, duration_ctn})->execute(block, arg_cols_idx, res_col_idx); - const IColumn * ctn_res = block.getByPosition(res_col_idx).column.get(); - const auto * col_res = checkAndGetColumn(ctn_res); - - Field res_field; - col_res->get(0, res_field); - Int64 s = res_field.get(); - EXPECT_EQ(results[i], s); + const auto & result = results[i]; + // nullable/non-null duration + ASSERT_COLUMN_EQ(toNullableVec({result}), executeFunction("extractMyDuration", createConstColumn(1, {unit}), createDurationColumn({duration_value}, 6))); + ASSERT_COLUMN_EQ(toVec({result}), executeFunction("extractMyDuration", createConstColumn(1, {unit}), createDurationColumn({duration_value}, 6))); + // const duration + ASSERT_COLUMN_EQ(createConstColumn(1, result), executeFunction("extractMyDuration", createConstColumn(1, {unit}), createDurationColumnConst(1, {duration_value}, 6))); } } CATCH diff --git a/dbms/src/TestUtils/FunctionTestUtils.h b/dbms/src/TestUtils/FunctionTestUtils.h index af38a5f8d37..a6d7049420c 100644 --- a/dbms/src/TestUtils/FunctionTestUtils.h +++ b/dbms/src/TestUtils/FunctionTestUtils.h @@ -377,6 +377,60 @@ ColumnWithTypeAndName createDateTimeColumnConst(size_t size, const std::optional return {std::move(col), data_type_ptr, "datetime"}; } +template +ColumnWithTypeAndName createDurationColumn(std::initializer_list> init, int fraction) +{ + DataTypePtr data_type_ptr = std::make_shared(fraction); + if constexpr (is_nullable) + { + data_type_ptr = makeNullable(data_type_ptr); + } + auto col = data_type_ptr->createColumn(); + for (const auto & dt : init) + { + if (dt.has_value()) + col->insert(Field(dt->nanoSecond())); + else + { + if constexpr (is_nullable) + { + col->insert(Null()); + } + else + { + throw Exception("Null value for not nullable DataTypeMyDuration"); + } + } + } + return {std::move(col), data_type_ptr, "duration"}; +} + +template +ColumnWithTypeAndName createDurationColumnConst(size_t size, const std::optional & duration, int fraction) +{ + DataTypePtr data_type_ptr = std::make_shared(fraction); + if constexpr (is_nullable) + { + data_type_ptr = makeNullable(data_type_ptr); + } + + ColumnPtr col; + if (duration.has_value()) + col = data_type_ptr->createColumnConst(size, Field(duration->nanoSecond())); + else + { + if constexpr (is_nullable) + { + col = data_type_ptr->createColumnConst(size, Field(Null())); + } + else + { + throw Exception("Null value for not nullable DataTypeMyDuration"); + } + } + return {std::move(col), data_type_ptr, "duration"}; +} + // parse a string into decimal field. template typename TypeTraits::FieldType parseDecimal( From a425fa21e03e3578b834b96cedce3e9ffd1dd8bf Mon Sep 17 00:00:00 2001 From: birdstorm Date: Wed, 9 Nov 2022 15:50:48 +0800 Subject: [PATCH 08/12] format Signed-off-by: birdstorm --- dbms/src/Functions/FunctionsDuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index a6383a81e60..495b01b38ea 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -14,9 +14,9 @@ #pragma once +#include #include #include -#include #include #include #include From 692982a6e5e627ffbdf5fe3ea06eb5599039cf30 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Wed, 9 Nov 2022 16:38:21 +0800 Subject: [PATCH 09/12] fix some tests Signed-off-by: birdstorm --- dbms/src/Functions/tests/gtest_duration_extract.cpp | 2 ++ tests/fullstack-test/expr/extract_duration.test | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dbms/src/Functions/tests/gtest_duration_extract.cpp b/dbms/src/Functions/tests/gtest_duration_extract.cpp index 88dd5c9e99d..b46a7bbb106 100644 --- a/dbms/src/Functions/tests/gtest_duration_extract.cpp +++ b/dbms/src/Functions/tests/gtest_duration_extract.cpp @@ -62,6 +62,8 @@ try ASSERT_COLUMN_EQ(toVec({result}), executeFunction("extractMyDuration", createConstColumn(1, {unit}), createDurationColumn({duration_value}, 6))); // const duration ASSERT_COLUMN_EQ(createConstColumn(1, result), executeFunction("extractMyDuration", createConstColumn(1, {unit}), createDurationColumnConst(1, {duration_value}, 6))); + // null + ASSERT_COLUMN_EQ(toNullableVec({std::nullopt}), executeFunction("extractMyDuration", createConstColumn(1, {unit}), createDurationColumn({std::nullopt}, 6))); } } CATCH diff --git a/tests/fullstack-test/expr/extract_duration.test b/tests/fullstack-test/expr/extract_duration.test index 413fef28790..26d55ddc93f 100644 --- a/tests/fullstack-test/expr/extract_duration.test +++ b/tests/fullstack-test/expr/extract_duration.test @@ -13,7 +13,7 @@ # limitations under the License. mysql> drop table if exists test.t -mysql> create table test.t (a time) +mysql> create table test.t (a time(6)) mysql> insert into test.t values('838:34:56.123456') mysql> insert into test.t values('-838:34:56.123456') mysql> alter table test.t set tiflash replica 1 From 9030ac31acfd1d074cee6dd37e223b5209421ad7 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Wed, 9 Nov 2022 17:04:01 +0800 Subject: [PATCH 10/12] fix compilation error Signed-off-by: birdstorm --- dbms/src/Flash/tests/gtest_log_search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Flash/tests/gtest_log_search.cpp b/dbms/src/Flash/tests/gtest_log_search.cpp index aa898c23399..87334dfb30c 100644 --- a/dbms/src/Flash/tests/gtest_log_search.cpp +++ b/dbms/src/Flash/tests/gtest_log_search.cpp @@ -41,7 +41,7 @@ inline Int64 getTimezoneAndOffset(int tz_sign, int tz_hour, int tz_min) inline void getTimezoneString(char * tzs, int tz_sign, int tz_hour, int tz_min) { - snprintf(tzs, 6, "%c%02d:%02d", tz_sign > 0 ? '+' : '-', tz_hour, tz_min); + snprintf(tzs, 10, "%c%02d:%02d", tz_sign > 0 ? '+' : '-', tz_hour, tz_min); } TEST_F(LogSearchTest, LogSearch) From 5ef618487b1361cf1dfe88ea686f20e94e1ee45f Mon Sep 17 00:00:00 2001 From: birdstorm Date: Thu, 10 Nov 2022 13:06:47 +0800 Subject: [PATCH 11/12] Update dbms/src/Functions/FunctionsDuration.h Co-authored-by: Zhi Qi <30543181+LittleFall@users.noreply.github.com> --- dbms/src/Functions/FunctionsDuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index 495b01b38ea..d89b23f431b 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -249,4 +249,4 @@ class FunctionExtractMyDuration : public IFunction } }; -} // namespace DB \ No newline at end of file +} // namespace DB From dfa45c83fbb74ad6a6bfc218f7979db0131b7ed9 Mon Sep 17 00:00:00 2001 From: birdstorm Date: Thu, 10 Nov 2022 13:57:12 +0800 Subject: [PATCH 12/12] add more support for extract duration Signed-off-by: birdstorm --- dbms/src/Functions/FunctionsDuration.h | 36 +++++++++++++++++-- .../tests/gtest_duration_extract.cpp | 6 +++- .../fullstack-test/expr/extract_duration.test | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/dbms/src/Functions/FunctionsDuration.h b/dbms/src/Functions/FunctionsDuration.h index d89b23f431b..1cb046b4d40 100644 --- a/dbms/src/Functions/FunctionsDuration.h +++ b/dbms/src/Functions/FunctionsDuration.h @@ -128,7 +128,7 @@ struct ExtractMyDurationImpl static Int64 extractMinuteMicrosecond(Int64 nano) { MyDuration duration(nano); - return signMultiplier(duration) * (duration.minutes() * 100000000LL + duration.seconds() * 1000000LL + duration.microSecond()); + return signMultiplier(duration) * ((duration.minutes() * 100LL + duration.seconds()) * 1000000LL + duration.microSecond()); } static Int64 extractMinuteSecond(Int64 nano) @@ -140,7 +140,7 @@ struct ExtractMyDurationImpl static Int64 extractHourMicrosecond(Int64 nano) { MyDuration duration(nano); - return signMultiplier(duration) * (duration.hours() * 10000000000LL + duration.minutes() * 100000000LL + duration.seconds() * 1000000LL + duration.microSecond()); + return signMultiplier(duration) * ((duration.hours() * 10000LL + duration.minutes() * 100LL + duration.seconds()) * 1000000LL + duration.microSecond()); } static Int64 extractHourSecond(Int64 nano) @@ -154,6 +154,30 @@ struct ExtractMyDurationImpl MyDuration duration(nano); return signMultiplier(duration) * (duration.hours() * 100LL + duration.minutes()); } + + static Int64 extractDayMicrosecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * ((duration.hours() * 10000LL + duration.minutes() * 100LL + duration.seconds()) * 1000000LL + duration.microSecond()); + } + + static Int64 extractDaySecond(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.hours() * 10000LL + duration.minutes() * 100LL + duration.seconds()); + } + + static Int64 extractDayMinute(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * (duration.hours() * 100LL + duration.minutes()); + } + + static Int64 extractDayHour(Int64 nano) + { + MyDuration duration(nano); + return signMultiplier(duration) * duration.hours(); + } }; class FunctionExtractMyDuration : public IFunction @@ -219,6 +243,14 @@ class FunctionExtractMyDuration : public IFunction dispatch(col_from, vec_to); else if (unit == "hour_minute") dispatch(col_from, vec_to); + else if (unit == "day_microsecond") + dispatch(col_from, vec_to); + else if (unit == "day_second") + dispatch(col_from, vec_to); + else if (unit == "day_minute") + dispatch(col_from, vec_to); + else if (unit == "day_hour") + dispatch(col_from, vec_to); else throw TiFlashException(fmt::format("Function {} does not support '{}' unit", getName(), unit), Errors::Coprocessor::BadRequest); diff --git a/dbms/src/Functions/tests/gtest_duration_extract.cpp b/dbms/src/Functions/tests/gtest_duration_extract.cpp index b46a7bbb106..7ffebb30d63 100644 --- a/dbms/src/Functions/tests/gtest_duration_extract.cpp +++ b/dbms/src/Functions/tests/gtest_duration_extract.cpp @@ -49,9 +49,13 @@ try "hour_microsecond", "hour_second", "hour_minute", + "day_microsecond", + "day_second", + "day_minute", + "day_hour", }; MyDuration duration_value(1, 838, 34, 56, 123456, 6); - std::vector results{838, 34, 56, 123456, 56123456, 3456123456, 3456, 8383456123456, 8383456, 83834}; + std::vector results{838, 34, 56, 123456, 56123456, 3456123456, 3456, 8383456123456, 8383456, 83834, 8383456123456, 8383456, 83834, 838}; for (size_t i = 0; i < units.size(); ++i) { diff --git a/tests/fullstack-test/expr/extract_duration.test b/tests/fullstack-test/expr/extract_duration.test index 26d55ddc93f..bc7bc98524e 100644 --- a/tests/fullstack-test/expr/extract_duration.test +++ b/tests/fullstack-test/expr/extract_duration.test @@ -23,7 +23,7 @@ mysql> set session tidb_isolation_read_engines='tiflash'; select a from test.t w a 838:34:56.123456 -mysql> set session tidb_isolation_read_engines='tiflash'; select a from test.t where extract(second_microsecond from a) = -56123456 and extract(minute_microsecond from a) = -3456123456 and extract(minute_second from a) = -3456 and extract(hour_microsecond from a) = -8383456123456 and extract(hour_second from a) = -8383456 and extract(hour_minute from a) = -83834; +mysql> set session tidb_isolation_read_engines='tiflash'; select a from test.t where extract(second_microsecond from a) = -56123456 and extract(minute_microsecond from a) = -3456123456 and extract(minute_second from a) = -3456 and extract(hour_microsecond from a) = -8383456123456 and extract(hour_second from a) = -8383456 and extract(hour_minute from a) = -83834 and extract(day_microsecond from a) = -8383456123456 and extract(day_second from a) = -8383456 and extract(day_minute from a) = -83834 and extract(day_hour from a) = -838; a -838:34:56.123456