/** * 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. */ #ifndef _OB_ENGINE_EXPR_EXPR_UTIL_H_ #define _OB_ENGINE_EXPR_EXPR_UTIL_H_ #include "lib/number/ob_number_v2.h" #include "sql/engine/expr/ob_expr_operator.h" namespace oceanbase { namespace sql { // // temporary allocator for number operation. e.g.: // ObNumStackAllocator num_alloc; // number::ObNumber num; // num.from(int_val, num_alloc); // expr_datum.set_number(num); // set_datum will deep copy num value. // template class ObNumStackAllocator : public common::ObDataBuffer { public: ObNumStackAllocator() : ObDataBuffer(local_buf_, sizeof(local_buf_)) {} private: char local_buf_[NUM_CNT * common::number::ObNumber::MAX_BYTE_LEN]; }; typedef ObNumStackAllocator<1> ObNumStackOnceAlloc; #define array_elements(A) ((uint)(sizeof(A) / sizeof(A[0]))) class ObExprUtil { public: static int get_trunc_int64(const common::ObObj& obj, common::ObExprCtx& expr_ctx, int64_t& out); static int get_round_int64(const common::ObObj& obj, common::ObExprCtx& expr_ctx, int64_t& out); static int get_trunc_int64(common::number::ObNumber& nmb, common::ObExprCtx& expr_ctx, int64_t& out); static int get_round_int64(common::number::ObNumber& nmb, common::ObExprCtx& expr_ctx, int64_t& out); static int kmp_reverse(const char* x, int64_t m, const char* y, int64_t n, int64_t count, int64_t& pos); static int kmp(const char* x, int64_t m, const char* y, int64_t n, int64_t count, int64_t& pos); static int get_mb_str_info(const common::ObString& str, common::ObCollationType cs_type, common::ObIArray& byte_num, common::ObIArray& byte_offset); static double round_double(double val, int64_t dec); static double round_double_nearest(double val, int64_t dec); static uint64_t round_uint64(uint64_t val, int64_t dec); static double trunc_double(double val, int64_t dec); template static T trunc_integer(T val, int64_t dec); // truncate the decimal part, truncate to INT64_MAX/INT64_MIN too if out of range. static int trunc_num2int64(const common::number::ObNumber& nmb, int64_t& v); // get number out of ObDatum and truncate to int64 static int trunc_num2int64(const common::ObDatum& datum, int64_t& v) { return trunc_num2int64(common::number::ObNumber(datum.get_number()), v); } // Get integer value from integer parameter which type is ObIntType in mysql // or ObNumberType in oracle. // // Keep %int_val unchanged if datum is NULL or datum->is_null(). static int get_int_param_val(common::ObDatum* datum, int64_t& int_val); // Set the ASCII string to expression result. // e.g.: // dump() need result is NLS_CHARACTERSET, but we can only generate ASCII string in code, // this function is used to convert the result characterset. static int set_expr_ascii_result( const ObExpr& expr, ObEvalCtx& ctx, common::ObDatum& expr_datum, const common::ObString& ascii_str); static int convert_string_collation(const common::ObString& in_str, const common::ObCollationType& in_collation, common::ObString& out_str, const common::ObCollationType& out_collation, common::ObIAllocator& alloc); static int need_convert_string_collation( const common::ObCollationType& in_collation, const common::ObCollationType& out_collation, bool& need_convert); // deep copy src to out. // it is ok if src and out is same. like this deep_copy_str(str1, str1, alloc) static int deep_copy_str(const common::ObString& src, common::ObString& out, common::ObIAllocator& alloc); static int eval_generated_column(const ObExpr& rt_expr, ObEvalCtx& ctx, ObDatum& expr_datum); static int eval_stack_overflow_check(const ObExpr& rt_expr, ObEvalCtx& ctx, ObDatum& expr_datum); private: static int get_int64_from_num(common::number::ObNumber& nmb, common::ObExprCtx& expr_ctx, const bool is_trunc, // true: trunc; false: round int64_t& out); static int get_int64_from_obj(const common::ObObj& obj, common::ObExprCtx& expr_ctx, const bool is_trunc, // true: trunc; false: round int64_t& out); DISALLOW_COPY_AND_ASSIGN(ObExprUtil); }; // make sure T is int/uint type template T ObExprUtil::trunc_integer(T val, int64_t dec) { volatile T res = 0; if (dec >= 0) { res = val; } else { const int64_t max_integer_desc = 19; if (std::abs(dec) > max_integer_desc) { res = 0; } else { const T pow_val = std::pow(10, static_cast(std::abs(dec))); res = (val / pow_val) * pow_val; } } return res; } // define triangle calc functions // eg: sin/cos/tan sinh/cosh/tanh asin/acos/atan // note: atan2 is defined elsewhere #define DEF_CALC_TRIGONOMETRIC_EXPR(tritype, INVALID_DOUBLE_ARG_CHECK, INVALID_DOUBLE_ARG_ERRNO) \ int calc_##tritype##_expr(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum) \ { \ int ret = OB_SUCCESS; \ ObDatum* radian = NULL; \ if (OB_FAIL(expr.args_[0]->eval(ctx, radian))) { \ LOG_WARN("eval radian arg failed", K(ret), K(expr)); \ } else if (radian->is_null()) { \ /* radian is already be cast to number type, no need to is_null_oracle */ \ res_datum.set_null(); \ } else if (ObNumberType == expr.args_[0]->datum_meta_.type_) { \ number::ObNumber res_nmb; \ number::ObNumber radian_nmb(radian->get_number()); \ if (OB_FAIL(radian_nmb.tritype(res_nmb, ctx.get_reset_tmp_alloc()))) { \ LOG_WARN("calc expr failed", K(ret), K(radian_nmb), K(expr)); \ } else { \ res_datum.set_number(res_nmb); \ } \ } else if (ObDoubleType == expr.args_[0]->datum_meta_.type_) { \ const double arg = radian->get_double(); \ if (INVALID_DOUBLE_ARG_CHECK) { \ res_datum.set_null(); \ } else { \ res_datum.set_double(tritype(arg)); \ } \ } else { \ ret = OB_ERR_UNEXPECTED; \ } \ return ret; \ } } // namespace sql } // namespace oceanbase #endif /* _OB_ENGINE_EXPR_EXPR_UTIL_H_ */