/** * 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_RESV #include "sql/resolver/dml/ob_hint.h" #include "lib/utility/ob_unify_serialize.h" #include "sql/optimizer/ob_log_plan.h" #include "common/ob_smart_call.h" #include "sql/monitor/ob_sql_plan.h" namespace oceanbase { using namespace common; namespace sql { void ObPhyPlanHint::reset() { read_consistency_ = INVALID_CONSISTENCY; query_timeout_ = -1; plan_cache_policy_ = OB_USE_PLAN_CACHE_INVALID; force_trace_log_ = false; log_level_.reset(); parallel_ = -1; monitor_ = false; } OB_SERIALIZE_MEMBER(ObPhyPlanHint, read_consistency_, query_timeout_, plan_cache_policy_, force_trace_log_, log_level_, parallel_, monitor_); int ObPhyPlanHint::deep_copy(const ObPhyPlanHint &other, ObIAllocator &allocator) { int ret = OB_SUCCESS; read_consistency_ = other.read_consistency_; query_timeout_ = other.query_timeout_; plan_cache_policy_ = other.plan_cache_policy_; force_trace_log_ = other.force_trace_log_; parallel_ = other.parallel_; monitor_ = other.monitor_; if (OB_FAIL(ob_write_string(allocator, other.log_level_, log_level_))) { LOG_WARN("Failed to deep copy log level", K(ret)); } return ret; } int ObDBLinkHit::print(char *buf, int64_t &buf_len, int64_t &pos, const char* outline_indent) const { int ret = OB_SUCCESS; if (0 < tx_id_) { if (OB_FAIL(BUF_PRINTF("%s%s(\'%s\' , %ld)", outline_indent, "DBLINK_INFO", "DBLINK_TX_ID", tx_id_))) { LOG_WARN("failed to print hint", K(ret), K("DBLINK_INFO(%s , %ld)")); } } if (OB_SUCC(ret) && 0 != tm_sessid_) { if (OB_FAIL(BUF_PRINTF("%s%s(\'%s\' , %u)", outline_indent, "DBLINK_INFO", "DBLINK_TM_SESSID", tm_sessid_))) { LOG_WARN("failed to print hint", K(ret), K("DBLINK_INFO(%s , %u)")); } } if (OB_SUCC(ret) && hint_xa_trans_stop_check_lock_) { if (OB_FAIL(BUF_PRINTF("%s%s(\'%s\' , \'%s\')", outline_indent, "DBLINK_INFO", "DBLINK_XA_TRANS_STOP_CHECK_LOCK", "TRUE"))) { LOG_WARN("failed to print hint", K(ret), K("DBLINK_INFO(%s , %s)")); } } return 0; } int ObGlobalHint::merge_alloc_op_hints(const ObIArray &alloc_op_hints) { int ret = OB_SUCCESS; bool find = false; for (int64_t i = 0; OB_SUCC(ret) && i < alloc_op_hints.count(); ++i) { find = false; for (int64_t j = 0; j < alloc_op_hints_.count(); ++j) { if ((alloc_op_hints.at(i).id_ == alloc_op_hints_.at(j).id_) && (alloc_op_hints.at(i).alloc_level_ == alloc_op_hints_.at(j).alloc_level_)) { alloc_op_hints_.at(j).flags_ |= alloc_op_hints.at(i).flags_; find = true; } } if (!find) { if (OB_FAIL(alloc_op_hints_.push_back(alloc_op_hints.at(i)))) { LOG_WARN("Failed to push back tracing", K(ret)); } } } return ret; } int ObGlobalHint::merge_dop_hint(uint64_t dfo, uint64_t dop) { int ret = OB_SUCCESS; bool find = false; for (int64_t i = 0; OB_SUCC(ret) && i < dops_.count(); ++i) { if (dfo == dops_.at(i).dfo_) { find = true; if (dop > dops_.at(i).dop_) { dops_.at(i).dop_ = dop; } } } if (!find) { ObDopHint hint; hint.dfo_ = dfo; hint.dop_ = dop; if (OB_FAIL(dops_.push_back(hint))) { LOG_WARN("Failed to push back dop", K(ret)); } } LOG_DEBUG("add dop hint", K(dops_)); return ret; } int ObGlobalHint::merge_dop_hint(const ObIArray &dop_hints) { int ret = OB_SUCCESS; bool find = false; for (int64_t i = 0; OB_SUCC(ret) && i < dop_hints.count(); ++i) { if (OB_FAIL(merge_dop_hint(dop_hints.at(i).dfo_, dop_hints.at(i).dop_))) { LOG_WARN("failed to add dop hint", K(dops_)); } } return ret; } void ObGlobalHint::merge_query_timeout_hint(int64_t hint_time) { if (hint_time > 0) { if (OB_UNLIKELY(hint_time > OB_MAX_USER_SPECIFIED_TIMEOUT)) { LOG_USER_WARN(OB_ERR_TIMEOUT_TRUNCATED); hint_time = std::min(OB_MAX_USER_SPECIFIED_TIMEOUT, hint_time); } if (query_timeout_ < 0) { query_timeout_ = hint_time; } else { query_timeout_ = std::min(hint_time, query_timeout_); } } } void ObGlobalHint::merge_tm_sessid_tx_id(int64_t tx_id, uint32_t tm_sessid) { if (0 < tx_id && 0 != tm_sessid) { dblink_hints_.tx_id_ = tx_id; dblink_hints_.tm_sessid_ = tm_sessid; int ret = 0; } } void ObGlobalHint::merge_dblink_info_tx_id(int64_t tx_id) { if (0 < tx_id) { dblink_hints_.tx_id_ = tx_id; } } void ObGlobalHint::merge_dblink_info_tm_sessid(uint32_t tm_sessid) { if (0 != tm_sessid) { dblink_hints_.tm_sessid_ = tm_sessid; } } void ObGlobalHint::reset_tm_sessid_tx_id_hint() { int ret = 0; dblink_hints_.tx_id_ = 0; dblink_hints_.tm_sessid_ = 0; } void ObGlobalHint::merge_max_concurrent_hint(int64_t max_concurrent) { if (max_concurrent >= 0) { if (UNSET_MAX_CONCURRENT == max_concurrent_) { max_concurrent_ = max_concurrent; } else { max_concurrent_ = std::min(max_concurrent_, max_concurrent); } } } /* global parallel hint priority: 1. with paralle degree: parallel(8) 2. enable auto dop: parallel(auto) 3. disable auto dop: parallel(manual) */ void ObGlobalHint::merge_parallel_hint(int64_t parallel) { if (SET_ENABLE_MANUAL_DOP == parallel) { parallel_ = UNSET_PARALLEL == parallel_ ? SET_ENABLE_MANUAL_DOP : parallel_; } else if (SET_ENABLE_AUTO_DOP == parallel) { parallel_ = (UNSET_PARALLEL == parallel_ || SET_ENABLE_MANUAL_DOP == parallel_) ? SET_ENABLE_AUTO_DOP : parallel_; } else if (UNSET_PARALLEL < parallel) { if (UNSET_PARALLEL >= parallel_) { parallel_ = parallel; } else { parallel_ = std::min(parallel, parallel_); } } } void ObGlobalHint::merge_dynamic_sampling_hint(int64_t dynamic_sampling) { if (dynamic_sampling != UNSET_DYNAMIC_SAMPLING) { if (UNSET_DYNAMIC_SAMPLING == dynamic_sampling_ || dynamic_sampling == dynamic_sampling_) { dynamic_sampling_ = dynamic_sampling; } else {//conflict will cause reset origin state compatible Oracle. dynamic_sampling_ = UNSET_DYNAMIC_SAMPLING; } } } void ObGlobalHint::merge_parallel_dml_hint(ObPDMLOption pdml_option) { if (ObPDMLOption::DISABLE != pdml_option_ && ObPDMLOption::ENABLE != pdml_option_) { if (ObPDMLOption::DISABLE == pdml_option || ObPDMLOption::ENABLE == pdml_option) { pdml_option_ = pdml_option; } } else if (ObPDMLOption::ENABLE == pdml_option_ || ObPDMLOption::ENABLE == pdml_option) { pdml_option_ = ObPDMLOption::ENABLE; } else { pdml_option_ = ObPDMLOption::DISABLE; } } void ObGlobalHint::merge_param_option_hint(ObParamOption opt) { if (ObParamOption::FORCE != param_option_ && ObParamOption::EXACT != param_option_) { if (ObParamOption::FORCE == opt || ObParamOption::EXACT == opt) { param_option_ = opt; } } else if (ObParamOption::EXACT == param_option_ || ObParamOption::EXACT == opt) { param_option_ = ObParamOption::EXACT; } else { param_option_ = ObParamOption::FORCE; } } void ObGlobalHint::merge_topk_hint(int64_t precision, int64_t sharding_minimum_row_count) { topk_precision_ = std::max(topk_precision_, precision); sharding_minimum_row_count_ = std::max(sharding_minimum_row_count_, sharding_minimum_row_count); } void ObGlobalHint::merge_plan_cache_hint(ObPlanCachePolicy policy) { if (ObPlanCachePolicy::OB_USE_PLAN_CACHE_NONE == policy || ObPlanCachePolicy::OB_USE_PLAN_CACHE_NONE == plan_cache_policy_) { plan_cache_policy_ = ObPlanCachePolicy::OB_USE_PLAN_CACHE_NONE; } else if (ObPlanCachePolicy::OB_USE_PLAN_CACHE_DEFAULT == policy || ObPlanCachePolicy::OB_USE_PLAN_CACHE_DEFAULT == plan_cache_policy_) { plan_cache_policy_ = ObPlanCachePolicy::OB_USE_PLAN_CACHE_DEFAULT; } } // use the first log level hint now. void ObGlobalHint::merge_log_level_hint(const ObString &log_level) { int tmp_ret = OB_SUCCESS; if (!log_level_.empty() || log_level.empty()) { // do nothing } else if (0 == log_level.case_compare("disabled")) { //allowed for variables LOG_WARN_RET(tmp_ret, "Log level parse check error", K(tmp_ret)); } else if (OB_UNLIKELY(tmp_ret = OB_LOGGER.parse_check(log_level.ptr(), log_level.length()))) { LOG_WARN_RET(tmp_ret, "Log level parse check error", K(tmp_ret)); } else { log_level_.assign_ptr(log_level.ptr(), log_level.length()); } } void ObGlobalHint::merge_read_consistency_hint(ObConsistencyLevel read_consistency, int64_t frozen_version) { if (INVALID_CONSISTENCY == read_consistency_) { read_consistency_ = read_consistency; frozen_version_ = frozen_version; } else if (FROZEN == read_consistency_ || FROZEN == read_consistency) { read_consistency_ = FROZEN; frozen_version_ = std::max(frozen_version_, frozen_version); } else if (WEAK == read_consistency_ || WEAK == read_consistency) { read_consistency_ = WEAK; frozen_version_ = -1; } else if (STRONG == read_consistency_ || STRONG == read_consistency) { read_consistency_ = STRONG; frozen_version_ = -1; } } void ObGlobalHint::merge_opt_features_version_hint(uint64_t opt_features_version) { if (is_valid_opt_features_version(opt_features_version)) { opt_features_version_ = std::max(opt_features_version_, opt_features_version); } } // zhanyue todo: try remove this later bool ObGlobalHint::has_hint_exclude_concurrent() const { bool bret = false; return -1 != frozen_version_ || -1 != topk_precision_ || 0 != sharding_minimum_row_count_ || UNSET_QUERY_TIMEOUT != query_timeout_ || dblink_hints_.has_valid_hint() || common::INVALID_CONSISTENCY != read_consistency_ || OB_USE_PLAN_CACHE_INVALID != plan_cache_policy_ || false != force_trace_log_ || false != enable_lock_early_release_ || false != force_refresh_lc_ || !log_level_.empty() || has_parallel_hint() || false != monitor_ || ObPDMLOption::NOT_SPECIFIED != pdml_option_ || ObParamOption::NOT_SPECIFIED != param_option_ || !alloc_op_hints_.empty() || !dops_.empty() || false != disable_transform_ || false != disable_cost_based_transform_ || false != enable_append_ || !opt_params_.empty() || !ob_ddl_schema_versions_.empty() || has_gather_opt_stat_hint() || false != has_dbms_stats_hint_ || -1 != dynamic_sampling_ || flashback_read_tx_uncommitted_; } void ObGlobalHint::reset() { frozen_version_ = -1; topk_precision_ = -1; sharding_minimum_row_count_ = 0; query_timeout_ = UNSET_QUERY_TIMEOUT; read_consistency_ = common::INVALID_CONSISTENCY; plan_cache_policy_ = OB_USE_PLAN_CACHE_INVALID; force_trace_log_ = false; max_concurrent_ = UNSET_MAX_CONCURRENT; enable_lock_early_release_ = false; force_refresh_lc_ = false; log_level_.reset(); parallel_ = UNSET_PARALLEL; monitor_ = false; pdml_option_ = ObPDMLOption::NOT_SPECIFIED; param_option_ = ObParamOption::NOT_SPECIFIED; dops_.reuse(); opt_features_version_ = UNSET_OPT_FEATURES_VERSION; disable_transform_ = false; disable_cost_based_transform_ = false; opt_params_.reset(); ob_ddl_schema_versions_.reuse(); enable_append_ = false; osg_hint_.flags_ = 0; has_dbms_stats_hint_ = false; flashback_read_tx_uncommitted_ = false; dynamic_sampling_ = ObGlobalHint::UNSET_DYNAMIC_SAMPLING; alloc_op_hints_.reuse(); dblink_hints_.reset(); } int ObGlobalHint::merge_global_hint(const ObGlobalHint &other) { int ret = OB_SUCCESS; merge_read_consistency_hint(other.read_consistency_, other.frozen_version_); merge_topk_hint(other.topk_precision_, other.sharding_minimum_row_count_); merge_query_timeout_hint(other.query_timeout_); enable_lock_early_release_ |= other.enable_lock_early_release_; merge_log_level_hint(other.log_level_); enable_lock_early_release_ |= other.enable_lock_early_release_; force_refresh_lc_ |= other.force_refresh_lc_; merge_plan_cache_hint(other.plan_cache_policy_); merge_parallel_dml_hint(other.pdml_option_); force_trace_log_ |= other.force_trace_log_; merge_max_concurrent_hint(other.max_concurrent_); merge_parallel_hint(other.parallel_); monitor_ |= other.monitor_; merge_param_option_hint(other.param_option_); merge_opt_features_version_hint(other.opt_features_version_); disable_transform_ |= other.disable_transform_; disable_cost_based_transform_ |= other.disable_cost_based_transform_; enable_append_ |= other.enable_append_; osg_hint_.flags_ |= other.osg_hint_.flags_; has_dbms_stats_hint_ |= other.has_dbms_stats_hint_; flashback_read_tx_uncommitted_ |= other.flashback_read_tx_uncommitted_; dblink_hints_ = other.dblink_hints_; merge_dynamic_sampling_hint(other.dynamic_sampling_); if (OB_FAIL(merge_alloc_op_hints(other.alloc_op_hints_))) { LOG_WARN("failed to merge alloc op hints", K(ret)); } else if (OB_FAIL(merge_dop_hint(other.dops_))) { LOG_WARN("failed to merge dop hints", K(ret)); } else if (OB_FAIL(opt_params_.merge_opt_param_hint(other.opt_params_))) { LOG_WARN("failed to merge opt param hint", K(ret)); } else if (OB_FAIL(append(ob_ddl_schema_versions_, other.ob_ddl_schema_versions_))) { LOG_WARN("failed to append ddl_schema_version", K(ret)); } return ret; } int ObGlobalHint::assign(const ObGlobalHint &other) { reset(); return merge_global_hint(other); } // hints below not print // MAX_CONCURRENT // ObDDLSchemaVersionHint int ObGlobalHint::print_global_hint(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; const char* outline_indent = ObQueryHint::get_outline_indent(plan_text.is_oneline_); const bool ignore_parallel_for_dblink = EXPLAIN_DBLINK_STMT == plan_text.type_; #define PRINT_GLOBAL_HINT_STR(hint_str) \ if (OB_FAIL(BUF_PRINTF("%s%s", outline_indent, hint_str))) { \ LOG_WARN("failed to print hint", K(ret), K(hint_str)); } \ #define PRINT_GLOBAL_HINT_NUM(hint_name, num) \ if (OB_FAIL(BUF_PRINTF("%s%s(%ld)", outline_indent, hint_name, num))) { \ LOG_WARN("failed to print hint", K(ret), K(hint_name)); } \ //TOPK if (OB_SUCC(ret) && (-1 < topk_precision_ || 0 < sharding_minimum_row_count_)) { if (OB_FAIL(BUF_PRINTF("%sTOPK(%ld %ld)", outline_indent, topk_precision_, sharding_minimum_row_count_))) { LOG_WARN("failed to print topk hint", K(ret)); } } // TRACING & STAT & BLOCKING if (OB_SUCC(ret) && !alloc_op_hints_.empty()) { if (OB_FAIL(print_alloc_op_hints(plan_text))) { LOG_WARN("failed to print alloc op hints", K(ret)); } } //DOP if (OB_SUCC(ret) && !dops_.empty() && !ignore_parallel_for_dblink) { for (int64_t i = 0; OB_SUCC(ret) && i < dops_.count(); ++i) { if (OB_FAIL(BUF_PRINTF("%sDOP(%lu, %lu)", outline_indent, dops_.at(i).dfo_, dops_.at(i).dop_))) { LOG_WARN("failed to print dop hint", K(ret)); } } } //READ_CONSISTENCY && FROZEN_VERSION if (OB_SUCC(ret) && (read_consistency_ != UNSET_CONSISTENCY)) { if (FROZEN == read_consistency_ && frozen_version_ != -1) { PRINT_GLOBAL_HINT_NUM("FROZEN_VERSION", frozen_version_); } else if (FROZEN == read_consistency_) { PRINT_GLOBAL_HINT_STR("READ_CONSISTENCY( FROZEN )"); } else if (WEAK == read_consistency_) { PRINT_GLOBAL_HINT_STR("READ_CONSISTENCY( WEAK )"); } else if (STRONG == read_consistency_) { PRINT_GLOBAL_HINT_STR("READ_CONSISTENCY( STRONG )"); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected READ_CONSISTENCY", K(ret), K_(read_consistency)); } } if (OB_SUCC(ret) && UNSET_QUERY_TIMEOUT != query_timeout_) { //QUERY_TIMEOUT PRINT_GLOBAL_HINT_NUM("QUERY_TIMEOUT", query_timeout_); } if (OB_SUCC(ret) && OB_FAIL(dblink_hints_.print(buf, buf_len, pos, outline_indent))) { // DBLINK_INFO LOG_WARN("failed to print dblink hints", K(ret), K(dblink_hints_)); } if (OB_SUCC(ret) && plan_cache_policy_ != OB_USE_PLAN_CACHE_INVALID) { //USE_PLAN_CACHE const char *plan_cache_policy = "INVALID"; if (OB_USE_PLAN_CACHE_NONE == plan_cache_policy_) { PRINT_GLOBAL_HINT_STR("USE_PLAN_CACHE( NONE )"); } else if (OB_USE_PLAN_CACHE_DEFAULT == plan_cache_policy_) { PRINT_GLOBAL_HINT_STR("USE_PLAN_CACHE( DEFAULT )"); } else { } } if (OB_SUCC(ret) && force_trace_log_) { //TRACE_LOG PRINT_GLOBAL_HINT_STR("TRACE_LOG"); } if (OB_SUCC(ret) && enable_lock_early_release_) { //TRANS_PARAM if (OB_FAIL(BUF_PRINTF("%sTRANS_PARAM(\'ENABLE_EARLY_LOCK_RELEASE\' \'true\')", outline_indent))) { LOG_WARN("failed to print hint TRANS_PARAM hint", K(ret)); } } if (OB_SUCC(ret) && force_refresh_lc_) { //FORCE_REFRESH_LOCATION_CACHE PRINT_GLOBAL_HINT_STR("FORCE_REFRESH_LOCATION_CACHE"); } if (OB_SUCC(ret) && !log_level_.empty()) { //LOG_LEVEL if (OB_FAIL(BUF_PRINTF("%sLOG_LEVEL(\"%.*s\")", outline_indent, log_level_.length(), log_level_.ptr() ))) { LOG_WARN("failed to print log level hint", K(ret)); } } if (OB_SUCC(ret) && has_parallel_hint() && !ignore_parallel_for_dblink) { //PARALLEL if (has_parallel_degree()) { PRINT_GLOBAL_HINT_NUM("PARALLEL", parallel_); } else if (enable_auto_dop()) { PRINT_GLOBAL_HINT_STR("PARALLEL( AUTO )"); } else if (enable_manual_dop()) { PRINT_GLOBAL_HINT_STR("PARALLEL( MANUAL )"); } } if (OB_SUCC(ret) && monitor_) { //MONITOR PRINT_GLOBAL_HINT_STR("MONITOR"); } if (OB_SUCC(ret) && ObPDMLOption::NOT_SPECIFIED != pdml_option_) { //PDML if (ObPDMLOption::ENABLE == pdml_option_) { if (!ignore_parallel_for_dblink) { PRINT_GLOBAL_HINT_STR("ENABLE_PARALLEL_DML"); } } else if (ObPDMLOption::DISABLE == pdml_option_) { PRINT_GLOBAL_HINT_STR("DISABLE_PARALLEL_DML"); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected pdml hint value", K(ret), K_(pdml_option)); } } if (OB_SUCC(ret) && ObParamOption::NOT_SPECIFIED != param_option_) { // PARAM if (OB_UNLIKELY(ObParamOption::EXACT != param_option_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param hint value", K(ret), K_(param_option)); } else { PRINT_GLOBAL_HINT_STR("CURSOR_SHARING_EXACT"); } } // OPTIMIZER_FEATURES_ENABLE if (OB_SUCC(ret) && (has_valid_opt_features_version())) { int64_t cur_pos = 0; // if enabled trace point outline valid check tp_no = 551 and opt_features_version_ is LASTED_COMPAT_VERSION, // just print OPTIMIZER_FEATURES_ENABLE('') to avoid mysqltest changed repeatedly after upgrade LASTED_COMPAT_VERSION const bool print_empty_str = (OB_SUCCESS != (OB_E(EventTable::EN_EXPLAIN_GENERATE_PLAN_WITH_OUTLINE) OB_SUCCESS) && LASTED_COMPAT_VERSION == opt_features_version_); if (OB_FAIL(BUF_PRINTF("%s%s(\'", outline_indent, "OPTIMIZER_FEATURES_ENABLE"))) { LOG_WARN("failed to print hint", K(ret)); } else if (!print_empty_str && OB_UNLIKELY(0 == (cur_pos = ObClusterVersion::print_version_str(buf + pos, buf_len - pos, opt_features_version_)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to print version str", K(ret), K(opt_features_version_)); } else if (OB_FALSE_IT(pos += cur_pos)) { } else if (OB_FAIL(BUF_PRINTF("\')"))) { } } if (OB_SUCC(ret) && disable_query_transform()) { PRINT_GLOBAL_HINT_STR("NO_QUERY_TRANSFORMATION"); } if (OB_SUCC(ret) && disable_cost_based_transform()) { PRINT_GLOBAL_HINT_STR("NO_COST_BASED_QUERY_TRANSFORMATION"); } if (OB_SUCC(ret) && has_append()) { // APPEND PRINT_GLOBAL_HINT_STR("APPEND"); } if (OB_SUCC(ret) && UNSET_DYNAMIC_SAMPLING != dynamic_sampling_) { //DYNAMIC SAMPLING PRINT_GLOBAL_HINT_NUM("DYNAMIC_SAMPLING", dynamic_sampling_); } if (OB_SUCC(ret) && OB_FAIL(opt_params_.print_opt_param_hint(plan_text))) { LOG_WARN("failed to print opt param hint", K(ret)); } if (OB_SUCC(ret) && OB_FAIL(osg_hint_.print_osg_hint(plan_text))) { LOG_WARN("failed to print optimizer statistics gathering hint", K(ret)); } if (OB_SUCC(ret) && has_dbms_stats_hint()) { PRINT_GLOBAL_HINT_STR("DBMS_STATS"); } if (OB_SUCC(ret) && get_flashback_read_tx_uncommitted()) { PRINT_GLOBAL_HINT_STR("FLASHBACK_READ_TX_UNCOMMITTED"); } return ret; } void ObGlobalHint::merge_osg_hint(int8_t flag) { osg_hint_.flags_ |= flag; } int ObOptimizerStatisticsGatheringHint::print_osg_hint(PlanText &plan_text) const { int ret = OB_SUCCESS; const char* outline_indent = ObQueryHint::get_outline_indent(plan_text.is_oneline_); char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if ((flags_ & OB_NO_OPT_STATS_GATHER)) { PRINT_GLOBAL_HINT_STR("NO_GATHER_OPTIMIZER_STATISTICS"); } if (OB_SUCC(ret) && (flags_ & OB_OPT_STATS_GATHER)) { PRINT_GLOBAL_HINT_STR("GATHER_OPTIMIZER_STATISTICS"); } if (OB_SUCC(ret) && (flags_ & OB_APPEND_HINT)) { PRINT_GLOBAL_HINT_STR("APPEND"); } return ret; } int ObGlobalHint::print_alloc_op_hints(PlanText &plan_text) const { int ret = OB_SUCCESS; if (!alloc_op_hints_.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; const char* outline_indent = ObQueryHint::get_outline_indent(plan_text.is_oneline_); ObSEArray tracing_ids; ObSEArray stat_ids; ObSEArray blocking_ids; for (int64_t i = 0; OB_SUCC(ret) && i < alloc_op_hints_.count(); ++i) { if (alloc_op_hints_.at(i).flags_ & ObAllocOpHint::OB_MONITOR_TRACING) { if (ObAllocOpHint::OB_ENUMERATE == alloc_op_hints_.at(i).alloc_level_ && OB_FAIL(tracing_ids.push_back(alloc_op_hints_.at(i).id_))){ LOG_WARN("failed to push back", K(ret)); } } if (OB_SUCC(ret) && alloc_op_hints_.at(i).flags_ & ObAllocOpHint::OB_MONITOR_STAT) { if (ObAllocOpHint::OB_ENUMERATE == alloc_op_hints_.at(i).alloc_level_ && OB_FAIL(stat_ids.push_back(alloc_op_hints_.at(i).id_))){ LOG_WARN("failed to push back", K(ret)); } } if (OB_SUCC(ret) && alloc_op_hints_.at(i).flags_ & ObAllocOpHint::OB_MATERIAL) { if (ObAllocOpHint::OB_ALL == alloc_op_hints_.at(i).alloc_level_ && OB_FAIL(BUF_PRINTF("%sBLOCKING('ALL')", outline_indent))) { LOG_WARN("failed to print blocking hint", K(ret)); } else if (ObAllocOpHint::OB_DFO == alloc_op_hints_.at(i).alloc_level_ && OB_FAIL(BUF_PRINTF("%sBLOCKING('DFO')", outline_indent))) { LOG_WARN("failed to print blocking hint", K(ret)); } else if (ObAllocOpHint::OB_ENUMERATE == alloc_op_hints_.at(i).alloc_level_ && OB_FAIL(blocking_ids.push_back(alloc_op_hints_.at(i).id_))){ LOG_WARN("failed to push back", K(ret)); } } } if (OB_SUCC(ret) && !tracing_ids.empty()) { if (OB_FAIL(BUF_PRINTF("%sTRACING(%lu", outline_indent, tracing_ids.at(0)))) { LOG_WARN("failed to print tracing hint", K(ret)); } for (int64_t i = 1; OB_SUCC(ret) && i < tracing_ids.count(); ++i) { if (OB_FAIL(BUF_PRINTF(" %lu", tracing_ids.at(i)))) { LOG_WARN("failed to print tracing hint", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print tracing hint", K(ret)); } } if (OB_SUCC(ret) && !stat_ids.empty()) { if (OB_FAIL(BUF_PRINTF("%sSTAT(%lu", outline_indent, stat_ids.at(0)))) { LOG_WARN("failed to print tracing hint", K(ret)); } for (int64_t i = 1; OB_SUCC(ret) && i < stat_ids.count(); ++i) { if (OB_FAIL(BUF_PRINTF(" %lu", stat_ids.at(i)))) { LOG_WARN("failed to print tracing hint", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print tracing hint", K(ret)); } } if (OB_SUCC(ret) && !blocking_ids.empty()) { if (OB_FAIL(BUF_PRINTF("%sBLOCKING(%lu", outline_indent, blocking_ids.at(0)))) { LOG_WARN("failed to print blocking hint", K(ret)); } for (int64_t i = 1; OB_SUCC(ret) && i < blocking_ids.count(); ++i) { if (OB_FAIL(BUF_PRINTF(" %lu", blocking_ids.at(i)))) { LOG_WARN("failed to print blocking hint", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print blocking hint", K(ret)); } } } return ret; } DEFINE_ENUM_FUNC(ObOptParamHint::OptParamType, opt_param, OPT_PARAM_TYPE_DEF, ObOptParamHint::); int ObOptParamHint::print_opt_param_hint(PlanText &plan_text) const { int ret = OB_SUCCESS; if (OB_UNLIKELY(param_types_.count() != param_vals_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected opt param hint", K(ret), K(*this)); } else if (param_types_.empty()) { /* do nothing*/ } else { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; const char* outline_indent = ObQueryHint::get_outline_indent(plan_text.is_oneline_); const char* param_name = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < param_types_.count(); ++i) { if (OB_UNLIKELY(OptParamType::INVALID_OPT_PARAM_TYPE == param_types_.at(i)) || OB_ISNULL(param_name = get_opt_param_string(param_types_.at(i)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param type in opt param hint", K(ret), K(param_types_.at(i))); } else if (OB_UNLIKELY(!param_vals_.at(i).is_int() && !param_vals_.at(i).is_varchar())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param value type", K(ret), K(param_vals_.at(i))); } else if (OB_FAIL(BUF_PRINTF("%sOPT_PARAM(\'%s\'", outline_indent, param_name))) { LOG_WARN("failed to print hint", K(ret), K(param_name)); } else if (param_vals_.at(i).is_int() && OB_FAIL(BUF_PRINTF(" %ld)", param_vals_.at(i).get_int()))) { LOG_WARN("failed to opt param hint value", K(ret), K(param_vals_.at(i))); } else if (param_vals_.at(i).is_varchar() && OB_FAIL(BUF_PRINTF(" \'%.*s\')", param_vals_.at(i).get_varchar().length(), param_vals_.at(i).get_varchar().ptr()))) { LOG_WARN("failed to opt param hint value", K(ret), K(param_vals_.at(i))); } } } return ret; } int ObOptParamHint::merge_opt_param_hint(const ObOptParamHint &other) { int ret = OB_SUCCESS; if (OB_UNLIKELY(param_types_.count() != param_vals_.count() || other.param_types_.count() != other.param_vals_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected opt param hint", K(ret), K(other)); } for (int64_t i = 0; OB_SUCC(ret) && i < other.param_types_.count(); ++i) { if (OB_FAIL(add_opt_param_hint(other.param_types_.at(i), other.param_vals_.at(i)))) { LOG_WARN("failed to add opt param hint", K(ret), K(i), K(other)); } } return ret; } int ObOptParamHint::add_opt_param_hint(const OptParamType param_type, const ObObj &val) { int ret = OB_SUCCESS; ObObj cur_value; if (!is_param_val_valid(param_type, val)) { /* do nothing */ } else if (OB_FAIL(get_opt_param(param_type, cur_value))) { LOG_WARN("failed to get opt param", K(ret), K(param_type)); } else if (!cur_value.is_nop_value()) { /* exists opt param hint for this type, use the first opt param hint */ } else if (OB_FAIL(param_types_.push_back(param_type)) || OB_FAIL(param_vals_.push_back(val))) { LOG_WARN("failed to push back", K(ret), K(param_type), K(val)); } return ret; } bool ObOptParamHint::is_param_val_valid(const OptParamType param_type, const ObObj &val) { bool is_valid = false; switch (param_type) { case HIDDEN_COLUMN_VISIBLE: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case ROWSETS_ENABLED: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case ROWSETS_MAX_ROWS: { is_valid = val.is_int() && (0 <= val.get_int() && 65535 >= val.get_int()); break; } case DDL_EXECUTION_ID: { is_valid = val.is_int() && (0 <= val.get_int()); break; } case DDL_TASK_ID: { is_valid = val.is_int() && (0 < val.get_int()); break; } case ENABLE_NEWSORT: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case USE_PART_SORT_MGB: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case USE_DEFAULT_OPT_STAT: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case ENABLE_IN_RANGE_OPTIMIZATION: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case XSOLAPI_GENERATE_WITH_CLAUSE: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case WORKAREA_SIZE_POLICY: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("MANULE")); break; } case ENABLE_RICH_VECTOR_FORMAT: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case _ENABLE_STORAGE_CARDINALITY_ESTIMATION: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } case PRESERVE_ORDER_FOR_PAGINATION: { is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") || 0 == val.get_varchar().case_compare("false")); break; } default: LOG_TRACE("invalid opt param val", K(param_type), K(val)); break; } return is_valid; } int ObOptParamHint::get_opt_param(const OptParamType param_type, ObObj &val) const { int ret = OB_SUCCESS; int64_t idx = OB_INVALID_INDEX; val.set_nop_value(); for (int64_t i = 0; OB_INVALID_INDEX == idx && i < param_types_.count(); ++i) { if (param_type == param_types_.at(i)) { idx = i; } } if (OB_INVALID_INDEX == idx) { /* do nothing */ } else if (OB_UNLIKELY(idx < 0 || idx >= param_vals_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected idx in opt param hint", K(ret)); } else { val = param_vals_.at(idx); } return ret; } // check opt params with 'true'/'false' value int ObOptParamHint::has_enable_opt_param(const OptParamType param_type, bool &enabled) const { int ret = OB_SUCCESS; ObObj val; enabled = false; if (OB_FAIL(get_opt_param(param_type, val))) { LOG_WARN("failed to get opt param", K(ret), K(param_type)); } else if (val.is_varchar() && 0 == val.get_varchar().case_compare("true")) { enabled = true; } return ret; } int ObOptParamHint::get_bool_opt_param(const OptParamType param_type, bool &val, bool &is_exists) const { int ret = OB_SUCCESS; is_exists = false; ObObj obj; if (OB_FAIL(get_opt_param(param_type, obj))) { LOG_WARN("fail to get rowsets_enabled opt_param", K(ret)); } else if (obj.is_nop_value()) { // do nothing } else if (!obj.is_varchar()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param obj is invalid", K(ret), K(obj)); } else { val = (0 == obj.get_varchar().case_compare("true")); is_exists = true; } return ret; } int ObOptParamHint::get_bool_opt_param(const OptParamType param_type, bool &val) const { bool is_exists = false; return get_bool_opt_param(param_type, val, is_exists); } int ObOptParamHint::get_integer_opt_param(const OptParamType param_type, int64_t &val) const { int ret = OB_SUCCESS; ObObj obj; if (OB_FAIL(get_opt_param(param_type, obj))) { LOG_WARN("fail to get rowsets_enabled opt_param", K(ret)); } else if (obj.is_nop_value()) { // do nothing } else if (!obj.is_int()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param obj is invalid", K(ret), K(obj)); } else { val = obj.get_int(); } return ret; } int ObOptParamHint::has_opt_param(const OptParamType param_type, bool &has_hint) const { int ret = OB_SUCCESS; has_hint = false; ObObj obj; if (OB_FAIL(get_opt_param(param_type, obj))) { LOG_WARN("fail to get rowsets_enabled opt_param", K(ret)); } else { has_hint = !obj.is_nop_value(); } return ret; } int ObOptParamHint::check_and_get_bool_opt_param(const OptParamType param_type, bool &has_opt_param_v, bool &val) const { int ret = OB_SUCCESS; has_opt_param_v = false, val = false; if (OB_FAIL(has_opt_param(param_type, has_opt_param_v))) { LOG_WARN("check opt param failed", K(ret)); } else if (OB_FAIL(has_enable_opt_param(param_type, val))) { LOG_WARN("get opt param value failed", K(ret)); } return ret; } void ObOptParamHint::reset() { param_types_.reuse(); param_vals_.reuse(); } ObItemType ObHint::get_hint_type(ObItemType type) { switch(type) { // transform hint case T_NO_EXPAND: return T_USE_CONCAT; case T_NO_MERGE_HINT: return T_MERGE_HINT; case T_NO_UNNEST: return T_UNNEST; case T_NO_PLACE_GROUP_BY: return T_PLACE_GROUP_BY; case T_INLINE: return T_MATERIALIZE; case T_NO_SEMI_TO_INNER: return T_SEMI_TO_INNER; case T_NO_REPLACE_CONST: return T_REPLACE_CONST; case T_NO_SIMPLIFY_ORDER_BY: return T_SIMPLIFY_ORDER_BY; case T_NO_SIMPLIFY_GROUP_BY: return T_SIMPLIFY_GROUP_BY; case T_NO_SIMPLIFY_DISTINCT: return T_SIMPLIFY_DISTINCT; case T_NO_SIMPLIFY_WINFUNC: return T_SIMPLIFY_WINFUNC; case T_NO_SIMPLIFY_EXPR: return T_SIMPLIFY_EXPR; case T_NO_SIMPLIFY_LIMIT: return T_SIMPLIFY_LIMIT; case T_NO_SIMPLIFY_SUBQUERY: return T_SIMPLIFY_SUBQUERY; case T_NO_FAST_MINMAX: return T_FAST_MINMAX; case T_NO_PROJECT_PRUNE: return T_PROJECT_PRUNE; case T_NO_SIMPLIFY_SET: return T_SIMPLIFY_SET; case T_NO_OUTER_TO_INNER: return T_OUTER_TO_INNER; case T_NO_COALESCE_SQ: return T_COALESCE_SQ; case T_NO_COUNT_TO_EXISTS : return T_COUNT_TO_EXISTS; case T_NO_LEFT_TO_ANTI : return T_LEFT_TO_ANTI; case T_NO_PUSH_LIMIT : return T_PUSH_LIMIT; case T_NO_ELIMINATE_JOIN : return T_ELIMINATE_JOIN; case T_NO_WIN_MAGIC : return T_WIN_MAGIC; case T_NO_PRED_DEDUCE: return T_PRED_DEDUCE; case T_NO_PUSH_PRED_CTE: return T_PUSH_PRED_CTE; case T_NO_PULLUP_EXPR : return T_PULLUP_EXPR; case T_NO_AGGR_FIRST_UNNEST: return T_AGGR_FIRST_UNNEST; case T_NO_JOIN_FIRST_UNNEST: return T_JOIN_FIRST_UNNEST; case T_NO_DECORRELATE : return T_DECORRELATE; // optimize hint case T_NO_USE_DAS_HINT: return T_USE_DAS_HINT; case T_NO_USE_COLUMN_STORE_HINT: return T_USE_COLUMN_STORE_HINT; case T_ORDERED: return T_LEADING; case T_NO_USE_MERGE: return T_USE_MERGE; case T_NO_USE_HASH: return T_USE_HASH; case T_NO_USE_NL: return T_USE_NL; case T_NO_USE_NL_MATERIALIZATION: return T_USE_NL_MATERIALIZATION; case T_NO_PX_JOIN_FILTER: return T_PX_JOIN_FILTER; case T_NO_PX_PART_JOIN_FILTER: return T_PX_PART_JOIN_FILTER; case T_NO_USE_LATE_MATERIALIZATION: return T_USE_LATE_MATERIALIZATION; case T_NO_USE_HASH_AGGREGATE: return T_USE_HASH_AGGREGATE; case T_NO_GBY_PUSHDOWN: return T_GBY_PUSHDOWN; case T_NO_USE_HASH_DISTINCT: return T_USE_HASH_DISTINCT; case T_NO_DISTINCT_PUSHDOWN: return T_DISTINCT_PUSHDOWN; case T_NO_USE_HASH_SET: return T_USE_HASH_SET; case T_NO_USE_DISTRIBUTED_DML: return T_USE_DISTRIBUTED_DML; default: return type; } } const char* ObHint::get_hint_name(ObItemType type, bool is_enable_hint /* default true*/ ) { switch(type) { // transform hint case T_NO_REWRITE: return "NO_REWRITE"; case T_USE_CONCAT: return is_enable_hint ? "USE_CONCAT" : "NO_EXPAND"; case T_MERGE_HINT: return is_enable_hint ? "MERGE" : "NO_MERGE"; case T_UNNEST: return is_enable_hint ? "UNNEST" : "NO_UNNEST"; case T_PLACE_GROUP_BY: return is_enable_hint ? "PLACE_GROUP_BY" : "NO_PLACE_GROUP_BY"; case T_PRED_DEDUCE: return is_enable_hint ? "PRED_DEDUCE" : "NO_PRED_DEDUCE"; case T_PUSH_PRED_CTE: return is_enable_hint ? "PUSH_PRED_CTE" : "NO_PUSH_PRED_CTE"; case T_MATERIALIZE: return is_enable_hint ? "MATERIALIZE" : "INLINE"; case T_SEMI_TO_INNER: return is_enable_hint ? "SEMI_TO_INNER" : "NO_SEMI_TO_INNER"; case T_REPLACE_CONST: return is_enable_hint ? "REPLACE_CONST" :"NO_REPLACE_CONST"; case T_SIMPLIFY_ORDER_BY: return is_enable_hint ? "SIMPLIFY_ORDER_BY" : "NO_SIMPLIFY_ORDER_BY"; case T_SIMPLIFY_GROUP_BY: return is_enable_hint ? "SIMPLIFY_GROUP_BY" : "NO_SIMPLIFY_GROUP_BY"; case T_SIMPLIFY_DISTINCT: return is_enable_hint ? "SIMPLIFY_DISTINCT" : "NO_SIMPLIFY_DISTINCT"; case T_SIMPLIFY_WINFUNC: return is_enable_hint ? "SIMPLIFY_WINFUNC" : "NO_SIMPLIFY_WINFUNC"; case T_SIMPLIFY_EXPR: return is_enable_hint ? "SIMPLIFY_EXPR" : "NO_SIMPLIFY_EXPR"; case T_SIMPLIFY_LIMIT: return is_enable_hint ? "SIMPLIFY_LIMIT" : "NO_SIMPLIFY_LIMIT"; case T_SIMPLIFY_SUBQUERY: return is_enable_hint ? "SIMPLIFY_SUBQUERY" : "NO_SIMPLIFY_SUBQUERY"; case T_FAST_MINMAX: return is_enable_hint ? "FAST_MINMAX" : "NO_FAST_MINMAX"; case T_PROJECT_PRUNE: return is_enable_hint ? "PROJECT_PRUNE" : "NO_PROJECT_PRUNE"; case T_SIMPLIFY_SET: return is_enable_hint ? "SIMPLIFY_SET" : "NO_SIMPLIFY_SET"; case T_OUTER_TO_INNER: return is_enable_hint ? "OUTER_TO_INNER" : "NO_OUTER_TO_INNER"; case T_COALESCE_SQ: return is_enable_hint ? "COALESCE_SQ" : "NO_COALESCE_SQ"; case T_COUNT_TO_EXISTS : return is_enable_hint ? "COUNT_TO_EXISTS" : "NO_COUNT_TO_EXISTS"; case T_LEFT_TO_ANTI : return is_enable_hint ? "LEFT_TO_ANTI" : "NO_LEFT_TO_ANTI"; case T_ELIMINATE_JOIN : return is_enable_hint ? "ELIMINATE_JOIN" : "NO_ELIMINATE_JOIN"; case T_WIN_MAGIC : return is_enable_hint ? "WIN_MAGIC" : "NO_WIN_MAGIC"; case T_PUSH_LIMIT : return is_enable_hint ? "PUSH_LIMIT" : "NO_PUSH_LIMIT"; case T_PULLUP_EXPR : return is_enable_hint ? "PULLUP_EXPR" : "NO_PULLUP_EXPR"; case T_AGGR_FIRST_UNNEST: return is_enable_hint ? "AGGR_FIRST_UNNEST" : "NO_AGGR_FIRST_UNNEST"; case T_JOIN_FIRST_UNNEST: return is_enable_hint ? "JOIN_FIRST_UNNEST" : "NO_JOIN_FIRST_UNNEST"; case T_DECORRELATE : return is_enable_hint ? "DECORRELATE" : "NO_DECORRELATE"; // optimize hint case T_INDEX_HINT: return "INDEX"; case T_FULL_HINT: return "FULL"; case T_NO_INDEX_HINT: return "NO_INDEX"; case T_USE_DAS_HINT: return is_enable_hint ? "USE_DAS" : "NO_USE_DAS"; case T_USE_COLUMN_STORE_HINT: return is_enable_hint ? "USE_COLUMN_TABLE" : "NO_USE_COLUMN_TABLE"; case T_INDEX_SS_HINT: return "INDEX_SS"; case T_INDEX_SS_ASC_HINT: return "INDEX_SS_ASC"; case T_INDEX_SS_DESC_HINT: return "INDEX_SS_DESC"; case T_LEADING: return is_enable_hint ? "LEADING" : "ORDERED"; case T_USE_MERGE: return is_enable_hint ? "USE_MERGE" : "NO_USE_MERGE"; case T_USE_HASH: return is_enable_hint ? "USE_HASH" : "NO_USE_HASH"; case T_USE_NL: return is_enable_hint ? "USE_NL" : "NO_USE_NL"; case T_USE_NL_MATERIALIZATION: return is_enable_hint ? "USE_NL_MATERIALIZATION" : "NO_USE_NL_MATERIALIZATION"; case T_PX_JOIN_FILTER: return is_enable_hint ? "PX_JOIN_FILTER" : "NO_PX_JOIN_FILTER"; case T_PX_PART_JOIN_FILTER: return is_enable_hint ? "PX_PART_JOIN_FILTER" : "NO_PX_PART_JOIN_FILTER"; case T_PQ_DISTRIBUTE: return "PQ_DISTRIBUTE"; case T_PQ_MAP: return "PQ_MAP"; case T_PQ_SET: return "PQ_SET"; case T_USE_LATE_MATERIALIZATION: return is_enable_hint ? "USE_LATE_MATERIALIZATION" : "NO_USE_LATE_MATERIALIZATION"; case T_USE_HASH_AGGREGATE: return is_enable_hint ? "USE_HASH_AGGREGATION" : "NO_USE_HASH_AGGREGATION"; case T_TABLE_PARALLEL: return "PARALLEL"; case T_PQ_DISTRIBUTE_WINDOW: return "PQ_DISTRIBUTE_WINDOW"; case T_GBY_PUSHDOWN: return is_enable_hint ? "GBY_PUSHDOWN" : "NO_GBY_PUSHDOWN"; case T_USE_HASH_DISTINCT: return is_enable_hint ? "USE_HASH_DISTINCT" : "NO_USE_HASH_DISTINCT"; case T_DISTINCT_PUSHDOWN: return is_enable_hint ? "DISTINCT_PUSHDOWN" : "NO_DISTINCT_PUSHDOWN"; case T_USE_HASH_SET: return is_enable_hint ? "USE_HASH_SET" : "NO_USE_HASH_SET"; case T_USE_DISTRIBUTED_DML: return is_enable_hint ? "USE_DISTRIBUTED_DML" : "NO_USE_DISTRIBUTED_DML"; case T_TABLE_DYNAMIC_SAMPLING: return "DYNAMIC_SAMPLING"; case T_PQ_SUBQUERY: return "PQ_SUBQUERY"; default: return NULL; } } int ObHint::print_hint(PlanText &plan_text) const { int ret = OB_SUCCESS; const ObHint *hint = plan_text.is_used_hint_ ? get_orig_hint() : this; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; int64_t old_pos1 = -1; int64_t old_pos2 = -1; if (OB_FAIL(BUF_PRINTF("%s%s(", ObQueryHint::get_outline_indent(plan_text.is_oneline_), get_hint_name()))) { LOG_WARN("failed to print hint name", K(ret)); } else if (OB_FALSE_IT(old_pos1 = pos)) { } else if (!hint->qb_name_.empty() && OB_FAIL(BUF_PRINTF("@\"%.*s\" ", hint->qb_name_.length(), hint->qb_name_.ptr()))) { LOG_WARN("failed to print qb_name", K(ret)); } else if (!hint->qb_name_.empty() && OB_FALSE_IT(old_pos2 = pos)) { } else if (OB_FAIL(hint->print_hint_desc(plan_text))) { LOG_WARN("failed to print hint", K(ret)); } else if (old_pos1 == pos) { pos = old_pos1 - 1; // delete "(" print before } else if (old_pos2 == pos && OB_FALSE_IT(pos = old_pos2 - 1)) { // delete " " after qb_name } else if (OB_FAIL(BUF_PRINTF(")"))) { } else { /* do nothing */ } return ret; } int ObHint::print_hint_desc(PlanText &plan_text) const { UNUSED(plan_text); return OB_SUCCESS; } int ObHint::deep_copy_hint_contain_table(ObIAllocator *allocator, ObHint *&hint) const { int ret = OB_SUCCESS; hint = NULL; #define DEEP_COPY_NORMAL_HINT(hint_class) { \ hint_class *new_hint = NULL; \ if (OB_FAIL(ObQueryHint::create_hint(allocator, hint_type_, new_hint))) { \ LOG_WARN("failed to create hint", K(ret)); \ } else if (OB_FAIL(new_hint->assign(*static_cast(this)))) { \ LOG_WARN("fail to assign hint", K(ret)); \ } else { hint = new_hint; }} \ switch(hint_class_) { case HINT_JOIN_ORDER: { const ObJoinOrderHint *cur_hint = static_cast(this); ObJoinOrderHint *new_hint = NULL; if (OB_FAIL(ObQueryHint::create_hint(allocator, hint_type_, new_hint))) { LOG_WARN("failed to create hint", K(ret)); } else if (OB_FAIL(new_hint->assign(*cur_hint))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(new_hint->get_table().deep_copy(allocator, cur_hint->get_table()))) { LOG_WARN("failed to deep copy leading table", K(ret)); } else { hint = new_hint; } break; } case HINT_ACCESS_PATH: DEEP_COPY_NORMAL_HINT(ObIndexHint); break; case HINT_JOIN_METHOD: DEEP_COPY_NORMAL_HINT(ObJoinHint); break; case HINT_TABLE_PARALLEL: DEEP_COPY_NORMAL_HINT(ObTableParallelHint); break; case HINT_SEMI_TO_INNER: DEEP_COPY_NORMAL_HINT(ObSemiToInnerHint); break; case HINT_LEFT_TO_ANTI: DEEP_COPY_NORMAL_HINT(ObLeftToAntiHint); break; case HINT_ELIMINATE_JOIN: DEEP_COPY_NORMAL_HINT(ObEliminateJoinHint); break; case HINT_GROUPBY_PLACEMENT: DEEP_COPY_NORMAL_HINT(ObGroupByPlacementHint); break; case HINT_JOIN_FILTER: DEEP_COPY_NORMAL_HINT(ObJoinFilterHint); break; case HINT_WIN_MAGIC: DEEP_COPY_NORMAL_HINT(ObWinMagicHint); break; default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected hint type to deep copy", K(ret), K(hint_class_)); } } return ret; } int ObHint::create_push_down_hint(ObIAllocator *allocator, ObCollationType cs_type, const TableItem &source_table, const TableItem &target_table, ObHint *&hint) { int ret = OB_SUCCESS; hint = NULL; ObSEArray all_tables; if (OB_FAIL(get_all_table_in_hint(all_tables))) { LOG_WARN("failed to get all table in hint", K(ret)); } else { bool need_replace = false; ObHint *new_hint = NULL; for (int64_t i = 0; !need_replace && OB_SUCC(ret) && i < all_tables.count(); ++i) { if (OB_ISNULL(all_tables.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else { need_replace = all_tables.at(i)->is_match_table_item(cs_type, source_table); } } all_tables.reuse(); if (!need_replace) { hint = this; } else if (OB_FAIL(deep_copy_hint_contain_table(allocator, new_hint))) { LOG_WARN("failed to deep copy hint", K(ret)); } else if (OB_FAIL(new_hint->get_all_table_in_hint(all_tables))) { LOG_WARN("failed to get all table in hint", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < all_tables.count(); ++i) { if (OB_ISNULL(all_tables.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (all_tables.at(i)->is_match_table_item(cs_type, source_table)) { all_tables.at(i)->db_name_ = target_table.database_name_; all_tables.at(i)->table_name_ = target_table.get_object_name(); } } if (OB_SUCC(ret)) { new_hint->set_orig_hint(this); hint = new_hint; } } } return ret; } int ObHint::assign(const ObHint &other) { int ret = OB_SUCCESS; hint_type_ = other.hint_type_; hint_class_ = other.hint_class_; qb_name_ = other.qb_name_; orig_hint_ = other.orig_hint_; is_enable_hint_ = other.is_enable_hint_; return ret; } int ObHint::merge_hint(const ObHint *cur_hint, const ObHint *other, ObHintMergePolicy policy, ObIArray &conflict_hints, const ObHint *&final_hint) const { int ret = OB_SUCCESS; final_hint = cur_hint; if (OB_ISNULL(other) || OB_LIKELY(NULL != cur_hint && cur_hint->get_hint_type() != other->get_hint_type())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected input hints", K(ret), K(cur_hint), K(other)); } else if (NULL == cur_hint) { if (has_exist_in_array(conflict_hints, other->get_hint_type())) { if (RIGHT_HINT_DOMINATED == policy) { final_hint = other; if (OB_FAIL(ObOptimizerUtil::remove_item(conflict_hints, other->get_hint_type()))) { LOG_WARN("failed to remove item", K(ret), K(conflict_hints), K(*other)); } } } else { final_hint = other; } } else if (RIGHT_HINT_DOMINATED == policy) { final_hint = other; } else if (LEFT_HINT_DOMINATED == policy || cur_hint->is_enable_hint() == other->is_enable_hint()) { /* do nothing */ } else if (OB_FAIL(conflict_hints.push_back(other->get_hint_type()))) { LOG_WARN("failed to push back", K(ret)); } else { final_hint = NULL; } return ret; } int ObHint::add_tables(ObIArray &tables, ObIArray &tables_ptr) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < tables.count(); ++i) { if (OB_FAIL(tables_ptr.push_back(&tables.at(i)))) { LOG_WARN("fail to push back table in hint", K(ret)); } } return ret; } int ObHint::get_expr_str_in_hint(ObIAllocator &allocator, const ObRawExpr &expr, ObString &str) { int ret = OB_SUCCESS; str.reset(); char buf[MAX_EXPR_STR_LENGTH_IN_HINT]; int64_t buf_len = MAX_EXPR_STR_LENGTH_IN_HINT; int64_t pos = 0; if (OB_FAIL(expr.get_name(buf, buf_len, pos, EXPLAIN_HINT_FORMAT))) { ret = OB_SUCCESS; pos = (pos < 0 || pos >= buf_len) ? 0 : pos; } ObString tmp_str(pos, buf); if (OB_FAIL(ob_write_string(allocator, tmp_str, str))) { LOG_WARN("Write string error", K(ret)); } return ret; } bool ObHint::is_expr_match_str(const ObRawExpr &expr, const ObString &str) { int ret = OB_SUCCESS; bool bret = false; char buf[MAX_EXPR_STR_LENGTH_IN_HINT]; int64_t buf_len = MAX_EXPR_STR_LENGTH_IN_HINT; int64_t pos = 0; if (OB_FAIL(expr.get_name(buf, buf_len, pos, EXPLAIN_HINT_FORMAT))) { ret = OB_SUCCESS; pos = (pos < 0 || pos >= buf_len) ? 0 : pos; } ObString tmp_str(pos, buf); bret = 0 == str.case_compare(tmp_str); LOG_DEBUG("check is expr match str", K(bret), K(tmp_str), K(str)); return bret; } int ObHint::print_table_list(const ObIArray &table_list, PlanText &plan_text) { int ret = OB_SUCCESS; if (!table_list.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; for (int64_t i = 0; OB_SUCC(ret) && i < table_list.count(); ++i) { const TablesInHint &cur_table = table_list.at(i); if (cur_table.count() > 1 && OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } else if (OB_FAIL(ObTableInHint::print_join_tables_in_hint(plan_text, cur_table))) { LOG_WARN("failed to print joined tables in hint", K(ret)); } else if (cur_table.count() > 1 && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } else if (i < table_list.count() - 1 && OB_FAIL(BUF_PRINTF(" "))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } } } return ret; } int ObViewMergeHint::assign(const ObViewMergeHint &other) { int ret = OB_SUCCESS; parent_qb_name_ = other.parent_qb_name_; is_query_push_down_ = other.is_query_push_down_; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObViewMergeHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (!parent_qb_name_.empty() && !is_query_push_down_ && OB_FAIL(BUF_PRINTF("> \"%.*s\"", parent_qb_name_.length(), parent_qb_name_.ptr()))) { LOG_WARN("fail to print parent qb name", K(ret)); } else if (!parent_qb_name_.empty() && is_query_push_down_ && OB_FAIL(BUF_PRINTF("< \"%.*s\"", parent_qb_name_.length(), parent_qb_name_.ptr()))) { LOG_WARN("fail to print parent qb name", K(ret)); } return ret; } int ObOrExpandHint::assign(const ObOrExpandHint &other) { int ret = OB_SUCCESS; expand_cond_ = other.expand_cond_; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObOrExpandHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; if (!expand_cond_.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_FAIL(BUF_PRINTF("\'%.*s\'", expand_cond_.length(), expand_cond_.ptr()))) { LOG_WARN("fail to print expand condition", K(ret)); } } return ret; } int QbNameList::assign(const QbNameList& other) { int ret = OB_SUCCESS; if (OB_FAIL(qb_names_.assign(other.qb_names_))) { LOG_WARN("failed to assign qb names", K(ret)); } return ret; } bool QbNameList::has_qb_name(const ObDMLStmt *stmt) const { bool bret = false; ObString qb_name; int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else if (OB_FAIL(stmt->get_qb_name(qb_name))) { LOG_WARN("failed to get qb name", K(ret)); } else { for (int i = 0; !bret && i < qb_names_.count(); ++i) { if (0 == qb_name.case_compare(qb_names_.at(i))) { bret = true; } } } return bret; } bool QbNameList::has_qb_name(const ObString& qb_name) const { bool bret = false; for (int i = 0; !bret && i < qb_names_.count(); ++i) { if (0 == qb_name.case_compare(qb_names_.at(i))) { bret = true; } } return bret; } bool QbNameList::is_equal(const ObIArray &stmts) const { bool bret = false; if (qb_names_.count() == stmts.count()) { bool all_found = true; for (int i = 0; all_found && i < stmts.count(); ++i) { if (!has_qb_name(stmts.at(i))) { all_found = false; } } if (all_found) { bret = true; } } return bret; } bool QbNameList::is_equal(const ObIArray &qb_name_list) const { bool bret = false; if (qb_names_.count() == qb_name_list.count()) { bool all_found = true; for (int i = 0; all_found && i < qb_name_list.count(); ++i) { if (!has_qb_name(qb_name_list.at(i))) { all_found = false; } } if (all_found) { bret = true; } } return bret; } bool QbNameList::is_subset(const ObIArray &stmts) const { bool bret = false; if (qb_names_.count() <= stmts.count()) { bool all_found = true; for (int i = 0; all_found && i < qb_names_.count(); ++i) { bool find = false; ObString stmt_qb_name; for (int j = 0; !find && j < stmts.count(); j ++) { int ret = OB_SUCCESS; if (OB_ISNULL(stmts.at(j))) { LOG_WARN("unexpected null stmt"); } else if (OB_FAIL(stmts.at(j)->get_qb_name(stmt_qb_name))) { LOG_WARN("failed to get qb name"); } else if (0 == stmt_qb_name.case_compare(qb_names_.at(i))) { find = true; } } if (!find) { all_found = false; } } if (all_found) { bret = true; } } return bret; } bool QbNameList::is_subset(const ObIArray &qb_name_list) const { bool bret = false; if (qb_names_.count() <= qb_name_list.count()) { bool all_found = true; for (int i = 0; all_found && i < qb_names_.count(); ++i) { bool find = false; ObString stmt_qb_name; for (int j = 0; !find && j < qb_name_list.count(); j ++) { if (0 == qb_name_list.at(j).case_compare(qb_names_.at(i))) { find = true; } } if (!find) { all_found = false; } } if (all_found) { bret = true; } } return bret; } int QbNameList::print_qb_names(PlanText &plan_text, const bool print_quote) const { int ret = OB_SUCCESS; if (!qb_names_.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (print_quote && OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < qb_names_.count(); ++i) { const ObString &qb_name = qb_names_.at(i); if (OB_FAIL(BUF_PRINTF("\"%.*s\"", qb_name.length(), qb_name.ptr()))) { LOG_WARN("failed to print qb name", K(ret)); } else if (i != qb_names_.count() - 1 && OB_FAIL(BUF_PRINTF(" "))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } } if (OB_SUCC(ret) && print_quote && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } } return ret; } int ObCountToExistsHint::assign(const ObCountToExistsHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(qb_names_.assign(other.qb_names_))) { LOG_WARN("failed to assign qb name list", K(ret)); } else if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObLeftToAntiHint::assign(const ObLeftToAntiHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(table_list_.assign(other.get_tb_name_list()))) { LOG_WARN("failed to assign table name list", K(ret)); } return ret; } int ObLeftToAntiHint::get_all_table_in_hint(ObIArray &all_tables) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_list_.count(); ++i) { if (OB_FAIL(add_tables(table_list_.at(i), all_tables))) { LOG_WARN("failed to add tables", K(ret), K(i), K(table_list_)); } } return ret; } bool ObLeftToAntiHint::enable_left_to_anti(ObCollationType cs_type, const TableItem &table) const { bool bret = false; if (is_enable_hint()) { for (int64_t i = 0; !bret && i < table_list_.count(); ++i) { bret = ObTableInHint::is_match_table_item(cs_type, table_list_.at(i), table); } bret |= table_list_.empty(); } return bret; } int ObEliminateJoinHint::assign(const ObEliminateJoinHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(table_list_.assign(other.get_tb_name_list()))) { LOG_WARN("failed to assign table name list", K(ret)); } return ret; } int ObEliminateJoinHint::get_all_table_in_hint(ObIArray &all_tables) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_list_.count(); ++i) { if (OB_FAIL(add_tables(table_list_.at(i), all_tables))) { LOG_WARN("failed to add tables", K(ret), K(i), K(table_list_)); } } return ret; } bool ObEliminateJoinHint::enable_eliminate_join(ObCollationType cs_type, const TableItem &table) const { bool bret = false; if (is_enable_hint()) { for (int64_t i = 0; !bret && i < table_list_.count(); ++i) { bret = ObTableInHint::is_match_table_item(cs_type, table_list_.at(i), table); } bret |= table_list_.empty(); } return bret; } int ObGroupByPlacementHint::assign(const ObGroupByPlacementHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(table_list_.assign(other.get_tb_name_list()))) { LOG_WARN("failed to assign table name list", K(ret)); } return ret; } int ObGroupByPlacementHint::get_all_table_in_hint(ObIArray &all_tables) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_list_.count(); ++i) { if (OB_FAIL(add_tables(table_list_.at(i), all_tables))) { LOG_WARN("failed to add tables", K(ret), K(i), K(table_list_)); } } return ret; } bool ObGroupByPlacementHint::enable_groupby_placement(ObCollationType cs_type, const TableItem &table) const { bool bret = false; if (is_enable_hint()) { for (int64_t i = 0; !bret && i < table_list_.count(); i++) { bret = ObTableInHint::is_match_table_item(cs_type, table_list_.at(i), table); } bret |= table_list_.empty(); } return bret; } bool ObGroupByPlacementHint::enable_groupby_placement(ObCollationType cs_type, const ObIArray &tables) const { bool bret = false; int ret = OB_SUCCESS; if (is_enable_hint()) { ObSEArray check_tables; if (OB_FAIL(check_tables.assign(tables))) { LOG_WARN("assign failed", K(ret)); } for (int64_t i = 0; !bret && i < table_list_.count(); i++) { bret = ObTableInHint::is_match_table_items(cs_type, table_list_.at(i), check_tables); } bret |= table_list_.empty(); } if (OB_FAIL(ret)) bret = false; return bret; } int ObWinMagicHint::assign(const ObWinMagicHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(table_list_.assign(other.get_tb_name_list()))) { LOG_WARN("failed to assign table name list", K(ret)); } return ret; } int ObWinMagicHint::get_all_table_in_hint(ObIArray &all_tables) { int ret = OB_SUCCESS; if (OB_FAIL(add_tables(table_list_, all_tables))) { LOG_WARN("failed to add tables", K(ret), K(table_list_)); } return ret; } int ObWinMagicHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; if (!table_list_.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_UNLIKELY(table_list_.count() < 2)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table in hint count < 2", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < table_list_.count(); ++i) { const ObTableInHint &cur_table = table_list_.at(i); if (table_list_.count() > 2 && i == 1 && OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } else if (OB_FAIL(cur_table.print_table_in_hint(plan_text))) { LOG_WARN("failed to print tables in hint", K(ret)); } else if (table_list_.count() > 2 && i == table_list_.count() - 1 && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } else if (i != table_list_.count() - 1 && OB_FAIL(BUF_PRINTF(" "))) { LOG_WARN("failed to do BUF_PRINTF", K(ret)); } } } return ret; } bool ObWinMagicHint::enable_win_magic(ObCollationType cs_type, const TableItem &table) const { bool bret = false; if (is_enable_hint()) { for (int64_t i = 0; !bret && i < table_list_.count(); ++i) { bret = table_list_.at(i).is_match_table_item(cs_type, table); } bret |= table_list_.empty(); } return bret; } int ObMaterializeHint::assign(const ObMaterializeHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(qb_name_list_.assign(other.qb_name_list_))) { LOG_WARN("failed to assign qb_name list", K(ret)); } return ret; } int ObMaterializeHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; if (!qb_name_list_.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; for (int i = 0; OB_SUCC(ret) && i < qb_name_list_.count(); ++i) { if (OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("fail to print materialize hint", K(ret)); } const ObIArray &qb_names = qb_name_list_.at(i).qb_names_; for (int j = 0; OB_SUCC(ret) && j < qb_names.count(); ++j) { if (j > 0) { if (OB_FAIL(BUF_PRINTF(", "))) { LOG_WARN("fail to print materialize hint", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(BUF_PRINTF("\"%.*s\"", qb_names.at(j).length(), qb_names.at(j).ptr()))) { LOG_WARN("fail to print materialize hint", K(ret)); } } } if (OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("fail to print materialize hint", K(ret)); } } } return ret; } int ObMaterializeHint::add_qb_name_list(const QbNameList& qb_names) { int ret = OB_SUCCESS; if (OB_FAIL(qb_name_list_.push_back(qb_names))) { LOG_WARN("failed to push back qb_names", K(ret)); } return ret; } int ObMaterializeHint::get_qb_name_list(const ObString& qb_name, QbNameList &qb_names) const { int ret = OB_SUCCESS; bool is_valid = false; for (int i = 0; OB_SUCC(ret) && !is_valid && i < qb_name_list_.count(); ++i) { if (!qb_name_list_.at(i).has_qb_name(qb_name)) { //do nothing } else if (OB_FAIL(qb_names.assign(qb_name_list_.at(i)))) { LOG_WARN("failed to assign qb names", K(ret)); } else { is_valid = true; } } return ret; } bool ObMaterializeHint::enable_materialize_subquery(const ObIArray & subqueries) const { bool bret = false; for (int i = 0; !bret && i < qb_name_list_.count(); ++i) { if (qb_name_list_.at(i).is_equal(subqueries)) { bret = true; } } return is_enable_hint() && bret; } int ObSemiToInnerHint::assign(const ObSemiToInnerHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(tables_.assign(other.tables_))) { LOG_WARN("fail to assign table", K(ret)); } else if (OB_FAIL(ObHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObSemiToInnerHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (tables_.empty()) { //do nothing } else if (tables_.count() > 1 && OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("failed to print hint", K(ret)); } else if (OB_FAIL(ObTableInHint::print_join_tables_in_hint(plan_text, tables_, true))) { LOG_WARN("failed to print tables", K(ret)); } else if (tables_.count() > 1 && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print hint", K(ret)); } return ret; } bool ObSemiToInnerHint::enable_semi_to_inner(ObCollationType cs_type, const TableItem &table_item) const { bool bret = false; if (T_SEMI_TO_INNER == hint_type_) { for (int i = 0; !bret && i < tables_.count(); ++i) { bret = tables_.at(i).is_match_table_item(cs_type, table_item); } } return bret; } int ObCoalesceSqHint::assign(const ObCoalesceSqHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(ObTransHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else if (OB_FAIL(qb_name_list_.assign(other.qb_name_list_))) { LOG_WARN("failed to assign qb_name list", K(ret)); } return ret; } int ObCoalesceSqHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; if (!qb_name_list_.empty()) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; for (int i = 0; i < qb_name_list_.count(); ++i) { if (OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("fail to print coalesce sq hint", K(ret)); } const ObIArray &qb_names = qb_name_list_.at(i).qb_names_; for (int j = 0; OB_SUCC(ret) && j < qb_names.count(); ++j) { if (j > 0) { if (OB_FAIL(BUF_PRINTF(", "))) { LOG_WARN("fail to print coalesce sq hint", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(BUF_PRINTF("\"%.*s\"", qb_names.at(j).length(), qb_names.at(j).ptr()))) { LOG_WARN("fail to print coalesce sq hint", K(ret)); } } } if (OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("fail to print coalesce sq hint", K(ret)); } } } return ret; } int ObCoalesceSqHint::add_qb_name_list(const QbNameList& qb_names) { int ret = OB_SUCCESS; if (OB_FAIL(qb_name_list_.push_back(qb_names))) { LOG_WARN("failed to push back qb_names", K(ret)); } return ret; } int ObCoalesceSqHint::get_qb_name_list(const ObString& qb_name, QbNameList &qb_names) const { int ret = OB_SUCCESS; bool find = T_NO_COALESCE_SQ == hint_type_; for (int i = 0; OB_SUCC(ret) && !find && i < qb_name_list_.count(); ++i) { if (!qb_name_list_.at(i).has_qb_name(qb_name)) { //do nothing } else if (OB_FAIL(qb_names.assign(qb_name_list_.at(i)))) { LOG_WARN("failed to assign qb names", K(ret)); } else { find = true; } } return ret; } bool ObCoalesceSqHint::has_qb_name_list(const ObIArray & qb_names) const { bool bret = false; for (int i = 0; !bret && i < qb_name_list_.count(); ++i) { if (qb_name_list_.at(i).is_equal(qb_names)) { bret = true; } } return bret; } int ObTableParallelHint::assign(const ObTableParallelHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(table_.assign(other.table_))) { LOG_WARN("fail to assign table", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else { parallel_ = other.parallel_; } return ret; } int ObTableParallelHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_FAIL(table_.print_table_in_hint(plan_text))) { LOG_WARN("fail to print table in hint", K(ret)); } else if (OB_FAIL(BUF_PRINTF(" %ld", parallel_))) { LOG_WARN("fail to print index name", K(ret)); } return ret; } const ObString ObIndexHint::PRIMARY_KEY = "primary"; int ObIndexHint::assign(const ObIndexHint &other) { int ret = OB_SUCCESS; index_name_ = other.index_name_; if (OB_FAIL(table_.assign(other.table_))) { LOG_WARN("fail to assign table", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObIndexHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_FAIL(table_.print_table_in_hint(plan_text))) { LOG_WARN("fail to print table in hint", K(ret)); } else if (T_FULL_HINT == hint_type_ || T_USE_DAS_HINT == hint_type_ || T_USE_COLUMN_STORE_HINT == hint_type_) { /* do nothing */ } else if (OB_FAIL(BUF_PRINTF(" \"%.*s\"", index_name_.length(), index_name_.ptr()))) { LOG_WARN("fail to print index name", K(ret)); } return ret; } int ObJoinHint::assign(const ObJoinHint &other) { int ret = OB_SUCCESS; dist_algo_ = other.dist_algo_; if (OB_FAIL(tables_.assign(other.tables_))) { LOG_WARN("fail to assign table", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObJoinHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; const char* algo_str = get_dist_algo_str(); char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_UNLIKELY(tables_.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected join hint", K(ret)); } else if (tables_.count() > 1 && OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("failed to print hint", K(ret)); } else if (OB_FAIL(ObTableInHint::print_join_tables_in_hint(plan_text, tables_))) { LOG_WARN("failed to print join tables", K(ret)); } else if (tables_.count() > 1 && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print hint", K(ret)); } else if (T_PQ_DISTRIBUTE == hint_type_ && NULL != algo_str && OB_FAIL(BUF_PRINTF(" %s", algo_str))) { LOG_WARN("failed to print dist algo", K(ret)); } return ret; } bool ObJoinHint::is_match_local_algo(JoinAlgo join_algo) const { bool bret = false; if (NESTED_LOOP_JOIN == join_algo) { bret = is_enable_hint() ? T_USE_NL == hint_type_ : (T_USE_HASH == hint_type_ || T_USE_MERGE == hint_type_); } else if (HASH_JOIN == join_algo) { bret = is_enable_hint() ? T_USE_HASH == hint_type_ : (T_USE_NL == hint_type_ || T_USE_MERGE == hint_type_); } else if (MERGE_JOIN == join_algo) { bret = is_enable_hint() ? T_USE_MERGE == hint_type_ : (T_USE_HASH == hint_type_ || T_USE_NL == hint_type_); } return bret; } const char *ObJoinHint::get_dist_algo_str(DistAlgo dist_algo) { switch (dist_algo) { case DistAlgo::DIST_PARTITION_NONE: return "PARTITION NONE"; case DistAlgo::DIST_NONE_PARTITION: return "NONE PARTITION"; case DistAlgo::DIST_BC2HOST_NONE: return "BC2HOST NONE"; case DistAlgo::DIST_BROADCAST_NONE: return "BROADCAST NONE"; case DistAlgo::DIST_NONE_BROADCAST: return "NONE BROADCAST"; case DistAlgo::DIST_HASH_HASH: return "HASH HASH"; case DistAlgo::DIST_HASH_NONE: return "HASH NONE"; case DistAlgo::DIST_NONE_HASH: return "NONE HASH"; case DistAlgo::DIST_PULL_TO_LOCAL: return "LOCAL LOCAL"; case DistAlgo::DIST_PARTITION_WISE: return "NONE NONE"; case DistAlgo::DIST_EXT_PARTITION_WISE: return "NONE NONE"; case DistAlgo::DIST_NONE_ALL: return "NONE ALL"; case DistAlgo::DIST_ALL_NONE: return "ALL NONE"; default: return NULL; } return NULL; }; int ObJoinFilterHint::assign(const ObJoinFilterHint &other) { int ret = OB_SUCCESS; filter_table_ = other.filter_table_; pushdown_filter_table_ = other.pushdown_filter_table_; if (OB_FAIL(left_tables_.assign(other.left_tables_))) { LOG_WARN("fail to assign left tables", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObJoinFilterHint::get_all_table_in_hint(ObIArray &all_tables) { int ret = OB_SUCCESS; if (OB_FAIL(add_tables(left_tables_, all_tables))) { LOG_WARN("failed to add tables", K(ret), K(left_tables_)); } else if (OB_FAIL(all_tables.push_back(&filter_table_))) { LOG_WARN("failed to push back", K(ret)); } return ret; } int ObJoinFilterHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_FAIL(filter_table_.print_table_in_hint(plan_text))) { LOG_WARN("fail to print table in hint", K(ret)); } else if (!left_tables_.empty() && OB_FAIL(BUF_PRINTF(" "))) { } else if (left_tables_.count() > 1 && OB_FAIL(BUF_PRINTF("("))) { LOG_WARN("failed to print hint", K(ret)); } else if (OB_FAIL(ObTableInHint::print_join_tables_in_hint(plan_text, left_tables_))) { LOG_WARN("failed to print join tables", K(ret)); } else if (left_tables_.count() > 1 && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print hint", K(ret)); } else if (has_pushdown_filter_table() && OB_FAIL(BUF_PRINTF(" "))) { LOG_WARN("fail to print table in hint", K(ret)); } else if (has_pushdown_filter_table() && OB_FAIL(pushdown_filter_table_.print_table_in_hint(plan_text))) { LOG_WARN("fail to print table in hint", K(ret)); } return ret; } int ObPQSetHint::assign(const ObPQSetHint &other) { int ret = OB_SUCCESS; left_branch_ = other.left_branch_; if (OB_FAIL(dist_methods_.assign(other.dist_methods_))) { LOG_WARN("fail to assign dist methods", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObPQSetHint::set_pq_set_hint(const DistAlgo dist_algo, const int64_t child_num, const int64_t random_none_idx) { int ret = OB_SUCCESS; dist_methods_.reuse(); if (OB_UNLIKELY(child_num < 2 || random_none_idx >= child_num) ||OB_UNLIKELY(random_none_idx < 0 && DistAlgo::DIST_SET_RANDOM == dist_algo)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected params", K(ret), K(child_num), K(random_none_idx), K(dist_algo)); } else if (DistAlgo::DIST_BASIC_METHOD == dist_algo) { /* do nothing */ } else if (OB_FAIL(dist_methods_.prepare_allocate(child_num))) { LOG_WARN("fail to prepare allocate", K(ret), K(child_num)); } else if (2 == child_num) { switch (dist_algo) { case DistAlgo::DIST_PULL_TO_LOCAL: { dist_methods_.at(0) = T_DISTRIBUTE_LOCAL; dist_methods_.at(1) = T_DISTRIBUTE_LOCAL; break; } case DistAlgo::DIST_PARTITION_WISE: { dist_methods_.at(0) = T_DISTRIBUTE_NONE; dist_methods_.at(1) = T_DISTRIBUTE_NONE; break; } case DistAlgo::DIST_EXT_PARTITION_WISE: { dist_methods_.at(0) = T_DISTRIBUTE_NONE; dist_methods_.at(1) = T_DISTRIBUTE_NONE; break; } case DistAlgo::DIST_SET_PARTITION_WISE: { dist_methods_.at(0) = T_DISTRIBUTE_NONE; dist_methods_.at(1) = T_DISTRIBUTE_NONE; break; } case DistAlgo::DIST_NONE_ALL: { dist_methods_.at(0) = T_DISTRIBUTE_NONE; dist_methods_.at(1) = T_DISTRIBUTE_ALL; break; } case DistAlgo::DIST_ALL_NONE: { dist_methods_.at(0) = T_DISTRIBUTE_ALL; dist_methods_.at(1) = T_DISTRIBUTE_NONE; break; } case DistAlgo::DIST_HASH_HASH: { dist_methods_.at(0) = T_DISTRIBUTE_HASH; dist_methods_.at(1) = T_DISTRIBUTE_HASH; break; } case DistAlgo::DIST_PARTITION_NONE: { dist_methods_.at(0) = T_DISTRIBUTE_PARTITION; dist_methods_.at(1) = T_DISTRIBUTE_NONE; break; } case DistAlgo::DIST_HASH_NONE: { dist_methods_.at(0) = T_DISTRIBUTE_HASH; dist_methods_.at(1) = T_DISTRIBUTE_NONE; break; } case DistAlgo::DIST_NONE_PARTITION: { dist_methods_.at(0) = T_DISTRIBUTE_NONE; dist_methods_.at(1) = T_DISTRIBUTE_PARTITION; break; } case DistAlgo::DIST_NONE_HASH: { dist_methods_.at(0) = T_DISTRIBUTE_NONE; dist_methods_.at(1) = T_DISTRIBUTE_HASH; break; } case DistAlgo::DIST_SET_RANDOM: { dist_methods_.at(0) = T_DISTRIBUTE_RANDOM; dist_methods_.at(1) = T_DISTRIBUTE_RANDOM; dist_methods_.at(random_none_idx) = T_DISTRIBUTE_NONE; break; } default : { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected dist algo", K(ret), K(dist_algo)); } } } else { // multi child union all ObItemType method = T_INVALID; if (DistAlgo::DIST_PARTITION_WISE == dist_algo) { method = T_DISTRIBUTE_NONE; } else if (DistAlgo::DIST_PULL_TO_LOCAL == dist_algo) { method = T_DISTRIBUTE_LOCAL; } else if (DistAlgo::DIST_SET_PARTITION_WISE == dist_algo) { method = T_DISTRIBUTE_NONE; } else if (DistAlgo::DIST_EXT_PARTITION_WISE == dist_algo) { method = T_DISTRIBUTE_NONE; } else if (DistAlgo::DIST_SET_RANDOM == dist_algo) { method = T_DISTRIBUTE_RANDOM; } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected dist algo", K(ret), K(dist_algo)); } if (OB_SUCC(ret)) { for (int i = 0; i < child_num; ++i) { dist_methods_.at(i) = method; } if (DistAlgo::DIST_SET_RANDOM == dist_algo) { dist_methods_.at(random_none_idx) = T_DISTRIBUTE_NONE; } } } return ret; } int ObPQSetHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_UNLIKELY(false == is_valid_dist_methods(dist_methods_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected pq set hint", K(ret)); } else if (!left_branch_.empty() && OB_FAIL(BUF_PRINTF(" \"%.*s\"", left_branch_.length(), left_branch_.ptr()))) { LOG_WARN("failed to print left branch qb name", K(ret)); } for (int i = 0; OB_SUCC(ret) && i < dist_methods_.count(); ++i) { if (OB_FAIL(BUF_PRINTF(" %s", get_dist_method_str(dist_methods_.at(i))))) { LOG_WARN("failed to print dist algo", K(ret)); } } return ret; } bool ObPQSetHint::is_valid_dist_methods(const ObIArray &dist_methods) { int64_t random_none_idx = OB_INVALID_INDEX; return DistAlgo::DIST_INVALID_METHOD != get_dist_algo(dist_methods, random_none_idx); } // DistAlgo::DIST_BASIC_METHOD indicate DistAlgo ObPQSetHint::get_dist_algo(const ObIArray &dist_methods, int64_t &random_none_idx) { DistAlgo dist_algo = DistAlgo::DIST_INVALID_METHOD; random_none_idx = OB_INVALID_INDEX; if (dist_methods.empty()) { dist_algo = DistAlgo::DIST_BASIC_METHOD; } else if (dist_methods.count() < 2) { /* do nothing */ } else if (2 == dist_methods.count()) { const ObItemType method1 = dist_methods.at(0); const ObItemType method2 = dist_methods.at(1); if (T_DISTRIBUTE_LOCAL == method1 && T_DISTRIBUTE_LOCAL == method2) { dist_algo = DistAlgo::DIST_PULL_TO_LOCAL; } else if (T_DISTRIBUTE_NONE == method1 && T_DISTRIBUTE_NONE == method2) { dist_algo = DistAlgo::DIST_PARTITION_WISE; } else if (T_DISTRIBUTE_NONE == method1 && T_DISTRIBUTE_ALL == method2) { dist_algo = DistAlgo::DIST_NONE_ALL; } else if (T_DISTRIBUTE_ALL == method1 && T_DISTRIBUTE_NONE == method2) { dist_algo = DistAlgo::DIST_ALL_NONE; } else if (T_DISTRIBUTE_HASH == method1 && T_DISTRIBUTE_HASH == method2) { dist_algo = DistAlgo::DIST_HASH_HASH; } else if (T_DISTRIBUTE_PARTITION == method1 && T_DISTRIBUTE_NONE == method2) { dist_algo = DistAlgo::DIST_PARTITION_NONE; } else if (T_DISTRIBUTE_NONE == method1 && T_DISTRIBUTE_PARTITION == method2) { dist_algo = DistAlgo::DIST_NONE_PARTITION; } else if (T_DISTRIBUTE_HASH == method1 && T_DISTRIBUTE_NONE == method2) { dist_algo = DistAlgo::DIST_HASH_NONE; } else if (T_DISTRIBUTE_NONE == method1 && T_DISTRIBUTE_HASH == method2) { dist_algo = DistAlgo::DIST_NONE_HASH; } else if (T_DISTRIBUTE_NONE == method1 && T_DISTRIBUTE_RANDOM == method2) { dist_algo = DistAlgo::DIST_SET_RANDOM; random_none_idx = 0; } else if (T_DISTRIBUTE_RANDOM == method1 && T_DISTRIBUTE_NONE == method2) { dist_algo = DistAlgo::DIST_SET_RANDOM; random_none_idx = 1; } } else { // multi child union all int64_t tmp = DistAlgo::DIST_PARTITION_WISE | DistAlgo::DIST_PULL_TO_LOCAL | DistAlgo::DIST_SET_RANDOM; for (int i = 0; DistAlgo::DIST_INVALID_METHOD != tmp && i < dist_methods.count(); ++i) { const ObItemType method = dist_methods.at(i); if (T_DISTRIBUTE_NONE != method) { tmp &= ~DistAlgo::DIST_PARTITION_WISE; } if (T_DISTRIBUTE_LOCAL != method) { tmp &= ~DistAlgo::DIST_PULL_TO_LOCAL; } if (T_DISTRIBUTE_NONE != method && T_DISTRIBUTE_RANDOM != method) { tmp &= ~DistAlgo::DIST_SET_RANDOM; } else if (T_DISTRIBUTE_NONE == method) { if (OB_INVALID_INDEX == random_none_idx) { random_none_idx = i; } else { tmp &= ~DistAlgo::DIST_SET_RANDOM; } } } if (DistAlgo::DIST_PARTITION_WISE == tmp || DistAlgo::DIST_PULL_TO_LOCAL == tmp || DistAlgo::DIST_SET_RANDOM == tmp) { dist_algo = sql::get_dist_algo(tmp); } } return dist_algo; } const char *ObPQSetHint::get_dist_method_str(const ObItemType dist_method) { switch (dist_method) { case T_DISTRIBUTE_ALL: return "ALL"; case T_DISTRIBUTE_NONE: return "NONE"; case T_DISTRIBUTE_PARTITION: return "PARTITION"; case T_DISTRIBUTE_HASH: return "HASH"; case T_DISTRIBUTE_LOCAL: return "LOCAL"; case T_DISTRIBUTE_RANDOM: return "RANDOM"; default: return NULL; } return NULL; }; int ObPQSubqueryHint::assign(const ObPQSubqueryHint &other) { int ret = OB_SUCCESS; dist_algo_ = other.dist_algo_; if (OB_FAIL(sub_qb_names_.assign(other.sub_qb_names_))) { LOG_WARN("fail to assign subplan qb names", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObPQSubqueryHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; const char *algo_str = NULL; if (OB_FAIL(sub_qb_names_.print_qb_names(plan_text, true))) { LOG_WARN("failed to print qb names", K(ret)); } else if (NULL != (algo_str = ObJoinHint::get_dist_algo_str(get_dist_algo())) && OB_FAIL(BUF_PRINTF(" %s", algo_str))) { LOG_WARN("failed to print dist algo", K(ret)); } return ret; } int ObJoinOrderHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; if (is_ordered_hint()) { /* do nothing */ } else if (OB_FAIL(table_.print_leading_table(plan_text))) { LOG_WARN("fail to print leading table", K(ret)); } return ret; } int ObJoinOrderHint::assign(const ObJoinOrderHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(table_.assign(other.table_))) { LOG_WARN("fail to assign table", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } return ret; } int ObJoinOrderHint::merge_hint(const ObHint *cur_hint, const ObHint *other, ObHintMergePolicy policy, ObIArray &conflict_hints, const ObHint *&final_hint) const { int ret = OB_SUCCESS; final_hint = cur_hint; if (OB_ISNULL(other) || OB_UNLIKELY(!other->is_join_order_hint()) || OB_UNLIKELY(NULL != cur_hint && !cur_hint->is_join_order_hint())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected hint", K(ret), K(other), K(cur_hint)); } else if (NULL == cur_hint) { if (has_exist_in_array(conflict_hints, other->get_hint_type())) { const ObJoinOrderHint *other_join_order = static_cast(other); if (other_join_order->is_ordered_hint() || RIGHT_HINT_DOMINATED == policy) { final_hint = other; if (OB_FAIL(ObOptimizerUtil::remove_item(conflict_hints, other->get_hint_type()))) { LOG_WARN("failed to remove item", K(ret), K(conflict_hints), K(*other)); } } } else { final_hint = other; } } else { const ObJoinOrderHint *cur_join_order = static_cast(cur_hint); const ObJoinOrderHint *other_join_order = static_cast(other); if (LEFT_HINT_DOMINATED == policy || cur_join_order->is_ordered_hint()) { /* do nothing */ } else if (RIGHT_HINT_DOMINATED == policy || other_join_order->is_ordered_hint()) { final_hint = other; } else if (OB_FAIL(conflict_hints.push_back(other->get_hint_type()))) { LOG_WARN("failed to push back", K(ret)); } else { final_hint = NULL; } } return ret; } int ObLeadingTable::assign(const ObLeadingTable &other) { int ret = OB_SUCCESS; table_ = other.table_; left_table_ = other.left_table_; right_table_ = other.right_table_; return ret; } DEF_TO_STRING(ObLeadingTable) { int64_t pos = 0; J_OBJ_START(); if (NULL != table_) { J_KV(K_(table)); } else { J_KV(K_(left_table)); J_COMMA(); J_KV(K_(right_table)); } J_OBJ_END(); return pos; } ObTableInHint *ObLeadingTable::find_match_hint_table(ObCollationType cs_type, const TableItem &table_item) { ObTableInHint *table = NULL; if (NULL != table_ && table_->is_match_table_item(cs_type, table_item)) { table = table_; } else if (NULL != left_table_ && NULL != (table = left_table_->find_match_hint_table(cs_type, table_item))) { /* do nothing */ } else if (NULL != right_table_ && NULL != (table = right_table_->find_match_hint_table(cs_type, table_item))) { /* do nothing */ } return table; } int ObLeadingTable::get_all_table_in_leading_table(ObIArray &all_tables) { int ret = OB_SUCCESS; if (NULL != table_ && OB_FAIL(all_tables.push_back(table_))) { LOG_WARN("failed to push back hint table", K(ret)); } else if (NULL != left_table_ && OB_FAIL(SMART_CALL(left_table_->get_all_table_in_leading_table(all_tables)))) { LOG_WARN("failed to get all table in leading table", K(ret)); } else if (NULL != left_table_ && OB_FAIL(SMART_CALL(right_table_->get_all_table_in_leading_table(all_tables)))) { LOG_WARN("failed to get all table in leading table", K(ret)); } return ret; } int ObLeadingTable::print_leading_table(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_UNLIKELY(!is_valid())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected leading table", K(ret), K(table_), K(left_table_), K(right_table_)); } else if (is_single_table()) { if (OB_FAIL(table_->print_table_in_hint(plan_text))) { LOG_WARN("fail to print table in hint", K(ret)); } } else if (OB_FAIL(BUF_PRINTF("("))) { } else if (OB_FAIL(SMART_CALL(left_table_->print_leading_table(plan_text)))) { LOG_WARN("fail to print leading table", K(ret)); } else if (OB_FAIL(BUF_PRINTF(" "))) { } else if (OB_FAIL(SMART_CALL(right_table_->print_leading_table(plan_text)))) { LOG_WARN("fail to print leading table", K(ret)); } else if (OB_FAIL(BUF_PRINTF(")"))) { } else { /* do nothing */ } return ret; } // do not copy string buf int ObLeadingTable::deep_copy(ObIAllocator *allocator, const ObLeadingTable &other) { int ret = OB_SUCCESS; reset(); if (NULL != other.table_) { if (OB_FAIL(ObQueryHint::create_hint_table(allocator, table_))) { LOG_WARN("fail to create hint table", K(ret)); } else if (OB_FAIL(table_->assign(*other.table_))) { LOG_WARN("fail to assign hint table", K(ret)); } } else if (OB_FAIL(ObQueryHint::create_leading_table(allocator, left_table_))) { LOG_WARN("fail to create leading table", K(ret)); } else if (OB_FAIL(SMART_CALL(left_table_->deep_copy(allocator, *other.left_table_)))) { LOG_WARN("fail to deep copy leading table", K(ret)); } else if (OB_FAIL(ObQueryHint::create_leading_table(allocator, right_table_))) { LOG_WARN("fail to create leading table", K(ret)); } else if (OB_FAIL(SMART_CALL(right_table_->deep_copy(allocator, *other.right_table_)))) { LOG_WARN("fail to deep copy leading table", K(ret)); } return ret; } int ObTableInHint::assign(const ObTableInHint &other) { int ret = OB_SUCCESS; qb_name_ = other.qb_name_; db_name_ = other.db_name_; table_name_ = other.table_name_; return ret; } bool ObTableInHint::equal(const ObTableInHint& other) const { return qb_name_.case_compare(other.qb_name_) == 0 && db_name_.case_compare(other.db_name_) == 0 && table_name_.case_compare(other.table_name_) == 0; } DEF_TO_STRING(ObTableInHint) { int64_t pos = 0; J_OBJ_START(); if (!qb_name_.empty()) { J_KV(K_(qb_name)); } if (!db_name_.empty()) { J_KV(K_(db_name)); J_COMMA(); } J_KV(K_(table_name)); J_OBJ_END(); return pos; } int ObTableInHint::print_join_tables_in_hint(PlanText &plan_text, const ObIArray &tables, bool ignore_qb_name /* default false */) { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; for (int64_t i = 0; OB_SUCC(ret) && i < tables.count(); ++i) { if (OB_FAIL(tables.at(i).print_table_in_hint(plan_text, ignore_qb_name))) { LOG_WARN("fail to print table in hint", K(ret)); } else if (i < tables.count() - 1 && OB_FAIL(BUF_PRINTF(" "))) { } else { /* do nothing */ } } return ret; } int ObTableInHint::print_table_in_hint(PlanText &plan_text, bool ignore_qb_name /* default false */) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_UNLIKELY(table_name_.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get empty table name for table in hint", K(ret), K(table_name_)); } else if (!db_name_.empty() && OB_FAIL(BUF_PRINTF("\"%.*s\".", db_name_.length(), db_name_.ptr()))) { LOG_WARN("fail to print db_name", K(ret), K(db_name_), K(buf), K(buf_len), K(pos)); } else if (OB_FAIL(BUF_PRINTF("\"%.*s\"", table_name_.length(), table_name_.ptr()))) { LOG_WARN("fail to print table_name", K(ret), K(table_name_), K(buf), K(buf_len), K(pos)); } else if (!ignore_qb_name && !qb_name_.empty() && OB_FAIL(BUF_PRINTF("@\"%.*s\"", qb_name_.length(), qb_name_.ptr()))) { LOG_WARN("fail to print qb_name", K(ret), K(qb_name_), K(buf), K(buf_len), K(pos)); } return ret; } // check table match table_item ignore qb_name_ bool ObTableInHint::is_match_table_item(ObCollationType cs_type, const TableItem &table_item) const { return 0 == ObCharset::strcmp(cs_type, table_name_, table_item.get_object_name()) && (db_name_.empty() || 0 == ObCharset::strcmp(cs_type, db_name_, table_item.database_name_)); } bool ObTableInHint::is_match_physical_table_item(ObCollationType cs_type, const TableItem &table_item) const { return 0 == ObCharset::strcmp(cs_type, table_name_, table_item.table_name_) && (db_name_.empty() || 0 == ObCharset::strcmp(cs_type, db_name_, table_item.database_name_)); } bool ObTableInHint::is_match_table_item(ObCollationType cs_type, const ObIArray &tables, const TableItem &table_item) { bool bret = false; if (!table_item.is_joined_table()) { bret = 1 == tables.count() && tables.at(0).is_match_table_item(cs_type, table_item); } else if (tables.count() != static_cast(table_item).single_table_ids_.count()) { bret = false; } else { int ret = OB_SUCCESS; const TableItem *cur_table = NULL; ObSEArray table_items; if (OB_FAIL(table_items.push_back(&table_item))) { LOG_WARN("fail to push back", K(ret)); } else { bret = true; for (int64_t i = 0; bret && OB_SUCC(ret) && i < table_items.count();) { if (OB_ISNULL(cur_table = table_items.at(i))) { bret = false; } else if (cur_table->is_joined_table()) { const JoinedTable *joined_table = static_cast(cur_table); if (OB_FAIL(table_items.push_back(joined_table->right_table_))) { LOG_WARN("fail to push back", K(ret)); } else { table_items.at(i) = joined_table->left_table_; } } else { bret = false; for (int64_t j = 0; !bret && j < tables.count(); ++j) { bret = tables.at(j).is_match_table_item(cs_type, *cur_table); } ++i; } } if (OB_FAIL(ret)) { bret = false; } } } return bret; } bool ObTableInHint::is_match_table_items(ObCollationType cs_type, const ObIArray &tables, ObIArray &table_items) { int ret = OB_SUCCESS; TableItem *cur_table = NULL; bool bret = true; for (int64_t i = 0; bret && OB_SUCC(ret) && i < table_items.count();) { if (OB_ISNULL(cur_table = table_items.at(i))) { bret = false; } else if (cur_table->is_joined_table()) { JoinedTable *joined_table = static_cast(cur_table); if (OB_FAIL(table_items.push_back(joined_table->right_table_))) { LOG_WARN("fail to push back", K(ret)); } else { table_items.at(i) = joined_table->left_table_; } } else { bret = false; for (int64_t j = 0; !bret && j < tables.count(); ++j) { bret = tables.at(j).is_match_table_item(cs_type, *cur_table); } ++i; } } if (OB_FAIL(ret)) { bret = false; } return bret; } void ObTableInHint::set_table(const TableItem& table) { qb_name_.assign_ptr(table.qb_name_.ptr(), table.qb_name_.length()); if (!table.alias_name_.empty()) { table_name_.assign_ptr(table.alias_name_.ptr(), table.alias_name_.length()); } else if (table.is_synonym()) { table_name_.assign_ptr(table.synonym_name_.ptr(), table.synonym_name_.length()); db_name_.assign_ptr(table.synonym_db_name_.ptr(), table.synonym_db_name_.length()); } else { table_name_.assign_ptr(table.table_name_.ptr(), table.table_name_.length()); if (table.is_basic_table()) { db_name_.assign_ptr(table.database_name_.ptr(), table.database_name_.length()); } } } const char *ObWindowDistHint::get_dist_algo_str(WinDistAlgo dist_algo) { switch (dist_algo) { case WinDistAlgo::WIN_DIST_NONE: return "NONE"; case WinDistAlgo::WIN_DIST_HASH: return "HASH"; case WinDistAlgo::WIN_DIST_RANGE: return "RANGE"; case WinDistAlgo::WIN_DIST_LIST: return "LIST"; default: return NULL; } return NULL; }; int ObWindowDistHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < win_dist_options_.count(); ++i) { if (OB_FAIL(win_dist_options_.at(i).print_win_dist_option(plan_text))) { LOG_WARN("failed to print win dist option", K(ret), K(i)); } } return ret; } int ObWindowDistHint::add_win_dist_option(const ObIArray &all_win_funcs, const ObIArray &cur_win_funcs, const WinDistAlgo algo, const bool is_push_down, const bool use_hash_sort, const bool use_topn_sort) { int ret = OB_SUCCESS; ObSEArray win_func_idxs; int64_t idx = OB_INVALID_INDEX; for (int64_t i = 0; OB_SUCC(ret) && i < cur_win_funcs.count(); ++i) { if (OB_UNLIKELY(!ObOptimizerUtil::find_item(all_win_funcs, cur_win_funcs.at(i), &idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to find item", K(ret), K(all_win_funcs), K(cur_win_funcs)); } else if (OB_FAIL(win_func_idxs.push_back(idx))) { LOG_WARN("failed to push back", K(ret)); } } if (OB_SUCC(ret) && add_win_dist_option(win_func_idxs, algo, is_push_down, use_hash_sort, use_topn_sort)) { LOG_WARN("failed to add win dist option", K(ret)); } return ret; } int ObWindowDistHint::add_win_dist_option(const ObIArray &win_func_idxs, const WinDistAlgo algo, const bool is_push_down, const bool use_hash_sort, const bool use_topn_sort) { int ret = OB_SUCCESS; int64_t idx = win_dist_options_.count(); if (OB_FAIL(win_dist_options_.prepare_allocate(win_dist_options_.count() + 1))) { LOG_WARN("array prepare allocate failed", K(ret)); } else { WinDistOption &win_dist_option = win_dist_options_.at(idx); win_dist_option.algo_ = algo; win_dist_option.is_push_down_ = is_push_down; win_dist_option.use_hash_sort_ = use_hash_sort; win_dist_option.use_topn_sort_ = use_topn_sort; if (win_dist_option.win_func_idxs_.assign(win_func_idxs)) { LOG_WARN("failed to add win dist option", K(ret)); } } return ret; } int ObWindowDistHint::WinDistOption::print_win_dist_option(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_UNLIKELY(!is_valid())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid WinDistOption", K(ret), K(*this)); } else if (win_func_idxs_.empty()) { /* do nothing */ } else if (OB_FAIL(BUF_PRINTF(" (%ld", win_func_idxs_.at(0)))) { LOG_WARN("fail to print win func idx", K(ret), K(win_func_idxs_)); } else { for (int64_t i = 1; OB_SUCC(ret) && i < win_func_idxs_.count(); ++i) { if (OB_FAIL(BUF_PRINTF(",%ld", win_func_idxs_.at(i)))) { LOG_WARN("fail to print win func idx", K(ret), K(win_func_idxs_)); } } if (OB_SUCC(ret) && OB_FAIL(BUF_PRINTF(")"))) { LOG_WARN("failed to print win func idx", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(BUF_PRINTF(" %s", ObWindowDistHint::get_dist_algo_str(algo_)))) { LOG_WARN("failed to print win func dist algo", K(ret)); } else if (use_hash_sort_ && OB_FAIL(BUF_PRINTF(" PARTITION_SORT"))) { LOG_WARN("failed to print win func sort", K(ret)); } else if (is_push_down_ && OB_FAIL(BUF_PRINTF(" PUSHDOWN"))) { LOG_WARN("failed to print win func push down", K(ret)); } else if (use_topn_sort_ && OB_FAIL(BUF_PRINTF(" WF_TOPN"))) { LOG_WARN("failed to print win func sort", K(ret)); } return ret; } bool ObWindowDistHint::WinDistOption::is_valid() const { bool bret = true; if (WinDistAlgo::WIN_DIST_INVALID == algo_) { bret = false; } else if (WinDistAlgo::WIN_DIST_HASH != algo_ && is_push_down_) { bret = false; } else if (WinDistAlgo::WIN_DIST_HASH != algo_ && WinDistAlgo::WIN_DIST_NONE != algo_ && (use_hash_sort_ || use_topn_sort_)) { bret = false; } else { for (int64_t i = 0; bret && i < win_func_idxs_.count(); ++i) { bret = win_func_idxs_.at(i) >= 0; } } return bret; } int ObWindowDistHint::WinDistOption::assign(const WinDistOption& other) { int ret = OB_SUCCESS; algo_ = other.algo_; use_hash_sort_ = other.use_hash_sort_; use_topn_sort_ = other.use_topn_sort_; is_push_down_ = other.is_push_down_; if (OB_FAIL(win_func_idxs_.assign(other.win_func_idxs_))) { LOG_WARN("failed to assign", K(ret)); } return ret; } void ObWindowDistHint::WinDistOption::reset() { algo_ = WinDistAlgo::WIN_DIST_INVALID; use_hash_sort_ = false; use_topn_sort_ = false; is_push_down_ = false; win_func_idxs_.reuse(); } int ObAggHint::assign(const ObAggHint &other) { int ret = OB_SUCCESS; sort_method_valid_ = other.sort_method_valid_; use_partition_sort_ = other.use_partition_sort_; return ret; } int ObAggHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; if (sort_method_valid_) { char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (use_partition_sort_ && OB_FAIL(BUF_PRINTF("PARTITION_SORT"))) { LOG_WARN("print failed", K(ret)); } else if (!use_partition_sort_ && OB_FAIL(BUF_PRINTF("NO_PARTITION_SORT"))) { LOG_WARN("print failed", K(ret)); } } return ret; } int ObTableDynamicSamplingHint::assign(const ObTableDynamicSamplingHint &other) { int ret = OB_SUCCESS; if (OB_FAIL(table_.assign(other.table_))) { LOG_WARN("fail to assign table", K(ret)); } else if (OB_FAIL(ObOptHint::assign(other))) { LOG_WARN("fail to assign hint", K(ret)); } else { dynamic_sampling_ = other.dynamic_sampling_; sample_block_cnt_ = other.sample_block_cnt_; } return ret; } int ObTableDynamicSamplingHint::print_hint_desc(PlanText &plan_text) const { int ret = OB_SUCCESS; char *buf = plan_text.buf_; int64_t &buf_len = plan_text.buf_len_; int64_t &pos = plan_text.pos_; if (OB_FAIL(table_.print_table_in_hint(plan_text))) { LOG_WARN("fail to print table in hint", K(ret)); } else if (OB_FAIL(BUF_PRINTF(" %ld", dynamic_sampling_))) { LOG_WARN("fail to print dynamic sampling", K(ret)); } else if (sample_block_cnt_ > 0 && OB_FAIL(BUF_PRINTF(" %ld", sample_block_cnt_))) { LOG_WARN("fail to print dynamic sampling sample percent", K(ret)); } return ret; } void ObAllocOpHint::reset() { id_ = 0; flags_ = 0; alloc_level_ = INVALID_LEVEL; } int ObAllocOpHint::assign(const ObAllocOpHint& other) { int ret = OB_SUCCESS; id_ = other.id_; flags_ = other.flags_; alloc_level_ = other.alloc_level_; return ret; } }//end of namespace sql }//end of namespace oceanbase