/** * 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_PC #include "sql/plan_cache/ob_plan_set.h" #include "lib/trace/ob_trace_event.h" #include "lib/number/ob_number_v2.h" #include "common/ob_role.h" #include "observer/ob_server_struct.h" #include "sql/ob_phy_table_location.h" #include "sql/ob_sql_utils.h" #include "sql/ob_sql_context.h" #include "sql/ob_sql_trans_control.h" #include "sql/plan_cache/ob_plan_cache.h" #include "sql/plan_cache/ob_pcv_set.h" #include "sql/plan_cache/ob_plan_cache_value.h" #include "sql/plan_cache/ob_cache_object.h" #include "sql/plan_cache/ob_dist_plans.h" #include "sql/privilege_check/ob_ora_priv_check.h" #include "sql/optimizer/ob_log_plan.h" #include "sql/engine/ob_physical_plan.h" #include "sql/engine/ob_exec_context.h" #include "sql/plan_cache/ob_cache_object_factory.h" #include "pl/ob_pl.h" #include "ob_plan_set.h" #include "share/resource_manager/ob_resource_manager.h" using namespace oceanbase; using namespace common; using namespace oceanbase::sql; using namespace oceanbase::transaction; using namespace share; using namespace share::schema; using namespace pl; namespace oceanbase { namespace sql { ObPlanSet::~ObPlanSet() { // Make sure destory planset before destory pre calculable expression. if (OB_ISNULL(pre_cal_expr_handler_)) { // have no pre calculable expression, do nothing } else { int64_t ref_cnt = pre_cal_expr_handler_->dec_ref_cnt(); if (ref_cnt == 0) { common::ObIAllocator* alloc = pre_cal_expr_handler_->pc_alloc_; pre_cal_expr_handler_->~PreCalcExprHandler(); alloc->free(pre_cal_expr_handler_); pre_cal_expr_handler_ = NULL; } } } //used for get plan int ObPlanSet::match_params_info(const ParamStore *params, ObPlanCacheCtx &pc_ctx, int64_t outline_param_idx, bool &is_same) { int ret = OB_SUCCESS; is_same = true; ObExecContext &exec_ctx = pc_ctx.exec_ctx_; ObSessionVariable sess_var; bool is_sql = is_sql_planset(); if (false == is_match_outline_param(outline_param_idx)) { is_same = false; } else if (OB_ISNULL(params)) { is_same = true; } else if (params->count() > params_info_.count()) { is_same = false; } else { //匹配原始的参数 int64_t N = params->count(); LOG_TRACE("params info", K(params_info_), K(*params), K(this)); for (int64_t i = 0; OB_SUCC(ret) && is_same && i < N; ++i) { if (OB_FAIL(match_param_info(params_info_.at(i), params->at(i), is_same, is_sql))) { LOG_WARN("fail to match param info", K(ret), K(params_info_), K(*params)); } } // 匹配相关的用户session变量 // 这里应该先进行related_user_var_names_跟session_info里面变量的比较,再进行预计算 // 否则会导致session var类型改变后, 无法匹配上计划. 举例如下 // eg: SQL ParamStore // 1. set @a := 1; // 2. select @a; int obj // 3. set @a := '1'; // 4. select @a; varchar obj // 5. select @a; int obj(因为填的是匹配sql2 plan时预计算的结果) // 结果: sql5无法匹配上sql4的计划 // 原因: sql5匹配sql2的计划时先预计算,得到int obj,再比较related_user_var_names_ // 发现session_info_里面的sess_var为varchar,匹配失败. // sql5再次匹配sql4的计划,由于已经预计算,不再进行计算,所以ParamStore // 里面还是int obj,而params_info_中Obj为varchar,匹配失败. // // 所以应该改为先比较related_user_var_names是否和sess_var相同,再进行预计算 // 就不会导致匹配时,ParamStore中填的是上一个计划的预计算结果 if (OB_SUCC(ret) && is_same && related_user_var_names_.count() > 0) { if (related_user_var_names_.count() != related_user_sess_var_metas_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("related_user_var_names and related_user_sess_vars should have the same size", K(ret), K(related_user_var_names_.count()), K(related_user_sess_var_metas_.count())); } else if (OB_ISNULL(pc_ctx.sql_ctx_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(pc_ctx.sql_ctx_.session_info_)); } else { ObSQLSessionInfo *session_info = pc_ctx.sql_ctx_.session_info_; for (int64_t i = 0 ; OB_SUCC(ret) && is_same && i < related_user_var_names_.count(); i++) { if (OB_FAIL(session_info->get_user_variable(related_user_var_names_.at(i), sess_var))) { LOG_WARN("failed to get user variable", K(ret), K(related_user_var_names_.at(i)), K(i)); } else { ObPCUserVarMeta tmp_meta(sess_var); is_same = (related_user_sess_var_metas_.at(i) == tmp_meta); } } } } // privilege if (OB_SUCC(ret) && is_same && all_priv_constraints_.count() > 0) { if (OB_FAIL(match_priv_cons(pc_ctx, is_same))) { LOG_WARN("failed to check privilege constraint", K(ret)); } } if (OB_SUCC(ret) && OB_NOT_NULL(pc_ctx.sql_ctx_.session_info_) && is_same) { is_same = (is_cli_return_rowid_ == pc_ctx.sql_ctx_.session_info_->is_client_return_rowid()); } //pre calculate if (OB_SUCC(ret) && is_same) { ObPhysicalPlanCtx *plan_ctx = exec_ctx.get_physical_plan_ctx(); ObSQLSessionInfo *session = exec_ctx.get_my_session(); if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null session", K(ret)); } else if (OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null plan context", K(ret)); } else if (fetch_cur_time_ && FALSE_IT(plan_ctx->set_cur_time( ObClockGenerator::getClock(), *session))) { // never reach } else if (FALSE_IT(plan_ctx->set_last_trace_id(session->get_last_trace_id()))) { } else if (params->count() != params_info_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param info count is different", K(params_info_), K(*params), K(ret)); } else { /* check calculable expr constraints*/ DLIST_FOREACH(pre_calc_con, all_pre_calc_constraints_) { if (OB_FAIL(ObPlanCacheObject::check_pre_calc_cons(is_ignore_stmt_, is_same, *pre_calc_con, exec_ctx))) { LOG_WARN("failed to pre calculate expression", K(ret)); } else if (!is_same) { break; } } } } //匹配true/false,此时的params中flag_是初始化的值, 不能直接使用。 for (int64_t i = 0; OB_SUCC(ret) && is_same && i < params->count(); ++i) { if (OB_FAIL(match_param_bool_value(params_info_.at(i), params->at(i), is_same))) { LOG_WARN("failed to match param bool value", K(ret), K(params_info_), K(*params)); } } //for end // check const constraint if (OB_SUCC(ret) && is_same) { OC( (match_constraint)(*params, is_same) ); } if (OB_SUCC(ret) && is_same) { if (OB_FAIL(match_multi_stmt_info(*params, multi_stmt_rowkey_pos_, is_same))) { LOG_WARN("failed to match multi stmt info", K(ret)); } else if (!is_same) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_TRACE("batched multi stmt needs rollback", K(ret)); } } if (OB_FAIL(ret)) { is_same = false; LOG_TRACE("after match param result", K(ret), K(is_same), K(params_info_)); } } LOG_DEBUG("after match param result", K(ret), K(is_same), K(params_info_)); return ret; } int ObPlanSet::copy_param_flag_from_param_info(ParamStore *params) { int ret = OB_SUCCESS; if (OB_ISNULL(params)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params is null", K(ret)); } else if (params->count() != params_info_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params is null", K(ret), KPC(params), K(params_info_)); } for (int64_t i = 0; OB_SUCC(ret) && i < params->count(); ++i) { params->at(i).set_param_flag(params_info_.at(i).flag_); } return ret; } //匹配参数类型信息 int ObPlanSet::match_param_info(const ObParamInfo ¶m_info, const ObObjParam ¶m, bool &is_same, bool is_sql_planset) const { int ret = OB_SUCCESS; is_same = true; // extend type must be checked // insert into t values (1) // insert into t values (:0) // two sql have the same key `insert into t values (?)` // but they have complete different plans if ((param_info.flag_.need_to_check_type_ || need_match_all_params_) || (is_sql_planset && lib::is_oracle_mode() && (param_info.type_ == ObTinyIntType || param.get_type() == ObTinyIntType))) { if (lib::is_oracle_mode() && param.get_param_meta().get_type() == ObCharType && param.get_type() == ObNullType) { // in oracle mode, empty string represents null // and therefore meta_'s type (ObCharType) is inconsistent // with param's type. } else if (param.get_param_meta().get_type() != param.get_type()) { LOG_TRACE("differ in match param info", K(param.get_param_meta().get_type()), K(param.get_type())); } if (param.get_collation_type() != param_info.col_type_) { is_same = false; } else if (param.get_param_meta().get_type() != param_info.type_) { is_same = false; } else if (param.is_ext()) { ObDataType data_type; if (!param_info.flag_.need_to_check_extend_type_) { // do nothing } else if (OB_FAIL(ObSQLUtils::get_ext_obj_data_type(param, data_type))) { LOG_WARN("fail to get obj data_type", K(ret), K(param)); } else if (data_type.get_scale() == param_info.scale_ && data_type.get_obj_type() == param_info.ext_real_type_) { is_same = true; } else { is_same = false; LOG_TRACE("ext match param info", K(data_type), K(param_info), K(is_same), K(ret)); } LOG_DEBUG("ext match param info", K(data_type), K(param_info), K(is_same), K(ret)); } else if (param_info.is_oracle_empty_string_ && !param.is_null()) { //普通字符串不匹配空串的计划 is_same = false; } else if (ObSQLUtils::is_oracle_empty_string(param) &&!param_info.is_oracle_empty_string_) { //空串不匹配普通字符串的计划 is_same = false; } else if (param_info.flag_.is_boolean_ != param.is_boolean()) { //bool type not match int type is_same = false; } else { // number params in point and st_point can ignore scale check to share plancache // please refrer to ObSqlParameterization::is_ignore_scale_check is_same = param_info.flag_.ignore_scale_check_ ? true : (param.get_scale() == param_info.scale_); is_same = is_same && match_decint_precision(param_info, param.get_precision()); } } return ret; } // 匹配真/假参数 int ObPlanSet::match_param_bool_value(const ObParamInfo ¶m_info, const ObObjParam ¶m, bool &is_same) const { int ret = OB_SUCCESS; is_same = true; bool vec_param_same = true; bool first_val = true; if (param_info.flag_.need_to_check_bool_value_) { bool is_value_true = false; if (OB_FAIL(ObObjEvaluator::is_true(param, is_value_true))) { SQL_PC_LOG(WARN, "fail to get param info", K(ret)); } else if (is_value_true != param_info.flag_.expected_bool_value_) { is_same = false; } } return ret; } int ObPlanSet::match_multi_stmt_info(const ParamStore ¶ms, const ObIArray &multi_stmt_rowkey_pos, bool &is_match) { int ret = OB_SUCCESS; is_match = false; if (multi_stmt_rowkey_pos.empty()) { is_match = true; } else { // check all rowkey are different int64_t stmt_count = 0; ObSEArray binding_data; for (int64_t i = 0; OB_SUCC(ret) && i < multi_stmt_rowkey_pos.count(); i++) { int64_t pos = multi_stmt_rowkey_pos.at(i); if (OB_UNLIKELY(pos < 0 || pos >= params.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected array pos",K(pos), K(params.count()), K(ret)); } else if (OB_UNLIKELY(!params.at(pos).is_ext_sql_array())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected type", K(params.at(pos)), K(ret)); } else { const ObSqlArrayObj *array_params = reinterpret_cast( params.at(pos).get_ext()); if (OB_ISNULL(array_params)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", KPC(array_params), K(ret)); } else if (OB_FAIL(binding_data.push_back(array_params->data_))) { LOG_WARN("failed to push back array", K(ret)); } else if (i == 0) { stmt_count = array_params->count_; } else if (OB_UNLIKELY(stmt_count != array_params->count_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected stmt count", K(ret)); } else { /*do nothing*/ } } } if (OB_SUCC(ret)) { is_match = true; HashKey hash_key; UniqueHashSet unique_ctx; if (OB_FAIL(unique_ctx.create(stmt_count))) { LOG_WARN("failed to hash set", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && is_match && i < stmt_count; i++) { hash_key.reuse(); for (int64_t j = 0; OB_SUCC(ret) && j < binding_data.count(); j++) { ret = hash_key.rowkey_.push_back(binding_data.at(j)[i]); } if (OB_SUCC(ret)) { ret = unique_ctx.exist_refactored(hash_key); if (OB_HASH_EXIST == ret) { ret = OB_SUCCESS; is_match = false; if (REACH_TIME_INTERVAL(10000000)) { LOG_INFO("batched multi-stmt does not have the same rowkey", K(i), K(hash_key)); } } else if (OB_HASH_NOT_EXIST == ret) { if (OB_FAIL(unique_ctx.set_refactored(hash_key))) { LOG_WARN("store rowkey failed", K(ret)); } } else { LOG_WARN("check rowkey distinct failed", K(ret)); } } } } } } return ret; } int ObPlanSet::match_priv_cons(ObPlanCacheCtx &pc_ctx, bool &is_matched) { int ret = OB_SUCCESS; is_matched = true; bool has_priv = false; ObSQLSessionInfo *session_info = pc_ctx.sql_ctx_.session_info_; ObSchemaGetterGuard *schema_guard = pc_ctx.sql_ctx_.schema_guard_; if (OB_ISNULL(session_info) || OB_ISNULL(schema_guard)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && is_matched && i < all_priv_constraints_.count(); ++i) { const ObPCPrivInfo &priv_info = all_priv_constraints_.at(i); bool has_priv = false; if (OB_FAIL(ObOraSysChecker::check_ora_user_sys_priv(*schema_guard, session_info->get_effective_tenant_id(), session_info->get_priv_user_id(), session_info->get_database_name(), priv_info.sys_priv_, session_info->get_enable_role_array()))) { if (OB_ERR_NO_PRIVILEGE == ret) { ret = OB_SUCCESS; LOG_DEBUG("lack sys privilege", "priv_type", all_priv_constraints_.at(i).sys_priv_); } else { LOG_WARN("failed to check ora user sys priv", K(ret)); } } else { has_priv = true; } if (OB_SUCC(ret)) { is_matched = priv_info.has_privilege_ == has_priv; } } return ret; } //判断多组参数中同一列参数的是否均为true/false, 并返回第一个参数是true/false int ObPlanSet::check_vector_param_same_bool(const ObObjParam ¶m_obj, bool &first_val, bool &is_same) { int ret = OB_SUCCESS; is_same = true; if (param_obj.is_ext_sql_array()) { const ObSqlArrayObj *array_params = reinterpret_cast(param_obj.get_ext()); if (OB_ISNULL(array_params)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("array params is null", K(ret)); } else if (OB_ISNULL(array_params->data_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("array data is null", K(ret), KPC(array_params)); } else { int64_t count = array_params->count_; if (count > 0) { bool is_value_true = true; for (int64_t param_idx = 0; OB_SUCC(ret) && is_same && param_idx < count; param_idx++) { if (OB_FAIL(ObObjEvaluator::is_true(array_params->data_[param_idx], is_value_true))) { SQL_PC_LOG(WARN, "fail to get param info", K(ret)); } else if (param_idx == 0) { first_val = is_value_true; } else if (first_val != is_value_true) { is_same = false; } } // for end } } } return ret; } /*//判断param store中array参数的每个obj是否恒真/假*/ //int ObPlanSet::check_array_bind_same_bool_param(const Ob2DArray ¶m_infos, //const ParamStore ¶m_store, //bool &same_bool_param) //{ //int ret = OB_SUCCESS; //bool first_val = false; //same_bool_param = true; //for (int64_t i = 0; OB_SUCC(ret) && same_bool_param && i < param_store.count(); ++i) { //if (param_infos.at(i).flag_.need_to_check_bool_value_ //&& param_store.at(i).is_ext()) { ////检查每一组参数的结果是否为true/false //if (OB_FAIL(check_vector_param_same_bool(param_store.at(i), //first_val, //same_bool_param))) { //LOG_WARN("fail to check vector param same bool", K(ret)); //} //} //} //for end //return ret; /*}*/ //used for add plan int ObPlanSet::match_params_info(const Ob2DArray &infos, int64_t outline_param_idx, const ObPlanCacheCtx &pc_ctx, bool &is_same) { int ret = OB_SUCCESS; is_same = true; ObSQLSessionInfo *session_info = pc_ctx.sql_ctx_.session_info_; ObSessionVariable sess_var; if (OB_ISNULL(session_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null session_info", K(ret)); } else if (false == is_match_outline_param(outline_param_idx)) { is_same = false; } else if (infos.count() != params_info_.count()) { is_same = false; } else { int64_t N = infos.count(); for (int64_t i = 0; is_same && i < N; ++i) { if (true == is_same && (params_info_.at(i).flag_.need_to_check_type_ || need_match_all_params_)) { if (infos.at(i).type_ != params_info_.at(i).type_ || infos.at(i).scale_ != params_info_.at(i).scale_ || infos.at(i).col_type_ != params_info_.at(i).col_type_ || (params_info_.at(i).flag_.need_to_check_extend_type_ && infos.at(i).ext_real_type_ != params_info_.at(i).ext_real_type_) || (params_info_.at(i).flag_.is_boolean_ != infos.at(i).flag_.is_boolean_) || !match_decint_precision(params_info_.at(i), infos.at(i).precision_)) { is_same = false; } } if (true == is_same && params_info_.at(i).flag_.need_to_check_bool_value_) { if (infos.at(i).flag_.expected_bool_value_ != params_info_.at(i).flag_.expected_bool_value_) { is_same = false; } } } if (is_same && related_user_var_names_.count() > 0) { if (related_user_var_names_.count() != pc_ctx.sql_ctx_.related_user_var_names_.count()) { is_same = false; } else { int64_t CNT = related_user_var_names_.count(); for (int64_t i = 0; OB_SUCC(ret) && is_same && i < CNT; i++) { if (related_user_var_names_.at(i) != pc_ctx.sql_ctx_.related_user_var_names_.at(i)) { is_same = false; } else if (OB_FAIL(session_info->get_user_variable(related_user_var_names_.at(i), sess_var))) { LOG_WARN("failed to get user variable", K(ret), K(sess_var)); } else { ObPCUserVarMeta tmp_meta(sess_var); is_same = (tmp_meta == related_user_sess_var_metas_.at(i)); } } } } if (OB_SUCC(ret) && is_same) { DLIST_FOREACH(pre_calc_con, all_pre_calc_constraints_) { if (OB_FAIL(ObPlanCacheObject::check_pre_calc_cons(is_ignore_stmt_, is_same, *pre_calc_con, pc_ctx.exec_ctx_))) { LOG_WARN("failed to pre calculate expression", K(ret)); } else if (!is_same) { break; } } } if (is_sql_planset() && OB_SUCC(ret) && is_same) { CK( OB_NOT_NULL(pc_ctx.exec_ctx_.get_physical_plan_ctx()) ); if (OB_SUCC(ret)) { const ParamStore ¶ms = pc_ctx.exec_ctx_.get_physical_plan_ctx()->get_param_store(); OC( (match_constraint)(params, is_same)); OC( (match_cons)(pc_ctx, is_same)); } } } if (OB_FAIL(ret)) { is_same = false; } return ret; } bool ObPlanSet::can_skip_params_match() { bool can_skip = true; for (int64_t i = 0; can_skip && i < params_info_.count(); i++) { if (params_info_.at(i).flag_.need_to_check_type_) { can_skip = false; } } if (can_skip) { if (!all_plan_const_param_constraints_.empty() || !all_possible_const_param_constraints_.empty() || !all_equal_param_constraints_.empty() || all_pre_calc_constraints_.get_size() != 0) { can_skip = false; LOG_DEBUG("print can't skip", K(can_skip), K(all_plan_const_param_constraints_.empty()), K(all_possible_const_param_constraints_.empty()), K(all_equal_param_constraints_.empty()), K(all_pre_calc_constraints_.get_size())); } } return can_skip; } bool ObPlanSet::can_delay_init_datum_store() { bool can_delay = true; if (all_pre_calc_constraints_.get_size() != 0) { can_delay = false; } return can_delay; } void ObPlanSet::reset() { ObDLinkBase::reset(); plan_cache_value_ = NULL; params_info_.reset(); stmt_type_ = stmt::T_NONE; fetch_cur_time_ = false; is_ignore_stmt_ = false; //is_wise_join_ = false; outline_param_idx_ = OB_INVALID_INDEX; related_user_var_names_.reset(); related_user_sess_var_metas_.reset(); is_cli_return_rowid_ = false; all_possible_const_param_constraints_.reset(); all_plan_const_param_constraints_.reset(); all_equal_param_constraints_.reset(); all_pre_calc_constraints_.reset(); all_priv_constraints_.reset(); can_skip_params_match_ = false; can_delay_init_datum_store_ = false; alloc_.reset(); } ObPlanCache *ObPlanSet::get_plan_cache() const { ObPlanCache *pc = NULL; if (NULL == plan_cache_value_ || NULL == plan_cache_value_->get_pcv_set() || NULL == plan_cache_value_->get_pcv_set()->get_plan_cache()) { pc = NULL; } else { pc = plan_cache_value_->get_pcv_set()->get_plan_cache(); } return pc; } int ObPlanSet::remove_cache_obj_entry(const ObCacheObjID obj_id) { int ret = OB_SUCCESS; ObPlanCache *pc = NULL; ObPCVSet *pcv_set = NULL; if (OB_ISNULL(get_plan_cache_value()) || OB_ISNULL(pcv_set = get_plan_cache_value()->get_pcv_set())) { LOG_WARN("invalid argument", K(pcv_set)); } else if (NULL == (pc = get_plan_cache())) { LOG_WARN("invalid argument", K(pc)); } else if (OB_FAIL(pcv_set->remove_cache_obj_entry(obj_id))) { LOG_WARN("failed to remove cache obj entry", K(ret), K(obj_id)); } else if (OB_FAIL(pc->remove_cache_obj_stat_entry(obj_id))) { LOG_WARN("failed to remove plan stat", K(obj_id), K(ret)); } return ret; } int ObPlanSet::init_new_set(const ObPlanCacheCtx &pc_ctx, const ObPlanCacheObject &plan, int64_t outline_param_idx, common::ObIAllocator* pc_alloc_) { int ret = OB_SUCCESS; ObPlanCache *pc = nullptr; const ObSqlCtx &sql_ctx = pc_ctx.sql_ctx_; const ObSQLSessionInfo *session_info = sql_ctx.session_info_; if (OB_ISNULL(pc = get_plan_cache()) || OB_ISNULL(session_info)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null plan cache or session info", K(ret), K(pc), K(session_info)); } else { alloc_.set_tenant_id(pc->get_tenant_id()); alloc_.set_ctx_id(ObCtxIds::PLAN_CACHE_CTX_ID); } if (OB_SUCC(ret)) { // set outline_param_idx outline_param_idx_ = outline_param_idx; char *buf = NULL; ObString var_name; ObSessionVariable sess_var; fetch_cur_time_ = plan.get_fetch_cur_time(); stmt_type_ = plan.get_stmt_type(); is_ignore_stmt_ = plan.is_ignore(); is_cli_return_rowid_ = session_info->is_client_return_rowid(); //add param info params_info_.reset(); // set variables for resource map rule // if rule changed, plan cache will be flush. res_map_rule_id_ = pc_ctx.sql_ctx_.res_map_rule_id_; res_map_rule_param_idx_ = pc_ctx.sql_ctx_.res_map_rule_param_idx_; if (OB_FAIL(init_pre_calc_exprs(plan, pc_alloc_))) { LOG_WARN("failed to init pre calc exprs", K(ret)); } else if (OB_FAIL(params_info_.reserve(plan.get_params_info().count()))) { LOG_WARN("failed to reserve 2d array", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < plan.get_params_info().count(); ++i) { if (OB_FAIL(params_info_.push_back(plan.get_params_info().at(i)))) { SQL_PC_LOG(WARN, "fail to push back param info", K(ret)); } } need_match_all_params_ = sql_ctx.need_match_all_params_; // add user session vars if necessary CK( OB_NOT_NULL(sql_ctx.session_info_) ); if (OB_SUCC(ret) && sql_ctx.related_user_var_names_.count() > 0) { related_user_var_names_.reset(); related_user_var_names_.set_allocator(&alloc_); related_user_sess_var_metas_.reset(); related_user_sess_var_metas_.set_allocator(&alloc_); int64_t N = sql_ctx.related_user_var_names_.count(); OZ( related_user_var_names_.init(N), N ); OZ( related_user_sess_var_metas_.init(N), N ); for (int64_t i = 0; OB_SUCC(ret) && i < sql_ctx.related_user_var_names_.count(); i++) { buf = (char *)alloc_.alloc(sql_ctx.related_user_var_names_.at(i).length()); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret), K(sql_ctx.related_user_var_names_.at(i).length())); } else { MEMCPY(buf, sql_ctx.related_user_var_names_.at(i).ptr(), sql_ctx.related_user_var_names_.at(i).length()); var_name.assign_ptr(buf, sql_ctx.related_user_var_names_.at(i).length()); OC( (related_user_var_names_.push_back)(var_name) ); } } for (int64_t i = 0; OB_SUCC(ret) && i < related_user_var_names_.count(); i++) { OZ( sql_ctx.session_info_->get_user_variable(related_user_var_names_.at(i), sess_var), ret, related_user_var_names_.at(i), i ); OC( (related_user_sess_var_metas_.push_back)(ObPCUserVarMeta(sess_var)) ); } if (OB_FAIL(ret)) { related_user_var_names_.reset(); related_user_sess_var_metas_.reset(); } } // init const param constraints ObPlanSetType ps_t = get_plan_set_type_by_cache_obj_type(plan.get_ns()); if (PST_PRCD == ps_t) { // pl does not have any const param constraint all_possible_const_param_constraints_.reset(); all_plan_const_param_constraints_.reset(); all_equal_param_constraints_.reset(); all_pre_calc_constraints_.reset(); all_priv_constraints_.reset(); } else if (PST_SQL_CRSR == ps_t) { // otherwise it should not be empty CK( OB_NOT_NULL(sql_ctx.all_plan_const_param_constraints_), OB_NOT_NULL(sql_ctx.all_possible_const_param_constraints_), OB_NOT_NULL(sql_ctx.all_equal_param_constraints_), OB_NOT_NULL(sql_ctx.all_pre_calc_constraints_), OB_NOT_NULL(sql_ctx.all_priv_constraints_)); OZ( (set_const_param_constraint)(*sql_ctx.all_plan_const_param_constraints_, false) ); OZ( (set_const_param_constraint)(*sql_ctx.all_possible_const_param_constraints_, true) ); OZ( (set_equal_param_constraint)(*sql_ctx.all_equal_param_constraints_) ); OZ( (set_pre_calc_constraint(*sql_ctx.all_pre_calc_constraints_))); OZ( (set_priv_constraint(*sql_ctx.all_priv_constraints_))); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get an unexpected plan set type", K(ps_t), K(plan.get_ns())); } // initialize multi_stmt rowkey pos if (OB_SUCC(ret) && sql_ctx.multi_stmt_rowkey_pos_.count() > 0) { if (OB_FAIL(multi_stmt_rowkey_pos_.init(sql_ctx.multi_stmt_rowkey_pos_.count()))) { LOG_WARN("failed to init array count", K(ret)); } else if (OB_FAIL(append(multi_stmt_rowkey_pos_, sql_ctx.multi_stmt_rowkey_pos_))) { LOG_WARN("failed to append multi stmt rowkey pos", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret) && sql_ctx.is_do_insert_batch_opt()) { can_skip_params_match_ = can_skip_params_match(); can_delay_init_datum_store_ = can_delay_init_datum_store(); } } return ret; } int ObPlanSet::set_const_param_constraint(ObIArray &const_param_constraint, const bool is_all_constraint) { int ret = OB_SUCCESS; ConstParamConstraint &cons_array = (is_all_constraint ? all_possible_const_param_constraints_ : all_plan_const_param_constraints_); cons_array.reset(); cons_array.set_allocator(&alloc_); if (const_param_constraint.count() > 0) { if (OB_FAIL(cons_array.prepare_allocate(const_param_constraint.count()))) { LOG_WARN("failed to init const param constraint array", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < const_param_constraint.count(); i++) { ObPCConstParamInfo &tmp_info = cons_array.at(i); tmp_info = const_param_constraint.at(i); if (tmp_info.const_idx_.count() <= 0 || tmp_info.const_params_.count() <= 0 || tmp_info.const_idx_.count() != tmp_info.const_params_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected const param info", K(tmp_info.const_idx_), K(tmp_info.const_params_)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < tmp_info.const_params_.count(); i++) { if (tmp_info.const_params_.at(i).need_deep_copy()) { const ObObj &src_obj = tmp_info.const_params_.at(i); int64_t deep_cp_size = tmp_info.const_params_.at(i).get_deep_copy_size(); int64_t pos = 0; char *tmp_buf = NULL; if (OB_ISNULL(tmp_buf = (char *)alloc_.alloc(deep_cp_size))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate mem", K(ret)); } else if (OB_FAIL(tmp_info.const_params_.at(i).deep_copy(src_obj, tmp_buf, deep_cp_size, pos))) { LOG_WARN("failed to deep copy obj", K(ret)); } else if (pos != deep_cp_size) { ret = OB_ERR_UNEXPECTED; LOG_WARN("deep copy went wrong", K(ret)); } else { // do nothing } } } // for end } } // for end } } if (OB_FAIL(ret)) { cons_array.reset(); } return ret; } int ObPlanSet::set_equal_param_constraint(common::ObIArray &equal_param_constraint) { int ret = OB_SUCCESS; all_equal_param_constraints_.reset(); all_equal_param_constraints_.set_allocator(&alloc_); if (equal_param_constraint.empty()) { //do nothing } else if (OB_FAIL(all_equal_param_constraints_.init(equal_param_constraint.count()))) { LOG_WARN("failed to init equal param constraint array", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < equal_param_constraint.count(); ++i) { ObPCParamEqualInfo &equal_info = equal_param_constraint.at(i); if (equal_info.first_param_idx_ < 0 || equal_info.second_param_idx_ < 0 || equal_info.first_param_idx_ > params_info_.count() || equal_info.second_param_idx_ > params_info_.count() || equal_info.first_param_idx_ == equal_info.second_param_idx_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid equal param constraint", K(ret), K(equal_info)); } else if (OB_FAIL(all_equal_param_constraints_.push_back(equal_info))) { LOG_WARN("failed to push back equal param info", K(ret)); } } return ret; } // adds pre calc constraint int ObPlanSet::set_pre_calc_constraint(common::ObDList &pre_calc_cons) { int ret = OB_SUCCESS; ObPreCalcExprConstraint *pre_calc_constraint = NULL; void *cons_buf = NULL; DLIST_FOREACH(cur_cons, pre_calc_cons) { if (PRE_CALC_ROWID == cur_cons->expect_result_) { if (OB_ISNULL(cons_buf = alloc_.alloc(sizeof(ObRowidConstraint)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else { pre_calc_constraint = new(cons_buf)ObRowidConstraint(alloc_); } } else { if (OB_ISNULL(cons_buf = alloc_.alloc(sizeof(ObPreCalcExprConstraint)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else { pre_calc_constraint = new(cons_buf)ObPreCalcExprConstraint(alloc_); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(pre_calc_constraint->assign(*cur_cons, alloc_))) { LOG_WARN("failed to deep copy pre calculable expression constriants", K(*cur_cons), K(ret)); } else if (OB_UNLIKELY(!all_pre_calc_constraints_.add_last(pre_calc_constraint))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to add element to dlist", K(ret)); } } return ret; } // add priv constraint int ObPlanSet::set_priv_constraint(common::ObIArray &priv_constraint) { int ret = OB_SUCCESS; all_priv_constraints_.reset(); all_priv_constraints_.set_allocator(&alloc_); if (priv_constraint.empty()) { //do nothing } else if (OB_FAIL(all_priv_constraints_.init(priv_constraint.count()))) { LOG_WARN("failed to init privilege constraint array", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < priv_constraint.count(); ++i) { const ObPCPrivInfo &priv_info = priv_constraint.at(i); if (OB_UNLIKELY(!(priv_info.sys_priv_ > PRIV_ID_NONE && priv_info.sys_priv_ < PRIV_ID_MAX))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid priv type", K(priv_info), K(ret)); } else if (OB_FAIL(all_priv_constraints_.push_back(priv_info))) { LOG_WARN("failed to push back priv info"); } } return ret; } // match actually constraint int ObPlanSet::match_cons(const ObPlanCacheCtx &pc_ctx, bool &is_matched) { int ret = OB_SUCCESS; ObIArray *param_cons = pc_ctx.sql_ctx_.all_plan_const_param_constraints_; ObIArray *possible_param_cons = pc_ctx.sql_ctx_.all_possible_const_param_constraints_; ObIArray *equal_cons = pc_ctx.sql_ctx_.all_equal_param_constraints_; ObIArray *priv_cons = pc_ctx.sql_ctx_.all_priv_constraints_; is_matched = true; if (OB_ISNULL(param_cons) || OB_ISNULL(possible_param_cons) || OB_ISNULL(equal_cons)) { is_matched = false; ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(param_cons), K(possible_param_cons), K(equal_cons)); } else if (param_cons->count() != all_plan_const_param_constraints_.count() || possible_param_cons->count() != all_possible_const_param_constraints_.count() || equal_cons->count() != all_equal_param_constraints_.count() || priv_cons->count() != all_priv_constraints_.count()) { is_matched = false; } else { for (int64_t i=0; is_matched && i < all_plan_const_param_constraints_.count(); i++) { is_matched = (all_plan_const_param_constraints_.at(i)==param_cons->at(i)); } for (int64_t i=0; is_matched && i < all_possible_const_param_constraints_.count(); i++) { is_matched = (all_possible_const_param_constraints_.at(i)==possible_param_cons->at(i)); } for (int64_t i=0; is_matched && i < all_equal_param_constraints_.count(); i++) { is_matched = (all_equal_param_constraints_.at(i)==equal_cons->at(i)); } for (int64_t i=0; is_matched && i < all_priv_constraints_.count(); i++) { is_matched = (all_priv_constraints_.at(i)==priv_cons->at(i)); } } return ret; } // 常量约束的检查逻辑: // 1. all_plan_const_param_constraints_不为空,检查all_plan_const_param_constraints_的约束是否满足, // 满足则命中plan_set,否则不命中; // 2. 否则,检查所有可能的常量约束,如果某一个约束被满足,那么需要生成新的计划,也即不命中,否则命中 // 3. 检查要求相等的参数约束是否被满足 int ObPlanSet::match_constraint(const ParamStore ¶ms, bool &is_matched) { int ret = OB_SUCCESS; is_matched = true; if (all_plan_const_param_constraints_.count() > 0) { // check all_plan_const_param_constraints_ first for (int64_t i = 0; is_matched && OB_SUCC(ret) && i < all_plan_const_param_constraints_.count(); i++) { const ObPCConstParamInfo &const_param_info = all_plan_const_param_constraints_.at(i); CK( const_param_info.const_idx_.count() > 0, const_param_info.const_params_.count() > 0, const_param_info.const_idx_.count() == const_param_info.const_params_.count() ); for (int64_t j = 0; is_matched && OB_SUCC(ret) && j < const_param_info.const_idx_.count(); j++) { const int64_t param_idx = const_param_info.const_idx_.at(j); const ObObj &const_param = const_param_info.const_params_.at(j); if (param_idx >= params.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get an unexpected param index", K(ret), K(param_idx), K(params.count())); } else if (const_param.is_invalid_type() || params.at(param_idx).is_invalid_type()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected invalid type", K(ret), K(const_param.get_type()), K(params.at(param_idx).get_type())); } else if (!const_param.can_compare(params.at(param_idx)) || 0 != const_param.compare(params.at(param_idx))) { LOG_TRACE("not matched const param", K(const_param), K(params.at(param_idx))); is_matched = false; } else { // do nothing } } } } else if (all_possible_const_param_constraints_.count() > 0) { // check if possible generated column exists for (int64_t i = 0; is_matched && OB_SUCC(ret) && i < all_possible_const_param_constraints_.count(); i++) { bool match_const = true; const ObPCConstParamInfo &const_param_info = all_possible_const_param_constraints_.at(i); CK( const_param_info.const_idx_.count() > 0, const_param_info.const_params_.count() > 0, const_param_info.const_idx_.count() == const_param_info.const_params_.count() ); for (int64_t j = 0; match_const && OB_SUCC(ret) && j < const_param_info.const_idx_.count(); j++) { const int64_t param_idx = const_param_info.const_idx_.at(j); const ObObj &const_param = const_param_info.const_params_.at(j); if (param_idx >= params.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get an unexpected param index", K(ret), K(param_idx), K(params.count())); } else if (const_param.is_invalid_type() || params.at(param_idx).is_invalid_type()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected invalid type", K(ret), K(const_param.get_type()), K(params.at(param_idx).get_type())); } else if (!const_param.can_compare(params.at(param_idx)) || 0 != const_param.compare(params.at(param_idx))) { match_const = false; } else { // do nothing } } if (match_const) { LOG_TRACE("matched const param constraint", K(params), K(all_possible_const_param_constraints_.at(i))); is_matched = false; // matching one of the constraint, need to generated new plan } } } else { // do nothing } for (int64_t i = 0; is_matched && OB_SUCC(ret) && i < all_equal_param_constraints_.count(); ++i) { int64_t first_idx = all_equal_param_constraints_.at(i).first_param_idx_; int64_t second_idx = all_equal_param_constraints_.at(i).second_param_idx_; common::ObObjParam param1 = params.at(first_idx); common::ObObjParam param2 = params.at(second_idx); param1.set_collation_type(CS_TYPE_BINARY); param2.set_collation_type(CS_TYPE_BINARY); if (OB_UNLIKELY(first_idx < 0 || first_idx >= params.count() || second_idx < 0 || second_idx >= params.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param index is invalid", K(ret), K(params.count()), K(first_idx), K(second_idx)); } else if (!all_equal_param_constraints_.at(i).use_abs_cmp_ && param1.can_compare(param2) && param1.get_collation_type() == param2.get_collation_type()) { is_matched = (0 == param1.compare(param2)); } else if (all_equal_param_constraints_.at(i).use_abs_cmp_) { /* * for plan like: select ? from t1 group by grouping sets (c1, ?); * if plan has absequal constraint, * then both "select -1 from t1 group by grouping sets (c1, 1);" * and "select 1 from t1 group by grouping sets (c1, 1);" * will hit the plan. * but "select -2 from t1 group by grouping sets (c1, 1);" won't hit the plan. */ if (param1.is_number() && param2.is_number()) { is_matched = (0 == param1.get_number().abs_compare(param2.get_number())); } else if (param1.is_double() && param2.is_double()) { is_matched = (0 == param1.get_double() + param2.get_double()) || (param1.get_double() == param2.get_double()); } else if (param1.is_float() && param2.is_float()) { is_matched = (0 == param1.get_float() + param2.get_float()) || (param1.get_float() == param2.get_float()); } else if (param1.is_decimal_int() && param2.is_decimal_int()) { is_matched = wide::abs_equal(param1, param2); } else if (param1.can_compare(param2) && param1.get_collation_type() == param2.get_collation_type()) { is_matched = (0 == param1.compare(param2)); } } if (OB_SUCC(ret) && !is_matched) { is_matched = false; LOG_TRACE("not match equal param constraint", K(params), K(first_idx), K(second_idx)); } } if (OB_FAIL(ret)) { is_matched = false; } return ret; } int ObPlanSet::init_pre_calc_exprs(const ObPlanCacheObject &phy_plan, common::ObIAllocator* pc_alloc_) { int ret = OB_SUCCESS; void *buf = NULL; if (phy_plan.get_pre_calc_frames().get_size() == 0) { // have no pre calculable expression, not initialize pre calculable expression handle. pre_cal_expr_handler_ = NULL; } else if (OB_ISNULL(pc_alloc_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan cache allocator has not been initialized."); } else if(OB_ISNULL( buf = pc_alloc_->alloc(sizeof(PreCalcExprHandler)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory.", K(ret)); } else { pre_cal_expr_handler_ = new(buf)PreCalcExprHandler(); pre_cal_expr_handler_->init(phy_plan.get_tenant_id(), pc_alloc_); buf = NULL; common::ObIAllocator& pre_expr_alloc = (pre_cal_expr_handler_->alloc_); if (OB_ISNULL(buf = pre_expr_alloc.alloc(sizeof(common::ObDList)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory.", K(ret)); } else { pre_cal_expr_handler_->pre_calc_frames_ = new (buf)common::ObDList; common::ObDList* pre_calc_frames = pre_cal_expr_handler_->pre_calc_frames_; ObPreCalcExprFrameInfo *pre_calc_frame = NULL; void *frame_buf = NULL; DLIST_FOREACH(frame, phy_plan.get_pre_calc_frames()) { if (OB_ISNULL(frame_buf = pre_expr_alloc.alloc(sizeof(ObPreCalcExprFrameInfo)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else if (FALSE_IT(pre_calc_frame = new(frame_buf)ObPreCalcExprFrameInfo( pre_expr_alloc))) { // do nothing } else if (OB_FAIL(pre_calc_frame->assign(*frame, pre_expr_alloc))) { LOG_WARN("failed to deep copy pre calc frame", K(ret)); } else if (OB_UNLIKELY(!pre_calc_frames->add_last(pre_calc_frame))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to add element to dlist", K(ret)); } else { frame_buf = NULL; pre_calc_frame = NULL; } } // set expr list of old engine nullptr pre_cal_expr_handler_->pre_calc_exprs_ = NULL; } } return ret; } int ObPlanSet::pre_calc_exprs(ObExecContext &exec_ctx) { int ret = OB_SUCCESS; ObSQLSessionInfo *session = exec_ctx.get_my_session(); if (OB_ISNULL(pre_cal_expr_handler_)) { // have no pre-calculable expression, do nothing } else if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null session", K(ret)); // for new engine } else if (OB_NOT_NULL(pre_cal_expr_handler_->pre_calc_frames_)) { DLIST_FOREACH(pre_calc_frame, *(pre_cal_expr_handler_->pre_calc_frames_)) { if (OB_FAIL(ObPlanCacheObject::pre_calculation(is_ignore_stmt_, *pre_calc_frame, exec_ctx))) { LOG_WARN("failed to pre calculate", K(ret)); } } } return ret; } int ObSqlPlanSet::add_cache_obj(ObPlanCacheObject &cache_object, ObPlanCacheCtx &pc_ctx, int64_t ol_param_idx, int &add_ret) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!cache_object.is_sql_crsr())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("cache_object type is invalid", K(cache_object.get_ns())); } else { ret = add_plan(static_cast(cache_object), pc_ctx, ol_param_idx); } cache_object.get_pre_expr_ref_count(); // ref_cnt++; if (OB_FAIL(ret)) { LOG_WARN("failed to add plan.", K(ret)); } else if (OB_ISNULL(pre_cal_expr_handler_)) { // have no pre-calculable expression, do nothing } else { cache_object.set_pre_calc_expr_handler(pre_cal_expr_handler_); cache_object.inc_pre_expr_ref_count(); // planset, handle, plan, ref_cnt(val) LOG_INFO("add pre calculable expression.", KP(this), KP(cache_object.get_pre_calc_expr_handler()), KP(&cache_object), K(cache_object.get_pre_expr_ref_count())); } add_ret = ret; return ret; } int ObSqlPlanSet::add_plan(ObPhysicalPlan &plan, ObPlanCacheCtx &pc_ctx, int64_t outline_param_idx) { int ret = OB_SUCCESS; ObSqlCtx &sql_ctx = pc_ctx.sql_ctx_; //DASTableLocList table_locs(pc_ctx.exec_ctx_.get_allocator()); ObArray candi_table_locs; ObPhyPlanType plan_type = OB_PHY_PLAN_UNINITIALIZED; if (OB_ISNULL(plan_cache_value_) || OB_ISNULL(pc_ctx.exec_ctx_.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; SQL_PC_LOG(WARN, "invalid argument", KP(plan_cache_value_), K(ret)); } else if (OB_FAIL(get_phy_locations(sql_ctx.partition_infos_, //table_locs, candi_table_locs))) { LOG_WARN("fail to get physical locations", K(ret)); } else if (OB_FAIL(set_concurrent_degree(outline_param_idx, plan))) { LOG_WARN("fail to check concurrent degree", K(ret)); } else { if (pc_ctx.exec_ctx_.get_physical_plan_ctx()->get_or_expand_transformed()) { need_try_plan_ |= TRY_PLAN_OR_EXPAND; } if (plan.get_is_late_materialized()) { need_try_plan_ |= TRY_PLAN_LATE_MAT; } if (plan.has_uncertain_local_operator()) { need_try_plan_ |= TRY_PLAN_UNCERTAIN; } if (plan.contain_index_location()) { need_try_plan_ |= TRY_PLAN_INDEX; } plan_type = plan.get_plan_type(); if (OB_SUCC(ret)) { switch(plan_type) { case OB_PHY_PLAN_LOCAL:{ SQL_PC_LOG(TRACE, "plan set add plan, local plan", K(ret)); if (is_multi_stmt_plan()) { if (NULL != array_binding_plan_) { ret = OB_SQL_PC_PLAN_DUPLICATE; } else { array_binding_plan_ = &plan; } } else { if (OB_FAIL(add_physical_plan(OB_PHY_PLAN_LOCAL, pc_ctx, plan))) { SQL_PC_LOG(TRACE, "fail to add local plan", K(ret)); } else if (OB_SUCC(ret) #ifdef OB_BUILD_SPM && is_spm_closed_ #endif && FALSE_IT(direct_local_plan_ = &plan)) { // do nothing } else { // local_phy_locations_.reset(); // if (OB_FAIL(init_phy_location(table_locs.count()))) { // SQL_PC_LOG(WARN, "init phy location failed"); // } else if (OB_FAIL(local_phy_locations_.assign(phy_locations))) { // SQL_PC_LOG(WARN, "fail to assign phy locations"); // } // LOG_TRACE("local phy locations", K(local_phy_locations_)); } } } break; case OB_PHY_PLAN_REMOTE:{ SQL_PC_LOG(DEBUG, "plan set add plan, remote plan", K(ret), K(remote_plan_)); if (NULL != remote_plan_) { ret = OB_SQL_PC_PLAN_DUPLICATE; } else { remote_plan_ = &plan; } } break; case OB_PHY_PLAN_DISTRIBUTED: { SQL_PC_LOG(TRACE, "plan set add plan, distr plan", K(ret)); if (OB_FAIL(add_physical_plan(OB_PHY_PLAN_DISTRIBUTED, pc_ctx, plan))) { LOG_WARN("failed to add dist plan", K(ret), K(plan)); } else { SQL_PC_LOG(DEBUG, "plan added to dist plan list", K(ret)); } } break; default: ret = OB_ERR_UNEXPECTED; SQL_PC_LOG(WARN, "unknown plan type", K(plan_type), K(ret)); break; } } } if (stmt::T_SELECT == stmt_type_) { for (int64_t i = 0; OB_SUCC(ret) && i < candi_table_locs.count(); ++i) { const ObCandiTableLoc &candi_table_loc = candi_table_locs.at(i); if (candi_table_loc.is_duplicate_table_not_in_dml()) { has_duplicate_table_ = true; break; } } } SQL_PC_LOG(TRACE, "plan set add plan", K(ret), K(&plan), "plan type ", plan_type, K(has_duplicate_table_), K(stmt_type_)); // increase plan ref_count, // if plan doesn't add in plan cache,don't increase ref_count; bool real_add = OB_PHY_PLAN_LOCAL != plan_type || pc_ctx.need_add_obj_stat_; if (OB_SUCCESS == ret && real_add) { CacheRefHandleID plan_handle; if (array_binding_plan_ == &plan) { plan_handle = PC_REF_PLAN_ARR_HANDLE; } else { plan_handle = OB_PHY_PLAN_LOCAL == plan_type ? PC_REF_PLAN_LOCAL_HANDLE : OB_PHY_PLAN_REMOTE == plan_type ? PC_REF_PLAN_REMOTE_HANDLE : PC_REF_PLAN_DIST_HANDLE; } plan.set_dynamic_ref_handle(plan_handle); // if (candi_table_locs.count() > 0) { // if (candi_table_locs.at(0).get_phy_part_loc_info_list().count() <= 0) { // ret = OB_INVALID_ARGUMENT; // LOG_WARN("part loc info list is empty", K(candi_table_locs.at(0)), K(ret)); // } else if (OB_FAIL(candi_table_locs.at(0).get_phy_part_loc_info_list(). // at(0).get_partition_location().get_partition_key(partition_key_))) { // LOG_WARN("fail to get partition key", K(ret)); // } // } } return ret; } int ObSqlPlanSet::init_new_set(const ObPlanCacheCtx &pc_ctx, const ObPlanCacheObject &plan, int64_t outline_param_idx, common::ObIAllocator* pc_malloc_) { int ret = OB_SUCCESS; const ObSqlCtx &sql_ctx = pc_ctx.sql_ctx_; // set outline_param_idx outline_param_idx_ = outline_param_idx; need_try_plan_ = 0; has_duplicate_table_ = false; #ifdef OB_BUILD_SPM bool is_spm_on = false; #endif const ObSQLSessionInfo *session_info = sql_ctx.session_info_; if (OB_ISNULL(session_info)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null plan cache or session info", K(ret), K(session_info)); #ifdef OB_BUILD_SPM } else if (OB_FAIL(session_info->get_use_plan_baseline(is_spm_on))) { LOG_WARN("failed to get spm configs", K(ret)); } else if (FALSE_IT(is_spm_closed_ = (!is_spm_on))) { // do nothing #endif } else if (OB_ISNULL(pc_malloc_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("pc_allocator has not been initialized.", K(ret)); } else if (OB_FAIL(ObPlanSet::init_new_set(pc_ctx, plan, outline_param_idx, pc_malloc_))) { LOG_WARN("init new set failed", K(ret)); } else if (OB_FAIL(table_locations_.prepare_allocate_and_keep_count(sql_ctx.partition_infos_.count(), *plan_cache_value_->get_pcv_set()->get_allocator()))) { LOG_WARN("fail to init table location count", K(ret)); #ifdef OB_BUILD_SPM } else if (OB_FAIL(local_evolution_plan_.init(this))) { SQL_PC_LOG(WARN, "failed to init local evolution plan", K(ret)); } else if (OB_FAIL(dist_evolution_plan_.init(this))) { SQL_PC_LOG(WARN, "failed to init dist evolution plan", K(ret)); #endif } else if (OB_FAIL(dist_plans_.init(this))) { SQL_PC_LOG(WARN, "failed to init dist plans", K(ret)); } else { //if (pc_ctx.sql_ctx_.multi_stmt_rowkey_pos_.empty()) { //for (int64_t i = 0; i < plan.get_params_info().count(); ++i) { //if (ObExtendType == plan.get_params_info().at(i).type_) { //has_array_binding_ = true; //} //} //} for (int64_t i = 0; !is_contain_virtual_table_ && i < plan.get_dependency_table().count(); i++) { const ObSchemaObjVersion &schema_obj = plan.get_dependency_table().at(i); if (TABLE_SCHEMA == schema_obj.get_schema_type() && is_virtual_table(schema_obj.object_id_)) { is_contain_virtual_table_ = true; LOG_DEBUG("contain virtual table", K(is_contain_virtual_table_), K(schema_obj)); } } // for end } bool contain_index_location = false; if (OB_FAIL(ret)) { // do nothing } else if (NS_CRSR != plan.get_ns()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected cache object type", K(ret), K(plan.get_ns())); } else { const ObPhysicalPlan &sql_plan = dynamic_cast(plan); enable_inner_part_parallel_exec_ = sql_plan.get_px_dop() > 1; contain_index_location = sql_plan.contain_index_location(); LOG_DEBUG("using px", K(enable_inner_part_parallel_exec_)); plan.get_pre_expr_ref_count(); } if (OB_SUCC(ret) && (!contain_index_location || is_multi_stmt_plan())) { const ObTablePartitionInfoArray &partition_infos = sql_ctx.partition_infos_; int64_t N = partition_infos.count(); //copy table location for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { if (NULL == partition_infos.at(i)) { ret = OB_ERR_UNEXPECTED; SQL_PC_LOG(TRACE, "invalid partition info"); } else if (OB_FAIL(table_locations_.push_back(partition_infos.at(i)->get_table_location()))) { SQL_PC_LOG(WARN, "fail to push table location", K(ret)); } else if (is_all_non_partition_ && partition_infos.at(i)->get_table_location().is_partitioned()) { is_all_non_partition_ = false; } } // for end } return ret; } int ObSqlPlanSet::select_plan(ObPlanCacheCtx &pc_ctx, ObPlanCacheObject *&cache_obj) { int ret = OB_SUCCESS; ObPhysicalPlan *plan = NULL; if (OB_ISNULL(plan_cache_value_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("location cache not init", K(plan_cache_value_), K(ret)); } else { if (OB_FAIL(get_plan_special(pc_ctx, plan))) { if (OB_SQL_PC_NOT_EXIST == ret) { LOG_TRACE("fail to get plan special", K(ret)); } else { LOG_WARN("fail to get plan special", K(ret)); } } } if (OB_SUCC(ret) && OB_NOT_NULL(plan) && plan->is_remote_plan()) { //记录下not param info和neg_param_index,用于在转发remote sql的时候定位能参数化常量的个数 pc_ctx.not_param_index_.reset(); pc_ctx.neg_param_index_.reset(); if (OB_FAIL(pc_ctx.not_param_index_.add_members2(plan_cache_value_->get_not_param_index()))) { LOG_WARN("assign not param info failed", K(ret), K(plan_cache_value_->get_not_param_index())); } else if (OB_FAIL(pc_ctx.neg_param_index_.add_members2( plan_cache_value_->get_neg_param_index()))) { LOG_WARN("assign neg param index failed", K(ret), K(plan_cache_value_->get_neg_param_index())); } } if (OB_FAIL(ret)) { } else if (OB_UNLIKELY(plan->is_limited_concurrent_num())) { if (OB_FAIL(plan->inc_concurrent_num())) { if (OB_REACH_MAX_CONCURRENT_NUM == ret) { LOG_USER_ERROR(OB_REACH_MAX_CONCURRENT_NUM, plan->get_max_concurrent_num()); } else { LOG_WARN("fail to inc concurrent num", K(ret)); } } } else {/*do nothing*/} if (OB_SUCC(ret)) { cache_obj = plan; } return ret; } /* * 不查询location cache直接获取local plan 条件: * 1.该次请求不是在重试中 * 2.该sql涉及的表裁剪后均为单分区 * 3.local plan 存在 * 4.上次执行local plan时open成功 * * 如果直接获取了local plan, 而实际需要的不是local plan, * 会在执行阶段open时报错,更新plan中last_execute_result状态并重试。 * */ //int ObSqlPlanSet::get_local_plan_direct(ObPlanCacheCtx &pc_ctx, // bool &is_direct_local_plan, // ObPhysicalPlan *&plan) //{ // int ret = OB_SUCCESS; // plan = NULL; // is_direct_local_plan = false; // int64_t N = table_locations_.count(); // bool is_all_non_partition = true; // bool is_leader = false; // ObSEArray table_parts; // ObExecContext &exec_ctx = pc_ctx.exec_ctx_; // ObSchemaGetterGuard *schema_guard = pc_ctx.sql_ctx_.schema_guard_; // const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(pc_ctx.sql_ctx_.session_info_); // ObPhysicalPlanCtx *plan_ctx = exec_ctx.get_physical_plan_ctx(); // if (OB_ISNULL(schema_guard) // || OB_ISNULL(dtc_params.tz_info_) // || OB_ISNULL(plan_ctx) // || OB_ISNULL(pc_ctx.sql_ctx_.session_info_)) { // ret = OB_INVALID_ARGUMENT; // LOG_WARN("invalid argument", KP(schema_guard), KP(dtc_params.tz_info_), // KP(plan_ctx), KP(pc_ctx.sql_ctx_.session_info_), K(ret)); // } // // //if(!has_partition_group_) LOG_INFO("has pg_key", K(has_partition_group_)); // ObSEArray partition_ids; // bool all_not_contains_pg = plan_cache_value_->is_all_not_contains_pg_key(); // for (int64_t i = 0; OB_SUCC(ret) && is_all_non_partition && i < N; ++i) { // ObPGKey pg_key; // uint64_t tg_id = OB_INVALID_ID; // int64_t pg_id = OB_INVALID_ID; // int64_t p_cnt = OB_INVALID_ID; // const ObTableLocation &table_location = table_locations_.at(i); // if (OB_ISNULL(plan_cache_value_)) { // ret = OB_ERR_UNEXPECTED; // LOG_WARN("empty plan cache value"); // } else if (OB_FAIL(table_location.calculate_partition_ids(exec_ctx, // schema_guard, // plan_ctx->get_param_store(), // partition_ids, // dtc_params))) { // LOG_WARN("fail to get partition ids", K(ret)); // } else if (partition_ids.count() != 1) { // is_all_non_partition = false; // // all table not in partition groups, just init a pg_key // } else if (all_not_contains_pg && FALSE_IT(pg_key.init(table_location.get_ref_table_id(), // partition_ids.at(0), // table_location.get_partition_cnt()))) { // // do nothing // } else if (!all_not_contains_pg && // OB_FAIL(ObSqlPartitionLocationCache::get_phy_key(*schema_guard, // table_location.get_ref_table_id(), // partition_ids.at(0), // tg_id, // pg_id, // pg_key))) { // LOG_WARN("fail to get pg key", K(ret)); // } else if (OB_FAIL(table_parts.push_back(TablePart(table_location.get_table_id(), // table_location.get_ref_table_id(), // partition_ids.at(0), // pg_key)))) { // LOG_WARN("fail to push table part", K(ret)); // } // partition_ids.reuse(); // } // // if (OB_SUCC(ret) && true == is_all_non_partition) { //get local plan directly // ObPartitionKey partition_key = partition_key_; // // directly get plan when spm is off // if (is_spm_acs_closed_ && OB_NOT_NULL(direct_local_plan_)) { // plan = direct_local_plan_; // plan->inc_ref_count(pc_ctx.handle_id_); // } else if (OB_FAIL(gen_partition_key(table_parts, partition_key))) { // LOG_WARN("fail to gen partition key", K(ret)); // } else if (OB_FAIL(local_plans_.get_plan(pc_ctx, partition_key, plan))) { // SQL_PC_LOG(DEBUG, "get local plan failed", K(ret)); // } // if (OB_SUCC(ret) && plan != NULL) { // int last_retry_err = pc_ctx.sql_ctx_.session_info_ // ->get_retry_info().get_last_query_retry_err(); // if (plan->is_last_exec_succ()) { // is_direct_local_plan = true; // } else if (pc_ctx.sql_ctx_.session_info_->get_is_in_retry() // && is_local_plan_opt_allowed(last_retry_err)) { // is_direct_local_plan = true; // } else { // is_direct_local_plan = false; // } // } // } // // if (OB_FAIL(ret)) { // //do nothing // } else if (is_direct_local_plan) { // ObPhyTableLocationIArray &phy_locations = exec_ctx.get_task_exec_ctx().get_table_locations(); // if (OB_FAIL(phy_locations.assign(local_phy_locations_))) { //copy phy table locations // SQL_PC_LOG(WARN, "fail to assign phy locations", K(ret)); // } else if (OB_FAIL(replace_partition_id(phy_locations, table_parts))) { // SQL_PC_LOG(WARN, "fail to replace partition id", K(ret)); // } // } // // LOG_DEBUG("get local plan direct", K(ret), KP(plan), K(is_direct_local_plan)); // // if (OB_FAIL(ret)) { // is_direct_local_plan = false; // } // exec_ctx.set_direct_local_plan(is_direct_local_plan); // // return ret; //} int ObSqlPlanSet::add_physical_plan(const ObPhyPlanType plan_type, ObPlanCacheCtx &pc_ctx, ObPhysicalPlan &plan) { int ret = OB_SUCCESS; if (plan_type != OB_PHY_PLAN_LOCAL && plan_type != OB_PHY_PLAN_DISTRIBUTED) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid plan type", K(ret), K(plan_type)); #ifndef OB_BUILD_SPM } else if (OB_PHY_PLAN_LOCAL == plan_type) { if (NULL != local_plan_) { ret = OB_SQL_PC_PLAN_DUPLICATE; } else { local_plan_ = &plan; } } else if (OB_FAIL(dist_plans_.add_plan(plan, pc_ctx))) { LOG_WARN("failed to add dist plan", K(ret), K(plan)); } #else } else if (!pc_ctx.need_evolution_ || is_spm_closed_) { // Addition of other non-evolving plans is prohibited in plan evolution if (OB_PHY_PLAN_LOCAL == plan_type) { if (local_evolution_plan_.get_is_evolving_flag()) { ret = OB_SQL_PC_PLAN_DUPLICATE; LOG_WARN("addition of other non-evolving plans is prohibited in local plan evolution"); } else if (NULL != local_plan_) { ret = OB_SQL_PC_PLAN_DUPLICATE; } else { local_plan_ = &plan; } } else { if (OB_FAIL(dist_plans_.add_plan(plan, pc_ctx))) { LOG_WARN("failed to add dist plan", K(ret), K(plan)); } } } else { // Clear local_plan_ and dist_plans_ before adding evolution plans ObSpmCacheCtx& spm_ctx = pc_ctx.sql_ctx_.spm_ctx_; if (ObSpmCacheCtx::STAT_ADD_BASELINE_PLAN == spm_ctx.spm_stat_) { if (OB_PHY_PLAN_LOCAL == spm_ctx.evolution_plan_type_) { OZ (local_evolution_plan_.add_plan(pc_ctx, &plan)); } else { OZ (dist_evolution_plan_.add_plan(pc_ctx, &plan)); } } else { if (OB_PHY_PLAN_LOCAL == plan_type) { if (NULL != local_plan_) { remove_cache_obj_entry(local_plan_->get_plan_id()); local_plan_ = NULL; } OZ (local_evolution_plan_.add_plan(pc_ctx, &plan)); OX (spm_ctx.evolution_plan_type_ = OB_PHY_PLAN_LOCAL); } else { OZ (dist_plans_.remove_plan_stat()); OZ (dist_evolution_plan_.add_plan(pc_ctx, &plan)); OX (spm_ctx.evolution_plan_type_ = OB_PHY_PLAN_DISTRIBUTED); } } } #endif return ret; } int ObSqlPlanSet::get_physical_plan(const ObPhyPlanType plan_type, ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan) { int ret = OB_SUCCESS; plan = NULL; bool get_next = false; #ifndef OB_BUILD_SPM if (plan_type != OB_PHY_PLAN_LOCAL && plan_type != OB_PHY_PLAN_DISTRIBUTED) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid plan type", K(ret), K(plan_type)); } else if (OB_PHY_PLAN_LOCAL == plan_type) { plan = local_plan_; } else if (OB_FAIL(dist_plans_.get_plan(pc_ctx, plan))) { LOG_DEBUG("failed to get dist plan", K(ret)); } #else if (plan_type != OB_PHY_PLAN_LOCAL && plan_type != OB_PHY_PLAN_DISTRIBUTED) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid plan type", K(ret), K(plan_type)); } else if (OB_PHY_PLAN_LOCAL == plan_type) { if (OB_FAIL(try_get_local_evolution_plan(pc_ctx, plan, get_next))) { LOG_WARN("failed to try get local evolution plan", K(ret)); } else if (get_next) { plan = local_plan_; } if (OB_SUCC(ret) && NULL == plan) { ret = OB_SQL_PC_NOT_EXIST; } } else if (OB_PHY_PLAN_DISTRIBUTED == plan_type) { if (OB_FAIL(try_get_dist_evolution_plan(pc_ctx, plan, get_next))) { LOG_WARN("failed to try get local evolution plan", K(ret)); } else if (get_next && OB_FAIL(dist_plans_.get_plan(pc_ctx, plan))) { LOG_TRACE("failed to get dist plan", K(ret)); } if (OB_SUCC(ret) && NULL == plan) { ret = OB_SQL_PC_NOT_EXIST; } } #endif return ret; } #ifdef OB_BUILD_SPM int ObSqlPlanSet::add_evolution_plan_for_spm(ObPhysicalPlan *plan, ObPlanCacheCtx &ctx) { int ret = OB_SUCCESS; ObPlanCache *pc = NULL; if (NULL == plan_cache_value_ || NULL == plan_cache_value_->get_pcv_set() || NULL == plan_cache_value_->get_pcv_set()->get_plan_cache()) { ret = OB_NOT_INIT; } else if (OB_ISNULL(plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan is null", K(ret)); } else if (OB_PHY_PLAN_LOCAL != plan->get_plan_type() && OB_PHY_PLAN_DISTRIBUTED != plan->get_plan_type()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not supported type", K(ret), K(plan->get_plan_type())); } else if (FALSE_IT(pc = plan_cache_value_->get_pcv_set()->get_plan_cache())) { } else if (OB_PHY_PLAN_LOCAL == plan->get_plan_type()) { if (NULL != local_plan_) { ret = OB_SQL_PC_PLAN_DUPLICATE; LOG_WARN("local plan duplicate", K(ret)); } else { local_plan_ = plan; } } else if (OB_FAIL(dist_plans_.add_evolution_plan(*plan, ctx))) { LOG_WARN("failed to add dist plan", K(ret), K(plan)); } return ret; } #endif //int ObSqlPlanSet::get_plan_normal(ObPlanCacheCtx &pc_ctx, // ObPhysicalPlan *&plan) //{ // int ret = OB_SUCCESS; // plan = NULL; // ObSQLSessionInfo *session = pc_ctx.sql_ctx_.session_info_; // if (OB_ISNULL(session)) { // ret = OB_INVALID_ARGUMENT; // LOG_WARN("invalid argument", K(ret)); // } // // if (OB_SQL_PC_NOT_EXIST == ret // || NULL == plan) { // pc_ctx.exec_ctx_.set_direct_local_plan(false); // // 进入该分支, 说明不走直接获取local plan的优化, // // 如果plan不为空, 说明已经拿到执行计划, // // 此时已经对该plan的引用计数+1, 在这里需要先减掉引用计数 // if (NULL != plan) { // /* // * 以下并发场景会进入该分支 // * 切主 // * A线程 B线程 // * // * 直接获取到local plan 直接获取local plan // * // * // * 分区不在本地重试 // * // * 发现其他线程已经 // * 执行该local计划失败, // * 重新计算plan type获取 // * 正确remote计划 // * // * 进入plan cache, // * 重新计算plan type // * 获取remote 计划 // * */ // plan = NULL; // } // ObPhyPlanType plan_type = OB_PHY_PLAN_UNINITIALIZED; // typedef ObSEArray PLS; // SMART_VAR(PLS, candi_table_locs) { // if (enable_inner_part_parallel_exec_) { // if (OB_FAIL(get_physical_plan(OB_PHY_PLAN_DISTRIBUTED, pc_ctx, plan))) { // LOG_TRACE("failed to get px plan", K(ret)); // } // } else if (OB_FAIL(get_plan_type(table_locations_, // false, // pc_ctx, // candi_table_locs, // plan_type))) { // // ret = OB_SQL_PC_NOT_EXIST; // SQL_PC_LOG(TRACE, "failed to get plan type", K(ret)); // } // // if (OB_SUCC(ret) && !enable_inner_part_parallel_exec_) { // NG_TRACE(get_plan_type_end); // SQL_PC_LOG(DEBUG, "get plan type before select plan", K(ret), K(plan_type)); // switch (plan_type) { // case OB_PHY_PLAN_LOCAL: { // if (/*has_array_binding_||*/ is_multi_stmt_plan()) { // if (NULL != array_binding_plan_) { // array_binding_plan_->set_dynamic_ref_handle(pc_ctx.handle_id_); // plan = array_binding_plan_; // } // } else if (OB_FAIL(get_physical_plan(OB_PHY_PLAN_LOCAL, pc_ctx, plan))) { // LOG_TRACE("failed to get local plan", K(ret)); // } // } break; // case OB_PHY_PLAN_REMOTE: { // if (NULL != remote_plan_) { // remote_plan_->set_dynamic_ref_handle(pc_ctx.handle_id_); // plan = remote_plan_; // } // } break; // case OB_PHY_PLAN_DISTRIBUTED: { // if (OB_FAIL(get_physical_plan(OB_PHY_PLAN_DISTRIBUTED, pc_ctx, plan))) { // if (OB_SQL_PC_NOT_EXIST == ret) { // LOG_TRACE("fail to get dist plan", K(ret)); // } else { // LOG_WARN("fail to get dist plan", K(ret)); // } // } // } break; // default: // break; // } // if (NULL == plan) { // ret = OB_SQL_PC_NOT_EXIST; // } // } // } // } // // return ret; //} #ifdef OB_BUILD_SPM int ObSqlPlanSet::try_get_local_evolution_plan(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan, bool &get_next) { int ret = OB_SUCCESS; plan = NULL; get_next = false; if ((!is_spm_closed_ && local_evolution_plan_.get_is_evolving_flag()) || pc_ctx.sql_ctx_.spm_ctx_.force_get_evolution_plan()) { if (OB_FAIL(local_evolution_plan_.get_plan(pc_ctx, plan))) { if (OB_SQL_PC_NOT_EXIST == ret) { ret = OB_SUCCESS; } SQL_PC_LOG(TRACE, "get evolution plan failed", K(ret)); } } if (OB_SUCC(ret) && NULL == plan) { get_next = true; } return ret; } int ObSqlPlanSet::try_get_dist_evolution_plan(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan, bool &get_next) { int ret = OB_SUCCESS; plan = NULL; get_next = false; if ((!is_spm_closed_ && dist_evolution_plan_.get_is_evolving_flag()) || pc_ctx.sql_ctx_.spm_ctx_.force_get_evolution_plan()) { if (OB_FAIL(dist_evolution_plan_.get_plan(pc_ctx, plan))) { if (OB_SQL_PC_NOT_EXIST == ret) { ret = OB_SUCCESS; } SQL_PC_LOG(TRACE, "get evolution plan failed", K(ret)); } } if (OB_SUCC(ret) && NULL == plan) { get_next = true; } return ret; } int ObSqlPlanSet::try_get_evolution_plan(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan, bool &get_next) { int ret = OB_SUCCESS; plan = NULL; get_next = false; if (OB_FAIL(try_get_local_evolution_plan(pc_ctx, plan, get_next))) { LOG_WARN("failed to try get local evolution plan", K(ret)); } else if (get_next && OB_FAIL(try_get_dist_evolution_plan(pc_ctx, plan, get_next))) { LOG_WARN("failed to try get dist evolution plan", K(ret)); } return ret; } #endif int ObSqlPlanSet::try_get_local_plan(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan, bool &get_next) { int ret = OB_SUCCESS; plan = NULL; get_next = false; ObPhyPlanType real_type = OB_PHY_PLAN_UNINITIALIZED; ObSEArray candi_table_locs; if (OB_ISNULL(local_plan_)) { LOG_DEBUG("local plan is null"); get_next = true; } else if (FALSE_IT(plan = local_plan_)) { } else if (OB_FAIL(get_plan_type(plan->get_table_locations(), plan->has_uncertain_local_operator(), pc_ctx, candi_table_locs, real_type))) { LOG_WARN("fail to get plan type", K(ret)); } else if (OB_PHY_PLAN_LOCAL != real_type) { LOG_DEBUG("not local plan", K(real_type)); plan = NULL; get_next = true; } if (OB_SUCC(ret) && NULL == plan) { get_next = true; } return ret; } int ObSqlPlanSet::try_get_remote_plan(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan, bool &get_next) { int ret = OB_SUCCESS; plan = NULL; get_next = false; ObPhyPlanType real_type = OB_PHY_PLAN_UNINITIALIZED; ObSEArray candi_table_locs; if (OB_ISNULL(remote_plan_)) { LOG_DEBUG("remote plan is null"); get_next = true; } else if (OB_FAIL(get_plan_type(remote_plan_->get_table_locations(), remote_plan_->has_uncertain_local_operator(), pc_ctx, candi_table_locs, real_type))) { LOG_WARN("fail to get plan type", K(ret)); } else if (OB_PHY_PLAN_REMOTE != real_type) { LOG_DEBUG("remote type is not match", K(real_type)); plan = NULL; get_next = true; } else { remote_plan_->set_dynamic_ref_handle(pc_ctx.handle_id_); plan = remote_plan_; } if (OB_SUCC(ret) && NULL == plan) { get_next = true; } return ret; } int ObSqlPlanSet::try_get_dist_plan(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan) { int ret = OB_SUCCESS; plan = NULL; if (OB_FAIL(dist_plans_.get_plan(pc_ctx, plan))) { LOG_TRACE("failed to get dist plan", K(ret)); } else if (plan != NULL) { LOG_TRACE("succeed to get dist plan", K(*plan)); } if (OB_SQL_PC_NOT_EXIST == ret) { ret = OB_SUCCESS; plan = NULL; } return ret; } int ObSqlPlanSet::get_plan_special(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *&plan) { LOG_DEBUG("get plan special", K(need_try_plan_)); int ret = OB_SUCCESS; plan = NULL; bool get_next = true; ObPhyPlanType real_type = OB_PHY_PLAN_UNINITIALIZED; ObSEArray candi_table_locs; #ifdef OB_BUILD_SPM if (OB_FAIL(try_get_evolution_plan(pc_ctx, plan, get_next))) { SQL_PC_LOG(TRACE, "get evolution plan failed", K(ret)); } #endif // try local plan if (OB_SUCC(ret) && get_next) { if (OB_FAIL(try_get_local_plan(pc_ctx, plan, get_next))) { LOG_WARN("failed to try get local plan", K(ret)); } } // try remote plan if (OB_SUCC(ret) && get_next) { if (OB_FAIL(try_get_remote_plan(pc_ctx, plan, get_next))) { LOG_WARN("failed to try get remote plan", K(ret)); } } //try dist plan if (OB_SUCC(ret) && get_next) { if (OB_FAIL(try_get_dist_plan(pc_ctx, plan))) { LOG_TRACE("failed to try get dist plan", K(ret)); } } if (OB_SUCC(ret) && nullptr == plan) { ret = OB_SQL_PC_NOT_EXIST; } return ret; } int64_t ObSqlPlanSet::get_mem_size() { int64_t plan_set_mem = 0; #ifdef OB_BUILD_SPM plan_set_mem += local_evolution_plan_.get_mem_size(); plan_set_mem += dist_evolution_plan_.get_mem_size(); #endif if (NULL != local_plan_) { plan_set_mem += local_plan_->get_mem_size(); } if (NULL != remote_plan_) { plan_set_mem += remote_plan_->get_mem_size(); } plan_set_mem += dist_plans_.get_mem_size(); return plan_set_mem; } void ObSqlPlanSet::reset() { is_all_non_partition_ = true; need_try_plan_ = 0; has_duplicate_table_ = false; //has_array_binding_ = false; is_contain_virtual_table_ = false; enable_inner_part_parallel_exec_ = false; table_locations_.reset(); if (OB_ISNULL(plan_cache_value_) || OB_ISNULL(plan_cache_value_->get_pc_alloc())) { //do nothing LOG_WARN_RET(OB_ERR_UNEXPECTED, "plan_cache_value or pc allocator is NULL"); } #ifdef OB_BUILD_SPM local_evolution_plan_.reset(); dist_evolution_plan_.reset(); #endif local_plan_ = NULL; array_binding_plan_ = NULL; remote_plan_ = NULL; dist_plans_.reset(); //local_phy_locations_.reset(); //partition_key_.reset(); ObPlanSet::reset(); } //get plan used //need_check_on_same_server: out, 是否需要检查分区在同一server, 如果里面检查过且不在同一server则置为false int ObSqlPlanSet::get_phy_locations(const ObIArray &table_locations, ObPlanCacheCtx &pc_ctx, ObIArray &candi_table_locs, bool &need_check_on_same_server) { int ret = OB_SUCCESS; need_check_on_same_server = true; DAS_CTX(pc_ctx.exec_ctx_).clear_all_location_info(); if (OB_FAIL(ObPhyLocationGetter::get_phy_locations(table_locations, pc_ctx, candi_table_locs, need_check_on_same_server))) { LOG_WARN("failed to get phy locations", K(ret), K(table_locations)); } else if (OB_FAIL(ObPhyLocationGetter::build_table_locs(pc_ctx.exec_ctx_.get_das_ctx(), table_locations, candi_table_locs))) { LOG_WARN("fail to init table locs", K(ret)); } return ret; } /* * calculate phy_plan type: *1. if not all tables are signal partition --->type is distributed *2 if all tables are signal partition: * if all partitions in local server --->type is local * if all partitions in the same remote server --->type is remote * if all partitions don't in the same server ---->type is distributed * parameter need_check_on_same_server, * TRUE: default value, need check; * FALSE: we know partitions on different servers via ObPhyLocationGetter::get_phy_locations * (when there are duplicate tables not in DML), no need to check again */ int ObSqlPlanSet::calc_phy_plan_type_v2(const ObIArray &candi_table_locs, ObPhyPlanType &plan_type, bool need_check_on_same_server) { int ret = OB_SUCCESS; int64_t N = candi_table_locs.count(); if (0 == N) { plan_type = OB_PHY_PLAN_LOCAL; SQL_PC_LOG(DEBUG, "no table used, thus local plan"); } else { bool is_all_empty = true; bool is_all_single_partition = true; for (int i = 0; is_all_single_partition && i < N; ++i) { if (candi_table_locs.at(i).get_partition_cnt() != 0) { is_all_empty = false; } if (candi_table_locs.at(i).get_partition_cnt() > 1) { is_all_single_partition = false; } } if (is_all_empty) { plan_type = OB_PHY_PLAN_LOCAL; } else if (is_all_single_partition) { bool is_same = true; ObAddr my_address = GCTX.self_addr(); ObAddr first_addr; if (!need_check_on_same_server) { is_same = false; } if (is_same && OB_FAIL(is_partition_in_same_server(candi_table_locs, is_same, first_addr))) { SQL_PC_LOG(WARN, "fail to calculate whether all partitions in same server", K(ret), K(candi_table_locs)); } else { if (is_same) { if (my_address == first_addr) { plan_type = OB_PHY_PLAN_LOCAL; } else { plan_type = OB_PHY_PLAN_REMOTE; } } else { plan_type = OB_PHY_PLAN_DISTRIBUTED; } } } else { plan_type = OB_PHY_PLAN_DISTRIBUTED; } } return ret; } int ObSqlPlanSet::calc_phy_plan_type(const ObIArray &candi_table_locs, ObPhyPlanType &plan_type) { int ret = OB_SUCCESS; int64_t phy_location_cnt = candi_table_locs.count(); if (0 == phy_location_cnt) { plan_type = OB_PHY_PLAN_LOCAL; SQL_PC_LOG(DEBUG, "no table used, thus local plan"); } else { bool is_all_empty = true; bool is_all_single_partition = true; for (int i = 0; is_all_single_partition && i < phy_location_cnt; ++i) { if (candi_table_locs.at(i).get_partition_cnt() != 0) { is_all_empty = false; } if (candi_table_locs.at(i).get_partition_cnt() > 1) { is_all_single_partition = false; } } if (is_all_empty) { plan_type = OB_PHY_PLAN_LOCAL; } else if (is_all_single_partition) { bool is_same = true; ObAddr first_addr; if (OB_FAIL(is_partition_in_same_server(candi_table_locs, is_same, first_addr))) { SQL_PC_LOG(WARN, "fail to calculate whether all partitions in same server", K(ret), K(candi_table_locs)); } else { if (is_same) { ObAddr my_address = GCTX.self_addr(); if (my_address == first_addr) { plan_type = OB_PHY_PLAN_LOCAL; } else { plan_type = OB_PHY_PLAN_REMOTE; } } else { plan_type = OB_PHY_PLAN_DISTRIBUTED; } } } else { plan_type = OB_PHY_PLAN_DISTRIBUTED; } } return ret; } //calculate whether all partitions in same server int ObSqlPlanSet::is_partition_in_same_server(const ObIArray &candi_table_locs, bool &is_same, ObAddr &first_addr) { int ret = OB_SUCCESS; int64_t phy_location_count = candi_table_locs.count(); if (phy_location_count > 0) { bool is_first = true; ObLSReplicaLocation replica_location; for (int64_t i = 0; OB_SUCC(ret) && is_same && i < phy_location_count; ++i) { int64_t partition_location_count = candi_table_locs.at(i).get_partition_cnt(); if (partition_location_count > 0) { for (int64_t j = 0; OB_SUCC(ret) && is_same && j < partition_location_count; ++j) { replica_location.reset(); const ObCandiTabletLoc &candi_table_loc = candi_table_locs.at(i).get_phy_part_loc_info_list().at(j); if (OB_FAIL(candi_table_loc.get_selected_replica(replica_location))) { SQL_PC_LOG(WARN, "fail to get selected replica", K(ret), K(candi_table_loc)); } else if (!replica_location.is_valid()) { SQL_PC_LOG(WARN, "replica_location is invalid", K(ret), K(replica_location)); } else { if (is_first) { //get first replica first_addr = replica_location.get_server(); is_same = true; is_first = false; SQL_PC_LOG(DEBUG, "part_location first replica", K(ret), K(replica_location)); } else { is_same = (replica_location.get_server() == first_addr); SQL_PC_LOG(DEBUG, "part_location replica", K(ret), K(i), K(replica_location)); } } } } else { ret = OB_ERR_UNEXPECTED; SQL_PC_LOG(WARN, "there is no partition_location in this phy_location", K(candi_table_locs.at(i))); } } } else { ret = OB_ERR_UNEXPECTED; SQL_PC_LOG(WARN, "phy_locations is empty"); } return ret; } void ObSqlPlanSet::remove_all_plan() { #ifdef OB_BUILD_SPM IGNORE_RETURN local_evolution_plan_.remove_all_plan(); IGNORE_RETURN dist_evolution_plan_.remove_all_plan(); #endif IGNORE_RETURN dist_plans_.remove_all_plan(); } //add plan used int ObSqlPlanSet::get_phy_locations(const ObTablePartitionInfoArray &partition_infos, //ObIArray &table_locs, ObIArray &candi_table_locs) { int ret = OB_SUCCESS; LOG_DEBUG("add plan partition infos", K(partition_infos)); if (OB_FAIL(ObPhyLocationGetter::get_phy_locations(partition_infos, //table_locs, candi_table_locs))) { LOG_WARN("failed to get phy location while adding plan", K(ret), K(partition_infos), K(candi_table_locs)); } else {/* do nothing */} return ret; } int ObSqlPlanSet::set_concurrent_degree(int64_t outline_param_idx, ObPhysicalPlan &plan) { int ret = OB_SUCCESS; if (OB_ISNULL(plan_cache_value_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else if (outline_param_idx != OB_INVALID_INDEX) { const ObMaxConcurrentParam *param = plan_cache_value_->get_outline_param(outline_param_idx); if (OB_ISNULL(param)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param is null", K(ret)); } else { plan.set_max_concurrent_num(param->get_concurrent_num()); if (OB_FAIL(plan.inc_concurrent_num())) { if (OB_REACH_MAX_CONCURRENT_NUM == ret) { LOG_USER_ERROR(OB_REACH_MAX_CONCURRENT_NUM, plan.get_max_concurrent_num()); } else { LOG_WARN("fail to inc concurrent num", K(ret)); } } } } return ret; } int ObSqlPlanSet::extend_param_store(const ParamStore ¶ms, ObIAllocator &allocator, ObIArray &expanded_params) { int ret = OB_SUCCESS; int64_t count = 0; for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); i++) { if (params.at(i).is_ext_sql_array()) { const ObSqlArrayObj *array_params = reinterpret_cast(params.at(i).get_ext()); if (OB_ISNULL(array_params)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("array params is null", K(ret)); } else { count = array_params->count_; break; } } } ParamStore *tmp_param_store = NULL; void *param_store_buf = NULL; ParamStore tmp_params( (ObWrapperAllocator(allocator)) ); for (int64_t vec_cnt = 0; OB_SUCC(ret) && vec_cnt < count; vec_cnt++) { if (OB_ISNULL(param_store_buf = allocator.alloc(sizeof(ParamStore)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else { tmp_param_store = new(param_store_buf)ParamStore( ObWrapperAllocator(allocator) ); if (OB_FAIL(expanded_params.push_back(tmp_param_store))) { LOG_WARN("failed to push back element", K(ret)); } } } for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); i++) { if (params.at(i).is_ext_sql_array()) { const ObSqlArrayObj *array_params = reinterpret_cast(params.at(i).get_ext()); if (OB_ISNULL(array_params) || OB_ISNULL(array_params->data_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("array params is null", K(ret), KPC(array_params)); } for (int64_t vec_cnt = 0; OB_SUCC(ret) && vec_cnt < count; vec_cnt++) { ObObjParam obj_param(array_params->data_[vec_cnt]); obj_param.set_accuracy(params.at(i).get_accuracy()); obj_param.set_result_flag(params.at(i).get_result_flag()); if (OB_FAIL(expanded_params.at(vec_cnt)->push_back(obj_param))) { LOG_WARN("fail to push param", K(ret), K(vec_cnt)); } } } else { for (int64_t vec_cnt = 0; OB_SUCC(ret) && vec_cnt < count; vec_cnt++) { if (OB_FAIL(expanded_params.at(vec_cnt)->push_back(params.at(i)))) { LOG_WARN("fail to push param", K(ret), K(vec_cnt)); } } } } // for LOG_DEBUG("extend param store", K(ret), K(count), K(expanded_params), K(params)); return ret; } int ObSqlPlanSet::get_plan_type(const ObIArray &table_locations, const bool is_contain_uncertain_op, ObPlanCacheCtx &pc_ctx, ObIArray &candi_table_locs, ObPhyPlanType &plan_type) { int ret = OB_SUCCESS; bool need_check_on_same_server = true; candi_table_locs.reuse(); if (OB_FAIL(get_phy_locations(table_locations, pc_ctx, candi_table_locs, need_check_on_same_server))) { LOG_WARN("failed to get physical locations", K(ret)); } else if (OB_FAIL(calc_phy_plan_type_v2(candi_table_locs, plan_type, need_check_on_same_server))) { LOG_WARN("failed to calcute physical plan type", K(ret)); } else { // Lookup算子支持压到远程去执行: // // Select的sql如果包含uncertain算子,不能将类型改为分布式计划 if (is_contain_uncertain_op && plan_type != OB_PHY_PLAN_LOCAL && stmt::T_SELECT != stmt_type_) { plan_type = OB_PHY_PLAN_DISTRIBUTED; } LOG_DEBUG("get plan type", K(table_locations), K(plan_type), K(candi_table_locs), K(is_contain_uncertain_op), K(stmt_type_), K(ret)); } return ret; } bool ObSqlPlanSet::is_local_plan_opt_allowed(const int last_retry_err) { bool ret_bool = false; if (OB_SUCCESS == last_retry_err) { ret_bool = true; } else if (last_retry_err == OB_TRANSACTION_SET_VIOLATION || last_retry_err == OB_TRY_LOCK_ROW_CONFLICT) { // 直接选取local计划,因为leader并没有变化 ret_bool = true; } else { ret_bool = false; } LOG_DEBUG("use direct local plan", K(ret_bool), K(last_retry_err)); return ret_bool; } bool ObSqlPlanSet::is_sql_planset() { return true; } #ifdef OB_BUILD_SPM int ObSqlPlanSet::get_evolving_evolution_task(EvolutionPlanList &evo_task_list) { int ret = OB_SUCCESS; if (local_evolution_plan_.get_is_evolving_flag() && OB_FAIL(evo_task_list.push_back(&local_evolution_plan_))) { LOG_WARN("failed to push back evolution plan", K(ret)); } else if (dist_evolution_plan_.get_is_evolving_flag() && OB_FAIL(evo_task_list.push_back(&dist_evolution_plan_))) { LOG_WARN("failed to push back evolution plan", K(ret)); } return ret; } #endif } bool ObPlanSet::match_decint_precision(const ObParamInfo ¶m_info, ObPrecision other_prec) const { bool ret = false; if (ob_is_decimal_int(param_info.type_)) { ret = (param_info.precision_ == other_prec); } else { // not decimal_int, return true ret = true; } return ret; } }