From af742a0654d48a87c577e92cc94d8f2e596c7b32 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 31 Oct 2024 17:46:28 +0800 Subject: [PATCH] Fix the wrong result bug when casting string as datetime with time zone or illegal chars (#9255) (#9351) close pingcap/tiflash#8754 Fix the wrong result bug when casting string as datetime with time zone or illegal chars - func `getFracIndex` ignore time zone. - func `parseFrac` ignore illegal suffix after microsecond format. Signed-off-by: Zhigao Tong Co-authored-by: TONG,Zhigao Co-authored-by: Zhigao Tong Co-authored-by: TONG, Zhigao --- dbms/src/Common/MyTime.cpp | 28 ++++++++++++++++++-------- dbms/src/Common/tests/gtest_mytime.cpp | 5 +++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/dbms/src/Common/MyTime.cpp b/dbms/src/Common/MyTime.cpp index 4f96592d226..a1e54a2004e 100644 --- a/dbms/src/Common/MyTime.cpp +++ b/dbms/src/Common/MyTime.cpp @@ -262,7 +262,7 @@ int getFracIndex(const String & format) int idx = -1; for (int i = end; i >= 0; i--) { - if (isPunctuation(format[i])) + if (format[i] != '+' && format[i] != '-' && isPunctuation(format[i])) { if (format[i] == '.') { @@ -745,7 +745,7 @@ inline bool numberToDateTime(Int64 number, MyDateTime & result, bool allowZeroDa } // returns frac, overflow, matched. eg., "999" fsp=2 will overflow. -std::tuple parseFrac(const String & str, int8_t fsp) +std::tuple parseFrac(const std::string_view str, int8_t fsp) { if (str.empty()) { @@ -761,15 +761,27 @@ std::tuple parseFrac(const String & str, int8_t fsp) } try { - int len = str.length(); - if (fsp >= len) + int end_pos = static_cast(fsp) >= str.size() ? str.size() : (fsp + 1); + UInt32 tmp = 0; + int size = 0; + for (int i = 0; i < end_pos; ++i) { - UInt32 tmp = std::stoul(str); - return {tmp * std::pow(10, 6 - len), false, true}; + if (auto c = str[i]; c >= '0' && c <= '9') + { + tmp = tmp * 10 + c - '0'; + size++; + } + else + { + break; + } + } + + if (fsp >= size) + { + return {tmp * std::pow(10, 6 - size), false, true}; } - // Round when fsp < string length. - UInt32 tmp = std::stoul(str.substr(0, fsp + 1)); tmp = (tmp + 5) / 10; if (tmp >= std::pow(10, fsp)) { diff --git a/dbms/src/Common/tests/gtest_mytime.cpp b/dbms/src/Common/tests/gtest_mytime.cpp index c65a7dc05a0..5c076739128 100644 --- a/dbms/src/Common/tests/gtest_mytime.cpp +++ b/dbms/src/Common/tests/gtest_mytime.cpp @@ -125,6 +125,8 @@ try {"2020-10-10 10.10", "2020-10-10 10:10:00.000000"}, {"2018.01.01", "2018-01-01 00:00:00.000000"}, {"2020--12-10 11:11:11..123456", "2020-12-10 11:11:11.123456"}, + {"2020-01-01 12:00:00.1234xxxx -0600 PST", "2020-01-01 12:00:00.123400"}, + {"2020-01-01 12:00:00.123456-05:00", "2020-01-01 17:00:00.123456"}, // tidb/issues/49555 }; DataTypeMyDateTime type_with_fraction(6); for (auto & [str, expected] : cases_with_fsp) @@ -184,6 +186,9 @@ try } DataTypeMyDateTime tp(2); checkParseMyDateTime("2010-12-31 23:59:59.99999", "2011-01-01 00:00:00.00", tp); + checkParseMyDateTime("2010-12-31 23:59:59.99xxxxx -0600 PST", "2010-12-31 23:59:59.99", tp); + checkParseMyDateTime("2020-01-01 12:00:00.123456 +0600 PST", "2020-01-01 12:00:00.12", tp); + checkParseMyDateTime("2020-01-01 12:00:00.123456 -0600 PST", "2020-01-01 12:00:00.12", tp); } catch (Exception & e) {