diff --git a/deps/oblib/src/lib/charset/ob_dtoa.cc b/deps/oblib/src/lib/charset/ob_dtoa.cc index 3233d0d63..a054bd085 100644 --- a/deps/oblib/src/lib/charset/ob_dtoa.cc +++ b/deps/oblib/src/lib/charset/ob_dtoa.cc @@ -388,60 +388,73 @@ inline bool is_whitespace(const char& c) { return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } +static std::errc ob_fast_strtod(const char *str, char **end, double *result) +{ + std::errc ret = std::errc(); + if (!(NULL != result + && end != NULL + && ((str != NULL && *end != NULL) || (str == NULL && *end == NULL)))) { + ret = std::errc::invalid_argument; + } else { + *result = 0.0; + int len = *end - str; + // skip leading and back spaces + int i = 0; + for (; i < len; ++i) { + if (!is_whitespace(str[i])) { + break; + } + } + if (i >= len || (i == len-1 && ('+' == str[i] || '-' == str[i]))) { + *end = (char *)str; + } else { + int j = len - 1; + for (; j >= i; j--) { + if (!is_whitespace(str[j])) { + break; + } + } + fast_float::from_chars_result ff_ret = fast_float::from_chars(str + i, str + j + 1, *result); + if (ff_ret.ec == std::errc()) { + *end = const_cast(ff_ret.ptr); + if (__builtin_isnan(*result) || __builtin_isinf(*result) || __builtin_isinf(-*result)) { + *end = (char *)str; + *result = 0.0; + } + } else { + ret = ff_ret.ec; + } + } + } + + return ret; +} + double ob_strtod(const char *str, char **end, int *error) { - char buf[DTOA_BUF_MAX_SIZE]; double res = 0.0; - if (!(end != NULL && ((str != NULL && *end != NULL) || - (str == NULL && *end == NULL)) && - error != NULL)) { - return 0.0; - } - int len = *end - str; - // skip leading and back spaces - int i = 0; - for (; i < len; ++i) { - if (!is_whitespace(str[i])) { - break; - } - } - if (i >= len || (i == len-1 && ('+' == str[i] || '-' == str[i]))) { - *end = (char *)str; - } else { - int j = len - 1; - for (; j >= i; j--) { - if (!is_whitespace(str[j])) { - break; - } - } - // The fast_float::from_chars function cannot handle leading '+' signs. - // For example, ObXmlUtil::to_number() might include a '+' for extract_xml expression. - if (i < len && '+' == str[i]) { - i ++; - } - fast_float::from_chars_result ret = fast_float::from_chars(str + i, str + j + 1, res); - *end = const_cast(ret.ptr); - if (ret.ec == std::errc::result_out_of_range) { - res= ob_strtod_int(str, end, error, buf, sizeof(buf)); + if (std::errc() != ob_fast_strtod(str, end, &res)) { + //rollback to call ob_strtod_int if failed to call fast strtod + if (!(end != NULL + && ((str != NULL && *end != NULL) || (str == NULL && *end == NULL)) + && error != NULL)) { + // do nothing + } else { + char buf[DTOA_BUF_MAX_SIZE]; + res = ob_strtod_int(str, end, error, buf, sizeof(buf)); if (*error != 0) { res = (res < 0 ? -DBL_MAX : DBL_MAX); } - // *error = EOVERFLOW; - // res = (res < 0 ? -DBL_MAX : DBL_MAX); - } - if (__builtin_isnan(res) || __builtin_isinf(res) || __builtin_isinf(-res)) { - *end = (char *)str; - res = 0.0; } } + return res; } - double ob_atof(const char *nptr) { int error; - const char *end= nptr+65535; + const char *end= nptr+65535; return (ob_strtod(nptr, (char**) &end, &error)); } diff --git a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/explicit_cast.result b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/explicit_cast.result index f79722115..dae7cfa35 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/explicit_cast.result +++ b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/explicit_cast.result @@ -664,4 +664,19 @@ select cast(a as double) from t1; | 0 | | -0 | +-------------------------+ +select cast('+-4' as double) from dual; ++-----------------------+ +| cast('+-4' as double) | ++-----------------------+ +| 0 | ++-----------------------+ +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: '+-4' +select cast('+4' as double) from dual; ++----------------------+ +| cast('+4' as double) | ++----------------------+ +| 4 | ++----------------------+ + drop table t1; diff --git a/tools/deploy/mysql_test/test_suite/static_engine/t/explicit_cast.test b/tools/deploy/mysql_test/test_suite/static_engine/t/explicit_cast.test index 0bf985bdb..8559bf554 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/t/explicit_cast.test +++ b/tools/deploy/mysql_test/test_suite/static_engine/t/explicit_cast.test @@ -178,4 +178,7 @@ select cast(a as float) from t1; select cast(a as double) from t1; --enable_warnings +select cast('+-4' as double) from dual; +select cast('+4' as double) from dual; + drop table t1;