/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/expr/ob_expr_mul.h" #include "sql/engine/expr/ob_expr_result_type_util.h" #include "sql/session/ob_sql_session_info.h" #include "sql/engine/expr/ob_batch_eval_util.h" using namespace oceanbase::common; namespace oceanbase { namespace sql { using namespace common; using namespace common::number; ObExprMul::ObExprMul(ObIAllocator &alloc, ObExprOperatorType type) : ObArithExprOperator(alloc, type, N_MUL, 2, NOT_ROW_DIMENSION, ObExprResultTypeUtil::get_mul_result_type, ObExprResultTypeUtil::get_mul_calc_type, mul_funcs_) { param_lazy_eval_ = lib::is_oracle_mode(); } int ObExprMul::calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, ObExprTypeCtx &type_ctx) const { int ret = OB_SUCCESS; if (OB_FAIL(ObArithExprOperator::calc_result_type2(type, type1, type2, type_ctx))) { } else if (lib::is_oracle_mode()){ if (type.is_oracle_decimal()) { type.set_scale(NUMBER_SCALE_UNKNOWN_YET); type.set_precision(PRECISION_UNKNOWN_YET); } else if (type.get_type_class() == ObIntervalTC) { 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()); } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("mul expr only support number or char-type for now", K(ret), K(type1), K(type2)); ObObjType err_type = !type1.is_number() && !type1.is_varchar_or_char() ? type1.get_type() : type2.get_type(); LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(ObNumberType), ob_obj_type_str(err_type)); } } else { ObScale scale1 = static_cast(MAX(type1.get_scale(), 0)); ObScale scale2 = static_cast(MAX(type2.get_scale(), 0)); if (SCALE_UNKNOWN_YET == type1.get_scale() || SCALE_UNKNOWN_YET == type2.get_scale()) { type.set_scale(SCALE_UNKNOWN_YET); } else { 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)); } } ObPrecision precision1 = static_cast(MAX(type1.get_precision(), 0)); ObPrecision precision2 = static_cast(MAX(type2.get_precision(), 0)); if (OB_UNLIKELY(PRECISION_UNKNOWN_YET == type1.get_precision()) || OB_UNLIKELY(PRECISION_UNKNOWN_YET == type2.get_precision())) { type.set_precision(PRECISION_UNKNOWN_YET); } else { // estimated precision 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; } int ObExprMul::calc(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { ObCalcTypeFunc calc_type_func = ObExprResultTypeUtil::get_arith_result_type; return ObArithExprOperator::calc(res, left, right, allocator, scale, calc_type_func, mul_funcs_); } int ObExprMul::calc(ObObj &res, const ObObj &left, const ObObj &right, ObExprCtx &expr_ctx, ObScale scale) { int ret = OB_SUCCESS; const ObObjTypeClass tc1 = left.get_type_class(); const ObObjTypeClass tc2 = right.get_type_class(); if (lib::is_oracle_mode() && ObIntervalTC == tc1 && ObNumberTC == tc2) { ret = mul_interval(res, left, right, expr_ctx.calc_buf_, scale); } else if (lib::is_oracle_mode() && ObNumberTC == tc1 && ObIntervalTC == tc2) { ret = mul_interval(res, right, left, expr_ctx.calc_buf_, scale); } else { ret = ObArithExprOperator::calc(res, left, right, expr_ctx, scale, ObExprResultTypeUtil::get_mul_result_type, mul_funcs_); } return ret; } ObArithFunc ObExprMul::mul_funcs_[ObMaxTC] = { NULL, ObExprMul::mul_int, ObExprMul::mul_uint, ObExprMul::mul_float, ObExprMul::mul_double, ObExprMul::mul_number, NULL,//datetime NULL,//date NULL,//time NULL,//year NULL,//string NULL,//extend NULL,//unknown NULL,//text NULL,//bit NULL,//enumset NULL,//enumsetInner NULL,//otimestamp NULL,//raw NULL,//interval }; ObArithFunc ObExprMul::agg_mul_funcs_[ObMaxTC] = { NULL, ObExprMul::mul_int, ObExprMul::mul_uint, ObExprMul::mul_float, ObExprMul::mul_double_no_overflow, ObExprMul::mul_number, NULL,//datetime NULL,//date NULL,//time NULL,//year NULL,//string NULL,//extend NULL,//unknown NULL,//text NULL,//bit NULL,//enumset NULL,//enumsetInner NULL,//otimestamp NULL,//raw NULL,//interval }; int ObExprMul::mul_int(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { int ret = OB_SUCCESS; int64_t left_i = left.get_int(); int64_t right_i = right.get_int(); char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; int64_t pos = 0; if (left.get_type_class() == right.get_type_class()) { if (OB_UNLIKELY(is_multi_overflow64(left_i, right_i))) { ret = OB_OPERATE_OVERFLOW; pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%ld * %ld)'", left_i, right_i); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT", expr_str); } res.set_int(left_i * right_i); } else if (OB_UNLIKELY(ObUIntTC != right.get_type_class())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid types", K(ret), K(left), K(right)); } else { if (OB_UNLIKELY(is_int_uint_mul_out_of_range(left_i, right_i))) { ret = OB_OPERATE_OVERFLOW; pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%ld * %lu)'", left_i, right_i); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT UNSIGNED", expr_str); } res.set_uint64(left_i * right_i); } UNUSED(allocator); UNUSED(scale); return ret; } int ObExprMul::mul_uint(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { int ret = OB_SUCCESS; uint64_t left_i = left.get_uint64(); uint64_t right_i = right.get_uint64(); char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; int64_t pos = 0; if (left.get_type_class() == right.get_type_class()) { if (OB_UNLIKELY(is_uint_uint_mul_out_of_range(left_i, right_i))) { ret = OB_OPERATE_OVERFLOW; pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%lu * %lu)'", left_i, right_i); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT UNSIGNED", expr_str); } res.set_uint64(left_i * right_i); } else if (OB_UNLIKELY(ObIntTC != right.get_type_class())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid types", K(ret), K(left), K(right)); } else { if (OB_UNLIKELY(is_int_uint_mul_out_of_range(right_i, left_i))) { ret = OB_OPERATE_OVERFLOW; pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%lu * %ld)'", left_i, right_i); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT UNSIGNED", expr_str); } res.set_uint64(left_i * right_i); } UNUSED(allocator); UNUSED(scale); return ret; } int ObExprMul::mul_float(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!lib::is_oracle_mode())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("only oracle mode arrive here", K(ret), K(left), K(right)); } else if (OB_UNLIKELY(left.get_type_class() != right.get_type_class())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid types", K(ret), K(left), K(right)); } else { float left_f = left.get_float(); float right_f = right.get_float(); res.set_float(left_f * right_f); if (OB_UNLIKELY(is_float_out_of_range(res.get_float())) && !lib::is_oracle_mode()) { ret = OB_OPERATE_OVERFLOW; char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%e * %e)'", left_f, right_f); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BINARY_FLOAT", expr_str); LOG_WARN("float out of range", K(ret), K(left), K(right), K(res)); } LOG_DEBUG("succ to mul float", K(left), K(right)); } UNUSED(allocator); UNUSED(scale); return ret; } int ObExprMul::mul_double(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { int ret = OB_SUCCESS; if (OB_UNLIKELY(left.get_type_class() != right.get_type_class())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid types", K(ret), K(left), K(right)); } else { double left_d = left.get_double(); double right_d = right.get_double(); res.set_double(left_d * right_d); if (OB_UNLIKELY(is_double_out_of_range(res.get_double())) && !lib::is_oracle_mode()) { ret = OB_OPERATE_OVERFLOW; char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%e * %e)'", left_d, right_d); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, lib::is_oracle_mode() ? "BINARY_DOUBLE" : "DOUBLE", expr_str); LOG_WARN("double out of range", K(ret), K(left), K(right), K(res)); res.set_null(); } LOG_DEBUG("succ to mul double", K(left), K(right)); } UNUSED(allocator); UNUSED(scale); return ret; } int ObExprMul::mul_double_no_overflow(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *, ObScale) { int ret = OB_SUCCESS; if (OB_UNLIKELY(left.get_type_class() != right.get_type_class())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid types", K(ret), K(left), K(right)); } else { double left_d = left.get_double(); double right_d = right.get_double(); res.set_double(left_d * right_d); LOG_DEBUG("succ to mul double", K(left), K(right)); } return ret; } int ObExprMul::mul_number(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { int ret = OB_SUCCESS; number::ObNumber res_nmb; if (OB_UNLIKELY(NULL == allocator)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allocator is null", K(ret)); } else if (OB_FAIL(left.get_number().mul_v3(right.get_number(), res_nmb, *allocator))) { LOG_WARN("failed to mul numbers", K(ret), K(left), K(right)); } else { ObObjType res_type = res.get_type(); if (ObUNumberType == res_type) { res.set_unumber(res_nmb); } else { res.set_number(res_nmb); } } UNUSED(scale); return ret; } int ObExprMul::mul_interval(ObObj &res, const ObObj &left, const ObObj &right, ObIAllocator *allocator, ObScale scale) { int ret = OB_SUCCESS; number::ObNumber res_number; number::ObNumber left_number; if (OB_UNLIKELY(left.get_type_class() != ObIntervalTC) || OB_UNLIKELY(right.get_type_class() != ObNumberTC)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid types", K(ret), K(left), K(right)); } else if (OB_ISNULL(allocator)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allocator is null", K(ret)); } else if (left.is_interval_ym()) { int64_t result_nmonth = 0; ObIntervalYMValue interval_res; if (OB_FAIL(left_number.from(left.get_interval_ym().get_nmonth(), *allocator))) { LOG_WARN("failed to convert to number", K(ret)); } else if (OB_FAIL(left_number.mul_v3(right.get_number(), res_number, *allocator))) { LOG_WARN("failed to do mul", K(ret)); } else if (OB_FAIL(res_number.trunc(0))) { LOG_WARN("failed to do trunc", K(ret)); } else if (OB_UNLIKELY(!res_number.is_valid_int64(result_nmonth))) { ret = OB_INVALID_NUMERIC; LOG_WARN("failed to get int64_t from number", K(ret)); } else { interval_res = ObIntervalYMValue(result_nmonth); if (OB_FAIL(interval_res.validate())) { LOG_WARN("invalid interval ym result", K(ret), K(interval_res)); } else { res.set_interval_ym(interval_res); } } } else { int64_t result_nsecond = 0; int64_t result_fs = 0; number::ObNumber nvalue; number::ObNumber fsecond; number::ObNumber power10; number::ObNumber fvalue; ObIntervalDSValue interval_res; static_assert(number::ObNumber::BASE == ObIntervalDSValue::MAX_FS_VALUE, "the mul caculation between interval day to second and number is base on this constrain"); if (OB_FAIL(nvalue.from(left.get_interval_ds().get_nsecond(), *allocator))) { LOG_WARN("failed to convert interval to number", K(ret)); } else if (OB_FAIL(fsecond.from(static_cast(left.get_interval_ds().get_fs()), *allocator))) { LOG_WARN("failed to convert interval to number", K(ret)); } else if (OB_FAIL(power10.from(static_cast(ObIntervalDSValue::MAX_FS_VALUE), *allocator))) { LOG_WARN("failed to round number", K(ret)); } else if (OB_FAIL(fsecond.div_v3(power10, fvalue, *allocator))) { LOG_WARN("fail to div fs", K(ret)); } else if (OB_FAIL(nvalue.add_v3(fvalue, left_number, *allocator))) { LOG_WARN("failed to add number", K(ret)); } else if (OB_FAIL(left_number.mul_v3(right.get_number(), res_number, *allocator))) { LOG_WARN("failed to do mul", K(ret)); } else if (OB_FAIL(res_number.round(MAX_SCALE_FOR_ORACLE_TEMPORAL))) { LOG_WARN("failed to round number", K(res_number)); } else if (OB_UNLIKELY(!res_number.is_int_parts_valid_int64(result_nsecond, result_fs))) { ret = OB_INVALID_NUMERIC; LOG_WARN("invalid date format", K(ret)); } else { if (result_nsecond < 0) { result_fs = -result_fs; } interval_res = ObIntervalDSValue(result_nsecond, static_cast(result_fs)); if (OB_FAIL(interval_res.validate())) { LOG_WARN("invalid interval result", K(ret), K(nvalue), K(fvalue), K(left_number), K(interval_res)); } else { res.set_interval_ds(interval_res); } } } res.set_scale(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][res.get_type()].get_scale()); UNUSED(scale); return ret; } struct ObIntIntBatchMulRaw : public ObArithOpRawType { static void raw_op(int64_t &res, const int64_t l, const int64_t r) { res = l * r; } static int raw_check(const int64_t, const int64_t l, const int64_t r) { int ret = OB_SUCCESS; long long res; if (OB_UNLIKELY(ObExprMul::is_mul_out_of_range(l, r, res))) { char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; ret = OB_OPERATE_OVERFLOW; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%ld * %ld)'", l, r); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT", expr_str); } return ret; } }; int ObExprMul::mul_int_int(EVAL_FUNC_ARG_DECL) { return def_arith_eval_func>(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_int_int_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST); } struct ObIntUIntBatchMulRaw : public ObArithOpRawType { static void raw_op(uint64_t &res, const int64_t l, const uint64_t r) { res = l * r; } static int raw_check(const uint64_t, const int64_t l, const uint64_t r) { int ret = OB_SUCCESS; if (OB_UNLIKELY(ObExprMul::is_int_uint_mul_out_of_range(l, r))) { char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; ret = OB_OPERATE_OVERFLOW; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%ld * %lu)'", l, r); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT UNSIGNED", expr_str); } return ret; } }; int ObExprMul::mul_int_uint(EVAL_FUNC_ARG_DECL) { return def_arith_eval_func>(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_int_uint_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST); } struct ObUIntIntBatchMulRaw : public ObArithOpRawType { static void raw_op(uint64_t &res, const uint64_t l, const int64_t r) { res = l * r; } static int raw_check(const uint64_t, const uint64_t l, const int64_t r) { int ret = OB_SUCCESS; if (OB_UNLIKELY(ObExprMul::is_int_uint_mul_out_of_range(r, l))) { char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; ret = OB_OPERATE_OVERFLOW; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%lu * %ld)'", l, r); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT UNSIGNED", expr_str); } return ret; } }; int ObExprMul::mul_uint_int(EVAL_FUNC_ARG_DECL) { return def_arith_eval_func>(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_uint_int_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST); } struct ObUIntUIntBatchMulRaw : public ObArithOpRawType { static void raw_op(uint64_t &res, const uint64_t l, const uint64_t r) { res = l * r; } static int raw_check(const uint64_t, const uint64_t l, const uint64_t r) { int ret = OB_SUCCESS; if (OB_UNLIKELY(ObExprMul::is_uint_uint_mul_out_of_range(l, r))) { char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; ret = OB_OPERATE_OVERFLOW; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%lu * %lu)'", l, r); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BIGINT UNSIGNED", expr_str); } return ret; } }; int ObExprMul::mul_uint_uint(EVAL_FUNC_ARG_DECL) { return def_arith_eval_func>(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_uint_uint_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST); } struct ObFloatBatchMulRawNoCheck : public ObArithOpRawType { static void raw_op(float &res, const float l, const float r) { res = l * r; } static int raw_check(const float, const float, const float) { return OB_SUCCESS; } }; struct ObFloatBatchMulRawWithCheck: public ObFloatBatchMulRawNoCheck { static int raw_check(const float res, const float l, const float r) { int ret = OB_SUCCESS; if (OB_UNLIKELY(ObExprMul::is_float_out_of_range(res))) { char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; ret = OB_OPERATE_OVERFLOW; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%e * %e)'", l, r); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "FLOAT", expr_str); LOG_WARN("float out of range", K(l), K(r), K(res)); } return ret; } }; int ObExprMul::mul_float(EVAL_FUNC_ARG_DECL) { return lib::is_oracle_mode() ? def_arith_eval_func>(EVAL_FUNC_ARG_LIST) : def_arith_eval_func>(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_float_batch(BATCH_EVAL_FUNC_ARG_DECL) { return lib::is_oracle_mode() ? def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST) : def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST); } struct ObDoubleBatchMulRawNoCheck : public ObArithOpRawType { static void raw_op(double &res, const double l, const double r) { res = l * r; } static int raw_check(const double , const double , const double) { return OB_SUCCESS; } }; struct ObDoubleBatchMulRawWithCheck: public ObDoubleBatchMulRawNoCheck { static int raw_check(const double res, const double l, const double r) { int ret = OB_SUCCESS; if (OB_UNLIKELY(ObExprMul::is_double_out_of_range(res))) { char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH]; ret = OB_OPERATE_OVERFLOW; int64_t pos = 0; databuff_printf(expr_str, OB_MAX_TWO_OPERATOR_EXPR_LENGTH, pos, "'(%e * %e)'", l, r); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DOUBLE", expr_str); LOG_WARN("double out of range", K(l), K(r), K(res)); } return ret; } }; int ObExprMul::mul_double(EVAL_FUNC_ARG_DECL) { return lib::is_oracle_mode() || T_OP_AGG_MUL == expr.type_ ? def_arith_eval_func>(EVAL_FUNC_ARG_LIST) : def_arith_eval_func>(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_double_batch(BATCH_EVAL_FUNC_ARG_DECL) { return lib::is_oracle_mode() || T_OP_AGG_MUL == expr.type_ ? def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST) : def_batch_arith_op>(BATCH_EVAL_FUNC_ARG_LIST); } struct ObNumberMulFunc { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { int ret = OB_SUCCESS; char local_buff[ObNumber::MAX_BYTE_LEN]; ObDataBuffer local_alloc(local_buff, ObNumber::MAX_BYTE_LEN); number::ObNumber l_num(l.get_number()); number::ObNumber r_num(r.get_number()); number::ObNumber res_num; if (OB_FAIL(l_num.mul_v3(r_num, res_num, local_alloc))) { LOG_WARN("mul num failed", K(ret), K(l_num), K(r_num)); } else { res.set_number(res_num); } return ret; } }; int ObExprMul::mul_number(EVAL_FUNC_ARG_DECL) { return def_arith_eval_func(EVAL_FUNC_ARG_LIST); } int ObExprMul::mul_number_batch(BATCH_EVAL_FUNC_ARG_DECL) { LOG_DEBUG("mul_number_batch begin"); int ret = OB_SUCCESS; ObDatumVector l_datums; ObDatumVector r_datums; const ObExpr &left = *expr.args_[0]; const ObExpr &right = *expr.args_[1]; if (OB_FAIL(binary_operand_batch_eval(expr, ctx, skip, size, lib::is_oracle_mode()))) { LOG_WARN("number multiply batch evaluation failure", K(ret)); } else { l_datums = left.locate_expr_datumvector(ctx); r_datums = right.locate_expr_datumvector(ctx); } if (OB_SUCC(ret)) { char local_buff[ObNumber::MAX_BYTE_LEN]; ObDataBuffer local_alloc(local_buff, ObNumber::MAX_BYTE_LEN); ObDatumVector results = expr.locate_expr_datumvector(ctx); ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); for (auto i = 0; OB_SUCC(ret) && i < size; i++) { if (eval_flags.at(i) || skip.at(i)) { continue; } if (l_datums.at(i)->is_null() || r_datums.at(i)->is_null()) { results.at(i)->set_null(); eval_flags.set(i); continue; } ObNumber res_num; ObNumber l_num(l_datums.at(i)->get_number()); ObNumber r_num(r_datums.at(i)->get_number()); uint32_t *res_digits = const_cast (results.at(i)->get_number_digits()); ObNumber::Desc &desc_buf = const_cast (results.at(i)->get_number_desc()); // Notice that, space of desc_buf is allocated in frame but without memset operation, which causes random memory content. // And the reserved in storage layer should be 0, thus you must replacement new here to avoid checksum error, etc. ObNumber::Desc *res_desc = new (&desc_buf) ObNumber::Desc(); // speedup detection if (ObNumber::try_fast_mul(l_num, r_num, res_digits, *res_desc)) { results.at(i)->set_pack(sizeof(number::ObCompactNumber) + res_desc->len_ * sizeof(*res_digits)); eval_flags.set(i); // LOG_DEBUG("mul speedup", K(l_num.format()), // K(r_num.format()), K(res_num.format())); } else { // normal path: no speedup if (OB_FAIL(l_num.mul_v3(r_num, res_num, local_alloc))) { LOG_WARN("mul num failed", K(ret), K(l_num), K(r_num)); } else { results.at(i)->set_number(res_num); eval_flags.set(i); } local_alloc.free(); } } } LOG_DEBUG("mul_number_batch done"); return ret; } struct ObIntervalYMNumberMulFunc { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const bool &swap_l_r) const { int ret = OB_SUCCESS; const ObDatum *interval_ym_datum = !swap_l_r ? &l : &r; const ObDatum *num_datum = !swap_l_r ? &r : &l; ObIntervalYMValue value_ym = ObIntervalYMValue(interval_ym_datum->get_interval_nmonth()); ObNumber value_number = num_datum->get_number(); char local_buff[ObNumber::MAX_BYTE_LEN * 2]; ObDataBuffer local_alloc(local_buff, ObNumber::MAX_BYTE_LEN * 2); ObNumber result; ObNumber ym_number; int64_t result_nmonth = 0; if (OB_FAIL(ym_number.from(value_ym.get_nmonth(), local_alloc))) { LOG_WARN("failed to convert to number", K(ret)); } else if (OB_FAIL(ym_number.mul_v3(value_number, result, local_alloc))) { LOG_WARN("failed to do mul", K(ret)); } else if (OB_FAIL(result.trunc(0))) { LOG_WARN("failed to do trunc", K(ret)); } else if (OB_UNLIKELY(!result.is_valid_int64(result_nmonth))) { ret = OB_INVALID_NUMERIC; LOG_WARN("failed to get int64_t from number", K(ret)); } else { ObIntervalYMValue value = ObIntervalYMValue(result_nmonth); if (OB_FAIL(value.validate())) { LOG_WARN("invalid interval ym result", K(ret), K(value)); } else { res.set_interval_nmonth(result_nmonth); } } return ret; } }; int ObExprMul::mul_intervalym_number_common(EVAL_FUNC_ARG_DECL,const bool number_left) { return def_arith_eval_func(EVAL_FUNC_ARG_LIST, number_left); } int ObExprMul::mul_intervalym_number_batch(BATCH_EVAL_FUNC_ARG_DECL) { const bool swap_l_r = false; return def_batch_arith_op_by_datum_func( BATCH_EVAL_FUNC_ARG_LIST, swap_l_r); } int ObExprMul::mul_number_intervalym_batch(BATCH_EVAL_FUNC_ARG_DECL) { const bool swap_l_r = true; return def_batch_arith_op_by_datum_func( BATCH_EVAL_FUNC_ARG_LIST, swap_l_r); } struct ObIntervalDSNumberMulFunc { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const bool &swap_l_r) const { int ret = OB_SUCCESS; const ObDatum *interval_ds_datum = !swap_l_r ? &l : &r; const ObDatum *num_datum = !swap_l_r ? &r : &l; ObIntervalDSValue value_ds = interval_ds_datum->get_interval_ds(); ObNumber value_number = num_datum->get_number(); char local_buff[ObNumber::MAX_BYTE_LEN * 6]; ObDataBuffer local_alloc(local_buff, ObNumber::MAX_BYTE_LEN * 6); int64_t result_nsecond = 0; int64_t result_fs = 0; number::ObNumber nvalue; number::ObNumber fsecond; number::ObNumber power10; number::ObNumber fvalue; number::ObNumber left_number; number::ObNumber res_number; if (OB_FAIL(nvalue.from(value_ds.get_nsecond(), local_alloc))) { LOG_WARN("failed to convert interval to number", K(ret)); } else if (OB_FAIL(fsecond.from(static_cast(value_ds.get_fs()), local_alloc))) { LOG_WARN("failed to convert interval to number", K(ret)); } else if (OB_FAIL(power10.from(static_cast(ObIntervalDSValue::MAX_FS_VALUE), local_alloc))) { LOG_WARN("failed to round number", K(ret)); } else if (OB_FAIL(fsecond.div_v3(power10, fvalue, local_alloc))) { LOG_WARN("fail to div fs", K(ret)); } else if (OB_FAIL(nvalue.add_v3(fvalue, left_number, local_alloc))) { LOG_WARN("failed to add number", K(ret)); } else if (OB_FAIL(left_number.mul_v3(value_number, res_number, local_alloc))) { LOG_WARN("failed to do mul", K(ret)); } else if (OB_FAIL(res_number.round(MAX_SCALE_FOR_ORACLE_TEMPORAL))) { LOG_WARN("failed to round number", K(res_number)); } else if (OB_UNLIKELY(!res_number.is_int_parts_valid_int64(result_nsecond, result_fs))) { ret = OB_INVALID_NUMERIC; LOG_WARN("invalid date format", K(ret)); } else { if (result_nsecond < 0) { result_fs = -result_fs; } ObIntervalDSValue value = ObIntervalDSValue(result_nsecond, static_cast(result_fs)); if (OB_FAIL(value.validate())) { LOG_WARN("invalid interval result", K(ret), K(nvalue), K(fvalue), K(left_number), K(value)); } else { res.set_interval_ds(value); } } return ret; } }; int ObExprMul::mul_intervalds_number_common(EVAL_FUNC_ARG_DECL, const bool number_left) { return def_arith_eval_func(EVAL_FUNC_ARG_LIST, number_left); } int ObExprMul::mul_intervalds_number_batch(BATCH_EVAL_FUNC_ARG_DECL) { const bool swap_l_r = false; return def_batch_arith_op_by_datum_func( BATCH_EVAL_FUNC_ARG_LIST, swap_l_r); } int ObExprMul::mul_number_intervalds_batch(BATCH_EVAL_FUNC_ARG_DECL) { const bool swap_l_r = true; return def_batch_arith_op_by_datum_func( BATCH_EVAL_FUNC_ARG_LIST, swap_l_r); } int ObExprMul::cg_expr(ObExprCGCtx &op_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const { #define SET_MUL_FUNC_PTR(v) \ rt_expr.eval_func_ = ObExprMul::v; \ rt_expr.eval_batch_func_ = ObExprMul::v##_batch; int ret = OB_SUCCESS; UNUSED(raw_expr); UNUSED(op_cg_ctx); OB_ASSERT(2 == rt_expr.arg_cnt_); OB_ASSERT(NULL != rt_expr.args_); OB_ASSERT(NULL != rt_expr.args_[0]); OB_ASSERT(NULL != rt_expr.args_[1]); const common::ObObjType left = rt_expr.args_[0]->datum_meta_.type_; const common::ObObjType right = rt_expr.args_[1]->datum_meta_.type_; const ObObjTypeClass left_tc = ob_obj_type_class(left); const ObObjTypeClass right_tc = ob_obj_type_class(right); OB_ASSERT(left == input_types_[0].get_calc_type()); OB_ASSERT(right == input_types_[1].get_calc_type()); rt_expr.inner_functions_ = NULL; LOG_DEBUG("arrive here cg_expr", K(ret), K(rt_expr)); switch (rt_expr.datum_meta_.type_) { case ObIntType: { SET_MUL_FUNC_PTR(mul_int_int); break; } case ObUInt64Type: { if (ObIntTC == left_tc) { if (ObUIntTC == right_tc) { SET_MUL_FUNC_PTR(mul_int_uint); } } else if (ObUIntTC == left_tc) { if (ObIntTC == right_tc) { SET_MUL_FUNC_PTR(mul_uint_int); } else if (ObUIntTC == right_tc) { SET_MUL_FUNC_PTR(mul_uint_uint); } } break; } case ObFloatType: { SET_MUL_FUNC_PTR(mul_float); break; } case ObDoubleType: { SET_MUL_FUNC_PTR(mul_double); break; } case ObUNumberType: case ObNumberType: { SET_MUL_FUNC_PTR(mul_number); break; } case ObIntervalYMType: { if (ObIntervalYMType == left) { SET_MUL_FUNC_PTR(mul_intervalym_number); } else { SET_MUL_FUNC_PTR(mul_number_intervalym); } break; } case ObIntervalDSType: { if (ObIntervalDSType == left) { SET_MUL_FUNC_PTR(mul_intervalds_number); } else { SET_MUL_FUNC_PTR(mul_number_intervalds); } break; } default: { break; } } if (OB_ISNULL(rt_expr.eval_func_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected result type", K(ret), K(rt_expr.datum_meta_.type_), K(left), K(right)); } return ret; #undef SET_MUL_FUNC_PTR } } }