Files
oceanbase/src/sql/plan_cache/ob_plan_set.cpp

2426 lines
94 KiB
C++

/**
* 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 &param_info,
const ObObjParam &param,
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 &param_info,
const ObObjParam &param,
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 &params,
const ObIArray<int64_t> &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<const ObObj*, 16> 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<const ObSqlArrayObj*>(
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 &param_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<const ObSqlArrayObj*>(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<ObParamInfo,
//OB_MALLOC_BIG_BLOCK_SIZE,
//ObWrapperAllocator, false> &param_infos,
//const ParamStore &param_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<ObParamInfo,
OB_MALLOC_BIG_BLOCK_SIZE,
ObWrapperAllocator, false> &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) {
if (OB_FAIL(ObPlanCacheObject::match_pre_calc_cons(all_pre_calc_constraints_, pc_ctx,
is_ignore_stmt_, is_same))) {
LOG_WARN("failed to match pre calc cons", K(ret));
} else if (!is_same) {
LOG_TRACE("pre calc constraints for plan set and cur plan not match");
}
}
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 &params = 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<ObPlanSet>::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<ObPCConstParamInfo> &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<ObPCParamEqualInfo> &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<ObPreCalcExprConstraint> &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<ObPCPrivInfo> &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<ObPCConstParamInfo> *param_cons = pc_ctx.sql_ctx_.all_plan_const_param_constraints_;
ObIArray<ObPCConstParamInfo> *possible_param_cons =
pc_ctx.sql_ctx_.all_possible_const_param_constraints_;
ObIArray<ObPCParamEqualInfo> *equal_cons = pc_ctx.sql_ctx_.all_equal_param_constraints_;
ObIArray<ObPCPrivInfo> *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 &params, 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<ObPreCalcExprFrameInfo>)))) {
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<ObPreCalcExprFrameInfo>;
common::ObDList<ObPreCalcExprFrameInfo>* 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<ObPhysicalPlan&>(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<ObCandiTableLoc> 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))) {
if (OB_REACH_MAX_CONCURRENT_NUM == ret && 0 == plan.get_max_concurrent_num()) {
pc_ctx.is_max_curr_limit_ = true;
ret = OB_SUCCESS;
} else {
LOG_WARN("fail to check concurrent degree", K(ret));
}
} else {
// do nothing
}
if (OB_FAIL(ret)) {
// do nothing
} 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<const ObPhysicalPlan &>(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<TablePart, 4> 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<int64_t, 1> 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<ObCandiTableLoc, 4> 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<ObCandiTableLoc, 2> 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<ObCandiTableLoc, 2> 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<ObCandiTableLoc, 2> 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<ObTableLocation> &table_locations,
ObPlanCacheCtx &pc_ctx,
ObIArray<ObCandiTableLoc> &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<ObCandiTableLoc> &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<ObCandiTableLoc> &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<ObCandiTableLoc> &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<ObDASTableLoc> &table_locs,
ObIArray<ObCandiTableLoc> &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 &params,
ObIAllocator &allocator,
ObIArray<ParamStore *> &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<const ObSqlArrayObj*>(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<const ObSqlArrayObj*>(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<ObTableLocation> &table_locations,
const bool is_contain_uncertain_op,
ObPlanCacheCtx &pc_ctx,
ObIArray<ObCandiTableLoc> &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 &param_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;
}
}