diff --git a/deps/oblib/src/common/object/ob_obj_compare.cpp b/deps/oblib/src/common/object/ob_obj_compare.cpp index e4735f7b6..8389e9846 100644 --- a/deps/oblib/src/common/object/ob_obj_compare.cpp +++ b/deps/oblib/src/common/object/ob_obj_compare.cpp @@ -301,6 +301,9 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, : CR_EQ; \ } +#define IS_FIXED_DOUBLE_CMP obj1.is_fixed_double() && obj2.is_fixed_double() && \ + lib::is_mysql_mode() + #define DEFINE_CMP_OP_FUNC_REAL_REAL_EQ(real1_tc, real1_type, real2_tc, real2_type) \ template <> inline \ int ObObjCmpFuncs::cmp_op_func(const ObObj &obj1, \ @@ -320,6 +323,8 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_FALSE;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + ret = fixed_double_cmp(obj1, obj2) == 0 ? CR_TRUE : CR_FALSE;\ } else {\ ret = (l_num == r_num ? CR_TRUE : CR_FALSE);\ }\ @@ -345,6 +350,8 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_TRUE;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + ret = fixed_double_cmp(obj1, obj2) <= 0 ? CR_TRUE : CR_FALSE;\ } else {\ ret = (l_num <= r_num ? CR_TRUE : CR_FALSE);\ }\ @@ -370,6 +377,8 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_TRUE;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + ret = fixed_double_cmp(obj1, obj2) < 0 ? CR_TRUE : CR_FALSE;\ } else {\ ret = (l_num < r_num ? CR_TRUE : CR_FALSE);\ }\ @@ -395,6 +404,8 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_FALSE;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + ret = fixed_double_cmp(obj1, obj2) >= 0 ? CR_TRUE : CR_FALSE;\ } else {\ ret = (l_num >= r_num ? CR_TRUE : CR_FALSE);\ }\ @@ -420,6 +431,8 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_FALSE;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + ret = fixed_double_cmp(obj1, obj2) > 0 ? CR_TRUE : CR_FALSE;\ } else {\ ret = (l_num > r_num ? CR_TRUE : CR_FALSE);\ }\ @@ -443,6 +456,8 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_TRUE;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + ret = fixed_double_cmp(obj1, obj2) != 0 ? CR_TRUE : CR_FALSE;\ } else {\ ret = (l_num != r_num ? CR_TRUE : CR_FALSE);\ }\ @@ -468,6 +483,9 @@ bool is_calc_with_end_space(ObObjType type1, ObObjType type2, } else {\ ret = CR_LT;\ }\ + } else if (IS_FIXED_DOUBLE_CMP) {\ + int cmp_res = fixed_double_cmp(obj1, obj2);\ + ret = cmp_res == 0 ? CR_EQ : (cmp_res < 0 ? CR_LT : CR_GT);\ } else {\ ret = l_num == r_num ? CR_EQ : (l_num < r_num ? CR_LT : CR_GT);\ }\ diff --git a/deps/oblib/src/common/object/ob_obj_compare.h b/deps/oblib/src/common/object/ob_obj_compare.h index 0be016457..014ffec8b 100644 --- a/deps/oblib/src/common/object/ob_obj_compare.h +++ b/deps/oblib/src/common/object/ob_obj_compare.h @@ -237,6 +237,36 @@ public: ObCmpOp cmp_op, obj_cmp_func_nullsafe &func); + OB_INLINE static int fixed_double_cmp(const ObObj &obj1, const ObObj &obj2) + { + int ret = 0; + const double P[] = + { + 5/1e000, 5/1e001, 5/1e002, 5/1e003, 5/1e004, 5/1e005, 5/1e006, 5/1e007, + 5/1e008, 5/1e009, 5/1e010, 5/1e011, 5/1e012, 5/1e013, 5/1e014, 5/1e015, + 5/1e016, 5/1e017, 5/1e018, 5/1e019, 5/1e020, 5/1e021, 5/1e022, 5/1e023, + 5/1e024, 5/1e025, 5/1e026, 5/1e027, 5/1e028, 5/1e029, 5/1e030, 5/1e031 + }; + // Compatible with mysql, the condition for judging whether two fixed double are equal + // is that their fabs is less than 5 divided by the log10 of the maximum scale plus 1. + const int cmp_scale = MAX(obj1.get_scale(), obj2.get_scale()) + 1; + double p = 0; + if (cmp_scale <= 0 || cmp_scale > OB_NOT_FIXED_SCALE) { + p = P[OB_NOT_FIXED_SCALE]; + COMMON_LOG(ERROR, "not fixed obj", K(obj1), K(obj2), K(lbt())); + } else { + p = P[cmp_scale]; + } + const double l = obj1.get_double(); + const double r = obj2.get_double(); + if (l == r || fabs(l - r) < p) { + ret = 0; + } else { + ret = (l < r ? -1 : 1); + } + return ret; + } + enum ObCmpRes { // for bool. diff --git a/deps/oblib/src/common/object/ob_obj_funcs.h b/deps/oblib/src/common/object/ob_obj_funcs.h index acae033bb..f70b374fe 100644 --- a/deps/oblib/src/common/object/ob_obj_funcs.h +++ b/deps/oblib/src/common/object/ob_obj_funcs.h @@ -288,9 +288,31 @@ template <> v = 0.0; \ } else if (isnan(v)) { \ v = NAN; \ - } \ + } else if (obj.is_fixed_double() && lib::is_mysql_mode()) { \ + char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0}; \ + int64_t len = ob_fcvt(v, static_cast(obj.get_scale()), sizeof(buf) - 1, buf, NULL); \ + return murmurhash(buf, static_cast(len), ret); \ + } \ return murmurhash(&v, sizeof(obj.get_##TYPE()), ret); \ } \ + template \ + struct ObjHashCalculator \ + { \ + static uint64_t calc_hash_value(const ObObj &obj, const uint64_t hash) { \ + VTYPE v = obj.get_##TYPE(); \ + HTYPE v2 = v; \ + if (0.0 == v2) { \ + v2 = 0.0; \ + } else if (isnan(v2)) { \ + v2 = NAN; \ + } else if (obj.is_fixed_double() && lib::is_mysql_mode()) { \ + char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0}; \ + int64_t len = ob_fcvt(v2, static_cast(obj.get_scale()), sizeof(buf) - 1, buf, NULL); \ + return T::hash(buf, static_cast(len), hash); \ + } \ + return T::hash(&v2, sizeof(v2), hash); \ + } \ + }; \ template \ struct ObjHashCalculator \ { \ diff --git a/deps/oblib/src/common/object/ob_object.h b/deps/oblib/src/common/object/ob_object.h index 9c6873513..d1f450a59 100644 --- a/deps/oblib/src/common/object/ob_object.h +++ b/deps/oblib/src/common/object/ob_object.h @@ -1193,6 +1193,8 @@ public: OB_INLINE bool is_blob_locator() const { return meta_.is_blob_locator(); } OB_INLINE bool is_clob_locator() const { return meta_.is_clob_locator(); } OB_INLINE bool is_lob_locator() const { return meta_.is_lob_locator(); } + OB_INLINE bool is_fixed_double() const { return meta_.is_double() && + SCALE_UNKNOWN_YET < meta_.get_scale() && OB_MAX_DOUBLE_FLOAT_SCALE >= meta_.get_scale(); } OB_INLINE bool is_string_or_lob_locator_type() const { return meta_.is_string_or_lob_locator_type(); } diff --git a/deps/oblib/src/common/rowkey/ob_rowkey.cpp b/deps/oblib/src/common/rowkey/ob_rowkey.cpp index 24926ab33..c17b87063 100644 --- a/deps/oblib/src/common/rowkey/ob_rowkey.cpp +++ b/deps/oblib/src/common/rowkey/ob_rowkey.cpp @@ -18,6 +18,7 @@ #include "common/rowkey/ob_rowkey_info.h" #include "common/object/ob_object.h" #include "common/object/ob_obj_type.h" +#include "common/object/ob_obj_compare.h" namespace oceanbase { @@ -104,7 +105,13 @@ int ObRowkey::equal(const ObRowkey &rhs, bool &is_equal) const is_equal = (obj.v_.float_ == rhs_obj.v_.float_); break; case ObDoubleTC: - is_equal = (obj.v_.double_ == rhs_obj.v_.double_); + { + if (lib::is_mysql_mode() && obj.is_fixed_double() && rhs_obj.is_fixed_double()) { + is_equal = ObObjCmpFuncs::fixed_double_cmp(obj, rhs_obj) == 0; + } else { + is_equal = (obj.v_.double_ == rhs_obj.v_.double_); + } + } break; case ObOTimestampTC: is_equal = (obj.time_ctx_.desc_ == rhs_obj.time_ctx_.desc_ && obj.v_.datetime_ == rhs_obj.v_.datetime_); @@ -203,7 +210,13 @@ bool ObRowkey::simple_equal(const ObRowkey &rhs) const ret = (obj.v_.float_ == rhs_obj.v_.float_); break; case ObDoubleTC: - ret = (obj.v_.double_ == rhs_obj.v_.double_); + { + if (lib::is_mysql_mode() && obj.is_fixed_double() && rhs_obj.is_fixed_double()) { + ret = ObObjCmpFuncs::fixed_double_cmp(obj, rhs_obj) == 0; + } else { + ret = (obj.v_.double_ == rhs_obj.v_.double_); + } + } break; case ObOTimestampTC: ret = (obj.time_ctx_.desc_ == rhs_obj.time_ctx_.desc_ && obj.v_.datetime_ == rhs_obj.v_.datetime_); diff --git a/deps/oblib/src/lib/ob_define.h b/deps/oblib/src/lib/ob_define.h index 9b3115e88..95eb8b8b1 100644 --- a/deps/oblib/src/lib/ob_define.h +++ b/deps/oblib/src/lib/ob_define.h @@ -1583,6 +1583,7 @@ const double OB_PRECISION_BINARY_TO_DECIMAL_FACTOR = 0.30103; const double OB_PRECISION_DECIMAL_TO_BINARY_FACTOR = 3.32193; const int64_t OB_MAX_DOUBLE_FLOAT_SCALE = 30; +const int64_t OB_NOT_FIXED_SCALE = OB_MAX_DOUBLE_FLOAT_SCALE + 1; const int64_t OB_MAX_DOUBLE_FLOAT_PRECISION = 53;//why?? mysql is 255 TODO::@yanhua const int64_t OB_MAX_FLOAT_PRECISION = 24; const int64_t OB_MAX_INTEGER_DISPLAY_WIDTH = 255; //TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT diff --git a/deps/oblib/src/rpc/obmysql/ob_mysql_util.h b/deps/oblib/src/rpc/obmysql/ob_mysql_util.h index a8adb070f..9598a79bf 100644 --- a/deps/oblib/src/rpc/obmysql/ob_mysql_util.h +++ b/deps/oblib/src/rpc/obmysql/ob_mysql_util.h @@ -431,6 +431,7 @@ public: const common::ObLobLocator &lob_locator, int64_t &pos); static int json_cell_str(char *buf, const int64_t len, const ObString &val, int64_t &pos); static int geometry_cell_str(char *buf, const int64_t len, const ObString &val, int64_t &pos); + static inline int16_t float_length(const int16_t scale); public: static const uint64_t NULL_; @@ -737,6 +738,14 @@ void ObMySQLUtil::get_uint8(char *&pos, uint64_t &v) } } +/* + * get precision for double type, keep same with MySQL + */ +int16_t ObMySQLUtil::float_length(const int16_t scale) +{ + return (scale >= 0 && scale <= OB_MAX_DOUBLE_FLOAT_SCALE) ? DBL_DIG + 2 + scale : DBL_DIG + 8; +} + } // namespace obmysql } // namespace oceanbase diff --git a/src/share/datum/ob_datum_cmp_func_def.h b/src/share/datum/ob_datum_cmp_func_def.h index 6efbdc50e..78ffbb49f 100644 --- a/src/share/datum/ob_datum_cmp_func_def.h +++ b/src/share/datum/ob_datum_cmp_func_def.h @@ -120,6 +120,32 @@ struct ObDatumTCCmp : public ObDefined<> } }; +template +struct ObFixedDoubleCmp: public ObDefined<> +{ + constexpr static double LOG_10[] = + { + 1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, + 1e008, 1e009, 1e010, 1e011, 1e012, 1e013, 1e014, 1e015, + 1e016, 1e017, 1e018, 1e019, 1e020, 1e021, 1e022, 1e023, + 1e024, 1e025, 1e026, 1e027, 1e028, 1e029, 1e030, 1e031 + }; + constexpr static double P = 5 / LOG_10[SCALE + 1]; + inline static int cmp(const ObDatum &l_datum, const ObDatum &r_datum) + { + int ret = 0; + const double l = l_datum.get_double(); + const double r = r_datum.get_double(); + if (l == r || fabs(l - r) < P) { + ret = 0; + } else { + ret = (l < r ? -1 : 1); + } + return ret; + } +}; + + template <> struct ObDatumTCCmp : public ObDatumTCCmp { diff --git a/src/share/datum/ob_datum_funcs.cpp b/src/share/datum/ob_datum_funcs.cpp index bb45c690c..6b9658ce2 100644 --- a/src/share/datum/ob_datum_funcs.cpp +++ b/src/share/datum/ob_datum_funcs.cpp @@ -76,6 +76,24 @@ struct ObNullSafeDatumStrCmp } }; +template +struct ObNullSafeFixedDoubleCmp +{ + inline static int cmp(const ObDatum &l, const ObDatum &r) { + int ret = 0; + if (OB_UNLIKELY(l.is_null()) && OB_UNLIKELY(r.is_null())) { + ret = 0; + } else if (OB_UNLIKELY(l.is_null())) { + ret = NULL_FIRST ? -1 : 1; + } else if (OB_UNLIKELY(r.is_null())) { + ret = NULL_FIRST ? 1 : -1; + } else { + ret = datum_cmp::ObFixedDoubleCmp::cmp(l, r); + } + return ret; + } +}; + static ObDatumCmpFuncType NULLSAFE_TYPE_CMP_FUNCS[ObMaxType][ObMaxType][2]; // init type type compare function array template @@ -153,9 +171,24 @@ struct InitStrCmpArray bool g_str_cmp_array_inited = ObArrayConstIniter::init(); +static ObDatumCmpFuncType FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE][2]; +template +struct InitFixedDoubleCmpArray +{ + static void init_array() + { + auto &funcs = FIXED_DOUBLE_CMP_FUNCS; + funcs[X][0] = ObNullSafeFixedDoubleCmp(X), false>::cmp; + funcs[X][1] = ObNullSafeFixedDoubleCmp(X), true>::cmp; + } +}; + +bool g_fixed_double_cmp_array_inited = + ObArrayConstIniter::init(); + ObDatumCmpFuncType ObDatumFuncs::get_nullsafe_cmp_func( const ObObjType type1, const ObObjType type2, const ObCmpNullPos null_pos, - const ObCollationType cs_type, const bool is_oracle_mode) { + const ObCollationType cs_type, const ObScale max_scale, const bool is_oracle_mode) { OB_ASSERT(type1 >= ObNullType && type1 < ObMaxType); OB_ASSERT(type2 >= ObNullType && type2 < ObMaxType); OB_ASSERT(cs_type > CS_TYPE_INVALID && cs_type < CS_TYPE_MAX); @@ -163,7 +196,10 @@ ObDatumCmpFuncType ObDatumFuncs::get_nullsafe_cmp_func( ObDatumCmpFuncType func_ptr = NULL; int null_pos_idx = NULL_LAST == null_pos ? 0 : 1; - if (!is_string_type(type1) || !is_string_type(type2)) { + if (!is_oracle_mode && ob_is_double_type(type1) && ob_is_double_type(type1) + && max_scale > SCALE_UNKNOWN_YET && max_scale < OB_NOT_FIXED_SCALE) { + func_ptr = FIXED_DOUBLE_CMP_FUNCS[max_scale][null_pos_idx]; + } else if (!is_string_type(type1) || !is_string_type(type2)) { func_ptr = NULLSAFE_TYPE_CMP_FUNCS[type1][type2][null_pos_idx]; } else { int64_t calc_with_end_space_idx = @@ -263,6 +299,19 @@ struct DatumStrHashCalculator : public DefHash } }; +template +struct DatumFixedDoubleHashCalculator : public DefHashMethod +{ + static uint64_t calc_datum_hash(const ObDatum &datum, const uint64_t seed) + { + // format fixed double to string first, then calc hash value of the string + const double d_val = datum.get_double(); + char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0}; + int64_t length = ob_fcvt(d_val, static_cast(SCALE), sizeof(buf) - 1, buf, NULL); + return T::hash(buf, static_cast(length), seed); + } +}; + template struct VectorIter { @@ -417,13 +466,37 @@ struct InitBasicStrFuncArray } }; +static ObExprBasicFuncs FIXED_DOUBLE_BASIC_FUNCS[OB_NOT_FIXED_SCALE]; +template +struct InitFixedDoubleBasicFuncArray +{ + template + using Hash = DefHashFunc(X), T>>; + static void init_array() + { + auto &basic_funcs = FIXED_DOUBLE_BASIC_FUNCS; + basic_funcs[X].default_hash_ = Hash::hash; + basic_funcs[X].default_hash_batch_= Hash::hash_batch; + basic_funcs[X].murmur_hash_ = Hash::hash; + basic_funcs[X].murmur_hash_batch_ = Hash::hash_batch; + basic_funcs[X].xx_hash_ = Hash::hash; + basic_funcs[X].xx_hash_batch_ = Hash::hash_batch; + basic_funcs[X].wy_hash_ = Hash::hash; + basic_funcs[X].wy_hash_batch_ = Hash::hash_batch; + basic_funcs[X].null_first_cmp_ = ObNullSafeFixedDoubleCmp(X), true>::cmp; + basic_funcs[X].null_last_cmp_ = ObNullSafeFixedDoubleCmp(X), false>::cmp; + } +}; bool g_basic_funcs_array_inited = ObArrayConstIniter::init(); bool g_basic_str_array_inited = Ob2DArrayConstIniter::init(); +bool g_fixed_double_basic_func_array_inited = + ObArrayConstIniter::init(); ObExprBasicFuncs* ObDatumFuncs::get_basic_func(const ObObjType type, const ObCollationType cs_type, - const bool is_oracle_mode) + const ObScale scale, + const bool is_oracle_mode) { ObExprBasicFuncs *res = NULL; if ((type >= ObNullType && type < ObMaxType)) { @@ -437,6 +510,9 @@ ObExprBasicFuncs* ObDatumFuncs::get_basic_func(const ObObjType type, bool calc_end_space = false; bool is_lob_locator = true; res = &EXPR_BASIC_STR_FUNCS[cs_type][calc_end_space][is_lob_locator]; + } else if (!is_oracle_mode && ob_is_double_type(type) && + scale > SCALE_UNKNOWN_YET && scale < OB_NOT_FIXED_SCALE) { + res = &FIXED_DOUBLE_BASIC_FUNCS[scale]; } else { res = &EXPR_BASIC_FUNCS[type]; } @@ -475,6 +551,12 @@ REG_SER_FUNC_ARRAY(OB_SFA_DATUM_NULLSAFE_STR_CMP, NULLSAFE_STR_CMP_FUNCS, sizeof(NULLSAFE_STR_CMP_FUNCS) / sizeof(void*)); +static_assert(OB_NOT_FIXED_SCALE * 2 == sizeof(FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), + "unexpected size"); +REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_NULLSAFE_CMP, + FIXED_DOUBLE_CMP_FUNCS, + sizeof(FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); + // When new function add to ObExprBasicFuncs, EXPR_BASIC_FUNCS should split into // multi arrays for register. struct ExprBasicFuncSerPart1 @@ -510,6 +592,8 @@ static ExprBasicFuncSerPart1 EXPR_BASIC_FUNCS_PART1[ObMaxType]; static ExprBasicFuncSerPart2 EXPR_BASIC_FUNCS_PART2[ObMaxType]; static ExprBasicFuncSerPart1 EXPR_BASIC_STR_FUNCS_PART1[CS_TYPE_MAX][2][2]; static ExprBasicFuncSerPart2 EXPR_BASIC_STR_FUNCS_PART2[CS_TYPE_MAX][2][2]; +static ExprBasicFuncSerPart1 EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART1[OB_NOT_FIXED_SCALE]; +static ExprBasicFuncSerPart2 EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART2[OB_NOT_FIXED_SCALE]; bool split_basic_func_for_ser(void) { @@ -523,6 +607,10 @@ bool split_basic_func_for_ser(void) reinterpret_cast(EXPR_BASIC_STR_FUNCS_PART2)[i].from( reinterpret_cast(EXPR_BASIC_STR_FUNCS)[i]); } + for (int64_t i = 0; i < sizeof(FIXED_DOUBLE_BASIC_FUNCS)/sizeof(ObExprBasicFuncs); i++) { + EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART1[i].from(FIXED_DOUBLE_BASIC_FUNCS[i]); + EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART2[i].from(FIXED_DOUBLE_BASIC_FUNCS[i]); + } return true; } bool g_split_basic_func_for_ser = split_basic_func_for_ser(); @@ -547,5 +635,14 @@ REG_SER_FUNC_ARRAY(OB_SFA_EXPR_STR_BASIC_PART2, EXPR_BASIC_STR_FUNCS_PART2, sizeof(EXPR_BASIC_STR_FUNCS_PART2) / sizeof(void *)); +static_assert(OB_NOT_FIXED_SCALE * 10 == sizeof(FIXED_DOUBLE_BASIC_FUNCS) / sizeof(void *), + "unexpected size"); +REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_BASIC_PART1, + EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART1, + sizeof(EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART1) / sizeof(void *)); +REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_BASIC_PART2, + EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART2, + sizeof(EXPR_BASIC_FIXED_DOUBLE_FUNCS_PART2) / sizeof(void *)); + } // end namespace sql } // end namespace oceanbase diff --git a/src/share/datum/ob_datum_funcs.h b/src/share/datum/ob_datum_funcs.h index 76d19c9cb..ed98ef9a4 100644 --- a/src/share/datum/ob_datum_funcs.h +++ b/src/share/datum/ob_datum_funcs.h @@ -32,6 +32,7 @@ public: const ObObjType type2, const ObCmpNullPos null_pos, const ObCollationType cs_type, + const ObScale max_scale, const bool is_oracle_mode); static bool is_string_type(const ObObjType type); static bool is_json(const ObObjType type); @@ -39,8 +40,17 @@ public: static bool is_varying_len_char_type(const ObObjType type, const ObCollationType cs_type) { return (type == ObNVarchar2Type || (type == ObVarcharType && cs_type != CS_TYPE_BINARY)); } + static ObScale max_scale(const ObScale s1, const ObScale s2) + { + ObScale max_scale = SCALE_UNKNOWN_YET; + if (s1 != SCALE_UNKNOWN_YET && s2 != SCALE_UNKNOWN_YET) { + max_scale = MAX(s1, s2); + } + return max_scale; + } static sql::ObExprBasicFuncs* get_basic_func(const ObObjType type, const ObCollationType cs_type, + const ObScale scale = SCALE_UNKNOWN_YET, const bool is_oracle_mode = lib::is_oracle_mode()); }; diff --git a/src/share/object/ob_obj_cast_util.h b/src/share/object/ob_obj_cast_util.h index 751fd58f5..503337d8f 100644 --- a/src/share/object/ob_obj_cast_util.h +++ b/src/share/object/ob_obj_cast_util.h @@ -203,6 +203,15 @@ int check_convert_str_err(const char *str, const int32_t len, const int err, const ObCollationType &in_cs_type); + +// decimal(aka NumberType) cast to double/float precision increment. If it is an unsigned decimal, +// don’t need to increment precision, otherwise increment 1 to cover sign bit. If scale is +// equal to 0, don’t need to increment precision, otherwise increment 1 to cover dot bit. +inline int16_t decimal_to_double_precision_inc(const ObObjType type, const ObScale s) +{ + return ((type == ObUNumberType) ? 0 : 1) + ((s > 0) ? 1 : 0); +} + } // end namespace common } // end namespace oceanbase diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 8f24f3d89..ded0f4db0 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -1121,6 +1121,7 @@ int ObStaticEngineCG::generate_spec( expr->datum_meta_.type_, NULL_LAST,//这里null last还是first无所谓 expr->datum_meta_.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); ObHashFunc hash_func; hash_func.hash_func_ = expr->basic_funcs_->murmur_hash_; @@ -1254,6 +1255,7 @@ int ObStaticEngineCG::generate_hash_set_spec(ObLogSet &op, ObHashSetSpec &spec) expr->datum_meta_.type_, field_collation.null_pos_, field_collation.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); ObHashFunc hash_func; hash_func.hash_func_ = expr->basic_funcs_->murmur_hash_; @@ -1423,6 +1425,7 @@ int ObStaticEngineCG::generate_merge_set_spec(ObLogSet &op, ObMergeSetSpec &spec expr->datum_meta_.type_, field_collation.null_pos_, field_collation.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); if (OB_ISNULL(cmp_func.cmp_func_)) { ret = OB_ERR_UNEXPECTED; @@ -1595,6 +1598,7 @@ int ObStaticEngineCG::fill_sort_funcs( expr->datum_meta_.type_, sort_collation.null_pos_, sort_collation.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); if (OB_ISNULL(cmp_func.cmp_func_)) { ret = OB_ERR_UNEXPECTED; @@ -3759,6 +3763,7 @@ int ObStaticEngineCG::generate_pump_exprs(ObLogJoin &op, ObNLConnectBySpecBase & expr->datum_meta_.type_, NULL_LAST,//这里null last还是first无所谓 expr->datum_meta_.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); if (OB_ISNULL(cmp_func.cmp_func_)) { ret = OB_ERR_UNEXPECTED; @@ -4002,8 +4007,9 @@ int ObStaticEngineCG::generate_join_spec(ObLogJoin &op, ObJoinSpec &spec) ObDatumMeta &r = equal_cond_info.expr_->args_[1]->datum_meta_; CK(l.cs_type_ == r.cs_type_); if (OB_SUCC(ret)) { + const ObScale scale = ObDatumFuncs::max_scale(l.scale_, r.scale_); equal_cond_info.ns_cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(l.type_, - r.type_, default_null_pos(), l.cs_type_, is_oracle_mode()); + r.type_, default_null_pos(), l.cs_type_, scale, is_oracle_mode()); CK(OB_NOT_NULL(equal_cond_info.ns_cmp_func_)); OZ(calc_equal_cond_opposite(op, *raw_expr, equal_cond_info.is_opposite_)); OZ(mj_spec.equal_cond_infos_.push_back(equal_cond_info)); @@ -5118,6 +5124,7 @@ int ObStaticEngineCG::fill_aggr_info(ObAggFunRawExpr &raw_expr, expr->datum_meta_.type_, field_collation.null_pos_, field_collation.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); if (OB_ISNULL(cmp_func.cmp_func_)) { ret = OB_ERR_UNEXPECTED; @@ -5619,6 +5626,7 @@ int ObStaticEngineCG::fil_sort_info(const ObIArray &sort_keys, expr->datum_meta_.type_, field_collation.null_pos_, field_collation.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); if (OB_ISNULL(cmp_func.cmp_func_)) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/code_generator/ob_static_engine_expr_cg.cpp b/src/sql/code_generator/ob_static_engine_expr_cg.cpp index d2f7faf1a..72540deaf 100644 --- a/src/sql/code_generator/ob_static_engine_expr_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_expr_cg.cpp @@ -1100,7 +1100,8 @@ int ObStaticEngineExprCG::cg_expr_basic_funcs(const ObIArray &raw_e LOG_WARN("rt expr is null", K(ret), K(*raw_exprs.at(i))); } else { rt_expr->basic_funcs_ = ObDatumFuncs::get_basic_func(rt_expr->datum_meta_.type_, - rt_expr->datum_meta_.cs_type_); + rt_expr->datum_meta_.cs_type_, + rt_expr->datum_meta_.scale_); CK(NULL != rt_expr->basic_funcs_); } } diff --git a/src/sql/engine/aggregate/ob_hash_groupby_op.cpp b/src/sql/engine/aggregate/ob_hash_groupby_op.cpp index 2f1a3099f..f39df083b 100644 --- a/src/sql/engine/aggregate/ob_hash_groupby_op.cpp +++ b/src/sql/engine/aggregate/ob_hash_groupby_op.cpp @@ -693,6 +693,7 @@ int ObHashGroupByOp::init_distinct_info(bool is_part) expr->datum_meta_.type_, NULL_LAST,//这里null last还是first无所谓 expr->datum_meta_.cs_type_, + expr->datum_meta_.scale_, lib::is_oracle_mode()); hash_func.hash_func_ = expr->basic_funcs_->murmur_hash_; hash_func.batch_hash_func_ = expr->basic_funcs_->murmur_hash_batch_; diff --git a/src/sql/engine/expr/ob_expr.cpp b/src/sql/engine/expr/ob_expr.cpp index ed8481450..2516a2c40 100644 --- a/src/sql/engine/expr/ob_expr.cpp +++ b/src/sql/engine/expr/ob_expr.cpp @@ -185,7 +185,8 @@ OB_DEF_DESERIALIZE(ObExpr) } if (OB_SUCC(ret)) { - basic_funcs_ = ObDatumFuncs::get_basic_func(datum_meta_.type_, datum_meta_.cs_type_); + basic_funcs_ = ObDatumFuncs::get_basic_func(datum_meta_.type_, datum_meta_.cs_type_, + datum_meta_.scale_); CK(NULL != basic_funcs_); } if (is_batch_result()) { diff --git a/src/sql/engine/expr/ob_expr_abs.cpp b/src/sql/engine/expr/ob_expr_abs.cpp index 3085b478a..45d0066e7 100644 --- a/src/sql/engine/expr/ob_expr_abs.cpp +++ b/src/sql/engine/expr/ob_expr_abs.cpp @@ -283,6 +283,9 @@ int ObExprAbs::calc_result_type1(ObExprResType &type, ObExprResType &type1, if (lib::is_oracle_mode() && (type1.is_varchar_or_char() || type1.is_number_float())) { type.set_precision(PRECISION_UNKNOWN_YET); type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET); + } else if (lib::is_mysql_mode() && type.is_double() && type1.get_scale() != SCALE_UNKNOWN_YET) { + type.set_scale(type1.get_scale()); + type.set_precision(static_cast(ObMySQLUtil::float_length(type1.get_scale()))); } else { type.set_accuracy(type1.get_accuracy()); } diff --git a/src/sql/engine/expr/ob_expr_add.cpp b/src/sql/engine/expr/ob_expr_add.cpp index 2bed21312..0719f6a2a 100644 --- a/src/sql/engine/expr/ob_expr_add.cpp +++ b/src/sql/engine/expr/ob_expr_add.cpp @@ -69,11 +69,15 @@ int ObExprAdd::calc_result_type2(ObExprResType &type, } else { ObScale scale1 = static_cast(MAX(type1.get_scale(), 0)); ObScale scale2 = static_cast(MAX(type2.get_scale(), 0)); - int64_t inter_part_length1 = type1.get_precision() - type1.get_scale(); - int64_t inter_part_length2 = type2.get_precision() - type2.get_scale(); scale = MAX(scale1, scale2); - precision = static_cast(MAX(inter_part_length1, inter_part_length2) - + CARRY_OFFSET + scale); + if (lib::is_mysql_mode() && type.is_double()) { + precision = ObMySQLUtil::float_length(scale); + } else { + int64_t inter_part_length1 = type1.get_precision() - type1.get_scale(); + int64_t inter_part_length2 = type2.get_precision() - type2.get_scale(); + precision = static_cast(MAX(inter_part_length1, inter_part_length2) + + CARRY_OFFSET + scale); + } } type.set_scale(scale); diff --git a/src/sql/engine/expr/ob_expr_between.cpp b/src/sql/engine/expr/ob_expr_between.cpp index e1d43a11a..e9c88519f 100644 --- a/src/sql/engine/expr/ob_expr_between.cpp +++ b/src/sql/engine/expr/ob_expr_between.cpp @@ -92,6 +92,7 @@ int ObExprBetween::cg_expr(ObExprCGCtx &expr_cg_ctx, raw_expr.get_result_type().get_calc_collation_type(); if (OB_ISNULL(cmp_func_1 = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( left_meta.type_, val_meta.type_, + left_meta.scale_, val_meta.scale_, is_oracle_mode(), cmp_cs_type))) { ret = OB_ERR_UNEXPECTED; @@ -99,6 +100,7 @@ int ObExprBetween::cg_expr(ObExprCGCtx &expr_cg_ctx, K(is_oracle_mode()), K(rt_expr)); } else if (OB_ISNULL(cmp_func_2 = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( val_meta.type_, right_meta.type_, + val_meta.scale_, right_meta.scale_, is_oracle_mode(), cmp_cs_type))) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/engine/expr/ob_expr_cast.cpp b/src/sql/engine/expr/ob_expr_cast.cpp index b57de8705..2a301c464 100644 --- a/src/sql/engine/expr/ob_expr_cast.cpp +++ b/src/sql/engine/expr/ob_expr_cast.cpp @@ -332,13 +332,25 @@ int ObExprCast::calc_result_type2(ObExprResType &type, // however, ob use -1 as default precision, so it is a valid value type.set_collation_type(dst_type.get_collation_type()); ObPrecision float_precision = dst_type.get_precision(); - if (float_precision < -1 || float_precision > OB_MAX_DOUBLE_FLOAT_PRECISION) { + ObScale float_scale = dst_type.get_scale(); + if (OB_UNLIKELY(float_scale > OB_MAX_DOUBLE_FLOAT_SCALE)) { + ret = OB_ERR_TOO_BIG_SCALE; + LOG_USER_ERROR(OB_ERR_TOO_BIG_SCALE, float_scale, "CAST", OB_MAX_DOUBLE_FLOAT_SCALE); + LOG_WARN("scale of float overflow", K(ret), K(float_scale), K(float_precision)); + } else if (float_precision < -1 || + (SCALE_UNKNOWN_YET == float_scale && float_precision > OB_MAX_DOUBLE_FLOAT_PRECISION)) { ret = OB_ERR_TOO_BIG_PRECISION; LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, float_precision, "CAST", OB_MAX_DOUBLE_FLOAT_PRECISION); - } else if (float_precision <= OB_MAX_FLOAT_PRECISION) { - type.set_type(ObFloatType); + } else if (SCALE_UNKNOWN_YET == float_scale) { + if (float_precision <= OB_MAX_FLOAT_PRECISION) { + type.set_type(ObFloatType); + } else { + type.set_type(ObDoubleType); + } } else { - type.set_type(ObDoubleType); + type.set_type(ObFloatType); + type.set_precision(float_precision); + type.set_scale(float_scale); } } else { type.set_type(dst_type.get_type()); diff --git a/src/sql/engine/expr/ob_expr_cmp_func.cpp b/src/sql/engine/expr/ob_expr_cmp_func.cpp index 1e043b0a2..d57fbdfa1 100644 --- a/src/sql/engine/expr/ob_expr_cmp_func.cpp +++ b/src/sql/engine/expr/ob_expr_cmp_func.cpp @@ -24,6 +24,12 @@ namespace sql { using namespace common; +#define IS_FIXED_DOUBLE \ + !is_oracle_mode && \ + ob_is_double_type(type1) && ob_is_double_type(type2) && \ + SCALE_UNKNOWN_YET < scale1 && SCALE_UNKNOWN_YET < scale2 && \ + MAX(scale1, scale2) <= OB_MAX_DOUBLE_FLOAT_SCALE \ + template constexpr int get_cmp_ret(const int) { @@ -176,6 +182,37 @@ struct ObRelationalStrFunc // } }; + +template +struct ObRelationFixedDoubleFunc{}; + +template +struct ObRelationFixedDoubleFunc : ObDummyRelationalFunc {}; + +template +struct ObRelationFixedDoubleFunc +{ + struct DatumCmp + { + int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const + { + res.set_int(get_cmp_ret(datum_cmp::ObFixedDoubleCmp::cmp(l, r))); + return OB_SUCCESS; + } + }; + + inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) + { + return def_relational_eval_func(expr, ctx, expr_datum); + } + + inline static int eval_batch(BATCH_EVAL_FUNC_ARG_DECL) + { + return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST); + } +}; + + // define null, extend, string evaluate batch functions. template struct ObRelationalExtraFunc @@ -250,6 +287,10 @@ static ObDatumCmpFuncType DATUM_TC_CMP_FUNCS[ObMaxTC][ObMaxTC]; static ObExpr::EvalFunc EVAL_STR_CMP_FUNCS[CS_TYPE_MAX][CO_MAX][2]; static ObDatumCmpFuncType DATUM_STR_CMP_FUNCS[CS_TYPE_MAX][2]; +static ObExpr::EvalFunc EVAL_FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE][CO_MAX]; +static ObExpr::EvalBatchFunc EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE][CO_MAX]; +static ObDatumCmpFuncType DATUM_FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE]; + template struct ExtraExprCmpIniter { @@ -378,6 +419,42 @@ int g_init_tc_ret = Ob2DArrayConstIniter: int g_init_str_ret = Ob2DArrayConstIniter::init(); int g_init_datum_str_ret = ObArrayConstIniter::init(); +template +struct FixedDoubleCmpFuncIniter +{ + using Def = datum_cmp::ObFixedDoubleCmp(X)>; + + template + using EvalCmp = ObRelationFixedDoubleFunc(X), cmp_op>; + static void init_array() + { + auto &funcs = EVAL_FIXED_DOUBLE_CMP_FUNCS; + funcs[X][CO_LE] = Def::defined_ ? &EvalCmp::eval : NULL; + funcs[X][CO_LT] = Def::defined_ ? &EvalCmp::eval : NULL; + funcs[X][CO_EQ] = Def::defined_ ? &EvalCmp::eval : NULL; + funcs[X][CO_GE] = Def::defined_ ? &EvalCmp::eval : NULL; + funcs[X][CO_GT] = Def::defined_ ? &EvalCmp::eval : NULL; + funcs[X][CO_NE] = Def::defined_ ? &EvalCmp::eval : NULL; + funcs[X][CO_CMP] = Def::defined_ ? &EvalCmp::eval : NULL; + + auto &batch_funcs = EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS; + batch_funcs[X][CO_LE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; + batch_funcs[X][CO_LT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; + batch_funcs[X][CO_EQ] = Def::defined_ ? &EvalCmp::eval_batch : NULL; + batch_funcs[X][CO_GE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; + batch_funcs[X][CO_GT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; + batch_funcs[X][CO_NE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; + // CO_CMP only used in T_FUN_SYS_STRCMP, set to NULL + batch_funcs[X][CO_CMP] = NULL; + + DATUM_FIXED_DOUBLE_CMP_FUNCS[X] = Def::defined_ ? &Def::cmp : NULL; + } +}; + +int g_init_fixed_double_ret = + ObArrayConstIniter::init(); + + static int64_t fill_type_with_tc_eval_func(void) { int64_t cnt = 0; @@ -408,6 +485,8 @@ int64_t g_fill_type_with_tc_eval_func = fill_type_with_tc_eval_func(); ObExpr::EvalFunc ObExprCmpFuncsHelper::get_eval_expr_cmp_func(const ObObjType type1, const ObObjType type2, + const ObScale scale1, + const ObScale scale2, const ObCmpOp cmp_op, const bool is_oracle_mode, const ObCollationType cs_type) @@ -423,6 +502,8 @@ ObExpr::EvalFunc ObExprCmpFuncsHelper::get_eval_expr_cmp_func(const ObObjType ty OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || OB_UNLIKELY(ob_is_invalid_obj_tc(tc2)))) { func_ptr = NULL; + } else if (IS_FIXED_DOUBLE) { + func_ptr = EVAL_FIXED_DOUBLE_CMP_FUNCS[MAX(scale1, scale2)][cmp_op]; } else if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { func_ptr = EVAL_TYPE_CMP_FUNCS[type1][type2][cmp_op]; } else { @@ -437,6 +518,8 @@ ObExpr::EvalFunc ObExprCmpFuncsHelper::get_eval_expr_cmp_func(const ObObjType ty ObExpr::EvalBatchFunc ObExprCmpFuncsHelper::get_eval_batch_expr_cmp_func( const ObObjType type1, const ObObjType type2, + const ObScale scale1, + const ObScale scale2, const ObCmpOp cmp_op, const bool is_oracle_mode, const ObCollationType cs_type) @@ -452,6 +535,8 @@ ObExpr::EvalBatchFunc ObExprCmpFuncsHelper::get_eval_batch_expr_cmp_func( OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || OB_UNLIKELY(ob_is_invalid_obj_tc(tc2)))) { func_ptr = NULL; + } else if (IS_FIXED_DOUBLE) { + func_ptr = EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS[MAX(scale1, scale2)][cmp_op]; } else if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { func_ptr = EVAL_BATCH_TYPE_CMP_FUNCS[type1][type2][cmp_op]; } else { @@ -467,6 +552,8 @@ ObExpr::EvalBatchFunc ObExprCmpFuncsHelper::get_eval_batch_expr_cmp_func( DatumCmpFunc ObExprCmpFuncsHelper::get_datum_expr_cmp_func(const ObObjType type1, const ObObjType type2, + const ObScale scale1, + const ObScale scale2, const bool is_oracle_mode, const ObCollationType cs_type) { @@ -476,7 +563,9 @@ DatumCmpFunc ObExprCmpFuncsHelper::get_datum_expr_cmp_func(const ObObjType type1 ObObjTypeClass tc1 = ob_obj_type_class(type1); ObObjTypeClass tc2 = ob_obj_type_class(type2); ObDatumCmpFuncType func_ptr = NULL; - if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { + if (IS_FIXED_DOUBLE) { + func_ptr = DATUM_FIXED_DOUBLE_CMP_FUNCS[MAX(scale1, scale2)]; + } else if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { func_ptr = DATUM_TYPE_CMP_FUNCS[type1][type2]; if (NULL == func_ptr) { func_ptr = DATUM_TC_CMP_FUNCS[tc1][tc2]; @@ -553,5 +642,27 @@ REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_STR, DATUM_STR_CMP_FUNCS, sizeof(DATUM_STR_CMP_FUNCS) / sizeof(void *)); +// Fixed double cmp functions reg +static_assert( + OB_NOT_FIXED_SCALE * CO_MAX == sizeof(EVAL_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), + "unexpected size"); +REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_CMP_EVAL, + EVAL_FIXED_DOUBLE_CMP_FUNCS, + sizeof(EVAL_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); + +static_assert( + OB_NOT_FIXED_SCALE * CO_MAX == sizeof(EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), + "unexpected size"); +REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_CMP_EVAL_BATCH, + EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS, + sizeof(EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); + +static_assert( + OB_NOT_FIXED_SCALE == sizeof(DATUM_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), + "unexpected size"); +REG_SER_FUNC_ARRAY(OB_SFA_DATUM_FIXED_DOUBLE_CMP, + DATUM_FIXED_DOUBLE_CMP_FUNCS, + sizeof(DATUM_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); + } // end namespace common; } // end namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_cmp_func.h b/src/sql/engine/expr/ob_expr_cmp_func.h index 72ed4ddac..59cfb2333 100644 --- a/src/sql/engine/expr/ob_expr_cmp_func.h +++ b/src/sql/engine/expr/ob_expr_cmp_func.h @@ -33,6 +33,8 @@ public: static sql::ObExpr::EvalFunc get_eval_expr_cmp_func( const common::ObObjType type1, const common::ObObjType type2, + const common::ObScale scale1, + const common::ObScale scale2, const common::ObCmpOp cmp_op, const bool is_oracle_mode, const common::ObCollationType cs_type); @@ -40,6 +42,8 @@ public: static sql::ObExpr::EvalBatchFunc get_eval_batch_expr_cmp_func( const common::ObObjType type1, const common::ObObjType type2, + const common::ObScale scale1, + const common::ObScale scale2, const common::ObCmpOp cmp_op, const bool is_oracle_mode, const common::ObCollationType cs_type); @@ -47,6 +51,8 @@ public: static DatumCmpFunc get_datum_expr_cmp_func( const common::ObObjType type1, const common::ObObjType type2, + const common::ObScale scale1, + const common::ObScale scale2, const bool is_oracle_mode, const common::ObCollationType cs_type); }; diff --git a/src/sql/engine/expr/ob_expr_div.cpp b/src/sql/engine/expr/ob_expr_div.cpp index a7d60e839..155d2d3b7 100644 --- a/src/sql/engine/expr/ob_expr_div.cpp +++ b/src/sql/engine/expr/ob_expr_div.cpp @@ -17,6 +17,7 @@ #include "sql/session/ob_sql_session_info.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_batch_eval_util.h" +#include "share/object/ob_obj_cast_util.h" namespace oceanbase { @@ -56,7 +57,7 @@ int ObExprDiv::calc_result_type2(ObExprResType &type, OC( (ObArithExprOperator::calc_result_type2)(type, type1, type2, type_ctx)); if (OB_SUCC(ret)) { const ObObjTypeClass result_tc = type.get_type_class(); - if (ObNumberTC == result_tc || ObDoubleTC == result_tc || ObFloatTC == result_tc) { + if (ObNumberTC == result_tc) { if (is_oracle_mode()) { type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET); type.set_precision(PRECISION_UNKNOWN_YET); @@ -92,6 +93,34 @@ int ObExprDiv::calc_result_type2(ObExprResType &type, "new_scale1", ROUND_UP(scale1), "new_scale2", ROUND_UP(scale2), K(div_precision_increment)); } + } else if (ObDoubleTC == result_tc || ObFloatTC == result_tc) { + if (is_oracle_mode()) { + type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET); + type.set_precision(PRECISION_UNKNOWN_YET); + } else { + ObScale scale = SCALE_UNKNOWN_YET; + ObPrecision precision = PRECISION_UNKNOWN_YET; + if (SCALE_UNKNOWN_YET != type1.get_scale() && SCALE_UNKNOWN_YET != type2.get_scale()) { + ObScale scale1 = static_cast(MAX(type1.get_scale(), 0)); + ObScale scale2 = static_cast(MAX(type2.get_scale(), 0)); + scale = MAX(scale1, scale2) + div_precision_increment; + if (scale > OB_MAX_DOUBLE_FLOAT_SCALE) { + scale = SCALE_UNKNOWN_YET; + } + } + if (PRECISION_UNKNOWN_YET != type1.get_precision() && + PRECISION_UNKNOWN_YET != type2.get_precision() && + SCALE_UNKNOWN_YET != scale) { + ObPrecision p1 = ObMySQLUtil::float_length(scale); + ObPrecision p2 = type1.get_precision() - type1.get_scale() + scale; + if (ObNumberTC == type1.get_type_class()) { + p2 += decimal_to_double_precision_inc(type1.get_type(), type1.get_scale()); + } + precision = MIN(p1, p2); + } + type.set_scale(scale); + type.set_precision(precision); + } } else if (ObIntervalTC == type.get_type_class()) { type.set_scale(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][type.get_type()].get_scale()); type.set_precision(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][type.get_type()].get_precision()); diff --git a/src/sql/engine/expr/ob_expr_func_ceil.cpp b/src/sql/engine/expr/ob_expr_func_ceil.cpp index cb0b1201d..c90043d31 100644 --- a/src/sql/engine/expr/ob_expr_func_ceil.cpp +++ b/src/sql/engine/expr/ob_expr_func_ceil.cpp @@ -100,7 +100,11 @@ int ObExprCeilFloor::calc_result_type1(ObExprResType &type, //no need to test ret here // scale type.set_scale(0); - type.set_precision(type1.get_precision()); + if (lib::is_mysql_mode() && type.is_double()) { + type.set_precision(17); // float length of 0 + } else { + type.set_precision(type1.get_precision()); + } } ObExprOperator::calc_result_flag1(type, type1); diff --git a/src/sql/engine/expr/ob_expr_func_round.cpp b/src/sql/engine/expr/ob_expr_func_round.cpp index 653e685ba..1a9bf1c16 100644 --- a/src/sql/engine/expr/ob_expr_func_round.cpp +++ b/src/sql/engine/expr/ob_expr_func_round.cpp @@ -177,18 +177,23 @@ int ObExprFuncRound::set_res_scale_prec(ObExprTypeCtx &type_ctx, ObExprResType * } } if (OB_SUCC(ret)) { - if (!is_oracle_mode() && ob_is_number_tc(res_type)) { - ObPrecision tmp_res_prec = -1; - if (1 == param_num) { - tmp_res_prec = static_cast(params[0].get_precision() - - params[0].get_scale() + 1); + if (!is_oracle_mode()) { + if (ob_is_number_tc(res_type)) { + ObPrecision tmp_res_prec = -1; + if (1 == param_num) { + tmp_res_prec = static_cast(params[0].get_precision() - + params[0].get_scale() + 1); + res_prec = tmp_res_prec >= 0 ? tmp_res_prec : res_prec; + res_scale = 0; + } else { + tmp_res_prec = static_cast(params[0].get_precision() - + params[0].get_scale() + res_scale + 1); + } res_prec = tmp_res_prec >= 0 ? tmp_res_prec : res_prec; - res_scale = 0; - } else { - tmp_res_prec = static_cast(params[0].get_precision() - - params[0].get_scale() + res_scale + 1); + } else if (ob_is_real_type(res_type)) { + res_prec = (SCALE_UNKNOWN_YET == res_scale) ? + PRECISION_UNKNOWN_YET : ObMySQLUtil::float_length(res_scale); } - res_prec = tmp_res_prec >= 0 ? tmp_res_prec : res_prec; } type.set_scale(res_scale); type.set_precision(res_prec); diff --git a/src/sql/engine/expr/ob_expr_ifnull.cpp b/src/sql/engine/expr/ob_expr_ifnull.cpp index 4a2161375..3921b5535 100644 --- a/src/sql/engine/expr/ob_expr_ifnull.cpp +++ b/src/sql/engine/expr/ob_expr_ifnull.cpp @@ -80,6 +80,10 @@ int ObExprIfNull::calc_result_type2(ObExprResType &type, } else { type.set_scale(-1); } + if (lib::is_mysql_mode() && ob_is_real_type(type.get_type()) && + SCALE_UNKNOWN_YET != type.get_scale()) { + type.set_precision(static_cast(ObMySQLUtil::float_length(type.get_scale()))); + } type.set_length(MAX(type1.get_length(), type2.get_length())); type1.set_calc_meta(type.get_obj_meta()); type1.set_calc_accuracy(type.get_accuracy()); diff --git a/src/sql/engine/expr/ob_expr_in.cpp b/src/sql/engine/expr/ob_expr_in.cpp index 06f2221cb..3953d5f6e 100644 --- a/src/sql/engine/expr/ob_expr_in.cpp +++ b/src/sql/engine/expr/ob_expr_in.cpp @@ -836,9 +836,11 @@ int ObExprInOrNotIn::cg_expr_without_row(ObIAllocator &allocator, ObObjType left_type = rt_expr.args_[0]->datum_meta_.type_; ObCollationType left_cs = rt_expr.args_[0]->datum_meta_.cs_type_; ObObjType right_type = rt_expr.args_[1]->args_[0]->datum_meta_.type_; + ObScale scale1 = rt_expr.args_[0]->datum_meta_.scale_; + ObScale scale2 = rt_expr.args_[1]->datum_meta_.scale_; rt_expr.inner_functions_ = func_buf; DatumCmpFunc func_ptr = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( - left_type, right_type, lib::is_oracle_mode(), left_cs); + left_type, right_type, scale1, scale2, lib::is_oracle_mode(), left_cs); for (int i = 0; i < rt_expr.inner_func_cnt_; i++) { rt_expr.inner_functions_[i] = (void *)func_ptr; } @@ -880,6 +882,8 @@ int ObExprInOrNotIn::cg_expr_with_row(ObIAllocator &allocator, ObSEArray left_types; ObSEArray left_cs_arr; ObSEArray right_types; + ObSEArray left_scales; + ObSEArray right_scales; #define LEFT_ROW rt_expr.args_[0] #define LEFT_ROW_ELE(i) rt_expr.args_[0]->args_[i] @@ -895,12 +899,16 @@ int ObExprInOrNotIn::cg_expr_with_row(ObIAllocator &allocator, } else if (OB_FAIL(left_cs_arr.push_back( LEFT_ROW_ELE(i)->datum_meta_.cs_type_))) { LOG_WARN("failed to push back element", K(ret)); + } else if (OB_FAIL(left_scales.push_back(LEFT_ROW_ELE(i)->datum_meta_.scale_))) { + LOG_WARN("failed to push back element", K(ret)); } else { /* do nothing */ } } // end for for (int i = 0; OB_SUCC(ret) && i < RIGHT_ROW(0)->arg_cnt_; i++) { if (OB_FAIL(right_types.push_back(RIGHT_ROW_ELE(0, i)->datum_meta_.type_))) { LOG_WARN("failed to push back element", K(ret)); + } else if (OB_FAIL(right_scales.push_back(RIGHT_ROW_ELE(0, i)->datum_meta_.scale_))) { + LOG_WARN("failed to push back element", K(ret)); } } if (OB_SUCC(ret)) { @@ -913,8 +921,8 @@ int ObExprInOrNotIn::cg_expr_with_row(ObIAllocator &allocator, } else { for (int i = 0; i < left_types.count(); i++) { DatumCmpFunc func_ptr = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( - left_types.at(i), right_types.at(i), lib::is_oracle_mode(), - left_cs_arr.at(i)); + left_types.at(i), right_types.at(i), left_scales.at(i), right_scales.at(i), + lib::is_oracle_mode(), left_cs_arr.at(i)); func_buf[i] = (void *)func_ptr; } // end for if (!is_param_all_const()) { @@ -982,7 +990,8 @@ int ObExprInOrNotIn::cg_expr_with_subquery(common::ObIAllocator &allocator, } if (OB_SUCC(ret)) { funcs[i] = (void *)ObExprCmpFuncsHelper::get_datum_expr_cmp_func( - l.get_type(), r.get_type(), lib::is_oracle_mode(), l.get_collation_type()); + l.get_type(), r.get_type(), l.get_scale(), r.get_scale(), + lib::is_oracle_mode(), l.get_collation_type()); CK(NULL != funcs[i]); } } diff --git a/src/sql/engine/expr/ob_expr_interval.cpp b/src/sql/engine/expr/ob_expr_interval.cpp index 74be3bf18..ca9eddbac 100644 --- a/src/sql/engine/expr/ob_expr_interval.cpp +++ b/src/sql/engine/expr/ob_expr_interval.cpp @@ -190,7 +190,8 @@ int ObExprInterval::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, // do not care NULL_FIRST or NULL_LAST, will ignore null in calc_interval_expr() rt_expr.inner_functions_[0] = reinterpret_cast( ObDatumFuncs::get_nullsafe_cmp_func(arg_type, arg_type, default_null_pos(), - CS_TYPE_BINARY, false)); + CS_TYPE_BINARY, + rt_expr.args_[0]->datum_meta_.scale_, false)); if (OB_ISNULL(rt_expr.inner_functions_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cmp_func is NULL", K(ret), K(arg_type)); diff --git a/src/sql/engine/expr/ob_expr_least.cpp b/src/sql/engine/expr/ob_expr_least.cpp index 922d4498a..1d056ed0c 100644 --- a/src/sql/engine/expr/ob_expr_least.cpp +++ b/src/sql/engine/expr/ob_expr_least.cpp @@ -316,6 +316,7 @@ int ObExprLeastGreatest::cg_expr(ObExprCGCtx &op_cg_ctx, cmp_meta.get_type(), NULL_LAST, cmp_meta.get_collation_type(), + info->cmp_meta_.scale_, lib::is_oracle_mode()); if (OB_ISNULL(cmp_func)) { ret = OB_INVALID_ARGUMENT; diff --git a/src/sql/engine/expr/ob_expr_minus.cpp b/src/sql/engine/expr/ob_expr_minus.cpp index 73368a066..3c4aebca7 100644 --- a/src/sql/engine/expr/ob_expr_minus.cpp +++ b/src/sql/engine/expr/ob_expr_minus.cpp @@ -84,11 +84,15 @@ int ObExprMinus::calc_result_type2(ObExprResType &type, } else { ObScale scale1 = static_cast(MAX(type1.get_scale(), 0)); ObScale scale2 = static_cast(MAX(type2.get_scale(), 0)); - int64_t inter_part_length1 = type1.get_precision() - type1.get_scale(); - int64_t inter_part_length2 = type2.get_precision() - type2.get_scale(); scale = MAX(scale1, scale2); - precision = static_cast(MAX(inter_part_length1, inter_part_length2) - + CARRY_OFFSET + scale); + if (lib::is_mysql_mode() && type.is_double()) { + precision = ObMySQLUtil::float_length(scale); + } else { + int64_t inter_part_length1 = type1.get_precision() - type1.get_scale(); + int64_t inter_part_length2 = type2.get_precision() - type2.get_scale(); + precision = static_cast(MAX(inter_part_length1, inter_part_length2) + + CARRY_OFFSET + scale); + } } type.set_scale(scale); diff --git a/src/sql/engine/expr/ob_expr_mod.cpp b/src/sql/engine/expr/ob_expr_mod.cpp index 10da4024f..61dcf5467 100644 --- a/src/sql/engine/expr/ob_expr_mod.cpp +++ b/src/sql/engine/expr/ob_expr_mod.cpp @@ -54,7 +54,11 @@ int ObExprMod::calc_result_type2(ObExprResType &type, type.set_scale(SCALE_UNKNOWN_YET); } else { type.set_scale(MAX(scale1, scale2)); - type.set_precision(MAX(type1.get_precision(),type2.get_precision())); + if (lib::is_mysql_mode() && type.is_double()) { + type.set_precision(ObMySQLUtil::float_length(type.get_scale())); + } else { + type.set_precision(MAX(type1.get_precision(),type2.get_precision())); + } } } return ret; diff --git a/src/sql/engine/expr/ob_expr_mul.cpp b/src/sql/engine/expr/ob_expr_mul.cpp index a2b71d903..5a0d23577 100644 --- a/src/sql/engine/expr/ob_expr_mul.cpp +++ b/src/sql/engine/expr/ob_expr_mul.cpp @@ -66,8 +66,8 @@ int ObExprMul::calc_result_type2(ObExprResType &type, if (SCALE_UNKNOWN_YET == type1.get_scale() || SCALE_UNKNOWN_YET == type2.get_scale()) { type.set_scale(SCALE_UNKNOWN_YET); } else { - if (lib::is_oracle_mode()) { - type.set_scale(MIN(static_cast(scale1 + scale2), OB_MAX_NUMBER_SCALE)); + if (lib::is_mysql_mode() && type.is_double()) { + type.set_scale(MAX(scale1, scale2)); } else { type.set_scale(MIN(static_cast(scale1 + scale2), OB_MAX_DECIMAL_SCALE)); } @@ -79,8 +79,12 @@ int ObExprMul::calc_result_type2(ObExprResType &type, type.set_precision(PRECISION_UNKNOWN_YET); } else { // estimated precision - type.set_precision(static_cast((precision1 - scale1) - + (precision2 - scale2) + type.get_scale())); + if (lib::is_mysql_mode() && type.is_double()) { + type.set_precision(ObMySQLUtil::float_length(type.get_scale())); + } else { + type.set_precision(static_cast((precision1 - scale1) + + (precision2 - scale2) + type.get_scale())); + } } } return ret; diff --git a/src/sql/engine/expr/ob_expr_neg.cpp b/src/sql/engine/expr/ob_expr_neg.cpp index 12b7c80bd..024baa871 100644 --- a/src/sql/engine/expr/ob_expr_neg.cpp +++ b/src/sql/engine/expr/ob_expr_neg.cpp @@ -214,7 +214,8 @@ int ObExprNeg::calc_result_type1(ObExprResType &type, ObExprResType &type1, ObEx if (type1.get_type() == ObUNumberType) { type.set_precision(static_cast(type1.get_precision())); } else { - type.set_precision(static_cast(type1.get_precision() + NEG_PRECISION_OFFSET)); + type.set_precision(static_cast( + MIN(type1.get_precision() + NEG_PRECISION_OFFSET, OB_MAX_INTEGER_DISPLAY_WIDTH))); } } } diff --git a/src/sql/engine/expr/ob_expr_not_between.cpp b/src/sql/engine/expr/ob_expr_not_between.cpp index 13a54c6be..52109ce16 100644 --- a/src/sql/engine/expr/ob_expr_not_between.cpp +++ b/src/sql/engine/expr/ob_expr_not_between.cpp @@ -93,6 +93,7 @@ int ObExprNotBetween::cg_expr(ObExprCGCtx &expr_cg_ctx, raw_expr.get_result_type().get_calc_collation_type(); if (OB_ISNULL(cmp_func_1 = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( val_meta.type_, left_meta.type_, + val_meta.scale_, left_meta.scale_, is_oracle_mode(), cmp_cs_type))) { ret = OB_ERR_UNEXPECTED; @@ -100,6 +101,7 @@ int ObExprNotBetween::cg_expr(ObExprCGCtx &expr_cg_ctx, K(is_oracle_mode()), K(rt_expr)); } else if (OB_ISNULL(cmp_func_2 = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( right_meta.type_, val_meta.type_, + right_meta.scale_, val_meta.scale_, is_oracle_mode(), cmp_cs_type))) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/engine/expr/ob_expr_null_safe_equal.cpp b/src/sql/engine/expr/ob_expr_null_safe_equal.cpp index b166c5666..e3cfd96a6 100644 --- a/src/sql/engine/expr/ob_expr_null_safe_equal.cpp +++ b/src/sql/engine/expr/ob_expr_null_safe_equal.cpp @@ -114,7 +114,7 @@ int ObExprNullSafeEqual::cg_expr( if (OB_SUCC(ret)) { funcs[0] = (void *)ObExprCmpFuncsHelper::get_datum_expr_cmp_func( - l.type_, r.type_, lib::is_oracle_mode(), l.cs_type_); + l.type_, r.type_, l.scale_, r.scale_, lib::is_oracle_mode(), l.cs_type_); CK(NULL != funcs[0]); rt_expr.inner_functions_ = funcs; rt_expr.inner_func_cnt_ = 1; diff --git a/src/sql/engine/expr/ob_expr_nullif.cpp b/src/sql/engine/expr/ob_expr_nullif.cpp index 8f0b915f4..326739fcb 100644 --- a/src/sql/engine/expr/ob_expr_nullif.cpp +++ b/src/sql/engine/expr/ob_expr_nullif.cpp @@ -74,7 +74,9 @@ int ObExprNullif::se_deduce_type(ObExprResType &type, int ret = OB_SUCCESS; type.set_meta(type1.get_obj_meta()); type.set_accuracy(type1.get_accuracy()); - if (ob_is_string_type(type.get_type()) || ob_is_enumset_tc(type.get_type())) { + if (ob_is_real_type(type.get_type()) && SCALE_UNKNOWN_YET != type1.get_scale()) { + type.set_precision(static_cast(ObMySQLUtil::float_length(type1.get_scale()))); + } else if (ob_is_string_type(type.get_type()) || ob_is_enumset_tc(type.get_type())) { ObCollationLevel res_cs_level = CS_LEVEL_INVALID; ObCollationType res_cs_type = CS_TYPE_INVALID; OZ(ObCharset::aggregate_collation(type1.get_collation_level(), type1.get_collation_type(), @@ -198,6 +200,8 @@ int ObExprNullif::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, cmp_func = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( rt_expr.args_[0]->datum_meta_.type_, rt_expr.args_[1]->datum_meta_.type_, + rt_expr.args_[0]->datum_meta_.scale_, + rt_expr.args_[1]->datum_meta_.scale_, lib::is_oracle_mode(), rt_expr.args_[0]->datum_meta_.cs_type_); } @@ -211,6 +215,8 @@ int ObExprNullif::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, if (OB_ISNULL(cmp_func = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( cmp_meta.get_type(), cmp_meta.get_type(), + cmp_meta.get_scale(), + cmp_meta.get_scale(), lib::is_oracle_mode(), cmp_meta.get_collation_type()))){ ret = OB_INVALID_ARGUMENT; diff --git a/src/sql/engine/expr/ob_expr_operator.cpp b/src/sql/engine/expr/ob_expr_operator.cpp index d72fd2879..f710b4827 100644 --- a/src/sql/engine/expr/ob_expr_operator.cpp +++ b/src/sql/engine/expr/ob_expr_operator.cpp @@ -1351,7 +1351,9 @@ int ObExprOperator::aggregate_numeric_accuracy_for_merge(ObExprResType &type, ObScale scale = 0; int16_t max_integer_digits = -1; int16_t max_decimal_digits = -1; + int16_t max_scale_for_real = -1; bool has_real_type = false; + bool has_unknow_scale = false; for (int64_t i = 0; i < param_num && OB_SUCC(ret); ++i) { precision = PRECISION_UNKNOWN_YET; scale = SCALE_UNKNOWN_YET; @@ -1368,6 +1370,8 @@ int ObExprOperator::aggregate_numeric_accuracy_for_merge(ObExprResType &type, a union c will result to 1.5 and 1923 */ has_real_type = true; + precision = types[i].get_precision(); + scale = types[i].get_scale(); } else { /* create table sb(a int(3));//3 ? display width ? precision? length? @@ -1397,12 +1401,25 @@ int ObExprOperator::aggregate_numeric_accuracy_for_merge(ObExprResType &type, max_decimal_digits = scale; } } + if (OB_SUCC(ret)) { + if (SCALE_UNKNOWN_YET == scale) { + has_unknow_scale = true; + } else { + max_scale_for_real = MAX(max_scale_for_real, scale); + } + } } if (OB_FAIL(ret)) { } else if (ob_is_real_type(type.get_type()) && has_real_type) { - type.set_precision(PRECISION_UNKNOWN_YET); - type.set_scale(SCALE_UNKNOWN_YET); + if (is_oracle_mode || has_unknow_scale || max_scale_for_real > OB_MAX_DOUBLE_FLOAT_SCALE) { + type.set_precision(PRECISION_UNKNOWN_YET); + type.set_scale(SCALE_UNKNOWN_YET); + } else { + precision = static_cast(ObMySQLUtil::float_length(scale)); + type.set_precision(precision); + type.set_scale(max_scale_for_real); + } } else { if (max_integer_digits + max_decimal_digits >= 0) { precision = static_cast(max_integer_digits + max_decimal_digits); @@ -1829,6 +1846,8 @@ bool ObRelationalExprOperator::can_cmp_without_cast(ObExprResType type1, } else { auto func_ptr = ObExprCmpFuncsHelper::get_eval_expr_cmp_func(type1.get_type(), type2.get_type(), + type1.get_scale(), + type2.get_scale(), cmp_op, lib::is_oracle_mode(), CS_TYPE_BINARY); @@ -2149,6 +2168,19 @@ int ObRelationalExprOperator::deduce_cmp_type(const ObExprOperator &expr, } else if (ObRawType == cmp_type.get_calc_type()) { type1.set_calc_collation_type(CS_TYPE_BINARY); type2.set_calc_collation_type(CS_TYPE_BINARY); + } else if (is_mysql_mode() && ObDoubleType == cmp_type.get_calc_type()) { + if (ob_is_numeric_tc(type1.get_type_class()) && ob_is_numeric_tc(type2.get_type_class()) && + SCALE_UNKNOWN_YET != type1.get_scale() && SCALE_UNKNOWN_YET != type2.get_scale()) { + const ObScale scale = MAX(type1.get_scale(), type2.get_scale()); + const ObPrecision precision = MAX(type1.get_precision(), type2.get_precision()); + ObAccuracy calc_acc(precision, scale); + type1.set_calc_accuracy(calc_acc); + type2.set_calc_accuracy(calc_acc); + } else { + ObAccuracy calc_acc(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET); + type1.set_calc_accuracy(calc_acc); + type2.set_calc_accuracy(calc_acc); + } } } return ret; @@ -3280,7 +3312,8 @@ int ObSubQueryRelationalExpr::cg_expr(ObExprCGCtx &op_cg_ctx, } if (OB_SUCC(ret)) { funcs[i] = (void *)ObExprCmpFuncsHelper::get_datum_expr_cmp_func( - l.get_type(), r.get_type(), lib::is_oracle_mode(), l.get_collation_type()); + l.get_type(), r.get_type(), l.get_scale(), r.get_scale(), + lib::is_oracle_mode(), l.get_collation_type()); CK(NULL != funcs[i]); } } @@ -3888,6 +3921,19 @@ int ObVectorExprOperator::calc_result_type2_(ObExprResType &type, } else if (ObRawType == cmp_type.get_calc_type()) { type1.set_calc_collation_type(CS_TYPE_BINARY); type2.set_calc_collation_type(CS_TYPE_BINARY); + } else if (is_mysql_mode() && ObDoubleType == cmp_type.get_calc_type()) { + if (ob_is_numeric_tc(type1.get_type_class()) && ob_is_numeric_tc(type2.get_type_class()) && + SCALE_UNKNOWN_YET != type1.get_scale() && SCALE_UNKNOWN_YET != type2.get_scale()) { + const ObScale scale = MAX(type1.get_scale(), type2.get_scale()); + const ObPrecision precision = MAX(type1.get_precision(), type2.get_precision()); + ObAccuracy calc_acc(precision, scale); + type1.set_calc_accuracy(calc_acc); + type2.set_calc_accuracy(calc_acc); + } else { + ObAccuracy calc_acc(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET); + type1.set_calc_accuracy(calc_acc); + type2.set_calc_accuracy(calc_acc); + } } } return ret; @@ -4766,8 +4812,18 @@ int ObMinMaxExprOperator::calc_result_meta_for_comparison( //兼容mysql行为对类型进行提升。 type.set_type(ObIntType); } - type.set_scale(result_scale); - type.set_precision(static_cast(max_precision + max_scale)); // esti, not accurate + if (lib::is_mysql_mode() && ob_is_real_type(type.get_type())) { + if (SCALE_UNKNOWN_YET != result_scale && OB_MAX_DOUBLE_FLOAT_SCALE >= result_scale) { + type.set_scale(result_scale); + type.set_precision(static_cast(ObMySQLUtil::float_length(result_scale))); + } else { + type.set_scale(SCALE_UNKNOWN_YET); + type.set_precision(PRECISION_UNKNOWN_YET); + } + } else { + type.set_scale(result_scale); + type.set_precision(static_cast(max_precision + max_scale)); // esti, not accurate + } } } @@ -5739,6 +5795,8 @@ int ObRelationalExprOperator::cg_datum_cmp_expr(const ObRawExpr &raw_expr, const ObCmpOp cmp_op = get_cmp_op(raw_expr.get_expr_type()); const ObObjType input_type1 = rt_expr.args_[0]->datum_meta_.type_; const ObObjType input_type2 = rt_expr.args_[1]->datum_meta_.type_; + const ObScale input_scale1 = rt_expr.args_[0]->datum_meta_.scale_; + const ObScale input_scale2 = rt_expr.args_[1]->datum_meta_.scale_; LOG_DEBUG("CG Datum CMP Expr", K(input_type1), K(input_type2), K(cmp_op)); const ObCollationType cs_type = rt_expr.args_[0]->datum_meta_.cs_type_; if (ObDatumFuncs::is_string_type(input_type1) && ObDatumFuncs::is_string_type(input_type2)) { @@ -5746,9 +5804,11 @@ int ObRelationalExprOperator::cg_datum_cmp_expr(const ObRawExpr &raw_expr, } if (OB_SUCC(ret)) { rt_expr.eval_func_ = ObExprCmpFuncsHelper::get_eval_expr_cmp_func( - input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type); + input_type1, input_type2, input_scale1, input_scale2, cmp_op, lib::is_oracle_mode(), + cs_type); rt_expr.eval_batch_func_ = ObExprCmpFuncsHelper::get_eval_batch_expr_cmp_func( - input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type); + input_type1, input_type2, input_scale1, input_scale2, cmp_op, lib::is_oracle_mode(), + cs_type); } CK(NULL != rt_expr.eval_func_); CK(NULL != rt_expr.eval_batch_func_); @@ -5808,17 +5868,20 @@ int ObRelationalExprOperator::cg_row_cmp_expr(const int row_dimension, { const ObObjType type1 = left_row->args_[i]->datum_meta_.type_; const ObObjType type2 = right_row->args_[i]->datum_meta_.type_; + const ObScale scale1 = left_row->args_[i]->datum_meta_.scale_; + const ObScale scale2 = right_row->args_[i]->datum_meta_.scale_; const ObCollationType cs_type = left_row->args_[i]->datum_meta_.cs_type_; if (ObDatumFuncs::is_string_type(type1) && ObDatumFuncs::is_string_type(type2)) { CK(left_row->args_[i]->datum_meta_.cs_type_ == right_row->args_[i]->datum_meta_.cs_type_); rt_expr.inner_functions_[i] = (void*)ObExprCmpFuncsHelper::get_datum_expr_cmp_func( type1, type2, + scale1, scale2, lib::is_oracle_mode(), cs_type); } else { rt_expr.inner_functions_[i] = (void *)ObExprCmpFuncsHelper::get_datum_expr_cmp_func( - type1, type2, lib::is_oracle_mode(), cs_type); + type1, type2, scale1, scale2, lib::is_oracle_mode(), cs_type); if (OB_ISNULL(rt_expr.inner_functions_[i])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null function", K(ret), K(i), K(type1), K(type2)); diff --git a/src/sql/engine/expr/ob_expr_operator.h b/src/sql/engine/expr/ob_expr_operator.h index 60668f8bf..fdd87838e 100644 --- a/src/sql/engine/expr/ob_expr_operator.h +++ b/src/sql/engine/expr/ob_expr_operator.h @@ -1208,7 +1208,7 @@ public: common::ObCharset::charset_type_by_coll(type2.get_collation_type()); } else { auto func_ptr = ObExprCmpFuncsHelper::get_eval_expr_cmp_func( - type1.get_type(), type2.get_type(), cmp_op, + type1.get_type(), type2.get_type(), type1.get_scale(), type2.get_scale(), cmp_op, lib::is_oracle_mode(), common::CS_TYPE_MAX); need_no_cast = (func_ptr != nullptr); } diff --git a/src/sql/engine/expr/ob_expr_oracle_decode.cpp b/src/sql/engine/expr/ob_expr_oracle_decode.cpp index c751e7db5..6a670aa22 100644 --- a/src/sql/engine/expr/ob_expr_oracle_decode.cpp +++ b/src/sql/engine/expr/ob_expr_oracle_decode.cpp @@ -485,6 +485,7 @@ int ObExprOracleDecode::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_e rt_expr.inner_functions_[0] = reinterpret_cast( ObDatumFuncs::get_nullsafe_cmp_func(cmp_meta.type_, cmp_meta.type_, default_null_pos(), cmp_meta.cs_type_, + cmp_meta.scale_, lib::is_oracle_mode())); } return ret; diff --git a/src/sql/engine/expr/ob_expr_oracle_nullif.cpp b/src/sql/engine/expr/ob_expr_oracle_nullif.cpp index 025c305b6..1a5e83993 100644 --- a/src/sql/engine/expr/ob_expr_oracle_nullif.cpp +++ b/src/sql/engine/expr/ob_expr_oracle_nullif.cpp @@ -242,6 +242,8 @@ int ObExprOracleNullif::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_e CK(OB_NOT_NULL(cmp_func = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( left_meta.type_, right_meta.type_, + left_meta.scale_, + right_meta.scale_, lib::is_oracle_mode(), cmp_cs_type))); OX(rt_expr.inner_func_cnt_ = 1); diff --git a/src/sql/engine/expr/ob_expr_relational_cmp_type.map b/src/sql/engine/expr/ob_expr_relational_cmp_type.map index 61042cbc4..b69030297 100644 --- a/src/sql/engine/expr/ob_expr_relational_cmp_type.map +++ b/src/sql/engine/expr/ob_expr_relational_cmp_type.map @@ -616,7 +616,7 @@ static ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* UMediumIntType */ ObDoubleType, /* UInt32Type */ ObDoubleType, /* UIntType */ - ObFloatType, /* FloatType */ + ObDoubleType, /* FloatType */ ObDoubleType, /* DoubleType */ ObDoubleType, /* UFloatType */ ObDoubleType, /* UDoubleType */ @@ -724,7 +724,7 @@ static ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* UIntType */ ObDoubleType, /* FloatType */ ObDoubleType, /* DoubleType */ - ObUFloatType, /* UFloatType */ + ObDoubleType, /* UFloatType */ ObDoubleType, /* UDoubleType */ ObDoubleType, /* NumberType */ ObDoubleType, /* UNumberType */ diff --git a/src/sql/engine/ob_serializable_function.h b/src/sql/engine/ob_serializable_function.h index a6e22fcde..cdef1dc28 100644 --- a/src/sql/engine/ob_serializable_function.h +++ b/src/sql/engine/ob_serializable_function.h @@ -65,6 +65,12 @@ typedef void (*ser_eval_batch_function)(ObBatchEvalFuncTag &); OB_SFA_SQL_EXPR_EVAL_BATCH, \ OB_SFA_EXPR_BASIC_PART2, \ OB_SFA_EXPR_STR_BASIC_PART2, \ + OB_SFA_FIXED_DOUBLE_NULLSAFE_CMP, \ + OB_SFA_FIXED_DOUBLE_BASIC_PART1, \ + OB_SFA_FIXED_DOUBLE_BASIC_PART2, \ + OB_SFA_FIXED_DOUBLE_CMP_EVAL, \ + OB_SFA_FIXED_DOUBLE_CMP_EVAL_BATCH, \ + OB_SFA_DATUM_FIXED_DOUBLE_CMP, \ OB_SFA_MAX enum ObSerFuncArrayID { diff --git a/src/sql/resolver/ddl/ob_ddl_resolver.cpp b/src/sql/resolver/ddl/ob_ddl_resolver.cpp index 8c48f21cd..e93223807 100644 --- a/src/sql/resolver/ddl/ob_ddl_resolver.cpp +++ b/src/sql/resolver/ddl/ob_ddl_resolver.cpp @@ -3518,7 +3518,8 @@ int ObDDLResolver::cast_default_value(ObObj &default_value, } else if (lib::is_mysql_mode() && (ObFloatTC == column_schema.get_data_type_class() || ObDoubleTC == column_schema.get_data_type_class()) && - (column_schema.get_data_precision() > 0 && column_schema.get_data_scale() == 0)) { + (column_schema.get_data_precision() != PRECISION_UNKNOWN_YET && + column_schema.get_data_scale() != SCALE_UNKNOWN_YET)) { const ObObj *res_obj = &default_value; const common::ObAccuracy &accuracy = column_schema.get_accuracy(); if (OB_FAIL(common::obj_accuracy_check(cast_ctx, accuracy, diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp index cf28412ee..638027cdb 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp @@ -14,6 +14,7 @@ #include "lib/container/ob_iarray.h" #include "lib/container/ob_fixed_array.h" #include "share/object/ob_obj_cast.h" +#include "share/object/ob_obj_cast_util.h" #include "sql/resolver/expr/ob_raw_expr_deduce_type.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/resolver/ob_stmt.h" @@ -1295,8 +1296,27 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) scale_increment_recover = result_type.get_scale(); result_type.set_scale(static_cast(result_type.get_scale() + scale_increment)); } - } else if (ob_is_float_tc(obj_type) || ob_is_double_tc(obj_type) || ob_is_json(obj_type) - || ob_is_string_type(obj_type) || ob_is_enumset_tc(obj_type)) { + } else if (ob_is_float_tc(obj_type) || ob_is_double_tc(obj_type)) { + result_type.set_double(); + if (result_type.get_scale() >= 0) { + scale_increment_recover = result_type.get_scale(); + result_type.set_scale(static_cast(result_type.get_scale() + scale_increment)); + if (T_FUN_AVG == expr.get_expr_type()) { + result_type.set_precision( + static_cast(result_type.get_precision() + scale_increment)); + } else { + result_type.set_precision( + static_cast(ObMySQLUtil::float_length(result_type.get_scale()))); + } + } + // recheck precision and scale overflow + if (result_type.get_precision() > OB_MAX_DOUBLE_FLOAT_DISPLAY_WIDTH || + result_type.get_scale() > OB_MAX_DOUBLE_FLOAT_SCALE) { + result_type.set_scale(SCALE_UNKNOWN_YET); + result_type.set_precision(PRECISION_UNKNOWN_YET); + } + } else if (ob_is_json(obj_type) || ob_is_string_type(obj_type) || + ob_is_enumset_tc(obj_type)) { result_type.set_double(); // todo jiuren // todo blob and text@hanhui @@ -1312,7 +1332,8 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) result_type.set_scale(static_cast(scale_increment)); } else { scale_increment_recover = result_type.get_scale(); - result_type.set_scale(static_cast(result_type.get_scale() + scale_increment)); + result_type.set_scale(static_cast( + MIN(OB_MAX_DOUBLE_FLOAT_SCALE, result_type.get_scale() + scale_increment))); } result_type.set_precision(static_cast(result_type.get_precision() + scale_increment)); } @@ -1452,19 +1473,9 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) } break; } - case T_FUN_GROUPING: { - if (!lib::is_oracle_mode()) { - result_type.set_int(); - expr.set_result_type(result_type); - } else { - result_type.set_number(); - result_type.set_scale(0); - result_type.set_precision(OB_MAX_NUMBER_PRECISION); - expr.set_result_type(result_type); - } - break; - } - case T_FUN_GROUPING_ID: { + case T_FUN_GROUPING: + case T_FUN_GROUPING_ID: + case T_FUN_GROUP_ID: { if (!lib::is_oracle_mode()) { result_type.set_int(); expr.set_result_type(result_type); @@ -1482,18 +1493,6 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) } break; } - case T_FUN_GROUP_ID: { - if (!lib::is_oracle_mode()) { - result_type.set_int(); - expr.set_result_type(result_type); - } else { - result_type.set_number(); - result_type.set_scale(0); - result_type.set_precision(OB_MAX_NUMBER_PRECISION); - expr.set_result_type(result_type); - } - break; - } case T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS: case T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE: { result_type.set_varchar(); @@ -2987,6 +2986,24 @@ int ObRawExprDeduceType::try_add_cast_expr_above_for_deduce_type(ObRawExpr &expr && ObDateTimeTC == child_res_type.get_type_class() && ObDateTimeTC == dst_type.get_calc_meta().get_type_class()) { cast_dst_type.set_accuracy(child_res_type.get_accuracy()); + } else if (lib::is_mysql_mode() && ObDoubleTC == dst_type.get_calc_meta().get_type_class()) { + if (ob_is_numeric_tc(child_res_type.get_type_class())) { + // passing scale and precision when casting float/double/decimal to double + ObScale s = child_res_type.get_calc_accuracy().get_scale(); + ObPrecision p = child_res_type.get_calc_accuracy().get_precision(); + if (ObNumberTC == child_res_type.get_type_class() && + SCALE_UNKNOWN_YET != s && PRECISION_UNKNOWN_YET != p) { + p += decimal_to_double_precision_inc(child_res_type.get_type(), s); + cast_dst_type.set_scale(s); + cast_dst_type.set_precision(p); + } else if (s != SCALE_UNKNOWN_YET && PRECISION_UNKNOWN_YET != p && + s <= OB_MAX_DOUBLE_FLOAT_SCALE && p >= s) { + cast_dst_type.set_accuracy(child_res_type.get_calc_accuracy()); + } + } else { + cast_dst_type.set_scale(SCALE_UNKNOWN_YET); + cast_dst_type.set_precision(PRECISION_UNKNOWN_YET); + } } // 这里仅设置部分情况的accuracy,其他情况的accuracy信息交给cast类型推导设置 diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index 3c5e22304..7c4c8cfad 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -6611,6 +6611,14 @@ int ObRawExprUtils::check_need_cast_expr(const ObExprResType &src_type, } else if ((ob_is_string_or_lob_type(in_type) && in_type == out_type && in_cs_type == out_cs_type) || (!ob_is_string_or_lob_type(in_type) && in_type == out_type)) { need_cast = false; + if (lib::is_mysql_mode() && ob_is_double_type(in_type) && + src_type.get_scale() != dst_type.get_scale() && + src_type.get_precision() != PRECISION_UNKNOWN_YET) { + // for the conversion between doubles with increased scale in mysql mode, + // it is necessary to explicitly add the cast expression + need_cast = (SCALE_UNKNOWN_YET == dst_type.get_scale()) || + (src_type.get_scale() < dst_type.get_scale()); + } } else if (ob_is_enumset_tc(out_type)) { //no need add cast, will add column_conv later need_cast = false; diff --git a/src/sql/resolver/ob_resolver_utils.cpp b/src/sql/resolver/ob_resolver_utils.cpp index 04482d032..0ab2cdc1a 100644 --- a/src/sql/resolver/ob_resolver_utils.cpp +++ b/src/sql/resolver/ob_resolver_utils.cpp @@ -4968,19 +4968,18 @@ int ObResolverUtils::resolve_data_type(const ParseNode &type_node, data_type.set_precision(precision); data_type.set_scale(scale); } else { - // OB does NOT support float/double(M,D) type if D is NOT zero - // See https://work.aone.alibaba-inc.com/issue/35557185 for detail - if (OB_UNLIKELY(OB_DECIMAL_NOT_SPECIFIED != scale && 0 != scale)) { - ret = OB_UNSUPPORTED_DEPRECATED_FEATURE; - LOG_USER_ERROR(OB_UNSUPPORTED_DEPRECATED_FEATURE, "MySQL"); - LOG_WARN("Not supported, deprecated MySQL feature", K(ret), K(scale), K(precision)); + if (OB_UNLIKELY(scale > OB_MAX_DOUBLE_FLOAT_SCALE)) { + ret = OB_ERR_TOO_BIG_SCALE; + LOG_USER_ERROR(OB_ERR_TOO_BIG_SCALE, scale, ident_name.ptr(), OB_MAX_DOUBLE_FLOAT_SCALE); + LOG_WARN("scale of double overflow", K(ret), K(scale), K(precision)); } else if (OB_UNLIKELY(OB_DECIMAL_NOT_SPECIFIED == scale && precision > OB_MAX_DOUBLE_FLOAT_PRECISION)) { ret = OB_ERR_COLUMN_SPEC; LOG_USER_ERROR(OB_ERR_COLUMN_SPEC, ident_name.length(), ident_name.ptr()); LOG_WARN("precision of double overflow", K(ret), K(scale), K(precision)); } else if (OB_UNLIKELY(OB_DECIMAL_NOT_SPECIFIED != scale && - precision > OB_MAX_DOUBLE_FLOAT_DISPLAY_WIDTH)) { + precision > OB_MAX_DOUBLE_FLOAT_DISPLAY_WIDTH || + (0 == scale && 0 == precision))) { ret = OB_ERR_TOO_BIG_DISPLAYWIDTH; LOG_USER_ERROR(OB_ERR_TOO_BIG_DISPLAYWIDTH, ident_name.ptr(), diff --git a/src/storage/blocksstable/encoding/ob_column_equal_encoder.cpp b/src/storage/blocksstable/encoding/ob_column_equal_encoder.cpp index 68551e9a5..736d8c0e1 100644 --- a/src/storage/blocksstable/encoding/ob_column_equal_encoder.cpp +++ b/src/storage/blocksstable/encoding/ob_column_equal_encoder.cpp @@ -101,7 +101,7 @@ int ObColumnEqualEncoder::traverse(bool &suitable) // to avoid overflow, we have to limit the max excepction count const int64_t max_exc_cnt = std::min(MAX_EXC_CNT, rows_->count() * EXC_THRESHOLD_PCT / 100 + 1); sql::ObExprBasicFuncs *basic_funcs = ObDatumFuncs::get_basic_func( - column_type_.get_type(), column_type_.get_collation_type()); + column_type_.get_type(), column_type_.get_collation_type(), column_type_.get_scale()); ObCmpFunc cmp_func; cmp_func.cmp_func_ = lib::is_oracle_mode() ? basic_funcs->null_last_cmp_ : basic_funcs->null_first_cmp_; diff --git a/src/storage/blocksstable/encoding/ob_dict_encoder.cpp b/src/storage/blocksstable/encoding/ob_dict_encoder.cpp index 7151b18e1..4a8396cec 100644 --- a/src/storage/blocksstable/encoding/ob_dict_encoder.cpp +++ b/src/storage/blocksstable/encoding/ob_dict_encoder.cpp @@ -145,7 +145,7 @@ int ObDictEncoder::build_dict() } else { if (need_sort_) { sql::ObExprBasicFuncs *basic_funcs = ObDatumFuncs::get_basic_func( - column_type_.get_type(), column_type_.get_collation_type()); + column_type_.get_type(), column_type_.get_collation_type(), column_type_.get_scale()); ObCmpFunc cmp_func; cmp_func.cmp_func_ = lib::is_oracle_mode() ? basic_funcs->null_last_cmp_ : basic_funcs->null_first_cmp_; diff --git a/src/storage/blocksstable/encoding/ob_encoding_hash_util.cpp b/src/storage/blocksstable/encoding/ob_encoding_hash_util.cpp index e46393b44..312101a2f 100644 --- a/src/storage/blocksstable/encoding/ob_encoding_hash_util.cpp +++ b/src/storage/blocksstable/encoding/ob_encoding_hash_util.cpp @@ -119,7 +119,8 @@ int ObEncodingHashTableBuilder::build(const ObColDatums &col_datums, const ObCol const bool need_binary_hash = (store_class == ObTextSC || store_class == ObJsonSC || store_class == ObLobSC || store_class == ObGeometrySC); sql::ObExprBasicFuncs *basic_funcs = ObDatumFuncs::get_basic_func( - col_desc.col_type_.get_type(), col_desc.col_type_.get_collation_type()); + col_desc.col_type_.get_type(), col_desc.col_type_.get_collation_type(), + col_desc.col_type_.get_scale()); ObHashFunc hash_func; hash_func.hash_func_ = basic_funcs->murmur_hash_; const uint64_t mask = (bucket_num_ - 1); diff --git a/src/storage/blocksstable/ob_datum_row.cpp b/src/storage/blocksstable/ob_datum_row.cpp index 9980f1b36..996949bbd 100644 --- a/src/storage/blocksstable/ob_datum_row.cpp +++ b/src/storage/blocksstable/ob_datum_row.cpp @@ -635,6 +635,7 @@ int ObStorageDatumUtils::init(const ObIArray &col_desc bool is_ascending = true || col_desc.col_order_ == ObOrderType::ASC; sql::ObExprBasicFuncs *basic_funcs = ObDatumFuncs::get_basic_func(col_desc.col_type_.get_type(), col_desc.col_type_.get_collation_type(), + col_desc.col_type_.get_scale(), is_oracle_mode); if (OB_UNLIKELY(nullptr == basic_funcs || nullptr == basic_funcs->null_last_cmp_ diff --git a/src/storage/ls/ob_ls_tablet_service.cpp b/src/storage/ls/ob_ls_tablet_service.cpp index 78c65d75f..8261c4206 100644 --- a/src/storage/ls/ob_ls_tablet_service.cpp +++ b/src/storage/ls/ob_ls_tablet_service.cpp @@ -4827,6 +4827,12 @@ int ObLSTabletService::table_refresh_row( LOG_WARN("get row from single row col count not equal.", K(ret), K(row.get_count()), K(new_row->get_count())); } else { LOG_DEBUG("get new row success.", K(row), KPC(new_row)); + // passing fixed double scale from row to new_row + for (int64_t i = 0; OB_SUCC(ret) && i < new_row->get_count(); ++i) { + if (row.cells_[i].is_fixed_double()) { + new_row->cells_[i].set_scale(row.cells_[i].get_scale()); + } + } if (OB_FAIL(ob_write_row(run_ctx.lob_allocator_, *new_row, row))) { LOG_WARN("failed to deep copy new row", K(ret)); } else { diff --git a/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_ceil.result b/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_ceil.result index 336aa95bf..9121e773b 100644 --- a/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_ceil.result +++ b/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_ceil.result @@ -146,16 +146,16 @@ floor(-161) -161 select ceil(null); Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ceil(null) 5 23 0 Y 32768 0 63 +def ceil(null) 5 17 0 Y 32768 0 63 ceil(null) NULL select floor(null); Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(null) 5 23 0 Y 32768 0 63 +def floor(null) 5 17 0 Y 32768 0 63 floor(null) NULL select floor(1+null*5); Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(1+null*5) 5 23 0 Y 32768 0 63 +def floor(1+null*5) 5 17 0 Y 32768 0 63 floor(1+null*5) NULL diff --git a/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_floor.result b/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_floor.result index 42cf4bbca..5ee65dce8 100644 --- a/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_floor.result +++ b/tools/deploy/mysql_test/test_suite/meta_info/r/mysql/meta_func_floor.result @@ -40,12 +40,12 @@ round(a + 0.4) drop table t1; select floor(null); Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(null) 5 23 0 Y 32768 0 63 +def floor(null) 5 17 0 Y 32768 0 63 floor(null) NULL select ceil(null); Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ceil(null) 5 23 0 Y 32768 0 63 +def ceil(null) 5 17 0 Y 32768 0 63 ceil(null) NULL select floor(-123); @@ -251,7 +251,7 @@ insert into tbl1 values(6,'now2','haha3',-10.4256,'2014-05-04 12:00:00',0.253); insert into tbl1 values(7,'now3','haha4',0.6256,'2014-05-04 12:00:00',1.677); select floor(i4),floor(i5) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(i4) 5 23 3 Y 32768 0 63 +def floor(i4) 5 17 3 Y 32768 0 63 def floor(i5) 8 5 3 Y 32768 0 63 floor(i4) floor(i5) 1 -11 @@ -263,31 +263,31 @@ floor(i4) floor(i5) 0 1 select max(floor(i4)),max(floor(i5)) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def max(floor(i4)) 5 23 1 Y 32768 0 63 +def max(floor(i4)) 5 17 1 Y 32768 0 63 def max(floor(i5)) 8 5 1 Y 32768 0 63 max(floor(i4)) max(floor(i5)) 5 3 select min(floor(i4)),min(floor(i5)) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def min(floor(i4)) 5 23 3 Y 32768 0 63 +def min(floor(i4)) 5 17 3 Y 32768 0 63 def min(floor(i5)) 8 5 3 Y 32768 0 63 min(floor(i4)) min(floor(i5)) -11 -11 select max(ceil(i4)),max(ceil(i5)) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def max(ceil(i4)) 5 23 1 Y 32768 0 63 +def max(ceil(i4)) 5 17 1 Y 32768 0 63 def max(ceil(i5)) 8 5 1 Y 32768 0 63 max(ceil(i4)) max(ceil(i5)) 6 4 select min(ceil(i4)),min(ceil(i5)) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def min(ceil(i4)) 5 23 3 Y 32768 0 63 +def min(ceil(i4)) 5 17 3 Y 32768 0 63 def min(ceil(i5)) 8 5 3 Y 32768 0 63 min(ceil(i4)) min(ceil(i5)) -10 -10 select avg(ceil(i4)),avg(ceil(i5)) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def avg(ceil(i4)) 5 23 6 Y 32768 4 63 +def avg(ceil(i4)) 5 21 6 Y 32768 4 63 def avg(ceil(i5)) 246 11 7 Y 32768 4 63 avg(ceil(i4)) avg(ceil(i5)) 0.2857 -0.2857 @@ -299,7 +299,7 @@ avg(ceil(i5)) avg(floor(i5)) -0.2857 -1.2857 select sum(ceil(i4)),sum(ceil(i5)) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def sum(ceil(i4)) 5 23 1 Y 32768 0 63 +def sum(ceil(i4)) 5 17 1 Y 32768 0 63 def sum(ceil(i5)) 246 6 2 Y 32768 0 63 sum(ceil(i4)) sum(ceil(i5)) 2 -2 @@ -317,13 +317,13 @@ ceil(count(ceil(i4))) floor(count(ceil(i5))) 7 7 select ceil(avg(ceil(i4))),floor(avg(ceil(i5))) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ceil(avg(ceil(i4))) 5 23 1 Y 32768 0 63 +def ceil(avg(ceil(i4))) 5 17 1 Y 32768 0 63 def floor(avg(ceil(i5))) 8 9 2 Y 32768 0 63 ceil(avg(ceil(i4))) floor(avg(ceil(i5))) 1 -1 select ceil(avg(ceil(i4))),ceil(avg(ceil(i5))) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ceil(avg(ceil(i4))) 5 23 1 Y 32768 0 63 +def ceil(avg(ceil(i4))) 5 17 1 Y 32768 0 63 def ceil(avg(ceil(i5))) 8 9 1 Y 32768 0 63 ceil(avg(ceil(i4))) ceil(avg(ceil(i5))) 1 0 @@ -426,7 +426,7 @@ i1 v2 i3 i4 d4 i5 6 now2 haha3 -10.4256 2014-05-04 12:00:00.000000 0.253 select floor(i4) abc from tbl1 order by abc desc; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def abc 5 23 3 Y 32768 0 63 +def abc 5 17 3 Y 32768 0 63 abc 5 1 @@ -437,7 +437,7 @@ abc -11 select floor(v2) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(v2) 5 23 1 Y 32768 0 63 +def floor(v2) 5 17 1 Y 32768 0 63 floor(v2) 0 0 @@ -456,7 +456,7 @@ Warning 1292 Truncated incorrect DOUBLE value: 'now2' Warning 1292 Truncated incorrect DOUBLE value: 'now3' select floor(i3) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(i3) 5 23 1 Y 32768 0 63 +def floor(i3) 5 17 1 Y 32768 0 63 floor(i3) 0 0 @@ -475,7 +475,7 @@ Warning 1292 Truncated incorrect DOUBLE value: 'haha3' Warning 1292 Truncated incorrect DOUBLE value: 'haha4' select floor(d4) from tbl1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(d4) 5 25 14 Y 32768 0 63 +def floor(d4) 5 17 14 Y 32768 0 63 floor(d4) 20140504120000 20140504120000 @@ -491,8 +491,8 @@ insert into tbl2 values(2,'2.5'); insert into tbl2 values(3,'-3.2'); select floor(v2),ceil(v2) from tbl2; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def floor(v2) 5 23 2 Y 32768 0 63 -def ceil(v2) 5 23 2 Y 32768 0 63 +def floor(v2) 5 17 2 Y 32768 0 63 +def ceil(v2) 5 17 2 Y 32768 0 63 floor(v2) ceil(v2) 1 1 2 3 diff --git a/unittest/share/test_datum_cmp.cpp b/unittest/share/test_datum_cmp.cpp index 275979ee2..1e67b4c4b 100644 --- a/unittest/share/test_datum_cmp.cpp +++ b/unittest/share/test_datum_cmp.cpp @@ -75,6 +75,7 @@ TEST(ObTestDatumCmp, defined_nullsafe_func_by_type) static_cast(j), NULL_FIRST, CS_TYPE_COLLATION_FREE, + SCALE_UNKNOWN_YET, false)) { of_result << "defined\n"; } else { @@ -104,6 +105,8 @@ TEST(ObTestDatumCmp, defined_expr_func_by_type) << "> : "; if (NULL != ObExprCmpFuncsHelper::get_datum_expr_cmp_func(static_cast(i), static_cast(j), + SCALE_UNKNOWN_YET, + SCALE_UNKNOWN_YET, false, CS_TYPE_COLLATION_FREE)) { of_result << "defined\n"; diff --git a/unittest/sql/engine/px/test_slice_calc.cpp b/unittest/sql/engine/px/test_slice_calc.cpp index ffe8cc3ee..37d30c0ba 100644 --- a/unittest/sql/engine/px/test_slice_calc.cpp +++ b/unittest/sql/engine/px/test_slice_calc.cpp @@ -68,6 +68,7 @@ void TestPkeyRangeSliceCalc::SetUp() ObObjType::ObIntType, ObCmpNullPos::NULL_LAST, ObCollationType::CS_TYPE_BINARY, + SCALE_UNKNOWN_YET, false/*is_orace_mode*/); ASSERT_EQ(OB_SUCCESS, sort_cmp_funcs_.push_back(cmp_func)); int_datum_.int_ = &tmp_int_; diff --git a/unittest/sql/engine/set/test_hash_set_op_dump.cpp b/unittest/sql/engine/set/test_hash_set_op_dump.cpp index 5bf77825f..33dbdb607 100644 --- a/unittest/sql/engine/set/test_hash_set_op_dump.cpp +++ b/unittest/sql/engine/set/test_hash_set_op_dump.cpp @@ -254,6 +254,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); ObHashFunc hash_func; if (0 == i) { @@ -351,6 +352,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); if (OB_FAIL(spec.sort_cmp_funs_.push_back(cmp_func))) { LOG_WARN("failed to push back sort function", K(ret)); diff --git a/unittest/sql/engine/set/test_hash_set_op_dump_vec.cpp b/unittest/sql/engine/set/test_hash_set_op_dump_vec.cpp index c77c61dfc..777442a63 100644 --- a/unittest/sql/engine/set/test_hash_set_op_dump_vec.cpp +++ b/unittest/sql/engine/set/test_hash_set_op_dump_vec.cpp @@ -298,6 +298,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); ObHashFunc hash_func; if (0 == i) { @@ -420,6 +421,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); if (OB_FAIL(spec.sort_cmp_funs_.push_back(cmp_func))) { LOG_WARN("failed to push back sort function", K(ret)); @@ -530,6 +532,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); ObHashFunc hash_func; if (0 == i) { @@ -646,6 +649,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); if (OB_FAIL(spec.cmp_funcs_.push_back(cmp_func))) { LOG_WARN("failed to push back sort function", K(ret)); diff --git a/unittest/sql/engine/set/test_merge_set_op_vec.cpp b/unittest/sql/engine/set/test_merge_set_op_vec.cpp index 4ef154c4e..ad052cd4b 100644 --- a/unittest/sql/engine/set/test_merge_set_op_vec.cpp +++ b/unittest/sql/engine/set/test_merge_set_op_vec.cpp @@ -265,6 +265,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); if (OB_FAIL(spec.sort_cmp_funs_.push_back(cmp_func))) { LOG_WARN("failed to push back sort function", K(ret)); @@ -359,6 +360,7 @@ public: tmp_type, field_collation.null_pos_, field_collation.cs_type_, + SCALE_UNKNOWN_YET, lib::is_oracle_mode()); if (OB_FAIL(spec.cmp_funcs_.push_back(cmp_func))) { LOG_WARN("failed to push back sort function", K(ret)); diff --git a/unittest/sql/optimizer/test_optimizer_schema.sql b/unittest/sql/optimizer/test_optimizer_schema.sql index 68bcef075..3d545cd11 100644 --- a/unittest/sql/optimizer/test_optimizer_schema.sql +++ b/unittest/sql/optimizer/test_optimizer_schema.sql @@ -200,7 +200,7 @@ create index idx_t_idx_c126 on t_idx(c126) LOCAL; create index idx_t_idx_c127 on t_idx(c127) LOCAL; create index idx_t_idx_c128 on t_idx(c128) LOCAL; create index idx_t_idx_c129 on t_idx(c129) LOCAL; -create table yuming(c1 float, c2 float, primary key(c1, c2)); +create table yuming(c1 float(10, 5), c2 float(10, 5), primary key(c1, c2)); create table query_range(c1 int, c2 int, c3 int, c4 int, c5 int, primary key(c1, c2, c3)); CREATE TABLE query_range1(c1 int(31) NOT NULL, `c2` decimal(5,1) DEFAULT NULL, `c3` int(123) DEFAULT NULL, `c4` int(6) DEFAULT NULL, `c5` int(19) NOT NULL, `c6` int(105) DEFAULT NULL, `c7` tinyint(112) NOT NULL, `c8` decimal(26,6) NOT NULL, `c9` decimal(14,4) NOT NULL, `c10` varbinary(18) DEFAULT NULL, `c11` decimal(35,8) NOT NULL, `c12` int(3) NOT NULL, PRIMARY KEY (`c9`, `c11`, `c8`, `c1`, `c12`, `c7`, `c5`), KEY `i_BX` (`c2`) BLOCK_SIZE 16384);