/** * 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. * This file contains implementation for array. */ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/expr/ob_expr_array_contains.h" #include "lib/udt/ob_collection_type.h" #include "lib/udt/ob_array_type.h" #include "sql/engine/expr/ob_expr_lob_utils.h" #include "sql/engine/expr/ob_array_expr_utils.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_expr_result_type_util.h" using namespace oceanbase::common; using namespace oceanbase::sql; using namespace oceanbase::omt; namespace oceanbase { namespace sql { ObExprArrayContains::ObExprArrayContains(ObIAllocator &alloc) : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_CONTAINS, N_ARRAY_CONTAINS, 2, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) { } ObExprArrayContains::ObExprArrayContains(ObIAllocator &alloc, ObExprOperatorType type, const char *name, int32_t param_num, int32_t dimension) : ObFuncExprOperator(alloc, type, name, param_num, VALID_FOR_GENERATED_COL, dimension) { } ObExprArrayContains::~ObExprArrayContains() { } int ObExprArrayContains::calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const { int ret = OB_SUCCESS; ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); ObSubSchemaValue arr_meta; const ObSqlCollectionInfo *coll_info = NULL; ObExprResType *type1_ptr = &type1; ObExprResType *type2_ptr = &type2; uint16_t subschema_id; if (OB_ISNULL(exec_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("exec ctx is null", K(ret)); } else if (OB_ISNULL(type_ctx.get_raw_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("raw expr is null", K(ret)); } else if (type_ctx.get_raw_expr()->get_extra() != 0) { // It's any operator ,param order is reversed ObExprResType *type_tmp = type2_ptr; type2_ptr = type1_ptr; type1_ptr = type_tmp; } if (OB_FAIL(ret)) { } else if (!ob_is_collection_sql_type(type1_ptr->get_type())) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1_ptr->get_type()), ob_obj_type_str(type2_ptr->get_type())); } else if (type2_ptr->is_null()) { // do nothing } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(type1_ptr->get_subschema_id(), arr_meta))) { LOG_WARN("failed to get elem meta.", K(ret), K(type1_ptr->get_subschema_id())); } else if (arr_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("invalid subschema type", K(ret), K(arr_meta.type_)); } else if (OB_ISNULL(coll_info = static_cast(arr_meta.value_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("coll info is null", K(ret)); } else if (!ob_is_collection_sql_type(type2_ptr->get_type())) { ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); ObCollectionTypeBase *elem_type = arr_type->element_type_; if (elem_type->type_id_ == ObNestedType::OB_BASIC_TYPE) { if (ob_obj_type_class(type2_ptr->get_type()) != static_cast(elem_type)->basic_meta_.get_type_class()) { ObObjType calc_type = type2_ptr->get_type(); if (type2_ptr->get_type() == ObDecimalIntType || type2_ptr->get_type() == ObNumberType || type2_ptr->get_type() == ObUNumberType) { calc_type = ObDoubleType; if (get_decimalint_type(type2_ptr->get_precision()) == DECIMAL_INT_32) { calc_type = ObFloatType; } } if (calc_type == static_cast(elem_type)->basic_meta_.get_obj_type()) { type2_ptr->set_calc_type(calc_type); } else { uint32_t depth = 0; ObDataType coll_elem1_type; ObExprResType deduce_type; bool is_vec = false; if (OB_FAIL(ret)) { } else if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, type1_ptr->get_subschema_id(), coll_elem1_type, depth, is_vec))) { LOG_WARN("failed to get array element type", K(ret)); } else if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, coll_elem1_type.get_obj_type(), calc_type, depth, deduce_type, calc_type))) { LOG_WARN("failed to get array calc type", K(ret)); } else { type1_ptr->set_calc_meta(deduce_type); type2_ptr->set_calc_type(calc_type); } } } } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("invalid obj type", K(ret), K(*coll_info), K(type2_ptr->get_type())); } } else { // type2_ptr->is array ObString child_def; uint16_t child_subschema_id; ObExprResType child_type; ObExprResType coll_calc_type; if (OB_FAIL(coll_info->get_child_def_string(child_def))) { LOG_WARN("failed to get type1 child define", K(ret), K(*coll_info)); } else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(child_def, child_subschema_id))) { LOG_WARN("failed to get type1 child subschema id", K(ret), K(*coll_info), K(child_def)); } else if (child_subschema_id == type2_ptr->get_subschema_id()) { // do nothing } else if (FALSE_IT(child_type.set_collection(child_subschema_id))) { } else if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, child_type, *type2_ptr, coll_calc_type))) { LOG_WARN("failed to check array compatibilty", K(ret)); } else { if (type2_ptr->get_subschema_id() != coll_calc_type.get_subschema_id()) { type2_ptr->set_calc_meta(coll_calc_type); } if (child_type.get_subschema_id() != coll_calc_type.get_subschema_id()) { ObDataType child_calc_type; uint16_t type1_calc_id; child_calc_type.meta_.set_collection(coll_calc_type.get_subschema_id()); if (OB_FAIL(ObArrayExprUtils::deduce_nested_array_subschema_id(exec_ctx, child_calc_type, type1_calc_id))) { LOG_WARN("failed to deduce nested array subschema id", K(ret)); } else { coll_calc_type.set_collection(type1_calc_id); type1_ptr->set_calc_meta(coll_calc_type); } } } } if (OB_SUCC(ret)) { type.set_int32(); type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); } return ret; } #define EVAL_FUNC_ARRAY_CONTAINS(TYPE, GET_FUNC) \ int ObExprArrayContains::eval_array_contains_##TYPE(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) \ { \ int ret = OB_SUCCESS; \ ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); \ common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); \ uint32_t p0 = expr.extra_ == 1 ? 1 : 0; \ uint32_t p1 = expr.extra_ == 1 ? 0 : 1; \ const uint16_t meta_id = expr.args_[p0]->obj_meta_.get_subschema_id(); \ ObIArrayType *arr_obj = NULL; \ ObDatum *datum = NULL; \ ObDatum *datum_val = NULL; \ TYPE val; \ bool bret = false; \ if (OB_FAIL(expr.args_[p0]->eval(ctx, datum))) { \ LOG_WARN("failed to eval args", K(ret)); \ } else if (OB_FAIL(expr.args_[p1]->eval(ctx, datum_val))) { \ LOG_WARN("failed to eval args", K(ret)); \ } else if (datum->is_null()) { \ res.set_null(); \ } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, meta_id, datum->get_string(), arr_obj))) { \ LOG_WARN("construct array obj failed", K(ret)); \ } else if (datum_val->is_null()) { \ bool contains_null = arr_obj->contain_null(); \ res.set_bool(contains_null); \ } else if (FALSE_IT(val = datum_val->GET_FUNC())) { \ } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, val, bret))) { \ LOG_WARN("array contains failed", K(ret)); \ } else { \ res.set_bool(bret); \ } \ return ret; \ } EVAL_FUNC_ARRAY_CONTAINS(int64_t, get_int) EVAL_FUNC_ARRAY_CONTAINS(float, get_float) EVAL_FUNC_ARRAY_CONTAINS(double, get_double) EVAL_FUNC_ARRAY_CONTAINS(ObString, get_string) int ObExprArrayContains::eval_array_contains_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) { int ret = OB_SUCCESS; ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); uint32_t p0 = expr.extra_ == 1 ? 1 : 0; uint32_t p1 = expr.extra_ == 1 ? 0 : 1; const uint16_t l_meta_id = expr.args_[p0]->obj_meta_.get_subschema_id(); const uint16_t r_meta_id = expr.args_[p1]->obj_meta_.get_subschema_id(); ObIArrayType *arr_obj = NULL; ObIArrayType *arr_val = NULL; ObDatum *datum = NULL; ObDatum *datum_val = NULL; bool bret = false; if (OB_FAIL(expr.args_[p0]->eval(ctx, datum))) { LOG_WARN("failed to eval args", K(ret)); } else if (OB_FAIL(expr.args_[p1]->eval(ctx, datum_val))) { LOG_WARN("failed to eval args", K(ret)); } else if (datum->is_null()) { res.set_null(); } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, l_meta_id, datum->get_string(), arr_obj))) { LOG_WARN("construct array obj failed", K(ret)); } else if (datum_val->is_null()) { bool contains_null = arr_obj->contain_null(); res.set_bool(contains_null); } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, r_meta_id, datum_val->get_string(), arr_val))) { LOG_WARN("construct array obj failed", K(ret)); } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, *arr_val, bret))) { LOG_WARN("array contains failed", K(ret)); } else { res.set_bool(bret); } return ret; } #define EVAL_FUNC_ARRAY_CONTAINS_BATCH(TYPE, GET_FUNC) \ int ObExprArrayContains::eval_array_contains_batch_##TYPE( \ const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size) \ { \ int ret = OB_SUCCESS; \ ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); \ ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); \ ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); \ common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); \ uint32_t p0 = expr.extra_ == 1 ? 1 : 0; \ uint32_t p1 = expr.extra_ == 1 ? 0 : 1; \ const uint16_t meta_id = expr.args_[p0]->obj_meta_.get_subschema_id(); \ ObIArrayType *arr_obj = NULL; \ if (OB_FAIL(expr.args_[p0]->eval_batch(ctx, skip, batch_size))) { \ LOG_WARN("eval date_unit_datum failed", K(ret)); \ } else if (OB_FAIL(expr.args_[p1]->eval_batch(ctx, skip, batch_size))) { \ LOG_WARN("failed to eval batch result args0", K(ret)); \ } else { \ ObDatumVector src_array = expr.args_[p0]->locate_expr_datumvector(ctx); \ ObDatumVector val_array = expr.args_[p1]->locate_expr_datumvector(ctx); \ for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { \ if (skip.at(j) || eval_flags.at(j)) { \ continue; \ } \ eval_flags.set(j); \ bool bret = false; \ TYPE val; \ if (src_array.at(j)->is_null()) { \ res_datum.at(j)->set_null(); \ } else if (OB_FAIL(ObArrayExprUtils::get_array_obj( \ tmp_allocator, ctx, meta_id, src_array.at(j)->get_string(), arr_obj))) { \ LOG_WARN("construct array obj failed", K(ret)); \ } else if (val_array.at(j)->is_null()) { \ bool contains_null = arr_obj->contain_null(); \ res_datum.at(j)->set_bool(contains_null); \ } else if (FALSE_IT(val = val_array.at(j)->GET_FUNC())) { \ } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, val, bret))) { \ LOG_WARN("array contains failed", K(ret)); \ } else { \ res_datum.at(j)->set_bool(bret); \ } \ } \ } \ return ret; \ } EVAL_FUNC_ARRAY_CONTAINS_BATCH(int64_t, get_int) EVAL_FUNC_ARRAY_CONTAINS_BATCH(float, get_float) EVAL_FUNC_ARRAY_CONTAINS_BATCH(double, get_double) EVAL_FUNC_ARRAY_CONTAINS_BATCH(ObString, get_string) int ObExprArrayContains::eval_array_contains_array_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size) { int ret = OB_SUCCESS; ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); uint32_t p0 = expr.extra_ == 1 ? 1 : 0; uint32_t p1 = expr.extra_ == 1 ? 0 : 1; const uint16_t l_meta_id = expr.args_[p0]->obj_meta_.get_subschema_id(); const uint16_t r_meta_id = expr.args_[p1]->obj_meta_.get_subschema_id(); ObIArrayType *arr_obj = NULL; ObIArrayType *arr_val = NULL; if (OB_FAIL(expr.args_[p0]->eval_batch(ctx, skip, batch_size))) { LOG_WARN("eval date_unit_datum failed", K(ret)); } else if (OB_FAIL(expr.args_[p1]->eval_batch(ctx, skip, batch_size))) { LOG_WARN("failed to eval batch result args0", K(ret)); } else { ObDatumVector src_array = expr.args_[p0]->locate_expr_datumvector(ctx); ObDatumVector val_array = expr.args_[p1]->locate_expr_datumvector(ctx); for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { if (skip.at(j) || eval_flags.at(j)) { continue; } eval_flags.set(j); bool bret = false; if (src_array.at(j)->is_null()) { res_datum.at(j)->set_null(); } else if (OB_FAIL( ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, l_meta_id, src_array.at(j)->get_string(), arr_obj))) { LOG_WARN("construct array obj failed", K(ret)); } else if (val_array.at(j)->is_null()) { bool contains_null = arr_obj->contain_null(); res_datum.at(j)->set_bool(contains_null); } else if (OB_FAIL(ObArrayExprUtils::get_array_obj( tmp_allocator, ctx, r_meta_id, val_array.at(j)->get_string(), arr_val))) { LOG_WARN("construct array obj failed", K(ret)); } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, *arr_val, bret))) { LOG_WARN("array contains failed", K(ret)); } else { res_datum.at(j)->set_bool(bret); } } } return ret; } #define EVAL_FUNC_ARRAY_CONTAINS_VECTOR(TYPE, GET_FUNC) \ int ObExprArrayContains::eval_array_contains_vector_##TYPE( \ const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound) \ { \ int ret = OB_SUCCESS; \ uint32_t p0 = expr.extra_ == 1 ? 1 : 0; \ uint32_t p1 = expr.extra_ == 1 ? 0 : 1; \ if (OB_FAIL(expr.args_[p0]->eval_vector(ctx, skip, bound)) || \ OB_FAIL(expr.args_[p1]->eval_vector(ctx, skip, bound))) { \ LOG_WARN("fail to eval params", K(ret)); \ } else { \ ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); \ common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); \ ObIVector *left_vec = expr.args_[p0]->get_vector(ctx); \ VectorFormat left_format = left_vec->get_format(); \ ObIVector *right_vec = expr.args_[p1]->get_vector(ctx); \ const uint16_t meta_id = expr.args_[p0]->obj_meta_.get_subschema_id(); \ ObIVector *res_vec = expr.get_vector(ctx); \ ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); \ ObIArrayType *arr_obj = NULL; \ TYPE val; \ for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { \ bool is_null_res = false; \ if (skip.at(idx) || eval_flags.at(idx)) { \ continue; \ } else if (left_vec->is_null(idx)) { \ is_null_res = true; \ } else if (left_format == VEC_UNIFORM || left_format == VEC_UNIFORM_CONST) { \ ObString left = left_vec->get_string(idx); \ if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, meta_id, left, arr_obj))) { \ LOG_WARN("construct array obj failed", K(ret)); \ } \ } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( \ tmp_allocator, ctx, *expr.args_[p0], meta_id, idx, arr_obj))) { \ LOG_WARN("construct array obj failed", K(ret)); \ } \ bool bret = false; \ if (OB_FAIL(ret)) { \ } else if (is_null_res) { \ res_vec->set_null(idx); \ eval_flags.set(idx); \ } else if (right_vec->is_null(idx)) { \ bool contains_null = arr_obj->contain_null(); \ res_vec->set_bool(idx, contains_null); \ eval_flags.set(idx); \ } else if (FALSE_IT(val = right_vec->GET_FUNC(idx))) { \ } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, val, bret))) { \ LOG_WARN("array contains failed", K(ret)); \ } else { \ res_vec->set_bool(idx, bret); \ eval_flags.set(idx); \ } \ } \ } \ return ret; \ } EVAL_FUNC_ARRAY_CONTAINS_VECTOR(int64_t, get_int) EVAL_FUNC_ARRAY_CONTAINS_VECTOR(float, get_float) EVAL_FUNC_ARRAY_CONTAINS_VECTOR(double, get_double) EVAL_FUNC_ARRAY_CONTAINS_VECTOR(ObString, get_string) int ObExprArrayContains::eval_array_contains_array_vector(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound) { int ret = OB_SUCCESS; uint32_t p0 = expr.extra_ == 1 ? 1 : 0; uint32_t p1 = expr.extra_ == 1 ? 0 : 1; if (OB_FAIL(expr.args_[p0]->eval_vector(ctx, skip, bound)) || OB_FAIL(expr.args_[p1]->eval_vector(ctx, skip, bound))) { LOG_WARN("fail to eval params", K(ret)); } else { ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); ObIVector *left_vec = expr.args_[p0]->get_vector(ctx); VectorFormat left_format = left_vec->get_format(); ObIVector *right_vec = expr.args_[p1]->get_vector(ctx); VectorFormat right_format = right_vec->get_format(); const uint16_t left_meta_id = expr.args_[p0]->obj_meta_.get_subschema_id(); const uint16_t right_meta_id = expr.args_[p1]->obj_meta_.get_subschema_id(); ObIVector *res_vec = expr.get_vector(ctx); ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); ObIArrayType *arr_obj = NULL; ObIArrayType *arr_val = NULL; for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { bool is_null_res = false; if (skip.at(idx) || eval_flags.at(idx)) { continue; } else if (left_vec->is_null(idx)) { is_null_res = true; } else if (left_format == VEC_UNIFORM || left_format == VEC_UNIFORM_CONST) { ObString left = left_vec->get_string(idx); if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, left_meta_id, left, arr_obj))) { LOG_WARN("construct array obj failed", K(ret)); } } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( tmp_allocator, ctx, *expr.args_[p0], left_meta_id, idx, arr_obj))) { LOG_WARN("construct array obj failed", K(ret)); } if (OB_FAIL(ret)) { } else if (is_null_res) { res_vec->set_null(idx); eval_flags.set(idx); } else if (right_vec->is_null(idx)) { bool contains_null = arr_obj->contain_null(); res_vec->set_bool(idx, contains_null); eval_flags.set(idx); } else if (right_format == VEC_UNIFORM || right_format == VEC_UNIFORM_CONST) { ObString right = right_vec->get_string(idx); if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, right_meta_id, right, arr_val))) { LOG_WARN("construct array obj failed", K(ret)); } } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( tmp_allocator, ctx, *expr.args_[p1], right_meta_id, idx, arr_val))) { LOG_WARN("construct array obj failed", K(ret)); } bool bret = false; if (OB_FAIL(ret)) { } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, *arr_val, bret))) { LOG_WARN("array contains failed", K(ret)); } else { res_vec->set_bool(idx, bret); eval_flags.set(idx); } } } return ret; } int ObExprArrayContains::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const { int ret = OB_SUCCESS; UNUSED(raw_expr); if (rt_expr.arg_cnt_ != 2 || OB_ISNULL(rt_expr.args_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("count of children is not 2 or children is null", K(ret), K(rt_expr.arg_cnt_), K(rt_expr.args_)); } else if (OB_ISNULL(rt_expr.args_[0]) || OB_ISNULL(rt_expr.args_[1])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child is null", K(ret), K(rt_expr.args_[0]), K(rt_expr.args_[1])); } else { rt_expr.eval_func_ = NULL; rt_expr.may_not_need_raw_check_ = false; rt_expr.extra_ = raw_expr.get_extra(); uint32_t p1 = rt_expr.extra_ == 1 ? 0 : 1; uint32_t p0 = rt_expr.extra_ == 1 ? 1 : 0; const ObObjType right_type = rt_expr.args_[p1]->datum_meta_.type_; ObObjTypeClass right_tc = ob_obj_type_class(right_type); if (right_tc == ObNullTC) { // use array element type ObExecContext *exec_ctx = expr_cg_ctx.session_->get_cur_exec_ctx(); const uint16_t sub_id = rt_expr.args_[p0]->obj_meta_.get_subschema_id(); ObObjType elem_type; uint32_t unused; bool is_vec = false; if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, sub_id, elem_type, unused, is_vec))) { LOG_WARN("failed to get collection elem type", K(ret), K(sub_id)); } else { right_tc = ob_obj_type_class(elem_type); } } if OB_SUCC(ret) { switch (right_tc) { case ObIntTC: rt_expr.eval_func_ = eval_array_contains_int64_t; rt_expr.eval_batch_func_ = eval_array_contains_batch_int64_t; rt_expr.eval_vector_func_ = eval_array_contains_vector_int64_t; break; case ObFloatTC: rt_expr.eval_func_ = eval_array_contains_float; rt_expr.eval_batch_func_ = eval_array_contains_batch_float; rt_expr.eval_vector_func_ = eval_array_contains_vector_float; break; case ObDoubleTC: rt_expr.eval_func_ = eval_array_contains_double; rt_expr.eval_batch_func_ = eval_array_contains_batch_double; rt_expr.eval_vector_func_ = eval_array_contains_vector_double; break; case ObStringTC: rt_expr.eval_func_ = eval_array_contains_ObString; rt_expr.eval_batch_func_ = eval_array_contains_batch_ObString; rt_expr.eval_vector_func_ = eval_array_contains_vector_ObString; break; case ObNullTC: case ObCollectionSQLTC: rt_expr.eval_func_ = eval_array_contains_array; rt_expr.eval_batch_func_ = eval_array_contains_array_batch; rt_expr.eval_vector_func_ = eval_array_contains_array_vector; break; default : ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("invalid type", K(ret), K(right_type)); } } } return OB_SUCCESS; } } // namespace sql } // namespace oceanbase