From 676c105da85ebd73c38c13c1fbab2bd67b6d0a30 Mon Sep 17 00:00:00 2001 From: obdev Date: Tue, 6 Dec 2022 14:35:58 +0000 Subject: [PATCH] Fix bug about second and microsecond function and update cases --- .../src/lib/timezone/ob_time_convert.cpp | 58 ++++++++++--------- deps/oblib/src/lib/timezone/ob_time_convert.h | 7 ++- src/sql/engine/expr/ob_datum_cast.cpp | 34 ++++++----- src/sql/engine/expr/ob_expr_time.h | 8 ++- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/deps/oblib/src/lib/timezone/ob_time_convert.cpp b/deps/oblib/src/lib/timezone/ob_time_convert.cpp index 0c93f7f975..88d47c8e72 100644 --- a/deps/oblib/src/lib/timezone/ob_time_convert.cpp +++ b/deps/oblib/src/lib/timezone/ob_time_convert.cpp @@ -140,7 +140,6 @@ static const int32_t DAYS_PER_YEAR[2]= #define EPOCH_WDAY 4 // 1970-1-1 is thursday. #define LEAP_YEAR_COUNT(y) ((y) / 4 - (y) / 100 + (y) / 400) #define IS_LEAP_YEAR(y) ((((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) ? 1 : 0) -#define TIME_MAX_VAL (3020399 * 1000000LL) // 838:59:59 . #define YEAR_MAX_YEAR 2155 #define YEAR_MIN_YEAR 1901 #define YEAR_BASE_YEAR 1900 @@ -793,7 +792,7 @@ int ObTimeConverter::str_to_date(const ObString &str, int32_t &value, return ret; } -int ObTimeConverter::str_to_time(const ObString &str, int64_t &value, int16_t *scale) +int ObTimeConverter::str_to_time(const ObString &str, int64_t &value, int16_t *scale, const ObScale &time_scale) { int ret = OB_SUCCESS; ObTime ob_time(DT_TYPE_TIME); @@ -801,14 +800,14 @@ int ObTimeConverter::str_to_time(const ObString &str, int64_t &value, int16_t *s LOG_WARN("failed to convert string to time", K(ret), K(str)); if (OB_ERR_TRUNCATED_WRONG_VALUE == ret) { value = ob_time_to_time(ob_time); - time_overflow_trunc(value); + time_overflow_trunc(value, time_scale); if (DT_MODE_NEG & ob_time.mode_) { value = -value; } } } else { value = ob_time_to_time(ob_time); - ret = time_overflow_trunc(value); + ret = time_overflow_trunc(value, time_scale); if (DT_MODE_NEG & ob_time.mode_) { value = -value; } @@ -1710,39 +1709,45 @@ int ObTimeConverter::int_to_ob_time_with_date(int64_t int64, ObTime &ob_time, bo return ret; } -int ObTimeConverter::int_to_ob_time_without_date(int64_t int64, ObTime &ob_time) +int ObTimeConverter::int_to_ob_time_without_date(int64_t time_second, ObTime &ob_time, int64_t nano_second) { int ret = OB_SUCCESS; int32_t *parts = ob_time.parts_; ObDTMode mode = DT_TYPE_TIME; - if (int64 < 0) { + if (time_second < 0) { ob_time.mode_ |= DT_MODE_NEG; - if (INT64_MIN == int64) { - int64 = INT64_MAX; + if (INT64_MIN == time_second) { + time_second = INT64_MAX; } else { - int64 = -int64; + time_second = -time_second; } } - if (int64 / power_of_10[4] < power_of_10[6]) { + if (time_second / power_of_10[4] < power_of_10[6]) { // [H]HHMMSS, like 123:45:56. - parts[DT_SEC] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_MIN] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_HOUR] = static_cast(int64 % power_of_10[6]); - if (OB_FAIL(validate_time(ob_time))) { - LOG_WARN("time integer is invalid", K(ret), K(int64)); + if(nano_second) { + parts[DT_USEC] = static_cast((nano_second + 500) / power_of_10[3]); } - } else if (int64 / power_of_10[6] < power_of_10[8]) { + parts[DT_SEC] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_MIN] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_HOUR] = static_cast(time_second % power_of_10[6]); + if (OB_FAIL(validate_time(ob_time))) { + LOG_WARN("time integer is invalid", K(ret), K(time_second)); + } + } else if (time_second / power_of_10[6] < power_of_10[8]) { // HHHHMMDDHHMMSS. mode = DT_TYPE_DATETIME; - parts[DT_SEC] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_MIN] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_HOUR] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_MDAY] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_MON] = static_cast(int64 % power_of_10[2]); int64 /= power_of_10[2]; - parts[DT_YEAR] = static_cast(int64 % power_of_10[4]); + if(nano_second) { + parts[DT_USEC] = static_cast((nano_second + 500) / power_of_10[3]); + } + parts[DT_SEC] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_MIN] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_HOUR] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_MDAY] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_MON] = static_cast(time_second % power_of_10[2]); time_second /= power_of_10[2]; + parts[DT_YEAR] = static_cast(time_second % power_of_10[4]); apply_date_year2_rule(parts[DT_YEAR]); if (OB_FAIL(validate_datetime(ob_time, false, 0))) { - LOG_WARN("datetime is invalid or out of range", K(ret), K(int64)); + LOG_WARN("datetime is invalid or out of range", K(ret), K(time_second), K(nano_second)); } else if (ZERO_DATE != parts[DT_DATE]) { parts[DT_DATE] = ob_time_to_date(ob_time); } @@ -5362,10 +5367,11 @@ int ObTimeConverter::set_ob_time_year_may_conflict(ObTime &ob_time, int32_t &jul return ret; } -int ObTimeConverter::time_overflow_trunc(int64_t &value) +int ObTimeConverter::time_overflow_trunc(int64_t &value, const ObScale &time_scale) { int ret = OB_SUCCESS; - if (value > TIME_MAX_VAL) { + int64_t increment = (6 == time_scale) ? 999999 : 0; + if (value > (TIME_MAX_VAL + increment)) { // we need some ob error codes that map to ER_TRUNCATED_WRONG_VALUE, // so we get OB_INVALID_DATE_FORMAT / OB_INVALID_DATE_VALUE / OB_ERR_TRUNCATED_WRONG_VALUE. // another requirement comes from cast function in ob_obj_cast.cpp is this time object will be @@ -5373,7 +5379,7 @@ int ObTimeConverter::time_overflow_trunc(int64_t &value) // so we get the ONLY one: OB_ERR_TRUNCATED_WRONG_VALUE, because the other two will direct to // ZERO_VAL of the temporal types, like cast 'abc' or '1998-76-54' to date. ret = OB_ERR_TRUNCATED_WRONG_VALUE; - value = TIME_MAX_VAL; + value = TIME_MAX_VAL + increment; } return ret; } diff --git a/deps/oblib/src/lib/timezone/ob_time_convert.h b/deps/oblib/src/lib/timezone/ob_time_convert.h index 05b5a957a6..337e759ed4 100644 --- a/deps/oblib/src/lib/timezone/ob_time_convert.h +++ b/deps/oblib/src/lib/timezone/ob_time_convert.h @@ -157,6 +157,7 @@ extern const int64_t USECS_PER_MIN; #define MYSQL_TIMESTAMP_MIN_VAL -62167046400000000 #define ORACLE_DATETIME_MIN_VAL -62135596800000000 //start from '0001-1-1 00:00:00' #define TIME_MAX_HOUR 838 +#define TIME_MAX_VAL (3020399 * 1000000LL) // 838:59:59 . struct ObIntervalLimit { static const ObOracleTimeLimiter YEAR; @@ -405,7 +406,7 @@ public: static int str_is_date_format(const ObString &str, bool &date_flag); static int str_to_date(const ObString &str, int32_t &value, const ObDateSqlMode date_sql_mode = 0); - static int str_to_time(const ObString &str, int64_t &value, int16_t *scale = NULL); + static int str_to_time(const ObString &str, int64_t &value, int16_t *scale = NULL, const ObScale &time_scale = 0); static int str_to_year(const ObString &str, uint8_t &value); static int str_to_interval(const ObString &str, ObDateUnitType unit_type, int64_t &value); // int / double / string <- datetime(timestamp) / date / time / year. @@ -475,7 +476,7 @@ public: // int / string -> ObTime / ObInterval <- datetime(timestamp) / date / time / year. static int int_to_ob_time_with_date(int64_t int64, ObTime &ob_time, bool is_dayofmonth, const ObDateSqlMode date_sql_mode); - static int int_to_ob_time_without_date(int64_t int64, ObTime &ob_time); + static int int_to_ob_time_without_date(int64_t time_second, ObTime &ob_time, int64_t nano_second = 0); static int str_to_ob_time_with_date(const ObString &str, ObTime &ob_time, int16_t *scale, const bool is_dayofmonth, const ObDateSqlMode date_sql_mode); static int str_to_ob_time_without_date(const ObString &str, ObTime &ob_time, int16_t *scale = NULL); @@ -569,7 +570,7 @@ public: static int set_ob_time_part_directly(ObTime &ob_time, int64_t &conflict_bitset, const int64_t part_offset, const int32_t part_value); static int set_ob_time_part_may_conflict(ObTime &ob_time, int64_t &conflict_bitset, const int64_t part_offset, const int32_t part_value); static int32_t calc_max_name_length(const ObTimeConstStr names[], const int64_t size); - static int time_overflow_trunc(int64_t &value); + static int time_overflow_trunc(int64_t &value, const ObScale &time_scale = 0); static void round_datetime(int16_t scale, int64_t &value); static ObOTimestampData round_otimestamp(const int16_t scale, const ObOTimestampData &in_ot_data); static int round_interval_ds(const ObScale scale, ObIntervalDSValue &value); diff --git a/src/sql/engine/expr/ob_datum_cast.cpp b/src/sql/engine/expr/ob_datum_cast.cpp index 2ca98d66d9..8ad1cf948b 100644 --- a/src/sql/engine/expr/ob_datum_cast.cpp +++ b/src/sql/engine/expr/ob_datum_cast.cpp @@ -32,7 +32,6 @@ namespace oceanbase namespace sql { using namespace oceanbase::common; - //// common function and macro #define CAST_FUNC_NAME(intype, outtype) \ int intype##_##outtype(const sql::ObExpr &expr, \ @@ -959,7 +958,8 @@ static OB_INLINE int common_string_time(const ObExpr &expr, int warning = OB_SUCCESS; int64_t out_val = 0; ObScale res_scale; // useless - if (CAST_FAIL(ObTimeConverter::str_to_time(in_str, out_val, &res_scale))) { + ObScale time_scale = expr.datum_meta_.scale_; + if (CAST_FAIL(ObTimeConverter::str_to_time(in_str, out_val, &res_scale, time_scale))) { LOG_WARN("str_to_time failed", K(ret), K(in_str)); } else { SET_RES_TIME(out_val); @@ -9234,7 +9234,7 @@ int ob_datum_to_ob_time_without_date(const ObDatum &datum, const ObObjType type, LOG_WARN("int to ob time without date failed", K(ret)); } else { //mysql中intTC转time时,如果hour超过838,那么time应该为null,而不是最大值。 - const int64_t time_max_val = 3020399 * 1000000LL; // 838:59:59 . + const int64_t time_max_val = TIME_MAX_VAL; // 838:59:59 . int64_t value = ObTimeConverter::ob_time_to_time(ob_time); if (value > time_max_val) { ret = OB_INVALID_DATE_VALUE; @@ -9279,21 +9279,23 @@ int ob_datum_to_ob_time_without_date(const ObDatum &datum, const ObObjType type, break; } case ObNumberTC: { - number::ObNumber num(datum.get_number()); - const char *num_format = num.format(); - if (OB_ISNULL(num_format)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("number format value is null", K(ret)); + int64_t int_part = 0; + int64_t dec_part = 0; + const number::ObNumber num(datum.get_number()); + if (!num.is_int_parts_valid_int64(int_part, dec_part)) { + ret = OB_INVALID_DATE_FORMAT; + LOG_WARN("invalid date format", K(ret), K(num)); } else { - ObString num_str(num_format); - if (OB_FAIL(ObTimeConverter::str_to_ob_time_without_date(num_str, ob_time))) { - LOG_WARN("str to obtime without date failed", K(ret)); + if (OB_FAIL(ObTimeConverter::int_to_ob_time_without_date(int_part, ob_time, dec_part))) { + LOG_WARN("int to ob time without date failed", K(ret)); } else { - int64_t value = ObTimeConverter::ob_time_to_time(ob_time); - int64_t tmp_value = value; - ObTimeConverter::time_overflow_trunc(value); - if (value != tmp_value) { - ObTimeConverter::time_to_ob_time(value, ob_time); + if ((!ob_time.parts_[DT_YEAR]) && (!ob_time.parts_[DT_MON]) && (!ob_time.parts_[DT_MDAY])) { + //mysql中intTC转time时,如果超过838:59:59.999999,那么time应该为null,而不是最大值。 + const int64_t time_max_val = TIME_MAX_VAL + 999999; // 838:59:59.999999 . + int64_t value = ObTimeConverter::ob_time_to_time(ob_time); + if(value > time_max_val) { + ret = OB_INVALID_DATE_VALUE; + } } } } diff --git a/src/sql/engine/expr/ob_expr_time.h b/src/sql/engine/expr/ob_expr_time.h index 38541d59e4..0efa1e511d 100644 --- a/src/sql/engine/expr/ob_expr_time.h +++ b/src/sql/engine/expr/ob_expr_time.h @@ -116,8 +116,10 @@ inline int ObExprSecond::calc_result_type1(ObExprResType &type, type.set_precision(4); type.set_scale(0); common::ObObjTypeClass tc1 = ob_obj_type_class(type1.get_type()); - if ((common::ObEnumSetTC == tc1) || (common::ObFloatTC == tc1) || (common::ObDoubleTC == tc1)) { + if ((common::ObEnumSetTC == tc1)) { type1.set_calc_type_default_varchar(); + } else if ((common::ObFloatTC == tc1) || (common::ObDoubleTC == tc1)) { + type1.set_calc_type(common::ObNumberType); } return common::OB_SUCCESS; } @@ -144,8 +146,10 @@ inline int ObExprMicrosecond::calc_result_type1(ObExprResType &type, type.set_precision(4); type.set_scale(0); common::ObObjTypeClass tc1 = ob_obj_type_class(type1.get_type()); - if ((common::ObEnumSetTC == tc1) || (common::ObFloatTC == tc1) || (common::ObDoubleTC == tc1)) { + if ((common::ObEnumSetTC == tc1)) { type1.set_calc_type_default_varchar(); + } else if ((common::ObFloatTC == tc1) || (common::ObDoubleTC == tc1)) { + type1.set_calc_type(common::ObNumberType); } return common::OB_SUCCESS; }