/** * 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_EXE #include "common/object/ob_obj_compare.h" #include "sql/engine/expr/ob_expr_between.h" #include "sql/engine/expr/ob_expr_less_than.h" #include "sql/engine/expr/ob_expr_less_equal.h" #include "sql/engine/expr/ob_expr_cmp_func.h" #include "sql/session/ob_sql_session_info.h" #include "share/vector/expr_cmp_func.h" namespace oceanbase { using namespace common; namespace sql { ObExprBetween::ObExprBetween(ObIAllocator &alloc) : ObRelationalExprOperator(alloc, T_OP_BTW, N_BTW, 3) { } int calc_between_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum) { // left <= val <= right int ret = OB_SUCCESS; ObDatum *val = NULL; ObDatum *left = NULL; ObDatum *right = NULL; if (OB_FAIL(expr.args_[0]->eval(ctx, val))) { LOG_WARN("eval arg 0 failed", K(ret)); } else if (val->is_null()) { res_datum.set_null(); } else if (OB_FAIL(expr.args_[1]->eval(ctx, left))) { LOG_WARN("eval arg 1 failed", K(ret)); } else if (OB_FAIL(expr.args_[2]->eval(ctx, right))) { LOG_WARN("eval arg 2 failed", K(ret)); } else if (left->is_null() && right->is_null()) { res_datum.set_null(); } else { bool left_cmp_succ = true; // is left <= val true or not bool right_cmp_succ = true; // is val <= right true or not int cmp_ret = 0; if (!left->is_null()) { if (OB_FAIL((reinterpret_cast(expr.inner_functions_[0]))(*left, *val, cmp_ret))) { LOG_WARN("compare left failed", K(ret)); } else { left_cmp_succ = cmp_ret <= 0 ? true : false; } } if (OB_FAIL(ret)) { } else if (left->is_null() || (left_cmp_succ && !right->is_null())) { if (OB_FAIL((reinterpret_cast(expr.inner_functions_[1]))(*val, *right, cmp_ret))) { LOG_WARN("compare left failed", K(ret)); } else { right_cmp_succ = cmp_ret <= 0 ? true : false; } } if (OB_FAIL(ret)) { } else if ((left->is_null() && right_cmp_succ) || (right->is_null() && left_cmp_succ)) { res_datum.set_null(); } else if (left_cmp_succ && right_cmp_succ) { res_datum.set_int32(1); } else { res_datum.set_int32(0); } } return ret; } #define BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, right_vec, res_vec) \ switch (l_format) { \ case VEC_FIXED: { \ ret = func_name( \ expr, ctx, my_skip, bound); \ break; \ } \ case VEC_DISCRETE: { \ ret = func_name( \ expr, ctx, my_skip, bound); \ break; \ } \ case VEC_CONTINUOUS: { \ ret = func_name( \ expr, ctx, my_skip, bound); \ break; \ } \ case VEC_UNIFORM: { \ ret = func_name, right_vec, res_vec, stage>( \ expr, ctx, my_skip, bound); \ break; \ } \ case VEC_UNIFORM_CONST: { \ ret = func_name, right_vec, res_vec, stage>( \ expr, ctx, my_skip, bound); \ break; \ } \ default: { \ ret = func_name( \ expr, ctx, my_skip, bound); \ } \ } #define BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \ func_name, stage, l_format, r_format, res_vec) \ switch (r_format) { \ case VEC_FIXED: { \ BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, ObFixedLengthBase, res_vec); \ break; \ } \ case VEC_DISCRETE: { \ BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, ObDiscreteFormat, res_vec); \ break; \ } \ case VEC_CONTINUOUS: { \ BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, ObContinuousFormat, res_vec); \ break; \ } \ case VEC_UNIFORM: { \ BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, ObUniformFormat, res_vec); \ break; \ } \ case VEC_UNIFORM_CONST: { \ BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, ObUniformFormat, res_vec); \ break; \ } \ default: { \ BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \ func_name, stage, l_format, ObVectorBase, res_vec); \ } \ } #define BETWEEN_DISPATCH_VECTOR_IN_RES_ARG_FORMAT( \ func_name, stage, l_format, r_format) \ switch (res_format) { \ case VEC_FIXED: { \ BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \ func_name, stage, l_format, r_format, IntegerFixedVec); \ break; \ } \ case VEC_UNIFORM: { \ BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \ func_name, stage, l_format, r_format, IntegerUniVec); \ break; \ } \ case VEC_UNIFORM_CONST: { \ BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \ func_name, stage, l_format, r_format, IntegerUniCVec); \ break; \ } \ default: { \ BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \ func_name, stage, l_format, r_format, ObVectorBase); \ } \ } int ObExprBetween::eval_between_vector(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound) { // left <= val <= right int ret = OB_SUCCESS; const ObExpr &val_expr = *expr.args_[0]; const ObExpr &left_expr = *expr.args_[1]; const ObExpr &right_expr = *expr.args_[2]; ObBitVector &my_skip = expr.get_pvt_skip(ctx); my_skip.deep_copy(skip, bound.start(), bound.end()); if (OB_FAIL(val_expr.eval_vector(ctx, my_skip, bound))) { LOG_WARN("eval left operand failed", K(ret)); } else if (OB_FAIL(left_expr.eval_vector(ctx, my_skip, bound))) { LOG_WARN("eval left operand failed", K(ret)); } else if (OB_FAIL(right_expr.eval_vector(ctx, my_skip, bound))) { LOG_WARN("eval left operand failed", K(ret)); } else { VectorFormat val_format = val_expr.get_format(ctx); VectorFormat left_format = left_expr.get_format(ctx); VectorFormat right_format = right_expr.get_format(ctx); VectorFormat res_format = expr.get_format(ctx); BETWEEN_DISPATCH_VECTOR_IN_RES_ARG_FORMAT( inner_eval_between_vector, BETWEEN_LEFT, left_format, val_format); if (OB_FAIL(ret)) { LOG_WARN("compare left and val failed", K(ret)); } else { BETWEEN_DISPATCH_VECTOR_IN_RES_ARG_FORMAT( inner_eval_between_vector, BETWEEN_RIGHT, val_format, right_format); if (OB_FAIL(ret)) { LOG_WARN("compare val and right failed", K(ret)); } else { ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); eval_flags.bit_not(skip, bound); } } } return ret; } int ObExprBetween::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const { // left <= val <= right int ret = OB_SUCCESS; if (OB_UNLIKELY(3 != rt_expr.arg_cnt_) || OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]) || OB_ISNULL(rt_expr.args_[1]) || OB_ISNULL(rt_expr.args_[2]) || OB_ISNULL(expr_cg_ctx.allocator_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("rt_expr is invalid", K(ret), K(rt_expr.arg_cnt_), KP(rt_expr.args_), KP(rt_expr.args_[0]), KP(rt_expr.args_[1]), KP(rt_expr.args_[2])); } else { DatumCmpFunc cmp_func_1 = NULL; // left <= val DatumCmpFunc cmp_func_2 = NULL; // val <= right const ObDatumMeta &val_meta = rt_expr.args_[0]->datum_meta_; const ObDatumMeta &left_meta = rt_expr.args_[1]->datum_meta_; const ObDatumMeta &right_meta = rt_expr.args_[2]->datum_meta_; const ObCollationType cmp_cs_type = raw_expr.get_result_type().get_calc_collation_type(); const bool has_lob_header1 = rt_expr.args_[0]->obj_meta_.has_lob_header() || rt_expr.args_[1]->obj_meta_.has_lob_header(); const bool has_lob_header2 = rt_expr.args_[0]->obj_meta_.has_lob_header() || rt_expr.args_[2]->obj_meta_.has_lob_header(); if (OB_ISNULL(cmp_func_1 = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( left_meta.type_, val_meta.type_, left_meta.scale_, val_meta.scale_, left_meta.precision_, val_meta.precision_, is_oracle_mode(), cmp_cs_type, has_lob_header1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_datum_expr_cmp_func failed", K(ret), K(left_meta), K(val_meta), K(is_oracle_mode()), K(rt_expr)); } else if (OB_ISNULL(cmp_func_2 = ObExprCmpFuncsHelper::get_datum_expr_cmp_func( val_meta.type_, right_meta.type_, val_meta.scale_, right_meta.scale_, val_meta.precision_, right_meta.precision_, is_oracle_mode(), cmp_cs_type, has_lob_header2))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_datum_expr_cmp_func failed", K(ret), K(val_meta), K(right_meta), K(is_oracle_mode()), K(rt_expr)); } else { rt_expr.eval_func_ = calc_between_expr; } if (OB_FAIL(ret)) { } else if (expr_cg_ctx.session_->use_rich_format()) { RowCmpFunc vec_cmp_func_1 = NULL; // left <= val RowCmpFunc vec_cmp_func_2 = NULL; // val <= right if (OB_ISNULL(vec_cmp_func_1 = VectorCmpExprFuncsHelper::get_row_cmp_func( left_meta, val_meta))) { ret = OB_ERR_UNEXPECTED; VecValueTypeClass value_tc = get_vec_value_tc(val_meta.type_, val_meta.scale_, val_meta.precision_); VecValueTypeClass left_tc = get_vec_value_tc(left_meta.type_, left_meta.scale_, left_meta.precision_); LOG_WARN("The result of get_eval_vector_between_expr_cmp_func(left) is null.", K(ret), K(left_meta), K(val_meta), K(right_meta), K(value_tc), K(left_tc), K(rt_expr)); } else if (OB_ISNULL(vec_cmp_func_2 = VectorCmpExprFuncsHelper::get_row_cmp_func( val_meta, right_meta))) { ret = OB_ERR_UNEXPECTED; VecValueTypeClass value_tc = get_vec_value_tc(val_meta.type_, val_meta.scale_, val_meta.precision_); VecValueTypeClass right_tc = get_vec_value_tc(right_meta.type_, right_meta.scale_, right_meta.precision_); LOG_WARN("The result of get_eval_vector_between_expr_cmp_func(right) is null.", K(ret), K(left_meta), K(val_meta), K(right_meta), K(value_tc), K(right_tc), K(rt_expr)); } else if (OB_ISNULL(rt_expr.inner_functions_ = reinterpret_cast( expr_cg_ctx.allocator_->alloc(sizeof(DatumCmpFunc) * 2 + sizeof(RowCmpFunc) * 2)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc memory for inner_functions_ failed", K(ret)); } else { rt_expr.inner_func_cnt_ = 4; rt_expr.inner_functions_[0] = reinterpret_cast(cmp_func_1); rt_expr.inner_functions_[1] = reinterpret_cast(cmp_func_2); rt_expr.inner_functions_[2] = reinterpret_cast(vec_cmp_func_1); rt_expr.inner_functions_[3] = reinterpret_cast(vec_cmp_func_2); rt_expr.eval_vector_func_ = eval_between_vector; } } else { // not use_rich_format if (OB_ISNULL(rt_expr.inner_functions_ = reinterpret_cast( expr_cg_ctx.allocator_->alloc(sizeof(DatumCmpFunc) * 2)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc memory for inner_functions_ failed", K(ret)); } else { rt_expr.inner_func_cnt_ = 2; rt_expr.inner_functions_[0] = reinterpret_cast(cmp_func_1); rt_expr.inner_functions_[1] = reinterpret_cast(cmp_func_2); } } } return ret; } #define DO_VECTOR_BETWEEN_ROW_CMP() \ if (std::is_same::value) { \ l_payload = fixed_base_l_payload + l_len * i; \ } else if (!std::is_same>::value){ \ l_vector->get_payload(i, l_payload, l_len); \ } \ if (std::is_same::value) { \ r_payload = fixed_base_r_payload + r_len * i; \ } else if (!std::is_same>::value){ \ r_vector->get_payload(i, r_payload, r_len); \ } \ if (Stage == EvalBetweenStage::BETWEEN_LEFT) { \ ret = (reinterpret_cast(expr.inner_functions_[2])) \ (left->obj_meta_, right->obj_meta_, \ (const void *)l_payload, l_len, \ (const void *)r_payload, r_len, cmp_ret); \ } else { /*BETWEEN_RIGHT*/ \ ret = (reinterpret_cast(expr.inner_functions_[3])) \ (left->obj_meta_, right->obj_meta_, \ (const void *)l_payload, l_len, \ (const void *)r_payload, r_len, cmp_ret); \ } #define DO_VECTOR_BETWEEN_SET_RES() \ /* Result priority: false > null > true */ \ if (OB_FAIL(ret)) { \ } else if (Stage == EvalBetweenStage::BETWEEN_LEFT) { \ /* If the current calculation is left<=val, any result is directly filled in. \ If the result is false, the subsequent calculation results are meaningless, \ and skip is set to true. */ \ res_vec->set_int(i, (cmp_ret <= 0)); \ if (cmp_ret > 0) { \ skip.set(i); \ } \ } else if (cmp_ret > 0) { /*BETWEEN_RIGHT*/ \ /* If currently calculating val<=right, \ only when the result is false will it be filled in. */ \ res_vec->set_int(i, 0); \ } template int ObExprBetween::inner_eval_between_vector(const ObExpr &expr, ObEvalCtx &ctx, ObBitVector &skip, const EvalBound &bound) { int ret = OB_SUCCESS; ObExpr *left = nullptr; ObExpr *right = nullptr; if (Stage == EvalBetweenStage::BETWEEN_LEFT) { left = expr.args_[1]; right = expr.args_[0]; } else { left = expr.args_[0]; right = expr.args_[2]; } LVec *l_vector = static_cast(left->get_vector(ctx)); RVec *r_vector = static_cast(right->get_vector(ctx)); ResVec *res_vec = static_cast(expr.get_vector(ctx)); ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); const char *l_payload = nullptr, *r_payload = nullptr; const char *fixed_base_l_payload = nullptr, *fixed_base_r_payload = nullptr; ObLength l_len = 0, r_len = 0; int cmp_ret = 0; bool l_has_null = l_vector->has_null(); bool r_has_null = r_vector->has_null(); // If a constant value exists and that constant value is null, // then set the entire res_vec to null. if (std::is_same>::value && l_has_null) { // If at this point the computation is val < right, and val is null, // then the result must have already been set to null previously, // and can be skipped directly. if (Stage == EvalBetweenStage::BETWEEN_LEFT) { for (int i = bound.start(); i < bound.end(); ++i) { if (skip.at(i) || eval_flags.at(i)) { continue; } res_vec->set_null(i); } } } else if (std::is_same>::value && r_has_null) { for (int i = bound.start(); i < bound.end(); ++i) { if (skip.at(i) || eval_flags.at(i)) { continue; } res_vec->set_null(i); } // For the case where both sides are constants, calculate only once, // then fill the values in a loop; // there is no need to consider the null situation, // as it has already been assessed previously. } else if (std::is_same>::value && std::is_same>::value) { l_vector->get_payload(0, l_payload, l_len); r_vector->get_payload(0, r_payload, r_len); if (Stage == EvalBetweenStage::BETWEEN_LEFT) { ret = (reinterpret_cast(expr.inner_functions_[2])) (left->obj_meta_, right->obj_meta_, (const void *)l_payload, l_len, (const void *)r_payload, r_len, cmp_ret); } else { /*BETWEEN_RIGHT*/ ret = (reinterpret_cast(expr.inner_functions_[3])) (left->obj_meta_, right->obj_meta_, (const void *)l_payload, l_len, (const void *)r_payload, r_len, cmp_ret); } for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); ++i) { if (skip.at(i) || eval_flags.at(i)) { continue; } DO_VECTOR_BETWEEN_SET_RES(); } } else { if (std::is_same::value) { fixed_base_l_payload = (reinterpret_cast(l_vector))->get_data(); l_len = (reinterpret_cast(l_vector))->get_length(); } else if (std::is_same>::value) { l_vector->get_payload(0, l_payload, l_len); } if (std::is_same::value) { fixed_base_r_payload = (reinterpret_cast(r_vector))->get_data(); r_len = (reinterpret_cast(r_vector))->get_length(); } else if (std::is_same>::value) { r_vector->get_payload(0, r_payload, r_len); } if (!(l_has_null || r_has_null)) { for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); ++i) { if (skip.at(i) || eval_flags.at(i)) { continue; } DO_VECTOR_BETWEEN_ROW_CMP(); DO_VECTOR_BETWEEN_SET_RES(); } } else { for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); ++i) { if (skip.at(i) || eval_flags.at(i)) { continue; } if (l_vector->is_null(i) || r_vector->is_null(i)) { res_vec->set_null(i); } else { DO_VECTOR_BETWEEN_ROW_CMP(); DO_VECTOR_BETWEEN_SET_RES(); } } } } return ret; } } }