From 83bc968292f1383349bdb408097821edf0a8dc99 Mon Sep 17 00:00:00 2001 From: obdev Date: Fri, 7 Apr 2023 11:54:21 +0000 Subject: [PATCH] [CP] [CP] Support to deduce prefix index from T_OP_LIKE expr --- src/sql/optimizer/ob_join_order.cpp | 259 ++++++++++++++++++--- src/sql/optimizer/ob_join_order.h | 14 +- src/sql/resolver/expr/ob_raw_expr_util.cpp | 69 +++++- src/sql/resolver/expr/ob_raw_expr_util.h | 12 + 4 files changed, 311 insertions(+), 43 deletions(-) diff --git a/src/sql/optimizer/ob_join_order.cpp b/src/sql/optimizer/ob_join_order.cpp index dd313c0b5a..c81f6ab3f2 100644 --- a/src/sql/optimizer/ob_join_order.cpp +++ b/src/sql/optimizer/ob_join_order.cpp @@ -1462,6 +1462,8 @@ int ObJoinOrder::create_one_access_path(const uint64_t table_id, LOG_WARN("failed to assign equal param constraints", K(ret)); } else if (OB_FAIL(ap->expr_constraints_.assign(range_info.get_expr_constraints()))) { LOG_WARN("failed to assign expr constraints", K(ret)); + } else if (OB_FAIL(append(ap->expr_constraints_, helper.expr_constraints_))) { + LOG_WARN("append expr constraints failed", K(ret)); } else { access_path = ap; } @@ -2059,7 +2061,7 @@ int ObJoinOrder::create_access_paths(const uint64_t table_id, LOG_WARN("get unexpected null", K(get_plan()), K(opt_ctx), K(params), K(stmt), K(ret)); } else if (OB_FAIL(get_generated_col_index_qual(table_id, - helper.filters_))) { + helper.filters_, helper))) { LOG_WARN("get prefix index qual failed"); } else if (OB_FAIL(get_valid_index_ids(table_id, ref_table_id, @@ -12502,7 +12504,8 @@ int ObJoinOrder::add_deduced_expr(ObRawExpr *deduced_expr, int ObJoinOrder::get_generated_col_index_qual(const int64_t table_id, - ObIArray &quals) + ObIArray &quals, + PathHelper &helper) { int ret = OB_SUCCESS; const TableItem *table_item = NULL; @@ -12521,7 +12524,7 @@ int ObJoinOrder::get_generated_col_index_qual(const int64_t table_id, if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); - } else if (OB_FAIL(deduce_prefix_str_idx_exprs(qual, table_item, new_qual))) { + } else if (OB_FAIL(deduce_prefix_str_idx_exprs(qual, table_item, new_qual, helper))) { LOG_WARN("deduce prefix str failed", K(ret)); } else if (new_qual != NULL) { if (OB_FAIL(quals.push_back(new_qual))) { @@ -12545,7 +12548,8 @@ int ObJoinOrder::get_generated_col_index_qual(const int64_t table_id, int ObJoinOrder::deduce_prefix_str_idx_exprs(ObRawExpr *expr, const TableItem *table_item, - ObRawExpr *&new_expr) + ObRawExpr *&new_expr, + PathHelper &helper) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { @@ -12567,15 +12571,13 @@ int ObJoinOrder::deduce_prefix_str_idx_exprs(ObRawExpr *expr, ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(*expr), K(expr->get_param_expr(0)), K(expr->get_param_expr(1)), K(ret)); } else if (T_OP_LIKE == expr->get_expr_type()) { - /* - - err1: should add const expr for expr2 - err2: if expr2 is 'a%d' deduce is error - c1 like 'a%d' DOESN'T MEAN: - substr(c1, 1, n) like substr('a%d', 1, n) - because after %, there is normal char. - */ - column_expr = NULL; + if (param_expr1->is_column_ref_expr() + && param_expr1->get_result_type().is_string_type() + && param_expr2->get_result_type().is_string_type()) { + column_expr = static_cast(param_expr1); + value_expr = param_expr2; + escape_expr = expr->get_param_expr(2); + } } else if (T_OP_IN == expr->get_expr_type()) { if (T_OP_ROW == param_expr2->get_expr_type() && !param_expr2->has_generalized_column() @@ -12605,8 +12607,7 @@ int ObJoinOrder::deduce_prefix_str_idx_exprs(ObRawExpr *expr, } } else if (param_expr1->is_static_scalar_const_expr() && param_expr2->is_column_ref_expr()) { if (param_expr1->get_result_type().is_string_type() - && param_expr2->get_result_type().is_string_type() - && param_expr1->get_collation_type() == param_expr2->get_collation_type()) { + && param_expr2->get_result_type().is_string_type()) { type = get_opposite_compare_type(expr->get_expr_type()); column_expr = static_cast(expr->get_param_expr(1)); value_expr = expr->get_param_expr(0); @@ -12622,7 +12623,8 @@ int ObJoinOrder::deduce_prefix_str_idx_exprs(ObRawExpr *expr, escape_expr, table_item, type, - new_expr))) { + new_expr, + helper))) { LOG_WARN("get_prefix str idx exprs faield", K(ret)); } else { //do nothing @@ -12640,7 +12642,8 @@ int ObJoinOrder::get_prefix_str_idx_exprs(ObRawExpr *expr, ObRawExpr *escape_expr, const TableItem *table_item, ObItemType type, - ObRawExpr *&new_expr) + ObRawExpr *&new_expr, + PathHelper &helper) { int ret = OB_SUCCESS; new_expr = NULL; @@ -12682,7 +12685,8 @@ int ObJoinOrder::get_prefix_str_idx_exprs(ObRawExpr *expr, gen_type, *value_expr, escape_expr, - new_expr))) { + new_expr, + helper))) { LOG_WARN("build prefix index compare expr failed", K(ret)); } else if (OB_FAIL(new_expr->formalize(get_plan()->get_optimizer_context().get_session_info()))) { LOG_WARN("formalize failed", K(ret)); @@ -12706,29 +12710,222 @@ int ObJoinOrder::build_prefix_index_compare_expr(ObRawExpr &column_expr, ObItemType type, ObRawExpr &value_expr, ObRawExpr *escape_expr, - ObRawExpr *&new_op_expr) + ObRawExpr *&new_op_expr, + PathHelper &helper) { int ret = OB_SUCCESS; ObSysFunRawExpr *substr_expr = NULL; + bool got_result = false; if (T_OP_LIKE == type) { //build value substr expr ObOpRawExpr *like_expr = NULL; - if (OB_FAIL(ObRawExprUtils::create_substr_expr(get_plan()->get_optimizer_context().get_expr_factory(), - get_plan()->get_optimizer_context().get_session_info(), + ObRawExpr *wildcard_over_length = NULL; + ObRawExpr *has_no_wildcard = NULL; + ObRawExpr *has_no_escape = NULL; + ObOpRawExpr *and_expr = NULL; + ObOpRawExpr *or_expr = NULL; + ObConstRawExpr *zero_expr = NULL; + ObConstRawExpr *wild_expr = NULL; + ObSysFunRawExpr *instr_wild_expr = NULL; + ObSysFunRawExpr *instr_escape_expr = NULL; + ObSysFunRawExpr *substr_value = NULL; + ObObj res; + bool is_true = false; + + ObTransformerCtx ctx; //For getting constraints only + ctx.session_info_ = NULL; + ctx.exec_ctx_ = NULL; + if (OB_ISNULL(ctx.session_info_ = OPT_CTX.get_session_info()) || OB_ISNULL(ctx.exec_ctx_ = OPT_CTX.get_exec_ctx()) + || OB_ISNULL(OPT_CTX.get_exec_ctx()->get_physical_plan_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected error", K(ret)); + } else if (!lib::is_oracle_mode() && OB_FAIL(ObRawExprUtils::build_const_int_expr( + OPT_CTX.get_expr_factory(), ObIntType, 0L, zero_expr))) { + LOG_WARN("build const failed", K(ret)); + } else if (lib::is_oracle_mode() && OB_FAIL(ObRawExprUtils::build_const_number_expr(OPT_CTX.get_expr_factory(), + ObNumberType, + number::ObNumber::get_zero(), + zero_expr))) { + } else if (OB_FAIL(ObRawExprUtils::build_const_string_expr(OPT_CTX.get_expr_factory(), + ObVarcharType, + ObString::make_string("%"), + value_expr.get_result_type().get_collation_type(), + wild_expr))) { + LOG_WARN("build const failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_substr_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + &value_expr, + prefix_expr->get_param_expr(1), + prefix_expr->get_param_expr(2), + substr_value))) { //value's substr + LOG_WARN("create substr expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_instr_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + substr_value, + escape_expr, + lib::is_oracle_mode() ? + prefix_expr->get_param_expr(1) : NULL, + lib::is_oracle_mode() ? + prefix_expr->get_param_expr(1) : NULL, + instr_escape_expr))) {//the escape's position + LOG_WARN("create instr expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + T_OP_EQ, + has_no_escape, + instr_escape_expr, + zero_expr))) { + LOG_WARN("create op expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_instr_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + substr_value, + wild_expr, + lib::is_oracle_mode() ? + prefix_expr->get_param_expr(1) : NULL, + lib::is_oracle_mode() ? + prefix_expr->get_param_expr(1) : NULL, + instr_wild_expr))) { // the wild position + LOG_WARN("create instr expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + T_OP_EQ, + has_no_wildcard, + instr_wild_expr, + zero_expr))) { //wild position is 0, then it does not exist + LOG_WARN("create op expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + T_OP_GT, + wildcard_over_length, + instr_wild_expr, + prefix_expr->get_param_expr(2)))) {// if wild wild position exists then it should larger than substr_length + LOG_WARN("create op expr failed", K(ret)); + } else if (OB_FAIL(OPT_CTX.get_expr_factory().create_raw_expr(T_OP_OR, or_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_FAIL(or_expr->add_param_expr(has_no_wildcard)) || // (wildcard not existed or occurs after length) and has no escape + OB_FAIL(or_expr->add_param_expr(wildcard_over_length))) { + LOG_WARN("set param expr failed", K(ret)); + } else if (OB_FAIL(OPT_CTX.get_expr_factory().create_raw_expr(T_OP_AND, and_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_FAIL(and_expr->add_param_expr(or_expr)) || + OB_FAIL(and_expr->add_param_expr(has_no_escape))) { + LOG_WARN("set param expr failed", K(ret)); + } else if (OB_FAIL(or_expr->formalize(OPT_CTX.get_session_info())) || + OB_FAIL(and_expr->formalize(OPT_CTX.get_session_info()))) { + LOG_WARN("formalize failed", K(ret)); + } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(OPT_CTX.get_exec_ctx(), and_expr, res, got_result, *allocator_))) { + LOG_WARN("calc const failed", K(ret)); + } else if (OB_FAIL(ObObjEvaluator::is_true(res, is_true))) { + LOG_WARN("Failed to get bool value", K(ret)); + } else if (is_true) {// wildcard and escapes matched, + LOG_TRACE("have wildcard or escape ", K(is_true)); + if (OB_FAIL(ObRawExprUtils::create_substr_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), &value_expr, prefix_expr->get_param_expr(1), prefix_expr->get_param_expr(2), substr_expr))) { - LOG_WARN("create substr expr failed", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::build_like_expr(get_plan()->get_optimizer_context().get_expr_factory(), - get_plan()->get_optimizer_context().get_session_info(), - prefix_expr, - substr_expr, - escape_expr, - like_expr))) { - LOG_WARN("build like expr failed", K(ret)); - } else { - new_op_expr = like_expr; + LOG_WARN("create substr expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_like_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + &column_expr, + substr_expr, + escape_expr, + like_expr))) { + LOG_WARN("build like expr failed", K(ret)); + } else { + new_op_expr = like_expr; + if (OB_FAIL(ObTransformUtils::add_param_bool_constraint(&ctx, and_expr, is_true))) { + LOG_WARN("add constraint failed", K(ret)); + } else { + ret = append(helper.expr_constraints_, ctx.expr_constraints_); + } + } + } else {// if has wildcard and escpae, make is specail and add some constraints. + LOG_TRACE("have wildcard or escape ", K(is_true)); + int64_t str_len; + ObNumber str_len_nm; + ObConstRawExpr *str_len_expr = NULL; + ObOpRawExpr *new_pattern = NULL; + if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr( + OPT_CTX.get_exec_ctx(), prefix_expr->get_param_expr(2), + res, got_result, *allocator_))) { + LOG_WARN("calc const failed", K(ret)); //calc the substr length + } else if (lib::is_oracle_mode()) { + res.get_number().extract_valid_int64_with_trunc(str_len); + } else { + str_len = res.get_int(); + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(OPT_CTX.get_exec_ctx(), + instr_escape_expr, res, got_result, + *allocator_))) { + LOG_WARN("calc const failed", K(ret)); //calc the escape position + } else { + int64_t instr_len = 0; + if (lib::is_oracle_mode()) { + ret = res.get_number().extract_valid_int64_with_trunc(instr_len); + } else { + instr_len = res.get_int(); + } + str_len = instr_len != 0 ? std::min(str_len, instr_len + 1 <= str_len ? + instr_len + 1 + : instr_len - 1) : str_len ; + }// if substr length < escape pos then do nothing else make strlen=espace length + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(OPT_CTX.get_exec_ctx(), instr_wild_expr, res, + got_result, *allocator_))) { + LOG_WARN("calc const failed", K(ret)); // calc the wildcard position + } else { + int64_t instr_len = 0; + if (lib::is_oracle_mode()) { + ret = res.get_number().extract_valid_int64_with_trunc(instr_len); + } else { + instr_len = res.get_int(); + } + str_len = instr_len != 0 ? std::min(str_len, instr_len) : str_len; + //get the min value between(str len and wildcard position) + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr( + OPT_CTX.get_expr_factory(), ObIntType, str_len, str_len_expr))) { + LOG_WARN("build const failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_substr_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + &value_expr, + prefix_expr->get_param_expr(1), + str_len_expr, //use the calculated length be the str len, should >=1 + substr_expr))) { + LOG_WARN("create substr expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_concat_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + substr_expr, + wild_expr, //add a % at the substr end + new_pattern))) { + LOG_WARN("create concat expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_like_expr(OPT_CTX.get_expr_factory(), + OPT_CTX.get_session_info(), + &column_expr, + new_pattern, //build like expr + escape_expr, + like_expr))) { + LOG_WARN("build like expr failed", K(ret)); + } else { + new_op_expr = like_expr; + if (OB_FAIL(ObTransformUtils::add_param_bool_constraint(&ctx, and_expr, is_true))) { + LOG_WARN("add constraint failed", K(ret)); + } else { + ret = append(helper.expr_constraints_, ctx.expr_constraints_); + } + } + } + if (OB_FAIL(ret) || OB_ISNULL(substr_expr) || OB_ISNULL(new_op_expr)) { + } else if (OB_FAIL(substr_expr->extract_info())) { + LOG_WARN("extract info failed", K(ret)); + } else if (OB_FAIL(new_op_expr->extract_info())) { + LOG_WARN("extract info failed", K(ret)); + } else if (OB_FAIL(new_op_expr->pull_relation_id())) { + LOG_WARN("pullup rel ids failed", K(ret)); } } else { ObRawExpr *right_expr = NULL; diff --git a/src/sql/optimizer/ob_join_order.h b/src/sql/optimizer/ob_join_order.h index 4ddfb5d2a6..fcd23ba615 100644 --- a/src/sql/optimizer/ob_join_order.h +++ b/src/sql/optimizer/ob_join_order.h @@ -1159,6 +1159,8 @@ struct NullAwareAntiJoinInfo { BaseTableOptInfo *table_opt_info_; ObSEArray equal_param_constraints_; ObSEArray const_param_constraints_; + + ObSEArray expr_constraints_; }; struct DeducedExprInfo { @@ -2295,14 +2297,16 @@ struct NullAwareAntiJoinInfo { ObIArray &pushdown_quals); int get_generated_col_index_qual(const int64_t table_id, - ObIArray &quals); + ObIArray &quals, + PathHelper &helper); int build_prefix_index_compare_expr(ObRawExpr &column_expr, ObRawExpr *prefix_expr, ObItemType type, ObRawExpr &value_expr, ObRawExpr *escape_expr, - ObRawExpr *&new_op_expr); + ObRawExpr *&new_op_expr, + PathHelper &helper); int get_prefix_str_idx_exprs(ObRawExpr *expr, ObColumnRefRawExpr *column_expr, @@ -2310,11 +2314,13 @@ struct NullAwareAntiJoinInfo { ObRawExpr *escape_expr, const TableItem *table_item, ObItemType type, - ObRawExpr *&new_expr); + ObRawExpr *&new_expr, + PathHelper &helper); int deduce_prefix_str_idx_exprs(ObRawExpr *expr, const TableItem *table_item, - ObRawExpr *&new_expr); + ObRawExpr *&new_expr, + PathHelper &helper); int deduce_common_gen_col_index_expr(ObRawExpr *qual, const TableItem *table_item, diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index f9723241a8..2576a2331d 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -3767,7 +3767,44 @@ int ObRawExprUtils::create_to_type_expr(ObRawExprFactory &expr_factory, } return ret; } - +int ObRawExprUtils::create_instr_expr(ObRawExprFactory &expr_factory, + ObSQLSessionInfo *session_info, + ObRawExpr *first_expr, + ObRawExpr *second_expr, + ObRawExpr *third_expr, + ObRawExpr *fourth_expr, + ObSysFunRawExpr *&out_expr) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(expr_factory.create_raw_expr(T_FUN_SYS_INSTR, out_expr))) { + LOG_WARN("create to_type expr failed", K(ret)); + } else if (OB_ISNULL(out_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("to_type is null"); + } else { + out_expr->set_func_name(N_INSTR); + if (NULL == third_expr) { + if (OB_FAIL(out_expr->set_param_exprs(first_expr, second_expr))) { + LOG_WARN("add param expr failed", K(ret)); + } + } else if (NULL == fourth_expr) { + if (OB_FAIL(out_expr->set_param_exprs(first_expr, second_expr, third_expr))) { + LOG_WARN("add param expr failed", K(ret)); + } + } else { + if (OB_FAIL(out_expr->add_param_expr(first_expr)) || + OB_FAIL(out_expr->add_param_expr(second_expr)) || + OB_FAIL(out_expr->add_param_expr(third_expr)) || + OB_FAIL(out_expr->add_param_expr(fourth_expr))) { + LOG_WARN("add param expr failed", K(ret)); + } + } + } + if (OB_SUCC(ret) && OB_FAIL(out_expr->formalize(session_info))) { + LOG_WARN("formalize to_type expr failed", K(ret)); + } + return ret; +} int ObRawExprUtils::create_substr_expr(ObRawExprFactory &expr_factory, ObSQLSessionInfo *session_info, ObRawExpr *first_expr, @@ -3799,6 +3836,26 @@ int ObRawExprUtils::create_substr_expr(ObRawExprFactory &expr_factory, return ret; } +int ObRawExprUtils::create_concat_expr(ObRawExprFactory &expr_factory, + ObSQLSessionInfo *session_info, + ObRawExpr *first_expr, + ObRawExpr *second_expr, + ObOpRawExpr *&out_expr) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(expr_factory.create_raw_expr(T_OP_CNN, out_expr))) { + LOG_WARN("create expr failed", K(ret)); + } else if (OB_FAIL(out_expr->add_param_expr(first_expr)) || + OB_FAIL(out_expr->add_param_expr(second_expr))) { + LOG_WARN("add param expr failed", K(ret)); + } + + if (OB_SUCC(ret) && OB_FAIL(out_expr->formalize(session_info))) { + LOG_WARN("formalize to_type expr failed", K(ret)); + } + return ret; +} + int ObRawExprUtils::create_type_to_str_expr(ObRawExprFactory &expr_factory, ObRawExpr *src_expr, ObSysFunRawExpr *&out_expr, @@ -6046,16 +6103,12 @@ bool ObRawExprUtils::has_prefix_str_expr(const ObRawExpr &expr, && param_expr1->get_result_type().is_string_or_lob_locator_type() && param_expr1->same_as(orig_column_expr)) { if (3 == tmp->get_param_count()) { + int64_t one = 1; const ObRawExpr *param_expr2 = tmp->get_param_expr(1); if (param_expr2 != NULL && param_expr2->is_const_raw_expr()) { const ObConstRawExpr *const_expr = static_cast(param_expr2); - int64_t cmp_val = 1; - if (const_expr->get_value().is_int() && - const_expr->get_value().get_int() == 1) { - bret = true; - substr_expr = tmp; - } else if (const_expr->get_value().is_number() && - const_expr->get_value().get_number().compare(cmp_val) == 0) { + if ((const_expr->get_value().is_int() && const_expr->get_value().get_int() == 1) || + (const_expr->get_value().is_oracle_decimal() && 0 == const_expr->get_value().get_number().compare(one))) { bret = true; substr_expr = tmp; } diff --git a/src/sql/resolver/expr/ob_raw_expr_util.h b/src/sql/resolver/expr/ob_raw_expr_util.h index d09cc299d9..e29066fa2a 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.h +++ b/src/sql/resolver/expr/ob_raw_expr_util.h @@ -470,6 +470,18 @@ public: ObRawExpr *second_expr, ObRawExpr *third_expr, ObSysFunRawExpr *&out_expr); + static int create_instr_expr(ObRawExprFactory &expr_factory, + ObSQLSessionInfo *session_info, + ObRawExpr *first_expr, + ObRawExpr *second_expr, + ObRawExpr *third_expr, + ObRawExpr *fourth_expr, + ObSysFunRawExpr *&out_expr); + static int create_concat_expr(ObRawExprFactory &expr_factory, + ObSQLSessionInfo *session_info, + ObRawExpr *first_expr, + ObRawExpr *second_expr, + ObOpRawExpr *&out_expr); static int create_type_to_str_expr(ObRawExprFactory &expr_factory, ObRawExpr *src_expr, ObSysFunRawExpr *&out_expr,