/** * 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_operator.h" #include #include "lib/oblog/ob_log.h" //#include "sql/engine/expr/ob_expr_promotion_util.h" #include "sql/engine/expr/ob_expr_result_type_util.h" #include "sql/engine/expr/ob_expr_less_than.h" #include "sql/engine/ob_physical_plan_ctx.h" #include "sql/engine/expr/ob_expr_add.h" #include "sql/engine/expr/ob_expr_minus.h" #include "sql/engine/expr/ob_expr_subquery_ref.h" #include "sql/engine/expr/ob_expr_null_safe_equal.h" #include "sql/session/ob_sql_session_info.h" #include "sql/engine/expr/ob_infix_expression.h" #include "sql/code_generator/ob_static_engine_expr_cg.h" #include "sql/engine/subquery/ob_subplan_filter_op.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_expr_util.h" namespace oceanbase { using namespace common; using namespace common::number; using namespace oceanbase::lib; namespace sql { static const int32_t DAYS_PER_YEAR[2] = {365, 366}; static const int8_t DAYS_PER_MON[2][12 + 1] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; #define IS_LEAP_YEAR(y) ((((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) ? 1 : 0) const char* ObExprTRDateFormat::FORMATS_TEXT[FORMAT_MAX_TYPE] = {"SYYYY", "YYYY", "YEAR", "SYEAR", "YYY", "YY", "Y", "IYYY", "IY", "I", "Q", "MONTH", "MON", "MM", "RM", "WW", "IW", "W", "DDD", "DD", "J", "DAY", "DY", "D", "HH", "HH12", "HH24", "MI", "CC", "SCC"}; uint64_t ObExprTRDateFormat::FORMATS_HASH[FORMAT_MAX_TYPE] = {0}; OB_SERIALIZE_MEMBER(ObFuncInputType, calc_meta_, max_length_, flag_); OB_SERIALIZE_MEMBER_INHERIT( ObExprResType, ObObjMeta, accuracy_, calc_accuracy_, calc_type_, res_flags_, row_calc_cmp_types_); const ObTimeZoneInfo* get_timezone_info(const ObSQLSessionInfo* session) { return TZ_INFO(session); } const common::ObString* get_nls_formats(const ObSQLSessionInfo* session) { return GET_NLS_FORMATS(session); } const common::ObObjPrintParams get_obj_print_params(const ObSQLSessionInfo* session) { return CREATE_OBJ_PRINT_PARAM(session); } int64_t get_cur_time(ObPhysicalPlanCtx* phy_plan_ctx) { return NULL != phy_plan_ctx ? phy_plan_ctx->get_cur_time().get_datetime() : 0; } int get_tz_offset(const ObTimeZoneInfo* tz_info, int64_t& offset) { int ret = OB_SUCCESS; offset = 0; int32_t tmp_offset = 0; if (NULL != tz_info && OB_SUCC(tz_info->get_timezone_offset(0, tmp_offset))) { offset = SEC_TO_USEC(tmp_offset); } return ret; } int ObExprOperator::assign(const ObExprOperator& other) { int ret = OB_SUCCESS; if (OB_LIKELY(this != &other)) { if (OB_FAIL(result_type_.assign(other.result_type_))) { LOG_WARN("copy result_type failed", K(ret)); } else if (OB_FAIL(input_types_.assign(other.input_types_))) { LOG_WARN("copy input_types failed", K(ret)); } else { this->magic_ = other.magic_; this->id_ = other.id_; this->row_dimension_ = other.row_dimension_; this->real_param_num_ = other.real_param_num_; this->is_called_in_sql_ = other.is_called_in_sql_; this->extra_serialize_ = other.extra_serialize_; } } return ret; } int ObExprOperator::cg_expr(ObExprCGCtx&, const ObRawExpr& raw_expr, ObExpr&) const { int ret = STATIC_ENG_NOT_IMPLEMENT; LOG_INFO("not implemented in sql static typing engine, " "will retry the old engine automatically", K(ret), K(raw_expr)); return ret; } // check function pointer in vtable to detect cg_expr() is overwrite or not. bool ObExprOperator::is_default_expr_cg() const { static ObArenaAllocator alloc; static ObExprOperator base(alloc, T_NULL, "fake_null_operator", 0); typedef int (ObExprOperator::*CGFunc)(ObExprCGCtx & op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const; union { CGFunc func_; int64_t val_; int64_t values_[2]; } func_val; static_assert(sizeof(int64_t) * 2 == sizeof(CGFunc), "size mismatch"); func_val.func_ = &ObExprOperator::cg_expr; const int64_t func_idx = func_val.val_ / sizeof(void *); return (*(void***)(&base))[func_idx] == (*(void***)(this))[func_idx]; } int ObExprOperator::set_input_types(const ObIExprResTypes& expr_types) { int ret = OB_SUCCESS; input_types_.reset(); if (OB_FAIL(input_types_.reserve(expr_types.count()))) { LOG_WARN("fail to init input types", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < expr_types.count(); ++i) { const ObExprResType& t = expr_types.at(i); ObFuncInputType type(t.get_calc_meta(), t.get_length(), t.get_result_flag()); ret = input_types_.push_back(type); } return ret; } ObObjType ObExprOperator::get_calc_cast_type(ObObjType param_type, ObObjType calc_type) { ObObjType cast_type = param_type; if (ObNullType == param_type || ObNullType == calc_type) { cast_type = param_type; } else if (ObMaxType == param_type || ObMaxType == calc_type) { cast_type = param_type; } else if (ob_is_integer_type(param_type) && ob_is_integer_type(calc_type)) { cast_type = param_type; // } else if (ob_is_enumset_tc(param_type) && ob_is_enumset_numeric_type(calc_type)) { // cast_type = param_type; } else if (param_type != calc_type) { cast_type = calc_type; } return cast_type; } int OB_INLINE ObExprOperator::cast_operand_type( common::ObObj& res_obj, const ObFuncInputType& res_type, common::ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; // check if need to cast const ObObjType param_type = res_obj.get_type(); const ObObjType calc_type = res_type.get_calc_type(); const ObCollationType param_collation_type = res_obj.get_collation_type(); const ObCollationType calc_collation_type = res_type.get_calc_meta().get_collation_type(); if (OB_LIKELY((calc_type != param_type && ObNullType != param_type) || (ob_is_string_or_lob_type(param_type) && ob_is_string_or_lob_type(calc_type) && (lib::is_oracle_mode() || param_collation_type != calc_collation_type)))) { LOG_DEBUG( "need cast operand", K(res_type), K(res_type.get_calc_meta().get_scale()), K(res_obj), K(res_obj.get_scale())); ObCastMode cast_mode = get_cast_mode(); if (ob_is_string_or_lob_type(res_type.get_calc_type()) && res_type.is_zerofill()) { // For zerofilled string ObZerofillInfo zf_info(true, res_type.get_length()); EXPR_DEFINE_CAST_CTX_ZF(expr_ctx, cast_mode, &zf_info); if (OB_FAIL(ObObjCaster::to_type(res_type.get_calc_type(), cast_ctx, res_obj, res_obj))) { LOG_WARN("fail to convert type", K(ret), K(res_type.get_calc_type()), K(res_obj)); } } else { /* type collatino convertion rules: * 1.set target collation in cast_ctx.utf8mb4 is the default value * 2.if both src and dest type are ObStirngTC, rule: * a.if calc_collation is set, use it * b.if calc_collation not set, use src collation */ EXPR_DEFINE_CAST_CTX(expr_ctx, cast_mode); if (ob_is_string_or_lob_type(calc_type)) { if (ob_is_string_or_lob_type(param_type)) { if (CS_TYPE_INVALID != calc_collation_type) { cast_ctx.dest_collation_ = calc_collation_type; } else if (share::is_mysql_mode() && CS_TYPE_INVALID != param_collation_type) { cast_ctx.dest_collation_ = param_collation_type; } } else { if (CS_TYPE_INVALID != calc_collation_type) { cast_ctx.dest_collation_ = calc_collation_type; } else { cast_ctx.dest_collation_ = ObCharset::get_default_collation_oracle(CHARSET_UTF8MB4); } } } ObObj res_obj_copy = res_obj; cast_ctx.expect_obj_collation_ = cast_ctx.dest_collation_; if (OB_FAIL(ObObjCaster::to_type(res_type.get_calc_type(), cast_ctx, res_obj_copy, res_obj))) { LOG_WARN("fail to convert type", K(ret), K(res_type.get_calc_type()), K(res_obj)); } if (OB_SUCC(ret) && ob_is_string_or_lob_type(param_type) && ob_is_string_or_lob_type(calc_type) && param_collation_type != calc_collation_type && calc_collation_type != CS_TYPE_INVALID) { res_obj.set_collation_type(calc_collation_type); } } } return ret; } int ObExprOperator::cast_operand_type(ObObj* params, const int64_t param_num, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; const bool fallback_old_mode = false; if (OB_ISNULL(params) || OB_UNLIKELY(param_num < 0) || OB_UNLIKELY(param_num != real_param_num_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("NULL param or invalid number", K(params), K(param_num), K(real_param_num_), K(ret)); } else if (fallback_old_mode) { // fallback } else if (OB_UNLIKELY(real_param_num_ <= 0 || 0 == input_types_.count() || NOT_ROW_DIMENSION != row_dimension_ || T_FUN_SYS_TIMESTAMP_NVL == get_type() /*|| T_FUN_SYS_CAST == get_type() || T_OP_CASE == get_type() || T_OP_ARG_CASE == get_type() || T_FUN_COLUMN_CONV == get_type()*/)) { // skip } else if (OB_UNLIKELY(input_types_.count() != real_param_num_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("real_param_num_ is wrong", K(input_types_.count()), K_(real_param_num)); } else { // convert param types only if src and dest are different types for (int64_t i = 0; OB_SUCC(ret) && i < real_param_num_; ++i) { if (OB_FAIL(cast_operand_type(params[i], input_types_.at(i), expr_ctx))) { LOG_WARN("cast failed", K(ret), K(params[i]), K(input_types_.at(i))); } } } return ret; } int ObExprOperator::call(ObObj* stack, int64_t& stack_size, ObExprCtx& expr_ctx) const { ObObj result; int ret = OB_SUCCESS; if (OB_ISNULL(stack) || OB_ISNULL(this) || OB_UNLIKELY(real_param_num_ < 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("stack or this is null or stack_size is wrong", K(stack), K(this), K(real_param_num_), K(ret)); } else if (OB_UNLIKELY(real_param_num_ > stack_size)) { ret = OB_INVALID_ARGUMENT_NUM; LOG_WARN("wrong number of input arguments on stack", K(real_param_num_), K(stack_size), K(ret)); } else if (OB_LIKELY(row_dimension_ != NOT_ROW_DIMENSION)) { int32_t param_num = real_param_num_ * row_dimension_; if (OB_UNLIKELY(param_num > stack_size)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("wrong number of input arguments on stack", K(param_num), K(stack_size)); // vector operator } else if (OB_FAIL(this->calc_resultN(result, &stack[stack_size - param_num], param_num, expr_ctx))) { LOG_WARN("fail to calc resultN", K(ret), K(param_num), K(stack_size)); } else { stack[stack_size - param_num] = result; stack_size -= (param_num - 1); } } else if (operand_auto_cast_ && OB_FAIL(cast_operand_type(stack + stack_size - real_param_num_, real_param_num_, expr_ctx))) { LOG_WARN("fail convert operand types", K(stack_size), K(ret)); } else { if (OB_UNLIKELY(param_num_ > 0 && param_num_ != real_param_num_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("bug! param_num is not equal than real_param_num", K_(name), K(get_type_name(type_)), K_(type), K_(param_num), K_(real_param_num), K_(row_dimension), K(input_types_.count()), K(stack_size), K(ret)); } if (OB_UNLIKELY(real_param_num_ < 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("bug! real_param_num is less than 0", K_(name), K(get_type_name(type_)), K_(type), K_(param_num), K_(real_param_num), K_(row_dimension), K(input_types_.count()), K(stack_size), K(ret)); } if (OB_SUCC(ret)) { switch (param_num_) { case 0: { if (OB_FAIL(this->calc_result0(result, expr_ctx))) { LOG_WARN("fail to calc result0", K(ret), K(stack_size)); } else { stack[stack_size] = result; ++stack_size; } break; } case 1: { if (OB_FAIL(this->calc_result1(result, stack[stack_size - 1], expr_ctx))) { LOG_WARN("fail to calc result1", K(ret), K(stack_size), N_FUNC, get_type_name(type_)); } else { stack[stack_size - 1] = result; } break; } case 2: { if (OB_FAIL(this->calc_result2(result, stack[stack_size - 2], stack[stack_size - 1], expr_ctx))) { LOG_WARN("fail to calc result2", K(ret), K(stack_size), N_FUNC, get_type_name(type_)); } else { stack[stack_size - 2] = result; stack_size--; } break; } case 3: { // org mode if (OB_FAIL(this->calc_result3( result, stack[stack_size - 3], stack[stack_size - 2], stack[stack_size - 1], expr_ctx))) { LOG_WARN("fail to calc result3", K(ret), K(stack_size), N_FUNC, get_type_name(type_)); } else { stack[stack_size - 3] = result; stack_size -= 2; } break; } default: { if (OB_FAIL(this->calc_resultN(result, &stack[stack_size - real_param_num_], real_param_num_, expr_ctx))) { LOG_WARN("fail to calc resultN", K(ret), K(stack_size), N_FUNC, get_type_name(type_)); } else { stack[stack_size - real_param_num_] = result; stack_size -= real_param_num_ - 1; } break; } } // end switch if (!stack[stack_size - 1].is_bit()) { stack[stack_size - 1].set_scale(result_type_.get_scale()); } } } return ret; } int ObExprOperator::eval( common::ObExprCtx& expr_ctx, common::ObObj& val, common::ObObj* params, int64_t param_num) const { int ret = OB_SUCCESS; // some expr (e.g.: subtime) rely on the default value of ObObj, so we construct it again. // (see ObExprOperator::calc(), use an new stack ObObj variable and assign to val finally). new (&val) ObObj(); if (OB_ISNULL(params) || OB_UNLIKELY(param_num < 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else if (OB_UNLIKELY(row_dimension_ != NOT_ROW_DIMENSION)) { // row operator if (OB_FAIL(calc_resultN(val, params, param_num, expr_ctx))) { LOG_WARN("calc result failed", K(ret), K(name_), K(get_type_name(type_))); } } else if (!is_param_lazy_eval() && operand_auto_cast_ && OB_FAIL(cast_operand_type(params, param_num, expr_ctx))) { LOG_WARN("cast operand failed", K(ret)); } else { if (OB_UNLIKELY(param_num != real_param_num_) || OB_UNLIKELY(param_num_ > 0 && param_num_ != real_param_num_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("wrong param num", K(ret), K(param_num), K(param_num_), K(real_param_num_)); } else { // Must use %param_num_, because it will set to negative number to indicate that // we should call calc_resultN here. e.g.: concat switch (param_num_) { case 0: { ret = calc_result0(val, expr_ctx); break; } case 1: { ret = calc_result1(val, params[0], expr_ctx); break; } case 2: { ret = calc_result2(val, params[0], params[1], expr_ctx); break; } case 3: { ret = calc_result3(val, params[0], params[1], params[2], expr_ctx); break; } default: { ret = calc_resultN(val, params, param_num, expr_ctx); } } if (OB_FAIL(ret)) { LOG_WARN("calc result failed", K(ret), K(param_num_), K(name_), K(get_type_name(type_))); } if (!val.is_bit() && !val.is_ext()) { val.set_scale(result_type_.get_scale()); } } } return ret; } int ObExprOperator::param_eval(common::ObExprCtx& expr_ctx, const common::ObObj& param, const int64_t param_index) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.infix_expr_)) { // do nothing for postfix expression } else { if (OB_FAIL(expr_ctx.infix_expr_->param_eval(expr_ctx, param))) { LOG_WARN("param eval failed", K(ret)); } else if (OB_LIKELY(row_dimension_ == NOT_ROW_DIMENSION) && OB_LIKELY(T_FUN_SYS_TIMESTAMP_NVL != type_) && OB_LIKELY(param_index) < input_types_.count()) { // skip row operator and T_FUN_SYS_TIMESTAMP_NVL. (see cast_operand_type()) if (operand_auto_cast_ && OB_FAIL(cast_operand_type(const_cast(param), input_types_.at(param_index), expr_ctx))) { LOG_WARN("cast failed", K(ret), K(param), K(input_types_.at(param_index))); } } } return ret; } bool ObExprOperator::is_valid_nls_param(const common::ObString& nls_param_str) { bool bret = false; if (!nls_param_str.empty() && NULL != nls_param_str.find('=')) { static const common::ObString DEFAULT_VALUE_CALENDAR("GREGORIAN"); static const common::ObString DEFAULT_VALUE_DATE_LANGUAGE("AMERICAN"); static const common::ObString DEFAULT_VALUE_LANGUAGE("AMERICAN"); static const common::ObString DEFAULT_VALUE_NUMERIC_CHARACTERS(".,"); static const common::ObString DEFAULT_VALUE_SORT("BINARY"); static const common::ObString DEFAULT_VALUE_COMP("BINARY"); static const common::ObString DEFAULT_VALUE_CURRENCY("$"); static const common::ObString DEFAULT_VALUE_ISO_CURRENCY("AMERICA"); static const common::ObString DEFAULT_VALUE_DUAL_CURRENCY("$"); static const common::ObString DEFAULT_NAME_CALENDAR(share::OB_SV_NLS_CALENDAR); static const common::ObString DEFAULT_NAME_DATE_LANGUAGE(share::OB_SV_NLS_DATE_LANGUAGE); static const common::ObString DEFAULT_NAME_LANGUAGE(share::OB_SV_NLS_LANGUAGE); static const common::ObString DEFAULT_NAME_NUMERIC_CHARACTERS(share::OB_SV_NLS_NUMERIC_CHARACTERS); static const common::ObString DEFAULT_NAME_SORT(share::OB_SV_NLS_SORT); static const common::ObString DEFAULT_NAME_COMP(share::OB_SV_NLS_COMP); static const common::ObString DEFAULT_NAME_CURRENCY(share::OB_SV_NLS_CURRENCY); static const common::ObString DEFAULT_NAME_ISO_CURRENCY(share::OB_SV_NLS_ISO_CURRENCY); static const common::ObString DEFAULT_NAME_DUAL_CURRENCY(share::OB_SV_NLS_DUAL_CURRENCY); ObString value_str = const_cast(nls_param_str).trim(); ObString name_str = value_str.split_on('='); name_str = name_str.trim(); value_str = value_str.trim(); if (!name_str.empty() && !value_str.empty()) { if ((0 == name_str.case_compare(DEFAULT_NAME_CALENDAR) && 0 == value_str.case_compare(DEFAULT_VALUE_CALENDAR)) || (0 == name_str.case_compare(DEFAULT_NAME_DATE_LANGUAGE) && 0 == value_str.case_compare(DEFAULT_VALUE_DATE_LANGUAGE)) || (0 == name_str.case_compare(DEFAULT_NAME_LANGUAGE) && 0 == value_str.case_compare(DEFAULT_VALUE_LANGUAGE)) || (0 == name_str.case_compare(DEFAULT_NAME_NUMERIC_CHARACTERS) && 0 == value_str.case_compare(DEFAULT_VALUE_NUMERIC_CHARACTERS)) || (0 == name_str.case_compare(DEFAULT_NAME_SORT) && 0 == value_str.case_compare(DEFAULT_VALUE_SORT)) || (0 == name_str.case_compare(DEFAULT_NAME_COMP) && 0 == value_str.case_compare(DEFAULT_VALUE_COMP)) || (0 == name_str.case_compare(DEFAULT_NAME_CURRENCY) && 0 == value_str.case_compare(DEFAULT_VALUE_CURRENCY)) || (0 == name_str.case_compare(DEFAULT_NAME_ISO_CURRENCY) && 0 == value_str.case_compare(DEFAULT_VALUE_ISO_CURRENCY)) || (0 == name_str.case_compare(DEFAULT_NAME_DUAL_CURRENCY) && 0 == value_str.case_compare(DEFAULT_VALUE_DUAL_CURRENCY))) { bret = true; } } } return bret; } /* * get default collation type from session for string type * do not use this function for non-string type * */ ObCollationType ObExprOperator::get_default_collation_type(ObObjType type, const ObBasicSessionInfo& session_info) { ObCollationType collation_type = CS_TYPE_INVALID; if (ob_is_string_or_lob_type(type)) { if (share::is_mysql_mode()) { collation_type = static_cast(session_info.get_local_collation_connection()); } else { if (ob_is_nstring(type)) { // nvarchar2 nchar nclob collation_type = session_info.get_nls_collation_nation(); } else { // varchar2 char clob collation_type = session_info.get_nls_collation(); } } } return collation_type; } OB_SERIALIZE_MEMBER(ObExprOperator, row_dimension_, real_param_num_, result_type_, input_types_, id_, extra_serialize_); int ObExprOperator::aggregate_collations( ObObjMeta& type, const ObObjMeta* types, int64_t param_num, uint32_t flags, const ObCollationType conn_coll_type) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else { ObCollationType coll_type = types[0].get_collation_type(); ObCollationLevel coll_level = types[0].get_collation_level(); for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) { ret = ObCharset::aggregate_collation( coll_level, coll_type, types[i].get_collation_level(), types[i].get_collation_type(), coll_level, coll_type); } if (OB_SUCC(ret)) { if (OB_UNLIKELY((flags & OB_COLL_DISALLOW_NONE) && CS_LEVEL_NONE == coll_level)) { // @todo () correct error code is OB_CANT_AGGREGATE_NCOLLATIONS ret = OB_CANT_AGGREGATE_2COLLATIONS; } } if (OB_SUCC(ret)) { /* If all arguments were numbers, reset to @@collation_connection */ if (OB_UNLIKELY((flags & OB_COLL_ALLOW_NUMERIC_CONV) && CS_LEVEL_NUMERIC == coll_level)) { coll_type = conn_coll_type; coll_level = CS_LEVEL_COERCIBLE; // MySQL need charset converter here. We consider only two charset(binary // and utf8mb4), so no conversion is actually needed } else { } if (OB_SUCC(ret)) { type.set_collation_type(coll_type); type.set_collation_level(coll_level); } else { } } else { } if (OB_CANT_AGGREGATE_2COLLATIONS == ret) { if (3 == param_num) { ret = OB_CANT_AGGREGATE_3COLLATIONS; } else if (3 < param_num) { ret = OB_CANT_AGGREGATE_NCOLLATIONS; } } } return ret; } int ObExprOperator::aggregate_charsets_for_string_result( ObObjMeta& type, const ObObjMeta* types, int64_t param_num, const ObCollationType conn_coll_type) { uint32_t flags = OB_COLL_ALLOW_NUMERIC_CONV; return aggregate_charsets(type, types, param_num, flags, conn_coll_type); } int ObExprOperator::aggregate_charsets_for_string_result( ObExprResType& type, const ObExprResType* types, int64_t param_num, const ObCollationType conn_coll_type) { uint32_t flags = OB_COLL_ALLOW_NUMERIC_CONV; return aggregate_charsets(type, types, param_num, flags, conn_coll_type); } int ObExprOperator::aggregate_charsets_for_comparison( ObObjMeta& type, const ObObjMeta* types, int64_t param_num, const ObCollationType conn_coll_type) { uint32_t flags = OB_COLL_DISALLOW_NONE; return aggregate_charsets(type, types, param_num, flags, conn_coll_type); } int ObExprOperator::aggregate_charsets_for_comparison( ObExprResType& type, const ObExprResType* types, int64_t param_num, const ObCollationType conn_coll_type) { uint32_t flags = OB_COLL_DISALLOW_NONE; return aggregate_charsets(type.get_calc_meta(), types, param_num, flags, conn_coll_type); } int ObExprOperator::aggregate_charsets_for_string_result_with_comparison( ObObjMeta& type, const ObObjMeta* types, int64_t param_num, const ObCollationType conn_coll_type) { uint32_t flags = OB_COLL_DISALLOW_NONE | OB_COLL_ALLOW_NUMERIC_CONV; return aggregate_charsets(type, types, param_num, flags, conn_coll_type); } int ObExprOperator::aggregate_charsets_for_string_result_with_comparison( ObObjMeta& type, const ObExprResType* types, int64_t param_num, const ObCollationType coll_type) { uint32_t flags = OB_COLL_DISALLOW_NONE | OB_COLL_ALLOW_NUMERIC_CONV; return aggregate_charsets(type, types, param_num, flags, coll_type); } int ObExprOperator::aggregate_charsets( ObObjMeta& type, const ObObjMeta* types, int64_t param_num, uint32_t flags, const ObCollationType conn_coll_type) { return aggregate_collations(type, types, param_num, flags, conn_coll_type); } int ObExprOperator::aggregate_charsets(ObObjMeta& type, const ObExprResType* types, int64_t param_num, uint32_t flags, const ObCollationType conn_coll_type) { int ret = OB_SUCCESS; CK(OB_NOT_NULL(types), !OB_UNLIKELY(param_num < 1)); if (OB_SUCC(ret)) { ObSEArray coll_types; ObObjMeta coll; for (int i = 0; OB_SUCC(ret) && i < param_num; ++i) { coll.reset(); coll.set_collation_type(types[i].get_collation_type()); coll.set_collation_level(types[i].get_collation_level()); ret = coll_types.push_back(coll); } // end for OZ(aggregate_charsets(type, &coll_types.at(0), param_num, flags, conn_coll_type)); } return ret; } int ObExprOperator::aggregate_string_type_and_charset_oracle(const ObBasicSessionInfo& session, const ObIArray& params, ObExprResType& result, bool prefer_var_len_char) { int ret = OB_SUCCESS; bool has_clob_type = false; bool has_character_type = false; bool has_varying_len_string_type = false; bool has_nation_string_type = false; CK(params.count() > 0); for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { const ObExprResType* param_meta = params.at(i); CK(OB_NOT_NULL(param_meta)); if (OB_SUCC(ret)) { if (param_meta->is_string_or_lob_locator_type()) { has_clob_type |= param_meta->is_clob(); has_clob_type |= param_meta->is_clob_locator(); has_character_type |= param_meta->is_character_type(); has_nation_string_type |= param_meta->is_nstring(); has_varying_len_string_type |= param_meta->is_varying_len_char_type(); } else { has_varying_len_string_type = true; } } } // 1. deduce type + charset ObObjType result_type = ObMaxType; ObCollationType result_charset = CS_TYPE_INVALID; if (OB_SUCC(ret)) { if (has_clob_type) { if (has_nation_string_type) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "type nclob"); } else { result_type = ObLongTextType; result_charset = session.get_nls_collation(); } } else if (has_character_type) { if (has_nation_string_type) { result_type = has_varying_len_string_type || prefer_var_len_char ? ObNVarchar2Type : ObNCharType; result_charset = session.get_nls_collation_nation(); } else { result_type = has_varying_len_string_type || prefer_var_len_char ? ObVarcharType : ObCharType; result_charset = session.get_nls_collation(); } } else { // blob and other types result_type = ObVarcharType; result_charset = session.get_nls_collation(); } } if (OB_SUCC(ret)) { result.set_type_simple(result_type); if (ob_is_large_text(result_type)) { result.set_lob_inrow(); } result.set_collation_type(result_charset); result.set_collation_level(CS_LEVEL_IMPLICIT); } //. deduce length sematics ObLengthSemantics result_ls = LS_INVALIED; if (OB_SUCC(ret)) { if (result.is_nstring() || result.is_clob() || result.is_clob_locator()) { result_ls = LS_CHAR; } else { bool is_all_the_same = true; for (int64_t i = 0; is_all_the_same && i < params.count(); ++i) { const ObExprResType* param_meta = params.at(i); if (param_meta->is_string_or_lob_locator_type()) { ObLengthSemantics curr_ls = param_meta->get_length_semantics(); if (LS_INVALIED == result_ls) { result_ls = curr_ls; } else { is_all_the_same = (result_ls == curr_ls); } } } if (!is_all_the_same || LS_INVALIED == result_ls) { result_ls = session.get_actual_nls_length_semantics(); } } } if (OB_SUCC(ret)) { result.set_length_semantics(result_ls); } LOG_DEBUG("aggregate string charset", K(result), K(params)); return ret; } int ObExprOperator::deduce_string_param_calc_type_and_charset( const ObBasicSessionInfo& session, const ObExprResType& result, ObIArray& params) { UNUSED(session); int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { ObExprResType* param_meta = params.at(i); CK(OB_NOT_NULL(param_meta)); OX(param_meta->set_calc_meta(result)); } return ret; } int ObExprOperator::is_same_kind_type_for_case(const ObExprResType& type1, const ObExprResType& type2, bool& match) { int ret = OB_SUCCESS; match = false; if (OB_UNLIKELY(type1.get_type() >= ObMaxType || type2.get_type() >= ObMaxType)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("the wrong type", K(type1), K(type2), K(ret)); } else { if (ob_is_null(type1.get_type()) || ob_is_null(type2.get_type())) { match = true; } else if (ob_is_varchar_char_type(type1.get_type(), type1.get_collation_type())) { match = ob_is_varchar_char_type(type2.get_type(), type2.get_collation_type()); } else if (ob_is_numeric_type(type1.get_type())) { match = ob_is_numeric_type(type2.get_type()); } else if (ob_is_datetime_tc(type1.get_type()) || ob_is_otimestampe_tc(type1.get_type())) { match = ob_is_datetime_tc(type2.get_type()) || ob_is_otimestampe_tc(type2.get_type()); } else if (ob_is_blob(type1.get_type(), type1.get_collation_type())) { match = ob_is_blob(type2.get_type(), type2.get_collation_type()); } else if (ob_is_text(type1.get_type(), type1.get_collation_type())) { match = ob_is_text(type2.get_type(), type2.get_collation_type()); } else if (ob_is_varbinary_type(type1.get_type(), type1.get_collation_type())) { match = ob_is_varbinary_type(type2.get_type(), type2.get_collation_type()); } else if (ob_is_raw(type1.get_type())) { match = ob_is_raw(type2.get_type()); } else if (ob_is_interval_ym(type1.get_type())) { match = ob_is_interval_ym(type2.get_type()); } else if (ob_is_interval_ds(type1.get_type())) { match = ob_is_interval_ds(type2.get_type()); } else if (ob_is_nstring_type(type1.get_type())) { match = ob_is_nstring_type(type2.get_type()); } else if (ob_is_urowid(type1.get_type())) { match = ob_is_urowid(type2.get_type()); } else if (ob_is_blob_locator(type1.get_type(), type1.get_collation_type())) { match = ob_is_blob_locator(type2.get_type(), type2.get_collation_type()); } else if (ob_is_clob_locator(type1.get_type(), type1.get_collation_type())) { match = ob_is_clob_locator(type2.get_type(), type2.get_collation_type()); } } return ret; } // coaesce expr, case when expr int ObExprOperator::aggregate_result_type_for_case(ObExprResType& type, const ObExprResType* types, int64_t param_num, const ObCollationType conn_coll_type, bool is_oracle_mode, const ObLengthSemantics default_length_semantics, const ObSQLSessionInfo* session, bool need_merge_type, bool skip_null) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1) || OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else if (1 == param_num && ob_is_enumset_tc(types[0].get_type())) { } else if (is_oracle_mode) { bool match = false; int64_t nth = OB_INVALID_ID; for (int64_t i = 0; OB_SUCC(ret) && OB_INVALID_ID == nth && i < param_num; ++i) { if (!ob_is_null(types[i].get_type())) { nth = i; } } nth = OB_INVALID_ID == nth ? 0 : nth; const ObExprResType& res_type = types[nth]; for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (OB_FAIL(ObExprOperator::is_same_kind_type_for_case(res_type, types[i], match))) { LOG_WARN("fail to judge same type", K(i), K(res_type), K(types[i]), K(ret)); } else if (!match) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("fail to judge same type", K(i), K(res_type), K(types[i]), K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(aggregate_result_type_for_merge(type, types, param_num, conn_coll_type, is_oracle_mode, default_length_semantics, session, need_merge_type, skip_null))) { LOG_WARN("fail to aggregate result type", K(ret)); } else if (ObFloatType == type.get_type() && !is_oracle_mode) { type.set_type(ObDoubleType); } } return ret; } int ObExprOperator::aggregate_result_type_for_merge(ObExprResType& type, const ObExprResType* types, int64_t param_num, const ObCollationType conn_coll_type, bool is_oracle_mode, const ObLengthSemantics default_length_semantics, const ObSQLSessionInfo* session, bool need_merge_type, bool skip_null) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1) || OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else if (1 == param_num && ob_is_enumset_tc(types[0].get_type())) { // this is for case when clause like case when 1 then c1 end; type.set_type(ObVarcharType); type.set_collation_level(common::CS_LEVEL_IMPLICIT); type.set_collation_type(session->get_local_collation_connection()); } else { ObObjType res_type = types[0].get_type(); for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (OB_FAIL(ObExprResultTypeUtil::get_merge_result_type(res_type, res_type, types[i].get_type()))) { // warn } else if (OB_UNLIKELY(ObMaxType == res_type)) { ret = OB_INVALID_ARGUMENT; // not compatible input LOG_WARN("invalid argument. wrong type for merge", K(i), K(types[i].get_type()), K(ret)); } } if (OB_SUCC(ret)) { type.set_type(res_type); if (ob_is_numeric_type(res_type)) { ret = aggregate_numeric_accuracy_for_merge(type, types, param_num, is_oracle_mode); } else if (ob_is_temporal_type(res_type) || ob_is_otimestamp_type(res_type)) { ret = aggregate_temporal_accuracy_for_merge(type, types, param_num); } else if (ob_is_string_type(res_type)) { if (OB_FAIL(aggregate_charsets_for_string_result(type, types, param_num, conn_coll_type))) { } else if (OB_FAIL(aggregate_max_length_for_string_result( type, types, param_num, is_oracle_mode, default_length_semantics, need_merge_type, skip_null))) { } else { /*do nothing*/ } } else if (ob_is_raw(res_type)) { type.set_collation_type(CS_TYPE_BINARY); type.set_collation_level(CS_LEVEL_NUMERIC); } else if (ob_is_interval_tc(res_type)) { ret = aggregate_accuracy_for_merge(type, types, param_num); } } LOG_DEBUG("merged type is", K(type), K(is_oracle_mode)); } return ret; } int ObExprOperator::aggregate_max_length_for_string_result(ObExprResType& type, const ObExprResType* types, int64_t param_num, bool is_oracle_mode, const ObLengthSemantics default_length_semantics, bool need_merge_type, bool skip_null) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else { ObLength max_length = -1; ObLength max_length_char = -1; ObLength length = -1; ObLengthSemantics length_semantics = -1; int64_t byte_length_count = 0; int64_t char_length_count = 0; bool len_in_byte = false; int64_t mbmaxlen = 1; if (OB_FAIL(common::ObCharset::get_mbmaxlen_by_coll(CS_TYPE_UTF8MB4_GENERAL_CI, mbmaxlen))) { LOG_WARN("fail to get mbmaxlen", K(ret)); } else if (OB_FAIL(ObCharset::get_aggregate_len_unit(type.get_collation_type(), len_in_byte))) { LOG_WARN("get aggregate len unit failed", K(ret), K(type)); } else if (len_in_byte) { // binary for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { if (ob_is_integer_type(types[i].get_type())) { length = MAX(ObAccuracy::DDL_DEFAULT_ACCURACY[types[i].get_type()].precision_, types[i].get_precision()); } else { if (OB_FAIL(types[i].get_length_for_meta_in_bytes(length))) { LOG_WARN("get length failed", K(ret), K(types[i])); } } /* Oracle compatible: if prejudged result type is char and args' length are different, change result type to * varchar */ LOG_DEBUG("cur len", K(length), K(max_length), K(types[i])); if (is_oracle_mode && need_merge_type && ((ObCharType == type.get_type() && ObCharType == types[i].get_type()) || (ob_is_nchar(type.get_type()) && ob_is_nchar(types[i].get_type()))) && (max_length != -1) && (length != max_length)) { LOG_DEBUG("Merge type from Char to Varchar ", K(length), K(max_length), K(types[i])); type.set_type(ob_is_nchar(type.get_type()) ? ObNVarchar2Type : ObVarcharType); } /*no need to if(OB_SUCCE(ret)) here*/ if (length > max_length) { if (types[i].is_null() && skip_null) { // skip } else { max_length = length; } } } // end for } else { for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { if (ob_is_integer_type(types[i].get_type())) { length = MAX(ObAccuracy::DDL_DEFAULT_ACCURACY[types[i].get_type()].precision_, types[i].get_precision()); length_semantics = -1; } else { length = types[i].get_length(); length_semantics = types[i].get_length_semantics(); if (LS_BYTE == length_semantics) { byte_length_count++; } else if (LS_CHAR == length_semantics) { char_length_count++; if (length > max_length_char) { max_length_char = length; } } } /* Oracle compatible: if prejudged result type is char and args' length are different, change result type to * varchar */ LOG_DEBUG("cur len", K(length), K(max_length), K(max_length_char), K(length_semantics), K(types[i]), K(type)); if (is_oracle_mode && need_merge_type && ((ObCharType == type.get_type() && ObCharType == types[i].get_type()) || (ob_is_nchar(type.get_type()) && ob_is_nchar(types[i].get_type()))) && (max_length != -1) && (length != max_length || (byte_length_count > 0 && char_length_count > 0))) { LOG_DEBUG("Merge type from Char to Varchar ", K(length), K(max_length), K(length_semantics), K(types[i])); type.set_type(ob_is_nchar(type.get_type()) ? ObNVarchar2Type : ObVarcharType); } if (length > max_length) { if (types[i].is_null() && skip_null) { // skip } else { max_length = length; } } } // end for } // set length if (OB_SUCC(ret) && max_length < 0) { if (skip_null) { max_length = 0; } else { ret = OB_ERR_UNEXPECTED; LOG_ERROR("unexpected max length.", K(ret), K(max_length), K(param_num), K(len_in_byte)); } } if (OB_SUCC(ret)) { if (is_oracle_mode && type.is_character_type()) { if (type.is_nstring()) { type.set_length_semantics(LS_CHAR); } else { if (byte_length_count > 0 && 0 == char_length_count) { type.set_length_semantics(LS_BYTE); } else if (char_length_count > 0 && 0 == byte_length_count) { type.set_length_semantics(LS_CHAR); } else { type.set_length_semantics(default_length_semantics); } } if (LS_CHAR == type.get_length_semantics()) { type.set_length(std::max(max_length_char, max_length)); } else { type.set_length(std::max(static_cast(max_length_char * mbmaxlen), max_length)); } } else { type.set_length(max_length); } } } return ret; } int ObExprOperator::aggregate_accuracy_for_merge(ObExprResType& type, const ObExprResType* types, int64_t param_num) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else { ObScale scale = -1; for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { if (types[i].get_scale() > scale) { scale = types[i].get_scale(); } } if (OB_UNLIKELY(scale < 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected scale.", K(ret), K(scale)); } else { type.set_scale(scale); } } return ret; } int ObExprOperator::aggregate_temporal_accuracy_for_merge( ObExprResType& type, const ObExprResType* types, int64_t param_num) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else { ObScale scale = -1; for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { if ((ob_is_temporal_type(types[i].get_type()) || ob_is_otimestamp_type(types[i].get_type())) && types[i].get_scale() > scale) { scale = types[i].get_scale(); } } if (OB_UNLIKELY(scale < 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected scale.", K(ret), K(scale)); } else { type.set_scale(scale); } } return ret; } int ObExprOperator::aggregate_numeric_accuracy_for_merge( ObExprResType& type, const ObExprResType* types, int64_t param_num, bool is_oracle_mode) { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else if (is_oracle_mode) { type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET); type.set_precision(PRECISION_UNKNOWN_YET); } else { ObPrecision precision = 0; ObScale scale = 0; int16_t max_integer_digits = -1; int16_t max_decimal_digits = -1; bool has_real_type = false; for (int64_t i = 0; i < param_num && OB_SUCC(ret); ++i) { precision = PRECISION_UNKNOWN_YET; scale = SCALE_UNKNOWN_YET; if (OB_UNLIKELY(types[i].get_type() < ObNullType || types[i].get_type() >= ObMaxType)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("unexpected error. wrong type", K(ret), K(types[i])); } else if (ob_is_real_type(types[i].get_type())) { /* create table sb(a float); create table sc(c year); insert sb values (1.5); insert sc values(1923); a union c will result to 1.5 and 1923 */ has_real_type = true; } else { /* create table sb(a int(3));//3 ? display width ? precision? length? create table sc(c decimal(5,3)); insert sb values (12345); insert sc values(123.33); a union c will result to 12345 and 123.33 */ if (ob_is_integer_type(types[i].get_type())) { precision = MAX(ObAccuracy::DDL_DEFAULT_ACCURACY2[is_oracle_mode][types[i].get_type()].precision_, types[i].get_precision()); scale = 0; } else if (ob_is_number_tc(types[i].get_type()) || ob_is_temporal_type(types[i].get_type())) { precision = types[i].get_precision(); scale = types[i].get_scale(); } else { // string type. precision and scale means nothing to string types // just let it go } if (precision >= 0 && precision - scale > max_integer_digits) { max_integer_digits = static_cast(precision - scale); } if (scale >= 0 && scale > max_decimal_digits) { max_decimal_digits = 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); } else { if (max_integer_digits + max_decimal_digits >= 0) { precision = static_cast(max_integer_digits + max_decimal_digits); type.set_precision(MIN(precision, ObAccuracy::MAX_ACCURACY2[is_oracle_mode][type.get_type()].precision_)); } if (max_decimal_digits >= 0) { type.set_scale(MIN(max_decimal_digits, ObAccuracy::MAX_ACCURACY2[is_oracle_mode][type.get_type()].scale_)); } } } return ret; } ObObjType ObExprOperator::enumset_calc_types_[ObMaxTC] = { ObUInt64Type, /*ObNullTC*/ ObUInt64Type, /*ObIntTC*/ ObUInt64Type, /*ObUIntTC*/ ObUInt64Type, /*ObFloatTC*/ ObUInt64Type, /*ObDoubleTC*/ ObUInt64Type, /*ObNumberTC*/ ObVarcharType, /*ObDateTimeTC*/ ObVarcharType, /*ObDateTC*/ ObVarcharType, /*ObTimeTC*/ ObUInt64Type, /*ObYearTC*/ ObVarcharType, /*ObStringTC*/ ObMaxType, /*ObExtendTC*/ ObMaxType, /*ObUnknownTC*/ ObVarcharType, /*ObTextTC*/ ObUInt64Type, /*ObBitTC*/ ObVarcharType, /*ObEnumSetTC*/ ObVarcharType, /*ObEnumSetInnerTC*/ }; //////////////////////////////////////////////////////////////// int ObArithExprOperator::assign(const ObExprOperator& other) { int ret = OB_SUCCESS; const ObArithExprOperator* tmp_other = dynamic_cast(&other); if (OB_UNLIKELY(NULL == tmp_other)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument. wrong type for other", K(ret), K(other)); } else if (this != tmp_other) { if (OB_FAIL(ObExprOperator::assign(other))) { LOG_WARN("copy in Base class ObExprOperator failed", K(ret)); } else { this->result_type_func_ = tmp_other->result_type_func_; this->calc_type_func_ = tmp_other->calc_type_func_; } } return ret; } int ObArithExprOperator::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; if (OB_ISNULL(result_type_func_) || OB_ISNULL(calc_type_func_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("result_type_func_ or calc_type_func_is null", K(ret)); } else { ObObjType calc_type = ObMaxType; ObObjType calc_ob1_type = ObMaxType; ObObjType calc_ob2_type = ObMaxType; if (OB_UNLIKELY(NOT_ROW_DIMENSION != row_dimension_)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; } else if (OB_FAIL(result_type_func_(type, type1, type2))) { LOG_WARN("fail to result_type_func_", K(ret)); } else if (OB_UNLIKELY(ObMaxType == type.get_type())) { ret = OB_ERR_INVALID_TYPE_FOR_OP; } else if (OB_FAIL(calc_type_func_(calc_type, calc_ob1_type, calc_ob2_type, type1.get_type(), type2.get_type()))) { LOG_WARN("fail to calc_type_func_", K(ret)); } else { type.set_calc_type(calc_type); type1.set_calc_type(get_calc_cast_type(type1.get_type(), calc_ob1_type)); type2.set_calc_type(get_calc_cast_type(type2.get_type(), calc_ob2_type)); ObExprOperator::calc_result_flag2(type, type1, type2); } LOG_DEBUG("arithmatic result type", K(type), K(type1), K(type2), K(calc_type), K(calc_ob1_type), K(calc_ob2_type), K(ret)); } return ret; } int ObArithExprOperator::calc_result2(ObObj& result, const ObObj& left, const ObObj& right, ObExprCtx& expr_ctx) const { return calc_( result, left, right, expr_ctx, result_type_.get_calc_scale(), result_type_.get_calc_type(), arith_funcs_); } int ObArithExprOperator::calc(ObObj& result, const ObObj& left, const ObObj& right, ObIAllocator* allocator, ObScale scale, ObCalcTypeFunc calc_type_func, const ObArithFunc* arith_funcs) { int ret = OB_SUCCESS; if (OB_ISNULL(calc_type_func) || OB_ISNULL(allocator) || OB_ISNULL(arith_funcs)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("the pointer is null", K(calc_type_func), K(allocator), K(arith_funcs), K(ret)); } else { ObObjType calc_type = ObMaxType; ObObjType calc_ob1_type = ObMaxType; ObObjType calc_ob2_type = ObMaxType; if (OB_FAIL(calc_type_func(calc_type, calc_ob1_type, calc_ob2_type, left.get_type(), right.get_type()))) { } else { ObExprCtx expr_ctx(NULL, NULL, NULL, allocator); ret = calc_(result, left, right, expr_ctx, scale, calc_type, arith_funcs); } } return ret; } int ObArithExprOperator::calc(ObObj& result, const ObObj& left, const ObObj& right, ObExprCtx& expr_ctx, ObScale calc_scale, ObCalcTypeFunc calc_type_func, const ObArithFunc* arith_funcs) { int ret = OB_SUCCESS; if (OB_ISNULL(calc_type_func) || OB_ISNULL(arith_funcs)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("calc_type_func is null", K(ret)); } else { ObObjType calc_type = ObMaxType; ObObjType calc_ob1_type = ObMaxType; ObObjType calc_ob2_type = ObMaxType; if (OB_FAIL(calc_type_func(calc_type, calc_ob1_type, calc_ob2_type, left.get_type(), right.get_type()))) { } else { ret = calc_(result, left, right, expr_ctx, calc_scale, calc_type, arith_funcs); } } return ret; } int ObArithExprOperator::calc_(ObObj& result, const ObObj& left, const ObObj& right, ObExprCtx& expr_ctx, ObScale calc_scale, ObObjType calc_type, const ObArithFunc* arith_funcs) { int ret = OB_SUCCESS; if (OB_ISNULL(arith_funcs) || OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("the pointer is null", K(arith_funcs), K(expr_ctx.calc_buf_), K(ret)); } else if (OB_UNLIKELY(ObNullType == calc_type || ObMaxType == calc_type)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("result type is invalid", K(ret), K(calc_type)); } if (OB_SUCC(ret) && (OB_UNLIKELY(ObNullType == left.get_type() || ObNullType == right.get_type()))) { result.set_null(); } else if (OB_SUCC(ret)) { const ObObj* res_left = &left; const ObObj* res_right = &right; ObObj tmp_left_obj; ObObj tmp_right_obj; if (left.get_type() != calc_type || right.get_type() != calc_type) { EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NO_CAST_INT_UINT); if (is_datetime_add_minus_calc(calc_type, arith_funcs)) { if (OB_FAIL(ObObjCaster::to_datetime(calc_type, cast_ctx, left, tmp_left_obj, res_left))) { LOG_WARN("cast failed.", K(ret), K(left), K(calc_type)); } else if (OB_FAIL(ObObjCaster::to_datetime(calc_type, cast_ctx, right, tmp_right_obj, res_right))) { LOG_WARN("cast failed.", K(ret), K(right), K(calc_type)); } } else if (OB_FAIL(ObObjCaster::to_type(calc_type, cast_ctx, left, tmp_left_obj, res_left))) { LOG_WARN("cast failed.", K(ret), K(left), K(calc_type)); } else if (OB_FAIL(ObObjCaster::to_type(calc_type, cast_ctx, right, tmp_right_obj, res_right))) { LOG_WARN("cast failed.", K(ret), K(right), K(calc_type)); } } // ok, let's calc it. if (OB_SUCC(ret)) { ObArithFunc arith_func = arith_funcs[res_left->get_type_class()]; LOG_DEBUG("begin calc", K(left), KPC(res_left), K(right), KPC(res_right), K(calc_scale), K(calc_type), K(lbt())); if (OB_ISNULL(arith_func)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("arith_func is null", K(ret)); } else { ret = arith_func(result, *res_left, *res_right, expr_ctx.calc_buf_, calc_scale); if (OB_ERR_UNEXPECTED == ret) { ob_abort(); } } } // } } return ret; } bool ObArithExprOperator::is_datetime_add_minus_calc(const common::ObObjType calc_type, const ObArithFunc* arith_funcs) { return (NULL != arith_funcs && (ObExprAdd::add_datetime == arith_funcs[ob_obj_type_class(calc_type)] || ObExprMinus::minus_datetime == arith_funcs[ob_obj_type_class(calc_type)])); } int ObRelationalExprOperator::deserialize(const char* buf, const int64_t data_len, int64_t& pos) { int ret = OB_SUCCESS; cmp_op_func2_ = NULL; ret = ObExprOperator::deserialize(buf, data_len, pos); if (OB_SUCC(ret) && (IS_COMMON_COMPARISON_OP(type_) || T_FUN_SYS_STRCMP == type_) && ObExprOperator::NOT_ROW_DIMENSION == row_dimension_ && real_param_num_ == 2) { if (input_types_.count() != 2) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("unexpected error. invalid input types", K(ret), K(type_), K(real_param_num_), K(input_types_.count())); } else { ObObjType left_operand_type = input_types_.at(0).get_calc_type(); ObObjType right_operand_type = input_types_.at(1).get_calc_type(); if (OB_FAIL(set_cmp_func(left_operand_type, right_operand_type))) { LOG_WARN("set cmp func failed", K(ret), K(left_operand_type), K(right_operand_type), K(type_)); cmp_op_func2_ = NULL; // defensive code } } } return ret; } int ObRelationalExprOperator::compare(ObObj& result, const ObObj& obj1, const ObObj& obj2, const ObCompareCtx& cmp_ctx, ObCastCtx& cast_ctx, ObCmpOp cmp_op) { int ret = OB_SUCCESS; bool need_cast = false; if (OB_FAIL(compare_nocast(result, obj1, obj2, cmp_ctx, cmp_op, need_cast))) { LOG_WARN("failed to compare objects", K(obj1), K(obj2)); } else if (need_cast) { if (OB_FAIL(compare_cast(result, obj1, obj2, cmp_ctx, cast_ctx, cmp_op))) { LOG_WARN("failed to compare objects", K(obj1), K(obj2)); } } return ret; } int ObRelationalExprOperator::compare_cast(ObObj& result, const ObObj& obj1, const ObObj& obj2, const ObCompareCtx& cmp_ctx, ObCastCtx& cast_ctx, ObCmpOp cmp_op) { int ret = OB_SUCCESS; ObObj buf_obj1; ObObj buf_obj2; const ObObj* res_obj1 = NULL; const ObObj* res_obj2 = NULL; bool need_cast = false; cast_ctx.dest_collation_ = cmp_ctx.cmp_cs_type_; if (OB_FAIL(ObObjCaster::to_type(cmp_ctx.cmp_type_, cast_ctx, obj1, buf_obj1, res_obj1))) { LOG_WARN("failed to cast obj", K(ret), K(cmp_ctx.cmp_type_), K(obj1)); } else if (OB_FAIL(ObObjCaster::to_type(cmp_ctx.cmp_type_, cast_ctx, obj2, buf_obj2, res_obj2))) { LOG_WARN("failed to cast obj", K(ret), K(cmp_ctx.cmp_type_), K(obj2)); } else if (OB_ISNULL(res_obj1) || OB_ISNULL(res_obj2)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("res_obj1 or res_obj2 is null"); } else if (OB_FAIL(ObObjCmpFuncs::compare(result, *res_obj1, *res_obj2, cmp_ctx, cmp_op, need_cast))) { LOG_WARN("failed to compare objects", K(ret), K(*res_obj1), K(*res_obj2), K(cmp_op)); } else if (need_cast) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to compare objects", K(ret), K(*res_obj1), K(*res_obj2), K(cmp_op)); } return ret; } int ObRelationalExprOperator::compare_nullsafe(int64_t& result, const ObObj& obj1, const ObObj& obj2, ObCastCtx& cast_ctx, ObObjType cmp_type, ObCollationType cmp_cs_type) { int ret = OB_SUCCESS; ObObj res_obj; int64_t tz_offset = 0; if (OB_FAIL(get_tz_offset(cast_ctx.dtc_params_.tz_info_, tz_offset))) { LOG_WARN("get tz_offset failed", K(ret), K(cast_ctx.dtc_params_.tz_info_), K(tz_offset)); } else { ObCompareCtx cmp_ctx(cmp_type, cmp_cs_type, true, tz_offset, default_null_pos()); if (OB_FAIL(compare(res_obj, obj1, obj2, cmp_ctx, cast_ctx, CO_CMP))) { } else { result = res_obj.get_int(); } } return ret; } bool ObRelationalExprOperator::can_cmp_without_cast( ObExprResType type1, ObExprResType type2, ObCmpOp cmp_op, const ObSQLSessionInfo& session) { bool need_no_cast = false; if (ob_is_enum_or_set_type(type1.get_type()) && ob_is_enum_or_set_type(type2.get_type())) { need_no_cast = false; } else if (session.use_static_typing_engine()) { if (ObDatumFuncs::is_string_type(type1.get_type()) && ObDatumFuncs::is_string_type(type2.get_type())) { need_no_cast = ObCharset::charset_type_by_coll(type1.get_collation_type()) == 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, lib::is_oracle_mode(), CS_TYPE_BINARY); need_no_cast = (func_ptr != nullptr); } } else { obj_cmp_func cmp_func = NULL; need_no_cast = ObObjCmpFuncs::can_cmp_without_cast(type1, type2, cmp_op, cmp_func); } return need_no_cast; } /* * Note that, the original motivation of this function is that, * * Provided that we have a = b and b = c in which a , b and c * are of metainfo meta1, meta2, meta3, respectively * * So, can we deduce that a = c holds actually? * * this func tells you this via result when and only when the ret is OB_SUCCESS */ int ObRelationalExprOperator::is_equivalent( const ObObjMeta& meta1, const ObObjMeta& meta2, const ObObjMeta& meta3, bool& result) { int ret = OB_SUCCESS; result = false; ObObjMeta equal_meta12; ObObjMeta equal_meta23; ObObjMeta equal_meta13; if (OB_FAIL(get_equal_meta(equal_meta12, meta1, meta2))) { LOG_WARN("get equal meta failed", K(ret), K(meta1), K(meta2)); } else if (OB_FAIL(get_equal_meta(equal_meta13, meta1, meta3))) { LOG_WARN("get equal meta failed", K(ret), K(meta1), K(meta3)); } else if (OB_FAIL(get_equal_meta(equal_meta23, meta2, meta3))) { LOG_WARN("get equal meta failed", K(ret), K(meta2), K(meta3)); } else if (OB_UNLIKELY(equal_meta12.get_type() == ObMaxType || equal_meta13.get_type() == ObMaxType /* no need to check ObNullType here*/ || equal_meta23.get_type() == ObMaxType)) { /*result = false;*/ } else if (equal_meta12.get_type() == equal_meta13.get_type() && equal_meta13.get_type() == equal_meta23.get_type()) { if (OB_UNLIKELY(ob_is_string_or_lob_type(equal_meta12.get_type()))) { // all are string type result = equal_meta12.get_collation_type() == equal_meta13.get_collation_type() && equal_meta13.get_collation_type() == equal_meta23.get_collation_type(); } else { result = true; } } return ret; } int ObRelationalExprOperator::get_equal_meta(ObObjMeta& meta, const ObObjMeta& meta1, const ObObjMeta& meta2) { int ret = OB_SUCCESS; ObObjType type = ObMaxType; if (OB_FAIL(ObExprResultTypeUtil::get_relational_equal_type(type, meta1.get_type(), meta2.get_type()))) { LOG_WARN("get equal type failed", K(ret), K(meta1), K(meta2)); } else if (ob_is_string_or_lob_type(type)) { ObObjMeta coll_types[2] = {meta1, meta2}; ret = aggregate_charsets_for_comparison(meta, coll_types, 2, CS_TYPE_INVALID); } if (OB_SUCC(ret)) { meta.set_type(type); } return ret; } // MySQL use item_cmp_type to calc target compare type int ObExprOperator::calc_cmp_type2( ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2, const ObCollationType coll_type) const { int ret = OB_SUCCESS; ObObjType cmp_type = ObMaxType; // todo: we can add such code after plan cache add same optimization. // if (is_int_cmp_const_str(&type1, &type2, cmp_type)) { // } else if (is_oracle_mode() && (type1.is_blob() || type2.is_blob() || type1.is_blob_locator() || type2.is_blob_locator()) && type_ != T_OP_IS && type_ != T_OP_IS_NOT) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type())); } else if (OB_FAIL(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type, type1.get_type(), type2.get_type()))) { LOG_WARN("fail to get cmp_type", K(ret)); } else if (OB_UNLIKELY(ObMaxType == cmp_type)) { ret = OB_INVALID_ARGUMENT; } else if (ObURowIDType == cmp_type) { // only support ,, , // , if (OB_UNLIKELY(ObStringTC != type1.get_type_class() && ObRowIDTC != type1.get_type_class() && ObNullTC != type1.get_type_class()) || OB_UNLIKELY(ObStringTC != type2.get_type_class() && ObRowIDTC != type2.get_type_class() && ObNullTC != type2.get_type_class())) { ret = OB_INVALID_ROWID; LOG_WARN("not supported compare type", K(type1), K(type2)); } } if (OB_SUCC(ret)) { type.set_calc_type(cmp_type); // collation if (ob_is_string_or_lob_type(cmp_type)) { ObObjMeta coll_types[2]; coll_types[0].set_collation(type1); coll_types[1].set_collation(type2); ret = aggregate_charsets_for_comparison(type.get_calc_meta(), coll_types, 2, coll_type); if (OB_FAIL(ret)) { LOG_WARN("aggregate charset failed", K(type1), K(type2), K(type.get_calc_meta())); } } else if (ObRawType == cmp_type) { type.get_calc_meta().set_collation_type(CS_TYPE_BINARY); } LOG_DEBUG("calc cmp type", K(type1), K(type2), K(type.get_calc_meta())); } return ret; } int ObExprOperator::calc_cmp_type3(ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2, const ObExprResType& type3, const ObCollationType coll_type) const { int ret = OB_SUCCESS; // cmp type ObObjType cmp_type = type1.get_type(); if (is_oracle_mode() && (type1.is_blob() || type1.is_blob_locator() || type2.is_blob() || type2.is_blob_locator() || type3.is_blob() || type3.is_blob_locator())) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type())); } else if (OB_SUCC(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type, type2.get_type(), cmp_type))) { if (OB_SUCC(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type, cmp_type, type3.get_type()))) { if (OB_UNLIKELY(ObMaxType == cmp_type)) { ret = OB_INVALID_ARGUMENT; // not compatible input } } } // collation if (OB_SUCC(ret)) { type.set_calc_type(cmp_type); if (ob_is_string_or_lob_type(cmp_type)) { ObObjMeta coll_types[3]; coll_types[0].set_collation(type1); coll_types[1].set_collation(type2); coll_types[2].set_collation(type3); ret = aggregate_charsets_for_comparison(type.get_calc_meta(), coll_types, 3, coll_type); } else if (ObRawType == cmp_type) { type.get_calc_meta().set_collation_type(CS_TYPE_BINARY); } } return ret; } // for sqrt, ln, e functions int ObExprOperator::calc_trig_function_result_type1( ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; if (NOT_ROW_DIMENSION != row_dimension_ || ObMaxType == type1.get_type()) { ret = OB_ERR_INVALID_TYPE_FOR_OP; } else if (!share::is_oracle_mode()) { type.set_double(); } else { if (ob_is_real_type(type1.get_type())) { type.set_double(); } else { type.set_number(); } type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][type.get_type()].get_scale()); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][type.get_type()].get_precision()); } type1.set_calc_type(type.get_type()); ObExprOperator::calc_result_flag1(type, type1); return ret; } int ObExprOperator::calc_trig_function_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; if (NOT_ROW_DIMENSION != row_dimension_) { ret = OB_ERR_INVALID_TYPE_FOR_OP; // arithmetic not support row } else if (ObMaxType == type1.get_type() || ObMaxType == type2.get_type()) { ret = OB_ERR_INVALID_TYPE_FOR_OP; } else if (!share::is_oracle_mode()) { type.set_double(); } else { if (ob_is_real_type(type1.get_type()) || ob_is_real_type(type2.get_type())) { type.set_double(); } else { type.set_number(); } type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][type.get_type()].get_scale()); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][type.get_type()].get_precision()); } type1.set_calc_type(type.get_type()); type2.set_calc_type(type.get_type()); ObExprOperator::calc_result_flag2(type, type1, type2); return ret; } ObCastMode ObExprOperator::get_cast_mode() const { return CM_NONE; } ObExpr* ObExprOperator::get_rt_expr(const ObRawExpr& raw_expr) const { return raw_expr.rt_expr_; } OB_SERIALIZE_MEMBER(ObIterExprOperator, expr_id_, expr_type_); int ObRelationalExprOperator::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { return deduce_cmp_type(*this, type, type1, type2, type_ctx); } int ObRelationalExprOperator::deduce_cmp_type(const ObExprOperator& expr, ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) { int ret = OB_SUCCESS; ObExprResType cmp_type; CK(NULL != type_ctx.get_session()); if (OB_FAIL(ret)) { } else if (OB_SUCC(expr.calc_cmp_type2(cmp_type, type1, type2, type_ctx.get_coll_type()))) { type.set_int32(); // not tinyint, compatible with MySQL type.set_precision(DEFAULT_PRECISION_FOR_BOOL); type.set_scale(DEFAULT_SCALE_FOR_INTEGER); type.set_calc_collation(cmp_type); type.set_calc_type(cmp_type.get_calc_type()); ObExprOperator::calc_result_flag2(type, type1, type2); bool need_no_cast = can_cmp_without_cast(type1, type2, get_cmp_op(expr.get_type()), *type_ctx.get_session()); type1.set_calc_type(need_no_cast ? type1.get_type() : cmp_type.get_calc_type()); type2.set_calc_type(need_no_cast ? type2.get_type() : cmp_type.get_calc_type()); if (ob_is_string_or_lob_type(cmp_type.get_calc_type())) { type1.set_calc_collation_type(cmp_type.get_calc_collation_type()); type2.set_calc_collation_type(cmp_type.get_calc_collation_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); } } return ret; } // TODO():invoke type has not set calc_type int ObRelationalExprOperator::calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; ObExprResType cmp_type; if (OB_SUCC(calc_cmp_type3(cmp_type, type1, type2, type3, type_ctx.get_coll_type()))) { type.set_int32(); type.set_calc_collation(cmp_type); type.set_calc_type(cmp_type.get_calc_type()); type.set_scale(DEFAULT_SCALE_FOR_INTEGER); type.set_precision(DEFAULT_PRECISION_FOR_BOOL); ObExprOperator::calc_result_flag3(type, type1, type2, type3); if (OB_FAIL(calc_calc_type3(type1, type2, type3, type_ctx, cmp_type.get_calc_type()))) { LOG_WARN("set calc type failed", K(type1), K(type2), K(type3), K(cmp_type), K(ret)); } if (ob_is_string_or_lob_type(cmp_type.get_calc_type())) { type1.set_calc_collation_type(cmp_type.get_calc_collation_type()); type2.set_calc_collation_type(cmp_type.get_calc_collation_type()); type3.set_calc_collation_type(cmp_type.get_calc_collation_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); type3.set_calc_collation_type(CS_TYPE_BINARY); } } return ret; } int ObRelationalExprOperator::calc_result_typeN( ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(0 >= row_dimension_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or row_dimension is less than 0", K(types), K(row_dimension_), K(ret)); } else if (OB_UNLIKELY(param_num <= 0 || 2 != param_num / row_dimension_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("param_num is wrong", K(param_num), K(ret)); } else if (OB_FAIL(type.init_row_dimension(row_dimension_))) { LOG_WARN("fail to init row dimemnsion", K(ret)); } else { // () MySQL deal with (a,b) = (c, d) policy: // compare pair by pair, with different types // select (1, '1.000000') = ('1.00x', '1.000000'); // 1 compare with '1.00x' as int, // '1.00000' compare with '1.000000' as string ObExprResType tmp_res_type; for (int64_t i = 0; OB_SUCC(ret) && i < row_dimension_; ++i) { if (OB_FAIL(ObRelationalExprOperator::calc_result_type2( tmp_res_type, types[i], types[i + row_dimension_], type_ctx))) { LOG_WARN("failed to calc result types", K(ret)); } else if (OB_FAIL(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()))) { LOG_WARN("failed to push back cmp type", K(ret)); } else { if (ob_is_string_or_lob_type(tmp_res_type.get_calc_type())) { types[i].set_calc_collation_type(tmp_res_type.get_calc_collation_type()); types[i + row_dimension_].set_calc_collation_type(tmp_res_type.get_calc_collation_type()); } else if (ObRawType == tmp_res_type.get_calc_type()) { types[i].set_calc_collation_type(CS_TYPE_BINARY); types[i + row_dimension_].set_calc_collation_type(CS_TYPE_BINARY); } } } // overall result type if (OB_SUCC(ret)) { type.set_int32(); type.set_precision(DEFAULT_PRECISION_FOR_BOOL); type.set_scale(DEFAULT_SCALE_FOR_INTEGER); ObExprOperator::calc_result_flagN(type, types, param_num); } } return ret; } int ObRelationalExprOperator::calc_calc_type3(ObExprResType& type1, ObExprResType& type2, ObExprResType& type3, ObExprTypeCtx& type_ctx, const ObObjType cmp_type) const { int ret = OB_SUCCESS; // a(type1) between b(type2) and c(type3) <==> b<=a && a <=c ObExprResType cmp_type21; // b <= a ObExprResType cmp_type13; // a <= c bool need_no_cast = false; CK(NULL != type_ctx.get_session()); if (OB_FAIL(ret)) { } else if (OB_FAIL(calc_cmp_type2(cmp_type21, type2, type1, type_ctx.get_coll_type()))) { LOG_WARN("get cmp failed", K(ret), K(type2), K(type1)); } else if (OB_FAIL(calc_cmp_type2(cmp_type13, type1, type3, type_ctx.get_coll_type()))) { LOG_WARN("get cmp failed", K(ret), K(type1), K(type3)); } else { ObObjType type21 = cmp_type21.get_type(); ObObjType type13 = cmp_type13.get_type(); if (OB_LIKELY(type21 == type13 && type13 == cmp_type)) { // type21 == type13 == cmp_type bool need_no_cast_21 = can_cmp_without_cast(type2, type1, get_cmp_op(type_), *type_ctx.get_session()); bool need_no_cast_13 = can_cmp_without_cast(type1, type3, get_cmp_op(type_), *type_ctx.get_session()); need_no_cast = need_no_cast_21 && need_no_cast_13; } } if (OB_SUCC(ret)) { if (need_no_cast) { type1.set_calc_type(type1.get_type()); type2.set_calc_type(type2.get_type()); type3.set_calc_type(type3.get_type()); } else { type1.set_calc_type(cmp_type); type2.set_calc_type(cmp_type); type3.set_calc_type(cmp_type); } } return ret; } int ObRelationalExprOperator::get_cmp_result_type3(ObExprResType& type, bool& need_no_cast, const ObExprResType* types, const int64_t param_num, const sql::ObSQLSessionInfo& my_session) { int ret = OB_SUCCESS; need_no_cast = false; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1) || OB_UNLIKELY(param_num > 3)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else if (1 == param_num) { // this is for case when clause like case when 1 then c1 end; type = types[0]; need_no_cast = true; } else { ObCollationType coll_type = CS_TYPE_INVALID; const ObLengthSemantics default_ls = my_session.get_actual_nls_length_semantics(); if (OB_FAIL(my_session.get_collation_connection(coll_type))) { LOG_WARN("fail to get_collation_connection", K(ret)); } else if (2 == param_num) { need_no_cast = can_cmp_without_cast(types[1], types[0], CO_CMP, my_session); if (!need_no_cast) { ret = calc_cmp_type2(type, types[0], types[1], coll_type); } } else { const ObExprResType& type1 = types[0]; const ObExprResType& type2 = types[1]; const ObExprResType& type3 = types[2]; // a(type1) between b(type2) and c(type3) <==> b<=a && a <=c ObExprResType cmp_type21; // b <= a ObExprResType cmp_type13; // a <= c if (OB_FAIL(calc_cmp_type3(type, type1, type2, type3, coll_type))) { LOG_WARN("fail to calc_cmp_type3", K(ret)); } else if (OB_FAIL(calc_cmp_type2(cmp_type21, type2, type1, coll_type))) { LOG_WARN("get cmp failed", K(ret), K(type2), K(type1)); } else if (OB_FAIL(calc_cmp_type2(cmp_type13, type1, type3, coll_type))) { LOG_WARN("get cmp failed", K(ret), K(type1), K(type3)); } else if (cmp_type21.get_type() == cmp_type13.get_type() && cmp_type13.get_type() == type.get_calc_type()) { // type21 == type13 == cmp_type bool need_no_cast_21 = can_cmp_without_cast(type2, type1, CO_CMP, my_session); bool need_no_cast_13 = can_cmp_without_cast(type1, type3, CO_CMP, my_session); need_no_cast = need_no_cast_21 && need_no_cast_13; } } } return ret; } int ObRelationalExprOperator::calc_result2( ObObj& result, const ObObj& obj1, const ObObj& obj2, ObExprCtx& expr_ctx, bool is_null_safe, ObCmpOp cmp_op) const { int ret = OB_SUCCESS; // TODO:: raw // bool need_cast = (share::is_oracle_mode() && obj1.get_collation_type() != obj2.get_collation_type()); bool need_cast = false; EXPR_DEFINE_CMP_CTX(result_type_.get_calc_meta(), is_null_safe, expr_ctx); /* * FIX ME,please. It seems that we must check obj1 and obj2 are null or not here * * But this is so ugly and everything will be retarded */ if (OB_LIKELY(!obj1.is_null() && !obj2.is_null() && cmp_op_func2_ != NULL && !need_cast)) { if (OB_FAIL(compare_nocast(result, obj1, obj2, cmp_ctx, cmp_op, cmp_op_func2_))) { LOG_WARN("failed to compare objects", K(ret), K(obj1), K(obj2)); } } else if (!need_cast && OB_FAIL(compare_nocast(result, obj1, obj2, cmp_ctx, cmp_op, need_cast))) { LOG_WARN("failed to compare objects", K(ret), K(obj1), K(obj2)); } else if (need_cast) { EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); if (OB_FAIL(compare_cast(result, obj1, obj2, cmp_ctx, cast_ctx, cmp_op))) { LOG_WARN("failed to compare objects", K(ret), K(obj1), K(obj2)); } } return ret; } /*If you know little about vector compare in mysql, before you start to read this function, *it is highly recommended for you to digg into this: *http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html * */ int ObRelationalExprOperator::calc_resultN(ObObj& result, const ObObj* objs_array, int64_t param_num, ObExprCtx& expr_ctx, bool is_null_safe, ObCmpOp cmp_op) const { int ret = OB_SUCCESS; if (OB_UNLIKELY(0 >= row_dimension_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("row_dimension_ is less or equal to 0", K(ret)); } else if (OB_ISNULL(objs_array) || OB_UNLIKELY(0 >= param_num) || OB_UNLIKELY(0 != param_num % row_dimension_) || OB_UNLIKELY(2 != param_num / row_dimension_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("objs_array or param_num or row_dimension_ is wrong", K(ret), K(param_num), K(row_dimension_)); } else if (cmp_op < CO_EQ || cmp_op >= CO_CMP) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid cmp_op argument", K(ret), K(cmp_op)); } else { EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); const ObIArray& cmp_types = result_type_.get_row_calc_cmp_types(); int64_t i = 0; bool row_cnt_null = false; ObCompareCtx cmp_ctx(ObMaxType, CS_TYPE_INVALID, is_null_safe, expr_ctx.tz_offset_, default_null_pos()); // firstly, we try to locate the first non-equal pair for (i = 0; OB_SUCC(ret) && i < row_dimension_; ++i) { cmp_ctx.cmp_type_ = cmp_types.at(i).get_type(); cmp_ctx.cmp_cs_type_ = cmp_types.at(i).get_collation_type(); if (OB_FAIL(compare(result, objs_array[i], objs_array[i + row_dimension_], cmp_ctx, cast_ctx, CO_NE))) { LOG_WARN("compare failed", K(objs_array[i]), K(objs_array[i + row_dimension_])); } else if (result.is_null()) { row_cnt_null = true; // no break here } else if (result.is_true()) { break; } } // end for if (OB_SUCC(ret)) { if (i == row_dimension_) { // all pairs are null or equal if (row_cnt_null) { // such as (1,2) op (null, 2) , (1,2) op (null, null) result.set_null(); } else { // all pairs are equal. such as (1,2) op (1,2) if (CO_EQ == cmp_op || CO_LE == cmp_op || CO_GE == cmp_op) { result.set_bool(true); } else { result.set_bool(false); } } } else { // exist one pair whose comparison result is non-equal if (row_cnt_null) { // such as (1,2) op (null, 3) if (CO_NE == cmp_op) { result.set_bool(true); } else if (CO_EQ == cmp_op) { result.set_bool(false); } else { result.set_null(); } } else { // such as (1,2,3) op (1,2,4) cmp_ctx.cmp_type_ = cmp_types.at(i).get_type(); cmp_ctx.cmp_cs_type_ = cmp_types.at(i).get_collation_type(); if (OB_FAIL(compare(result, objs_array[i], objs_array[i + row_dimension_], cmp_ctx, cast_ctx, cmp_op))) { LOG_WARN("compare failed", K(objs_array[i]), K(objs_array[i + row_dimension_]), K(cmp_op)); } } } } if (OB_SUCC(ret)) { if (false == result.is_null()) { // compatiable with MySQL,relational op result type is int32 result.set_int(ObInt32Type, result.get_int()); } } } return ret; } bool ObRelationalExprOperator::is_int_cmp_const_str( const ObExprResType* type1, const ObExprResType* type2, ObObjType& cmp_type) { UNUSED(type1); UNUSED(type2); UNUSED(cmp_type); return false; } int ObRelationalExprOperator::assign(const ObExprOperator& other) { int ret = OB_SUCCESS; const ObRelationalExprOperator* tmp_other = dynamic_cast(&other); if (OB_UNLIKELY(NULL == tmp_other)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument. wrong type for other", K(ret), K(other)); } else if (OB_LIKELY(this != tmp_other)) { if (OB_FAIL(ObExprOperator::assign(other))) { LOG_WARN("copy in Base class ObExprOperator failed", K(ret)); } else { this->cmp_op_func2_ = tmp_other->cmp_op_func2_; } } return ret; } int ObRelationalExprOperator::set_cmp_func(const ObObjType type1, const ObObjType type2) { int ret = OB_SUCCESS; ObCmpOp cmp_op = get_cmp_op(type_); ObObjTypeClass tc1 = ob_obj_type_class(type1); ObObjTypeClass tc2 = ob_obj_type_class(type2); if (OB_FAIL(ObObjCmpFuncs::get_cmp_func(tc1, tc2, cmp_op, cmp_op_func2_))) { LOG_WARN("get cmp func failed", K(type1), K(type2), K(tc1), K(tc2), K(ret)); } return ret; } OB_SERIALIZE_MEMBER((ObSubQueryRelationalExpr, ObExprOperator), subquery_key_, left_is_iter_, right_is_iter_); int ObSubQueryRelationalExpr::assign(const ObExprOperator& other) { int ret = OB_SUCCESS; const ObSubQueryRelationalExpr* tmp_other = dynamic_cast(&other); if (OB_UNLIKELY(NULL == tmp_other)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument. wrong type for other", K(ret), K(other)); } else if (OB_LIKELY(this != tmp_other)) { if (OB_FAIL(ObExprOperator::assign(other))) { LOG_WARN("copy in Base class ObExprOperator failed", K(ret)); } else { this->subquery_key_ = tmp_other->subquery_key_; this->left_is_iter_ = tmp_other->left_is_iter_; this->right_is_iter_ = tmp_other->right_is_iter_; } } return ret; } int ObSubQueryRelationalExpr::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; ObExprResType tmp_res_type; CK(NULL != type_ctx.get_session()); OZ(type.init_row_dimension(1)); if (OB_SUCC(ret) && !type_ctx.get_session()->use_static_typing_engine()) { // static typing engine not enabled, keep the old behavior: // type1, type2 are unchanged if (OB_FAIL(calc_result_type2_(tmp_res_type, type1, type2, type_ctx))) { LOG_WARN("failed to calc_result_type2_", K(ret)); } else if (OB_FAIL(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()))) { LOG_WARN("failed to push back cmp_type", K(ret)); } else { type.set_tinyint(); type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObTinyIntType].scale_); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObTinyIntType].precision_); ObExprOperator::calc_result_flag2(type, type1, type2); } } if (OB_SUCC(ret) && type_ctx.get_session()->use_static_typing_engine()) { // static typing engine enabled, same with ObRelationalExprOperator::calc_result_type OZ(ObRelationalExprOperator::deduce_cmp_type(*this, type, type1, type2, type_ctx)); OZ(type.get_row_calc_cmp_types().push_back(type.get_calc_meta())); } return ret; } int ObSubQueryRelationalExpr::calc_result_typeN( ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; CK(NULL != type_ctx.get_session()); if (OB_FAIL(ret)) { } else if (OB_ISNULL(types) || OB_UNLIKELY(0 >= row_dimension_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or row_dimension_ is less equal than 0", K(types), K(row_dimension_), K(ret)); } else if (OB_UNLIKELY(param_num <= 0 || 2 != param_num / row_dimension_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("param_num is wrong", K(ret)); } else if (OB_FAIL(type.init_row_dimension(row_dimension_))) { LOG_WARN("fail to init row dimension", K(ret)); } if (OB_SUCC(ret) && !type_ctx.get_session()->use_static_typing_engine()) { // static typing engine not enabled, keep the old behavior unchanged: // parameters' type is unchanged. // select (c1, c2) = (select b1, b2 from B); // c1 compare with b1 with type X, // c2 compare with b2 with type Y ObExprResType tmp_res_type; for (int64_t i = 0; OB_SUCC(ret) && i < row_dimension_; ++i) { if (OB_FAIL(ObSubQueryRelationalExpr::calc_result_type2_( tmp_res_type, types[i], types[i + row_dimension_], type_ctx))) { LOG_WARN("fail to calc_result_type2_ when calc_result_typeN", K(ret)); } else if (OB_FAIL(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()))) { LOG_WARN("failed to push back cmp_type", K(ret)); } } // overall result type if (OB_SUCC(ret)) { type.set_tinyint(); ObExprOperator::calc_result_flagN(type, types, param_num); } } if (OB_SUCC(ret) && type_ctx.get_session()->use_static_typing_engine()) { for (int64_t i = 0; OB_SUCC(ret) && i < row_dimension_; i++) { ObExprResType tmp_res_type; OZ(ObRelationalExprOperator::deduce_cmp_type(*this, tmp_res_type, types[i], types[i + row_dimension_], type_ctx)); OZ(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta())); if (OB_SUCC(ret)) { if (ob_is_string_type(tmp_res_type.get_calc_type())) { types[i].set_calc_collation_type(tmp_res_type.get_calc_collation_type()); types[i + row_dimension_].set_calc_collation_type(tmp_res_type.get_calc_collation_type()); } else if (ObRawType == tmp_res_type.get_calc_type()) { types[i].set_calc_collation_type(CS_TYPE_BINARY); types[i + row_dimension_].set_calc_collation_type(CS_TYPE_BINARY); } } } if (OB_SUCC(ret)) { type.set_int32(); type.set_precision(DEFAULT_PRECISION_FOR_BOOL); type.set_scale(DEFAULT_SCALE_FOR_INTEGER); ObExprOperator::calc_result_flagN(type, types, param_num); } } return ret; } int ObSubQueryRelationalExpr::calc_result2( ObObj& result, const ObObj& obj1, const ObObj& obj2, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_UNLIKELY(!right_is_iter_) || OB_ISNULL(expr_ctx.subplan_iters_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("right_is_iter_ is wrong or expr_ctx.subplan_iters_ is null", K(right_is_iter_), K(expr_ctx.subplan_iters_), K(ret)); } else { int64_t subquery_idx = OB_INVALID_INDEX; ObNewRow tmp_row; ObNewRow* left_row = NULL; ObNewRowIterator* left_row_iter = NULL; if (left_is_iter_) { int64_t left_idx = OB_INVALID_INDEX; if (OB_FAIL(obj1.get_int(left_idx))) { LOG_WARN("get left subquery index failed", K(ret), K(obj1)); } else if (OB_ISNULL(left_row_iter = expr_ctx.subplan_iters_->at(left_idx))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get row iterator failed", K(left_idx)); } else if (OB_FAIL(left_row_iter->get_next_row(left_row))) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; result.set_null(); } else { LOG_WARN("get next row from left row iterator failed", K(ret)); } } } else { tmp_row.cells_ = const_cast(&obj1); tmp_row.count_ = 1; left_row = &tmp_row; } if (OB_SUCC(ret) && NULL != left_row) { if (OB_FAIL(obj2.get_int(subquery_idx))) { LOG_WARN("get subquery index failed", K(ret), K(obj2)); } else if (T_WITH_ALL == subquery_key_) { if (OB_FAIL(calc_result_with_all(result, *left_row, subquery_idx, expr_ctx))) { LOG_WARN("calc result with all failed", K(ret)); } } else if (T_WITH_ANY == subquery_key_) { if (OB_FAIL(calc_result_with_any(result, *left_row, subquery_idx, expr_ctx))) { LOG_WARN("calc result with any failed", K(ret)); } } else if (T_WITH_NONE == subquery_key_) { // vector compare. scenario: both left right sides are subqueries if (OB_UNLIKELY(!left_is_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("left_is_iter_ is wrong", K(ret)); } else if (OB_FAIL(calc_result_with_none(result, *left_row, subquery_idx, expr_ctx))) { LOG_WARN("calc result with none failed", K(ret)); } } } // for the comparison of subquery, if the left param is row iterator, // we must check the row count of the left row iterator // the left row iterator can only return one row if (OB_SUCC(ret) && left_is_iter_) { ObNewRow* tmp_left_row = NULL; if (OB_FAIL(left_row_iter->get_next_row(tmp_left_row))) { if (OB_LIKELY(OB_ITER_END == ret)) { ret = OB_SUCCESS; } else { LOG_WARN("get next row from iter failed", K(ret)); } } else { ret = OB_SUBQUERY_TOO_MANY_ROW; } } } return ret; } int ObSubQueryRelationalExpr::calc_resultN( ObObj& result, const ObObj* param_array, int64_t param_num, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_UNLIKELY(param_num <= 2)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("param_num is wrong", K(param_array), K(ret)); } else if (OB_UNLIKELY(left_is_iter_ && right_is_iter_) || OB_ISNULL(expr_ctx.subplan_iters_) || OB_ISNULL(param_array)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("left_is_iter_ and right_is_iter cann't be same true", K(param_num), K(left_is_iter_), K(right_is_iter_), K(expr_ctx.subplan_iters_), K(param_array), K(ret)); } else { int64_t subquery_idx = OB_INVALID_ID; ObNewRow tmp_row; ObNewRow* left_row = NULL; ObNewRowIterator* row_iter = NULL; if (left_is_iter_) { int64_t left_idx = OB_INVALID_INDEX; const ObObj& idx_obj = param_array[0]; if (OB_FAIL(idx_obj.get_int(left_idx))) { LOG_WARN("get left subquery index failed", K(ret), K(idx_obj)); } else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(left_idx))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get row iterator failed", K(left_idx)); } else if (OB_FAIL(row_iter->get_next_row(left_row))) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; result.set_null(); } else { LOG_WARN("get next row from left row iterator failed", K(ret)); } } else { ObNewRow* tmp_left_row = NULL; tmp_row.cells_ = const_cast(¶m_array[1]); tmp_row.count_ = param_num - 1; if (OB_ISNULL(left_row)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("left_row is null", K(left_row), K(ret)); } else if (OB_FAIL(compare_single_row(*left_row, tmp_row, expr_ctx, result))) { LOG_WARN("compare single row failed", K(ret)); } else if (OB_FAIL(row_iter->get_next_row(tmp_left_row))) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; } else { LOG_WARN("get next row from iter failed", K(ret)); } } else { ret = OB_SUBQUERY_TOO_MANY_ROW; } } } else if (right_is_iter_) { tmp_row.cells_ = const_cast(param_array); tmp_row.count_ = param_num - 1; left_row = &tmp_row; const ObObj& idx_obj = param_array[param_num - 1]; if (OB_ISNULL(left_row)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("left_row is null", K(left_row), K(ret)); } else if (OB_FAIL(idx_obj.get_int(subquery_idx))) { LOG_WARN("get subquery index failed", K(ret)); } else if (T_WITH_ALL == subquery_key_) { if (OB_FAIL(calc_result_with_all(result, *left_row, subquery_idx, expr_ctx))) { LOG_WARN("calc result with all failed", K(ret)); } } else if (T_WITH_ANY == subquery_key_) { if (OB_FAIL(calc_result_with_any(result, *left_row, subquery_idx, expr_ctx))) { LOG_WARN("calc result with any failed", K(ret)); } } else if (T_WITH_NONE == subquery_key_) { if (OB_FAIL(calc_result_with_none(result, *left_row, subquery_idx, expr_ctx))) { LOG_WARN("calc result with none failed", K(ret)); } } } else { ret = OB_ERR_UNEXPECTED; LOG_ERROR("left_is_iter_ and right_is_iter are all false", K(ret)); } } return ret; } int ObSubQueryRelationalExpr::call(ObObj* stack, int64_t& stack_size, ObExprCtx& expr_ctx) const { ObObj result; int ret = OB_SUCCESS; if (OB_ISNULL(stack) || OB_UNLIKELY(real_param_num_ < 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("stack is null or the param is wrong", K(stack), K(real_param_num_), K(ret)); } else if (OB_UNLIKELY(real_param_num_ > stack_size)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stack is null or the param is wrong", K(stack_size), K(real_param_num_), K(ret)); } else { switch (real_param_num_) { case 1: { if (OB_FAIL(calc_result1(result, stack[stack_size - 1], expr_ctx))) { LOG_WARN("fail to calc result1", K(ret), K(stack_size)); } else { stack[stack_size - 1] = result; } break; } case 2: { if (OB_FAIL(calc_result2(result, stack[stack_size - 2], stack[stack_size - 1], expr_ctx))) { LOG_WARN("fail to calc result1", K(ret), K(stack_size)); } else { stack[stack_size - 2] = result; stack_size--; } break; } default: { if (OB_FAIL(this->calc_resultN(result, &stack[stack_size - real_param_num_], real_param_num_, expr_ctx))) { LOG_WARN("fail to calc resultN", K(ret), K(stack_size)); } else { stack[stack_size - real_param_num_] = result; stack_size -= real_param_num_ - 1; } break; } // end switch } } return ret; } int ObSubQueryRelationalExpr::eval( common::ObExprCtx& expr_ctx, common::ObObj& val, common::ObObj* params, int64_t param_num) const { int ret = OB_SUCCESS; new (&val) ObObj(); if (OB_ISNULL(params) || OB_UNLIKELY(param_num < 0) || OB_UNLIKELY(real_param_num_ != param_num)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(param_num), K(real_param_num_)); } else { switch (real_param_num_) { case 1: { ret = calc_result1(val, params[0], expr_ctx); break; } case 2: { ret = calc_result2(val, params[0], params[1], expr_ctx); break; } default: { ret = calc_resultN(val, params, param_num, expr_ctx); } } if (OB_FAIL(ret)) { LOG_WARN("calc result failed", K(ret), K(param_num_), K(name_), K(get_type_name(type_))); } } return ret; } int ObSubQueryRelationalExpr::calc_result_with_none( ObObj& result, const ObNewRow& left_row, int64_t subquery_idx, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; ObNewRowIterator* row_iter = NULL; ObNewRow* row = NULL; if (OB_ISNULL(expr_ctx.subplan_iters_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr_ctx.subplan_iters_ is null"); } else if (OB_UNLIKELY(subquery_idx < 0 || subquery_idx >= expr_ctx.subplan_iters_->count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery_idx is invalied", K(subquery_idx), "iter count", expr_ctx.subplan_iters_->count()); } else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(subquery_idx))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery result iterator is null"); } else if (OB_FAIL(row_iter->get_next_row(row))) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; result.set_null(); } else { LOG_WARN("get next row from row iterator failed", K(ret)); } } else { if (OB_ISNULL(row)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("row is null"); } else if (OB_UNLIKELY(left_row.get_count() != row->get_count())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("left_row and right row is not equal"); } else { if (OB_FAIL(compare_single_row(left_row, *row, expr_ctx, result))) { LOG_WARN("compare single row failed", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(row_iter->get_next_row(row))) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; } else { LOG_WARN("get next row from iter failed", K(ret)); } } else { ret = OB_SUBQUERY_TOO_MANY_ROW; } } return ret; } /** * ALL sematics: all true return true. if any false exists, return false * if NULL exists, return NULL if other values are true, return false if any values is false */ int ObSubQueryRelationalExpr::calc_result_with_all( ObObj& result, const ObNewRow& left_row, int64_t subquery_idx, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; ObNewRowIterator* row_iter = NULL; ObNewRow* row = NULL; ObObj tmp_result; bool cnt_null = false; if (OB_ISNULL(expr_ctx.subplan_iters_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery_idx is invalied", K(expr_ctx.subplan_iters_), K(ret)); } else if (OB_UNLIKELY(subquery_idx < 0 || subquery_idx >= expr_ctx.subplan_iters_->count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery_idx is invalied", K(subquery_idx), "iter count", expr_ctx.subplan_iters_->count()); } else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(subquery_idx))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery result iterator is null"); } else { tmp_result.set_bool(true); // empty set returns true while (OB_SUCC(ret) && OB_SUCC(row_iter->get_next_row(row))) { if (OB_ISNULL(row)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("row is null", K(ret)); } else if (OB_UNLIKELY(left_row.get_count() != row->get_count())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("left_row and right_row is not equal", K(ret)); } else { if (OB_FAIL(compare_single_row(left_row, *row, expr_ctx, tmp_result))) { LOG_WARN("compare single row failed", K(ret)); } else if (OB_UNLIKELY(!tmp_result.is_int32() && !tmp_result.is_null())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("result type type is invalid", K(tmp_result)); } else if (tmp_result.is_false()) { break; } else if (tmp_result.is_null()) { cnt_null = true; } } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } if (OB_SUCC(ret)) { if (tmp_result.is_true() && cnt_null) { tmp_result.set_null(); } result = tmp_result; } } return ret; } /** * ANY sematics: return true if any value is true. * return NULL if all other values are false * return false if all values are false */ int ObSubQueryRelationalExpr::calc_result_with_any( ObObj& result, const ObNewRow& left_row, int64_t subquery_idx, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; ObNewRowIterator* row_iter = NULL; ObNewRow* row = NULL; ObObj tmp_result; bool cnt_null = false; if (OB_ISNULL(expr_ctx.subplan_iters_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery_idx is invalied", K(expr_ctx.subplan_iters_), K(ret)); } else if (OB_UNLIKELY(subquery_idx < 0 || subquery_idx >= expr_ctx.subplan_iters_->count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery_idx is invalied", K(subquery_idx), "iter count", expr_ctx.subplan_iters_->count()); } else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(subquery_idx))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("subquery result iterator is null"); } else { tmp_result.set_bool(false); while (OB_SUCC(ret) && OB_SUCC(row_iter->get_next_row(row))) { if (OB_UNLIKELY(left_row.get_count() != row->get_count())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("left_row and right_row is not equal", K(ret)); } else { if (OB_FAIL(compare_single_row(left_row, *row, expr_ctx, tmp_result))) { LOG_WARN("compare single row failed", K(ret)); } else if (OB_UNLIKELY(!tmp_result.is_int32() && !tmp_result.is_null())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("result type type is invalid", K(tmp_result), K(ret)); } else if (tmp_result.is_true()) { break; } else if (tmp_result.is_null()) { cnt_null = true; } } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } if (OB_SUCC(ret)) { if (tmp_result.is_false() && cnt_null) { tmp_result.set_null(); } result = tmp_result; } } return ret; } int ObSubQueryRelationalExpr::compare_obj(common::ObExprCtx& expr_ctx, const ObObj& obj1, const ObObj& obj2, const ObExprCalcType& cmp_type, bool is_null_safe, ObObj& result) const { int ret = OB_SUCCESS; EXPR_DEFINE_CMP_CTX(cmp_type, is_null_safe, expr_ctx); EXPR_DEFINE_CAST_CTX(expr_ctx, CM_WARN_ON_FAIL); if (OB_FAIL(ObRelationalExprOperator::compare_cast(result, obj1, obj2, cmp_ctx, cast_ctx, CO_CMP))) { LOG_WARN("Compare expression failed", K(ret)); } return ret; } int ObSubQueryRelationalExpr::compare_single_row( const ObNewRow& left_row, const ObNewRow& right_row, ObExprCtx& expr_ctx, ObObj& result) const { UNUSED(left_row); UNUSED(right_row); UNUSED(expr_ctx); UNUSED(result); return OB_NOT_IMPLEMENT; } int ObSubQueryRelationalExpr::get_param_types( const ObRawExpr& param, const bool is_iter, ObIArray& types) const { int ret = OB_SUCCESS; if (param.get_expr_type() == T_OP_ROW) { for (int64_t i = 0; OB_SUCC(ret) && i < param.get_param_count(); i++) { const ObRawExpr* e = param.get_param_expr(i); CK(NULL != e); OZ(types.push_back(e->get_result_meta())); } } else if (param.get_expr_type() == T_REF_QUERY && is_iter) { const ObQueryRefRawExpr& ref = static_cast(param); FOREACH_CNT_X(t, ref.get_column_types(), OB_SUCC(ret)) { OZ(types.push_back(*t)); } } else { OZ(types.push_back(param.get_result_meta())); } return ret; } int ObSubQueryRelationalExpr::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { int ret = OB_SUCCESS; ObSEArray left_types; ObSEArray right_types; void** funcs = NULL; CK(NULL != op_cg_ctx.allocator_); CK(2 == raw_expr.get_param_count()); CK(NULL != raw_expr.get_param_expr(0)); CK(NULL != raw_expr.get_param_expr(1)); // row_dimension_ is set for old expr engine in ObExprGeneratorImpl, can not used here OZ(get_param_types(*raw_expr.get_param_expr(0), left_is_iter_, left_types)); OZ(get_param_types(*raw_expr.get_param_expr(1), right_is_iter_, right_types)); if (OB_FAIL(ret)) { } else if (left_types.empty() || left_types.count() != right_types.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("operand cnt mismatch", K(ret), K(left_types.count()), K(right_types.count())); } else if (OB_ISNULL(funcs = (void**)op_cg_ctx.allocator_->alloc(sizeof(void*) * left_types.count()))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc memory failed", K(ret)); } else { rt_expr.inner_func_cnt_ = left_types.count(); rt_expr.inner_functions_ = funcs; for (int64_t i = 0; OB_SUCC(ret) && i < rt_expr.inner_func_cnt_; i++) { auto& l = left_types.at(i); auto& r = right_types.at(i); if (ObDatumFuncs::is_string_type(l.get_type()) && ObDatumFuncs::is_string_type(r.get_type())) { CK(l.get_collation_type() == r.get_collation_type()); } 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()); CK(NULL != funcs[i]); } } if (OB_SUCC(ret)) { ExtraInfo& info = ExtraInfo::get_info(rt_expr); info.subquery_key_ = subquery_key_; info.left_is_iter_ = left_is_iter_; info.right_is_iter_ = right_is_iter_; rt_expr.eval_func_ = &subquery_cmp_eval; } } return ret; } int ObSubQueryRelationalExpr::check_exists(const ObExpr& expr, ObEvalCtx& ctx, bool& exists) { int ret = OB_SUCCESS; ObDatum* v = NULL; ObSubQueryIterator* iter = NULL; exists = false; if (1 != expr.arg_cnt_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected argument count", K(ret)); } else if (OB_FAIL(expr.args_[0]->eval(ctx, v))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL subquery ref info returned", K(ret)); } else if (OB_FAIL(ObExprSubQueryRef::get_subquery_iter( ctx, ObExprSubQueryRef::ExtraInfo::get_info(v->get_int()), iter))) { LOG_WARN("get subquery iterator failed", K(ret)); } else if (OB_ISNULL(iter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL subquery iterator", K(ret)); } else if (OB_FAIL(iter->start())) { LOG_WARN("start iterate failed", K(ret)); } else if (OB_FAIL(iter->get_next_row())) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; exists = false; } else { LOG_WARN("get next row failed", K(ret)); } } else { exists = true; } return ret; } int ObSubQueryRelationalExpr::setup_row(ObExpr** expr, ObEvalCtx& ctx, const bool is_iter, const int64_t cmp_func_cnt, ObSubQueryIterator*& iter, ObExpr**& row) { int ret = OB_SUCCESS; if (is_iter) { ObDatum* v = NULL; if (OB_FAIL(expr[0]->eval(ctx, v))) { LOG_WARN("expr evaluate failed", K(ret)); } else if (v->is_null()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL subquery ref info returned", K(ret)); } else if (OB_FAIL(ObExprSubQueryRef::get_subquery_iter( ctx, ObExprSubQueryRef::ExtraInfo::get_info(v->get_int()), iter))) { LOG_WARN("get subquery iterator failed", K(ret)); } else if (OB_ISNULL(iter) || cmp_func_cnt != iter->get_output().count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL subquery iterator", K(ret), KP(iter), K(cmp_func_cnt)); } else if (OB_FAIL(iter->start())) { LOG_WARN("start iterate failed", K(ret)); } else { row = &const_cast(iter->get_output()).at(0); } } else if (T_OP_ROW == expr[0]->type_) { if (cmp_func_cnt != expr[0]->arg_cnt_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cmp function count mismatch", K(ret), K(cmp_func_cnt), K(*expr[0])); } else { row = expr[0]->args_; } } else { row = expr; } return ret; } int ObSubQueryRelationalExpr::cmp_one_row( const ObExpr& expr, ObDatum& res, ObExpr** l_row, ObEvalCtx& l_ctx, ObExpr** r_row, ObEvalCtx& r_ctx) { int ret = OB_SUCCESS; if (OB_UNLIKELY(T_OP_SQ_NSEQ == expr.type_)) { ret = ObExprNullSafeEqual::ns_equal(expr, res, l_row, l_ctx, r_row, r_ctx); } else { ret = ObRelationalExprOperator::row_cmp(expr, res, l_row, l_ctx, r_row, r_ctx); } return ret; } int ObSubQueryRelationalExpr::subquery_cmp_eval(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; const ExtraInfo& info = ExtraInfo::get_info(expr); ObSubQueryIterator* l_iter = NULL; ObSubQueryIterator* r_iter = NULL; ObExpr** l_row = NULL; ObExpr** r_row = NULL; if (2 != expr.arg_cnt_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected argument count", K(ret)); } else if (OB_FAIL(setup_row(expr.args_, ctx, info.left_is_iter_, expr.inner_func_cnt_, l_iter, l_row))) { LOG_WARN("setup left row failed", K(ret)); } else if (OB_FAIL(setup_row(expr.args_ + 1, ctx, info.right_is_iter_, expr.inner_func_cnt_, r_iter, r_row))) { LOG_WARN("setup right row failed", K(ret)); } else if (OB_ISNULL(l_row) || OB_ISNULL(r_row)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null row", K(ret)); } else { bool l_end = false; if (NULL != l_iter) { if (OB_FAIL(l_iter->get_next_row())) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; l_end = true; // set row to NULL for (int64_t i = 0; i < expr.inner_func_cnt_; i++) { l_row[i]->locate_expr_datum(ctx).set_null(); l_row[i]->get_eval_info(ctx).evaluated_ = true; } } else { LOG_WARN("get next row failed", K(ret)); } } } if (OB_SUCC(ret)) { switch (info.subquery_key_) { case T_WITH_NONE: { ret = subquery_cmp_eval_with_none(expr, ctx, expr_datum, l_row, r_row, r_iter); break; } case T_WITH_ANY: { ret = subquery_cmp_eval_with_any(expr, ctx, expr_datum, l_row, r_row, r_iter); break; } case T_WITH_ALL: { ret = subquery_cmp_eval_with_all(expr, ctx, expr_datum, l_row, r_row, r_iter); break; } } } if (OB_SUCC(ret) && NULL != l_iter && !l_end) { if (OB_FAIL(l_iter->get_next_row())) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; } else { LOG_WARN("get next row failed", K(ret)); } } else { // only one row expected for left row ret = OB_SUBQUERY_TOO_MANY_ROW; } } } return ret; } int ObSubQueryRelationalExpr::subquery_cmp_eval_with_none( const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res, ObExpr** l_row, ObExpr** r_row, ObSubQueryIterator* r_iter) { int ret = OB_SUCCESS; // %l_row, %r_row is checked no need to check. // %iter may be NULL for with none. bool iter_end = false; if (NULL != r_iter) { if (OB_FAIL(r_iter->get_next_row())) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; iter_end = true; // set row to NULL for (int64_t i = 0; i < expr.inner_func_cnt_; i++) { r_row[i]->locate_expr_datum(ctx).set_null(); r_row[i]->get_eval_info(ctx).evaluated_ = true; } } else { LOG_WARN("get next row failed", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(cmp_one_row(expr, res, l_row, ctx, r_row, ctx))) { LOG_WARN("compare one row failed", K(ret)); } } if (NULL != r_iter && !iter_end && OB_SUCC(ret)) { if (OB_FAIL(r_iter->get_next_row())) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; } else { LOG_WARN("get next row failed", K(ret)); } } else { // only one row expected for left row ret = OB_SUBQUERY_TOO_MANY_ROW; } } return ret; } // copy from ObSubQueryRelationalExpr::calc_result_with_any int ObSubQueryRelationalExpr::subquery_cmp_eval_with_any( const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res, ObExpr** l_row, ObExpr** r_row, ObSubQueryIterator* r_iter) { // %l_row, %r_row is checked no need to check. int ret = OB_SUCCESS; if (OB_ISNULL(r_iter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("iter should not be null", K(ret)); } else { bool cnt_null = false; res.set_false(); while (OB_SUCC(ret) && OB_SUCC(r_iter->get_next_row())) { // use subquery's eval ctx for right row to avoid ObEvalCtx::alloc_ expanding. if (OB_FAIL(cmp_one_row(expr, res, l_row, ctx, r_row, r_iter->get_op().get_eval_ctx()))) { LOG_WARN("compare single row failed", K(ret)); } else if (res.is_true()) { break; } else if (res.is_null()) { cnt_null = true; } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } if (OB_SUCC(ret)) { if (res.is_false() && cnt_null) { res.set_null(); } } } return ret; } // copy from ObSubQueryRelationalExpr::calc_result_with_all int ObSubQueryRelationalExpr::subquery_cmp_eval_with_all( const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res, ObExpr** l_row, ObExpr** r_row, ObSubQueryIterator* r_iter) { // %l_row, %r_row is checked no need to check. int ret = OB_SUCCESS; if (OB_ISNULL(r_iter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("iter should not be null", K(ret)); } else { bool cnt_null = false; res.set_true(); while (OB_SUCC(ret) && OB_SUCC(r_iter->get_next_row())) { // use subquery's eval ctx for right row to avoid ObEvalCtx::alloc_ expanding. if (OB_FAIL(cmp_one_row(expr, res, l_row, ctx, r_row, r_iter->get_op().get_eval_ctx()))) { LOG_WARN("compare single row failed", K(ret)); } else if (res.is_false()) { break; } else if (res.is_null()) { cnt_null = true; } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } if (OB_SUCC(ret)) { if (res.is_true() && cnt_null) { res.set_null(); } } } return ret; } int ObLogicalExprOperator::calc_result_type1(ObExprResType& type, ObExprResType& type1, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; UNUSED(type1); if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { type.set_tinyint(); } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; } return ret; } int ObSubQueryRelationalExpr::calc_result_type2_( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; ObExprResType cmp_type; if (OB_SUCC(calc_cmp_type2(cmp_type, type1, type2, type_ctx.get_coll_type()))) { type.set_tinyint(); type.set_calc_collation(cmp_type); type.set_calc_type(cmp_type.get_calc_type()); ObExprOperator::calc_result_flag2(type, type1, type2); } return ret; } int ObLogicalExprOperator::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; UNUSED(type1); UNUSED(type2); UNUSED(type_ctx); if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { type.set_tinyint(); } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; } return ret; } int ObLogicalExprOperator::calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; UNUSED(type1); UNUSED(type2); UNUSED(type3); UNUSED(type_ctx); if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { type.set_tinyint(); } else { ret = OB_NOT_SUPPORTED; } return ret; } int ObLogicalExprOperator::calc_result_typeN( ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; UNUSED(types); UNUSED(param_num); UNUSED(type_ctx); if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { type.set_tinyint(); } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; } return ret; } int ObLogicalExprOperator::is_true(const ObObj& obj, ObCastMode cast_mode, bool& result) { int ret = OB_SUCCESS; if (OB_FAIL(ObObjEvaluator::is_true(obj, cast_mode, result))) { // ugly...really ugly in order to be compatible with mysql. if (OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD == ret) { // slow path. need twice calls for is_true_. not efficient but we will not reach here too frequently ret = ObObjEvaluator::is_true(obj, CM_WARN_ON_FAIL | CM_NO_RANGE_CHECK, result); } } return ret; } int ObVectorExprOperator::calc_result_type1(ObExprResType& type, ObExprResType& type1, ObExprTypeCtx& type_ctx) const { int ret = OB_ERR_UNEXPECTED; UNUSED(type); UNUSED(type1); UNUSED(type_ctx); LOG_WARN("operator in should not come here", K(ret)); return ret; } int ObVectorExprOperator::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { ObArenaAllocator alloc; ObExprResType types[2] = {alloc, alloc}; types[0] = type1; types[1] = type2; return calc_result_typeN(type, types, 2, type_ctx); } int ObVectorExprOperator::calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3, ObExprTypeCtx& type_ctx) const { ObArenaAllocator alloc; ObExprResType types[3] = {alloc, alloc, alloc}; types[0] = type1; types[1] = type2; types[2] = type3; return calc_result_typeN(type, types, 3, type_ctx); } int ObVectorExprOperator::calc_result_typeN( ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num <= 0 || 0 >= row_dimension_) || OB_ISNULL(type_ctx.get_session())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("types is null or invalid param num or row_dimension_", K(types), K(param_num), K(row_dimension_), K(type_ctx.get_session()), K(ret)); } else { int64_t left_start_idx = 0; int64_t right_start_idx = row_dimension_; int64_t right_element_count = param_num / row_dimension_ - 1; ObExprResType tmp_res_type; if (OB_FAIL(type.init_row_dimension(param_num))) { LOG_WARN("fail to init row dimension", K(ret)); } bool is_nested_table_elem = true; // in maybe nest table, (nt1 in (nt2, nt3, nt4)) for (int64_t k = 0; lib::is_oracle_mode() && k < param_num; ++k) { is_nested_table_elem &= types[k].is_ext(); } if (lib::is_oracle_mode() && is_nested_table_elem) { if (row_dimension_ != 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("in condition of nest table can only have one left operator", K(ret), K(row_dimension_), K(param_num)); } else { // extend type is unknown yet, get at runtime } } else { for (int64_t i = 0; OB_SUCC(ret) && i < right_element_count; ++i, right_start_idx += row_dimension_) { tmp_res_type.reset(); for (int64_t j = 0; OB_SUCC(ret) && j < row_dimension_; ++j) { if (OB_FAIL(ObVectorExprOperator::calc_result_type2_( tmp_res_type, types[left_start_idx + j], types[right_start_idx + j], type_ctx))) { LOG_WARN("failed to calc result types", K(ret)); } else if (OB_FAIL(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()))) { LOG_WARN("failed to push back cmp type", K(ret)); } } } } // overall result type if (OB_SUCC(ret)) { type.set_int32(); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[type.get_type()].precision_); type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[type.get_type()].scale_); ObExprOperator::calc_result_flagN(type, types, param_num); } } return ret; } int ObVectorExprOperator::calc_result_type2_( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; ObExprResType cmp_type; if (OB_SUCC(calc_cmp_type2(cmp_type, type1, type2, type_ctx.get_coll_type()))) { type.set_int(); // not tinyint, compatiable with MySQL type.set_calc_collation(cmp_type); type.set_calc_type(cmp_type.get_calc_type()); ObExprOperator::calc_result_flag2(type, type1, type2); if (GCONF.enable_static_engine_for_query()) { obj_cmp_func func_ptr = NULL; bool need_no_cast = ObRelationalExprOperator::can_cmp_without_cast(type1, type2, CO_EQ, func_ptr); type1.set_calc_type(need_no_cast ? type1.get_type() : cmp_type.get_calc_type()); type2.set_calc_type(need_no_cast ? type2.get_type() : cmp_type.get_calc_type()); if (ob_is_string_type(cmp_type.get_calc_type())) { if (OB_ISNULL(type_ctx.get_session())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null session", K(type_ctx.get_session())); } else if (share::is_oracle_mode()) { // oracle charset deduce ObExprResType tmp_res_type; ObSEArray tmp_param_array; if (OB_FAIL(tmp_param_array.push_back(&type1)) || OB_FAIL(tmp_param_array.push_back(&type2))) { LOG_WARN("failed to push back element", K(ret)); } else if (OB_FAIL(aggregate_string_type_and_charset_oracle( *type_ctx.get_session(), tmp_param_array, tmp_res_type))) { LOG_WARN("unexpected failed", K(ret)); } else if (OB_FAIL(deduce_string_param_calc_type_and_charset( *type_ctx.get_session(), tmp_res_type, tmp_param_array))) { LOG_WARN("unexpected failed", K(ret)); } } else { type1.set_calc_collation_type(cmp_type.get_calc_collation_type()); type2.set_calc_collation_type(cmp_type.get_calc_collation_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); } } } return ret; } int ObStringExprOperator::convert_result_collation( const ObExprResType& result_type, ObObj& in_obj, ObIAllocator* allocator) { int ret = OB_SUCCESS; ObCollationType in_collation = in_obj.get_collation_type(); ObString out_str; if (OB_UNLIKELY(!in_obj.is_string_or_lob_locator_type() || !result_type.is_string_or_lob_locator_type() || !ObCharset::is_valid_collation(in_collation) || !ObCharset::is_valid_collation(result_type.get_collation_type()) || OB_ISNULL(allocator))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(in_obj), K(result_type)); } else if (OB_FAIL(ObExprUtil::convert_string_collation( in_obj.get_string(), in_collation, out_str, result_type.get_collation_type(), *allocator))) { LOG_WARN("convert_string_collation failed", K(ret), K(in_obj), K(result_type)); } else { in_obj.set_string(result_type.get_type(), out_str); in_obj.set_collation(result_type); } return ret; } ObObjType ObStringExprOperator::get_result_type_mysql(int64_t char_length) const { /* drop table t1; drop table t2; create table t1 ( col_varchar varchar(1), col_varbinary varbinary(1), col_char char(1), col_binary binary(1), col_tinytext tinytext, col_tinyblob tinyblob, col_mediumtext mediumtext, col_mediumblob mediumblob, col_text text, col_blob blob, col_count bigint); create table t2 as select repeat('啊', 512), repeat('a', 513), repeat('啊', 21845), repeat('a', 21846), repeat(col_varchar, '512'), repeat(col_varchar, '513'), repeat(col_varchar, 65535), repeat(col_varchar, 65536), repeat(col_varbinary, '512'), repeat(col_varbinary, '513'), repeat(col_varbinary, 65535), repeat(col_varbinary, 65536), repeat(col_char, '512'), repeat(col_char, '513'), repeat(col_char, 65535), repeat(col_char, 65536), repeat(col_binary, '512'), repeat(col_binary, '513'), repeat(col_binary, 65535), repeat(col_binary, 65536), repeat(col_tinytext, 2), repeat(col_tinytext, 3), repeat(col_tinytext, 257), repeat(col_tinytext, 258), repeat(col_tinyblob, 2), repeat(col_tinyblob, 3), repeat(col_tinyblob, 257), repeat(col_tinyblob, 258), repeat(col_mediumtext, 1), repeat(col_mediumblob, 1), repeat(col_text, 1), repeat(col_text, 2), repeat(col_blob, 1), repeat(col_blob, 2), repeat('啊', col_count), repeat('a', col_count), repeat(col_varchar, col_count), repeat(col_varbinary, col_count), repeat(col_char, col_count), repeat(col_binary, col_count), repeat(col_tinytext, col_count), repeat(col_tinyblob, col_count), repeat(col_mediumtext, col_count), repeat(col_mediumblob, col_count), repeat(col_text, col_count), repeat(col_blob, col_count) from t1; desc t2; MySQL> desc t2; +-----------------------------------+----------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------------------------------+----------------+------+-----+---------+-------+ | repeat('啊', 512) | varchar(512) | YES | | NULL | | | repeat('a', 513) | text | YES | | NULL | | | repeat('啊', 21845) | text | YES | | NULL | | | repeat('a', 21846) | longtext | YES | | NULL | | | repeat(col_varchar, '512') | varchar(512) | YES | | NULL | | | repeat(col_varchar, '513') | text | YES | | NULL | | | repeat(col_varchar, 65535) | text | YES | | NULL | | | repeat(col_varchar, 65536) | longtext | YES | | NULL | | | repeat(col_varbinary, '512') | varbinary(512) | YES | | NULL | | | repeat(col_varbinary, '513') | blob | YES | | NULL | | | repeat(col_varbinary, 65535) | blob | YES | | NULL | | | repeat(col_varbinary, 65536) | longblob | YES | | NULL | | | repeat(col_char, '512') | varchar(512) | YES | | NULL | | | repeat(col_char, '513') | text | YES | | NULL | | | repeat(col_char, 65535) | text | YES | | NULL | | | repeat(col_char, 65536) | longtext | YES | | NULL | | | repeat(col_binary, '512') | varbinary(512) | YES | | NULL | | | repeat(col_binary, '513') | blob | YES | | NULL | | | repeat(col_binary, 65535) | blob | YES | | NULL | | | repeat(col_binary, 65536) | longblob | YES | | NULL | | | repeat(col_tinytext, 2) | varchar(510) | YES | | NULL | | | repeat(col_tinytext, 3) | text | YES | | NULL | | | repeat(col_tinytext, 257) | text | YES | | NULL | | | repeat(col_tinytext, 258) | longtext | YES | | NULL | | | repeat(col_tinyblob, 2) | varbinary(510) | YES | | NULL | | | repeat(col_tinyblob, 3) | blob | YES | | NULL | | | repeat(col_tinyblob, 257) | blob | YES | | NULL | | | repeat(col_tinyblob, 258) | longblob | YES | | NULL | | | repeat(col_mediumtext, 1) | longtext | YES | | NULL | | | repeat(col_mediumblob, 1) | longblob | YES | | NULL | | | repeat(col_text, 1) | text | YES | | NULL | | | repeat(col_text, 2) | longtext | YES | | NULL | | | repeat(col_blob, 1) | blob | YES | | NULL | | | repeat(col_blob, 2) | longblob | YES | | NULL | | | repeat('啊', col_count) | longtext | YES | | NULL | | | repeat('a', col_count) | longtext | YES | | NULL | | | repeat(col_varchar, col_count) | longtext | YES | | NULL | | | repeat(col_varbinary, col_count) | longblob | YES | | NULL | | | repeat(col_char, col_count) | longtext | YES | | NULL | | | repeat(col_binary, col_count) | longblob | YES | | NULL | | | repeat(col_tinytext, col_count) | longtext | YES | | NULL | | | repeat(col_tinyblob, col_count) | longblob | YES | | NULL | | | repeat(col_mediumtext, col_count) | longtext | YES | | NULL | | | repeat(col_mediumblob, col_count) | longblob | YES | | NULL | | | repeat(col_text, col_count) | longtext | YES | | NULL | | | repeat(col_blob, col_count) | longblob | YES | | NULL | | +-----------------------------------+----------------+------+-----+---------+-------+ 46 rows in set (0.00 sec) * summarize the rules that mysql decide the result type of some string functions, * which mainly depend on the MAX CHAR LENGTH of result: * 1. less than or equal to 512: varchar, otherwise * 2. less than or equal to 65535: text or blob, otherwise * 3. longtext or longblob (including UNKNOWN length when count param is not const). * do not care about the input data type, or whether the input is column or const. * * ATTENTION! we will ignore these exceptions: * 1. repeat('啊', 21845) => text, repeat('a', 21846) => longtext. we can not * understand the magic numbers 21845 and 21846. * 2. repeat(col_mediumtext, 1) => longtext, repeat(col_mediumblob, 1) => longblob. * text or blob is enough, see: * repeat(col_text, 1) => text, repeat(col_blob, 1) => blob. */ ObObjType res_type = ObMaxType; if (char_length <= MAX_CHAR_LENGTH_FOR_VARCAHR_RESULT) { res_type = ObVarcharType; } else if (char_length <= MAX_CHAR_LENGTH_FOR_TEXT_RESULT) { res_type = ObTextType; } else { res_type = ObLongTextType; } return res_type; } // for static_typing_engine int ObBitwiseExprOperator::set_calc_type(ObExprResType& type) { if (lib::is_oracle_mode()) { type.set_calc_type(ObNumberType); type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER); type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER); } else { if (ObNumberType == type.get_type()) { type.set_calc_type(ObNumberType); type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER); type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER); } else { type.set_calc_type(ObUInt64Type); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_); type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_); } } return OB_SUCCESS; } int ObBitwiseExprOperator::calc_result_type1(ObExprResType& type, ObExprResType& type1, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { if (is_oracle_mode()) { type.set_number(); type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER); type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER); } else { type.set_uint64(); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_); type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_); } ObExprOperator::calc_result_flag1(type, type1); const ObSQLSessionInfo* session = dynamic_cast(type_ctx.get_session()); if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cast basic session to sql session failed", K(ret)); } else if (session->use_static_typing_engine()) { if (OB_FAIL(set_calc_type(type1))) { LOG_WARN("set_calc_type for type1 failed", K(ret), K(type1)); } else { ObCastMode cm = lib::is_oracle_mode() ? CM_NONE : CM_STRING_INTEGER_TRUNC; type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NO_RANGE_CHECK | cm); } } } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; } return ret; } int ObBitwiseExprOperator::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { if (is_oracle_mode()) { type.set_number(); type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER); type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER); } else { type.set_uint64(); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_); type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_); } ObExprOperator::calc_result_flag2(type, type1, type2); const ObSQLSessionInfo* session = dynamic_cast(type_ctx.get_session()); if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cast basic session to sql session failed", K(ret)); } else if (session->use_static_typing_engine()) { if (OB_FAIL(set_calc_type(type1))) { LOG_WARN("set_calc_type for type1 failed", K(ret), K(type1)); } else if (OB_FAIL(set_calc_type(type2))) { LOG_WARN("set_calc_type for type2 failed", K(ret), K(type2)); } else { ObCastMode cm = lib::is_oracle_mode() ? CM_NONE : CM_STRING_INTEGER_TRUNC; type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NO_RANGE_CHECK | cm); } } } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; } LOG_DEBUG("bitwise calc type2 done", K(ret), K(type), K(type1), K(type2)); return ret; } int ObBitwiseExprOperator::calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); int ret = OB_SUCCESS; if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { if (is_oracle_mode()) { type.set_number(); type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER); type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER); } else { type.set_uint64(); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_); type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_); } ObExprOperator::calc_result_flag3(type, type1, type2, type3); } else { ret = OB_NOT_SUPPORTED; } return ret; } int ObBitwiseExprOperator::calc_result_typeN( ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; UNUSED(types); UNUSED(param_num); UNUSED(type_ctx); if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) { if (is_oracle_mode()) { type.set_number(); type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER); type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER); } else { type.set_uint64(); type.set_scale(DEFAULT_SCALE_FOR_INTEGER); } ObExprOperator::calc_result_flagN(type, types, param_num); } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; } return ret; } int ObBitwiseExprOperator::calc_( ObObj& res, const ObObj& obj1, const ObObj& obj2, ObExprCtx& expr_ctx, BitOperator op) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("expr_ctx.calc_buf_ is null", K(expr_ctx.calc_buf_), K(ret)); } else if (OB_UNLIKELY(op < 0 || op >= BIT_MAX)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid index", K(obj1), K(obj2), K(op)); } else if (OB_UNLIKELY(obj1.is_null() || obj2.is_null())) { res.set_null(); } else { if (share::is_mysql_mode()) { uint64_t uint64_v1 = 0; uint64_t uint64_v2 = 0; if (OB_FAIL(get_uint64(obj1, expr_ctx, true, uint64_v1))) { LOG_WARN("fail to get uint64", K(obj1), K(ret)); } else if (OB_FAIL(get_uint64(obj2, expr_ctx, true, uint64_v2))) { LOG_WARN("fail to get uint64", K(obj2), K(ret)); } else { // Do not worry too much about the efficiency // although we calc 5 results while only one is used here. // Bit operations take little time uint64_t bit_op_res[BIT_MAX] = {uint64_v1 & uint64_v2, uint64_v1 | uint64_v2, uint64_v1 ^ uint64_v2, uint64_v2 < sizeof(uint64_t) * 8 ? uint64_v1 << uint64_v2 : 0, uint64_v2 < sizeof(uint64_t) * 8 ? uint64_v1 >> uint64_v2 : 0}; res.set_uint64(bit_op_res[op]); } } else { if (op != BIT_AND) { ret = OB_NOT_SUPPORTED; // oracle mode support bitand op only LOG_WARN("not support bit op in oracle mode", K(ret), K(op)); } else { int64_t int64_v1 = 0; int64_t int64_v2 = 0; if (OB_FAIL(get_int64(obj1, expr_ctx, false, int64_v1))) { LOG_WARN("failed to get int64", K(obj1), K(ret)); } else if (OB_FAIL(get_int64(obj2, expr_ctx, false, int64_v2))) { LOG_WARN("failed to get int64", K(obj2), K(ret)); } else { ObNumber result; result.from((int64_v1 & int64_v2), *expr_ctx.calc_buf_); res.set_number(result); } } } } return ret; } int ObBitwiseExprOperator::calc_result2_mysql(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum) { int ret = OB_SUCCESS; ObDatum* left = NULL; ObDatum* right = NULL; const BitOperator op = static_cast(expr.extra_); ObCastMode cast_mode = CM_NONE; if (OB_UNLIKELY(op < 0 || op >= BIT_MAX)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(op)); } else if (OB_FAIL(expr.args_[0]->eval(ctx, left))) { LOG_WARN("eval arg 0 failed", K(ret)); } else if (left->is_null()) { res_datum.set_null(); } else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) { LOG_WARN("eval arg 1 failed", K(ret)); } else if (right->is_null()) { res_datum.set_null(); } else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(false, 0, ctx.exec_ctx_.get_my_session(), cast_mode))) { LOG_WARN("get default cast mode failed", K(ret)); } else { uint64_t left_uint = 0; uint64_t right_uint = 0; void* get_uint_func0 = NULL; void* get_uint_func1 = NULL; const ObObjType& left_type = expr.args_[0]->datum_meta_.type_; const ObObjType& right_type = expr.args_[1]->datum_meta_.type_; if (OB_FAIL(choose_get_int_func(left_type, get_uint_func0))) { LOG_WARN("choose_get_int_func failed", K(ret), K(left_type)); } else if (OB_FAIL((reinterpret_cast(get_uint_func0)(*left, true, left_uint, cast_mode)))) { LOG_WARN("get uint64 failed", K(ret), K(*left)); } else if (OB_FAIL(choose_get_int_func(right_type, get_uint_func1))) { LOG_WARN("choose_get_int_func failed", K(ret), K(right_type)); } else if (OB_FAIL((reinterpret_cast(get_uint_func1)(*right, true, right_uint, cast_mode)))) { LOG_WARN("get uint64 failed", K(ret), K(*right)); } else { // Do not worry too much about the efficiency // although we calc 5 results while only one is used here. // Bit operations take little time uint64_t bit_op_res[BIT_MAX] = {left_uint & right_uint, left_uint | right_uint, left_uint ^ right_uint, right_uint < sizeof(uint64_t) * 8 ? left_uint << right_uint : 0, right_uint < sizeof(uint64_t) * 8 ? left_uint >> right_uint : 0}; res_datum.set_uint(bit_op_res[op]); } } return ret; } int ObBitwiseExprOperator::calc_result2_oracle(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum) { int ret = OB_SUCCESS; ObDatum* left = NULL; ObDatum* right = NULL; const BitOperator op = static_cast(expr.extra_); ObCastMode cast_mode = CM_NONE; if (OB_UNLIKELY(BIT_AND != op)) { ret = OB_NOT_SUPPORTED; LOG_WARN("unsupported bit operator", K(ret), K(op), K(BIT_AND)); } else if (OB_FAIL(expr.args_[0]->eval(ctx, left))) { LOG_WARN("eval arg 0 failed", K(ret)); } else if (left->is_null()) { res_datum.set_null(); } else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) { LOG_WARN("eval arg 1 failed", K(ret)); } else if (right->is_null()) { res_datum.set_null(); } else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(false, 0, ctx.exec_ctx_.get_my_session(), cast_mode))) { LOG_WARN("get default cast mode failed", K(ret)); } else { int64_t left_int = 0; int64_t right_int = 0; ObNumStackOnceAlloc tmp_alloc; ObNumber result; void* get_int_func0 = NULL; void* get_int_func1 = NULL; const ObObjType& left_type = expr.args_[0]->datum_meta_.type_; const ObObjType& right_type = expr.args_[1]->datum_meta_.type_; if (OB_FAIL(choose_get_int_func(left_type, get_int_func0))) { LOG_WARN("choose_get_int_func failed", K(ret), K(left_type)); } else if (OB_FAIL((reinterpret_cast(get_int_func0)(*left, false, left_int, cast_mode)))) { LOG_WARN("get uint64 failed", K(ret), K(*left)); } else if (OB_FAIL(choose_get_int_func(right_type, get_int_func1))) { LOG_WARN("choose_get_int_func failed", K(ret), K(right_type)); } else if (OB_FAIL((reinterpret_cast(get_int_func1)(*right, false, right_int, cast_mode)))) { LOG_WARN("get uint64 failed", K(ret), K(*right)); } else if (OB_FAIL(result.from((left_int & right_int), tmp_alloc))) { LOG_WARN("get ObNumber from int64 failed", K(ret), K(left_int & right_int)); } else { res_datum.set_number(result); } } return ret; } // for static typing engine int ObBitwiseExprOperator::cg_bitwise_expr( ObExprCGCtx& expr_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr, const BitOperator op) { int ret = OB_SUCCESS; UNUSED(raw_expr); // bit count, bit neg: 1 == arg_cnt_ // bit and/or/xor/left shift/right shift: 2 == arg_cnt_ if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(expr_cg_ctx.allocator_) || OB_UNLIKELY(1 != rt_expr.arg_cnt_ && 2 != rt_expr.arg_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("args_ is NULL or arg_cnt_ is invalid", K(ret), K(rt_expr)); } else { rt_expr.extra_ = static_cast(op); if (2 == rt_expr.arg_cnt_) { if (lib::is_oracle_mode()) { rt_expr.eval_func_ = ObBitwiseExprOperator::calc_result2_oracle; } else { rt_expr.eval_func_ = ObBitwiseExprOperator::calc_result2_mysql; } } else { // must be set in its cg_expr method rt_expr.eval_func_ = NULL; } } return ret; } int ObBitwiseExprOperator::choose_get_int_func(const ObObjType type, void*& out_func) { int ret = OB_SUCCESS; if (ObNumberTC == ob_obj_type_class(type)) { if (lib::is_oracle_mode()) { out_func = reinterpret_cast(ObBitwiseExprOperator::get_int64_from_number_type); } else { out_func = reinterpret_cast(ObBitwiseExprOperator::get_uint64_from_number_type); } } else { if (lib::is_oracle_mode()) { out_func = reinterpret_cast(ObBitwiseExprOperator::get_int64_from_int_tc); } else { out_func = reinterpret_cast(ObBitwiseExprOperator::get_uint64_from_int_tc); } } return ret; } int ObBitwiseExprOperator::get_int64_from_int_tc( const ObDatum& datum, bool is_round, int64_t& out, const ObCastMode& cast_mode) { int ret = OB_SUCCESS; UNUSED(is_round); UNUSED(cast_mode); out = datum.get_int(); return ret; } int ObBitwiseExprOperator::get_uint64_from_int_tc( const ObDatum& datum, bool is_round, uint64_t& out, const ObCastMode& cast_mode) { int ret = OB_SUCCESS; UNUSED(is_round); UNUSED(cast_mode); out = datum.get_uint(); return ret; } int ObBitwiseExprOperator::get_int64_from_number_type( const ObDatum& datum, bool is_round, int64_t& out, const ObCastMode& cast_mode) { int ret = OB_SUCCESS; int64_t tmp_int = 0; number::ObNumber nmb(datum.get_number()); if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) { LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb)); } else if (nmb.is_valid_int64(tmp_int)) { out = tmp_int; } else { ret = OB_ERR_TRUNCATED_WRONG_VALUE; if (CM_IS_WARN_ON_FAIL(cast_mode)) { ret = OB_SUCCESS; out = 0; } } return ret; } int ObBitwiseExprOperator::get_uint64_from_number_type( const ObDatum& datum, bool is_round, uint64_t& out, const ObCastMode& cast_mode) { int ret = OB_SUCCESS; number::ObNumber nmb(datum.get_number()); int64_t tmp_int = 0; uint64_t tmp_uint = 0; if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) { LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb)); } else if (nmb.is_valid_int64(tmp_int)) { out = static_cast(tmp_int); } else if (nmb.is_valid_uint64(tmp_uint)) { out = tmp_uint; } else { ret = OB_ERR_TRUNCATED_WRONG_VALUE; if (CM_IS_WARN_ON_FAIL(cast_mode)) { ret = OB_SUCCESS; out = 0; } } return ret; } int ObBitwiseExprOperator::get_int64(const ObObj& obj, ObExprCtx& expr_ctx, bool is_round, int64_t& out) { int ret = OB_SUCCESS; out = 0; ObObjType type = obj.get_type(); if (OB_LIKELY(ob_is_int_tc(type))) { out = obj.get_int(); } else if (OB_UNLIKELY(obj.is_number())) { int64_t tmp_int = 0; number::ObNumber nmb; EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); if (OB_FAIL(nmb.from(obj.get_number(), cast_ctx))) { LOG_WARN("deep copy failed", K(ret), K(is_round), K(obj)); } else if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) { LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb)); } else if (nmb.is_valid_int64(tmp_int)) { out = tmp_int; } else { ret = OB_ERR_TRUNCATED_WRONG_VALUE; if (CM_IS_WARN_ON_FAIL(cast_ctx.cast_mode_)) { ret = OB_SUCCESS; out = 0; } } } else { EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); EXPR_GET_INT64_V2(obj, out); } return ret; } int ObBitwiseExprOperator::get_uint64(const ObObj& obj, ObExprCtx& expr_ctx, bool is_round, uint64_t& out) { int ret = OB_SUCCESS; out = 0; ObObjType type = obj.get_type(); if (OB_LIKELY(ob_is_int_tc(type))) { out = static_cast(obj.get_int()); } else if (ob_is_uint_tc(type)) { out = obj.get_uint64(); } else if (OB_UNLIKELY(obj.is_number())) { uint64_t tmp_uint = 0; number::ObNumber value = obj.get_number(); if (OB_LIKELY(value.is_valid_uint64(tmp_uint))) { out = tmp_uint; } else { int64_t tmp_int = 0; number::ObNumber nmb; EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); if (OB_FAIL(nmb.from(value, cast_ctx))) { LOG_WARN("deep copy failed", K(ret), K(is_round), K(obj)); } else if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) { LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb)); } else if (nmb.is_valid_int64(tmp_int)) { out = static_cast(tmp_int); } else if (nmb.is_valid_uint64(tmp_uint)) { out = tmp_uint; } else { ret = OB_ERR_TRUNCATED_WRONG_VALUE; if (CM_IS_WARN_ON_FAIL(cast_ctx.cast_mode_)) { ret = OB_SUCCESS; out = 0; } } } } else { // need add CM_NO_RANGE_CHECK, otherwise 1 & -3.5(float) return 0. EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NO_RANGE_CHECK); EXPR_GET_UINT64_V2(obj, out); } return ret; } int ObMinMaxExprOperator::assign(const ObExprOperator& other) { int ret = OB_SUCCESS; const ObMinMaxExprOperator* tmp_other = dynamic_cast(&other); if (OB_UNLIKELY(NULL == tmp_other)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument. wrong type for other", K(ret), K(other)); } else if (OB_LIKELY(this != tmp_other)) { if (OB_FAIL(ObExprOperator::assign(other))) { LOG_WARN("copy in Base class ObExprOperator failed", K(ret)); } else { this->need_cast_ = tmp_other->need_cast_; } } return ret; } int ObMinMaxExprOperator::aggregate_result_type_for_comparison( ObExprResType& type, const ObExprResType* types, int64_t param_num) const { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else { ObObjType res_type = types[0].get_type(); ObScale max_scale = types[0].get_scale(); for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (OB_FAIL(ObExprResultTypeUtil::get_relational_result_type(res_type, res_type, types[i].get_type()))) { // warn } else if (OB_UNLIKELY(ObMaxType == res_type)) { ret = OB_INVALID_ARGUMENT; // not compatible input } else if (!ob_is_string_or_lob_type(types[i].get_type()) && types[i].get_scale() > max_scale) { max_scale = types[i].get_scale(); } } if (OB_SUCC(ret)) { type.set_type(res_type); type.set_scale(max_scale); } } return ret; } int ObMinMaxExprOperator::aggregate_cmp_type_for_comparison( ObExprResType& type, const ObExprResType* types, int64_t param_num) const { int ret = OB_SUCCESS; if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret)); } else { ObObjType cmp_type = types[0].get_type(); for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (OB_FAIL(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type, cmp_type, types[i].get_type()))) { // warn } else if (OB_UNLIKELY(ObMaxType == cmp_type)) { ret = OB_INVALID_ARGUMENT; // not compatible input } } if (OB_SUCC(ret)) { type.set_calc_type(cmp_type); } } return ret; } int ObMinMaxExprOperator::calc_result_meta_for_comparison(ObExprResType& type, ObExprResType* types_stack, int64_t param_num, const ObCollationType coll_type, const ObLengthSemantics default_length_semantics) const { UNUSED(default_length_semantics); int ret = OB_SUCCESS; int64_t i = 0; int64_t byte_semantics_str_num = 0; int64_t char_semantics_str_num = 0; // bool all_string = true; if (OB_ISNULL(types_stack) || OB_UNLIKELY(param_num < 1)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stack is null or param_num is wrong", K(types_stack), K(param_num), K(ret)); } // result_type if (OB_SUCC(ret)) { ret = aggregate_result_type_for_comparison(type, types_stack, param_num); } if (OB_SUCC(ret)) { ret = aggregate_cmp_type_for_comparison(type, types_stack, param_num); } bool string_result = ob_is_string_or_enumset_type(type.get_type()) || ob_is_text_tc(type.get_type()); bool string_cmp = ob_is_string_or_enumset_type(type.get_calc_type()) || ob_is_text_tc(type.get_calc_type()); // compare collation if (OB_SUCC(ret) && string_cmp) { ret = aggregate_charsets_for_comparison(type, types_stack, param_num, coll_type); } // result collation if (OB_SUCC(ret) && string_result) { ret = aggregate_charsets_for_string_result(type, types_stack, param_num, coll_type); } if (OB_SUCC(ret)) { if (string_result) { int64_t max_length = 0; for (i = 0; i < param_num; ++i) { max_length = MAX(max_length, types_stack[i].get_length()); } type.set_length(static_cast(max_length)); } else { int64_t max_scale = 0; int64_t max_precision = 0; for (i = 0; i < param_num; ++i) { max_scale = MAX(max_scale, types_stack[i].get_mysql_compatible_scale()); max_precision = MAX(max_precision, types_stack[i].get_precision()); } ObScale result_scale = static_cast(NOT_FIXED_DEC == max_scale ? -1 : max_scale); const int64_t int32_max_precision = 11; if (result_scale > 0 && ob_is_int_tc(type.get_type())) { type.set_type(ObNumberType); } else if (max_precision > int32_max_precision && ObInt32Type == type.get_type()) { type.set_type(ObIntType); } type.set_scale(result_scale); type.set_precision(static_cast(max_precision + max_scale)); // esti, not accurate } } if (OB_SUCC(ret)) { ObObjType dest_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[type.get_calc_type()]]; if (OB_UNLIKELY(ObMaxType == dest_type)) { ret = OB_ERR_UNEXPECTED; SQL_ENG_LOG(WARN, "invalid type", K(type), K(ret)); } else if (ObVarcharType == dest_type) { for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { if (ob_is_enumset_tc(types_stack[i].get_type())) { types_stack[i].set_calc_type(dest_type); } } } else { /*do nothing*/ } } return ret; } int ObMinMaxExprOperator::calc_(ObObj& result, const ObObj* objs_stack, int64_t param_num, const ObExprResType& result_type, ObExprCtx& expr_ctx, ObCmpOp cmp_op, bool need_cast) { // todo: // we assume that result type / result collation / compare type / compare collation are CORRECT. // but who knowns? we should check it ASAP. int ret = OB_SUCCESS; if (OB_UNLIKELY(need_cast)) { ret = calc_with_cast(result, objs_stack, param_num, result_type, expr_ctx, cmp_op); } else { ret = calc_without_cast(result, objs_stack, param_num, result_type, expr_ctx, cmp_op); } return ret; } int ObMinMaxExprOperator::calc_without_cast(ObObj& result, const ObObj* objs_stack, int64_t param_num, const ObExprResType& result_type, ObExprCtx& expr_ctx, ObCmpOp cmp_op) { int ret = OB_SUCCESS; if (OB_UNLIKELY(CO_LT != cmp_op && CO_GT != cmp_op)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("the compare oper is wrong", K(ret), K(cmp_op)); } else if (OB_ISNULL(objs_stack) || OB_ISNULL(expr_ctx.calc_buf_) || OB_UNLIKELY(param_num < 1) || OB_UNLIKELY(result_type.is_invalid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stack is null or param_num is wrong", K(objs_stack), K(param_num), K(result_type), K(ret)); } else { bool has_null = false; for (int i = 0; OB_SUCC(ret) && !has_null && i < param_num; ++i) { if (objs_stack[i].is_null()) { has_null = true; result.set_null(); } } if (!has_null) { // compare all params. int res_idx = 0; ObCollationType cmp_cs_type = result_type.get_calc_collation_type(); for (int i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (ObObjCmpFuncs::compare_oper_nullsafe(objs_stack[i], objs_stack[res_idx], cmp_cs_type, cmp_op)) { res_idx = i; } } // ok, we got the least / greatest param. if (OB_SUCC(ret)) { if (OB_LIKELY(result_type.get_type() == objs_stack[res_idx].get_type() && result_type.get_collation_type() == objs_stack[res_idx].get_collation_type())) { result = objs_stack[res_idx]; } else { // slow path EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); if (OB_FAIL(ObObjCaster::to_type( result_type.get_type(), result_type.get_collation_type(), cast_ctx, objs_stack[res_idx], result))) {} } } } } return ret; } int ObMinMaxExprOperator::calc_with_cast(ObObj& result, const ObObj* objs_stack, int64_t param_num, const ObExprResType& result_type, ObExprCtx& expr_ctx, ObCmpOp cmp_op) { int ret = OB_SUCCESS; if (OB_UNLIKELY(CO_LT != cmp_op && CO_GT != cmp_op)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("the compare oper is wrong", K(ret), K(cmp_op)); } else if (OB_ISNULL(objs_stack) || OB_ISNULL(expr_ctx.calc_buf_) || OB_UNLIKELY(param_num < 1) || OB_UNLIKELY(result_type.is_invalid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stack is null or param_num is wrong", K(objs_stack), K(param_num), K(result_type), K(ret)); } else { EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); if (ob_is_nstring_type(result_type.get_calc_type())) { cast_ctx.dest_collation_ = expr_ctx.my_session_->get_nls_collation_nation(); } else if (share::is_mysql_mode() && CS_TYPE_INVALID != result_type.get_collation_type()) { cast_ctx.dest_collation_ = result_type.get_collation_type(); } ObFixedArray buf_obj(expr_ctx.calc_buf_, param_num); ObFixedArray res_obj(expr_ctx.calc_buf_, param_num); // inited in the for loop below. if (OB_FAIL(buf_obj.prepare_allocate(param_num))) { LOG_WARN("prepare allocate failed", K(param_num), K(ret)); } else if (OB_FAIL(res_obj.prepare_allocate(param_num))) { LOG_WARN("prepare allocate failed", K(param_num), K(ret)); } // ret status will be checked within OB_SUCC(ret)s bool has_null = false; // cast all params to cmp type, and check if exist null. for (int i = 0; OB_SUCC(ret) && !has_null && i < param_num; ++i) { res_obj[i] = NULL; if (objs_stack[i].is_null()) { has_null = true; result.set_null(); } else if (OB_FAIL(ObObjCaster::to_type( result_type.get_calc_type(), cast_ctx, objs_stack[i], buf_obj[i], res_obj[i]))) { } else if (OB_ISNULL(res_obj[i])) { ret = OB_ERR_UNEXPECTED; } } if (OB_SUCC(ret) && !has_null) { // compare all params. int res_idx = 0; ObCollationType cmp_cs_type = result_type.get_calc_collation_type(); for (int i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (ObObjCmpFuncs::compare_oper_nullsafe(*res_obj[i], *res_obj[res_idx], cmp_cs_type, cmp_op)) { res_idx = i; } } // ok, we got the least / greatest param. if (OB_SUCC(ret)) { if (OB_FAIL(ObObjCaster::to_type( result_type.get_type(), result_type.get_collation_type(), cast_ctx, *res_obj[res_idx], result))) {} } } } return ret; } int ObArithExprOperator::interval_add_minus( ObObj& res, const ObObj& left, const ObObj& right, ObExprCtx& expr_ctx, ObScale scale, bool is_minus) { int ret = OB_SUCCESS; if (OB_UNLIKELY(ObIntervalTC != right.get_type_class())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else { switch (left.get_type_class()) { case ObIntervalTC: { // interval + interval if (OB_UNLIKELY(left.get_type() != right.get_type())) { ret = OB_ERR_INVALID_TYPE_FOR_OP; // ORA-30081: invalid data type for datetime/interval arithmetic LOG_WARN("invalid data type interval arithmetic"); } else if (left.is_interval_ym()) { ObIntervalYMValue value = is_minus ? left.get_interval_ym() - right.get_interval_ym() : left.get_interval_ym() + right.get_interval_ym(); if (OB_FAIL(value.validate())) { LOG_WARN("value validate failed", K(ret), K(value)); } else { res.set_interval_ym(value); res.set_scale(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][ObIntervalYMType].get_scale()); } LOG_DEBUG("add interval year to month result", K(value), K(res)); } else { ObIntervalDSValue value = is_minus ? left.get_interval_ds() - right.get_interval_ds() : left.get_interval_ds() + right.get_interval_ds(); if (OB_FAIL(value.validate())) { LOG_WARN("value validate failed", K(ret), K(value)); } else { res.set_interval_ds(value); res.set_scale(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][ObIntervalDSType].get_scale()); } LOG_DEBUG("add interval day to second result", K(value), K(res)); } break; } case ObDateTimeTC: { // date +- interval int64_t date_v = left.get_datetime(); int64_t result_v = 0; int64_t sign = is_minus ? -1 : 1; if (OB_FAIL(right.is_interval_ym() ? ObTimeConverter::date_add_nmonth( date_v, right.get_interval_ym().get_nmonth() * sign, result_v) : ObTimeConverter::date_add_nsecond(date_v, right.get_interval_ds().get_nsecond() * sign, right.get_interval_ds().get_fs() * sign, result_v))) { LOG_WARN("add value failed", K(ret), K(left), K(right)); } else { res.set_datetime(result_v); res.set_scale(0); } break; } case ObOTimestampTC: { // timestamp +- interval ObOTimestampData result_v; int32_t sign = is_minus ? -1 : 1; if (OB_FAIL(right.is_interval_ym() ? ObTimeConverter::otimestamp_add_nmonth(left.get_type(), left.get_otimestamp_value(), get_timezone_info(expr_ctx.my_session_), right.get_interval_ym().get_nmonth() * sign, result_v) : ObTimeConverter::otimestamp_add_nsecond(left.get_otimestamp_value(), right.get_interval_ds().get_nsecond() * sign, right.get_interval_ds().get_fs() * sign, result_v))) { LOG_WARN("calc with timestamp value failed", K(ret), K(left), K(right)); } else { res.set_otimestamp_value(left.get_type(), result_v); res.set_scale(MAX_SCALE_FOR_ORACLE_TEMPORAL); } break; } case ObNullTC: { res.set_null(); break; } default: { ret = OB_ERR_INVALID_TYPE_FOR_OP; // ORA-30081: invalid data type for datetime/interval arithmetic LOG_WARN("invalid calc type", K(ret)); } } } LOG_DEBUG("add interval", K(left), K(right), K(scale), K(res)); UNUSED(scale); return ret; } int ObMinMaxExprOperator::deserialize(const char* buf, const int64_t data_len, int64_t& pos) { int ret = OB_SUCCESS; need_cast_ = true; // defensive code if (OB_FAIL(ObExprOperator::deserialize(buf, data_len, pos))) { LOG_WARN("deserialize in BASE class failed", K(ret)); } else { OB_UNIS_DECODE(need_cast_); } return ret; } int ObMinMaxExprOperator::serialize(char* buf, const int64_t buf_len, int64_t& pos) const { int ret = OB_SUCCESS; if (OB_FAIL(ObExprOperator::serialize(buf, buf_len, pos))) { LOG_WARN("serialize in BASE class failed", K(ret)); } else { OB_UNIS_ENCODE(need_cast_); } return ret; } int64_t ObMinMaxExprOperator::get_serialize_size() const { int64_t len = 0; BASE_ADD_LEN((ObMinMaxExprOperator, ObExprOperator)); OB_UNIS_ADD_LEN(need_cast_); return len; } // ObLocationExprOperator int ObLocationExprOperator::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; ObExprOperator::calc_result_flag2(type, type1, type2); type.set_int(); type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].precision_); type.set_scale(DEFAULT_SCALE_FOR_INTEGER); type1.set_calc_type(ObVarcharType); type2.set_calc_type(ObVarcharType); type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC); ObObjMeta types[2] = {type1, type2}; OZ(aggregate_charsets_for_comparison(type.get_calc_meta(), types, 2, type_ctx.get_coll_type())); OX(type1.set_calc_collation_type(type.get_calc_collation_type())); OX(type2.set_calc_collation_type(type.get_calc_collation_type())); return ret; } int ObLocationExprOperator::calc_result2( common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2, common::ObExprCtx& expr_ctx) const { ObObj position; position.set_int(1); return ObLocationExprOperator::calc_result3(result, obj1, obj2, position, expr_ctx); } int ObLocationExprOperator::calc_result3(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2, const common::ObObj& obj3, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("the pointer is null", K(expr_ctx.calc_buf_), K(ret)); } else if (OB_UNLIKELY(obj1.is_null() || obj2.is_null())) { result.set_null(); } else if (obj3.is_null()) { result.set_int(0); } else if (OB_UNLIKELY(!is_type_valid(obj1.get_type()) || !is_type_valid(obj2.get_type()) || !is_type_valid(obj3.get_type()))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("the param is not castable", K(obj1), K(obj2), K(obj3), K(ret)); } else { int64_t pos = 0; ret = get_pos_int64(obj3, expr_ctx, pos); if (OB_SUCC(ret)) { TYPE_CHECK(obj1, ObVarcharType); TYPE_CHECK(obj2, ObVarcharType); ObString str1 = obj1.get_string(); ObString str2 = obj2.get_string(); uint32_t idx = ObCharset::locate( result_type_.get_calc_collation_type(), str2.ptr(), str2.length(), str1.ptr(), str1.length(), pos); result.set_int(static_cast(idx)); } } return ret; } int ObLocationExprOperator::get_pos_int64(const ObObj& obj, ObExprCtx& expr_ctx, int64_t& out) { int ret = OB_SUCCESS; out = 0; ObObjType type = obj.get_type(); if (OB_LIKELY(ob_is_int_tc(type))) { out = obj.get_int(); } else if (ob_is_uint_tc(type)) { uint64_t value = obj.get_uint64(); out = (value > INT64_MAX) ? 0 : static_cast(value); } else if (OB_UNLIKELY(obj.is_number())) { int64_t tmp_int = 0; uint64_t tmp_uint = 0; number::ObNumber nmb = obj.get_number(); number::ObNumber* pnmb = &nmb; number::ObNumber newmb; if (OB_UNLIKELY(!nmb.is_integer())) { // such as select locate('bar', 'foobarbar', 5.3); yeah, really ugly. EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); if (OB_FAIL(newmb.from(nmb, cast_ctx))) { // copy is essential since if we did not do that, obj will be modified LOG_WARN("copy nmb failed", K(ret), K(nmb)); } else if (OB_FAIL(newmb.round(0))) { LOG_WARN("round failed", K(ret), K(nmb)); } else { pnmb = &newmb; } } if (OB_FAIL(ret)) { // do nothing } else if (OB_ISNULL(pnmb)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected error. null pointer", K(ret)); } else if (pnmb->is_valid_int64(tmp_int)) { out = tmp_int; } else if (pnmb->is_valid_uint64(tmp_uint)) { out = 0; // no errors no warnings in mysql. } else { ret = OB_ERR_TRUNCATED_WRONG_VALUE; if (CM_IS_WARN_ON_FAIL(expr_ctx.cast_mode_)) { ret = OB_SUCCESS; out = 0; } } } else { EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE); EXPR_GET_INT64_V2(obj, out); } return ret; } int ObLocationExprOperator::get_calc_cs_type(const ObExpr& expr, ObCollationType& calc_cs_type) { int ret = OB_SUCCESS; const ObCollationType cs_type1 = expr.args_[0]->datum_meta_.cs_type_; const ObCollationType cs_type2 = expr.args_[1]->datum_meta_.cs_type_; if (OB_UNLIKELY(cs_type1 != cs_type2)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cs type should be same", K(ret), K(cs_type1), K(cs_type2)); } else if (OB_UNLIKELY(!ObCharset::is_valid_collation(static_cast(cs_type1)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid cs_type", K(ret), K(cs_type1)); } else { calc_cs_type = cs_type1; } return ret; } int ObLocationExprOperator::calc_location_expr(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum) { int ret = OB_SUCCESS; // locate(sub, ori, pos) if (OB_UNLIKELY(2 > expr.arg_cnt_ || 3 < expr.arg_cnt_) || OB_ISNULL(expr.args_) || OB_ISNULL(expr.args_[0]) || OB_ISNULL(expr.args_[1])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid expr", K(ret), K(expr)); } else if (OB_FAIL(calc_(expr, *expr.args_[0], *expr.args_[1], ctx, res_datum))) { LOG_WARN("calc_ faied", K(ret)); } return ret; } int ObLocationExprOperator::calc_( const ObExpr& expr, const ObExpr& sub_arg, const ObExpr& ori_arg, ObEvalCtx& ctx, ObDatum& res_datum) { int ret = OB_SUCCESS; ObDatum* sub = NULL; ObDatum* ori = NULL; ObDatum* pos = NULL; bool has_result = false; if (OB_FAIL(sub_arg.eval(ctx, sub)) || OB_FAIL(ori_arg.eval(ctx, ori))) { LOG_WARN("eval arg failed", K(ret)); } else if (sub->is_null() || ori->is_null()) { res_datum.set_null(); has_result = true; } int64_t pos_int = 1; if (OB_SUCC(ret) && !has_result && 3 == expr.arg_cnt_) { if (OB_FAIL(expr.args_[2]->eval(ctx, pos))) { LOG_WARN("eval arg 2 failed", K(ret)); } else if (pos->is_null()) { res_datum.set_int(0); has_result = true; } else { pos_int = pos->get_int(); } } if (OB_SUCC(ret) && !has_result) { const ObString& ori_str = ori->get_string(); const ObString& sub_str = sub->get_string(); ObCollationType calc_cs_type = CS_TYPE_INVALID; if (OB_FAIL(get_calc_cs_type(expr, calc_cs_type))) { LOG_WARN("get_calc_cs_type failed", K(ret)); } else { uint32_t idx = ObCharset::locate(calc_cs_type, ori_str.ptr(), ori_str.length(), sub_str.ptr(), sub_str.length(), pos_int); res_datum.set_int(static_cast(idx)); } } return ret; } int ObLocationExprOperator::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); rt_expr.eval_func_ = calc_location_expr; return OB_SUCCESS; } int ObExprTRDateFormat::calc_hash(const char* p, int64_t len, uint64_t& hash) { int ret = OB_SUCCESS; hash = 0; if (OB_ISNULL(p) || OB_UNLIKELY(len <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("unexpected error.invalid arguments", K(p), K(len)); } else { for (int64_t i = 0; i < len; ++i) { hash = (hash << 7) + (hash << 1) + hash + toupper(p[i]); } } return ret; } int ObExprTRDateFormat::init() { int ret = OB_SUCCESS; for (int64_t i = 0; i < FORMAT_MAX_TYPE && OB_SUCC(ret); ++i) { ret = calc_hash(FORMATS_TEXT[i], strlen(FORMATS_TEXT[i]), FORMATS_HASH[i]); // validation for (int64_t j = 0; j < i && OB_SUCC(ret); ++j) { if (FORMATS_HASH[i] == FORMATS_HASH[j]) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("unexpected error.hash func is not perfect hash", K(i), K(j)); break; } } } return ret; } int ObExprTRDateFormat::trunc_new_obtime(ObTime& ob_time, const ObString& fmt) { int ret = OB_SUCCESS; if (OB_UNLIKELY(fmt.empty())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("empty string.", K(ret), K(fmt)); } else { int64_t fmt_id = SYYYY; const char* ptr = fmt.ptr(); int32_t ptr_len = fmt.length(); uint64_t fmt_hash = 0; if (OB_FAIL(calc_hash(ptr, ptr_len, fmt_hash))) { LOG_WARN("calc hash failed", K(ret), K(fmt)); } else if (FALSE_IT(get_format_id(fmt_hash, fmt_id))) { } else if (OB_UNLIKELY(fmt_id < 0 || fmt_id >= FORMAT_MAX_TYPE)) { ret = OB_INVALID_DATE_FORMAT; LOG_WARN("invalid format string", K(ret), K(fmt_id), K(fmt)); } else if (OB_UNLIKELY(strncasecmp(ptr, FORMATS_TEXT[fmt_id], ptr_len))) { // what a pity ! same hash value, while not expected content ret = OB_INVALID_DATE_FORMAT; LOG_WARN("invalid format string", K(ret), K(fmt_id), K(fmt)); } else { switch (fmt_id) { case SYYYY: // go through case YYYY: // go through case YEAR: case SYEAR: // go through case YYY: // go through case YY: // go through case Y: { set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_YDAY] - 1); ob_time.parts_[DT_DATE] -= offset; break; } case Q: { set_time_part_to_zero(ob_time); int32_t quarter = (ob_time.parts_[DT_MON] + 2) / MONS_PER_QUAR; ob_time.parts_[DT_MON] = (quarter - 1) * MONS_PER_QUAR + 1; ob_time.parts_[DT_MDAY] = 1; ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time); break; } case MONTH: // go through case MON: // go through case MM: // go through case RM: { set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_MDAY] - 1); ob_time.parts_[DT_DATE] -= offset; break; } case WW: { // 01-01 is the first day of year set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] -= offset; break; } case IW: { // within a week. monday is the first day set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] -= offset; break; } case W: { // xx-01 is the first day set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] -= offset; break; } case DDD: // go through case DD: // go through case J: { set_time_part_to_zero(ob_time); break; } case DAY: // go through case DY: // go through case D: { // within a week. sunday is the first day set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_WDAY]) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] -= offset; break; } case HH: // go through case HH12: // go through case HH24: { ob_time.parts_[DT_MIN] = 0; ob_time.parts_[DT_SEC] = 0; ob_time.parts_[DT_USEC] = 0; break; } case MI: { ob_time.parts_[DT_SEC] = 0; ob_time.parts_[DT_USEC] = 0; break; } case CC: // go through case SCC: { set_time_part_to_zero(ob_time); ob_time.parts_[DT_YEAR] = ob_time.parts_[DT_YEAR] / YEARS_PER_CENTURY * YEARS_PER_CENTURY + 1; ob_time.parts_[DT_MON] = 1; ob_time.parts_[DT_MDAY] = 1; ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time); break; } case IYYY: // go through case IY: // go through case I: { // not used heavily. so, do not care too much about performance ! set_time_part_to_zero(ob_time); ObTimeConverter::get_first_day_of_isoyear(ob_time); break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected fmt_id", K(fmt_id), K(ret), K(fmt)); } } // end switch } } return ret; } int ObExprTRDateFormat::round_new_obtime(ObTime& ob_time, const ObString& fmt) { int ret = OB_SUCCESS; if (OB_UNLIKELY(fmt.empty())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("empty string.", K(ret), K(fmt)); } else { int64_t fmt_id = SYYYY; const char* ptr = fmt.ptr(); int32_t ptr_len = fmt.length(); uint64_t fmt_hash = 0; if (OB_FAIL(calc_hash(ptr, ptr_len, fmt_hash))) { LOG_WARN("calc hash failed", K(ret), K(fmt)); } else if (FALSE_IT(get_format_id(fmt_hash, fmt_id))) { } else if (OB_UNLIKELY(fmt_id < 0 || fmt_id >= FORMAT_MAX_TYPE)) { ret = OB_INVALID_DATE_FORMAT; LOG_WARN("invalid format string", K(ret), K(fmt_id), K(fmt)); } else if (OB_UNLIKELY(strncasecmp(ptr, FORMATS_TEXT[fmt_id], ptr_len))) { // what a pity ! same hash value, while not expected content ret = OB_INVALID_DATE_FORMAT; LOG_WARN("invalid format string", K(ret), K(fmt_id), K(fmt)); } else { LOG_DEBUG("check value", K(ob_time), K(fmt_id), K(fmt)); switch (fmt_id) { case SYYYY: // go through case YYYY: // go through case YEAR: case SYEAR: // go through case YYY: // go through case YY: // go through case Y: { //>6 const int32_t add_year = (ob_time.parts_[DT_MON] > DT_PART_MAX[DT_MON] / 2) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_YDAY] - 1); ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_year * DAYS_PER_YEAR[IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])]; break; } case Q: { //>15 const int32_t add_quarter = (((ob_time.parts_[DT_MON] - 1) % MONS_PER_QUAR > 1) || (1 == (ob_time.parts_[DT_MON] - 1) % MONS_PER_QUAR && ob_time.parts_[DT_MDAY] > DT_PART_MAX[DT_MDAY] / 2)) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t quarter = (ob_time.parts_[DT_MON] + 2) / MONS_PER_QUAR + add_quarter; ob_time.parts_[DT_MON] = (quarter - 1) * MONS_PER_QUAR + 1; if (ob_time.parts_[DT_MON] > DT_PART_MAX[DT_MON]) { ob_time.parts_[DT_MON] -= static_cast(DT_PART_MAX[DT_MON]); ob_time.parts_[DT_YEAR] += 1; } ob_time.parts_[DT_MDAY] = 1; ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time); break; } case MONTH: // go through case MON: // go through case MM: // go through case RM: { //>15 const int32_t add_month = (ob_time.parts_[DT_MDAY] > DT_PART_MAX[DT_MDAY] / 2) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_MDAY] - 1); ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_month * DAYS_PER_MON[IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])][ob_time.parts_[DT_MON]]; break; } case WW: { // 01-01 is the first day of year const int32_t add_ww = ((((ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2) || (((ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2 && ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2)) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_ww * DAYS_PER_WEEK; break; } case IW: { // within a week. monday is the first day const int32_t add_iw = ((((ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2) || (((ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2 && ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2)) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_iw * DAYS_PER_WEEK; break; } case W: { // xx-01 is the first day const int32_t add_w = ((((ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2) || (((ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2 && ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2)) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_w * DAYS_PER_WEEK; break; } case DDD: // go through case DD: // go through case J: { const int32_t add_d = (ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2) ? 1 : 0; set_time_part_to_zero(ob_time); ob_time.parts_[DT_DATE] += add_d; break; } case DAY: // go through case DY: // go through case D: { // within a week. sunday is the first day const int32_t add_dy = (((ob_time.parts_[DT_WDAY] % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2) || ((ob_time.parts_[DT_WDAY] % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2 && ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2)) ? 1 : 0; set_time_part_to_zero(ob_time); int32_t offset = (ob_time.parts_[DT_WDAY]) % DAYS_PER_WEEK; ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_dy * DAYS_PER_WEEK; break; } case HH: // go through case HH12: // go through case HH24: { const int32_t add_dh = (ob_time.parts_[DT_MIN] > DT_PART_MAX[DT_MIN] / 2) ? 1 : 0; ob_time.parts_[DT_MIN] = 0; ob_time.parts_[DT_SEC] = 0; ob_time.parts_[DT_USEC] = 0; ob_time.parts_[DT_HOUR] += add_dh; if (ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR]) { ob_time.parts_[DT_HOUR] -= static_cast(DT_PART_MAX[DT_HOUR]); ob_time.parts_[DT_DATE] += 1; } break; } case MI: { const int32_t add_mi = (ob_time.parts_[DT_SEC] >= DT_PART_MAX[DT_SEC] / 2) ? 1 : 0; ob_time.parts_[DT_SEC] = 0; ob_time.parts_[DT_USEC] = 0; ob_time.parts_[DT_MIN] += add_mi; if (ob_time.parts_[DT_MIN] > DT_PART_MAX[DT_MIN]) { ob_time.parts_[DT_MIN] -= static_cast(DT_PART_MAX[DT_MIN]); ob_time.parts_[DT_HOUR] += 1; if (ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR]) { ob_time.parts_[DT_HOUR] -= static_cast(DT_PART_MAX[DT_HOUR]); ob_time.parts_[DT_DATE] += 1; } } break; } case CC: // go through case SCC: { const int32_t add_cc = (ob_time.parts_[DT_YEAR] % YEARS_PER_CENTURY > YEARS_PER_CENTURY / 2) ? 1 : 0; set_time_part_to_zero(ob_time); ob_time.parts_[DT_YEAR] = ob_time.parts_[DT_YEAR] / YEARS_PER_CENTURY * YEARS_PER_CENTURY + 1 + add_cc * YEARS_PER_CENTURY; ob_time.parts_[DT_MON] = 1; ob_time.parts_[DT_MDAY] = 1; ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time); break; } case IYYY: // go through case IY: // go through case I: { // not used heavily. so, do not care too much about performance ! set_time_part_to_zero(ob_time); ret = ObTimeConverter::get_round_day_of_isoyear(ob_time); break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected fmt_id", K(fmt_id), K(ret), K(fmt)); } } // end switch } } return ret; } int ObRelationalExprOperator::is_row_cmp(const ObRawExpr& raw_expr, int& row_dim) { int ret = OB_SUCCESS; row_dim = -1; if (OB_UNLIKELY(2 != raw_expr.get_param_count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid param count", K(ret), K(raw_expr.get_param_count())); } else if (T_OP_ROW == raw_expr.get_param_expr(0)->get_expr_type() && T_OP_ROW == raw_expr.get_param_expr(1)->get_expr_type()) { if (raw_expr.get_param_expr(0)->get_param_count() != raw_expr.get_param_expr(1)->get_param_count()) { if (1 == raw_expr.get_param_expr(1)->get_param_count() && T_OP_ROW == raw_expr.get_param_expr(1)->get_param_expr(0)->get_expr_type()) { // (c1, c2) = (c1, c2), (c1, c2) = ((c1, c2)) are both allowed in oralce mode if (raw_expr.get_param_expr(0)->get_param_count() == raw_expr.get_param_expr(1)->get_param_expr(0)->get_param_count()) { row_dim = raw_expr.get_param_expr(0)->get_param_count(); } } } else { row_dim = raw_expr.get_param_expr(0)->get_param_count(); } if (OB_UNLIKELY(-1 == row_dim)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param cnt", K(raw_expr.get_param_expr(0)->get_param_count()), K(raw_expr.get_param_expr(1)->get_param_count()), K(raw_expr.get_param_expr(1)->get_expr_type())); } } return ret; } int ObRelationalExprOperator::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { int ret = OB_SUCCESS; int row_dim = -1; if (OB_FAIL(is_row_cmp(raw_expr, row_dim))) { LOG_WARN("failed to get row dimension", K(ret)); } else if (OB_ISNULL(op_cg_ctx.allocator_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null allocator", K(ret), K(op_cg_ctx.allocator_)); } else if (row_dim > 0) { ret = cg_row_cmp_expr(row_dim, *op_cg_ctx.allocator_, raw_expr, input_types_, rt_expr); } else { ret = cg_datum_cmp_expr(raw_expr, input_types_, rt_expr); } return ret; } int ObRelationalExprOperator::cg_datum_cmp_expr( const ObRawExpr& raw_expr, const ObExprOperatorInputTypeArray& input_types, ObExpr& rt_expr) { int ret = OB_SUCCESS; UNUSED(raw_expr); if (OB_UNLIKELY(2 != rt_expr.arg_cnt_ || NULL == rt_expr.args_ || NULL == rt_expr.args_[0] || NULL == rt_expr.args_[1] || input_types.count() != 2)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else { rt_expr.inner_func_cnt_ = 0; rt_expr.inner_functions_ = NULL; 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_; 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)) { CK(rt_expr.args_[0]->datum_meta_.cs_type_ == rt_expr.args_[1]->datum_meta_.cs_type_); rt_expr.eval_func_ = ObExprCmpFuncsHelper::get_eval_expr_cmp_func( input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type); } else { rt_expr.eval_func_ = ObExprCmpFuncsHelper::get_eval_expr_cmp_func( input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type); CK(NULL != rt_expr.eval_func_); } } return ret; } int ObRelationalExprOperator::cg_row_cmp_expr(const int row_dimension, ObIAllocator& allocator, const ObRawExpr& raw_expr, const ObExprOperatorInputTypeArray& input_types, ObExpr& rt_expr) { int ret = OB_SUCCESS; if (OB_UNLIKELY(rt_expr.arg_cnt_ != 2 || row_dimension <= 0 || NULL == rt_expr.args_ || NULL == rt_expr.args_[0] || NULL == rt_expr.args_[1] || rt_expr.args_[0]->arg_cnt_ != row_dimension || input_types.count() != row_dimension * 2)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else { void** inner_func_buf = NULL; if (OB_ISNULL(inner_func_buf = (void**)allocator.alloc(sizeof(void*) * row_dimension))) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { rt_expr.inner_func_cnt_ = row_dimension; rt_expr.inner_functions_ = inner_func_buf; const ObCmpOp cmp_op = get_cmp_op(raw_expr.get_expr_type()); ObExpr* left_row = rt_expr.args_[0]; ObExpr* right_row = NULL; if (OB_LIKELY(T_OP_ROW == rt_expr.args_[1]->type_ && NULL != rt_expr.args_[1]->args_[0])) { if (T_OP_ROW == rt_expr.args_[1]->args_[0]->type_) { right_row = rt_expr.args_[1]->args_[0]; } else { right_row = rt_expr.args_[1]; } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected error", K(ret)); } if (OB_UNLIKELY(left_row->arg_cnt_ != right_row->arg_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected row cnt", K(left_row->arg_cnt_), K(right_row->arg_cnt_)); } LOG_DEBUG("CG ROW CMP Expr", K(input_types), K(cmp_op)); for (int i = 0; OB_SUCC(ret) && i < row_dimension; i++) { const ObObjType type1 = left_row->args_[i]->datum_meta_.type_; const ObObjType type2 = right_row->args_[i]->datum_meta_.type_; 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, 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); 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)); } } } // for end if (OB_SUCC(ret)) { rt_expr.eval_func_ = &row_eval; } } } return ret; } int ObRelationalExprOperator::row_eval(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_UNLIKELY(2 != expr.arg_cnt_ || NULL == expr.args_ || expr.inner_func_cnt_ <= 0 || expr.args_[0]->arg_cnt_ != expr.inner_func_cnt_ || NULL == expr.args_[0]->args_ || NULL == expr.args_[1]->args_ || NULL == expr.inner_functions_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else { ObExpr* left_row = expr.args_[0]; ObExpr* right_row = NULL; if (1 == expr.args_[1]->arg_cnt_ && T_OP_ROW == expr.args_[1]->args_[0]->type_) { if (expr.args_[1]->args_[0]->arg_cnt_ != expr.inner_func_cnt_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected arg cnt", K(ret), K(expr.inner_func_cnt_), K(expr.args_[1]->args_[0]->arg_cnt_)); } else { right_row = expr.args_[1]->args_[0]; } } else if (OB_UNLIKELY(expr.inner_func_cnt_ != expr.args_[1]->arg_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected arg cnt", K(ret), K(expr.inner_func_cnt_), K(expr.args_[1]->arg_cnt_)); } else { right_row = expr.args_[1]; } ret = row_cmp(expr, expr_datum, left_row->args_, ctx, right_row->args_, ctx); } return ret; } int ObRelationalExprOperator::row_cmp( const ObExpr& expr, ObDatum& expr_datum, ObExpr** l_row, ObEvalCtx& l_ctx, ObExpr** r_row, ObEvalCtx& r_ctx) { // performance critical, do not check pointer validity. int ret = OB_SUCCESS; ObDatum* left = NULL; ObDatum* right = NULL; bool cnt_row_null = false; int first_nonequal_cmp_ret = 0; int i = 0; // locate first non-equal pair for (; OB_SUCC(ret) && i < expr.inner_func_cnt_; i++) { if (OB_FAIL(l_row[i]->eval(l_ctx, left))) { LOG_WARN("failed to eval left in row cmp", K(ret)); } else if (left->is_null()) { cnt_row_null = true; } else if (OB_FAIL(r_row[i]->eval(r_ctx, right))) { LOG_WARN("failed to eval right in row cmp", K(ret)); } else if (right->is_null()) { cnt_row_null = true; } else if (0 != (first_nonequal_cmp_ret = ((DatumCmpFunc)expr.inner_functions_[i])(*left, *right))) { break; } } // for end ObCmpOp cmp_op = get_cmp_op(expr.type_); if (OB_FAIL(ret)) { // do nothing } else if (i == expr.inner_func_cnt_) { if (cnt_row_null) { expr_datum.set_null(); } else { expr_datum.set_int(is_expected_cmp_ret(cmp_op, 0)); } } else { if (cnt_row_null) { if (CO_NE == cmp_op) { expr_datum.set_int(true); } else if (CO_EQ == cmp_op) { expr_datum.set_int(false); } else { expr_datum.set_null(); } } else { expr_datum.set_int(is_expected_cmp_ret(cmp_op, first_nonequal_cmp_ret)); } } return ret; } } // namespace sql } // namespace oceanbase