diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index 56761b710e5..70de5355e12 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit 56761b710e56a2abc6fead1c16e705134be08e6d +Subproject commit 70de5355e12daca1663df33db21dee6ac5bc45ae diff --git a/dbms/src/DataStreams/IProfilingBlockInputStream.h b/dbms/src/DataStreams/IProfilingBlockInputStream.h index 2ce328c94e9..2b78ced4df0 100644 --- a/dbms/src/DataStreams/IProfilingBlockInputStream.h +++ b/dbms/src/DataStreams/IProfilingBlockInputStream.h @@ -54,7 +54,7 @@ class IProfilingBlockInputStream : public IBlockInputStream Block read() override final; - Block read(FilterPtr & res_filter, bool return_filter) override final; + Block read(FilterPtr & res_filter, bool return_filter) override; /** The default implementation calls readPrefixImpl() on itself, and then readPrefix() recursively for all children. * There are cases when you do not want `readPrefix` of children to be called synchronously, in this function, diff --git a/dbms/src/DataStreams/SharedQueryBlockInputStream.h b/dbms/src/DataStreams/SharedQueryBlockInputStream.h index d7c0707b5aa..7882c8cf5c9 100644 --- a/dbms/src/DataStreams/SharedQueryBlockInputStream.h +++ b/dbms/src/DataStreams/SharedQueryBlockInputStream.h @@ -112,7 +112,10 @@ class SharedQueryBlockInputStream : public IProfilingBlockInputStream } protected: - Block readImpl() override + /// The BlockStreamProfileInfo of SharedQuery is useless, + /// and it will trigger tsan UT fail because of data race. + /// So overriding method `read` here. + Block read(FilterPtr &, bool) override { std::unique_lock lock(mutex); @@ -134,6 +137,10 @@ class SharedQueryBlockInputStream : public IProfilingBlockInputStream return block; } + Block readImpl() override + { + throw Exception("Unsupport"); + } void fetchBlocks() { diff --git a/dbms/src/Flash/Coprocessor/DAGUtils.cpp b/dbms/src/Flash/Coprocessor/DAGUtils.cpp old mode 100644 new mode 100755 index 4b1d3546406..75eb75ecbb0 --- a/dbms/src/Flash/Coprocessor/DAGUtils.cpp +++ b/dbms/src/Flash/Coprocessor/DAGUtils.cpp @@ -107,7 +107,7 @@ const std::unordered_map scalar_func_map({ {tipb::ScalarFuncSig::CastTimeAsString, "tidb_cast"}, {tipb::ScalarFuncSig::CastTimeAsDecimal, "tidb_cast"}, {tipb::ScalarFuncSig::CastTimeAsTime, "tidb_cast"}, - //{tipb::ScalarFuncSig::CastTimeAsDuration, "cast"}, + {tipb::ScalarFuncSig::CastTimeAsDuration, "tidb_cast"}, //{tipb::ScalarFuncSig::CastTimeAsJson, "cast"}, //{tipb::ScalarFuncSig::CastDurationAsInt, "cast"}, diff --git a/dbms/src/Functions/FunctionsTiDBConversion.h b/dbms/src/Functions/FunctionsTiDBConversion.h old mode 100644 new mode 100755 index 036b04fa8ca..d649191ad3e --- a/dbms/src/Functions/FunctionsTiDBConversion.h +++ b/dbms/src/Functions/FunctionsTiDBConversion.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1549,7 +1550,7 @@ struct TiDBConvertToTime } }; -/// cast duration as duration +/// cast time/duration as duration /// TODO: support more types convert to duration template struct TiDBConvertToDuration @@ -1601,6 +1602,41 @@ struct TiDBConvertToDuration block.getByPosition(result).column = std::move(to_col); } } + else if constexpr (std::is_same_v) + { + // cast date as duration + const auto & to_type = checkAndGetDataType(removeNullable(block.getByPosition(result).type).get()); + block.getByPosition(result).column = to_type->createColumnConst(size, toField(0)); // The DATE type is used for values with a date part but no time part. The value of Duration is always zero. + } + else if constexpr (std::is_same_v) + { + // cast time as duration + const auto * col_from = checkAndGetColumn(block.getByPosition(arguments[0]).column.get()); + const ColumnUInt64::Container & from_vec = col_from->getData(); + const auto & from_type = checkAndGetDataType(block.getByPosition(arguments[0]).type.get()); + int from_fsp = from_type->getFraction(); + + auto to_col = ColumnVector::create(); + auto & vec_to = to_col->getData(); + vec_to.resize(size); + const auto & to_type = checkAndGetDataType(removeNullable(block.getByPosition(result).type).get()); + int to_fsp = to_type->getFsp(); + + for (size_t i = 0; i < size; ++i) + { + MyDateTime datetime(from_vec[i]); + MyDuration duration(1 /*neg*/, datetime.hour, datetime.minute, datetime.second, datetime.micro_second, from_fsp); + if (to_fsp < from_fsp) + { + vec_to[i] = round(duration.nanoSecond(), (6 - to_fsp) + 3); + } + else + { + vec_to[i] = duration.nanoSecond(); + } + } + block.getByPosition(result).column = std::move(to_col); + } else { throw Exception( diff --git a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp index 387d479c680..51ddcc81f1e 100644 --- a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp +++ b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp @@ -1313,7 +1313,7 @@ try const auto from_type = std::make_shared(3); const auto to_type_1 = std::make_shared(5); // from_fsp < to_fsp const auto to_type_2 = std::make_shared(3); // from_fsp == to_fsp - const auto to_type_3 = std::make_shared(2); // from_fsp < to_fsp + const auto to_type_3 = std::make_shared(2); // from_fsp > to_fsp ColumnWithTypeAndName input( createColumn({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 555000000L, @@ -1766,5 +1766,116 @@ try } CATCH +TEST_F(TestTidbConversion, castTimeAsDuration) +try +{ + const auto to_type_1 = std::make_shared(5); // from_fsp < to_fsp + const auto to_type_2 = std::make_shared(4); // from_fsp == to_fsp + const auto to_type_3 = std::make_shared(2); // from_fsp > to_fsp + // cast datetime to duration + const auto datetime_type_ptr = std::make_shared(4); + MyDateTime date(2021, 10, 26, 0, 0, 0, 0); + MyDateTime datetime(2021, 10, 26, 11, 11, 11, 0); + MyDateTime datetime_frac1(2021, 10, 26, 11, 11, 11, 111100); + MyDateTime datetime_frac2(2021, 10, 26, 11, 11, 11, 123500); + MyDateTime datetime_frac3(2021, 10, 26, 11, 11, 11, 999900); + + auto col_datetime = ColumnUInt64::create(); + col_datetime->insert(Field(date.toPackedUInt())); + col_datetime->insert(Field(datetime.toPackedUInt())); + col_datetime->insert(Field(datetime_frac1.toPackedUInt())); + col_datetime->insert(Field(datetime_frac2.toPackedUInt())); + col_datetime->insert(Field(datetime_frac3.toPackedUInt())); + + auto ctn_datetime = ColumnWithTypeAndName(std::move(col_datetime), datetime_type_ptr, "datetime"); + ColumnWithTypeAndName datetime_output1( + createColumn({(0 * 3600 + 0 * 60 + 0) * 1000000000L + 000000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 000000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 111100000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 123500000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 999900000L}) + .column, + to_type_1, + "datetime_output1"); + ColumnWithTypeAndName datetime_output2( + createColumn({(0 * 3600 + 0 * 60 + 0) * 1000000000L + 000000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 000000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 111100000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 123500000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 999900000L}) + .column, + to_type_2, + "datetime_output2"); + + ColumnWithTypeAndName datetime_output3( + createColumn({(0 * 3600 + 0 * 60 + 0) * 1000000000L + 000000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 000000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 110000000L, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 120000000L, + (11 * 3600 + 11 * 60 + 12) * 1000000000L + 000000000L}) + .column, + to_type_3, + "datetime_output3"); + + + ASSERT_COLUMN_EQ(datetime_output1, executeFunction(func_name, {ctn_datetime, createCastTypeConstColumn(to_type_1->getName())})); + ASSERT_COLUMN_EQ(datetime_output2, executeFunction(func_name, {ctn_datetime, createCastTypeConstColumn(to_type_2->getName())})); + ASSERT_COLUMN_EQ(datetime_output3, executeFunction(func_name, {ctn_datetime, createCastTypeConstColumn(to_type_3->getName())})); + + + // Test Const + ColumnWithTypeAndName input_const(createConstColumn(1, datetime_frac2.toPackedUInt()).column, datetime_type_ptr, "input_const"); + ColumnWithTypeAndName output1_const(createConstColumn(1, (11 * 3600 + 11 * 60 + 11) * 1000000000L + 123500000L).column, to_type_1, "output1_const"); + ColumnWithTypeAndName output2_const(createConstColumn(1, (11 * 3600 + 11 * 60 + 11) * 1000000000L + 123500000L).column, to_type_2, "output2_const"); + ColumnWithTypeAndName output3_const(createConstColumn(1, (11 * 3600 + 11 * 60 + 11) * 1000000000L + 120000000L).column, to_type_3, "output3_const"); + + ASSERT_COLUMN_EQ(output1_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_1->getName())})); + ASSERT_COLUMN_EQ(output2_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_2->getName())})); + ASSERT_COLUMN_EQ(output3_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_3->getName())})); + + // Test Nullable + ColumnWithTypeAndName input_nullable( + createColumn>({datetime_frac1.toPackedUInt(), + {}, + datetime_frac2.toPackedUInt(), + {}, + datetime_frac3.toPackedUInt()}) + .column, + makeNullable(datetime_type_ptr), + "input_nullable"); + ColumnWithTypeAndName output1_nullable( + createColumn>({(11 * 3600 + 11 * 60 + 11) * 1000000000L + 111100000L, + {}, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 123500000L, + {}, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 999900000L}) + .column, + makeNullable(to_type_1), + "output1_output"); + ColumnWithTypeAndName output2_nullable( + createColumn>({(11 * 3600 + 11 * 60 + 11) * 1000000000L + 111100000L, + {}, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 123500000L, + {}, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 999900000L}) + .column, + makeNullable(to_type_2), + "output2_output"); + ColumnWithTypeAndName output3_nullable( + createColumn>({(11 * 3600 + 11 * 60 + 11) * 1000000000L + 110000000L, + {}, + (11 * 3600 + 11 * 60 + 11) * 1000000000L + 120000000L, + {}, + (11 * 3600 + 11 * 60 + 12) * 1000000000L + 000000000L}) + .column, + makeNullable(to_type_3), + "output3_output"); + + ASSERT_COLUMN_EQ(output1_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_1)->getName())})); + ASSERT_COLUMN_EQ(output2_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_2)->getName())})); + ASSERT_COLUMN_EQ(output3_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_3)->getName())})); +} +CATCH + } // namespace } // namespace DB::tests diff --git a/tests/fullstack-test/expr/cast_as_duration.test b/tests/fullstack-test/expr/cast_as_duration.test new file mode 100644 index 00000000000..ad2afcee92c --- /dev/null +++ b/tests/fullstack-test/expr/cast_as_duration.test @@ -0,0 +1,95 @@ +# 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(c1 date, c2 datetime(4)); +mysql> insert into test.t values('2022-01-01','2022-09-20 11:11:11.0000'); +mysql> insert into test.t values('2022-01-01','2022-09-20 11:11:11.1111'); +mysql> insert into test.t values('2022-01-01','2022-09-20 11:11:11.1234'); +mysql> insert into test.t values('2022-01-01','2022-09-20 11:11:11.1255'); +mysql> insert into test.t values('2022-01-01','2022-09-20 11:11:11.9999'); +mysql> insert into test.t values(null,null); + +mysql> alter table test.t set tiflash replica 1; + +func> wait_table test t + +mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1; select cast(test.t.c1 as time(2)) from test.t; ++----------------------------+ +| cast(test.t.c1 as time(2)) | ++----------------------------+ +| 00:00:00.00 | +| 00:00:00.00 | +| 00:00:00.00 | +| 00:00:00.00 | +| 00:00:00.00 | +| NULL | ++----------------------------+ +mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1; select cast(test.t.c1 as time(4)) from test.t; ++----------------------------+ +| cast(test.t.c1 as time(4)) | ++----------------------------+ +| 00:00:00.0000 | +| 00:00:00.0000 | +| 00:00:00.0000 | +| 00:00:00.0000 | +| 00:00:00.0000 | +| NULL | ++----------------------------+ +mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1; select cast(test.t.c1 as time(5)) from test.t; ++----------------------------+ +| cast(test.t.c1 as time(5)) | ++----------------------------+ +| 00:00:00.00000 | +| 00:00:00.00000 | +| 00:00:00.00000 | +| 00:00:00.00000 | +| 00:00:00.00000 | +| NULL | ++----------------------------+ +mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1; select cast(test.t.c2 as time(2)) from test.t; ++----------------------------+ +| cast(test.t.c2 as time(2)) | ++----------------------------+ +| 11:11:11.00 | +| 11:11:11.11 | +| 11:11:11.12 | +| 11:11:11.13 | +| 11:11:12.00 | +| NULL | ++----------------------------+ +mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1; select cast(test.t.c2 as time(4)) from test.t; ++----------------------------+ +| cast(test.t.c2 as time(4)) | ++----------------------------+ +| 11:11:11.0000 | +| 11:11:11.1111 | +| 11:11:11.1234 | +| 11:11:11.1255 | +| 11:11:11.9999 | +| NULL | ++----------------------------+ +mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1; select cast(test.t.c2 as time(5)) from test.t; ++----------------------------+ +| cast(test.t.c2 as time(5)) | ++----------------------------+ +| 11:11:11.00000 | +| 11:11:11.11110 | +| 11:11:11.12340 | +| 11:11:11.12550 | +| 11:11:11.99990 | +| NULL | ++----------------------------+ +mysql> drop table if exists test.t; diff --git a/tests/sanitize/tsan.suppression b/tests/sanitize/tsan.suppression index d24afc30209..73824caa2b9 100644 --- a/tests/sanitize/tsan.suppression +++ b/tests/sanitize/tsan.suppression @@ -1,2 +1 @@ race:dbms/src/Common/TiFlashMetrics.h -race:dbms/src/DataStreams/BlockStreamProfileInfo.h \ No newline at end of file