You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2023/04/07 14:02:22 UTC

[doris] branch master updated: [Bug](cast) Fix bug for cast function between datetimev2 and string (#18442)

This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new d881d71cd1 [Bug](cast) Fix bug for cast function between datetimev2 and string (#18442)
d881d71cd1 is described below

commit d881d71cd1eec660c9a909aea0f63759a2fd2ce2
Author: Gabriel <ga...@gmail.com>
AuthorDate: Fri Apr 7 22:02:15 2023 +0800

    [Bug](cast) Fix bug for cast function between datetimev2 and string (#18442)
    
    Fix bug for cast function between datetimev2 and string
---
 be/src/vec/data_types/data_type_time_v2.cpp        |  5 +++
 be/src/vec/data_types/data_type_time_v2.h          |  2 +
 be/src/vec/runtime/vdatetime_value.cpp             | 52 ++++++++++++++++++++--
 be/src/vec/runtime/vdatetime_value.h               |  4 ++
 .../cast_function/test_cast_function.out           | 16 ++++++-
 .../cast_function/test_cast_with_scale_type.out    |  4 +-
 .../cast_function/test_cast_function.groovy        | 38 +++++++++++++++-
 7 files changed, 112 insertions(+), 9 deletions(-)

diff --git a/be/src/vec/data_types/data_type_time_v2.cpp b/be/src/vec/data_types/data_type_time_v2.cpp
index 293eb2e9ec..789815ca29 100644
--- a/be/src/vec/data_types/data_type_time_v2.cpp
+++ b/be/src/vec/data_types/data_type_time_v2.cpp
@@ -145,6 +145,11 @@ Status DataTypeDateTimeV2::from_string(ReadBuffer& rb, IColumn* column) const {
     return Status::OK();
 }
 
+void DataTypeDateTimeV2::to_pb_column_meta(PColumnMeta* col_meta) const {
+    IDataType::to_pb_column_meta(col_meta);
+    col_meta->mutable_decimal_param()->set_scale(_scale);
+}
+
 MutableColumnPtr DataTypeDateTimeV2::create_column() const {
     return DataTypeNumberBase<UInt64>::create_column();
 }
diff --git a/be/src/vec/data_types/data_type_time_v2.h b/be/src/vec/data_types/data_type_time_v2.h
index 97b5152b73..97928a9b23 100644
--- a/be/src/vec/data_types/data_type_time_v2.h
+++ b/be/src/vec/data_types/data_type_time_v2.h
@@ -90,6 +90,8 @@ public:
 
     UInt32 get_scale() const { return _scale; }
 
+    void to_pb_column_meta(PColumnMeta* col_meta) const override;
+
     static void cast_to_date(const UInt64 from, Int64& to);
     static void cast_to_date_time(const UInt64 from, Int64& to);
     static void cast_to_date_v2(const UInt64 from, UInt32& to);
diff --git a/be/src/vec/runtime/vdatetime_value.cpp b/be/src/vec/runtime/vdatetime_value.cpp
index 2d4d78d1ab..16ee2b5664 100644
--- a/be/src/vec/runtime/vdatetime_value.cpp
+++ b/be/src/vec/runtime/vdatetime_value.cpp
@@ -1794,6 +1794,34 @@ bool DateV2Value<T>::is_invalid(uint32_t year, uint32_t month, uint32_t day, uin
     return false;
 }
 
+template <typename T>
+void DateV2Value<T>::format_datetime(uint32_t* date_val) const {
+    // ms
+    DCHECK(date_val[6] < 1000000L);
+    // hour, minute, second
+    for (size_t i = 5; i > 2; i--) {
+        if (date_val[i] == MAX_TIME_PART_VALUE[i - 3] + 1) {
+            date_val[i] = 0;
+            date_val[i - 1] += 1;
+        }
+    }
+    // day
+    if (date_val[1] == 2 && doris::is_leap(date_val[0])) {
+        if (date_val[2] == 30) {
+            date_val[2] = 1;
+            date_val[1] += 1;
+        }
+    } else if (date_val[2] == s_days_in_month[date_val[1]] + 1) {
+        date_val[2] = 1;
+        date_val[1] += 1;
+    }
+    // month
+    if (date_val[1] == 13) {
+        date_val[1] = 1;
+        date_val[0] += 1;
+    }
+}
+
 // The interval format is that with no delimiters
 // YYYY-MM-DD HH-MM-DD.FFFFFF AM in default format
 // 0    1  2  3  4  5  6      7
@@ -1803,7 +1831,6 @@ bool DateV2Value<T>::from_date_str(const char* date_str, int len, int scale) {
     const char* end = date_str + len;
     // ONLY 2, 6 can follow by a space
     const static int allow_space_mask = 4 | 64;
-    const static int MAX_DATE_PARTS = 7;
     uint32_t date_val[MAX_DATE_PARTS] = {0};
     int32_t date_len[MAX_DATE_PARTS] = {0};
 
@@ -1845,11 +1872,27 @@ bool DateV2Value<T>::from_date_str(const char* date_str, int len, int scale) {
         }
         if (field_idx == 6) {
             // Microsecond
-            temp_val *= std::pow(10, 6 - (end - start));
+            const auto ms_part = end - start;
+            temp_val *= std::pow(10, std::max(0L, 6 - ms_part));
             if constexpr (is_datetime) {
                 if (scale >= 0) {
-                    temp_val /= std::pow(10, 6 - scale);
-                    temp_val *= std::pow(10, 6 - scale);
+                    if (scale == 6 && ms_part > 6) {
+                        if (ptr < end && isdigit(*ptr) && *ptr >= '5') {
+                            temp_val += 1;
+                        }
+                    } else {
+                        const int divisor = std::pow(10, 6 - scale);
+                        int remainder = temp_val % divisor;
+                        temp_val /= divisor;
+                        if (scale < 6 && std::abs(remainder) >= (divisor >> 1)) {
+                            temp_val += 1;
+                        }
+                        temp_val *= divisor;
+                        if (temp_val == 1000000L) {
+                            temp_val = 0;
+                            date_val[field_idx - 1] += 1;
+                        }
+                    }
                 }
             }
         }
@@ -1912,6 +1955,7 @@ bool DateV2Value<T>::from_date_str(const char* date_str, int len, int scale) {
     }
 
     if (num_field < 3) return false;
+    format_datetime(date_val);
     return check_range_and_set_time(date_val[0], date_val[1], date_val[2], date_val[3], date_val[4],
                                     date_val[5], date_val[6]);
 }
diff --git a/be/src/vec/runtime/vdatetime_value.h b/be/src/vec/runtime/vdatetime_value.h
index a0e1739c36..622a4d9350 100644
--- a/be/src/vec/runtime/vdatetime_value.h
+++ b/be/src/vec/runtime/vdatetime_value.h
@@ -1119,6 +1119,10 @@ public:
 
     bool from_date_format_str(const char* format, int format_len, const char* value, int value_len,
                               const char** sub_val_end);
+    static constexpr int MAX_DATE_PARTS = 7;
+    static constexpr uint32_t MAX_TIME_PART_VALUE[3] = {23, 59, 59};
+
+    void format_datetime(uint32_t* date_val) const;
 
 private:
     static uint8_t calc_week(const uint32_t& day_nr, const uint16_t& year, const uint8_t& month,
diff --git a/regression-test/data/query_p0/sql_functions/cast_function/test_cast_function.out b/regression-test/data/query_p0/sql_functions/cast_function/test_cast_function.out
index 410a0dca01..1fbc5e6502 100644
--- a/regression-test/data/query_p0/sql_functions/cast_function/test_cast_function.out
+++ b/regression-test/data/query_p0/sql_functions/cast_function/test_cast_function.out
@@ -17,6 +17,18 @@
 -- !sql --
 20
 
--- !sql_null_cast_bitmap --
-true
+-- !select1 --
+0	2022-12-01T22:23:24.123	2022-12-01 22:23:24.123	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.123	78.12345678	78.12346	78.12345678
+1	2022-12-01T22:23:24.123	2022-12-01 22:23:24.123456789	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.123	78.12345678	78.12346	78.12345678
+2	2022-12-01T22:23:24.123	2022-12-01 22:23:24.12341234	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.123	78.12341234	78.12341	78.12341234
+
+-- !select2 --
+0	2022-12-01T22:23:24.123	2022-12-01 22:23:24.123	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.123	78.123000000	78.12346	78.12346
+1	2022-12-01T22:23:24.123	2022-12-01 22:23:24.123	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.123	78.123000000	78.12346	78.12346
+2	2022-12-01T22:23:24.123	2022-12-01 22:23:24.123	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.123	78.123000000	78.12341	78.12341
+
+-- !select3 --
+0	2022-12-01 22:23:24.123	2022-12-01T22:23:24.123	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.12345678	78.12346	78.12345678	78.123457
+1	2022-12-01 22:23:24.123456789	2022-12-01T22:23:24.123460	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.12345678	78.12346	78.12345678	78.123457
+2	2022-12-01 22:23:24.12341234	2022-12-01T22:23:24.123410	2022-12-01	2022-12-01	2022-12-01	2022-12-01	78.12341234	78.12341	78.12341234	78.123412
 
diff --git a/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out b/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
index def023304e..4fc3d0d1f1 100644
--- a/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
+++ b/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
@@ -4,8 +4,8 @@
 2	2022-12-02T22:23:24.999	2022-12-02 22:23:24.999999
 
 -- !select2 --
-1	2022-12-01T22:23:24.999	2022-12-01T22:23:24.999
-2	2022-12-02T22:23:24.999	2022-12-02T22:23:24.999
+1	2022-12-01T22:23:24.999	2022-12-01T22:23:25
+2	2022-12-02T22:23:24.999	2022-12-02T22:23:25
 
 -- !select3 --
 2022-12-02T22:23:24.999	2022-12-02T22:23:23.999
diff --git a/regression-test/suites/query_p0/sql_functions/cast_function/test_cast_function.groovy b/regression-test/suites/query_p0/sql_functions/cast_function/test_cast_function.groovy
index 8dbec6ee91..4d0142811e 100644
--- a/regression-test/suites/query_p0/sql_functions/cast_function/test_cast_function.groovy
+++ b/regression-test/suites/query_p0/sql_functions/cast_function/test_cast_function.groovy
@@ -23,6 +23,42 @@ suite("test_cast_function") {
     qt_sql """ select cast (NULL AS CHAR(1)); """
     qt_sql """ select cast ('20190101' AS CHAR(2)); """
 
-    qt_sql_null_cast_bitmap """ select cast (case when BITMAP_EMPTY() is NULL then null else null end as bitmap) is NULL; """
+    def tableName = "test_cast_function_nullable"
+    sql "DROP TABLE IF EXISTS ${tableName}"
+    sql """
+        CREATE TABLE IF NOT EXISTS `${tableName}` (
+        `uid` int(11) NULL COMMENT "",
+        `datetimev2` datetimev2(3) NULL COMMENT "",
+        `datetimev2_str` varchar(30) NULL COMMENT "",
+        `datev2_val` datev2 NULL COMMENT "",
+        `datev2_str` varchar(30) NULL COMMENT "",
+        `date_val` date NULL COMMENT "",
+        `date_str` varchar(30) NULL COMMENT "",
+        `decimalv2_val` decimal(9,3) NULL COMMENT "",
+        `decimalv2_str` varchar(30) NULL COMMENT "",
+        `decimalv3_val` decimalv3(12,5) NULL COMMENT "",
+        `decimalv3_str` varchar(30) NULL COMMENT ""
+        ) ENGINE=OLAP
+    DUPLICATE KEY(`uid`)
+    COMMENT "OLAP"
+    DISTRIBUTED BY HASH(`uid`) BUCKETS 1
+    PROPERTIES (
+    "replication_allocation" = "tag.location.default: 1",
+    "in_memory" = "false",
+    "storage_format" = "V2"
+    )
+    """
+
+    sql """INSERT INTO ${tableName} values
+    (0,"2022-12-01 22:23:24.123",'2022-12-01 22:23:24.123','2022-12-01','2022-12-01','2022-12-01','2022-12-01','78.12345678','78.12345678','78.12345678','78.12345678'),
+    (1,"2022-12-01 22:23:24.123456789",'2022-12-01 22:23:24.123456789','2022-12-01','2022-12-01','2022-12-01','2022-12-01','78.12345678','78.12345678','78.12345678','78.12345678'),
+    (2,"2022-12-01 22:23:24.12341234",'2022-12-01 22:23:24.12341234','2022-12-01','2022-12-01','2022-12-01','2022-12-01','78.12341234','78.12341234','78.12341234','78.12341234')
+    """
+
+    qt_select1 "select * from ${tableName} order by uid"
+    // test cast date,datetimev2,decimalv2,decimalv3 to string
+    qt_select2 "select uid, datetimev2, cast(datetimev2 as string), datev2_val, cast(datev2_val as string), date_val, cast(date_val as string), decimalv2_val, cast(decimalv2_val as string),  decimalv3_val, cast(decimalv3_val as string) from ${tableName}  order by uid"
+    // test cast from string to date,datetimev2,decimalv2,decimalv3
+    qt_select3 "select uid, datetimev2_str, cast(datetimev2_str as datetimev2(5)), datev2_str, cast(datev2_str as datev2), date_str, cast(date_str as date), decimalv2_str, cast(decimalv2_str as decimal(9,5)),  decimalv3_str, cast(decimalv3_str as decimalv3(12,6)) from ${tableName}  order by uid"
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org