/** * 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_cmp_func.h" #include "share/datum/ob_datum_cmp_func_def.h" #include "share/datum/ob_datum_funcs.h" #include "sql/engine/expr/ob_expr_operator.h" #include "sql/engine/expr/ob_batch_eval_util.h" #include "share/ob_lob_access_utils.h" namespace oceanbase { namespace sql { using namespace common; #define IS_FIXED_DOUBLE \ !is_oracle_mode && \ ob_is_double_type(type1) && ob_is_double_type(type2) && \ SCALE_UNKNOWN_YET < scale1 && SCALE_UNKNOWN_YET < scale2 && \ MAX(scale1, scale2) <= OB_MAX_DOUBLE_FLOAT_SCALE \ template constexpr int get_cmp_ret(const int) { return 0; }; template <> constexpr int get_cmp_ret (const int ret) { return ret == 0; } template <> constexpr int get_cmp_ret (const int ret) { return ret <= 0; } template <> constexpr int get_cmp_ret (const int ret) { return ret < 0; } template <> constexpr int get_cmp_ret (const int ret) { return ret >= 0; } template <> constexpr int get_cmp_ret (const int ret) { return ret > 0; } template <> constexpr int get_cmp_ret (const int ret) { return ret != 0; } template <> constexpr int get_cmp_ret (const int ret) { return ret; } template int def_relational_eval_func(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { int ret = OB_SUCCESS; ObDatum *l = NULL; ObDatum *r = NULL; bool contain_null = false; if (OB_FAIL(ObRelationalExprOperator::get_comparator_operands( expr, ctx, l, r, expr_datum, contain_null))) { LOG_WARN("failed to eval args", K(ret)); } else if (!contain_null) { if (OB_ISNULL(l) || OB_ISNULL(r)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid operands", K(ret), K(l), K(r)); } else { ret = DatumFunc()(expr_datum, *l, *r); } } return ret; }; template int def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_DECL, Args &...args) { int ret = OB_SUCCESS; const static bool short_circuit = true; if (OB_FAIL(binary_operand_batch_eval(expr, ctx, skip, size, short_circuit))) { LOG_WARN("binary operand batch evaluate failed", K(ret), K(expr)); } else { ret = call_functor_with_arg_iter< ObWrapArithOpNullCheck, ObDoArithBatchEval>(BATCH_EVAL_FUNC_ARG_LIST, args...); } return ret; } template int def_oper_cmp_func(ObDatum &res, const ObDatum &l, const ObDatum &r) { int cmp_ret = 0; int ret = DatumFunc::cmp(l, r, cmp_ret); if (OB_FAIL(ret)) { LOG_WARN("fail to compare", K(ret)); } else { res.set_int(get_cmp_ret(cmp_ret)); } return ret; } struct ObDummyRelationalFunc { inline static int eval(const ObExpr &, ObEvalCtx &, ObDatum &) { return 0;}; inline static int eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { UNUSEDx(BATCH_EVAL_FUNC_ARG_LIST); return 0; } }; template struct ObRelationalTypeFunc {}; template struct ObRelationalTypeFunc : public ObDummyRelationalFunc {}; template struct ObRelationalTypeFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } inline static int eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST); } }; template struct ObRelationalTCFunc {}; template struct ObRelationalTCFunc : public ObDummyRelationalFunc {}; template struct ObRelationalTCFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } inline static int eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST); } }; template struct ObRelationalStrFunc{}; template struct ObRelationalStrFunc : ObDummyRelationalFunc {}; template struct ObRelationalStrFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } // defined in ObRelationalExtraFunc // inline static int eval_batch(BATCH_EVAL_FUNC_ARG_DECL) // { // return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST); // } }; template struct ObRelationFixedDoubleFunc{}; template struct ObRelationFixedDoubleFunc : ObDummyRelationalFunc {}; template struct ObRelationFixedDoubleFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } inline static int eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST); } }; template struct ObRelationalTextFunc{}; template struct ObRelationalTextFunc : ObDummyRelationalFunc {}; template struct ObRelationalTextFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } }; template struct ObRelationalTextStrFunc{}; template struct ObRelationalTextStrFunc : ObDummyRelationalFunc {}; template struct ObRelationalTextStrFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } }; template struct ObRelationalStrTextFunc{}; template struct ObRelationalStrTextFunc : ObDummyRelationalFunc {}; template struct ObRelationalStrTextFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } }; template struct ObRelationalJsonFunc{}; template struct ObRelationalJsonFunc : ObDummyRelationalFunc {}; template struct ObRelationalJsonFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } }; template struct ObRelationalGeoFunc{}; template struct ObRelationalGeoFunc : ObDummyRelationalFunc {}; template struct ObRelationalGeoFunc { struct DatumCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r) const { return def_oper_cmp_func, CMP_OP>(res, l, r); } }; inline static int eval(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { return def_relational_eval_func(expr, ctx, expr_datum); } }; // define null, extend, string evaluate batch functions. template struct ObRelationalExtraFunc { struct NullExtendCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObExpr &expr) const { int ret = OB_SUCCESS; ObObjType lt = expr.args_[0]->datum_meta_.type_; ObObjType rt = expr.args_[1]->datum_meta_.type_; int cmp_ret = 0; if (ObExtendType == lt && ObExtendType == rt) { ret = datum_cmp::ObDatumTCCmp::cmp(l, r, cmp_ret); } else if (ObExtendType == lt) { ret = datum_cmp::ObDatumTCCmp::cmp(l, r, cmp_ret); } else if (ObExtendType == rt) { ret = datum_cmp::ObDatumTCCmp::cmp(r, l, cmp_ret); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("only extend type should reach here", K(ret)); } if (OB_SUCC(ret)) { res.set_int(get_cmp_ret(cmp_ret)); } return ret; } }; inline static int null_extend_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, expr); } struct StrCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObCollationType cs_type, bool with_end_space) const { int ret = OB_SUCCESS; int cmp_ret = ObCharset::strcmpsp(cs_type, l.ptr_, l.len_, r.ptr_, r.len_, with_end_space); res.set_int(get_cmp_ret(cmp_ret > 0 ? 1 : (cmp_ret < 0 ? -1 : 0))); return ret; } }; inline static int str_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { bool with_end_space = is_calc_with_end_space( expr.args_[0]->datum_meta_.type_, expr.args_[1]->datum_meta_.type_, lib::is_oracle_mode(), expr.args_[0]->datum_meta_.cs_type_, expr.args_[1]->datum_meta_.cs_type_); return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, expr.args_[0]->datum_meta_.cs_type_, with_end_space); } struct TextCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObCollationType cs_type, bool with_end_space) const { int ret = OB_SUCCESS; ObString l_data; ObString r_data; common::ObArenaAllocator allocator(ObModIds::OB_LOB_READER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); ObTextStringIter l_instr_iter(ObLongTextType, cs_type, l.get_string(), true); ObTextStringIter r_instr_iter(ObLongTextType, cs_type, r.get_string(), true); if (OB_FAIL(l_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "Lob: init left text str iter failed", K(ret), K(cs_type), K(l)); } else if (OB_FAIL(l_instr_iter.get_full_data(l_data))) { COMMON_LOG(WARN, "Lob: get left text str iter full data failed ", K(ret), K(cs_type), K(l_instr_iter)); } else if (OB_FAIL(r_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "Lob: init right text str iter failed", K(ret), K(ret), K(r)); } else if (OB_FAIL(r_instr_iter.get_full_data(r_data))) { COMMON_LOG(WARN, "Lob: get right text str iter full data failed ", K(ret), K(cs_type), K(r_instr_iter)); } else { int cmp_ret = ObCharset::strcmpsp(cs_type, l_data.ptr(), l_data.length(), r_data.ptr(), r_data.length(), with_end_space); res.set_int(get_cmp_ret(cmp_ret > 0 ? 1 : (cmp_ret < 0 ? -1 : 0))); } return ret; } }; inline static int text_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { bool with_end_space = is_calc_with_end_space( expr.args_[0]->datum_meta_.type_, expr.args_[1]->datum_meta_.type_, lib::is_oracle_mode(), expr.args_[0]->datum_meta_.cs_type_, expr.args_[1]->datum_meta_.cs_type_); return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, expr.args_[0]->datum_meta_.cs_type_, with_end_space); } struct TextStrCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObCollationType cs_type, bool with_end_space) const { int ret = OB_SUCCESS; ObString l_data; common::ObArenaAllocator allocator(ObModIds::OB_LOB_READER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); ObTextStringIter l_instr_iter(ObLongTextType, cs_type, l.get_string(), true); if (OB_FAIL(l_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "Lob: init left text str iter failed", K(ret), K(cs_type), K(l)); } else if (OB_FAIL(l_instr_iter.get_full_data(l_data))) { COMMON_LOG(WARN, "Lob: get left text str iter full data failed ", K(ret), K(cs_type), K(l_instr_iter)); } else { int cmp_ret = ObCharset::strcmpsp(cs_type, l_data.ptr(), l_data.length(), r.ptr_, r.len_, with_end_space); res.set_int(get_cmp_ret(cmp_ret > 0 ? 1 : (cmp_ret < 0 ? -1 : 0))); } return ret; } }; inline static int text_str_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { bool with_end_space = is_calc_with_end_space( expr.args_[0]->datum_meta_.type_, expr.args_[1]->datum_meta_.type_, lib::is_oracle_mode(), expr.args_[0]->datum_meta_.cs_type_, expr.args_[1]->datum_meta_.cs_type_); return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, expr.args_[0]->datum_meta_.cs_type_, with_end_space); } struct StrTextCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObCollationType cs_type, bool with_end_space) const { int ret = OB_SUCCESS; ObString r_data; common::ObArenaAllocator allocator(ObModIds::OB_LOB_READER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); ObTextStringIter r_instr_iter(ObLongTextType, cs_type, r.get_string(), true); if (OB_FAIL(r_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "Lob: init right text str iter failed", K(ret), K(ret), K(r)); } else if (OB_FAIL(r_instr_iter.get_full_data(r_data))) { COMMON_LOG(WARN, "Lob: get right text str iter full data failed ", K(ret), K(cs_type), K(r_instr_iter)); } else { int cmp_ret = ObCharset::strcmpsp(cs_type, l.ptr_, l.len_, r_data.ptr(), r_data.length(), with_end_space); res.set_int(get_cmp_ret(cmp_ret > 0 ? 1 : (cmp_ret < 0 ? -1 : 0))); } return ret; } }; inline static int str_text_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { bool with_end_space = is_calc_with_end_space( expr.args_[0]->datum_meta_.type_, expr.args_[1]->datum_meta_.type_, lib::is_oracle_mode(), expr.args_[0]->datum_meta_.cs_type_, expr.args_[1]->datum_meta_.cs_type_); return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, expr.args_[0]->datum_meta_.cs_type_, with_end_space); } struct JsonCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, bool has_lob_header) const { int ret = OB_SUCCESS; int result = 0; ObString l_data; ObString r_data; common::ObArenaAllocator allocator(ObModIds::OB_LOB_READER); ObTextStringIter l_instr_iter(ObJsonType, CS_TYPE_BINARY, l.get_string(), has_lob_header); ObTextStringIter r_instr_iter(ObJsonType, CS_TYPE_BINARY, r.get_string(), has_lob_header); if (OB_FAIL(l_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "LobDebug: init left lob str iter failed", K(ret), K(l)); } else if (OB_FAIL(l_instr_iter.get_full_data(l_data))) { COMMON_LOG(WARN, "LobDebug: get left lob str iter full data failed ", K(ret), K(l_instr_iter)); } else if (OB_FAIL(r_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "LobDebug: init right lob str iter failed", K(ret), K(ret), K(r)); } else if (OB_FAIL(r_instr_iter.get_full_data(r_data))) { COMMON_LOG(WARN, "LobDebug: get right lob str iter full data failed ", K(ret), K(r_instr_iter)); } else { ObJsonBin j_bin_l(l_data.ptr(), l_data.length()); ObJsonBin j_bin_r(r_data.ptr(), r_data.length()); ObIJsonBase *j_base_l = &j_bin_l; ObIJsonBase *j_base_r = &j_bin_r; if (OB_FAIL(j_bin_l.reset_iter())) { COMMON_LOG(WARN, "fail to reset left json bin iter", K(ret), K(l.len_)); } else if (OB_FAIL(j_bin_r.reset_iter())) { COMMON_LOG(WARN, "fail to reset right json bin iter", K(ret), K(r.len_)); } else if (OB_FAIL(j_base_l->compare(*j_base_r, result))) { COMMON_LOG(WARN, "fail to compare json", K(ret), K(*j_base_l), K(*j_base_r)); } else { res.set_int(get_cmp_ret(result > 0 ? 1 : (result < 0 ? -1 : 0))); } } return ret; } }; inline static int json_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { bool has_lob_header = expr.args_[0]->obj_meta_.has_lob_header(); return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, has_lob_header); } struct GeoCmp { int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, bool has_lob_header) const { int ret = OB_SUCCESS; int result = 0; ObString l_data; ObString r_data; common::ObArenaAllocator allocator(ObModIds::OB_LOB_READER); ObTextStringIter l_instr_iter(ObJsonType, CS_TYPE_BINARY, l.get_string(), has_lob_header); ObTextStringIter r_instr_iter(ObJsonType, CS_TYPE_BINARY, r.get_string(), has_lob_header); if (OB_FAIL(l_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "LobDebug: init left lob str iter failed", K(ret), K(l)); } else if (OB_FAIL(l_instr_iter.get_full_data(l_data))) { COMMON_LOG(WARN, "LobDebug: get left lob str iter full data failed ", K(ret), K(l_instr_iter)); } else if (OB_FAIL(r_instr_iter.init(0, NULL, &allocator))) { COMMON_LOG(WARN, "LobDebug: init right lob str iter failed", K(ret), K(ret), K(r)); } else if (OB_FAIL(r_instr_iter.get_full_data(r_data))) { COMMON_LOG(WARN, "LobDebug: get right lob str iter full data failed ", K(ret), K(r_instr_iter)); } else { result = ObCharset::strcmpsp(CS_TYPE_BINARY, l_data.ptr(), l_data.length(), r_data.ptr(), r_data.length(), false); res.set_int(get_cmp_ret(result > 0 ? 1 : (result < 0 ? -1 : 0))); } return ret; } }; inline static int geo_eval_batch(BATCH_EVAL_FUNC_ARG_DECL) { bool has_lob_header = expr.args_[0]->obj_meta_.has_lob_header(); return def_relational_eval_batch_func(BATCH_EVAL_FUNC_ARG_LIST, has_lob_header); } }; static ObExpr::EvalBatchFunc EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_STR_CMP_FUNCS[CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_TEXT_CMP_FUNCS[CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_TEXT_STR_CMP_FUNCS[CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_STR_TEXT_CMP_FUNCS[CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_JSON_CMP_FUNCS[CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_GEO_CMP_FUNCS[CO_MAX]; static ObExpr::EvalFunc EVAL_TYPE_CMP_FUNCS[ObMaxType][ObMaxType][CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_TYPE_CMP_FUNCS[ObMaxType][ObMaxType][CO_MAX]; static ObDatumCmpFuncType DATUM_TYPE_CMP_FUNCS[ObMaxType][ObMaxType]; // TODO serialize static ObExpr::EvalFunc EVAL_TC_CMP_FUNCS[ObMaxTC][ObMaxTC][CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_TC_CMP_FUNCS[ObMaxTC][ObMaxTC][CO_MAX]; static ObDatumCmpFuncType DATUM_TC_CMP_FUNCS[ObMaxTC][ObMaxTC]; static ObExpr::EvalFunc EVAL_STR_CMP_FUNCS[CS_TYPE_MAX][CO_MAX][2]; static ObDatumCmpFuncType DATUM_STR_CMP_FUNCS[CS_TYPE_MAX][2]; static ObExpr::EvalFunc EVAL_TEXT_CMP_FUNCS[CS_TYPE_MAX][CO_MAX][2]; static ObDatumCmpFuncType DATUM_TEXT_CMP_FUNCS[CS_TYPE_MAX][2]; static ObExpr::EvalFunc EVAL_TEXT_STR_CMP_FUNCS[CS_TYPE_MAX][CO_MAX][2]; static ObDatumCmpFuncType DATUM_TEXT_STR_CMP_FUNCS[CS_TYPE_MAX][2]; static ObExpr::EvalFunc EVAL_STR_TEXT_CMP_FUNCS[CS_TYPE_MAX][CO_MAX][2]; static ObDatumCmpFuncType DATUM_STR_TEXT_CMP_FUNCS[CS_TYPE_MAX][2]; static ObExpr::EvalFunc EVAL_JSON_CMP_FUNCS[CO_MAX][2]; static ObDatumCmpFuncType DATUM_JSON_CMP_FUNCS[2]; static ObExpr::EvalFunc EVAL_GEO_CMP_FUNCS[CO_MAX][2]; static ObDatumCmpFuncType DATUM_GEO_CMP_FUNCS[2]; static ObExpr::EvalFunc EVAL_FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE][CO_MAX]; static ObExpr::EvalBatchFunc EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE][CO_MAX]; static ObDatumCmpFuncType DATUM_FIXED_DOUBLE_CMP_FUNCS[OB_NOT_FIXED_SCALE]; template struct ExtraExprCmpIniter { static void init_array() { using Func = ObRelationalExtraFunc(X)>; EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[X] = Func::null_extend_eval_batch; EVAL_BATCH_STR_CMP_FUNCS[X] = Func::str_eval_batch; EVAL_BATCH_TEXT_CMP_FUNCS[X] = Func::text_eval_batch; EVAL_BATCH_TEXT_STR_CMP_FUNCS[X] = Func::text_str_eval_batch; EVAL_BATCH_STR_TEXT_CMP_FUNCS[X] = Func::str_text_eval_batch; EVAL_BATCH_JSON_CMP_FUNCS[X] = Func::json_eval_batch; EVAL_BATCH_GEO_CMP_FUNCS[X] = Func::geo_eval_batch; } }; int g_init_extra_expr_ret = ObArrayConstIniter::init(); template struct TypeExprCmpFuncIniter { using Def = datum_cmp::ObDatumTypeCmp< static_cast(X), static_cast(Y)>; template using EvalCmp = ObRelationalTypeFunc(X), static_cast(Y), cmp_op>; static void init_array() { auto &funcs = EVAL_TYPE_CMP_FUNCS; funcs[X][Y][CO_LE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_LT] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_EQ] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_GE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_GT] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_NE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_CMP] = Def::defined_ ? &EvalCmp::eval : NULL; auto &batch_funcs = EVAL_BATCH_TYPE_CMP_FUNCS; batch_funcs[X][Y][CO_LE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_LT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_EQ] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_GE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_GT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_NE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; // CO_CMP only used in T_FUN_SYS_STRCMP, set to NULL batch_funcs[X][Y][CO_CMP] = NULL; DATUM_TYPE_CMP_FUNCS[X][Y] = Def::defined_ ? &Def::cmp : NULL; } }; template struct TCExprCmpFuncIniter { using Def = datum_cmp::ObDatumTCCmp< static_cast(X), static_cast(Y)>; template using EvalCmp = ObRelationalTCFunc(X), static_cast(Y), cmp_op>; static void init_array() { auto &funcs = EVAL_TC_CMP_FUNCS; funcs[X][Y][CO_LE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_LT] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_EQ] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_GE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_GT] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_NE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][Y][CO_CMP] = Def::defined_ ? &EvalCmp::eval : NULL; auto &batch_funcs = EVAL_BATCH_TC_CMP_FUNCS; if (X == ObNullTC || X == ObExtendTC || Y == ObNullTC || Y == ObExtendTC) { batch_funcs[X][Y][CO_LE] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_LE]; batch_funcs[X][Y][CO_LT] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_LT]; batch_funcs[X][Y][CO_EQ] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_EQ]; batch_funcs[X][Y][CO_GE] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_GE]; batch_funcs[X][Y][CO_GT] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_GT]; batch_funcs[X][Y][CO_NE] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_NE]; batch_funcs[X][Y][CO_CMP] = EVAL_BATCH_NULL_EXTEND_CMP_FUNCS[CO_CMP]; } else { batch_funcs[X][Y][CO_LE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_LT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_EQ] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_GE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_GT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][Y][CO_NE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; // CO_CMP only used in T_FUN_SYS_STRCMP, set to NULL batch_funcs[X][Y][CO_CMP] = NULL; } DATUM_TC_CMP_FUNCS[X][Y] = Def::defined_ ? &Def::cmp : NULL; } }; template struct StrExprFuncIniter { using Def = datum_cmp::ObDatumStrCmp(X), false>; template using EvalCmp = ObRelationalStrFunc(X), WITH_END_SPACE, static_cast(Y)>; static void init_array() { EVAL_STR_CMP_FUNCS[X][Y][0] = Def::defined_ ? EvalCmp<0>::eval : NULL; EVAL_STR_CMP_FUNCS[X][Y][1] = Def::defined_ ? EvalCmp<1>::eval : NULL; } }; template struct TextExprFuncIniter { using Def = datum_cmp::ObDatumTextCmp(X), false>; template using EvalCmp = ObRelationalTextFunc(X), WITH_END_SPACE, static_cast(Y)>; static void init_array() { EVAL_TEXT_CMP_FUNCS[X][Y][0] = Def::defined_ ? EvalCmp<0>::eval : NULL; EVAL_TEXT_CMP_FUNCS[X][Y][1] = Def::defined_ ? EvalCmp<1>::eval : NULL; } }; template struct TextStrExprFuncIniter { using Def = datum_cmp::ObDatumTextStringCmp(X), false>; template using EvalCmp = ObRelationalTextStrFunc(X), WITH_END_SPACE, static_cast(Y)>; static void init_array() { EVAL_TEXT_STR_CMP_FUNCS[X][Y][0] = Def::defined_ ? EvalCmp<0>::eval : NULL; EVAL_TEXT_STR_CMP_FUNCS[X][Y][1] = Def::defined_ ? EvalCmp<1>::eval : NULL; } }; template struct StrTextExprFuncIniter { using Def = datum_cmp::ObDatumStringTextCmp(X), false>; template using EvalCmp = ObRelationalStrTextFunc(X), WITH_END_SPACE, static_cast(Y)>; static void init_array() { EVAL_STR_TEXT_CMP_FUNCS[X][Y][0] = Def::defined_ ? EvalCmp<0>::eval : NULL; EVAL_STR_TEXT_CMP_FUNCS[X][Y][1] = Def::defined_ ? EvalCmp<1>::eval : NULL; } }; template struct DatumStrExprCmpIniter { template using DatumCmp = datum_cmp::ObDatumStrCmp(X), WITH_END_SPACE>; using Def = datum_cmp::ObDatumStrCmp(X), false>; static void init_array() { DATUM_STR_CMP_FUNCS[X][0] = Def::defined_ ? DatumCmp<0>::cmp : NULL; DATUM_STR_CMP_FUNCS[X][1] = Def::defined_ ? DatumCmp<1>::cmp : NULL; } }; template struct DatumTextExprCmpIniter { template using DatumCmp = datum_cmp::ObDatumTextCmp(X), WITH_END_SPACE>; using Def = datum_cmp::ObDatumTextCmp(X), false>; static void init_array() { DATUM_TEXT_CMP_FUNCS[X][0] = Def::defined_ ? DatumCmp<0>::cmp : NULL; DATUM_TEXT_CMP_FUNCS[X][1] = Def::defined_ ? DatumCmp<1>::cmp : NULL; } }; template struct DatumTextStrExprCmpIniter { template using DatumCmp = datum_cmp::ObDatumTextStringCmp(X), WITH_END_SPACE>; using Def = datum_cmp::ObDatumTextStringCmp(X), false>; static void init_array() { DATUM_TEXT_STR_CMP_FUNCS[X][0] = Def::defined_ ? DatumCmp<0>::cmp : NULL; DATUM_TEXT_STR_CMP_FUNCS[X][1] = Def::defined_ ? DatumCmp<1>::cmp : NULL; } }; template struct DatumStrTextExprCmpIniter { template using DatumCmp = datum_cmp::ObDatumStringTextCmp(X), WITH_END_SPACE>; using Def = datum_cmp::ObDatumStringTextCmp(X), false>; static void init_array() { DATUM_STR_TEXT_CMP_FUNCS[X][0] = Def::defined_ ? DatumCmp<0>::cmp : NULL; DATUM_STR_TEXT_CMP_FUNCS[X][1] = Def::defined_ ? DatumCmp<1>::cmp : NULL; } }; template struct JsonExprFuncIniter { using Def = datum_cmp::ObDatumJsonCmp; template using EvalCmp = ObRelationalJsonFunc(Y)>; static void init_array() { EVAL_JSON_CMP_FUNCS[Y][0] = Def::defined_ ? EvalCmp<0>::eval : NULL; EVAL_JSON_CMP_FUNCS[Y][1] = Def::defined_ ? EvalCmp<1>::eval : NULL; } }; template struct DatumJsonExprCmpIniter { template using DatumCmp = datum_cmp::ObDatumJsonCmp; using Def = datum_cmp::ObDatumJsonCmp; static void init_array() { DATUM_JSON_CMP_FUNCS[0] = Def::defined_ ? DatumCmp<0>::cmp : NULL; DATUM_JSON_CMP_FUNCS[1] = Def::defined_ ? DatumCmp<1>::cmp : NULL; } }; template struct GeoExprFuncIniter { using Def = datum_cmp::ObDatumGeoCmp; template using EvalCmp = ObRelationalGeoFunc(Y)>; static void init_array() { EVAL_GEO_CMP_FUNCS[Y][0] = Def::defined_ ? EvalCmp<0>::eval : NULL; EVAL_GEO_CMP_FUNCS[Y][1] = Def::defined_ ? EvalCmp<1>::eval : NULL; } }; template struct DatumGeoExprCmpIniter { template using DatumCmp = datum_cmp::ObDatumGeoCmp; using Def = datum_cmp::ObDatumGeoCmp; static void init_array() { DATUM_GEO_CMP_FUNCS[0] = Def::defined_ ? DatumCmp<0>::cmp : NULL; DATUM_GEO_CMP_FUNCS[1] = Def::defined_ ? DatumCmp<1>::cmp : NULL; } }; int g_init_type_ret = Ob2DArrayConstIniter::init(); int g_init_tc_ret = Ob2DArrayConstIniter::init(); int g_init_str_ret = Ob2DArrayConstIniter::init(); int g_init_datum_str_ret = ObArrayConstIniter::init(); int g_init_text_ret = Ob2DArrayConstIniter::init(); int g_init_datum_text_ret = ObArrayConstIniter::init(); int g_init_text_str_ret = Ob2DArrayConstIniter::init(); int g_init_datum_text_str_ret = ObArrayConstIniter::init(); int g_init_str_text_ret = Ob2DArrayConstIniter::init(); int g_init_str_datum_text_ret = ObArrayConstIniter::init(); int g_init_json_ret = ObArrayConstIniter::init(); int g_init_json_datum_ret = ObArrayConstIniter<1, DatumJsonExprCmpIniter>::init(); int g_init_geo_ret = ObArrayConstIniter::init(); int g_init_geo_datum_ret = ObArrayConstIniter<1, DatumGeoExprCmpIniter>::init(); template struct FixedDoubleCmpFuncIniter { using Def = datum_cmp::ObFixedDoubleCmp(X)>; template using EvalCmp = ObRelationFixedDoubleFunc(X), cmp_op>; static void init_array() { auto &funcs = EVAL_FIXED_DOUBLE_CMP_FUNCS; funcs[X][CO_LE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][CO_LT] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][CO_EQ] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][CO_GE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][CO_GT] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][CO_NE] = Def::defined_ ? &EvalCmp::eval : NULL; funcs[X][CO_CMP] = Def::defined_ ? &EvalCmp::eval : NULL; auto &batch_funcs = EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS; batch_funcs[X][CO_LE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][CO_LT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][CO_EQ] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][CO_GE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][CO_GT] = Def::defined_ ? &EvalCmp::eval_batch : NULL; batch_funcs[X][CO_NE] = Def::defined_ ? &EvalCmp::eval_batch : NULL; // CO_CMP only used in T_FUN_SYS_STRCMP, set to NULL batch_funcs[X][CO_CMP] = NULL; DATUM_FIXED_DOUBLE_CMP_FUNCS[X] = Def::defined_ ? &Def::cmp : NULL; } }; int g_init_fixed_double_ret = ObArrayConstIniter::init(); static int64_t fill_type_with_tc_eval_func(void) { int64_t cnt = 0; for (int64_t i = 0; i < ObMaxType; i++) { ObObjTypeClass i_tc = ob_obj_type_class((ObObjType)i); for (int64_t j = 0; j < ObMaxType; j++) { ObObjTypeClass j_tc = ob_obj_type_class((ObObjType)j); if (NULL == EVAL_TYPE_CMP_FUNCS[i][j][0]) { const int64_t size = sizeof(void *) * CO_MAX; memcpy(&EVAL_TYPE_CMP_FUNCS[i][j][0], &EVAL_TC_CMP_FUNCS[i_tc][j_tc][0], size); memcpy(&EVAL_BATCH_TYPE_CMP_FUNCS[i][j][0], &EVAL_BATCH_TC_CMP_FUNCS[i_tc][j_tc][0], size); cnt++; } if (NULL == DATUM_TYPE_CMP_FUNCS[i][j]) { DATUM_TYPE_CMP_FUNCS[i][j] = DATUM_TC_CMP_FUNCS[i_tc][j_tc]; cnt++; } } } return cnt; } int64_t g_fill_type_with_tc_eval_func = fill_type_with_tc_eval_func(); ObExpr::EvalFunc ObExprCmpFuncsHelper::get_eval_expr_cmp_func(const ObObjType type1, const ObObjType type2, const ObScale scale1, const ObScale scale2, const ObCmpOp cmp_op, const bool is_oracle_mode, const ObCollationType cs_type, const bool has_lob_header) { OB_ASSERT(type1 >= ObNullType && type1 < ObMaxType); OB_ASSERT(type2 >= ObNullType && type2 < ObMaxType); OB_ASSERT(cmp_op >= CO_EQ && cmp_op <= CO_MAX); ObObjTypeClass tc1 = ob_obj_type_class(type1); ObObjTypeClass tc2 = ob_obj_type_class(type2); ObExpr::EvalFunc func_ptr = NULL; if (OB_UNLIKELY(ob_is_invalid_cmp_op(cmp_op)) || OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || OB_UNLIKELY(ob_is_invalid_obj_tc(tc2)))) { func_ptr = NULL; } else if (tc1 == ObJsonTC && tc2 == ObJsonTC) { func_ptr = EVAL_JSON_CMP_FUNCS[cmp_op][has_lob_header]; } else if (tc1 == ObGeometryTC && tc2 == ObGeometryTC) { func_ptr = EVAL_GEO_CMP_FUNCS[cmp_op][has_lob_header]; } else if (IS_FIXED_DOUBLE) { func_ptr = EVAL_FIXED_DOUBLE_CMP_FUNCS[MAX(scale1, scale2)][cmp_op]; } else if (tc1 == ObUserDefinedSQLTC || tc2 == ObUserDefinedSQLTC) { func_ptr = NULL; //? } else if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { func_ptr = EVAL_TYPE_CMP_FUNCS[type1][type2][cmp_op]; } else { OB_ASSERT(cs_type > CS_TYPE_INVALID && cs_type < CS_TYPE_MAX); int64_t calc_with_end_space_idx = (is_calc_with_end_space(type1, type2, is_oracle_mode, cs_type, cs_type) ? 1 : 0); if (has_lob_header && (ob_is_large_text(type1) || ob_is_large_text(type2))) { if (ob_is_large_text(type1) && ob_is_large_text(type2)) { func_ptr = EVAL_TEXT_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]; } else if (ob_is_large_text(type1)) { // type2 not large text func_ptr = EVAL_TEXT_STR_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]; } else { // type1 not large text func_ptr = EVAL_STR_TEXT_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]; } } else { // no lob header or tinytext use original str cmp func func_ptr = EVAL_STR_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]; } } return func_ptr; } ObExpr::EvalBatchFunc ObExprCmpFuncsHelper::get_eval_batch_expr_cmp_func( const ObObjType type1, const ObObjType type2, const ObScale scale1, const ObScale scale2, const ObCmpOp cmp_op, const bool is_oracle_mode, const ObCollationType cs_type, const bool has_lob_header) { OB_ASSERT(type1 >= ObNullType && type1 < ObMaxType); OB_ASSERT(type2 >= ObNullType && type2 < ObMaxType); OB_ASSERT(cmp_op >= CO_EQ && cmp_op <= CO_MAX); ObObjTypeClass tc1 = ob_obj_type_class(type1); ObObjTypeClass tc2 = ob_obj_type_class(type2); ObExpr::EvalBatchFunc func_ptr = NULL; if (OB_UNLIKELY(ob_is_invalid_cmp_op(cmp_op)) || OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || OB_UNLIKELY(ob_is_invalid_obj_tc(tc2)))) { func_ptr = NULL; } else if (type1 == ObJsonType && type2 == ObJsonType) { if (NULL != EVAL_JSON_CMP_FUNCS[cmp_op][has_lob_header]) { func_ptr = EVAL_BATCH_JSON_CMP_FUNCS[cmp_op]; } } else if (tc1 == ObGeometryTC && tc2 == ObGeometryTC) { if (NULL != EVAL_GEO_CMP_FUNCS[cmp_op][has_lob_header]) { func_ptr = EVAL_BATCH_GEO_CMP_FUNCS[cmp_op]; } } else if (IS_FIXED_DOUBLE) { func_ptr = EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS[MAX(scale1, scale2)][cmp_op]; } else if (tc1 == ObUserDefinedSQLTC || tc2 == ObUserDefinedSQLTC) { func_ptr = NULL; //? } else if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { func_ptr = EVAL_BATCH_TYPE_CMP_FUNCS[type1][type2][cmp_op]; } else { OB_ASSERT(cs_type > CS_TYPE_INVALID && cs_type < CS_TYPE_MAX); int64_t calc_with_end_space_idx = (is_calc_with_end_space(type1, type2, is_oracle_mode, cs_type, cs_type) ? 1 : 0); if (has_lob_header && (ob_is_large_text(type1) || ob_is_large_text(type2))) { if (ob_is_large_text(type1) && ob_is_large_text(type2)) { if (NULL != EVAL_TEXT_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]) { func_ptr = EVAL_BATCH_TEXT_CMP_FUNCS[cmp_op]; } } else if (ob_is_large_text(type1)) { // type2 not large text if (NULL != EVAL_TEXT_STR_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]) { func_ptr = EVAL_BATCH_TEXT_STR_CMP_FUNCS[cmp_op]; } } else { // type1 not large text if (NULL != EVAL_STR_TEXT_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]) { func_ptr = EVAL_BATCH_STR_TEXT_CMP_FUNCS[cmp_op]; } } } else { // no lob header or tinytext use original str cmp func if (NULL != EVAL_STR_CMP_FUNCS[cs_type][cmp_op][calc_with_end_space_idx]) { func_ptr = EVAL_BATCH_STR_CMP_FUNCS[cmp_op]; } } } return func_ptr; } DatumCmpFunc ObExprCmpFuncsHelper::get_datum_expr_cmp_func(const ObObjType type1, const ObObjType type2, const ObScale scale1, const ObScale scale2, const bool is_oracle_mode, const ObCollationType cs_type, const bool has_lob_header) { OB_ASSERT(type1 >= ObNullType && type1 < ObMaxType); OB_ASSERT(type2 >= ObNullType && type2 < ObMaxType); ObObjTypeClass tc1 = ob_obj_type_class(type1); ObObjTypeClass tc2 = ob_obj_type_class(type2); ObDatumCmpFuncType func_ptr = NULL; if (type1 == ObJsonType && type2 == ObJsonType) { func_ptr = DATUM_JSON_CMP_FUNCS[has_lob_header]; } else if (type1 == ObGeometryType && type2 == ObGeometryType) { func_ptr = DATUM_GEO_CMP_FUNCS[has_lob_header]; } else if (IS_FIXED_DOUBLE) { func_ptr = DATUM_FIXED_DOUBLE_CMP_FUNCS[MAX(scale1, scale2)]; } else if (tc1 == ObUserDefinedSQLTC || tc2 == ObUserDefinedSQLTC) { func_ptr = NULL; //? } else if (!ObDatumFuncs::is_string_type(type1) || !ObDatumFuncs::is_string_type(type2)) { func_ptr = DATUM_TYPE_CMP_FUNCS[type1][type2]; if (NULL == func_ptr) { func_ptr = DATUM_TC_CMP_FUNCS[tc1][tc2]; } } else { OB_ASSERT(cs_type > CS_TYPE_INVALID && cs_type < CS_TYPE_MAX); int64_t calc_with_end_space_idx = (is_calc_with_end_space(type1, type2, is_oracle_mode, cs_type, cs_type) ? 1 : 0); if (has_lob_header && (ob_is_large_text(type1) || ob_is_large_text(type2))) { if (ob_is_large_text(type1) && ob_is_large_text(type2)) { func_ptr = DATUM_TEXT_CMP_FUNCS[cs_type][calc_with_end_space_idx]; } else if (ob_is_large_text(type1)) { // type2 not large text func_ptr = DATUM_TEXT_STR_CMP_FUNCS[cs_type][calc_with_end_space_idx]; } else { // type1 not large text func_ptr = DATUM_STR_TEXT_CMP_FUNCS[cs_type][calc_with_end_space_idx]; } } else { // no lob header or tinytext use original str cmp func func_ptr = DATUM_STR_CMP_FUNCS[cs_type][calc_with_end_space_idx]; } } return func_ptr; } // register function serialization // Need too convert two dimension arrayto index stable one dimension array first. // register type * type evaluate functions static_assert(7 == CO_MAX, "unexpected size"); void *g_ser_eval_type_cmp_funcs[ObMaxType * ObMaxType * 7]; static_assert(sizeof(g_ser_eval_type_cmp_funcs) == sizeof(EVAL_TYPE_CMP_FUNCS), "unexpected size"); bool g_ser_eval_type_cmp_funcs_init = ObFuncSerialization::convert_NxN_array( g_ser_eval_type_cmp_funcs, reinterpret_cast(EVAL_TYPE_CMP_FUNCS), ObMaxType, 7, 0, 7); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL, g_ser_eval_type_cmp_funcs, sizeof(g_ser_eval_type_cmp_funcs) / sizeof(void *)); static_assert(7 == CO_MAX, "unexpected size"); void *g_ser_eval_batch_type_cmp_funcs[ObMaxType * ObMaxType * 7]; static_assert(sizeof(g_ser_eval_batch_type_cmp_funcs) == sizeof(EVAL_BATCH_TYPE_CMP_FUNCS), "unexpected size"); bool g_ser_eval_batch_type_cmp_funcs_init = ObFuncSerialization::convert_NxN_array( g_ser_eval_batch_type_cmp_funcs, reinterpret_cast(EVAL_BATCH_TYPE_CMP_FUNCS), ObMaxType, 7, 0, 7); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_BATCH, g_ser_eval_batch_type_cmp_funcs, sizeof(g_ser_eval_batch_type_cmp_funcs) / sizeof(void *)); void *g_ser_datum_type_cmp_funcs[ObMaxType * ObMaxType]; static_assert(sizeof(g_ser_datum_type_cmp_funcs) == sizeof(DATUM_TYPE_CMP_FUNCS), "unexpected size"); bool g_ser_datum_cmp_funcs_init = ObFuncSerialization::convert_NxN_array( g_ser_datum_type_cmp_funcs, reinterpret_cast(DATUM_TYPE_CMP_FUNCS), ObMaxType); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP, g_ser_datum_type_cmp_funcs, sizeof(g_ser_datum_type_cmp_funcs) / sizeof(void *)); static_assert(7 == CO_MAX && CS_TYPE_MAX * 7 * 2 == sizeof(EVAL_STR_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_STR, EVAL_STR_CMP_FUNCS, sizeof(EVAL_STR_CMP_FUNCS) / sizeof(void *)); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_STR_EVAL_BATCH, EVAL_BATCH_STR_CMP_FUNCS, sizeof(EVAL_BATCH_STR_CMP_FUNCS) / sizeof(void *)); static_assert(CS_TYPE_MAX * 2 == sizeof(DATUM_STR_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_STR, DATUM_STR_CMP_FUNCS, sizeof(DATUM_STR_CMP_FUNCS) / sizeof(void *)); static_assert(7 == CO_MAX && CS_TYPE_MAX * 7 * 2 == sizeof(EVAL_TEXT_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_TEXT, EVAL_TEXT_CMP_FUNCS, sizeof(EVAL_TEXT_CMP_FUNCS) / sizeof(void *)); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_TEXT_EVAL_BATCH, EVAL_BATCH_TEXT_CMP_FUNCS, sizeof(EVAL_BATCH_TEXT_CMP_FUNCS) / sizeof(void *)); static_assert(CS_TYPE_MAX * 2 == sizeof(DATUM_TEXT_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_TEXT, DATUM_TEXT_CMP_FUNCS, sizeof(DATUM_TEXT_CMP_FUNCS) / sizeof(void *)); static_assert(7 == CO_MAX && CS_TYPE_MAX * 7 * 2 == sizeof(EVAL_TEXT_STR_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_TEXT_STR, EVAL_TEXT_STR_CMP_FUNCS, sizeof(EVAL_TEXT_STR_CMP_FUNCS) / sizeof(void *)); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_TEXT_STR_EVAL_BATCH, EVAL_BATCH_TEXT_STR_CMP_FUNCS, sizeof(EVAL_BATCH_TEXT_STR_CMP_FUNCS) / sizeof(void *)); static_assert(CS_TYPE_MAX * 2 == sizeof(DATUM_TEXT_STR_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_TEXT_STR, DATUM_TEXT_STR_CMP_FUNCS, sizeof(DATUM_TEXT_STR_CMP_FUNCS) / sizeof(void *)); static_assert(7 == CO_MAX && CS_TYPE_MAX * 7 * 2 == sizeof(EVAL_STR_TEXT_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_STR_TEXT, EVAL_STR_TEXT_CMP_FUNCS, sizeof(EVAL_STR_TEXT_CMP_FUNCS) / sizeof(void *)); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_STR_TEXT_EVAL_BATCH, EVAL_BATCH_STR_TEXT_CMP_FUNCS, sizeof(EVAL_BATCH_STR_TEXT_CMP_FUNCS) / sizeof(void *)); static_assert(CS_TYPE_MAX * 2 == sizeof(DATUM_STR_TEXT_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_STR_TEXT, DATUM_STR_TEXT_CMP_FUNCS, sizeof(DATUM_STR_TEXT_CMP_FUNCS) / sizeof(void *)); static_assert(7 == CO_MAX && CO_MAX * 2 == sizeof(EVAL_JSON_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_JSON, EVAL_JSON_CMP_FUNCS, sizeof(EVAL_JSON_CMP_FUNCS) / sizeof(void *)); static_assert(7 == CO_MAX && CO_MAX == sizeof(EVAL_BATCH_JSON_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_JSON_EVAL_BATCH, EVAL_BATCH_JSON_CMP_FUNCS, sizeof(EVAL_BATCH_JSON_CMP_FUNCS) / sizeof(void *)); static_assert(2 == sizeof(DATUM_JSON_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_JSON, DATUM_JSON_CMP_FUNCS, sizeof(DATUM_JSON_CMP_FUNCS) / sizeof(void *)); // Geo cmp functions reg static_assert(7 == CO_MAX && CO_MAX * 2 == sizeof(EVAL_GEO_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_EVAL_GEO, EVAL_GEO_CMP_FUNCS, sizeof(EVAL_GEO_CMP_FUNCS) / sizeof(void *)); static_assert(7 == CO_MAX && CO_MAX == sizeof(EVAL_BATCH_GEO_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_RELATION_EXPR_GEO_EVAL_BATCH, EVAL_BATCH_GEO_CMP_FUNCS, sizeof(EVAL_BATCH_GEO_CMP_FUNCS) / sizeof(void *)); static_assert(2 == sizeof(DATUM_GEO_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_CMP_GEO, DATUM_GEO_CMP_FUNCS, sizeof(DATUM_GEO_CMP_FUNCS) / sizeof(void *)); // Fixed double cmp functions reg static_assert( OB_NOT_FIXED_SCALE * CO_MAX == sizeof(EVAL_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_CMP_EVAL, EVAL_FIXED_DOUBLE_CMP_FUNCS, sizeof(EVAL_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); static_assert( OB_NOT_FIXED_SCALE * CO_MAX == sizeof(EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_FIXED_DOUBLE_CMP_EVAL_BATCH, EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS, sizeof(EVAL_BATCH_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); static_assert( OB_NOT_FIXED_SCALE == sizeof(DATUM_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *), "unexpected size"); REG_SER_FUNC_ARRAY(OB_SFA_DATUM_FIXED_DOUBLE_CMP, DATUM_FIXED_DOUBLE_CMP_FUNCS, sizeof(DATUM_FIXED_DOUBLE_CMP_FUNCS) / sizeof(void *)); } // end namespace common; } // end namespace oceanbase