2420 lines
94 KiB
C++
2420 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 ¶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<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 ¶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<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> ¶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<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) {
|
|
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<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 ¶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<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))) {
|
|
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<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 ¶ms,
|
|
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 ¶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;
|
|
}
|
|
|
|
}
|