/** * 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_OPT #include #include "lib/container/ob_array.h" #include "lib/container/ob_array_iterator.h" #include "lib/hash/ob_hashset.h" #include "share/ob_server_locality_cache.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/ob_sql_utils.h" #include "sql/ob_sql_trans_control.h" #include "sql/optimizer/ob_log_plan.h" #include "sql/optimizer/ob_log_table_scan.h" #include "sql/optimizer/ob_log_mv_table_scan.h" #include "sql/optimizer/ob_log_join.h" #include "sql/optimizer/ob_intersect_route_policy.h" #include "sql/optimizer/ob_join_order.h" #include "sql/optimizer/ob_log_plan_factory.h" #include "sql/optimizer/ob_log_sort.h" #include "sql/optimizer/ob_log_group_by.h" #include "sql/optimizer/ob_log_distinct.h" #include "sql/optimizer/ob_log_limit.h" #include "sql/optimizer/ob_log_sequence.h" #include "sql/optimizer/ob_log_set.h" #include "sql/optimizer/ob_log_subplan_scan.h" #include "sql/optimizer/ob_log_subplan_filter.h" #include "sql/optimizer/ob_log_material.h" #include "sql/optimizer/ob_log_select_into.h" #include "sql/optimizer/ob_log_count.h" #include "sql/optimizer/ob_log_table_lookup.h" #include "sql/optimizer/ob_opt_est_cost.h" #include "sql/optimizer/ob_optimizer.h" #include "sql/optimizer/ob_log_del_upd.h" #include "sql/optimizer/ob_log_expr_values.h" #include "sql/optimizer/ob_log_function_table.h" #include "sql/optimizer/ob_raw_expr_connectby_level_visitor.h" #include "sql/rewrite/ob_transform_utils.h" #include "storage/ob_partition_service.h" #include "sql/optimizer/ob_log_exchange.h" #include "sql/optimizer/ob_log_values.h" #include "sql/optimizer/ob_log_temp_table_insert.h" #include "sql/optimizer/ob_log_temp_table_access.h" #include "sql/optimizer/ob_log_temp_table_transformation.h" #include "sql/optimizer/ob_px_resource_analyzer.h" #include "common/ob_smart_call.h" using namespace oceanbase; using namespace sql; using namespace oceanbase::common; using namespace oceanbase::share; using namespace oceanbase::transaction; using namespace oceanbase::storage; using namespace oceanbase::sql::log_op_def; using share::schema::ObColumnSchemaV2; using share::schema::ObSchemaGetterGuard; using share::schema::ObTableSchema; #include "sql/optimizer/ob_join_property.map" static const char* ExplainColumnName[] = {"ID", "OPERATOR", "NAME", "EST. ROWS", "COST"}; ObLogPlan::ObLogPlan(ObOptimizerContext& ctx, const ObDMLStmt* stmt) : optimizer_context_(ctx), allocator_(ctx.get_allocator()), stmt_(stmt), log_op_factory_(allocator_), candidates_(), phy_plan_type_(OB_PHY_PLAN_UNINITIALIZED), location_type_(OB_PHY_PLAN_UNINITIALIZED), group_replaced_exprs_(), query_ref_(NULL), root_(NULL), sql_text_(), hash_value_(0), subplan_infos_(), onetime_exprs_(), acs_index_infos_(), autoinc_params_(), join_order_(NULL), predicate_selectivities_(), affected_last_insert_id_(false), expected_worker_count_(0), multi_stmt_rowkey_pos_(), equal_sets_(), all_exprs_(allocator_), max_op_id_(OB_INVALID_ID), require_local_execution_(false), est_sel_info_(ctx, const_cast(stmt)), is_subplan_scan_(false), const_exprs_() {} ObLogPlan::~ObLogPlan() { if (NULL != join_order_) { join_order_->~ObJoinOrder(); join_order_ = NULL; } for (int64_t i = 0; i < subplan_infos_.count(); ++i) { if (NULL != subplan_infos_.at(i)) { subplan_infos_.at(i)->~SubPlanInfo(); subplan_infos_.at(i) = NULL; } else { /* Do nothing */ } } } double ObLogPlan::get_optimization_cost() { double opt_cost = 0.0; if (OB_NOT_NULL(root_)) { opt_cost = root_->get_cost(); } return opt_cost; } int ObLogPlan::get_current_best_plan(ObLogicalOperator*& best_plan) { int ret = OB_SUCCESS; best_plan = NULL; if (OB_FAIL(candidates_.get_best_plan(best_plan))) { LOG_WARN("failed to get best plan", K(ret)); } else if (OB_ISNULL(best_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { LOG_TRACE("succeed to get best plan", K(best_plan->get_card()), K(best_plan->get_cost()), K(best_plan->get_type())); } return ret; } int ObLogPlan::set_final_plan_root(ObLogicalOperator* best_plan) { int ret = OB_SUCCESS; if (OB_ISNULL(best_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(best_plan), K(ret)); } else { set_plan_root(best_plan); best_plan->mark_is_plan_root(); } return ret; } int planText::init() { int ret = OB_SUCCESS; #undef KEY_DEF #define KEY_DEF(identifier, name) name static const char* names[] = {KEYS_DEF}; #undef KEY_DEF for (int i = 0; i < Max_Plan_Column; i++) { formatter.column_width[i] = (int)strlen(names[i]); formatter.column_name[i] = names[i]; } // formatter.num_of_columns = (EXPLAIN_SIMPLE == format) ? SIMPLE_COLUMN_NUM : Max_Plan_Column; if (EXPLAIN_BASIC == format) { formatter.num_of_columns = SIMPLE_COLUMN_NUM; } else if (EXPLAIN_PLANREGRESS == format) { formatter.num_of_columns = SIMPLE_COLUMN_NUM; } else { formatter.num_of_columns = Max_Plan_Column; } is_inited_ = true; return ret; } int ObLogPlan::plan_tree_copy(ObLogicalOperator* src, ObLogicalOperator*& dst) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(src)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(src)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else { ObLogicalOperator* tmp = NULL; if (OB_FAIL(src->copy_without_child(tmp))) { LOG_WARN("failed to copy_without_child", K(src->get_type()), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < src->get_num_of_child(); i++) { ObLogicalOperator* sub_tree = NULL; if (OB_FAIL(SMART_CALL(plan_tree_copy(src->get_child(i), sub_tree)))) { LOG_WARN("failed to copy plan tree", K(ret)); } else if (OB_ISNULL(tmp) || OB_ISNULL(sub_tree)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(tmp), K(sub_tree)); } else { tmp->set_child(i, sub_tree); } } } if (OB_SUCC(ret)) { dst = tmp; } else { /* Do nothing */ } } return ret; } #define NEW_LINE "\n" #define SEPARATOR "|" #define SPACE " " #define PLAN_WRAPPER "=" #define LINE_SEPARATOR "-" int64_t ObLogPlan::to_string(char* buf, const int64_t buf_len, ExplainType type) const { int ret = OB_SUCCESS; planText plan(buf, buf_len, type); plan.is_oneline_ = false; int64_t& pos = plan.pos; if (OB_FAIL(plan.init())) { databuff_printf(buf, buf_len, pos, "WARN failed to plan.init(), ret=%d", ret); } else if (OB_FAIL(const_cast(this)->plan_tree_traverse(EXPLAIN_COLLECT_WIDTH, &plan))) { databuff_printf(buf, buf_len, pos, "WARN failed to traverse plan for collecting width, ret=%d", ret); } else { int64_t total_width = 0; for (int i = 0; OB_SUCC(ret) && i < plan.formatter.num_of_columns; i++) { total_width += plan.formatter.column_width[i]; } // adding a separator between each column total_width += plan.formatter.num_of_columns + 1; // print plan text header line for (int i = 0; OB_SUCC(ret) && i < total_width; i++) { ret = BUF_PRINTF(PLAN_WRAPPER); } if (OB_FAIL(ret)) { databuff_printf(buf, buf_len, pos, "WARN failed to previous step, ret=%d", ret); } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else { // print column names ret = BUF_PRINTF(SEPARATOR); } for (int i = 0; OB_SUCC(ret) && i < plan.formatter.num_of_columns; i++) { if (OB_FAIL(BUF_PRINTF("%-*s", plan.formatter.column_width[i], ExplainColumnName[i]))) { /* Do nothing */ } else { ret = BUF_PRINTF(SEPARATOR); } } if (OB_SUCC(ret)) { ret = BUF_PRINTF(NEW_LINE); } else { /* Do nothing */ } // print line separator for (int i = 0; OB_SUCC(ret) && i < total_width; i++) { ret = BUF_PRINTF(LINE_SEPARATOR); } if (OB_SUCC(ret)) { ret = BUF_PRINTF(NEW_LINE); } else { /* Do nothing */ } plan.level = 0; if (OB_FAIL(ret)) { databuff_printf(buf, buf_len, pos, "WARN failed to previous step, ret=%d", ret); } else if (OB_FAIL(const_cast(this)->plan_tree_traverse(EXPLAIN_WRITE_BUFFER, &plan))) { databuff_printf(buf, buf_len, pos, "WARN failed to traverse plan for writing buffer, ret=%d", ret); } else { // print plan text footer line for (int i = 0; OB_SUCC(ret) && i < total_width; i++) { ret = BUF_PRINTF(PLAN_WRAPPER); } if (OB_SUCC(ret)) { ret = BUF_PRINTF(NEW_LINE); } else { /* Do nothing */ } } if (OB_SUCC(ret)) { if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("Outputs & filters: "))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("-------------------------------------"))) { /* Do nothing */ } else if (FALSE_IT(plan.level = 0)) { /* Do nothing */ } else if (OB_FAIL(const_cast(this)->plan_tree_traverse(EXPLAIN_WRITE_BUFFER_OUTPUT, &plan))) { databuff_printf(buf, buf_len, pos, "WARN failed to print output exprs, ret=%d", ret); } else { ret = BUF_PRINTF(NEW_LINE); } } else { /* Do nothing */ } // print Used Hint if (OB_SUCC(ret) && (EXPLAIN_EXTENDED == type)) { plan.outline_type_ = USED_HINT; if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("Used Hint:"))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("-------------------------------------\n"))) { /* Do nothing */ } else if (OB_FAIL(print_outline(plan))) { databuff_printf(buf, buf_len, pos, "WARN failed to print outline, ret=%d", ret); } else { ret = BUF_PRINTF(NEW_LINE); } } else { /* Do nothing */ } // print Outline Data if (OB_SUCC(ret) && (EXPLAIN_EXTENDED == type || EXPLAIN_OUTLINE == type)) { plan.outline_type_ = OUTLINE_DATA; if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("Outline Data:"))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("-------------------------------------\n"))) { /* Do nothing */ } else if (OB_FAIL(print_outline(plan))) { databuff_printf(buf, buf_len, pos, "WARN failed to print outline, ret=%d", ret); } else { ret = BUF_PRINTF(NEW_LINE); } } else { /* Do nothing */ } // print log plan type if (OB_SUCC(ret) && EXPLAIN_EXTENDED == type) { if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("Plan Type:"))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("-------------------------------------\n"))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF(ob_plan_type_str(get_phy_plan_type())))) { /* Do nothing */ } else { ret = BUF_PRINTF(NEW_LINE); } } else { /* Do nothing */ } // print optimization info if (OB_SUCC(ret) && EXPLAIN_EXTENDED == type) { if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("Optimization Info:"))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OB_FAIL(BUF_PRINTF("-------------------------------------\n"))) { /* Do nothing */ } else if (OB_FAIL(const_cast(this)->plan_tree_traverse(EXPLAIN_INDEX_SELECTION_INFO, &plan))) { databuff_printf(buf, buf_len, pos, "WARN failed to print index selection info, ret=%d", ret); } } else { /* Do nothing */ } // print params if (OB_SUCC(ret) && EXPLAIN_EXTENDED == type) { if (OB_FAIL(BUF_PRINTF("Parameters"))) { } else if (OB_FAIL(BUF_PRINTF(NEW_LINE))) { } else { ret = BUF_PRINTF("-------------------------------------\n"); } const ParamStore* params = NULL; if (OB_ISNULL(params = get_optimizer_context().get_params())) { ret = OB_ERR_UNEXPECTED; databuff_printf(buf, buf_len, pos, "WARN Get unexpected null, ret=%d", ret); } else { /* Do nothing */ } for (int64_t i = 0; OB_SUCC(ret) && NULL != params && i < params->count(); i++) { pos += params->at(i).to_string(buf + pos, buf_len - pos); if (i < params->count() - 1) { ret = BUF_PRINTF(", "); } else { /* Do nothing */ } } } else { /* Do nothing */ } } if (OB_FAIL(ret)) { databuff_printf(buf, buf_len, pos, "WARN Get unexpected error in to_string, ret=%d", ret); } else { /* Do nothing */ } return pos; } int ObLogPlan::get_table_items(const ObIArray& from_items, ObIArray& table_items) { int ret = OB_SUCCESS; ObDMLStmt* stmt = NULL; if (OB_ISNULL(stmt = get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null stmt", K(stmt), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < from_items.count(); i++) { const FromItem& from_item = from_items.at(i); TableItem* temp_table_item = NULL; if (!from_item.is_joined_) { temp_table_item = stmt->get_table_item_by_id(from_item.table_id_); } else { temp_table_item = stmt->get_joined_table(from_item.table_id_); } if (OB_FAIL(table_items.push_back(temp_table_item))) { LOG_WARN("failed to push back table item", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObLogPlan::get_table_ids(TableItem* table_item, ObRelIds& table_ids) { int ret = OB_SUCCESS; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(table_item) || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item or stmt", K(ret)); } else if (!table_item->is_joined_table()) { if (OB_FAIL(table_ids.add_member(stmt->get_table_bit_index(table_item->table_id_)))) { LOG_WARN("failed to add members", K(ret)); } } else { JoinedTable* joined_table = static_cast(table_item); if (OB_FAIL(ObTransformUtils::get_rel_ids_from_join_table(stmt, joined_table, table_ids))) { LOG_WARN("failed to get rel ids from joined table", K(ret)); } } return ret; } int ObLogPlan::get_table_ids(const ObIArray& table_ids, ObRelIds& rel_ids) { int ret = OB_SUCCESS; ObDMLStmt* stmt = NULL; int32_t idx = OB_INVALID_INDEX; if (OB_ISNULL(stmt = get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < table_ids.count(); ++i) { idx = stmt->get_table_bit_index(table_ids.at(i)); if (OB_UNLIKELY(OB_INVALID_INDEX == idx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item or stmt", K(ret)); } else if (OB_FAIL(rel_ids.add_member(idx))) { LOG_WARN("failed to add members", K(ret)); } } return ret; } int ObLogPlan::get_table_ids(const ObIArray& table_items, ObRelIds& table_ids) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { TableItem* item = table_items.at(i); if (OB_ISNULL(item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (OB_FAIL(get_table_ids(item, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } } return ret; } int ObLogPlan::get_table_ids(const ObIArray& exprs, ObRelIds& table_ids) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { ObRawExpr* expr = exprs.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (OB_FAIL(table_ids.add_members(expr->get_relation_ids()))) { LOG_WARN("failed to add members", K(ret)); } } return ret; } int ObLogPlan::is_joined_table_filter(const ObIArray& table_items, const ObRawExpr* expr, bool& is_filter) { int ret = OB_SUCCESS; is_filter = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr or stmt", K(ret)); } else if (expr->get_relation_ids().is_empty()) { // do nothing } else { for (int64_t i = 0; OB_SUCC(ret) && !is_filter && i < table_items.count(); ++i) { TableItem* item = table_items.at(i); ObRelIds joined_table_ids; if (OB_ISNULL(item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null semi item", K(ret)); } else if (!item->is_joined_table()) { // do nothing } else if (OB_FAIL(get_table_ids(item, joined_table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (joined_table_ids.is_superset(expr->get_relation_ids())) { is_filter = true; } } } return ret; } int ObLogPlan::find_inner_conflict_detector( const ObIArray& inner_conflict_detectors, const ObRelIds& rel_ids, ConflictDetector*& detector) { int ret = OB_SUCCESS; detector = NULL; int64_t N = inner_conflict_detectors.count(); for (int64_t i = 0; OB_SUCC(ret) && NULL == detector && i < N; ++i) { ConflictDetector* temp_detector = inner_conflict_detectors.at(i); if (OB_ISNULL(temp_detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (temp_detector->join_info_.join_type_ != INNER_JOIN) { // do nothing } else if (temp_detector->join_info_.table_set_.equal(rel_ids)) { detector = temp_detector; } } return ret; } int ObLogPlan::satisfy_associativity_rule(const ConflictDetector& left, const ConflictDetector& right, bool& is_satisfy) { int ret = OB_SUCCESS; if (!ASSOC_PROPERTY[left.join_info_.join_type_][right.join_info_.join_type_]) { is_satisfy = false; } else if ((LEFT_OUTER_JOIN == left.join_info_.join_type_ || FULL_OUTER_JOIN == left.join_info_.join_type_) && LEFT_OUTER_JOIN == right.join_info_.join_type_) { if (OB_FAIL(ObTransformUtils::is_null_reject_conditions(right.join_info_.on_condition_, left.R_DS_.is_subset(right.L_DS_) ? left.R_DS_ : right.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } } else if (FULL_OUTER_JOIN == left.join_info_.join_type_ && FULL_OUTER_JOIN == right.join_info_.join_type_) { if (OB_FAIL(ObTransformUtils::is_null_reject_conditions( left.join_info_.on_condition_, left.R_DS_.is_subset(right.L_DS_) ? left.R_DS_ : right.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } else if (!is_satisfy) { // do nothing } else if (OB_FAIL(ObTransformUtils::is_null_reject_conditions(right.join_info_.on_condition_, left.R_DS_.is_subset(right.L_DS_) ? left.R_DS_ : right.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } } else { is_satisfy = true; } return ret; } int ObLogPlan::satisfy_left_asscom_rule(const ConflictDetector& left, const ConflictDetector& right, bool& is_satisfy) { int ret = OB_SUCCESS; if (!L_ASSCOM_PROPERTY[left.join_info_.join_type_][right.join_info_.join_type_]) { is_satisfy = false; } else if (LEFT_OUTER_JOIN == left.join_info_.join_type_ && FULL_OUTER_JOIN == right.join_info_.join_type_) { if (OB_FAIL(ObTransformUtils::is_null_reject_conditions(left.join_info_.on_condition_, left.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } } else if (FULL_OUTER_JOIN == left.join_info_.join_type_ && LEFT_OUTER_JOIN == right.join_info_.join_type_) { if (OB_FAIL(ObTransformUtils::is_null_reject_conditions(right.join_info_.on_condition_, left.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } } else if (FULL_OUTER_JOIN == left.join_info_.join_type_ && FULL_OUTER_JOIN == right.join_info_.join_type_) { if (OB_FAIL(ObTransformUtils::is_null_reject_conditions(left.join_info_.on_condition_, left.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } else if (!is_satisfy) { // do nothing } else if (OB_FAIL(ObTransformUtils::is_null_reject_conditions( right.join_info_.on_condition_, left.L_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } } else { is_satisfy = true; } LOG_TRACE("succeed to check l-asscom", K(left), K(right), K(is_satisfy)); return ret; } int ObLogPlan::satisfy_right_asscom_rule(const ConflictDetector& left, const ConflictDetector& right, bool& is_satisfy) { int ret = OB_SUCCESS; if (!R_ASSCOM_PROPERTY[left.join_info_.join_type_][right.join_info_.join_type_]) { is_satisfy = false; } else if (FULL_OUTER_JOIN == left.join_info_.join_type_ && FULL_OUTER_JOIN == right.join_info_.join_type_) { if (OB_FAIL(ObTransformUtils::is_null_reject_conditions(left.join_info_.on_condition_, right.R_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } else if (!is_satisfy) { // do nothing } else if (OB_FAIL(ObTransformUtils::is_null_reject_conditions( right.join_info_.on_condition_, right.R_DS_, is_satisfy))) { LOG_WARN("failed to check is null reject conditions", K(ret)); } } else { is_satisfy = true; } LOG_TRACE("succeed to check r-asscom", K(left), K(right), K(is_satisfy)); return ret; } int ObLogPlan::add_conflict_rule( const ObRelIds& left, const ObRelIds& right, ObIArray>& rules) { int ret = OB_SUCCESS; ObRelIds* left_handle_rule = NULL; ObRelIds* right_handle_rule = NULL; bool find = false; for (int64_t i = 0; !find && i < rules.count(); ++i) { if (rules.at(i).first.equal(left) && rules.at(i).second.equal(right)) { find = true; } else if (rules.at(i).first.equal(left)) { left_handle_rule = &rules.at(i).second; } else if (rules.at(i).second.equal(right)) { right_handle_rule = &rules.at(i).first; } } if (find) { // do nothing } else if (NULL != left_handle_rule) { if (OB_FAIL(left_handle_rule->add_members(right))) { LOG_WARN("failed to add members", K(ret)); } } else if (NULL != right_handle_rule) { if (OB_FAIL(right_handle_rule->add_members(left))) { LOG_WARN("failed to add members", K(ret)); } } else { std::pair rule; if (OB_FAIL(rule.first.add_members(left))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(rule.second.add_members(right))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(rules.push_back(rule))) { LOG_WARN("failed to push back rule", K(ret)); } } return ret; } int ObLogPlan::generate_conflict_rule(ConflictDetector* parent, ConflictDetector* child, bool is_left_child, ObIArray>& rules) { int ret = OB_SUCCESS; bool is_satisfy = false; ObRelIds ids; if (OB_ISNULL(parent) || OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (is_left_child) { LOG_TRACE("generate left child conflict rule for ", K(*parent), K(*child)); // check assoc(o^a, o^b) if (OB_FAIL(satisfy_associativity_rule(*child, *parent, is_satisfy))) { LOG_WARN("failed to check satisfy assoc", K(ret)); } else if (is_satisfy) { LOG_TRACE("satisfy assoc"); } else if (OB_FAIL(ids.intersect(child->L_DS_, child->join_info_.table_set_))) { LOG_WARN("failed to cal intersect table ids", K(ret)); } else if (ids.is_empty()) { // CR += T(right(o^a)) -> T(left(o^a)) if (OB_FAIL(add_conflict_rule(child->R_DS_, child->L_DS_, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else if (OB_FAIL(add_conflict_rule(child->R_DS_, child->R_DS_, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict1", K(rules)); } } else { // CR += T(right(o^a)) -> T(left(o^a)) n T(quals) if (OB_FAIL(add_conflict_rule(child->R_DS_, ids, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else if (OB_FAIL(add_conflict_rule(child->R_DS_, child->R_DS_, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict2", K(rules)); } } // check l-asscom(o^a, o^b) if (OB_FAIL(ret)) { } else if (OB_FAIL(satisfy_left_asscom_rule(*child, *parent, is_satisfy))) { LOG_WARN("failed to check satisfy assoc", K(ret)); } else if (is_satisfy) { LOG_TRACE("satisfy l-asscom"); } else if (OB_FAIL(ids.intersect(child->R_DS_, child->join_info_.table_set_))) { LOG_WARN("failed to cal intersect table ids", K(ret)); } else if (ids.is_empty()) { // CR += T(left(o^a)) -> T(right(o^a)) if (OB_FAIL(add_conflict_rule(child->L_DS_, child->R_DS_, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict3", K(rules)); } } else { // CR += T(left(o^a)) -> T(right(o^a)) n T(quals) if (OB_FAIL(add_conflict_rule(child->L_DS_, ids, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict4", K(rules)); } } } else { LOG_TRACE("generate right child conflict rule for ", K(*parent), K(*child)); // check assoc(o^b, o^a) if (OB_FAIL(satisfy_associativity_rule(*parent, *child, is_satisfy))) { LOG_WARN("failed to check satisfy assoc", K(ret)); } else if (is_satisfy) { LOG_TRACE("satisfy assoc"); } else if (OB_FAIL(ids.intersect(child->R_DS_, child->join_info_.table_set_))) { LOG_WARN("failed to cal intersect table ids", K(ret)); } else if (ids.is_empty()) { // CR += T(left(o^a)) -> T(right(o^a)) if (OB_FAIL(add_conflict_rule(child->L_DS_, child->R_DS_, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict5", K(rules)); } } else { // CR += T(left(o^a)) -> T(right(o^a)) n T(quals) if (OB_FAIL(add_conflict_rule(child->L_DS_, ids, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict6", K(rules)); } } // check r-asscom(o^b, o^a) if (OB_FAIL(ret)) { } else if (OB_FAIL(satisfy_right_asscom_rule(*parent, *child, is_satisfy))) { LOG_WARN("failed to check satisfy assoc", K(ret)); } else if (is_satisfy) { LOG_TRACE("satisfy r-asscom"); } else if (OB_FAIL(ids.intersect(child->L_DS_, child->join_info_.table_set_))) { LOG_WARN("failed to cal intersect table ids", K(ret)); } else if (ids.is_empty()) { // CR += T(right(o^a)) -> T(left(o^a)) if (OB_FAIL(add_conflict_rule(child->R_DS_, child->L_DS_, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict7", K(rules)); } } else { // CR += T(right(o^a)) -> T(left(o^a)) n T(quals) if (OB_FAIL(add_conflict_rule(child->R_DS_, ids, rules))) { LOG_WARN("failed to add conflict rule", K(ret)); } else { LOG_TRACE("succeed to add condlict8", K(rules)); } } } return ret; } int ObLogPlan::get_base_table_items(ObDMLStmt& stmt, const ObIArray& table_items, const ObIArray& semi_infos, ObIArray& base_tables) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { TableItem* item = table_items.at(i); if (OB_ISNULL(item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (!item->is_joined_table()) { ret = base_tables.push_back(item); } else { JoinedTable* joined_table = static_cast(item); for (int64_t j = 0; OB_SUCC(ret) && j < joined_table->single_table_ids_.count(); ++j) { TableItem* table = stmt.get_table_item_by_id(joined_table->single_table_ids_.at(j)); ret = base_tables.push_back(table); } } } for (int64_t i = 0; OB_SUCC(ret) && i < semi_infos.count(); ++i) { if (OB_ISNULL(semi_infos.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null semi info", K(ret)); } else { TableItem* table = stmt.get_table_item_by_id(semi_infos.at(i)->right_table_id_); ret = base_tables.push_back(table); } } return ret; } int ObLogPlan::generate_join_orders() { int ret = OB_SUCCESS; ObDMLStmt* stmt = NULL; ObSEArray quals; ObSEArray semi_infos; ObSEArray table_items; JoinOrderArray base_level; int64_t join_level = 0; common::ObArray join_rels; ObSEArray base_tables; if (OB_ISNULL(stmt = get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(stmt), K(ret)); } else if (OB_FAIL(semi_infos.assign(stmt->get_semi_infos()))) { LOG_WARN("failed to assign semi infos", K(ret)); } else if (OB_FAIL(get_table_items(stmt->get_from_items(), table_items))) { LOG_WARN("failed to get table items", K(ret)); } else if (stmt->is_insert_stmt()) { /*do nothing*/ } else if (OB_FAIL(append(quals, get_stmt()->get_condition_exprs()))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(append(quals, get_pushdown_filters()))) { LOG_WARN("failed to append exprs", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(get_base_table_items(*stmt, table_items, semi_infos, base_tables))) { LOG_WARN("failed to flatten table items", K(ret)); } else if (OB_FAIL(generate_base_level_join_order(base_tables, base_level))) { LOG_WARN("fail to generate base level join order", K(ret)); } else if (OB_FAIL(pre_process_quals(table_items, semi_infos, quals))) { LOG_WARN("failed to distribute special quals", K(ret)); } else if (OB_FAIL(generate_conflict_detectors(table_items, semi_infos, quals, base_level))) { LOG_WARN("failed to generate conflict detectors", K(ret)); } else { join_level = base_level.count(); if (OB_UNLIKELY(join_level < 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected join level", K(ret), K(join_level)); } else if (OB_FAIL(join_rels.prepare_allocate(join_level))) { LOG_WARN("failed to prepare allocate join rels", K(ret)); } else if (OB_FAIL(join_rels.at(0).assign(base_level))) { LOG_WARN("failed to assign base level join order", K(ret)); } } } for (int64_t i = 0; OB_SUCC(ret) && i < join_level; ++i) { if (OB_ISNULL(join_rels.at(0).at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("join_rels_.at(0).at(i) is null", K(ret), K(i)); } else if (OB_FAIL(join_rels.at(0).at(i)->generate_base_paths())) { LOG_WARN("failed to generate base path", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(init_leading_info(table_items, semi_infos))) { LOG_WARN("failed to get leading hint info", K(ret)); } else if (OB_FAIL(init_bushy_tree_info(table_items))) { LOG_WARN("failed to init bushy tree infos", K(ret)); } else if (join_rels.at(0).count() <= DEFAULT_SEARCH_SPACE_RELS || !leading_tables_.is_empty()) { if (OB_FAIL(generate_join_levels_with_DP(join_rels, join_level))) { LOG_WARN("failed to generate join levels with dynamic program", K(ret)); } } else { if (OB_FAIL(generate_join_levels_with_linear(join_rels, table_items, join_level))) { LOG_WARN("failed to generate join levels with linear", K(ret)); } } } if (OB_SUCC(ret)) { if (1 != join_rels.at(join_level - 1).count()) { ret = OB_ERR_NO_JOIN_ORDER_GENERATED; LOG_WARN("No final JoinOrder generated", K(ret), K(join_rels.at(join_level - 1).count())); } else if (OB_ISNULL(join_order_ = join_rels.at(join_level - 1).at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null join order", K(ret), K(join_order_)); } else if (OB_UNLIKELY(join_order_->get_interesting_paths().empty())) { ret = OB_ERR_NO_PATH_GENERATED; LOG_WARN("No final join path generated", K(ret), K(*join_order_)); } else { LOG_TRACE("succeed to generate join order", K(ret)); } } return ret; } int ObLogPlan::generate_base_level_join_order( const ObIArray& table_items, ObIArray& base_level) { int ret = OB_SUCCESS; ObJoinOrder* this_jo = NULL; int64_t N = table_items.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { if (OB_ISNULL(table_items.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null table item", K(ret), K(i)); } else if (OB_ISNULL(this_jo = create_join_order(ACCESS))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate an ObJoinOrder", K(ret)); } else if (OB_FAIL(this_jo->init_base_join_order(table_items.at(i)))) { LOG_WARN("fail to generate the base rel", K(ret), K(*table_items.at(i))); this_jo->~ObJoinOrder(); this_jo = NULL; } else if (OB_FAIL(base_level.push_back(this_jo))) { LOG_WARN("fail to push back an ObJoinOrder", K(ret)); } else { /*do nothing*/ } } return ret; } int ObLogPlan::split_or_quals(const ObIArray& table_items, ObIArray& quals) { int ret = OB_SUCCESS; ObSEArray new_quals; for (int64_t i = 0; OB_SUCC(ret) && i < quals.count(); ++i) { if (OB_FAIL(split_or_quals(table_items, quals.at(i), new_quals))) { LOG_WARN("failed to split or quals", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(append(quals, new_quals))) { LOG_WARN("failed to append quals", K(ret)); } } return ret; } int ObLogPlan::split_or_quals(const ObIArray& table_items, ObRawExpr* qual, ObIArray& new_quals) { int ret = OB_SUCCESS; ObRelIds table_ids; bool is_filter = false; if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null qual", K(ret)); } else if (T_OP_OR != qual->get_expr_type()) { // do nothing } else if (!qual->has_flag(CNT_SUB_QUERY) && OB_FAIL(is_joined_table_filter(table_items, qual, is_filter))) { LOG_WARN("failed to check is joined table filter", K(ret)); } else if (is_filter) { } else { ObOpRawExpr* or_qual = static_cast(qual); for (int64_t j = 0; OB_SUCC(ret) && j < table_items.count(); ++j) { TableItem* table_item = table_items.at(j); table_ids.reuse(); if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(get_table_ids(table_item, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (!table_ids.overlap(or_qual->get_relation_ids())) { // do nothing } else if (qual->has_flag(CNT_SUB_QUERY) || (!table_ids.is_superset(or_qual->get_relation_ids()))) { ret = try_split_or_qual(table_ids, *or_qual, new_quals); } } } return ret; } int ObLogPlan::pre_process_quals( const ObIArray& table_items, const ObIArray& semi_infos, ObIArray& quals) { int ret = OB_SUCCESS; ObSEArray normal_quals; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(stmt)); } // 1. where conditions for (int64_t i = 0; OB_SUCC(ret) && i < quals.count(); ++i) { ObRawExpr* qual = quals.at(i); bool can_distribute = false; if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null qual", K(ret)); } else if (qual->has_flag(CNT_ROWNUM)) { ret = add_rownum_expr(qual); } else if (qual->has_flag(CNT_RAND_FUNC)) { ret = add_random_expr(qual); } else if (qual->has_flag(CNT_USER_VARIABLE)) { ret = add_user_var_filter(qual); } else if (qual->has_flag(CNT_SUB_QUERY)) { if (OB_FAIL(distribute_onetime_subquery(qual, can_distribute))) { LOG_WARN("failed to check qual can pushdown", K(ret)); } else if (!can_distribute) { if (OB_FAIL(split_or_quals(table_items, qual, quals))) { LOG_WARN("failed to split or quals", K(ret)); } else { ret = add_subquery_filter(qual); } } else { ret = normal_quals.push_back(qual); } } else if (ObOptimizerUtil::has_hierarchical_expr(*qual)) { ret = normal_quals.push_back(qual); } else if (0 == qual->get_relation_ids().num_members() || is_upper_stmt_column_ref(*qual, *stmt)) { ret = add_startup_filter(qual); } else { ret = normal_quals.push_back(qual); } } if (OB_SUCC(ret)) { if (OB_FAIL(quals.assign(normal_quals))) { LOG_WARN("failed to assign quals", K(ret)); } } // 2. on conditions for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { ret = pre_process_quals(table_items.at(i)); } // 3. semi conditions for (int64_t i = 0; OB_SUCC(ret) && i < semi_infos.count(); ++i) { ret = pre_process_quals(semi_infos.at(i)); } return ret; } int ObLogPlan::pre_process_quals(SemiInfo* semi_info) { int ret = OB_SUCCESS; if (OB_ISNULL(semi_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null semi info", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < semi_info->semi_conditions_.count(); ++i) { bool can_distribute = true; ObRawExpr* expr = NULL; if (OB_ISNULL(expr = semi_info->semi_conditions_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret), K(expr)); } else if (expr->has_flag(CNT_ROWNUM) || expr->has_flag(CNT_RAND_FUNC) || expr->has_flag(CNT_USER_VARIABLE)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected expr in semi condition", K(ret), K(*expr)); } else if (expr->has_flag(CNT_SUB_QUERY) && OB_FAIL(distribute_subquery_qual(expr, can_distribute))) { LOG_WARN("failed to distribute subquery expr", K(ret)); } else if (!can_distribute) { ret = OB_NOT_SUPPORTED; LOG_WARN("correlated subquery in outer join condition is not supported", KPC(expr), K(ret)); } else { semi_info->semi_conditions_.at(i) = expr; } } return ret; } int ObLogPlan::pre_process_quals(TableItem* table_item) { int ret = OB_SUCCESS; JoinedTable* joined_table = static_cast(table_item); if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (!table_item->is_joined_table()) { // do nothing } else if (OB_FAIL(SMART_CALL(pre_process_quals(joined_table->left_table_)))) { LOG_WARN("failed to distribute special quals", K(ret)); } else if (OB_FAIL(SMART_CALL(pre_process_quals(joined_table->right_table_)))) { LOG_WARN("failed to distribute special quals", K(ret)); } else { if (FULL_OUTER_JOIN == joined_table->joined_type_ && !ObOptimizerUtil::has_equal_join_conditions(joined_table->join_conditions_)) { ret = OB_NOT_SUPPORTED; LOG_WARN("full outer join without equal join conditions is not supported now", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < joined_table->join_conditions_.count(); ++i) { bool can_distribute = true; ObRawExpr* expr = NULL; if (OB_ISNULL(expr = joined_table->join_conditions_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret), K(expr)); } else if (expr->has_flag(CNT_SUB_QUERY) && OB_FAIL(distribute_subquery_qual(expr, can_distribute))) { LOG_WARN("failed to distribute subquery expr", K(ret)); } else if (!can_distribute) { ret = OB_NOT_SUPPORTED; LOG_WARN("correlated subquery in outer join condition is not supported", KPC(expr), K(ret)); } else { joined_table->join_conditions_.at(i) = expr; } } } return ret; } int ObLogPlan::generate_conflict_detectors(const ObIArray& table_items, const ObIArray& semi_infos, ObIArray& quals, ObIArray& baserels) { int ret = OB_SUCCESS; ObRelIds table_ids; ObSEArray semi_join_detectors; ObSEArray inner_join_detectors; LOG_TRACE("start to generate conflict detector", K(table_items), K(semi_infos), K(quals)); conflict_detectors_.reuse(); if (OB_FAIL(get_table_ids(table_items, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(generate_inner_join_detectors(table_items, quals, baserels, inner_join_detectors))) { LOG_WARN("failed to generate inner join detectors", K(ret)); } else if (OB_FAIL(generate_semi_join_detectors(semi_infos, table_ids, inner_join_detectors, semi_join_detectors))) { LOG_WARN("failed to generate semi join detectors", K(ret)); } else if (OB_FAIL(append(conflict_detectors_, semi_join_detectors))) { LOG_WARN("failed to append detectors", K(ret)); } else if (OB_FAIL(append(conflict_detectors_, inner_join_detectors))) { LOG_WARN("failed to append detectors", K(ret)); } else { LOG_TRACE("succeed to generate confilct detectors", K(semi_join_detectors), K(inner_join_detectors)); } return ret; } int ObLogPlan::generate_semi_join_detectors(const ObIArray& semi_infos, ObRelIds& left_rel_ids, const ObIArray& inner_join_detectors, ObIArray& semi_join_detectors) { int ret = OB_SUCCESS; ObSqlBitSet<> right_rel_ids; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(stmt)); } for (int64_t i = 0; OB_SUCC(ret) && i < semi_infos.count(); ++i) { right_rel_ids.reuse(); SemiInfo* info = semi_infos.at(i); ConflictDetector* detector = NULL; if (OB_ISNULL(info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null semi info", K(ret)); // 1. create conflict detector } else if (OB_FAIL(ConflictDetector::build_confict(get_allocator(), detector))) { LOG_WARN("failed to build conflict detector", K(ret)); } else if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null conflict detector", K(ret)); } else if (OB_FAIL(detector->L_DS_.add_members(left_rel_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(stmt->get_table_rel_ids(info->right_table_id_, right_rel_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(detector->R_DS_.add_members(right_rel_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(semi_join_detectors.push_back(detector))) { LOG_WARN("failed to push back detector", K(ret)); } else { detector->join_info_.join_type_ = info->join_type_; // 2. add equal join conditions ObRawExpr* expr = NULL; for (int64_t j = 0; OB_SUCC(ret) && j < info->semi_conditions_.count(); ++j) { if (OB_ISNULL(expr = info->semi_conditions_.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(expr)); } else if (OB_FAIL(detector->join_info_.table_set_.add_members(expr->get_relation_ids()))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(detector->join_info_.where_condition_.push_back(expr))) { LOG_WARN("failed to push back exprs", K(ret)); } else if (expr->has_flag(IS_JOIN_COND) && OB_FAIL(detector->join_info_.equal_join_condition_.push_back(expr))) { LOG_WARN("failed to push back qual", K(ret)); } } // 3. add other infos to conflict detector if (OB_FAIL(ret)) { } else if (OB_FAIL(detector->L_TES_.intersect(detector->join_info_.table_set_, detector->L_DS_))) { LOG_WARN("failed to generate L-TES", K(ret)); } else if (OB_FAIL(detector->R_TES_.intersect(detector->join_info_.table_set_, detector->R_DS_))) { LOG_WARN("failed to generate R-TES", K(ret)); } else if (detector->join_info_.table_set_.overlap(detector->L_DS_) && detector->join_info_.table_set_.overlap(detector->R_DS_)) { detector->is_degenerate_pred_ = false; detector->is_commutative_ = COMM_PROPERTY[detector->join_info_.join_type_]; } else { detector->is_degenerate_pred_ = true; detector->is_commutative_ = COMM_PROPERTY[detector->join_info_.join_type_]; } } for (int64_t j = 0; OB_SUCC(ret) && j < inner_join_detectors.count(); ++j) { if (OB_FAIL(generate_conflict_rule(detector, inner_join_detectors.at(j), true, detector->CR_))) { LOG_WARN("failed to generate conflict rule", K(ret)); } } } return ret; } int ObLogPlan::generate_inner_join_detectors(const ObIArray& table_items, ObIArray& quals, ObIArray& baserels, ObIArray& inner_join_detectors) { int ret = OB_SUCCESS; ObSEArray outer_join_detectors; ObSEArray all_table_filters; ObSEArray table_filters; ObRelIds table_ids; if (OB_FAIL(split_or_quals(table_items, quals))) { LOG_WARN("failed to split or quals", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { table_filters.reuse(); table_ids.reuse(); if (OB_FAIL(get_table_ids(table_items.at(i), table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < quals.count(); ++j) { ObRawExpr* expr = quals.at(j); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (!expr->get_relation_ids().is_subset(table_ids)) { // do nothing } else if (OB_FAIL(table_filters.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(all_table_filters.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(generate_outer_join_detectors(table_items.at(i), table_filters, baserels, outer_join_detectors))) { LOG_WARN("failed to generate outer join detectors", K(ret)); } } } ObRawExpr* expr = NULL; ConflictDetector* detector = NULL; ObSEArray join_conditions; for (int64_t i = 0; OB_SUCC(ret) && i < quals.count(); ++i) { if (OB_ISNULL(expr = quals.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (ObOptimizerUtil::find_item(all_table_filters, expr)) { // do nothing } else if (OB_FAIL(join_conditions.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(find_inner_conflict_detector(inner_join_detectors, expr->get_relation_ids(), detector))) { LOG_WARN("failed to find conflict detector", K(ret)); } else if (NULL == detector) { if (OB_FAIL(ConflictDetector::build_confict(get_allocator(), detector))) { LOG_WARN("failed to build conflict detector", K(ret)); } else if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (OB_FAIL(detector->join_info_.where_condition_.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (expr->has_flag(IS_JOIN_COND) && OB_FAIL(detector->join_info_.equal_join_condition_.push_back(expr))) { LOG_WARN("failed to push back qual", K(ret)); } else if (OB_FAIL(detector->join_info_.table_set_.add_members(expr->get_relation_ids()))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(inner_join_detectors.push_back(detector))) { LOG_WARN("failed to push back detector", K(ret)); } else { detector->is_degenerate_pred_ = false; detector->is_commutative_ = COMM_PROPERTY[INNER_JOIN]; detector->join_info_.join_type_ = INNER_JOIN; } } else if (OB_FAIL(detector->join_info_.where_condition_.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (expr->has_flag(IS_JOIN_COND) && OB_FAIL(detector->join_info_.equal_join_condition_.push_back(expr))) { LOG_WARN("failed to push back qual", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < inner_join_detectors.count(); ++i) { ConflictDetector* inner_detector = inner_join_detectors.at(i); const ObRelIds& table_set = inner_detector->join_info_.table_set_; if (OB_ISNULL(inner_detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < table_items.count(); ++j) { table_ids.reuse(); if (OB_FAIL(get_table_ids(table_items.at(j), table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (!table_ids.overlap(table_set)) { // do nothing } else if (OB_FAIL(inner_detector->L_DS_.add_members(table_ids))) { LOG_WARN("failed to generate R-TES", K(ret)); } else if (OB_FAIL(inner_detector->R_DS_.add_members(table_ids))) { LOG_WARN("failed to generate R-TES", K(ret)); } } //对于inner join来说,满足交换律,所以不需要区分L_TES、R_TES //为了方便之后统一applicable算法,L_TES、R_TES都等于SES if (OB_FAIL(ret)) { } else if (OB_FAIL(inner_detector->L_TES_.add_members(table_set))) { LOG_WARN("failed to generate L-TES", K(ret)); } else if (OB_FAIL(inner_detector->R_TES_.add_members(table_set))) { LOG_WARN("failed to generate R-TES", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < outer_join_detectors.count(); ++j) { ConflictDetector* outer_detector = outer_join_detectors.at(j); if (OB_ISNULL(outer_detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (!IS_OUTER_OR_CONNECT_BY_JOIN(outer_detector->join_info_.join_type_)) { } else if (OB_FAIL(generate_conflict_rule(inner_detector, outer_detector, true, inner_detector->CR_))) { LOG_WARN("failed to generate conflict rule", K(ret)); } else if (OB_FAIL(generate_conflict_rule(inner_detector, outer_detector, false, inner_detector->CR_))) { LOG_WARN("failed to generate conflict rule", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(append(inner_join_detectors, outer_join_detectors))) { LOG_WARN("failed to append detectors", K(ret)); } else if (OB_FAIL(generate_cross_product_detector(table_items, join_conditions, inner_join_detectors))) { LOG_WARN("failed to generate cross product detector", K(ret)); } } return ret; } int ObLogPlan::generate_outer_join_detectors(TableItem* table_item, ObIArray& table_filter, ObIArray& baserels, ObIArray& outer_join_detectors) { int ret = OB_SUCCESS; JoinedTable* joined_table = static_cast(table_item); if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (!table_item->is_joined_table()) { if (OB_FAIL(distribute_quals(table_item, table_filter, baserels))) { LOG_WARN("failed to distribute table filter", K(ret)); } } else if (INNER_JOIN == joined_table->joined_type_) { ObSEArray table_items; ObSEArray detectors; if (OB_FAIL(flatten_inner_join(table_item, table_filter, table_items))) { LOG_WARN("failed to flatten inner join", K(ret)); } else if (OB_FAIL(generate_inner_join_detectors(table_items, table_filter, baserels, detectors))) { LOG_WARN("failed to generate inner join detectors", K(ret)); } else if (OB_FAIL(append(outer_join_detectors, detectors))) { LOG_WARN("failed to append detectors", K(ret)); } } else if (OB_FAIL(inner_generate_outer_join_detectors(joined_table, table_filter, baserels, outer_join_detectors))) { LOG_WARN("failed to generate outer join detectors", K(ret)); } return ret; } int ObLogPlan::distribute_quals( TableItem* table_item, const ObIArray& table_filter, ObIArray& baserels) { int ret = OB_SUCCESS; ObJoinOrder* cur_rel = NULL; ObSEArray relids; ObRelIds table_ids; if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(table_item)); } else if (OB_FAIL(get_table_ids(table_item, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(table_ids.to_array(relids))) { LOG_WARN("to_array error", K(ret)); } else if (1 != relids.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expect basic table item", K(ret)); } else if (OB_FAIL(find_base_rel(baserels, relids.at(0), cur_rel))) { LOG_WARN("find_base_rel fails", K(ret)); } else if (OB_ISNULL(cur_rel)) { ret = OB_SQL_OPT_ERROR; LOG_WARN("failed to distribute qual to rel", K(baserels), K(relids), K(ret)); } else if (OB_FAIL(append(cur_rel->get_restrict_infos(), table_filter))) { LOG_WARN("failed to distribute qual to rel", K(ret)); } return ret; } int ObLogPlan::flatten_table_items( ObIArray& table_items, ObIArray& table_filter, ObIArray& flatten_table_items) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { if (OB_FAIL(flatten_inner_join(table_items.at(i), table_filter, flatten_table_items))) { LOG_WARN("failed to flatten inner join", K(ret)); } } return ret; } int ObLogPlan::flatten_inner_join( TableItem* table_item, ObIArray& table_filter, ObIArray& table_items) { int ret = OB_SUCCESS; JoinedTable* joined_table = static_cast(table_item); if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (!table_item->is_joined_table() || INNER_JOIN != joined_table->joined_type_) { ret = table_items.push_back(table_item); } else if (OB_FAIL(SMART_CALL(flatten_inner_join(joined_table->left_table_, table_filter, table_items)))) { LOG_WARN("failed to faltten inner join", K(ret)); } else if (OB_FAIL(SMART_CALL(flatten_inner_join(joined_table->right_table_, table_filter, table_items)))) { LOG_WARN("failed to faltten inner join", K(ret)); } else if (OB_FAIL(append(table_filter, joined_table->join_conditions_))) { LOG_WARN("failed to append exprs", K(ret)); } return ret; } int ObLogPlan::inner_generate_outer_join_detectors(JoinedTable* joined_table, ObIArray& table_filter, ObIArray& baserels, ObIArray& outer_join_detectors) { int ret = OB_SUCCESS; ObRelIds table_set; ObRelIds left_table_ids; ObRelIds right_table_ids; ConflictDetector* detector = NULL; ObSEArray left_quals; ObSEArray right_quals; ObSEArray left_detectors; ObSEArray right_detectors; if (OB_ISNULL(joined_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->join_conditions_, table_set))) { LOG_WARN("failed to get table ids", K(ret)); // 1. pushdown where condition } else if (OB_FAIL(pushdown_where_filters(joined_table, table_filter, left_quals, right_quals))) { LOG_WARN("failed to pushdown where filters", K(ret)); // 2. pushdown on condition } else if (OB_FAIL(pushdown_on_conditions(joined_table, left_quals, right_quals))) { LOG_WARN("failed to pushdown on conditions", K(ret)); // 3. generate left child detectors } else if (OB_FAIL(generate_outer_join_detectors(joined_table->left_table_, left_quals, baserels, left_detectors))) { LOG_WARN("failed to generate outer join detectors", K(ret)); } else if (OB_FAIL(append(outer_join_detectors, left_detectors))) { LOG_WARN("failed to append detectors", K(ret)); // 4. generate right child detectors } else if (OB_FAIL( generate_outer_join_detectors(joined_table->right_table_, right_quals, baserels, right_detectors))) { LOG_WARN("failed to generate outer join detectors", K(ret)); } else if (OB_FAIL(append(outer_join_detectors, right_detectors))) { LOG_WARN("failed to append detectors", K(ret)); // 5. create outer join detector } else if (OB_FAIL(ConflictDetector::build_confict(get_allocator(), detector))) { LOG_WARN("failed to build conflict detector", K(ret)); } else if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->left_table_, left_table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->right_table_, right_table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(detector->join_info_.table_set_.add_members(table_set))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(detector->L_DS_.add_members(left_table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(detector->R_DS_.add_members(right_table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(append(detector->join_info_.on_condition_, joined_table->join_conditions_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(outer_join_detectors.push_back(detector))) { LOG_WARN("failed to push back detecotor", K(ret)); } else { detector->is_commutative_ = COMM_PROPERTY[joined_table->joined_type_]; detector->join_info_.join_type_ = joined_table->joined_type_; if (table_set.overlap(left_table_ids) && table_set.overlap(right_table_ids)) { detector->is_degenerate_pred_ = false; } else { detector->is_degenerate_pred_ = true; } if (CONNECT_BY_JOIN == joined_table->joined_type_) { if (OB_FAIL(detector->join_info_.table_set_.add_members(left_table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(detector->join_info_.table_set_.add_members(right_table_ids))) { LOG_WARN("failed to add members", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(detector->L_TES_.intersect(detector->join_info_.table_set_, detector->L_DS_))) { LOG_WARN("failed to generate L-TES", K(ret)); } else if (OB_FAIL(detector->R_TES_.intersect(detector->join_info_.table_set_, detector->R_DS_))) { LOG_WARN("failed to generate R-TES", K(ret)); } } int64_t N = joined_table->join_conditions_.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { ObRawExpr* expr = joined_table->join_conditions_.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->has_flag(IS_JOIN_COND) && OB_FAIL(detector->join_info_.equal_join_condition_.push_back(expr))) { LOG_WARN("failed to push back qual", K(ret)); } } // 6. generate conflict rules for (int64_t i = 0; OB_SUCC(ret) && i < left_detectors.count(); ++i) { if (OB_FAIL(generate_conflict_rule(detector, left_detectors.at(i), true, detector->CR_))) { LOG_WARN("failed to generate conflict rule", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < right_detectors.count(); ++i) { if (OB_FAIL(generate_conflict_rule(detector, right_detectors.at(i), false, detector->CR_))) { LOG_WARN("failed to generate conflict rule", K(ret)); } } // 7. generate conflict detector for table filter if (OB_SUCC(ret) && !table_filter.empty()) { if (OB_FAIL(ConflictDetector::build_confict(get_allocator(), detector))) { LOG_WARN("failed to build conflict detector", K(ret)); } else if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (OB_FAIL(append(detector->join_info_.where_condition_, table_filter))) { LOG_WARN("failed to append expr", K(ret)); } else if (OB_FAIL(detector->join_info_.table_set_.add_members(left_table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(detector->join_info_.table_set_.add_members(right_table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(outer_join_detectors.push_back(detector))) { LOG_WARN("failed to push back detector", K(ret)); } else { detector->is_degenerate_pred_ = false; detector->is_commutative_ = COMM_PROPERTY[INNER_JOIN]; detector->join_info_.join_type_ = INNER_JOIN; } } } return ret; } int ObLogPlan::pushdown_where_filters(JoinedTable* joined_table, ObIArray& table_filter, ObIArray& left_quals, ObIArray& right_quals) { int ret = OB_SUCCESS; if (OB_ISNULL(joined_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else { ObRelIds left_table_set; ObRelIds right_table_set; int64_t N = table_filter.count(); ObSEArray new_quals; ObJoinType join_type = joined_table->joined_type_; if (OB_FAIL(get_table_ids(joined_table->left_table_, left_table_set))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->right_table_, right_table_set))) { LOG_WARN("failed to get table ids", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) { ObRawExpr* qual = table_filter.at(i); if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(qual), K(ret)); } else if (qual->get_relation_ids().is_empty() && !ObOptimizerUtil::has_hierarchical_expr(*qual)) { if (OB_FAIL(left_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(right_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (LEFT_OUTER_JOIN == join_type && qual->get_relation_ids().is_subset(left_table_set)) { if (OB_FAIL(left_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (RIGHT_OUTER_JOIN == join_type && qual->get_relation_ids().is_subset(right_table_set)) { if (OB_FAIL(right_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (OB_FAIL(new_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } else if (T_OP_OR == qual->get_expr_type()) { ObOpRawExpr* or_qual = static_cast(qual); if (LEFT_OUTER_JOIN == join_type && OB_FAIL(try_split_or_qual(left_table_set, *or_qual, left_quals))) { LOG_WARN("failed to split or qual on left table", K(ret)); } else if (RIGHT_OUTER_JOIN == join_type && OB_FAIL(try_split_or_qual(right_table_set, *or_qual, right_quals))) { LOG_WARN("failed to split or qual on right table", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(table_filter.assign(new_quals))) { LOG_WARN("failed to assign exprs", K(ret)); } } } return ret; } int ObLogPlan::pushdown_on_conditions( JoinedTable* joined_table, ObIArray& left_quals, ObIArray& right_quals) { int ret = OB_SUCCESS; if (OB_ISNULL(joined_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else { ObRawExpr* qual = NULL; ObRelIds left_table_set; ObRelIds right_table_set; ObSEArray new_quals; ObJoinType join_type = joined_table->joined_type_; int64_t N = joined_table->join_conditions_.count(); if (OB_FAIL(get_table_ids(joined_table->left_table_, left_table_set))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->right_table_, right_table_set))) { LOG_WARN("failed to get table ids", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) { if (OB_ISNULL(qual = joined_table->join_conditions_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(qual), K(ret)); } else if (RIGHT_OUTER_JOIN == join_type && qual->get_relation_ids().is_subset(left_table_set)) { if (OB_FAIL(left_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (LEFT_OUTER_JOIN == join_type && qual->get_relation_ids().is_subset(right_table_set)) { if (OB_FAIL(right_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (CONNECT_BY_JOIN == join_type && !qual->get_relation_ids().is_empty() && qual->get_relation_ids().is_subset(right_table_set) && !qual->has_flag(CNT_LEVEL) && !qual->has_flag(CNT_PRIOR) && !qual->has_flag(CNT_ROWNUM)) { if (OB_FAIL(right_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (OB_FAIL(new_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } else if (!qual->get_relation_ids().is_empty() && T_OP_OR == qual->get_expr_type()) { ObOpRawExpr* or_qual = static_cast(qual); if (LEFT_OUTER_JOIN == join_type && OB_FAIL(try_split_or_qual(right_table_set, *or_qual, right_quals))) { LOG_WARN("failed to split or qual on right table", K(ret)); } else if (RIGHT_OUTER_JOIN == join_type && OB_FAIL(try_split_or_qual(left_table_set, *or_qual, left_quals))) { LOG_WARN("failed to split or qual on left table", K(ret)); } else if (CONNECT_BY_JOIN == join_type && !qual->has_flag(CNT_LEVEL) && !qual->has_flag(CNT_ROWNUM) && !qual->has_flag(CNT_PRIOR) && OB_FAIL(try_split_or_qual(right_table_set, *or_qual, right_quals))) { LOG_WARN("failed to split or qual on right table", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(joined_table->join_conditions_.assign(new_quals))) { LOG_WARN("failed to assign exprs", K(ret)); } } } return ret; } int ObLogPlan::generate_cross_product_detector(const ObIArray& table_items, ObIArray& quals, ObIArray& inner_join_detectors) { int ret = OB_SUCCESS; ObRelIds table_ids; ConflictDetector* detector = NULL; if (table_items.count() < 2) { // do nothing } else if (OB_FAIL(get_table_ids(table_items, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(ConflictDetector::build_confict(get_allocator(), detector))) { LOG_WARN("failed to build conflict detector", K(ret)); } else if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null conflict detector", K(ret)); } else if (OB_FAIL(detector->L_DS_.add_members(table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(detector->R_DS_.add_members(table_ids))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(generate_cross_product_conflict_rule(detector, table_items, quals))) { LOG_WARN("failed to generate cross product conflict rule", K(ret)); } else if (OB_FAIL(inner_join_detectors.push_back(detector))) { LOG_WARN("failed to push back detector", K(ret)); } else { detector->join_info_.join_type_ = INNER_JOIN; detector->is_degenerate_pred_ = true; detector->is_commutative_ = true; } return ret; } int ObLogPlan::check_join_info( const ObRelIds& left, const ObRelIds& right, const ObIArray& base_table_ids, bool& is_connected) { int ret = OB_SUCCESS; ObRelIds table_ids; is_connected = false; if (OB_FAIL(table_ids.except(left, right))) { LOG_WARN("failed to cal except for rel ids", K(ret)); } else if (table_ids.is_empty()) { is_connected = true; } else { int64_t N = base_table_ids.count(); for (int64_t i = 0; OB_SUCC(ret) && !is_connected && i < N; ++i) { if (table_ids.is_subset(base_table_ids.at(i))) { is_connected = true; } } } return ret; } int ObLogPlan::generate_cross_product_conflict_rule(ConflictDetector* cross_product_detector, const ObIArray& table_items, const ObIArray& join_conditions) { int ret = OB_SUCCESS; if (OB_ISNULL(cross_product_detector)) { ret = OB_SUCCESS; LOG_WARN("unexpect null detector", K(ret)); } else { ObRelIds table_ids; bool have_new_connect_info = true; ObSEArray base_table_ids; ObSEArray connect_infos; LOG_TRACE("start generate cross product conflict rule", K(table_items), K(join_conditions)); for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { table_ids.reuse(); if (OB_FAIL(get_table_ids(table_items.at(i), table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(base_table_ids.push_back(table_ids))) { LOG_WARN("failed to push back rel ids", K(ret)); } else if (OB_FAIL(connect_infos.push_back(table_ids))) { LOG_WARN("failed to push back rel ids", K(ret)); } } ObSqlBitSet<> used_join_conditions; while (have_new_connect_info) { have_new_connect_info = false; for (int64_t i = 0; OB_SUCC(ret) && i < join_conditions.count(); ++i) { ObRawExpr* expr = join_conditions.at(i); if (used_join_conditions.has_member(i)) { // do nothing } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else { ObSqlBitSet<> used_infos; ObRelIds connect_tables; if (OB_FAIL(connect_tables.add_members(expr->get_relation_ids()))) { LOG_WARN("failed to add members", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < connect_infos.count(); ++j) { bool is_connected = false; if (OB_FAIL(check_join_info(expr->get_relation_ids(), connect_infos.at(j), base_table_ids, is_connected))) { LOG_WARN("failed to check join info", K(ret)); } else if (!is_connected) { // do nothing } else if (OB_FAIL(used_infos.add_member(j))) { LOG_WARN("failed to add member", K(ret)); } else if (connect_tables.add_members(connect_infos.at(j))) { LOG_WARN("failed to add members", K(ret)); } } if (OB_SUCC(ret) && !used_infos.is_empty()) { have_new_connect_info = true; if (OB_FAIL(used_join_conditions.add_member(i))) { LOG_WARN("failed to add member", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < connect_infos.count(); ++j) { if (!used_infos.has_member(j)) { // do nothing } else if (OB_FAIL(connect_infos.at(j).add_members(connect_tables))) { LOG_WARN("failed to add members", K(ret)); } } LOG_TRACE("succeed to add new connect info", K(*expr), K(connect_infos)); } } } } ObSEArray new_connect_infos; for (int64_t i = 0; OB_SUCC(ret) && i < connect_infos.count(); ++i) { bool find = false; for (int64_t j = 0; !find && j < new_connect_infos.count(); ++j) { if (new_connect_infos.at(j).equal(connect_infos.at(i))) { find = true; } } if (!find) { ret = new_connect_infos.push_back(connect_infos.at(i)); } } for (int64_t i = 0; OB_SUCC(ret) && i < base_table_ids.count(); ++i) { if (base_table_ids.at(i).num_members() < 2) { // do nothing } else if (OB_FAIL(add_conflict_rule( base_table_ids.at(i), base_table_ids.at(i), cross_product_detector->cross_product_rule_))) { LOG_WARN("failed to add conflict rule", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < new_connect_infos.count(); ++i) { if (new_connect_infos.at(i).num_members() < 2) { // do nothing } else if (OB_FAIL(add_conflict_rule(new_connect_infos.at(i), new_connect_infos.at(i), cross_product_detector->delay_cross_product_rule_))) { LOG_WARN("failed to add conflict rule", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < new_connect_infos.count(); ++i) { if (new_connect_infos.at(i).num_members() > 1) { for (int64_t j = i + 1; OB_SUCC(ret) && j < new_connect_infos.count(); ++j) { if (new_connect_infos.at(j).num_members() > 1) { ObRelIds bushy_info; if (OB_FAIL(bushy_info.add_members(new_connect_infos.at(i)))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(bushy_info.add_members(new_connect_infos.at(j)))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(bushy_tree_infos_.push_back(bushy_info))) { LOG_WARN("failed to push back info", K(ret)); } } } } } if (OB_SUCC(ret)) { if (new_connect_infos.count() == 1) { cross_product_detector->is_redundancy_ = true; } } LOG_TRACE("update bushy tree info", K(bushy_tree_infos_)); } return ret; } int ObLogPlan::select_location(ObIArray& tbl_part_info_list) { int ret = OB_SUCCESS; ObExecContext* exec_ctx = optimizer_context_.get_exec_ctx(); ObSEArray tbl_loc_list; ObSEArray phy_tbl_loc_info_list; if (OB_ISNULL(exec_ctx)) { LOG_ERROR("exec ctx is NULL", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < tbl_part_info_list.count(); ++i) { ObTablePartitionInfo* tbl_part_info = tbl_part_info_list.at(i); if (OB_ISNULL(tbl_part_info)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("tbl part info is NULL", K(ret), K(i), K(tbl_part_info_list.count())); } else if (OB_FAIL(tbl_loc_list.push_back(&tbl_part_info->get_table_location()))) { LOG_WARN("fail to push back table location list", K(ret), K(tbl_part_info->get_table_location())); } else if (OB_FAIL(phy_tbl_loc_info_list.push_back(&tbl_part_info->get_phy_tbl_location_info_for_update()))) { LOG_WARN("fail to push back phy tble loc info", K(ret), K(tbl_part_info->get_phy_tbl_location_info_for_update())); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObLogPlan::select_replicas( *exec_ctx, tbl_loc_list, optimizer_context_.get_local_server_addr(), phy_tbl_loc_info_list))) { LOG_WARN("fail to select replicas", K(ret), K(tbl_loc_list.count()), K(optimizer_context_.get_local_server_addr()), K(phy_tbl_loc_info_list.count())); } return ret; } int ObLogPlan::select_replicas(ObExecContext& exec_ctx, const ObIArray& tbl_loc_list, const ObAddr& local_server, ObIArray& phy_tbl_loc_info_list) { int ret = OB_SUCCESS; bool is_weak = true; if (OB_ISNULL(exec_ctx.get_my_session())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { is_weak = !ObDMLStmt::is_dml_write_stmt(exec_ctx.get_my_session()->get_stmt_type()); } for (int64_t i = 0; OB_SUCC(ret) && is_weak && i < tbl_loc_list.count(); i++) { bool is_weak_read = false; const ObTableLocation* table_location = tbl_loc_list.at(i); if (OB_ISNULL(table_location)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("table location is NULL", K(ret), K(i), K(tbl_loc_list.count())); } else if (OB_FAIL(table_location->get_is_weak_read(exec_ctx, is_weak_read))) { LOG_WARN("fail to get is weak read", K(ret), K(*table_location)); } else if (!is_weak_read) { is_weak = false; } } if (OB_SUCC(ret)) { if (OB_FAIL(select_replicas(exec_ctx, is_weak, local_server, phy_tbl_loc_info_list))) { LOG_WARN("select replicas failed", K(ret)); } } return ret; } int ObLogPlan::select_replicas(ObExecContext& exec_ctx, bool is_weak, const ObAddr& local_server, ObIArray& phy_tbl_loc_info_list) { int ret = OB_SUCCESS; ObSQLSessionInfo* session = exec_ctx.get_my_session(); ObTaskExecutorCtx& task_exec_ctx = exec_ctx.get_task_exec_ctx(); ObPartitionService* partition_service = NULL; bool is_hit_partition = false; ObFollowerFirstFeedbackType follower_first_feedback = FFF_HIT_MIN; int64_t route_policy_type = 0; bool proxy_priority_hit_support = false; if (OB_ISNULL(session) || OB_ISNULL(partition_service = task_exec_ctx.get_partition_service())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("session is NULL", K(ret), K(session), K(partition_service)); } else if (OB_FAIL(session->get_sys_variable(SYS_VAR_OB_ROUTE_POLICY, route_policy_type))) { LOG_WARN("fail to get sys variable", K(ret)); } else { proxy_priority_hit_support = session->get_proxy_cap_flags().is_priority_hit_support(); } if (OB_FAIL(ret)) { } else if (is_weak) { if (OB_FAIL(ObLogPlan::weak_select_replicas(*partition_service, local_server, static_cast(route_policy_type), proxy_priority_hit_support, phy_tbl_loc_info_list, is_hit_partition, follower_first_feedback))) { LOG_WARN("fail to weak select intersect replicas", K(ret), K(local_server), K(phy_tbl_loc_info_list.count())); } else { ObPartitionKey part_key; session->partition_hit().try_set_bool(is_hit_partition); if (FFF_HIT_MIN != follower_first_feedback) { if (OB_FAIL(session->set_follower_first_feedback(follower_first_feedback))) { LOG_WARN("fail to set_follower_first_feedback", K(follower_first_feedback), K(ret)); } } if (OB_SUCC(ret)) { task_exec_ctx.set_need_renew_location_cache(!is_hit_partition); if (task_exec_ctx.is_need_renew_location_cache()) { for (int64_t i = 0; OB_SUCC(ret) && i < phy_tbl_loc_info_list.count(); ++i) { const ObPhyTableLocationInfo* phy_tbl_loc_info = phy_tbl_loc_info_list.at(i); if (OB_ISNULL(phy_tbl_loc_info)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("phy tbl loc info is NULL", K(ret), K(i)); } else { const ObPhyPartitionLocationInfoIArray& phy_part_loc_info_list = phy_tbl_loc_info->get_phy_part_loc_info_list(); for (int64_t j = 0; OB_SUCC(ret) && j < phy_part_loc_info_list.count(); ++j) { part_key.reset(); const ObPhyPartitionLocationInfo& phy_part_loc_info = phy_part_loc_info_list.at(j); if (OB_FAIL(phy_part_loc_info.get_partition_location().get_partition_key(part_key))) { LOG_WARN("fail to get part key", K(ret), K(phy_part_loc_info.get_partition_location())); } else if (OB_FAIL(task_exec_ctx.add_need_renew_partition_keys_distinctly(part_key))) { LOG_WARN("fail to add need renew partition key", K(ret), K(part_key)); } } } } } } } } else { const bool sess_in_retry = session->get_is_in_retry_for_dup_tbl(); if (OB_FAIL( ObLogPlan::strong_select_replicas(local_server, phy_tbl_loc_info_list, is_hit_partition, sess_in_retry))) { LOG_WARN("fail to strong select replicas", K(ret), K(local_server), K(phy_tbl_loc_info_list.count())); int tmp_ret = set_table_location(task_exec_ctx, phy_tbl_loc_info_list); if (OB_SUCCESS != tmp_ret) { LOG_WARN("fail to set table location", K(tmp_ret), K(phy_tbl_loc_info_list)); } } else { session->partition_hit().try_set_bool(is_hit_partition); task_exec_ctx.set_need_renew_location_cache(false); } } return ret; } int ObLogPlan::set_table_location( ObTaskExecutorCtx& task_exec_ctx, ObIArray& phy_tbl_loc_info_list) { int ret = OB_SUCCESS; ObPhyTableLocation location; ObPartitionKey key; ObPartitionReplicaLocation partition_replica_location; for (int64_t i = 0; i < phy_tbl_loc_info_list.count() && OB_SUCC(ret); i++) { ObPhyTableLocationInfo*& info = phy_tbl_loc_info_list.at(i); location.reset(); for (int64_t j = 0; j < info->get_phy_part_loc_info_list().count() && OB_SUCC(ret); j++) { const ObPhyPartitionLocationInfo& partition_location_info = info->get_phy_part_loc_info_list().at(j); const ObOptPartLoc& part_loc = partition_location_info.get_partition_location(); if (OB_FAIL(part_loc.get_partition_key(key))) { LOG_WARN("fail to get partition key", K(ret), K(part_loc)); } else { partition_replica_location.set_table_id(key.get_table_id()); partition_replica_location.set_partition_id(key.get_partition_id()); partition_replica_location.set_partition_cnt(key.get_partition_cnt()); if (OB_FAIL(location.add_partition_location(partition_replica_location))) { LOG_WARN("fail to add partition location", K(ret)); } } } // end for if (OB_SUCC(ret)) { if (OB_FAIL(task_exec_ctx.get_table_locations().push_back(location))) { LOG_WARN("fail to push back", K(ret), K(location)); } } } // end for LOG_TRACE("finish set table location", "table_locaiont", task_exec_ctx.get_table_locations()); return ret; } int ObLogPlan::strong_select_replicas(const ObAddr& local_server, ObIArray& phy_tbl_loc_info_list, bool& is_hit_partition, bool sess_in_retry) { int ret = OB_SUCCESS; bool all_is_on_same_server = true; ObAddr all_same_server = local_server; ObAddr cur_same_server; for (int64_t i = 0; OB_SUCC(ret) && i < phy_tbl_loc_info_list.count(); ++i) { cur_same_server.reset(); ObPhyTableLocationInfo* phy_tbl_loc_info = phy_tbl_loc_info_list.at(i); bool is_on_same_server = false; if (OB_ISNULL(phy_tbl_loc_info)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("phy_tbl_loc_info is NULL", K(ret), K(i), K(phy_tbl_loc_info_list.count())); } else if (0 == phy_tbl_loc_info->get_partition_cnt()) { } else { if (!sess_in_retry && phy_tbl_loc_info->is_duplicate_table_not_in_dml()) { if (OB_FAIL(phy_tbl_loc_info->all_select_local_replica_or_leader( is_on_same_server, cur_same_server, local_server))) { LOG_WARN("fail to all select leader", K(ret), K(*phy_tbl_loc_info)); } else { LOG_TRACE("succeed to select replica for duplicate table", K(*phy_tbl_loc_info), K(is_on_same_server)); } } else { if (OB_FAIL(phy_tbl_loc_info->all_select_leader(is_on_same_server, cur_same_server))) { LOG_WARN("fail to all select leader", K(ret), K(*phy_tbl_loc_info)); } } if (OB_FAIL(ret)) { // do nothing... } else if (all_is_on_same_server) { if (is_on_same_server) { if (0 == i) { all_same_server = cur_same_server; } else if (all_same_server != cur_same_server) { all_is_on_same_server = false; } } else { all_is_on_same_server = false; } } } } if (OB_SUCC(ret)) { if (all_is_on_same_server && local_server != all_same_server) { is_hit_partition = false; } else { is_hit_partition = true; } } return ret; } int ObLogPlan::get_global_phy_tbl_location_info(ObPhyTableLocationInfoIArray& tbl_infos) const { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt()) || OB_ISNULL(get_stmt()->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(get_stmt())); } else { const ObTablePartitionInfoArray& tbl_part_infos = get_stmt()->get_query_ctx()->table_partition_infos_; ARRAY_FOREACH(tbl_part_infos, i) { if (OB_ISNULL(tbl_part_infos.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table partition info is null"); } else if (OB_FAIL(tbl_infos.push_back(tbl_part_infos.at(i)->get_phy_tbl_location_info()))) { LOG_WARN("add phy table location info failed", K(ret)); } } } return ret; } int ObLogPlan::weak_select_replicas(ObPartitionService& partition_service, const ObAddr& local_server, ObRoutePolicyType route_type, bool proxy_priority_hit_support, ObIArray& phy_tbl_loc_info_list, bool& is_hit_partition, ObFollowerFirstFeedbackType& follower_first_feedback) { int ret = OB_SUCCESS; is_hit_partition = true; ObPhyTableLocationInfo* phy_tbl_loc_info = nullptr; ObArenaAllocator allocator(ObModIds::OB_SQL_OPTIMIZER_SELECT_REPLICA); ObList intersect_server_list(allocator); ObRoutePolicy route_policy(local_server, partition_service); ObRoutePolicyCtx route_policy_ctx; route_policy_ctx.policy_type_ = route_type; route_policy_ctx.consistency_level_ = WEAK; route_policy_ctx.is_proxy_priority_hit_support_ = proxy_priority_hit_support; if (OB_FAIL(route_policy.init())) { LOG_WARN("fail to init route policy", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < phy_tbl_loc_info_list.count(); ++i) { if (OB_ISNULL(phy_tbl_loc_info = phy_tbl_loc_info_list.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("phy table loc info is NULL", K(phy_tbl_loc_info), K(i), K(ret)); } else { ObPhyPartitionLocationInfoIArray& phy_part_loc_info_list = phy_tbl_loc_info->get_phy_part_loc_info_list_for_update(); for (int64_t j = 0; OB_SUCC(ret) && j < phy_part_loc_info_list.count(); ++j) { ObPhyPartitionLocationInfo& phy_part_loc_info = phy_part_loc_info_list.at(j); if (phy_part_loc_info.has_selected_replica()) { // do nothing } else { ObIArray& replica_array = phy_part_loc_info.get_partition_location().get_replica_locations(); if (OB_FAIL(route_policy.init_candidate_replicas(replica_array))) { LOG_WARN("fail to init candidate replicas", K(replica_array), K(ret)); } else if (OB_FAIL(route_policy.calculate_replica_priority(replica_array, route_policy_ctx))) { LOG_WARN("fail to calculate replica priority", K(replica_array), K(route_policy_ctx), K(ret)); } else if (OB_FAIL(route_policy.select_replica_with_priority( route_policy_ctx, replica_array, phy_part_loc_info))) { LOG_WARN("fail to select replica", K(replica_array), K(ret)); } } } } } if (OB_FAIL(ret)) { } else if (OB_FAIL(route_policy.select_intersect_replica( route_policy_ctx, phy_tbl_loc_info_list, intersect_server_list, is_hit_partition))) { LOG_WARN("fail to select intersect replica", K(route_policy_ctx), K(phy_tbl_loc_info_list), K(intersect_server_list), K(ret)); } if (OB_SUCC(ret)) { if (proxy_priority_hit_support) { // nothing, current doesn't support } else { ObArenaAllocator allocator(ObModIds::OB_SQL_OPTIMIZER_SELECT_REPLICA); ObAddrList intersect_servers(allocator); if (OB_FAIL(calc_hit_partition_for_compat( phy_tbl_loc_info_list, local_server, is_hit_partition, intersect_servers))) { LOG_WARN("fail to calc hit partition for compat", K(ret)); } else { if (is_hit_partition && route_policy.is_follower_first_route_policy_type(route_policy_ctx)) { if (OB_FAIL(calc_follower_first_feedback( phy_tbl_loc_info_list, local_server, intersect_servers, follower_first_feedback))) { LOG_WARN("fail to calc follower first feedback", K(ret)); } } } } } if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) { LOG_INFO("selected replica ", "intersect_server_list", intersect_server_list, "\n phy_tbl_loc_info_list", phy_tbl_loc_info_list, "\n route_policy", route_policy, "\n route_policy_ctx", route_policy_ctx, "\n follower_first_feedback", follower_first_feedback, "\n is_hit_partition", is_hit_partition); } return ret; } int ObLogPlan::calc_follower_first_feedback(const ObIArray& phy_tbl_loc_info_list, const ObAddr& local_server, const ObAddrList& intersect_servers, ObFollowerFirstFeedbackType& follower_first_feedback) { INIT_SUCC(ret); follower_first_feedback = FFF_HIT_MIN; if (intersect_servers.empty()) { // nothing, no need feedback } else { bool is_leader_replica = true; for (int64_t i = 0; OB_SUCC(ret) && is_leader_replica && (i < phy_tbl_loc_info_list.count()); ++i) { const ObPhyTableLocationInfo* phy_tbl_loc_info = phy_tbl_loc_info_list.at(i); if (OB_ISNULL(phy_tbl_loc_info)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("phy_tbl_loc_info is NULL", K(ret), K(i), K(phy_tbl_loc_info_list.count())); } else { const ObPhyPartitionLocationInfoIArray& phy_part_loc_info_list = phy_tbl_loc_info->get_phy_part_loc_info_list(); if (phy_part_loc_info_list.empty()) { // juest defense, when partition location list is empty, treat as it's not leader replica is_leader_replica = false; } for (int64_t j = 0; OB_SUCC(ret) && is_leader_replica && (j < phy_part_loc_info_list.count()); ++j) { bool found_server = false; const ObPhyPartitionLocationInfo& phy_part_loc_info = phy_part_loc_info_list.at(j); const ObIArray& replica_loc_list = phy_part_loc_info.get_partition_location().get_replica_locations(); for (int64_t k = 0; !found_server && (k < replica_loc_list.count()); ++k) { const ObRoutePolicy::CandidateReplica& tmp_replica = replica_loc_list.at(k); if (local_server == tmp_replica.server_) { found_server = true; is_leader_replica = (is_strong_leader(tmp_replica.role_)); } } if (!found_server) { // if not found, just treat as it's not leader is_leader_replica = false; } } } } if (is_leader_replica) { follower_first_feedback = FFF_HIT_LEADER; } else { // nothing, no need feedback } LOG_TRACE("after calc follower first feedback", K(follower_first_feedback), K(is_leader_replica), K(local_server), K(intersect_servers)); } return ret; } int ObLogPlan::calc_hit_partition_for_compat(const ObIArray& phy_tbl_loc_info_list, const ObAddr& local_server, bool& is_hit_partition, ObAddrList& intersect_servers) { int ret = OB_SUCCESS; bool can_select_local_server = false; is_hit_partition = false; if (OB_FAIL(calc_intersect_servers(phy_tbl_loc_info_list, intersect_servers))) { LOG_WARN("fail to calc hit partition for compat", K(ret)); } else if (intersect_servers.empty()) { is_hit_partition = true; } else { ObAddrList::iterator candidate_server_list_iter = intersect_servers.begin(); for (; OB_SUCC(ret) && !can_select_local_server && candidate_server_list_iter != intersect_servers.end(); candidate_server_list_iter++) { const ObAddr& candidate_server = *candidate_server_list_iter; if (local_server == candidate_server) { is_hit_partition = true; can_select_local_server = true; } } } return ret; } int ObLogPlan::calc_intersect_servers( const ObIArray& phy_tbl_loc_info_list, ObAddrList& candidate_server_list) { int ret = OB_SUCCESS; bool can_select_one_server = true; ObRoutePolicy::CandidateReplica tmp_replica; candidate_server_list.reset(); for (int64_t i = 0; OB_SUCC(ret) && can_select_one_server && i < phy_tbl_loc_info_list.count(); ++i) { const ObPhyTableLocationInfo* phy_tbl_loc_info = phy_tbl_loc_info_list.at(i); if (OB_ISNULL(phy_tbl_loc_info)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("phy_tbl_loc_info is NULL", K(ret), K(i), K(phy_tbl_loc_info_list.count())); } else { const ObPhyPartitionLocationInfoIArray& phy_part_loc_info_list = phy_tbl_loc_info->get_phy_part_loc_info_list(); for (int64_t j = 0; OB_SUCC(ret) && can_select_one_server && j < phy_part_loc_info_list.count(); ++j) { const ObPhyPartitionLocationInfo& phy_part_loc_info = phy_part_loc_info_list.at(j); const ObIArray& replica_loc_list = phy_part_loc_info.get_partition_location().get_replica_locations(); if (0 == i && 0 == j) { for (int64_t k = 0; OB_SUCC(ret) && k < replica_loc_list.count(); ++k) { if (OB_FAIL(candidate_server_list.push_back(replica_loc_list.at(k).server_))) { LOG_WARN("fail to push back candidate server", K(ret), K(k), K(replica_loc_list.at(k))); } } } else { ObAddrList::iterator candidate_server_list_iter = candidate_server_list.begin(); for (; OB_SUCC(ret) && candidate_server_list_iter != candidate_server_list.end(); candidate_server_list_iter++) { const ObAddr& candidate_server = *candidate_server_list_iter; bool has_replica = false; for (int64_t k = 0; OB_SUCC(ret) && !has_replica && k < replica_loc_list.count(); ++k) { if (replica_loc_list.at(k).server_ == candidate_server) { has_replica = true; } } if (OB_SUCC(ret) && !has_replica) { if (OB_FAIL(candidate_server_list.erase(candidate_server_list_iter))) { LOG_WARN("fail to erase from list", K(ret), K(replica_loc_list), K(candidate_server)); } } } if (OB_SUCC(ret) && candidate_server_list.empty()) { can_select_one_server = false; } } } } } return ret; } int ObLogPlan::select_one_server( const ObAddr& selected_server, ObIArray& phy_tbl_loc_info_list) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < phy_tbl_loc_info_list.count(); ++i) { ObPhyTableLocationInfo* phy_tbl_loc_info = phy_tbl_loc_info_list.at(i); if (OB_ISNULL(phy_tbl_loc_info)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("phy_tbl_loc_info is NULL", K(ret), K(i), K(phy_tbl_loc_info_list.count())); } else { ObPhyPartitionLocationInfoIArray& phy_part_loc_info_list = phy_tbl_loc_info->get_phy_part_loc_info_list_for_update(); for (int64_t j = 0; OB_SUCC(ret) && j < phy_part_loc_info_list.count(); ++j) { ObPhyPartitionLocationInfo& phy_part_loc_info = phy_part_loc_info_list.at(j); if (phy_part_loc_info.has_selected_replica()) { } else { const ObIArray& replica_loc_list = phy_part_loc_info.get_partition_location().get_replica_locations(); bool replica_is_selected = false; for (int64_t k = 0; OB_SUCC(ret) && !replica_is_selected && k < replica_loc_list.count(); ++k) { if (selected_server == replica_loc_list.at(k).server_) { if (OB_FAIL(phy_part_loc_info.set_selected_replica_idx(k))) { LOG_WARN("fail to set selected replica idx", K(ret), K(k), K(phy_part_loc_info)); } else { replica_is_selected = true; } } } if (OB_SUCC(ret) && OB_UNLIKELY(!replica_is_selected)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("has no selected replica", K(ret), K(selected_server), K(replica_loc_list)); } } } } } return ret; } int ObLogPlan::init_leading_info_from_joined_tables(TableItem* table) { int ret = OB_SUCCESS; if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (!table->is_joined_table()) { // do nothing } else { JoinedTable* joined_table = static_cast(table); LeadingInfo hint_info; if (OB_FAIL(get_table_ids(table, hint_info.table_set_))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->left_table_, hint_info.left_table_set_))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(get_table_ids(joined_table->right_table_, hint_info.right_table_set_))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(leading_infos_.push_back(hint_info))) { LOG_WARN("failed to push back hint info", K(ret)); } else if (OB_FAIL(SMART_CALL(init_leading_info_from_joined_tables(joined_table->left_table_)))) { LOG_WARN("failed to get leading hint info", K(ret)); } else if (OB_FAIL(SMART_CALL(init_leading_info_from_joined_tables(joined_table->right_table_)))) { LOG_WARN("failed to get leading hint info", K(ret)); } } return ret; } int ObLogPlan::init_leading_info_from_tables( const ObIArray& table_items, const ObIArray& semi_infos) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { TableItem* table = table_items.at(i); LeadingInfo hint_info; ObRelIds table_ids; if (OB_FAIL(get_table_ids(table, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(init_leading_info_from_joined_tables(table))) { LOG_WARN("failed to get leading hint infos", K(ret)); } else if (i == 0) { ret = leading_tables_.add_members(table_ids); } else if (OB_FAIL(hint_info.left_table_set_.add_members(leading_tables_))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(hint_info.right_table_set_.add_members(table_ids))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(leading_tables_.add_members(table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(hint_info.table_set_.add_members(leading_tables_))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(leading_infos_.push_back(hint_info))) { LOG_WARN("failed to push back hint info", K(ret)); } } ObSqlBitSet<> right_rel_ids; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < semi_infos.count(); ++i) { SemiInfo* semi_info = semi_infos.at(i); LeadingInfo hint_info; right_rel_ids.reuse(); if (OB_ISNULL(semi_info)) { LOG_WARN("unexpect null semi info", K(ret)); } else if (OB_FAIL(stmt->get_table_rel_ids(semi_info->right_table_id_, right_rel_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(hint_info.left_table_set_.add_members(leading_tables_))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(hint_info.right_table_set_.add_members(right_rel_ids))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(leading_tables_.add_members(right_rel_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(hint_info.table_set_.add_members(leading_tables_))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(leading_infos_.push_back(hint_info))) { LOG_WARN("failed to push back hint info", K(ret)); } } return ret; } int ObLogPlan::find_join_order_pair( uint8_t beg_pos, uint8_t& end_pos, uint8_t ignore_beg_pos, uint8_t& ignore_end_pos, bool& found) { int ret = OB_SUCCESS; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else { const ObStmtHint& hint = stmt->get_stmt_hint(); const ObIArray>& join_order_pairs = hint.join_order_pairs_; for (int64_t i = 0; i < join_order_pairs.count(); ++i) { if (join_order_pairs.at(i).first == ignore_beg_pos && join_order_pairs.at(i).second == ignore_end_pos) { // do nothing } else if (join_order_pairs.at(i).second > ignore_end_pos) { // do nothing } else if (join_order_pairs.at(i).first == beg_pos) { if (found && end_pos < join_order_pairs.at(i).second) { end_pos = join_order_pairs.at(i).second; } else if (!found) { end_pos = join_order_pairs.at(i).second; found = true; } } } } return ret; } int ObLogPlan::get_table_ids_from_leading(uint8_t pos, ObRelIds& table_ids) { int ret = OB_SUCCESS; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else { int32_t id = OB_INVALID; const ObStmtHint& hint = stmt->get_stmt_hint(); const ObIArray& join_order_ids = hint.join_order_ids_; if (pos >= join_order_ids.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect join order id", K(ret)); } else if ((id = stmt->get_table_bit_index(join_order_ids.at(pos))) == OB_INVALID) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid table id", K(ret)); } else if (OB_FAIL(table_ids.add_member(id))) { LOG_WARN("failed to add table id", K(ret)); } } return ret; } int ObLogPlan::init_leading_info_from_leading_pair(uint8_t beg_pos, uint8_t end_pos, ObRelIds& table_set) { int ret = OB_SUCCESS; uint8_t pair_end = 0; for (int64_t i = beg_pos; OB_SUCC(ret) && i <= end_pos; ++i) { LeadingInfo hint_info; ObRelIds table_ids; bool found = false; if (OB_FAIL(find_join_order_pair(i, pair_end, beg_pos, end_pos, found))) { LOG_WARN("failed to find join order pair", K(ret)); } else if (!found && OB_FAIL(get_table_ids_from_leading(i, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (found && OB_FAIL(SMART_CALL(init_leading_info_from_leading_pair(i, pair_end, table_ids)))) { LOG_WARN("failed to get leading hint info from leading pair", K(ret)); } else if (i == beg_pos) { ret = table_set.add_members(table_ids); } else if (OB_FAIL(hint_info.left_table_set_.add_members(table_set))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(hint_info.right_table_set_.add_members(table_ids))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(table_set.add_members(table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(hint_info.table_set_.add_members(table_set))) { LOG_WARN("failed to add table ids", K(ret)); } else if (OB_FAIL(leading_infos_.push_back(hint_info))) { LOG_WARN("failed to push back hint info", K(ret)); } if (OB_SUCC(ret) && found) { i = pair_end; } } return ret; } int ObLogPlan::init_leading_info_from_leading() { int ret = OB_SUCCESS; ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else { const ObStmtHint& hint = stmt->get_stmt_hint(); const ObIArray& join_order_ids = hint.join_order_ids_; if (join_order_ids.count() == 0) { // do nothing } else if (OB_FAIL(init_leading_info_from_leading_pair(0, join_order_ids.count() - 1, leading_tables_))) { LOG_WARN("failed to get leading hint", K(ret)); } } return ret; } int ObLogPlan::init_leading_info(const ObIArray& table_items, const ObIArray& semi_infos) { int ret = OB_SUCCESS; ObDMLStmt* stmt = get_stmt(); leading_tables_.reuse(); leading_infos_.reuse(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else if (stmt->get_stmt_hint().join_ordered_) { ret = init_leading_info_from_tables(table_items, semi_infos); } else if (stmt->get_stmt_hint().join_order_ids_.count() > 0) { ret = init_leading_info_from_leading(); } if (OB_SUCC(ret)) { LOG_TRACE("succeed to get leading infos", K(leading_tables_), K(leading_infos_)); } return ret; } int ObLogPlan::init_bushy_tree_info(const ObIArray& table_items) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < leading_infos_.count(); ++i) { const LeadingInfo& info = leading_infos_.at(i); if (info.left_table_set_.num_members() > 1 && info.right_table_set_.num_members() > 1) { ret = bushy_tree_infos_.push_back(info.table_set_); } } for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { if (OB_FAIL(init_bushy_tree_info_from_joined_tables(table_items.at(i)))) { LOG_WARN("failed to init bushy tree info", K(ret)); } } if (OB_SUCC(ret)) { LOG_TRACE("succeed to get bushy infos", K(bushy_tree_infos_)); } return ret; } int ObLogPlan::init_bushy_tree_info_from_joined_tables(TableItem* table) { int ret = OB_SUCCESS; if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (!table->is_joined_table()) { // do nothing } else { JoinedTable* joined_table = static_cast(table); if (OB_ISNULL(joined_table->left_table_) || OB_ISNULL(joined_table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (joined_table->left_table_->is_joined_table() && joined_table->right_table_->is_joined_table()) { ObRelIds table_ids; if (OB_FAIL(get_table_ids(table, table_ids))) { LOG_WARN("failed to get table ids", K(ret)); } else if (OB_FAIL(bushy_tree_infos_.push_back(table_ids))) { LOG_WARN("failed to push back table ids", K(ret)); } } if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(SMART_CALL(init_bushy_tree_info_from_joined_tables(joined_table->left_table_)))) { LOG_WARN("failed to init bushy tree infos", K(ret)); } else if (OB_FAIL(SMART_CALL(init_bushy_tree_info_from_joined_tables(joined_table->right_table_)))) { LOG_WARN("failed to init bushy tree infos", K(ret)); } } return ret; } int ObLogPlan::check_need_bushy_tree(common::ObIArray& join_rels, const int64_t level, bool& need) { int ret = OB_SUCCESS; need = false; if (level >= join_rels.count()) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("Index out of range", K(ret), K(join_rels.count()), K(level)); } else if (join_rels.at(level).empty()) { need = true; } for (int64_t i = 0; OB_SUCC(ret) && !need && i < bushy_tree_infos_.count(); ++i) { const ObRelIds& table_ids = bushy_tree_infos_.at(i); if (table_ids.num_members() != level + 1) { // do nothing } else { bool has_generated = false; int64_t N = join_rels.at(level).count(); for (int64_t j = 0; OB_SUCC(ret) && !has_generated && j < N; ++j) { ObJoinOrder* join_order = join_rels.at(level).at(j); if (OB_ISNULL(join_order)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join order", K(ret)); } else if (table_ids.is_subset(join_order->get_tables())) { has_generated = true; } } if (OB_SUCC(ret)) { need = !has_generated; } } } return ret; } int ObLogPlan::generate_join_levels_with_DP(common::ObIArray& join_rels, const int64_t join_level) { int ret = OB_SUCCESS; if (!leading_tables_.is_empty() && OB_FAIL(inner_generate_join_levels_with_DP(join_rels, join_level, false))) { LOG_WARN("failed to generate join levels with hint", K(ret)); } else if (1 == join_rels.at(join_level - 1).count()) { } else if (OB_FAIL(inner_generate_join_levels_with_DP(join_rels, join_level, true))) { LOG_WARN("failed to generate join level in generate_join_orders", K(ret), K(join_level)); } return ret; } int ObLogPlan::generate_join_levels_with_linear( common::ObIArray& join_rels, const ObIArray& table_items, const int64_t join_level) { int ret = OB_SUCCESS; if (OB_FAIL(preprocess_for_linear(table_items, join_rels))) { LOG_WARN("failed to preprocess for linear", K(ret)); } else if (OB_FAIL(inner_generate_join_levels_with_linear(join_rels, join_level))) { LOG_WARN("failed to generate join level in generate_join_orders", K(ret), K(join_level)); } return ret; } int ObLogPlan::inner_generate_join_levels_with_DP( common::ObIArray& join_rels, const int64_t join_level, bool ignore_hint) { int ret = OB_SUCCESS; bool abort = false; for (uint32_t base_level = 1; OB_SUCC(ret) && !abort && base_level < join_level; ++base_level) { LOG_TRACE("start to generate one level join order with DP", K(base_level)); for (uint32_t i = 0; OB_SUCC(ret) && !abort && i <= base_level / 2; ++i) { uint32_t right_level = i; uint32_t left_level = base_level - 1 - right_level; if (right_level > left_level) { // do nothing } else if (OB_FAIL(THIS_WORKER.check_status())) { LOG_WARN("check status fail", K(ret)); } else if (OB_FAIL(generate_single_join_level_with_DP( join_rels, left_level, right_level, base_level, ignore_hint, abort))) { LOG_WARN("failed to generate join order with dynamic program", K(ret)); } bool need_bushy = false; if (OB_FAIL(ret) || right_level > left_level) { } else if (abort) { LOG_TRACE("abort generate join order", K(ret)); } else if (join_rels.count() <= base_level) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("Index out of range", K(ret), K(join_rels.count()), K(base_level)); } else if (OB_FAIL(check_need_bushy_tree(join_rels, base_level, need_bushy))) { LOG_WARN("failed to check need bushy tree", K(ret)); } else if (need_bushy) { LOG_TRACE("no valid ZigZag tree or leading hint required, we will enumerate bushy tree"); } else { LOG_TRACE("there is valid ZigZag tree, we will not enumerate bushy tree"); break; } } LOG_TRACE("succeed to generate on level join order", K(base_level), K(join_rels.at(base_level).count())); } return ret; } int ObLogPlan::inner_generate_join_levels_with_linear( common::ObIArray& join_rels, const int64_t join_level) { int ret = OB_SUCCESS; for (uint32_t base_level = 1; OB_SUCC(ret) && base_level < join_level; ++base_level) { LOG_TRACE("start to generate one level join order with linear", K(base_level)); for (uint32_t i = 0; OB_SUCC(ret) && i <= base_level / 2; ++i) { uint32_t right_level = i; uint32_t left_level = base_level - 1 - right_level; if (right_level > left_level) { // do nothing } else if (OB_FAIL(THIS_WORKER.check_status())) { LOG_WARN("check status fail", K(ret)); } else if (OB_FAIL(generate_single_join_level_with_linear(join_rels, left_level, right_level, base_level))) { LOG_WARN("failed to generate join order with linear", K(ret)); } bool need_bushy = false; if (OB_FAIL(ret) || right_level > left_level) { } else if (join_rels.count() <= base_level) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("Index out of range", K(ret), K(join_rels.count()), K(base_level)); } else if (OB_FAIL(check_need_bushy_tree(join_rels, base_level, need_bushy))) { LOG_WARN("failed to check need bushy tree", K(ret)); } else if (need_bushy) { LOG_TRACE("no valid ZigZag tree or leading hint required, we will enumerate bushy tree"); } else { LOG_TRACE("there is valid ZigZag tree, we will not enumerate bushy tree"); break; } } LOG_TRACE("succeed to generate on level join order", K(base_level), K(join_rels.at(base_level).count())); } return ret; } int ObLogPlan::preprocess_for_linear(const ObIArray& table_items, ObIArray& join_rels) { int ret = OB_SUCCESS; if (join_rels.empty()) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("join_rels is empty", K(ret), K(join_rels.count())); } for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { ObJoinOrder* join_tree = NULL; if (OB_FAIL(generate_join_order_with_table_tree(join_rels, table_items.at(i), join_tree))) { LOG_WARN("failed to generate join order", K(ret)); } } return ret; } int ObLogPlan::generate_join_order_with_table_tree( ObIArray& join_rels, TableItem* table, ObJoinOrder*& join_tree) { int ret = OB_SUCCESS; JoinedTable* joined_table = NULL; ObJoinOrder* left_tree = NULL; ObJoinOrder* right_tree = NULL; join_tree = NULL; if (OB_ISNULL(table) || join_rels.empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else if (!table->is_joined_table()) { // find base join rels ObIArray& single_join_rels = join_rels.at(0); for (int64_t i = 0; OB_SUCC(ret) && NULL == join_tree && i < single_join_rels.count(); ++i) { ObJoinOrder* base_rel = single_join_rels.at(i); if (OB_ISNULL(base_rel)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null base rel", K(ret)); } else if (table->table_id_ == base_rel->get_table_id()) { join_tree = base_rel; } } } else if (OB_FALSE_IT(joined_table = static_cast(table))) { } else if (OB_FAIL( SMART_CALL(generate_join_order_with_table_tree(join_rels, joined_table->left_table_, left_tree)))) { LOG_WARN("failed to generate join order", K(ret)); } else if (OB_FAIL( SMART_CALL(generate_join_order_with_table_tree(join_rels, joined_table->right_table_, right_tree)))) { LOG_WARN("failed to generate join order", K(ret)); } else if (OB_ISNULL(left_tree) || OB_ISNULL(right_tree)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join order", K(ret)); } else { bool is_valid_join = false; ObRelIds cur_relids; int64_t level = left_tree->get_tables().num_members() + right_tree->get_tables().num_members() - 1; if (OB_FAIL(inner_generate_join_order(join_rels, left_tree, right_tree, level, false, false, is_valid_join))) { LOG_WARN("failed to generated join order", K(ret)); } else if (OB_FAIL(cur_relids.add_members(left_tree->get_tables()))) { LOG_WARN("fail to add left tree' table ids", K(ret)); } else if (OB_FAIL(cur_relids.add_members(right_tree->get_tables()))) { LOG_WARN("fail to add right tree' table ids", K(ret)); } else if (OB_FAIL(find_join_rel(join_rels.at(level), cur_relids, join_tree))) { LOG_WARN("find_join_rel fails", K(ret), K(level)); } else if (OB_ISNULL(join_tree)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join order", K(ret)); } } return ret; } int ObLogPlan::generate_single_join_level_with_DP(ObIArray& join_rels, uint32_t left_level, uint32_t right_level, uint32_t level, bool ignore_hint, bool& abort) { int ret = OB_SUCCESS; abort = false; if (join_rels.empty() || left_level >= join_rels.count() || right_level >= join_rels.count() || level >= join_rels.count()) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("Index out of range", K(ret), K(join_rels.count()), K(left_level), K(right_level), K(level)); } else { ObIArray& left_rels = join_rels.at(left_level); ObIArray& right_rels = join_rels.at(right_level); ObJoinOrder* left_tree = NULL; ObJoinOrder* right_tree = NULL; for (int64_t i = 0; OB_SUCC(ret) && !abort && i < left_rels.count(); ++i) { left_tree = left_rels.at(i); if (OB_ISNULL(left_tree)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join tree", K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && !abort && j < right_rels.count(); ++j) { right_tree = right_rels.at(j); bool match_hint = false; bool is_legal = true; bool is_strict_order = true; bool is_valid_join = false; if (OB_ISNULL(right_tree)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join tree", K(ret)); } else if (!ignore_hint && OB_FAIL(check_join_hint( left_tree->get_tables(), right_tree->get_tables(), match_hint, is_legal, is_strict_order))) { LOG_WARN("failed to check join hint", K(ret)); } else if (!is_legal) { LOG_TRACE("join order conflict with leading hint", K(left_tree->get_tables()), K(right_tree->get_tables())); } else if (OB_FAIL(inner_generate_join_order(join_rels, is_strict_order ? left_tree : right_tree, is_strict_order ? right_tree : left_tree, level, match_hint, !match_hint, is_valid_join))) { LOG_WARN("failed to generate join order", K(level), K(ret)); } else if (match_hint && !leading_tables_.is_subset(left_tree->get_tables()) && !is_valid_join) { abort = true; } else { LOG_TRACE("succeed to check join order", K(left_tree->get_tables()), K(right_tree->get_tables()), K(is_valid_join)); } } } } } return ret; } int ObLogPlan::generate_single_join_level_with_linear( ObIArray& join_rels, uint32_t left_level, uint32_t right_level, uint32_t level) { int ret = OB_SUCCESS; if (join_rels.empty() || left_level >= join_rels.count() || right_level >= join_rels.count() || level >= join_rels.count()) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("Index out of range", K(ret), K(join_rels.count()), K(left_level), K(right_level), K(level)); } else { ObIArray& left_rels = join_rels.at(left_level); ObIArray& right_rels = join_rels.at(right_level); ObJoinOrder* left_tree = NULL; ObJoinOrder* right_tree = NULL; if (OB_FAIL(sort_cur_rels(left_rels))) { LOG_WARN("failed to sort rels", K(left_rels.count()), K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < left_rels.count() && join_rels.at(level).empty(); ++i) { left_tree = left_rels.at(i); for (int64_t j = 0; OB_SUCC(ret) && j < right_rels.count(); ++j) { right_tree = right_rels.at(j); bool is_valid_join = false; if (OB_FAIL(inner_generate_join_order(join_rels, left_tree, right_tree, level, false, true, is_valid_join))) { LOG_WARN("failed to generate join order", K(level), K(ret)); } else { LOG_TRACE( "succeed to check join order", K(left_tree->get_tables()), K(right_tree->get_tables()), K(is_valid_join)); } } } for (int64_t i = 0; OB_SUCC(ret) && i < left_rels.count() && join_rels.at(level).empty(); ++i) { left_tree = left_rels.at(i); for (int64_t j = 0; OB_SUCC(ret) && j < right_rels.count(); ++j) { right_tree = right_rels.at(j); bool is_valid_join = false; if (OB_FAIL(inner_generate_join_order(join_rels, left_tree, right_tree, level, false, false, is_valid_join))) { LOG_WARN("failed to generate join order", K(level), K(ret)); } else { LOG_TRACE( "succeed to check join order", K(left_tree->get_tables()), K(right_tree->get_tables()), K(is_valid_join)); } } } } return ret; } int ObLogPlan::inner_generate_join_order(ObIArray& join_rels, ObJoinOrder* left_tree, ObJoinOrder* right_tree, uint32_t level, bool hint_force_order, bool delay_cross_product, bool& is_valid_join) { int ret = OB_SUCCESS; is_valid_join = false; if (join_rels.empty() || level >= join_rels.count() || OB_ISNULL(left_tree) || OB_ISNULL(right_tree)) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("Index out of range", K(ret), K(join_rels.count()), K(left_tree), K(right_tree), K(level)); } else { ObSEArray valid_detectors; ObRelIds cur_relids; JoinInfo join_info; ObJoinOrder* join_tree = NULL; bool is_strict_order = true; if (left_tree->get_tables().overlap(right_tree->get_tables())) { } else if (OB_FAIL( choose_join_info(left_tree, right_tree, valid_detectors, delay_cross_product, is_strict_order))) { LOG_WARN("failed to choose join info", K(ret)); } else if (valid_detectors.empty()) { LOG_TRACE("there is no valid join info for ", K(left_tree->get_tables()), K(right_tree->get_tables())); } else if (OB_FAIL(cur_relids.add_members(left_tree->get_tables()))) { LOG_WARN("fail to add left tree' table ids", K(ret)); } else if (OB_FAIL(cur_relids.add_members(right_tree->get_tables()))) { LOG_WARN("fail to add right tree' table ids", K(ret)); } else if (OB_FAIL(find_join_rel(join_rels.at(level), cur_relids, join_tree))) { LOG_WARN("find_join_rel fails", K(ret), K(level)); } else if (OB_FAIL(merge_join_info(valid_detectors, join_info))) { LOG_WARN("failed to merge join info", K(ret)); } else if (NULL != join_tree && level <= 1 && !hint_force_order) { is_valid_join = true; } else { if (!is_strict_order) { if (!hint_force_order) { std::swap(left_tree, right_tree); } else { join_info.join_type_ = get_opposite_join_type(join_info.join_type_); } } if (NULL == join_tree) { if (OB_ISNULL(join_tree = create_join_order(JOIN))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to create join tree", K(ret)); } else if (OB_FAIL(join_tree->init_join_order(left_tree, right_tree, &join_info))) { LOG_WARN("failed to init join order", K(ret)); } else if (OB_FAIL(join_rels.at(level).push_back(join_tree))) { LOG_WARN("failed to push back join order", K(ret)); } } if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(join_tree->merge_conflict_detectors(left_tree, right_tree, valid_detectors))) { LOG_WARN("failed to merge conflict detectors", K(ret)); } else if (OB_FAIL(join_tree->generate_join_paths(left_tree, right_tree, &join_info, hint_force_order))) { LOG_WARN("failed to generate join paths for left_tree", K(level), K(ret)); } else { is_valid_join = true; LOG_TRACE("succeed to generate join order for ", K(left_tree->get_tables()), K(right_tree->get_tables()), K(is_strict_order), K(join_info)); } } } return ret; } int ObLogPlan::is_detector_used( ObJoinOrder* left_tree, ObJoinOrder* right_tree, ConflictDetector* detector, bool& is_used) { int ret = OB_SUCCESS; is_used = false; if (OB_ISNULL(left_tree) || OB_ISNULL(right_tree) || OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else if (INNER_JOIN == detector->join_info_.join_type_ && detector->join_info_.where_condition_.empty()) { } else if (ObOptimizerUtil::find_item(left_tree->get_conflict_detectors(), detector)) { is_used = true; } else if (ObOptimizerUtil::find_item(right_tree->get_conflict_detectors(), detector)) { is_used = true; } return ret; } int ObLogPlan::choose_join_info(ObJoinOrder* left_tree, ObJoinOrder* right_tree, ObIArray& valid_detectors, bool delay_cross_product, bool& is_strict_order) { int ret = OB_SUCCESS; bool is_legal = false; if (OB_ISNULL(left_tree) || OB_ISNULL(right_tree)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect empty conflict detectors", K(ret)); } is_strict_order = true; for (int64_t i = 0; OB_SUCC(ret) && i < conflict_detectors_.count(); ++i) { ConflictDetector* detector = conflict_detectors_.at(i); bool is_used = false; if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("conflict detector is null", K(ret)); } else if (OB_FAIL(is_detector_used(left_tree, right_tree, detector, is_used))) { LOG_WARN("failed to check detector is used", K(ret)); } else if (is_used) { // do nothing } else if (OB_FAIL(check_join_legal( left_tree->get_tables(), right_tree->get_tables(), detector, delay_cross_product, is_legal))) { LOG_WARN("failed to check join legal", K(ret)); } else if (!is_legal) { LOG_TRACE("left tree join right tree is not legal", K(left_tree->get_tables()), K(right_tree->get_tables()), K(*detector)); if (OB_FAIL(check_join_legal( right_tree->get_tables(), left_tree->get_tables(), detector, delay_cross_product, is_legal))) { LOG_WARN("failed to check join legal", K(ret)); } else if (!is_legal) { LOG_TRACE("right tree join left tree is not legal", K(right_tree->get_tables()), K(left_tree->get_tables()), K(*detector)); } else if (OB_FAIL(valid_detectors.push_back(detector))) { LOG_WARN("failed to push back detector", K(ret)); } else { is_strict_order = false; LOG_TRACE("succeed to find join info for ", K(left_tree->get_tables()), K(right_tree->get_tables()), K(left_tree->get_conflict_detectors()), K(right_tree->get_conflict_detectors()), K(*detector)); } } else if (OB_FAIL(valid_detectors.push_back(detector))) { LOG_WARN("failed to push back detector", K(ret)); } else { LOG_TRACE("succeed to find join info for ", K(left_tree->get_tables()), K(right_tree->get_tables()), K(left_tree->get_conflict_detectors()), K(right_tree->get_conflict_detectors()), K(*detector)); } } return ret; } int ObLogPlan::check_join_info( const ObIArray& valid_detectors, ObJoinType& join_type, bool& is_valid) { int ret = OB_SUCCESS; ConflictDetector* detector = NULL; bool has_non_inner_join = false; is_valid = true; join_type = INNER_JOIN; if (valid_detectors.empty()) { is_valid = false; } for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < valid_detectors.count(); ++i) { detector = valid_detectors.at(i); if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detectors", K(ret)); } else if (INNER_JOIN == detector->join_info_.join_type_) { // do nothing } else if (has_non_inner_join) { is_valid = false; } else { has_non_inner_join = true; join_type = detector->join_info_.join_type_; } } return ret; } int ObLogPlan::merge_join_info(const ObIArray& valid_detectors, JoinInfo& join_info) { int ret = OB_SUCCESS; bool is_valid = false; if (OB_FAIL(check_join_info(valid_detectors, join_info.join_type_, is_valid))) { LOG_WARN("failed to check join info", K(ret)); } else if (!is_valid) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect different join info", K(valid_detectors), K(ret)); } else { ConflictDetector* detector = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < valid_detectors.count(); ++i) { detector = valid_detectors.at(i); if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detectors", K(ret)); } else if (OB_FAIL(join_info.table_set_.add_members(detector->join_info_.table_set_))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(append_array_no_dup(join_info.where_condition_, detector->join_info_.where_condition_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(append_array_no_dup(join_info.on_condition_, detector->join_info_.on_condition_))) { LOG_WARN("failed to append exprs", K(ret)); } } if (OB_SUCC(ret)) { if (INNER_JOIN == join_info.join_type_) { for (int64_t i = 0; OB_SUCC(ret) && i < join_info.where_condition_.count(); ++i) { ObRawExpr* qual = join_info.where_condition_.at(i); if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join qual", K(ret)); } else if (!qual->has_flag(IS_JOIN_COND)) { // do nothing } else if (OB_FAIL(join_info.equal_join_condition_.push_back(qual))) { LOG_WARN("failed to push back join qual", K(ret)); } } } else { for (int64_t i = 0; OB_SUCC(ret) && i < join_info.on_condition_.count(); ++i) { ObRawExpr* qual = join_info.on_condition_.at(i); if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null join qual", K(ret)); } else if (!qual->has_flag(IS_JOIN_COND)) { // do nothing } else if (OB_FAIL(join_info.equal_join_condition_.push_back(qual))) { LOG_WARN("failed to push back join qual", K(ret)); } } } } } return ret; } int ObLogPlan::distribute_onetime_subquery(ObRawExpr*& qual, bool& can_distribute) { int ret = OB_SUCCESS; ObDMLStmt* stmt = get_stmt(); can_distribute = false; ObRawExpr* new_qual = NULL; if (OB_ISNULL(qual) || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(qual), K(stmt)); } else if (!qual->has_flag(CNT_SUB_QUERY)) { can_distribute = true; } else if (OB_FAIL(check_qual_can_distribute(qual, stmt, can_distribute))) { LOG_WARN("failed to check subquery can pushdown", K(ret)); } else if (!can_distribute) { // do nothing } else if (qual->get_relation_ids().is_empty()) { can_distribute = false; } else if (OB_FAIL(extract_params_for_subplan_filter(qual, new_qual))) { LOG_WARN("failed to extract params for subplan filter", K(ret)); } else if (OB_ISNULL(new_qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (OB_FAIL(new_qual->extract_info())) { LOG_WARN("failed extract info", K(ret)); } else if (OB_FAIL(add_subquery_filter(new_qual))) { LOG_WARN("failed to add expr", K(ret)); } else { qual = new_qual; } return ret; } int ObLogPlan::distribute_subquery_qual(ObRawExpr*& qual, bool& can_distribute) { int ret = OB_SUCCESS; bool is_semi_subquery = false; can_distribute = false; if (OB_ISNULL(qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(qual)); } else if (!qual->has_flag(CNT_SUB_QUERY)) { can_distribute = true; } else if (OB_FAIL(distribute_onetime_subquery(qual, can_distribute))) { LOG_WARN("failed to check qual can pushdown", K(ret)); } else if (can_distribute) { // do nothing } else if (OB_FAIL(add_subquery_filter(qual))) { LOG_WARN("failed to add expr", K(ret)); } else { LOG_TRACE("succeed to distribute subquery qual", K(is_semi_subquery), K(can_distribute)); } return ret; } int ObLogPlan::check_qual_can_distribute(ObRawExpr* qual, ObDMLStmt* stmt, bool& can_distribute) { int ret = OB_SUCCESS; bool is_onetime_expr = false; can_distribute = true; if (OB_ISNULL(qual) || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(qual), K(stmt), K(ret)); } else if (!qual->has_flag(CNT_SUB_QUERY)) { // do nothing } else if (OB_FAIL(ObOptimizerUtil::check_is_onetime_expr(get_onetime_exprs(), qual, stmt, is_onetime_expr))) { LOG_WARN("failed to check is onetime expr", K(ret)); } else if (is_onetime_expr) { // do nothing } else if (!is_onetime_expr && qual->has_flag(IS_SUB_QUERY)) { can_distribute = false; } else { for (int64_t i = 0; OB_SUCC(ret) && can_distribute && i < qual->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(check_qual_can_distribute(qual->get_param_expr(i), stmt, can_distribute)))) { LOG_WARN("failed to check qual can push down", K(ret)); } } } return ret; } int ObLogPlan::extract_params_for_subplan_filter(ObRawExpr* expr, ObRawExpr*& new_expr) { int ret = OB_SUCCESS; new_expr = expr; ObDMLStmt* stmt = NULL; ObOptimizerContext* opt_ctx = NULL; bool is_onetime_expr = false; if (OB_ISNULL(expr) || OB_ISNULL(stmt = get_stmt()) || OB_ISNULL(opt_ctx = &get_optimizer_context())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(expr), K(stmt), K(opt_ctx), K(ret)); } else if (expr->has_flag(CNT_SUB_QUERY) && OB_FAIL(ObOptimizerUtil::check_is_onetime_expr(get_onetime_exprs(), expr, stmt, is_onetime_expr))) { LOG_WARN("failed to check is onetime expr", K(ret)); } else if (is_onetime_expr) { ObSQLSessionInfo* session_info = const_cast(opt_ctx->get_session_info()); int64_t param_num = ObOptimizerUtil::find_exec_param(get_onetime_exprs(), expr); if (param_num >= 0) { ObRawExpr* param_expr = ObOptimizerUtil::find_param_expr(stmt->get_exec_param_ref_exprs(), param_num); if (param_expr != NULL) { new_expr = param_expr; } } else { std::pair init_expr; if (OB_FAIL(ObRawExprUtils::create_exec_param_expr( stmt, opt_ctx->get_expr_factory(), new_expr, session_info, init_expr))) { LOG_WARN("create param for stmt error", K(ret)); } else if (OB_FAIL(onetime_exprs_.push_back(init_expr))) { LOG_WARN("push back error", K(ret)); } } } else if (expr->has_flag(CNT_SUB_QUERY)) { ObRawExpr::ExprClass expr_class = expr->get_expr_class(); switch (expr_class) { case ObRawExpr::EXPR_QUERY_REF: { break; } case ObRawExpr::EXPR_CASE_OPERATOR: { ObCaseOpRawExpr* case_expr = NULL; if (OB_FAIL(opt_ctx->get_expr_factory().create_raw_expr(expr->get_expr_type(), case_expr))) { LOG_WARN("create case operator expr failed", K(ret)); } else if (OB_ISNULL(new_expr = case_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("case_expr is null", K(case_expr)); } else { ret = case_expr->assign(static_cast(*expr)); if (OB_SUCC(ret)) { case_expr->clear_child(); if (OB_FAIL(extract_params_for_subplan_expr(new_expr, expr))) { LOG_WARN("failed to extract child expr info", K(ret), K(*new_expr)); } else { /*do nothing*/ } } } break; } case ObRawExpr::EXPR_AGGR: { ObAggFunRawExpr* aggr_expr = NULL; if (OB_FAIL(opt_ctx->get_expr_factory().create_raw_expr(expr->get_expr_type(), aggr_expr))) { LOG_WARN("create aggr expr failed", K(ret)); } else if (OB_ISNULL(new_expr = aggr_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("aggr_expr is null", K(aggr_expr)); } else { ret = aggr_expr->assign(static_cast(*expr)); if (OB_SUCC(ret)) { aggr_expr->clear_child(); if (OB_FAIL(extract_params_for_subplan_expr(new_expr, expr))) { LOG_WARN("failed to extract child expr info", K(ret), K(*new_expr)); } else { /*do nothing*/ } } } break; } case ObRawExpr::EXPR_SYS_FUNC: { ObSysFunRawExpr* func_expr = NULL; if (OB_FAIL(opt_ctx->get_expr_factory().create_raw_expr(expr->get_expr_type(), func_expr))) { LOG_WARN("create system function expr failed", K(ret)); } else if (OB_ISNULL(new_expr = func_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("func_expr is null", K(func_expr)); } else { ret = func_expr->assign(static_cast(*expr)); if (OB_SUCC(ret)) { func_expr->clear_child(); if (OB_FAIL(extract_params_for_subplan_expr(new_expr, expr))) { LOG_WARN("failed to extract child expr info", K(ret), K(*new_expr)); } else { /*do nothing*/ } } } break; } case ObRawExpr::EXPR_UDF: { ret = OB_NOT_SUPPORTED; break; } case ObRawExpr::EXPR_OPERATOR: { ObOpRawExpr* op_expr = NULL; if (OB_FAIL(opt_ctx->get_expr_factory().create_raw_expr(expr->get_expr_type(), op_expr))) { LOG_WARN("create operator expr failed", K(ret)); } else if (OB_ISNULL(new_expr = op_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("op_expr is null", K(op_expr)); } else { ret = op_expr->assign(static_cast(*expr)); if (OB_SUCC(ret)) { op_expr->clear_child(); if (OB_FAIL(extract_params_for_subplan_expr(new_expr, expr))) { LOG_WARN("failed to extract child expr info", K(ret), K(*new_expr)); } else { /*do nothing*/ } } } break; } case ObRawExpr::EXPR_INVALID_CLASS: default: ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid expr class", K(expr_class), K(ret)); // should not reach here break; } // switch case end } return ret; } int ObLogPlan::extract_params_for_subplan_expr(ObRawExpr*& new_expr, ObRawExpr* expr) { int ret = OB_SUCCESS; if (OB_ISNULL(new_expr) || OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(new_expr), K(expr), K(ret)); } else { int64_t count = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { ObRawExpr* expr_element = expr->get_param_expr(i); if (OB_ISNULL(expr_element)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null poiner passed in", K(i), K(expr_element), K(ret)); } else if (!expr_element->has_flag(CNT_SUB_QUERY)) { if (OB_FAIL(ObOptimizerUtil::add_parameterized_expr(new_expr, expr, expr_element, i))) { LOG_WARN("fail to push raw expr", K(ret), K(new_expr)); } else { /*do nothing*/ } } else { ObRawExpr* dest_element = NULL; // recursive to child expr extract params if (OB_FAIL(SMART_CALL(extract_params_for_subplan_filter(expr_element, dest_element)))) { LOG_WARN("failed to extract params", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::add_parameterized_expr(new_expr, expr, dest_element, i))) { LOG_WARN("fail to push raw expr", K(ret), K(new_expr)); } else { /*do nothing*/ } } } } return ret; } int ObLogPlan::try_split_or_qual(const ObRelIds& table_ids, ObOpRawExpr& or_qual, ObIArray& table_quals) { int ret = OB_SUCCESS; ObOpRawExpr* new_expr = NULL; if (OB_FAIL( ObOptimizerUtil::split_or_qual_on_table(get_stmt(), get_optimizer_context(), table_ids, or_qual, new_expr))) { LOG_WARN("failed to split or qual on table", K(ret)); } else if (NULL == new_expr) { /* do nothing */ } else if (new_expr->get_relation_ids().num_members() > 1) { // do nothing } else if (ObOptimizerUtil::find_equal_expr(table_quals, new_expr)) { /* do nothing */ } else if (OB_FAIL(table_quals.push_back(new_expr))) { LOG_WARN("failed to push back new expr", K(ret)); } return ret; } int ObLogPlan::generate_subplan(ObRawExpr*& expr) { int ret = OB_SUCCESS; ObArray query_refs; if (OB_ISNULL(expr) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(expr), K(get_stmt())); } else if (OB_FAIL(get_query_ref_in_expr_tree(expr, get_stmt()->get_current_level(), query_refs))) { LOG_WARN("get query reference in expr tree failed", K(ret)); } else { LOG_TRACE("number of subquery ref", K(query_refs.count()), K(get_stmt()->get_current_level())); } for (int64_t i = 0; OB_SUCC(ret) && i < query_refs.count(); ++i) { if (OB_FAIL(generate_subplan_for_query_ref(query_refs.at(i)))) { LOG_WARN("generate subplan for query ref failed", K(ret)); } else { LOG_TRACE("succeed to generate subplan for query ref", K(get_stmt()->get_current_level()), K(query_refs.at(i))); } } return ret; } int ObLogPlan::generate_subplan_for_query_ref(ObQueryRefRawExpr* query_ref) { int ret = OB_SUCCESS; // check if sub plan has been generated SubPlanInfo* subplan_info = NULL; ObOptimizerContext& opt_ctx = get_optimizer_context(); if (OB_FAIL(get_subplan(query_ref, subplan_info))) { LOG_WARN("get_subplan() fails", K(ret)); } else if (NULL == subplan_info && query_ref->is_ref_stmt()) { ObSelectStmt* subquery = query_ref->get_ref_stmt(); if (NULL != subquery) { ObArray> exec_params; ObLogPlan* logical_plan = NULL; if (OB_ISNULL(logical_plan = opt_ctx.get_log_plan_factory().create(opt_ctx, *subquery))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to create plan", K(ret), K(subquery->get_sql_stmt())); } else if (OB_FAIL(logical_plan->init_plan_info())) { LOG_WARN("failed to init equal sets", K(ret)); } else if (OB_FAIL( logical_plan->extract_params_for_subplan_in_stmt(get_stmt()->get_current_level(), exec_params))) { LOG_WARN("failed to extract params from subplan", K(ret)); } else if (OB_FAIL(static_cast(logical_plan)->generate_raw_plan())) { LOG_WARN("failed to optimize sub-select", K(ret)); } else { SubPlanInfo* info = static_cast(get_allocator().alloc(sizeof(SubPlanInfo))); bool has_ref_assign_user_var = false; if (OB_ISNULL(info)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc semi info", K(ret)); } else if (OB_FAIL(subquery->has_ref_assign_user_var(has_ref_assign_user_var))) { LOG_WARN("faield to check stmt has assignment ref user var", K(ret)); } else { bool is_initplan = exec_params.empty() && !has_ref_assign_user_var; info = new (info) SubPlanInfo(query_ref, logical_plan, is_initplan); if (OB_FAIL(info->add_sp_params(exec_params))) { LOG_WARN("failed to add sp params to SubPlanInfo", K(ret)); } else if (OB_FAIL(add_subplan(info))) { LOG_WARN("failed to add sp params to rel", K(ret)); } else { query_ref->set_ref_id(get_subplan_size() - 1); query_ref->set_ref_operator(logical_plan->get_plan_root()); logical_plan->set_query_ref(query_ref); LOG_TRACE("succ to generate logical plan of sub-select"); } } if (OB_FAIL(ret) && NULL != info) { info->subplan_ = NULL; // we leave logical plan to be freed later info->~SubPlanInfo(); info = NULL; } else { /* Do nothing */ } } } else { /* Do nothing */ } } else { /* Do nothing */ } return ret; } int ObLogPlan::get_query_ref_in_expr_tree( ObRawExpr* expr, int32_t expr_level, ObIArray& query_refs) const { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("root is null"); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else if (!expr->has_flag(CNT_SUB_QUERY)) { /*do nothing if no subquery*/ } else if (expr->is_query_ref_expr()) { ObQueryRefRawExpr* query_ref = static_cast(expr); if (query_ref->get_ref_stmt() != NULL) { if (query_ref->get_expr_level() == expr_level) { if (OB_FAIL(query_refs.push_back(query_ref))) { LOG_WARN("add query ref to array failed", K(ret)); } else { LOG_TRACE("subquery belong to current level", K(query_ref), K(expr_level), K(*query_ref)); } } else { LOG_TRACE("subquery does not belong to current level", K(expr_level), K(query_ref->get_expr_level()), K(query_ref), K(*query_ref)); } } } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(get_query_ref_in_expr_tree(expr->get_param_expr(i), expr_level, query_refs)))) { LOG_WARN("get query reference in expr tree", K(ret)); } } } return ret; } int ObLogPlan::extract_params_for_subplan_in_stmt( const int32_t level, ObIArray>& exec_params) { int ret = OB_SUCCESS; ret = resolve_unsolvable_exprs(level, get_stmt(), exec_params); return ret; } int ObLogPlan::resolve_unsolvable_exprs( const int32_t level, ObDMLStmt* stmt, ObIArray>& params) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(stmt)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else { ObArray child_stmts; if (OB_FAIL(extract_stmt_params(stmt, level, params))) { LOG_WARN("fail to extract param from raw expr", K(ret)); } else if (OB_FAIL(stmt->get_child_stmts(child_stmts))) { LOG_WARN("get child stmt failed", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) { if (OB_FAIL(SMART_CALL(resolve_unsolvable_exprs(level, child_stmts.at(i), params)))) { LOG_WARN("fail to extract param from child stmts", K(ret)); } else { /* Do nothing */ } } } } return ret; } int ObLogPlan::extract_stmt_params( ObDMLStmt* stmt, const int32_t level, ObIArray>& params) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt)); } else if (stmt->get_current_level() <= level) { } else if (!stmt->is_select_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid SubQuery type", K(ret), K(stmt->get_stmt_type())); } else { ObSelectStmt* select_stmt = static_cast(stmt); // 1, Select Clause for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_select_item_size(); ++i) { if (OB_FAIL(extract_params(select_stmt->get_select_item(i).expr_, level, params))) { LOG_WARN("fail to resolve ref param for select clause", K(ret)); } else { /* Do nothing */ } } // 2.1, join table if (OB_SUCC(ret) && select_stmt->get_joined_tables().count() > 0) { for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_joined_tables().count(); ++i) { JoinedTable* join_table = select_stmt->get_joined_tables().at(i); if (OB_ISNULL(join_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("join_table is null", K(ret)); } else if (OB_FAIL(extract_join_table_condition_params(*join_table, level, params))) { LOG_WARN("extract join table condition params failed", K(ret)); } else { /* Do nothing */ } } } else { /* Do nothing */ } // 2.2, semi info if (OB_SUCC(ret) && select_stmt->get_semi_info_size() > 0) { ObIArray& semi_infos = select_stmt->get_semi_infos(); for (int64_t i = 0; OB_SUCC(ret) && i < semi_infos.count(); ++i) { if (OB_ISNULL(semi_infos.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(semi_infos)); } else if (OB_FAIL(extract_params(semi_infos.at(i)->semi_conditions_, level, params))) { LOG_WARN("extract semi condition params failed", K(ret)); } else { /* Do nothing */ } } } else { /* Do nothing */ } // 3, Where Clause if (OB_SUCC(ret)) { ret = extract_params(select_stmt->get_condition_exprs(), level, params); } else { /* Do nothing */ } // 4.1, Group Clause if (OB_SUCC(ret)) { ret = extract_params(select_stmt->get_group_exprs(), level, params); } // 4.2, Rollup Clause if (OB_SUCC(ret)) { ret = extract_params(select_stmt->get_rollup_exprs(), level, params); } // 4.3, Agg Clause aggregate expr for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_aggr_item_size(); ++i) { ObRawExpr* aggr_expr = select_stmt->get_aggr_item(i); ret = extract_params(aggr_expr, level, params); } // 5, Having Clause if (OB_SUCC(ret)) { ret = extract_params(select_stmt->get_having_exprs(), level, params); } else { /* Do nothing */ } // 6, Order Clause for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_order_item_size(); ++i) { ret = extract_params(select_stmt->get_order_item(i).expr_, level, params); } // 7, Limit Clause if (OB_SUCC(ret) && select_stmt->get_limit_expr()) { ret = extract_params(select_stmt->get_limit_expr(), level, params); } else { /* Do nothing */ } if (OB_SUCC(ret) && select_stmt->get_offset_expr()) { ret = extract_params(select_stmt->get_offset_expr(), level, params); } else { /* Do nothing */ } // 8, start with Clause if (OB_SUCC(ret)) { ret = extract_params(select_stmt->get_start_with_exprs(), level, params); } else { /* Do nothing */ } // 9. connect_by_prior exprs if (OB_SUCC(ret)) { ret = extract_params(select_stmt->get_connect_by_prior_exprs(), level, params); } else { /* Do nothing */ } if (OB_SUCC(ret)) { ret = extract_params(get_rownum_exprs(), level, params); } else { /* Do nothing */ } } return ret; } int ObLogPlan::extract_join_table_condition_params( JoinedTable& join_table, int32_t level, ObIArray>& params) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else if (OB_FAIL(extract_params(join_table.join_conditions_, level, params))) { LOG_WARN("extract join condition params failed", K(ret)); } else { if (NULL != join_table.left_table_ && TableItem::JOINED_TABLE == join_table.left_table_->type_) { JoinedTable& left_table = *static_cast(join_table.left_table_); if (OB_FAIL(SMART_CALL(extract_join_table_condition_params(left_table, level, params)))) { LOG_WARN("extract left join table condition param failed", K(ret)); } else { /* Do nothing */ } } else { /* Do nothing */ } if (OB_SUCC(ret) && NULL != join_table.right_table_ && TableItem::JOINED_TABLE == join_table.right_table_->type_) { JoinedTable& right_table = *static_cast(join_table.right_table_); if (OB_FAIL(SMART_CALL(extract_join_table_condition_params(right_table, level, params)))) { LOG_WARN("extract right join table condition param failed", K(ret)); } else { /* Do nothing */ } } else { /* Do nothing */ } } return ret; } int ObLogPlan::extract_params( common::ObIArray& exprs, const int32_t level, ObIArray>& params) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(extract_params(exprs.at(i), level, params))) { LOG_WARN("extract expr params failed", K(ret)); } else { /* Do nothing */ } } return ret; } int ObLogPlan::extract_params(ObRawExpr*& expr, const int32_t level, ObIArray>& params) { int ret = OB_SUCCESS; bool is_stack_overflow = false; bool can_produce = false; if (OB_ISNULL(expr) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), KP(expr), KP(get_stmt())); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else if (!expr->get_expr_levels().has_member(level) && !expr->is_set_op_expr()) { // do nothing } else if (OB_FAIL(can_produce_by_upper_stmt(expr, level, can_produce))) { LOG_WARN("failed to check expr can produce by stmt", K(ret)); } else if (can_produce) { if (OB_FAIL(extract_param_for_generalized_column(expr, params))) { LOG_WARN("extract param for generalized column failed", K(ret)); } } else { int64_t count = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_ISNULL(expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr->get_param_expr(i) returns null", K(ret), K(i)); } else if (OB_FAIL(SMART_CALL(extract_params(expr->get_param_expr(i), level, params)))) { LOG_WARN("fail to extract param from raw expr", K(ret), K(expr->get_param_expr(i))); } else { /* Do nothing */ } } } if (OB_SUCC(ret) && OB_FAIL(expr->extract_info())) { LOG_WARN("failed to extract expr info", K(ret)); } return ret; } int ObLogPlan::can_produce_by_upper_stmt(ObRawExpr* expr, const int32_t stmt_level, bool& can_produce) { int ret = OB_SUCCESS; can_produce = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->get_expr_level() == stmt_level || expr->is_const_expr()) { can_produce = true; } else if (ObOptimizerUtil::has_psedu_column(*expr) || ObOptimizerUtil::has_hierarchical_expr(*expr) || expr->is_set_op_expr() || expr->has_flag(IS_AGG) || expr->has_flag(IS_WINDOW_FUNC) || T_OP_ROW == expr->get_expr_type()) { can_produce = false; } else if (expr->get_param_count() > 0) { can_produce = true; int64_t count = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && can_produce && i < count; ++i) { if (OB_ISNULL(expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr->get_param_expr(i) returns null", K(ret), K(i)); } else if (OB_FAIL(SMART_CALL(can_produce_by_upper_stmt(expr->get_param_expr(i), stmt_level, can_produce)))) { LOG_WARN("fail to check expr can produce by stmt", K(ret), K(expr->get_param_expr(i))); } else { /* Do nothing */ } } } return ret; } int ObLogPlan::extract_param_for_generalized_column( ObRawExpr*& general_expr, ObIArray>& params) { int ret = OB_SUCCESS; if (OB_ISNULL(general_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("general expr is null"); } else { int64_t param_num = ObOptimizerUtil::find_exec_param(params, general_expr); if (param_num >= 0) { // stmt all_exprs contain all questionmark exprs ObRawExpr* param_expr = ObOptimizerUtil::find_param_expr(get_stmt()->get_exec_param_ref_exprs(), param_num); if (NULL != param_expr) { general_expr = param_expr; } else { /* Do nothing */ } } else { std::pair init_expr; if (OB_FAIL(ObRawExprUtils::create_exec_param_expr( get_stmt(), optimizer_context_.get_expr_factory(), general_expr, NULL, init_expr))) { LOG_WARN("create param for stmt error in extract_params_for_nl", K(ret)); } else if (OB_FAIL(params.push_back(init_expr))) { LOG_WARN("push back error", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObLogPlan::get_subplan(const ObRawExpr* expr, SubPlanInfo*& info) { int ret = OB_SUCCESS; info = NULL; bool found = false; for (int64_t i = 0; OB_SUCC(ret) && !found && i < get_subplans().count(); ++i) { if (OB_ISNULL(get_subplans().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_subplans().at(i) returns null", K(ret), K(i)); } else if (get_subplans().at(i)->init_expr_ == expr) { info = get_subplans().at(i); found = true; } else { /* Do nothing */ } } return ret; } int ObLogPlan::get_subplan_info(const ObRawExpr* expr, ObIArray& subplans) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid raw expr", K(ret), K(expr)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else { if (expr->is_query_ref_expr()) { SubPlanInfo* info = NULL; if (OB_FAIL(get_subplan(expr, info))) { LOG_WARN("get_subplan() fails", K(ret)); } else if (NULL != info) { ret = subplans.push_back(info); } else { /* Do nothing */ } } else if (expr->is_const_expr()) { if (expr->has_flag(IS_PARAM)) { int64_t param_value = static_cast(expr)->get_value().get_unknown(); ObRawExpr* init_expr = NULL; if (NULL == (init_expr = ObOptimizerUtil::find_exec_param(get_onetime_exprs(), param_value))) { } else { ret = SMART_CALL(get_subplan_info(init_expr, subplans)); } } else { /* Do nothing */ } } else { int64_t N = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { if (expr->get_param_expr(i)->has_flag(CNT_SUB_QUERY) || expr->get_param_expr(i)->has_flag(CNT_PARAM)) { ret = SMART_CALL(get_subplan_info(expr->get_param_expr(i), subplans)); } } } } return ret; } int ObLogPlan::find_base_rel(ObIArray& base_level, int64_t table_idx, ObJoinOrder*& base_rel) { int ret = OB_SUCCESS; ObJoinOrder* cur_rel = NULL; bool find = false; base_rel = NULL; for (int64_t i = 0; OB_SUCC(ret) && !find && i < base_level.count(); ++i) { if (OB_ISNULL(cur_rel = base_level.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(cur_rel)); } else if (cur_rel->get_tables().has_member(table_idx)) { find = true; base_rel = cur_rel; LOG_TRACE("succeed to find base rel", K(cur_rel->get_tables()), K(table_idx)); } else { /* do nothing */ } } return ret; } int ObLogPlan::find_join_rel(ObIArray& join_level, ObRelIds& relids, ObJoinOrder*& join_rel) { int ret = OB_SUCCESS; join_rel = NULL; ObJoinOrder* cur_rel = NULL; int32_t i = 0; bool found = false; for (i = 0; OB_SUCC(ret) && !found && i < join_level.count(); ++i) { cur_rel = join_level.at(i); if (OB_ISNULL(cur_rel)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cur_rel is null", K(ret), K(cur_rel)); } else if (cur_rel->get_tables().equal(relids)) { join_rel = cur_rel; LOG_TRACE("join rel is found"); found = true; } else { /* Do nothing */ } } return ret; } int ObLogPlan::sort_cur_rels(ObIArray& cur_rels) { int ret = OB_SUCCESS; int64_t N = cur_rels.count(); bool swap = true; for (int64_t i = 0; OB_SUCC(ret) && swap && i < N; ++i) { swap = false; for (int64_t j = 0; OB_SUCC(ret) && j < N - 1 - i; ++j) { if (OB_ISNULL(cur_rels.at(j)) || OB_ISNULL(cur_rels.at(j + 1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("rel is null", K(cur_rels), K(ret)); } else if (cur_rels.at(j)->get_output_rows() > cur_rels.at(j + 1)->get_output_rows()) { ObJoinOrder* tmp = cur_rels.at(j); cur_rels.at(j) = cur_rels.at(j + 1); cur_rels.at(j + 1) = tmp; swap = true; } else { /*do nothing*/ } } } return ret; } int ObLogPlan::allocate_function_table_path(AccessPath* ap, ObLogicalOperator*& out_access_path_op) { int ret = OB_SUCCESS; ObLogFunctionTable* op = NULL; if (OB_ISNULL(op = static_cast(get_log_op_factory().allocate(*this, LOG_FUNCTION_TABLE)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for ObLogFunctionTableScan failed", K(ret)); } else { const TableItem* table_item = NULL; CK(OB_NOT_NULL(get_stmt())); CK(OB_NOT_NULL(table_item = get_stmt()->get_table_item_by_id(ap->get_table_id()))); CK(OB_NOT_NULL(table_item)); CK(table_item->is_function_table()); CK(OB_NOT_NULL(table_item->function_table_expr_)); if (OB_SUCC(ret) && table_item->function_table_expr_->has_flag(CNT_SUB_QUERY)) { ObLogExprValues* values_op = NULL; if (OB_ISNULL(values_op = static_cast(log_op_factory_.allocate(*this, LOG_EXPR_VALUES)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("Allocate memory for ObLogInsertValues failed", K(ret)); } else { values_op->set_card(1); values_op->set_cost(ObOptEstCost::get_cost_params().CPU_TUPLE_COST); values_op->set_op_cost(values_op->get_cost()); values_op->set_est_sel_info(&get_est_sel_info()); values_op->set_need_columnlized(true); op->add_child(values_op); } ObArray subquery_exprs; OZ(subquery_exprs.push_back(table_item->function_table_expr_)); OZ(allocate_subplan_filter_as_below(subquery_exprs, op)); } if (OB_SUCC(ret)) { // compute property anyway OX(op->add_values_expr(table_item->function_table_expr_)); OX(op->set_table_id(ap->get_table_id())); OZ(append(op->get_filter_exprs(), ap->filter_)); if (OB_FAIL(op->compute_property(ap))) { LOG_WARN("failed to compute property", K(ret)); } } OX(out_access_path_op = op); } return ret; } int ObLogPlan::allocate_temp_table_path(AccessPath* ap, ObLogicalOperator*& out_access_path_op) { int ret = OB_SUCCESS; const TableItem* table_item = NULL; ObLogTempTableAccess* op = NULL; if (OB_ISNULL(ap) || OB_ISNULL(get_stmt()) || OB_ISNULL(table_item = get_stmt()->get_table_item_by_id(ap->get_table_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ap), K(get_stmt()), K(table_item), K(ret)); } else if (OB_ISNULL( op = static_cast(log_op_factory_.allocate(*this, LOG_TEMP_TABLE_ACCESS)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for ObLogFunctionTableScan failed", K(ret)); } else { op->set_table_id(ap->get_table_id()); op->set_ref_table_id(ap->get_ref_table_id()); op->get_table_name().assign_ptr(table_item->table_name_.ptr(), table_item->table_name_.length()); op->set_last_access(static_cast(get_stmt())->is_last_access()); if (OB_FAIL(op->get_filter_exprs().assign(ap->filter_))) { LOG_WARN("failed to assign filter exprs", K(ret)); } else if (OB_FAIL(op->compute_property(ap))) { LOG_WARN("failed to compute property", K(ret)); } else { out_access_path_op = op; } } return ret; } int ObLogPlan::allocate_access_path(AccessPath* ap, ObLogicalOperator*& out_access_path_op) { int ret = OB_SUCCESS; ObLogTableScan* scan = NULL; ObJoinOrder* join_order = NULL; ObSqlSchemaGuard* schema_guard = NULL; ObLogOpType op_type = LOG_TABLE_SCAN; const ObTableSchema* table_schema = NULL; const TableItem* table_item = NULL; if (OB_ISNULL(ap) || OB_ISNULL(get_stmt()) || OB_ISNULL(join_order = ap->parent_) || OB_ISNULL(ap->get_sharding_info()) || OB_ISNULL(schema_guard = get_optimizer_context().get_sql_schema_guard()) || OB_ISNULL(table_item = get_stmt()->get_table_item_by_id(ap->get_table_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ap), K(get_stmt()), K(schema_guard), K(join_order), K(table_item), K(ret)); } else if (OB_FAIL(schema_guard->get_table_schema(ap->table_id_, table_schema))) { LOG_WARN("fail to get_table_schema", K(ret)); } else if (!table_schema) { // do nothing } else if (share::schema::MATERIALIZED_VIEW == table_schema->get_table_type()) { op_type = LOG_MV_TABLE_SCAN; } else { /*do nothing*/ } if (OB_SUCC(ret)) { if (OB_UNLIKELY(NULL == (scan = static_cast(get_log_op_factory().allocate(*this, op_type))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to allocate table/index operator", K(ret)); } else if (OB_FAIL(scan->set_est_row_count_record(ap->est_records_))) { LOG_WARN("failed to set estimation info", K(ret)); } else if (OB_FAIL(append(scan->get_pushdown_filter_exprs(), ap->pushdown_filters_))) { LOG_WARN("failed to append pushdown filters", K(ret)); } else { bool is_index_back = ap->est_cost_info_.index_meta_info_.is_index_back_; ObSEArray global_index_filters; ObSEArray remaining_filters; scan->set_est_cost_info(&ap->get_cost_table_scan_info()); scan->set_table_id(ap->get_table_id()); scan->set_ref_table_id(ap->get_ref_table_id()); scan->set_index_table_id(ap->get_index_table_id()); scan->set_scan_direction(ap->order_direction_); scan->set_is_index_global(ap->is_global_index_); scan->set_is_global_index_back(is_index_back); scan->set_phy_location_type(ap->get_sharding_info()->get_location_type()); scan->set_table_opt_info(ap->table_opt_info_); if (is_index_back && ap->is_global_index_) { scan->set_index_back(false); } else { scan->set_index_back(is_index_back); } if (ap->is_global_index_) { if (OB_ISNULL(ap->table_partition_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { scan->set_table_partition_info(const_cast(ap->table_partition_info_)); } } else { scan->set_table_partition_info(&join_order->get_table_partition_info()); } scan->set_sample_info(ap->sample_info_); if (NULL != table_schema && table_schema->is_tmp_table()) { scan->set_session_id(table_schema->get_session_id()); } if (LOG_MV_TABLE_SCAN == op_type) { ObLogMVTableScan* mv_scan = static_cast(scan); const ObIArray& depend_tids = table_schema->get_depend_table_ids(); if (depend_tids.count() != 1) { ret = OB_NOT_SUPPORTED; LOG_WARN("depend_tid count is not 1", K(depend_tids.count())); } else { uint64_t depend_tid = depend_tids.at(0); mv_scan->set_depend_table_id(depend_tid); } } scan->set_table_row_count(ap->table_row_count_); scan->set_output_row_count(ap->output_row_count_); scan->set_phy_query_range_row_count(ap->phy_query_range_row_count_); scan->set_query_range_row_count(ap->query_range_row_count_); scan->set_index_back_row_count(ap->index_back_row_count_); scan->set_estimate_method(ap->est_cost_info_.row_est_method_); scan->set_is_fake_cte_table(ap->is_cte_path()); scan->set_pre_query_range(ap->pre_query_range_); if (OB_FAIL(scan->set_update_info())) { LOG_WARN("Fail to set_update_info", K(ret)); } else if (!ap->is_inner_path_ && OB_FAIL(scan->set_query_ranges(ap->get_cost_table_scan_info().ranges_))) { LOG_WARN("failed to set query ranges", K(ret)); } else if (OB_FAIL(scan->set_range_columns(ap->get_cost_table_scan_info().range_columns_))) { LOG_WARN("failed to set range column", K(ret)); } else { // set table name and index name scan->set_table_name(table_item->get_table_name()); scan->set_diverse_path_count(ap->parent_->get_diverse_path_count()); if (ap->get_index_table_id() != ap->get_ref_table_id()) { if (OB_FAIL(store_index_column_ids(*schema_guard, *scan, ap->get_index_table_id()))) { LOG_WARN("Failed to store index column id", K(ret)); } } } if (OB_SUCC(ret)) { if (ap->is_global_index_ && is_index_back && ap->est_cost_info_.table_filters_.count() > 0) { if (OB_FAIL(get_global_index_filters(*ap, global_index_filters, remaining_filters))) { LOG_WARN("failed to get global index filters", K(ret)); } else if (OB_FAIL(scan->set_filters(global_index_filters))) { LOG_WARN("failed to set filters", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(scan->set_filters(ap->filter_))) { LOG_WARN("failed to set filters", K(ret)); } else { /* do nothing */ } } } else { /*do nothing*/ } if (OB_SUCC(ret)) { // If assign partitions to scan, set partitions if (!ap->is_global_index_ && get_stmt()->get_stmt_hint().part_hints_.count() > 0) { scan->set_part_hint(get_stmt()->get_stmt_hint().get_part_hint(ap->get_table_id())); } else { /* Do nothing */ } } else { /* Do nothing */ } // Get ObRpcScanHint if (OB_SUCC(ret)) { const ObQueryHint& query_hint = get_optimizer_context().get_query_hint(); if (INVALID_CONSISTENCY != query_hint.read_consistency_) { scan->set_exist_hint(true); scan->get_hint().read_consistency_ = query_hint.read_consistency_; if (FROZEN == query_hint.read_consistency_) { scan->get_hint().frozen_version_ = query_hint.frozen_version_; } else { /* Do nothing */ } } else { /* Do nothing */ } // TODO in 052dev, else hint.read_consistency_ = table_schema->get_consistency_level() if (query_hint.force_refresh_lc_) { scan->set_exist_hint(true); scan->get_hint().force_refresh_lc_ = true; } } else { /* Do nothing */ } // compute equal set if (OB_SUCC(ret)) { if (OB_FAIL(scan->compute_property(ap))) { LOG_WARN("failed to compute property", K(ret)); } } // init part/subpart expr for query range prune if (OB_SUCC(ret)) { uint64_t table_id = scan->get_table_id(); uint64_t ref_table_id = scan->get_location_table_id(); share::schema::ObPartitionLevel part_level = share::schema::PARTITION_LEVEL_MAX; if (is_virtual_table(ref_table_id) || is_inner_table(ref_table_id) || is_cte_table(ref_table_id) || is_link_table_id(ref_table_id)) { // do nothing } else { ObRawExpr* part_expr = NULL; ObRawExpr* subpart_expr = NULL; OZ(scan->get_part_exprs(table_id, ref_table_id, part_level, part_expr, subpart_expr)); scan->set_part_expr(part_expr); scan->set_subpart_expr(subpart_expr); } } if (OB_SUCC(ret)) { if (ap->is_global_index_ && is_index_back) { ObLogicalOperator* temp_op = NULL; if (OB_FAIL(allocate_table_lookup( *ap, scan->get_table_name(), scan->get_index_name(), scan, remaining_filters, temp_op))) { LOG_WARN("failed to allocate table lookup operator", K(ret)); } else if (OB_ISNULL(temp_op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null operator", K(ret)); } else { out_access_path_op = temp_op; } } else { out_access_path_op = scan; } } } } return ret; } int ObLogPlan::get_global_index_filters( const AccessPath& ap, ObIArray& global_index_filters, ObIArray& remaining_filters) { int ret = OB_SUCCESS; ObSEArray filter_before_index_back; if (OB_FAIL(ObOptimizerUtil::check_filter_before_indexback(ap.index_id_, get_optimizer_context().get_schema_guard(), ap.filter_, false, OB_INVALID_ID, filter_before_index_back))) { LOG_WARN("Failed to check filter before index back", K(ret)); } else if (OB_UNLIKELY(filter_before_index_back.count() != ap.filter_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unequal array size", K(filter_before_index_back.count()), K(ap.filter_.count()), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < filter_before_index_back.count(); i++) { if (OB_ISNULL(ap.filter_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret)); } else if (filter_before_index_back.at(i) && !ap.filter_.at(i)->has_flag(CNT_SUB_QUERY)) { if (OB_FAIL(global_index_filters.push_back(ap.filter_.at(i)))) { LOG_WARN("failed to push back filter", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(remaining_filters.push_back(ap.filter_.at(i)))) { LOG_WARN("failed to push back filter", K(ret)); } else { /*do nothing*/ } } } } return ret; } int ObLogPlan::allocate_table_lookup(AccessPath& ap, ObString& table_name, ObString& index_name, ObLogicalOperator* child_node, ObIArray& filter_exprs, ObLogicalOperator*& output_op) { int ret = OB_SUCCESS; ObLogTableLookup* table_lookup = NULL; ObLogTableScan* table_scan = NULL; if (OB_ISNULL(child_node) || OB_ISNULL(get_stmt()) || OB_ISNULL(ap.parent_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(child_node), K(get_stmt()), K(ap.parent_), K(ret)); } else if (OB_UNLIKELY(!ap.is_global_index_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not global index", K(ap.is_global_index_), K(ret)); } else if (OB_UNLIKELY(!ap.est_cost_info_.index_meta_info_.is_index_back_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("is not index back", K(ret)); } else if (OB_ISNULL(table_lookup = static_cast( get_log_op_factory().allocate(*this, log_op_def::LOG_TABLE_LOOKUP)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate operator", K(ret)); } else if (OB_ISNULL(table_scan = static_cast( get_log_op_factory().allocate(*this, log_op_def::LOG_TABLE_SCAN)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate operator", K(ret)); } else { // set up table look up operator table_lookup->set_table_id(ap.table_id_); table_lookup->set_ref_table_id(ap.ref_table_id_); table_lookup->set_index_id(ap.index_id_); table_lookup->set_table_name(table_name); table_lookup->set_index_name(index_name); table_lookup->set_index_back_scan(table_scan); table_lookup->set_child(0, child_node); // set up index back op table_scan->set_table_id(ap.table_id_); table_scan->set_ref_table_id(ap.ref_table_id_); table_scan->set_index_table_id(ap.ref_table_id_); table_scan->set_is_index_global(false); table_scan->set_is_global_index_back(false); table_scan->set_index_back(false); table_scan->set_is_multi_part_table_scan(true); table_scan->set_table_partition_info(&ap.parent_->get_table_partition_info()); table_scan->set_scan_direction(ap.order_direction_); table_scan->set_update_info(); // set up filter if (OB_SUCC(ret)) { if (OB_FAIL(append(table_scan->get_filter_exprs(), filter_exprs))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(append(table_lookup->get_pushdown_filter_exprs(), ap.pushdown_filters_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(table_lookup->init_calc_part_id_expr())) { LOG_WARN("fail to init calc part id expr", K(ret)); } else { output_op = table_lookup; } } // compute property if (OB_SUCC(ret)) { if (OB_FAIL(output_op->compute_property(&ap))) { LOG_WARN("faield to compute property", K(ret)); } } } return ret; } int ObLogPlan::store_index_column_ids(ObSqlSchemaGuard& schema_guard, ObLogTableScan& scan, const int64_t index_id) { int ret = OB_SUCCESS; ObString index_name; const ObTableSchema* index_schema = NULL; if (OB_FAIL(schema_guard.get_table_schema(index_id, index_schema))) { ret = OB_SCHEMA_ERROR; LOG_WARN("set index name error", K(ret), K(index_id), K(index_schema)); } else { if (index_schema->is_materialized_view()) { index_name = index_schema->get_table_name_str(); } else { if (OB_FAIL(index_schema->get_index_name(index_name))) { LOG_WARN("fail to get index name", K(index_name), K(ret)); } } } if (OB_SUCC(ret)) { scan.set_index_name(index_name); for (ObTableSchema::const_column_iterator iter = index_schema->column_begin(); OB_SUCC(ret) && iter != index_schema->column_end(); ++iter) { if (OB_ISNULL(iter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("iter is null", K(ret), K(iter)); } else { const ObColumnSchemaV2* column_schema = *iter; if (OB_ISNULL(column_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column_schema is null", K(ret)); } else if (OB_FAIL(scan.add_idx_column_id(column_schema->get_column_id()))) { LOG_WARN("Fail to add column id to scan", K(ret)); } else { } // do nothing } } } return ret; } int ObLogPlan::allocate_join_path(JoinPath* join_path, ObLogicalOperator*& out_join_path_op) { int ret = OB_SUCCESS; ObJoinOrder* join_order = NULL; if (OB_ISNULL(join_path) || OB_ISNULL(join_order = join_path->parent_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(join_path), K(join_order)); } else { Path* left_path = const_cast(join_path->left_path_); Path* right_path = const_cast(join_path->right_path_); ObLogicalOperator* left_child = NULL; ObLogicalOperator* right_child = NULL; ObLogJoin* join_op = NULL; if (OB_ISNULL(left_path) || OB_ISNULL(right_path)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(left_path), K(right_path)); } else if (OB_FAIL(create_plan_tree_from_path(left_path, left_child)) || OB_FAIL(create_plan_tree_from_path(right_path, right_child))) { LOG_WARN("failed to create plan tree from path", K(ret)); } else if (OB_ISNULL(left_child) || OB_ISNULL(right_child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get expected null", K(left_child), K(right_child), K(ret)); } else if (join_path->left_need_sort_ && OB_FAIL(allocate_sort_as_top(left_child, join_path->left_expected_ordering_))) { LOG_WARN("failed to allocate sort operator", K(ret)); } else if (join_path->need_mat_ && (join_path->join_type_ != CONNECT_BY_JOIN) && OB_FAIL(allocate_material_as_top(right_child))) { LOG_WARN("failed to allocate material operator", K(ret)); } else if (join_path->right_need_sort_ && OB_FAIL(allocate_sort_as_top(right_child, join_path->right_expected_ordering_))) { LOG_WARN("failed to allocate sort operator", K(ret)); } else if (OB_ISNULL(join_op = static_cast(get_log_op_factory().allocate(*this, LOG_JOIN)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to allocate join_op operator", K(ret)); } else if (OB_ISNULL(join_op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(join_op)); } else { /* * Prefix sort check for outer merge join may have problems * for example, select * from t1 left join t2 on t1.a = t2.a where t2.a is null * in this case sort for t2 will use prefix sort since t2.a is null in our condition, but it is wrong * we should maintain this info when generating merge join */ if ((join_path->join_type_ == LEFT_OUTER_JOIN || join_path->join_type_ == FULL_OUTER_JOIN) && log_op_def::LOG_SORT == right_child->get_type()) { static_cast(right_child)->set_prefix_pos(0); } if ((join_path->join_type_ == RIGHT_OUTER_JOIN || join_path->join_type_ == FULL_OUTER_JOIN) && log_op_def::LOG_SORT == left_child->get_type()) { static_cast(left_child)->set_prefix_pos(0); } if (right_path->is_inner_path() && (LEFT_SEMI_JOIN == join_path->join_type_ || LEFT_ANTI_JOIN == join_path->join_type_)) { bool re_est = false; if (OB_FAIL(right_child->re_est_cost(join_op, 1, re_est))) { LOG_WARN("failed to re est cost", K(ret)); } } join_op->set_left_child(left_child); join_op->set_right_child(right_child); join_op->set_join_type(join_path->join_type_); join_op->set_join_algo(join_path->join_algo_); join_op->set_anti_or_semi_sel(join_order->get_anti_or_semi_match_sel()); if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(join_op->set_nl_params(right_path->nl_params_))) { LOG_WARN("set_nl_params fails", K(ret)); } else if (OB_FAIL(join_op->set_join_conditions(join_path->equal_join_condition_))) { LOG_WARN("append error in allocate_join_path", K(ret)); } else if (IS_OUTER_OR_CONNECT_BY_JOIN(join_path->join_type_)) { if (OB_FAIL(extract_level_pseudo_as_param(join_path->other_join_condition_, join_op->get_exec_params()))) { LOG_WARN("Failed to extract level pseudo as param", K(ret)); } else if (OB_FAIL(append(join_op->get_join_filters(), join_path->other_join_condition_))) { LOG_WARN("failed to allocate filter", K(ret)); } else if (OB_FAIL(append(join_op->get_filter_exprs(), join_path->filter_))) { LOG_WARN("failed to allocate filter", K(ret)); } else { LOG_TRACE("connect by join exec params", K(join_op->get_exec_params()), K(join_path->other_join_condition_), K(ret)); } } else if (OB_FAIL(append(join_op->get_join_filters(), join_path->other_join_condition_))) { LOG_WARN("failed to allocate filter", K(ret)); } else { /* do nothing */ } if (OB_SUCC(ret) && MERGE_JOIN == join_path->join_algo_) { if (OB_FAIL(join_op->set_left_expected_ordering(join_path->left_expected_ordering_))) { LOG_WARN("failed to set left_path expected ordering", K(ret)); } else if (OB_FAIL(join_op->set_right_expected_ordering(join_path->right_expected_ordering_))) { LOG_WARN("failed to set right expected ordering", K(ret)); } else if (OB_FAIL(join_op->set_merge_directions(join_path->merge_directions_))) { LOG_WARN("failed to set merge directions", K(ret)); } } if (OB_SUCC(ret) && CONNECT_BY_JOIN == join_path->join_type_) { ObJoinOrder* left_jo = NULL; ObJoinOrder* right_jo = NULL; ObSEArray column_exprs; if (OB_ISNULL(join_path->left_path_) || OB_ISNULL(join_path->right_path_) || OB_ISNULL(left_jo = join_path->left_path_->parent_) || OB_ISNULL(right_jo = join_path->right_path_->parent_) || OB_ISNULL(stmt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected NULL", K(ret)); } else if (OB_FAIL(stmt_->get_column_exprs(left_jo->get_table_id(), column_exprs))) { LOG_WARN("failed to get left table columns", K(ret)); } else if (OB_FAIL(stmt_->get_column_exprs(right_jo->get_table_id(), column_exprs))) { LOG_WARN("failed to get right table columns", K(ret)); } else if (OB_FAIL(join_op->set_connect_by_extra_exprs(column_exprs))) { LOG_WARN("failed to set connect by extra exprs", K(ret)); } else if (OB_FAIL(join_op->set_right_expected_ordering(join_path->right_expected_ordering_))) { LOG_WARN("failed to set right expected ordering", K(ret)); } LOG_TRACE("set connect by right expected ordering", K(join_path->right_expected_ordering_)); } if (OB_SUCC(ret)) { if (OB_FAIL(add_connect_by_prior_exprs(*join_op))) { LOG_WARN("fail to add connect_by prior_exprs", K(ret)); } } // compute property for join // (equal sets, unique sets, est_sel_info, cost, card, width) if (OB_SUCC(ret)) { if (OB_FAIL(join_op->compute_property(join_path))) { LOG_WARN("failed to compute property for join op", K(ret)); } else { out_join_path_op = join_op; } } } } return ret; } int ObLogPlan::add_connect_by_prior_exprs(ObLogJoin& log_join) { int ret = OB_SUCCESS; ObSelectStmt* select_stmt = NULL; if (CONNECT_BY_JOIN == log_join.get_join_type()) { if (OB_ISNULL(get_stmt()) || OB_UNLIKELY(false == get_stmt()->is_select_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid stmt", KPC(get_stmt()), K(ret)); } else { select_stmt = static_cast(get_stmt()); if (select_stmt->is_hierarchical_query()) { if (OB_FAIL(log_join.set_connect_by_prior_exprs(select_stmt->get_connect_by_prior_exprs()))) { LOG_WARN("fail to set connect by priro expr", K(ret)); } } LOG_TRACE("cby connect by prior", K(select_stmt->get_connect_by_prior_exprs()), K(select_stmt)); } } return ret; } int ObLogPlan::allocate_subquery_path(SubQueryPath* subpath, ObLogicalOperator*& out_subquery_path_op) { int ret = OB_SUCCESS; ObLogicalOperator* root = NULL; ObLogSubPlanScan* subplan_scan = NULL; if (OB_ISNULL(subpath) || OB_ISNULL(root = subpath->root_) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(subpath), K(root), K(get_stmt()), K(ret)); } else if (OB_ISNULL(subplan_scan = static_cast(get_log_op_factory().allocate(*this, LOG_SUBPLAN_SCAN)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to allocate subquery operator", K(ret)); } else { root->mark_is_plan_root(); subplan_scan->set_subquery_id(subpath->subquery_id_); subplan_scan->set_child(ObLogicalOperator::first_child, root); // set subquery name const TableItem* table_item = get_stmt()->get_table_item_by_id(subplan_scan->get_subquery_id()); if (OB_ISNULL(table_item)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(ret)); } else { subplan_scan->get_subquery_name().assign_ptr(table_item->table_name_.ptr(), table_item->table_name_.length()); if (OB_FAIL(append(subplan_scan->get_filter_exprs(), subpath->filter_))) { LOG_WARN("failed to append filters", K(ret)); } else if (OB_FAIL(append(subplan_scan->get_pushdown_filter_exprs(), subpath->pushdown_filters_))) { LOG_WARN("failed to append pushdown filters", K(ret)); } else if (OB_FAIL(subplan_scan->compute_property(subpath))) { LOG_WARN("failed to compute property", K(ret)); } else { out_subquery_path_op = subplan_scan; } } } return ret; } int ObLogPlan::allocate_material_as_top(ObLogicalOperator*& old_top) { int ret = OB_SUCCESS; ObLogMaterial* material_op = NULL; if (OB_ISNULL(old_top)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(old_top)); } else if (OB_ISNULL(material_op = static_cast(get_log_op_factory().allocate(*this, LOG_MATERIAL)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate material operator", K(ret)); } else { material_op->set_child(ObLogicalOperator::first_child, old_top); if (OB_FAIL(material_op->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { old_top = material_op; } } return ret; } int ObLogPlan::create_plan_tree_from_path(Path* path, ObLogicalOperator*& out_plan_tree) { int ret = OB_SUCCESS; if (OB_ISNULL(path) || OB_ISNULL(path->parent_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(path)); } else if (NULL != path->log_op_) { out_plan_tree = path->log_op_; } else { ObLogicalOperator* op = NULL; if (ACCESS == path->path_type_) { AccessPath* access_path = static_cast(path); if (access_path->is_function_table_path()) { if (OB_FAIL(allocate_function_table_path(access_path, op))) { LOG_WARN("failed to allocate function table path", K(ret)); } } else if (access_path->is_temp_table_path()) { if (OB_FAIL(allocate_temp_table_path(access_path, op))) { LOG_WARN("failed to allocate access path", K(ret)); } else { /* Do nothing */ } } else if (OB_FAIL(allocate_access_path(access_path, op))) { LOG_WARN("failed to allocate access path", K(ret)); } else { /* Do nothing */ } } else if (JOIN == path->path_type_) { JoinPath* join_path = static_cast(path); if (OB_FAIL(allocate_join_path(join_path, op))) { LOG_WARN("failed to allocate join path", K(ret)); } else { /* Do nothing */ } } else if (SUBQUERY == path->path_type_) { SubQueryPath* join_path = static_cast(path); if (OB_FAIL(allocate_subquery_path(join_path, op))) { LOG_WARN("failed to allocate subquery path", K(ret)); } else { /* Do nothing */ } } else if (FAKE_CTE_TABLE_ACCESS == path->path_type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("there is no access belong to FAKE_CTE_TABLE_ACCESS"); } else { /* Do nothing */ } if (OB_SUCC(ret)) { path->log_op_ = op; out_plan_tree = op; } } return ret; } int ObLogPlan::extract_onetime_subquery_exprs(ObRawExpr* expr, ObIArray& onetime_subquery_exprs) { int ret = OB_SUCCESS; ObArray params; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (!expr->has_flag(CNT_EXEC_PARAM)) { // do nothing } else if (OB_FAIL(ObOptimizerUtil::extract_params(expr, params))) { LOG_WARN("failed to extract_params", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < params.count(); ++j) { ObRawExpr* param = params.at(j); ObRawExpr* onetime_expr = NULL; if (OB_ISNULL(param) || !param->has_flag(IS_PARAM)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect param expr", K(param), K(ret)); } else if (OB_ISNULL(onetime_expr = ObOptimizerUtil::find_exec_param( onetime_exprs_, static_cast(param)->get_value().get_unknown()))) { } else if (!onetime_expr->has_flag(CNT_SUB_QUERY)) { // do nothing } else if (OB_FAIL(onetime_subquery_exprs.push_back(onetime_expr))) { LOG_WARN("failed to push back onetime expr", K(ret)); } } return ret; } int ObLogPlan::candi_init() { int ret = OB_SUCCESS; if (OB_ISNULL(join_order_) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(join_order_), K(get_stmt())); } else { int64_t total_usage = allocator_.total(); LOG_TRACE("memory usage after generating join order", K(total_usage)); ObLogicalOperator* root = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < join_order_->get_interesting_paths().count(); i++) { if (OB_ISNULL(join_order_->get_interesting_paths().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("join_order_->get_join_orders().at(i) is null", K(ret), K(i)); } else if (OB_FAIL(create_plan_tree_from_path(join_order_->get_interesting_paths().at(i), root))) { LOG_WARN("failed to create a path", K(ret)); } else if (OB_ISNULL(root)) { ret = OB_SQL_OPT_GEN_PLAN_FALIED; LOG_WARN("root is null", K(ret), K(root)); } else if (OB_FAIL(append(root->get_filter_exprs(), get_random_exprs()))) { LOG_WARN("failed to append random exprs to filter", K(ret)); } else if (OB_FAIL(append(root->get_filter_exprs(), get_user_var_filters()))) { LOG_WARN("failed to append user var to filter", K(ret)); } else if (OB_FAIL(append_array_no_dup(root->get_startup_exprs(), get_startup_filters()))) { LOG_WARN("failed to append startup filters", K(ret)); } else { CandidatePlan cp; cp.plan_tree_ = root; if (OB_FAIL(candidates_.candidate_plans_.push_back(cp))) { LOG_WARN("push back error", K(ret)); } else { // update the 'uninteresting' plan cost if (1 == candidates_.candidate_plans_.count() || cp.plan_tree_->get_cost() < candidates_.plain_plan_.first) { if (OB_ISNULL(cp.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cp.plan_tree_ is null", K(ret)); } else { // the cost of the candidate plan should be noted in the root operator candidates_.plain_plan_.first = cp.plan_tree_->get_cost(); // position in the candidate plan list candidates_.plain_plan_.second = candidates_.candidate_plans_.count() - 1; } } else { /* Do nothing */ } LOG_TRACE("add a candidate plan", "count", candidates_.candidate_plans_.count(), K(candidates_.plain_plan_.first), K(candidates_.plain_plan_.second)); int64_t plan_usage = allocator_.total() - total_usage; total_usage = allocator_.total(); LOG_TRACE("memory usage after generate a candidate", K(total_usage), K(plan_usage)); total_usage = allocator_.total(); } } } // for join orders end } return ret; } int ObLogPlan::get_order_by_exprs( ObLogicalOperator& root, ObIArray& order_by_exprs, ObIArray* directions) { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(get_stmt())); } else { for (int64_t i = 0; OB_SUCC(ret) && i < get_stmt()->get_order_item_size(); i++) { const OrderItem& order_item = get_stmt()->get_order_item(i); bool is_const = false; bool has_null_reject = false; if (OB_ISNULL(order_item.expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::is_const_expr(order_item.expr_, root.get_output_const_exprs(), is_const))) { LOG_WARN("check is const expr failed", K(ret)); } else if (is_const || (order_item.expr_->has_flag(CNT_COLUMN) && !order_item.expr_->has_flag(CNT_SUB_QUERY) && !order_item.expr_->get_expr_levels().has_member(get_stmt()->get_current_level()))) { } else if (OB_FAIL(order_by_exprs.push_back(order_item.expr_))) { LOG_WARN("failed to add order by expr", K(ret)); } else if (NULL != directions) { if (OB_FAIL(ObTransformUtils::has_null_reject_condition( get_stmt()->get_condition_exprs(), order_item.expr_, has_null_reject))) { LOG_WARN("failed to check null rejection", K(ret)); } else if (!has_null_reject) { ret = directions->push_back(order_item.order_type_); } else if (is_ascending_direction(order_item.order_type_)) { ret = directions->push_back(default_asc_direction()); } else { ret = directions->push_back(default_desc_direction()); } } } } return ret; } int ObLogPlan::make_order_items( const common::ObIArray& exprs, const ObIArray* dirs, ObIArray& items) { int ret = OB_SUCCESS; if (NULL == dirs) { if (OB_FAIL(make_order_items(exprs, items))) { LOG_WARN("Failed to make order items", K(ret)); } } else { if (OB_FAIL(make_order_items(exprs, *dirs, items))) { LOG_WARN("Failed to make order items", K(ret)); } } return ret; } int ObLogPlan::make_order_items(const common::ObIArray& exprs, common::ObIArray& items) { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(get_stmt())); } else { ObOrderDirection direction = default_asc_direction(); if (get_stmt()->get_order_item_size() > 0) { direction = get_stmt()->get_order_item(0).order_type_; } else { /* Do nothing */ } int64_t N = exprs.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { OrderItem key; key.expr_ = exprs.at(i); key.order_type_ = direction; ret = items.push_back(key); } } return ret; } int ObLogPlan::make_order_items( const ObIArray& exprs, const ObIArray& dirs, ObIArray& items) { int ret = OB_SUCCESS; if (OB_UNLIKELY(exprs.count() != dirs.count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr and dir count not match", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { OrderItem key; if (OB_ISNULL(exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(exprs.at(i))); } else if (exprs.at(i)->has_const_or_const_expr_flag()) { // do nothing } else { key.expr_ = exprs.at(i); key.order_type_ = dirs.at(i); if (OB_FAIL(items.push_back(key))) { LOG_WARN("Failed to push array", K(ret)); } } } } return ret; } int ObLogPlan::candi_allocate_sequence() { int ret = OB_SUCCESS; double min_cost = 0.0; int64_t min_idx = OB_INVALID_INDEX; for (int64_t idx = 0; OB_SUCC(ret) && idx < candidates_.candidate_plans_.count(); ++idx) { CandidatePlan& plain_plan = candidates_.candidate_plans_.at(idx); if (OB_FAIL(allocate_sequence_as_top(plain_plan.plan_tree_))) { LOG_WARN("fail alloc candi sequence op", K(idx), K(ret)); } else if (OB_ISNULL(plain_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null plan tree", K(ret)); } else if (plain_plan.plan_tree_->get_cost() < min_cost || OB_INVALID_INDEX == min_idx) { min_cost = plain_plan.plan_tree_->get_cost(); min_idx = idx; } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (OB_UNLIKELY(OB_INVALID_INDEX == min_idx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Min idx is invalid", K(ret), K(min_idx)); } else { candidates_.plain_plan_.first = min_cost; candidates_.plain_plan_.second = min_idx; } } return ret; } /* * for sequence, old_top may be null * |ID|OPERATOR |NAME|EST. ROWS|COST| * ------------------------------------- * |0 |INSERT | |0 |1 | * |1 | EXPRESSION | |1 |1 | * |2 | SEQUENCE | |1 |1 | */ int ObLogPlan::allocate_sequence_as_top(ObLogicalOperator*& old_top) { int ret = OB_SUCCESS; ObLogSequence* sequence = NULL; if (OB_ISNULL(get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Get unexpected null", K(ret), K(old_top), K(get_stmt())); } else if (OB_ISNULL(sequence = static_cast(get_log_op_factory().allocate(*this, LOG_SEQUENCE)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate sequence operator", K(ret)); } else if (OB_FAIL(append_array_no_dup(sequence->get_sequence_ids(), get_stmt()->get_nextval_sequence_ids()))) { LOG_WARN("failed to append array no dup", K(ret)); } else { if (NULL != old_top) { sequence->set_child(ObLogicalOperator::first_child, old_top); } if (OB_FAIL(sequence->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { old_top = sequence; } } return ret; } int ObLogPlan::candi_allocate_order_by(ObIArray& order_items) { int ret = OB_SUCCESS; ObSEArray order_by_exprs; ObSEArray directions; ObSEArray candi_subquery_exprs; ObSEArray candi_order_items; ObLogicalOperator* best_plan = NULL; if (OB_ISNULL(get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else if (OB_FAIL(get_stmt()->get_order_exprs(candi_subquery_exprs))) { LOG_WARN("failed to get exprs", K(ret)); } else if (OB_FAIL(candi_allocate_subplan_filter_for_exprs(candi_subquery_exprs))) { LOG_WARN("failed to allocate subplan filter for exprs", K(ret)); } else if (OB_FAIL(get_current_best_plan(best_plan))) { LOG_WARN("failed to get best plan", K(ret)); } else if (OB_ISNULL(best_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(get_order_by_exprs(*best_plan, order_by_exprs, &directions))) { LOG_WARN("failed to get order by columns", K(ret)); } else if (order_by_exprs.empty()) { /*do nothing*/ } else if (OB_FAIL(make_order_items(order_by_exprs, directions, candi_order_items))) { LOG_WARN("Failed to make order items", K(ret)); } else if (OB_FAIL(best_plan->simplify_ordered_exprs(candi_order_items, order_items))) { LOG_WARN("failed to simplify ordered exprs", K(ret)); } else if (order_items.empty()) { /*do nothing*/ } else { for (int64_t i = 0; OB_SUCC(ret) && i < candidates_.candidate_plans_.count(); i++) { bool need_sort = false; CandidatePlan& plain_plan = candidates_.candidate_plans_.at(i); if (OB_ISNULL(plain_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(plain_plan.plan_tree_->check_need_sort_above_node(order_items, need_sort))) { LOG_WARN("failed to check plan need sort for order by", K(ret)); } else if (!need_sort) { LOG_TRACE("no need to allocate sort for order-by", K(need_sort)); } else if (OB_FAIL(allocate_sort_as_top(plain_plan.plan_tree_, order_items))) { LOG_WARN("failed to allocate sort as top", K(ret)); } else { LOG_TRACE("succeed to allocate sort for order-by", K(need_sort)); } } // keep minimal cost plan or interesting plan if (OB_SUCC(ret)) { ObSEArray all_plans; int64_t check_scope = OrderingCheckScope::CHECK_SET; if (OB_FAIL(all_plans.assign(candidates_.candidate_plans_))) { LOG_WARN("failed to assign plan", K(ret)); } else if (OB_FAIL(update_plans_interesting_order_info(all_plans, check_scope))) { LOG_WARN("failed to update plans interesting order info", K(ret)); } else if (OB_FAIL(prune_and_keep_best_plans(all_plans))) { LOG_WARN("failed to prune and keep best plans", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObLogPlan::candi_allocate_subplan_filter_for_exprs(ObIArray& exprs) { int ret = OB_SUCCESS; ObSEArray subquery_exprs; ObSEArray nested_subquery_exprs; ObSEArray subqueries; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::get_subquery_exprs(exprs, subquery_exprs))) { LOG_WARN("failed to get subquery exprs", K(ret)); } else if (subquery_exprs.empty()) { /*do nothing*/ } else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(subquery_exprs, subqueries))) { LOG_WARN("failed to get extract query ref expr", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::extract_target_level_query_ref_expr( subquery_exprs, get_stmt()->get_current_level(), subqueries, nested_subquery_exprs))) { LOG_WARN("failed to extract target level query ref expr", K(ret)); } else if (!nested_subquery_exprs.empty() && OB_FAIL(candi_allocate_subplan_filter(nested_subquery_exprs, false))) { LOG_WARN("failed to allocate subplan filter for order by exprs", K(ret)); } else if (OB_FAIL(candi_allocate_subplan_filter(subquery_exprs, false))) { LOG_WARN("failed to allocate subplan filter for order by exprs", K(ret)); } else { /*do nothing*/ } return ret; } int ObLogPlan::allocate_sort_as_top( ObLogicalOperator*& top, const ObIArray& order_by_exprs, const ObIArray* directions) { int ret = OB_SUCCESS; ObSEArray order_items; if (OB_ISNULL(top)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(top), K(ret)); } else if (OB_FAIL(make_order_items(order_by_exprs, directions, order_items))) { LOG_WARN("failed to make order items", K(ret)); } else if (OB_FAIL(allocate_sort_as_top(top, order_items))) { LOG_WARN("failed to allocate sort as top", K(ret)); } else { /*do nothing*/ } return ret; } int ObLogPlan::allocate_group_by_as_top(ObLogicalOperator*& top, const AggregateAlgo algo, const ObIArray& group_by_exprs, const ObIArray& rollup_exprs, const ObIArray& agg_items, const ObIArray& having_exprs, const ObIArray& expected_ordering, const bool from_pivot /* = false*/) { int ret = OB_SUCCESS; ObLogicalOperator* group_by_op = NULL; if (OB_ISNULL(top)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(top)); } else if (OB_ISNULL(group_by_op = get_log_op_factory().allocate(*this, LOG_GROUP_BY))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to allocate group by operator", K(ret)); } else { ObLogGroupBy* group_by = static_cast(group_by_op); group_by->set_child(ObLogicalOperator::first_child, top); group_by->set_algo_type(algo); group_by->set_from_pivot(from_pivot); if (OB_FAIL(group_by->set_group_by_exprs(group_by_exprs))) { LOG_WARN("failed to set group by columns", K(ret)); } else if (OB_FAIL(group_by->set_rollup_exprs(rollup_exprs))) { LOG_WARN("failed to set rollup columns", K(ret)); } else if (OB_FAIL(group_by->set_aggr_exprs(agg_items))) { LOG_WARN("failed to set aggregation exprs", K(ret)); } else if (OB_FAIL(group_by->set_expected_ordering(expected_ordering))) { LOG_WARN("failed to set expected ordering", K(ret)); } else if (OB_FAIL(group_by->get_filter_exprs().assign(having_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(group_by->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { top = group_by; } } return ret; } int ObLogPlan::allocate_sort_as_top(ObLogicalOperator*& top, const ObIArray& sort_keys) { int ret = OB_SUCCESS; ObLogSort* sort = NULL; if (OB_ISNULL(top)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(top), K(ret)); } else if (OB_ISNULL(sort = static_cast(get_log_op_factory().allocate(*this, LOG_SORT)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to allocate sort for order by", K(ret)); } else { sort->set_child(ObLogicalOperator::first_child, top); if (OB_FAIL(sort->set_sort_keys(sort_keys))) { LOG_WARN("failed to set sort keys", K(ret)); } else if (OB_FAIL(sort->check_prefix_sort())) { LOG_WARN("failed to check prefix sort", K(ret)); } else { /*do nothing*/ } } // set plan root, for allocate exchange and adjust sort if (OB_SUCC(ret) && top->is_plan_root()) { top->set_is_plan_root(false); sort->mark_is_plan_root(); set_plan_root(sort); } // compute property if (OB_SUCC(ret)) { if (OB_FAIL(sort->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { top = sort; } } return ret; } /* * Limit clause will trigger a cost re-estimation phase based on a uniform distribution assumption. * instead of choosing minimal-cost plans, we prefer more reliable plans. */ int ObLogPlan::candi_allocate_limit(ObIArray& order_items) { int ret = OB_SUCCESS; ObDMLStmt* stmt = NULL; bool has_union_child = false; if (OB_ISNULL(stmt = get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(get_stmt()), K(ret)); } else if (stmt->is_set_stmt()) { has_union_child = static_cast(stmt)->get_set_op() == ObSelectStmt::UNION; } else { /*do nothing*/ } if (OB_SUCC(ret)) { if (OB_FAIL(candi_allocate_limit(stmt->get_limit_expr(), stmt->get_offset_expr(), stmt->get_limit_percent_expr(), order_items, has_union_child, stmt->is_calc_found_rows(), stmt->has_top_limit(), stmt->is_fetch_with_ties()))) { LOG_WARN("failed to allocate limit operator", K(ret)); } else { /*do nothing*/ } } return ret; } int ObLogPlan::candi_allocate_limit(ObRawExpr* limit_expr, ObRawExpr* offset_expr, ObRawExpr* percent_expr, ObIArray& expect_ordering, const bool has_union_child, const bool is_calc_found_rows, const bool is_top_limit, const bool is_fetch_with_ties) { int ret = OB_SUCCESS; CandidatePlan temp_plan; ObSEArray non_reliable_plans; ObSEArray reliable_plans; // aggregate the number of parent for each operator for (int64_t i = 0; OB_SUCC(ret) && i < candidates_.candidate_plans_.count(); ++i) { ObLogicalOperator* root = candidates_.candidate_plans_.at(i).plan_tree_; if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(root->aggregate_number_of_parent())) { LOG_WARN("failed to aggregate number of parent", K(ret)); } else { /*do nothing*/ } } for (int64_t idx = 0; OB_SUCC(ret) && idx < candidates_.candidate_plans_.count(); ++idx) { bool need_copy_tree = false; bool need_alloc_limit = false; bool is_reliable = false; CandidatePlan& plain_plan = candidates_.candidate_plans_.at(idx); if (OB_ISNULL(plain_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(plain_plan.plan_tree_->need_copy_plan_tree(need_copy_tree))) { LOG_WARN("failed to check whether need copy plan tree", K(ret)); } else if (!need_copy_tree) { temp_plan.plan_tree_ = plain_plan.plan_tree_; } else if (OB_FAIL(plan_tree_copy(plain_plan.plan_tree_, temp_plan.plan_tree_))) { LOG_WARN("failed to do plan tree copy", K(ret)); } else { /*do nothing*/ } if (OB_FAIL(ret)) { /*do nothing*/ } else if (OB_ISNULL(temp_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(if_plan_need_limit(temp_plan.plan_tree_, limit_expr, offset_expr, percent_expr, is_fetch_with_ties, need_alloc_limit))) { LOG_WARN("Failed to check limit needed", K(ret)); } else if (need_alloc_limit && OB_FAIL(allocate_limit_as_top(temp_plan.plan_tree_, limit_expr, offset_expr, percent_expr, expect_ordering, has_union_child, is_calc_found_rows, is_top_limit, is_fetch_with_ties))) { LOG_WARN("failed to allocate limit", K(ret)); } else if (OB_ISNULL(temp_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(is_plan_reliable(temp_plan.plan_tree_, is_reliable))) { LOG_WARN("failed to check plan is reliable", K(ret)); } else if (is_reliable) { ret = reliable_plans.push_back(temp_plan); } else { ret = non_reliable_plans.push_back(temp_plan); } } if (OB_SUCC(ret)) { int64_t check_scope = OrderingCheckScope::NOT_CHECK; if (!reliable_plans.empty()) { if (OB_FAIL(update_plans_interesting_order_info(reliable_plans, check_scope))) { LOG_WARN("failed to update plans interesting order info", K(ret)); } else if (OB_FAIL(prune_and_keep_best_plans(reliable_plans))) { LOG_WARN("failed to prune and keep best plans", K(ret)); } else { LOG_TRACE("Limit-k clause choose a more reliable plan"); } } else { if (OB_FAIL(update_plans_interesting_order_info(non_reliable_plans, check_scope))) { LOG_WARN("failed to update plans interesting order info", K(ret)); } else if (OB_FAIL(prune_and_keep_best_plans(non_reliable_plans))) { LOG_WARN("failed to prune and keep best plans", K(ret)); } else { LOG_TRACE("Limit-k clause does not choose a more reliable plan"); } } } // reset number of parent for each operator for (int64_t i = 0; OB_SUCC(ret) && i < candidates_.candidate_plans_.count(); ++i) { ObLogicalOperator* root = candidates_.candidate_plans_.at(i).plan_tree_; if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(root->reset_number_of_parent())) { LOG_WARN("failed to reset number of parent", K(ret)); } else { /*do nothing*/ } } return ret; } /* * A plan is reliable if it does not make any uniform assumption during the cost re-estimation phase. * In other words, it should satisfy the following two requirements: * 1 no operator in the plan has more than 1 children * 2 all operators in the plan belong to the set {LOG_LIMIT, LOG_COUNT, LOG_TABLE_LOOKUP, * LOG_SUBPLAN_SCAN, LOG_TABLE_SCAN, LOG_UNPIVOT}, * and does not have any filters. */ int ObLogPlan::is_plan_reliable(const ObLogicalOperator* root, bool& is_reliable) { int ret = OB_SUCCESS; is_reliable = false; if (OB_ISNULL(root)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else if (log_op_def::LOG_TABLE_SCAN == root->get_type()) { const ObCostTableScanInfo* cost_info = static_cast(root)->get_est_cost_info(); if (OB_ISNULL(cost_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cost info is null", K(ret)); } else { is_reliable = cost_info->table_filters_.empty() && cost_info->postfix_filters_.empty(); } } else if (log_op_def::LOG_SORT == root->get_type()) { if (fabs(root->get_op_cost()) < OB_DOUBLE_EPSINON) { // this sort operator is allocated to adjust sort, can ignore is_reliable = true; } else { is_reliable = false; } } else if (root->get_filter_exprs().count() == 0 && (log_op_def::LOG_LIMIT == root->get_type() || log_op_def::LOG_COUNT == root->get_type() || log_op_def::LOG_TABLE_LOOKUP == root->get_type() || log_op_def::LOG_SUBPLAN_SCAN == root->get_type() || log_op_def::LOG_UNPIVOT == root->get_type())) { is_reliable = true; } else { is_reliable = false; } if (OB_SUCC(ret) && is_reliable) { bool is_child_reliable = false; if (root->get_num_of_child() > 1) { is_reliable = false; } else if (root->get_num_of_child() == 0) { is_reliable = true; } else if (OB_ISNULL(root->get_child(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(is_plan_reliable(root->get_child(0), is_child_reliable))) { LOG_WARN("failed to check plan is reliable", K(ret)); } else { is_reliable &= is_child_reliable; } } if (OB_SUCC(ret)) { LOG_TRACE("succeed to check plan is reliable", K(is_reliable), K(root)); } return ret; } int ObLogPlan::candi_allocate_select_into() { int ret = OB_SUCCESS; ObSEArray select_into_plans; ObIArray& candidates = candidates_.candidate_plans_; int64_t best_plan_id = candidates_.plain_plan_.second; if (OB_UNLIKELY(best_plan_id < 0 || best_plan_id >= candidates.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected array pos", K(best_plan_id), K(candidates.count()), K(ret)); } else { CandidatePlan candidate_plan = candidates.at(best_plan_id); if (OB_ISNULL(candidate_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(allocate_selectinto_as_top(candidate_plan.plan_tree_))) { LOG_WARN("failed to allocate selectinto as top", K(ret)); } else if (OB_FAIL(select_into_plans.push_back(candidate_plan))) { LOG_WARN("failed to push back candidate plan", K(ret)); } else if (OB_FAIL(prune_and_keep_best_plans(select_into_plans))) { LOG_WARN("failed to prune and keep best plans", K(ret)); } else { /*do nothing*/ } } return ret; } int ObLogPlan::allocate_selectinto_as_top(ObLogicalOperator*& old_top) { int ret = OB_SUCCESS; ObLogSelectInto* select_into = NULL; ObSelectStmt* stmt = static_cast(get_stmt()); if (OB_ISNULL(old_top) || OB_ISNULL(get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Get unexpected null", K(ret), K(old_top), K(get_stmt())); } else if (OB_ISNULL( select_into = static_cast(get_log_op_factory().allocate(*this, LOG_SELECT_INTO)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allocate memory for ObLogSelectInto failed", K(ret)); } else { ObSelectIntoItem* into_item = stmt->get_select_into(); bool need_expected_ordering = stmt->has_order_by() && !stmt->has_limit(); if (OB_ISNULL(into_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("into item is null", K(ret)); } else { select_into->set_into_type(into_item->into_type_); select_into->set_outfile_name(into_item->outfile_name_); select_into->set_filed_str(into_item->filed_str_); select_into->set_line_str(into_item->line_str_); select_into->set_user_vars(into_item->user_vars_); select_into->set_is_optional(into_item->is_optional_); select_into->set_closed_cht(into_item->closed_cht_); select_into->set_child(ObLogicalOperator::first_child, old_top); old_top = select_into; // compute equal set if (OB_SUCC(ret)) { if (need_expected_ordering && OB_FAIL(select_into->set_expected_ordering(stmt->get_order_items()))) { LOG_WARN("failed to set expected ordering", K(ret)); } else if (OB_FAIL(select_into->compute_property())) { LOG_WARN("failed to compute equal set", K(ret)); } else { /*do nothing*/ } } } } return ret; } int ObLogPlan::if_plan_need_limit(ObLogicalOperator* top, ObRawExpr* limit_expr, ObRawExpr* offset_expr, ObRawExpr* percent_expr, bool is_fetch_with_ties, bool& need_alloc_limit) { int ret = OB_SUCCESS; need_alloc_limit = true; if (OB_ISNULL(top) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(top), K(get_stmt()), K(ret)); } else if (log_op_def::instance_of_log_table_scan(top->get_type())) { ObLogTableScan* table_scan = static_cast(top); if (!is_virtual_table(table_scan->get_ref_table_id()) && !get_stmt()->is_calc_found_rows() && (table_scan->get_phy_location_type() == OB_TBL_LOCATION_LOCAL || table_scan->get_phy_location_type() == OB_TBL_LOCATION_REMOTE) && OB_USE_LATE_MATERIALIZATION != get_stmt()->get_stmt_hint().use_late_mat_ && !table_scan->is_sample_scan() && NULL == table_scan->get_limit_expr() && NULL == percent_expr && !is_fetch_with_ties && limit_expr != NULL) { // Push down limit onto TableScan // 1. TODO: limit and offset on TableScan for virtual table are not handled yet. // 2. For cases with distributed sharding_info_, the limit pushing down will be done later // when allocating the EXCHANGE // 3. Only do on SELECT log plan, since we can't get sharding_info_ for table_scan now // and we need to use sharding_info_ on SELECT log plan. // Reminder: location type is distributed if use intra parallel table_scan->set_limit_offset(limit_expr, offset_expr); need_alloc_limit = false; // Adjust card for table scan if (OB_FAIL(table_scan->set_limit_size())) { LOG_WARN("Setting limit size for table scan fails", K(ret)); } } } else { /*do nothing*/ } return ret; } int ObLogPlan::allocate_limit_as_top(ObLogicalOperator*& old_top, ObRawExpr* limit_expr, ObRawExpr* offset_expr, ObRawExpr* percent_expr, ObIArray& expect_ordering, const bool has_union_child, const bool is_calc_found_rows, const bool is_top_limit, const bool is_fetch_with_ties) { int ret = OB_SUCCESS; ObLogLimit* limit = NULL; if (OB_ISNULL(old_top) || OB_ISNULL(get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(old_top), K(get_stmt()), K(ret)); } else if (OB_ISNULL(limit = static_cast(get_log_op_factory().allocate(*this, LOG_LIMIT)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory for limit op", K(ret)); } else { limit->set_limit_count(limit_expr); limit->set_limit_offset(offset_expr); limit->set_limit_percent(percent_expr); limit->set_child(ObLogicalOperator::first_child, old_top); limit->set_has_union_child(has_union_child); limit->set_calc_found_rows(is_calc_found_rows); limit->set_top_limit(is_top_limit); limit->set_fetch_with_ties(is_fetch_with_ties); if (OB_FAIL(limit->set_expected_ordering(expect_ordering))) { LOG_WARN("failed to set expected ordering", K(ret)); } else if (OB_FAIL(limit->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { old_top = limit; } } return ret; } int ObLogPlan::plan_tree_traverse(const TraverseOp& operation, void* ctx) { int ret = OB_SUCCESS; int64_t parallel = get_optimizer_context().get_parallel(); if (OB_ISNULL(get_plan_root()) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(get_stmt()), K(get_plan_root())); } else { NumberingCtx numbering_ctx; // operator numbering context NumberingExchangeCtx numbering_exchange_ctx; // operator numbering context ObArenaAllocator allocator(CURRENT_CONTEXT->get_malloc_allocator()); allocator.set_label("PlanTreeTraver"); ObAllocExprContext alloc_expr_ctx(allocator); // expr allocation context AllocExchContext alloc_exch_ctx(parallel); // exchange allocation context AdjustSortContext adjust_sort_ctx; // exchange allocation context uint64_t hash_seed = 0; // seed for plan signature ObBitSet<256> output_deps; // output expr dependencies AllocGIContext gi_ctx(parallel); ObPxPipeBlockingCtx pipe_block_ctx(get_allocator()); ObLocationConstraintContext location_constraints; AllocMDContext md_ctx; GenLinkStmtContext link_ctx; // set up context switch (operation) { case PX_PIPE_BLOCKING: { ctx = &pipe_block_ctx; if (OB_FAIL(get_plan_root()->init_all_traverse_ctx(pipe_block_ctx))) { LOG_WARN("init traverse ctx failed", K(ret)); } break; } case ALLOC_GI: { ctx = &gi_ctx; bool is_valid = true; if (get_stmt()->is_insert_stmt() && !static_cast(get_stmt())->value_from_select()) { gi_ctx.is_valid_for_gi_ = false; } else if (OB_FAIL(get_plan_root()->should_allocate_gi_for_dml(is_valid))) { LOG_WARN("failed to check should allocate gi for dml", K(ret)); } else { gi_ctx.is_valid_for_gi_ = get_stmt()->is_dml_write_stmt() && is_valid; } break; } case ALLOC_MONITORING_DUMP: { ctx = &md_ctx; break; } case ALLOC_EXCH: { ctx = &alloc_exch_ctx; break; } case ADJUST_SORT_OPERATOR: { ctx = &adjust_sort_ctx; break; } case PROJECT_PRUNING: { ctx = &output_deps; break; } case ALLOC_EXPR: { if (OB_FAIL(alloc_expr_ctx.not_produced_exprs_.init())) { LOG_WARN("fail to init not_produced_exprs", K(ret)); } else if (OB_FAIL(alloc_expr_ctx.set_group_replaced_exprs(group_replaced_exprs_))) { LOG_WARN("failed to set_group_replaced_exprs", K(ret)); } else { ctx = &alloc_expr_ctx; } break; } case OPERATOR_NUMBERING: { ctx = &numbering_ctx; break; } case EXCHANGE_NUMBERING: { ctx = &numbering_exchange_ctx; break; } case GEN_SIGNATURE: { ctx = &hash_seed; break; } case GEN_LOCATION_CONSTRAINT: { ctx = &location_constraints; break; } case PX_ESTIMATE_SIZE: break; case GEN_LINK_STMT: { ctx = &link_ctx; break; } case EXPLAIN_COLLECT_WIDTH: case EXPLAIN_WRITE_BUFFER: case EXPLAIN_WRITE_BUFFER_OUTPUT: case EXPLAIN_WRITE_BUFFER_OUTLINE: case EXPLAIN_INDEX_SELECTION_INFO: case ALLOC_STARTUP_EXPR: default: break; } if (OB_SUCC(ret)) { if (((PX_ESTIMATE_SIZE == operation) || (PX_PIPE_BLOCKING == operation) || (PX_RESCAN == operation)) && (is_local_or_remote_plan())) { /*do nothing*/ } else if (ALLOC_GI == operation && is_local_or_remote_plan() && !(gi_ctx.is_valid_for_gi_ && get_optimizer_context().enable_batch_rpc())) { /*do nothing*/ } else if (OB_FAIL(get_plan_root()->do_plan_tree_traverse(operation, ctx))) { LOG_WARN("failed to apply operation to operator", K(operation), K(ret)); } else { // remember signature in plan if (GEN_SIGNATURE == operation) { if (OB_ISNULL(ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx is null", K(ret), K(ctx)); } else { hash_value_ = *static_cast(ctx); LOG_TRACE("succ to generate plan hash value", "hash_value", hash_value_); } } else if (ALLOC_EXCH == operation) { set_phy_plan_type(alloc_exch_ctx); if (!alloc_exch_ctx.exchange_allocated_) { set_require_local_execution(true); } if (OB_FAIL(set_group_replaced_exprs(alloc_exch_ctx.group_push_down_replaced_exprs_))) { LOG_WARN("failed to set_group_replaced_exprs", K(ret)); } } else if (GEN_LOCATION_CONSTRAINT == operation) { ObSqlCtx* sql_ctx = NULL; if (OB_ISNULL(optimizer_context_.get_exec_ctx()) || OB_ISNULL(sql_ctx = optimizer_context_.get_exec_ctx()->get_sql_ctx())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(optimizer_context_.get_exec_ctx()), K(sql_ctx)); } else if (OB_FAIL(remove_duplicate_constraint(location_constraints, *sql_ctx))) { LOG_WARN("fail to remove duplicate constraint", K(ret)); } else if (OB_FAIL(calc_and_set_exec_pwj_map(location_constraints))) { LOG_WARN("failed to calc and set exec pwj map", K(ret)); } } else if (ADJUST_SORT_OPERATOR == operation) { if (0 != adjust_sort_ctx.exchange_cnt_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid traverse for adjust sort", K(ret), K(adjust_sort_ctx.exchange_cnt_)); } } else if (ALLOC_EXPR == operation) { if (OB_FAIL(set_all_exprs(alloc_expr_ctx))) { LOG_WARN("fail to set all exprs", K(ret)); } } else if (OPERATOR_NUMBERING == operation) { NumberingCtx* num_ctx = static_cast(ctx); max_op_id_ = num_ctx->op_id_; LOG_TRACE("trace max operator id", K(max_op_id_), K(this)); } else { /* Do nothing */ } LOG_TRACE("succ to apply operaion to operator", K(operation), K(ret)); } } } return ret; } int ObLogPlan::change_id_hint_to_idx() { int ret = OB_SUCCESS; ObDMLStmt* dml_stmt = get_stmt(); if (OB_ISNULL(dml_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dml stmt is null", K(ret)); } else { ObStmtHint& stmt_hint = dml_stmt->get_stmt_hint(); if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.use_merge_ids_, stmt_hint.use_merge_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use merge ids", K(ret)); } else if (OB_FAIL( dml_stmt->convert_table_ids_to_bitset(stmt_hint.no_use_merge_ids_, stmt_hint.no_use_merge_idxs_))) { LOG_WARN("failed to convert table ids to bitset for no use merge ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.use_nl_ids_, stmt_hint.use_nl_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use nl ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.no_use_nl_ids_, stmt_hint.no_use_nl_idxs_))) { LOG_WARN("failed to convert table ids to bitset for no use nl ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.use_bnl_ids_, stmt_hint.use_bnl_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use bnl ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.no_use_bnl_ids_, stmt_hint.no_use_bnl_idxs_))) { LOG_WARN("failed to convert table ids to bitset for no use bnl ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.use_hash_ids_, stmt_hint.use_hash_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL( dml_stmt->convert_table_ids_to_bitset(stmt_hint.no_use_hash_ids_, stmt_hint.no_use_hash_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset( stmt_hint.use_nl_materialization_ids_, stmt_hint.use_nl_materialization_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset( stmt_hint.no_use_nl_materialization_ids_, stmt_hint.no_use_nl_materialization_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL( dml_stmt->convert_table_ids_to_bitset(stmt_hint.pq_distributes_, stmt_hint.pq_distributes_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset(stmt_hint.pq_maps_, stmt_hint.pq_map_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset( stmt_hint.px_join_filter_ids_, stmt_hint.px_join_filter_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else if (OB_FAIL(dml_stmt->convert_table_ids_to_bitset( stmt_hint.no_px_join_filter_ids_, stmt_hint.no_px_join_filter_idxs_))) { LOG_WARN("failed to convert table ids to bitset for use hash ids", K(ret)); } else { } } return ret; } int ObLogPlan::generate_plan_tree() { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(get_stmt())); } else { // 1.1 generate access paths /* random exprs should be split from condition exprs to avoid being pushed down * random exprs will be added back in function candi_init*/ if (OB_FAIL(ObTransformUtils::right_join_to_left(get_stmt()))) { LOG_WARN("failed to change right join to left", K(ret)); } else if (OB_FAIL(change_id_hint_to_idx())) { LOG_WARN("failed to change id hint to idx", K(ret)); } else if (OB_FAIL(generate_join_orders())) { LOG_WARN("failed to generate the access path for the single-table query", K(ret), K(get_stmt()->get_sql_stmt())); } else if (OB_FAIL(candi_init())) { LOG_WARN("failed to initialized the plan candidates from the join order", K(ret)); } else { LOG_TRACE("plan candidates is initialized from the join order", "# of candidates", candidates_.candidate_plans_.count()); } } return ret; } void ObLogPlan::set_phy_plan_type(AllocExchContext& ctx) { AllocExchContext::DistrStat status = ctx.get_plan_type(); if (AllocExchContext::UNINITIALIZED == status || AllocExchContext::LOCAL == status) { phy_plan_type_ = OB_PHY_PLAN_LOCAL; } else if (AllocExchContext::REMOTE == status) { phy_plan_type_ = OB_PHY_PLAN_REMOTE; } else { phy_plan_type_ = OB_PHY_PLAN_DISTRIBUTED; } } int ObLogPlan::check_join_legal(const ObRelIds& left_set, const ObRelIds& right_set, ConflictDetector* detector, bool delay_cross_product, bool& legal) { int ret = OB_SUCCESS; ObRelIds ids; legal = true; if (OB_ISNULL(detector)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null detector", K(ret)); } else if (INNER_JOIN == detector->join_info_.join_type_) { if (OB_FAIL(ids.add_members(left_set))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(ids.add_members(right_set))) { LOG_WARN("failed to add members", K(ret)); } else if (!detector->join_info_.table_set_.is_subset(ids)) { legal = false; } } else { if (detector->L_TES_.is_subset(left_set) && detector->R_TES_.is_subset(right_set)) { // do nothing } else if (!detector->is_commutative_) { legal = false; } else if (detector->R_TES_.is_subset(left_set) && detector->L_TES_.is_subset(right_set)) { // do nothing } else { legal = false; } if (legal && !detector->is_commutative_) { if (left_set.overlap(detector->R_DS_) || right_set.overlap(detector->L_DS_)) { legal = false; } } } if (OB_FAIL(ret) || !legal) { // do nothing } else if (detector->is_degenerate_pred_) { // check T(left(o)) n S1 != empty ^ T(right(o)) n S2 != empty if (detector->L_DS_.overlap(left_set) && detector->R_DS_.overlap(right_set)) { // do nothing } else if (!detector->is_commutative_) { legal = false; } else if (detector->R_DS_.overlap(left_set) && detector->L_DS_.overlap(right_set)) { // do nothing } else { legal = false; } } if (OB_FAIL(ret) || !legal) { // do nothing } else if (OB_FAIL(ids.add_members(left_set))) { LOG_WARN("failed to add members", K(ret)); } else if (OB_FAIL(ids.add_members(right_set))) { LOG_WARN("failed to add members", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && legal && i < detector->CR_.count(); ++i) { const ObRelIds& T1 = detector->CR_.at(i).first; const ObRelIds& T2 = detector->CR_.at(i).second; if (T1.overlap(ids) && !T2.is_subset(ids)) { legal = false; } } if (OB_SUCC(ret) && legal) { for (int64_t i = 0; OB_SUCC(ret) && legal && i < detector->cross_product_rule_.count(); ++i) { const ObRelIds& T1 = detector->cross_product_rule_.at(i).first; const ObRelIds& T2 = detector->cross_product_rule_.at(i).second; if (T1.overlap(left_set) && !T2.is_subset(left_set)) { legal = false; } else if (T1.overlap(right_set) && !T2.is_subset(right_set)) { legal = false; } } } if (OB_SUCC(ret) && delay_cross_product && legal) { for (int64_t i = 0; OB_SUCC(ret) && legal && i < detector->delay_cross_product_rule_.count(); ++i) { const ObRelIds& T1 = detector->delay_cross_product_rule_.at(i).first; const ObRelIds& T2 = detector->delay_cross_product_rule_.at(i).second; if (T1.overlap(left_set) && !T2.is_subset(left_set)) { legal = false; } else if (T1.overlap(right_set) && !T2.is_subset(right_set)) { legal = false; } } } } return ret; } int ObLogPlan::check_join_hint( const ObRelIds& left_set, const ObRelIds& right_set, bool& match_hint, bool& is_legal, bool& is_strict_order) { int ret = OB_SUCCESS; if (!left_set.overlap(leading_tables_) && !right_set.overlap(leading_tables_)) { match_hint = false; is_legal = true; is_strict_order = true; } else if (left_set.is_subset(leading_tables_) && right_set.is_subset(leading_tables_)) { bool found = false; for (int64_t i = 0; !found && i < leading_infos_.count(); ++i) { const LeadingInfo& info = leading_infos_.at(i); if (left_set.equal(info.left_table_set_) && right_set.equal(info.right_table_set_)) { is_strict_order = true; found = true; } else if (right_set.equal(info.left_table_set_) && left_set.equal(info.right_table_set_)) { is_strict_order = false; found = true; } } if (!found) { is_legal = false; } else { match_hint = true; is_legal = true; } } else if (leading_tables_.is_subset(left_set)) { match_hint = true; is_legal = true; is_strict_order = true; } else { is_legal = false; } return ret; } int ObLogPlan::extract_onetime_exprs( ObRawExpr* expr, ObIArray>& onetime_exprs, ObBitSet<>& idxs) { int ret = OB_SUCCESS; bool is_onetime_expr = false; bool is_stack_overflow = false; if (OB_ISNULL(expr) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), KP(expr), KP(get_stmt())); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::check_is_onetime_expr(get_onetime_exprs(), expr, get_stmt(), is_onetime_expr))) { LOG_WARN("failed to check subquery is onetime expr", K(ret)); } else if (is_onetime_expr) { if (OB_FAIL(extract_subquery_ids(expr, idxs))) { LOG_WARN("fail to extract param from raw expr", K(ret)); } else if (0 <= ObOptimizerUtil::find_exec_param(onetime_exprs, expr)) { /* expr has added */ } else { int64_t param_num = ObOptimizerUtil::find_exec_param(get_onetime_exprs(), expr); if (param_num >= 0) { ObRawExpr* param_expr = ObOptimizerUtil::find_param_expr(get_stmt()->get_exec_param_ref_exprs(), param_num); if (NULL != param_expr) { if (OB_FAIL(onetime_exprs.push_back(std::pair(param_num, expr)))) { LOG_WARN("push back onetime_exprs error", K(ret)); } else { /*do nothing*/ } } else { /* do nothing */ } } else { ObRawExpr* temp_expr = expr; std::pair init_expr; if (OB_FAIL(ObRawExprUtils::create_exec_param_expr( get_stmt(), optimizer_context_.get_expr_factory(), temp_expr, NULL, init_expr))) { LOG_WARN("create param for stmt error in extract_params_for_nl", K(ret)); } else if (OB_FAIL(onetime_exprs.push_back(init_expr))) { LOG_WARN("push back error", K(ret)); } else { /*do nothing*/ } } } } else { int64_t count = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(SMART_CALL(extract_onetime_exprs(expr->get_param_expr(i), onetime_exprs, idxs)))) { LOG_WARN("fail to extract param from raw expr", K(ret), K(expr->get_param_expr(i))); } else { /* Do nothing */ } } } return ret; } int ObLogPlan::extract_subquery_ids(ObRawExpr* expr, ObBitSet<>& idxs) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else { ObRawExpr::ExprClass expr_class = expr->get_expr_class(); switch (expr_class) { case ObRawExpr::EXPR_CONST: { break; } case ObRawExpr::EXPR_QUERY_REF: { if (OB_FAIL(idxs.add_member(static_cast(expr)->get_ref_id()))) { LOG_WARN("add_member fails", K(ret)); } else { /* Do nothing */ } break; } case ObRawExpr::EXPR_SET_OP: case ObRawExpr::EXPR_COLUMN_REF: { break; } case ObRawExpr::EXPR_CASE_OPERATOR: // fallthrough case ObRawExpr::EXPR_AGGR: // fallthrough case ObRawExpr::EXPR_SYS_FUNC: // fallthrough case ObRawExpr::EXPR_UDF: case ObRawExpr::EXPR_OPERATOR: { int64_t count = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_ISNULL(expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr->get_param_expr(i) is null", K(ret), K(i)); } else if (!expr->get_param_expr(i)->has_flag(CNT_SUB_QUERY)) { } else if (OB_FAIL(SMART_CALL(extract_subquery_ids(expr->get_param_expr(i), idxs)))) { LOG_WARN("fail to extract subquery ids from raw expr", K(ret)); } else { /* Do nothing */ } } break; } case ObRawExpr::EXPR_INVALID_CLASS: default: ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid expr class", K(expr_class), K(ret)); // should not reach here break; } // switch case end } return ret; } int ObLogPlan::print_outline(planText& plan, bool is_hints) const { int ret = OB_SUCCESS; char* buf = plan.buf; int64_t& buf_len = plan.buf_len; int64_t& pos = plan.pos; bool is_oneline = plan.is_oneline_; OutlineType outline_type = plan.outline_type_; const ObQueryCtx* query_ctx = NULL; if (OB_ISNULL(stmt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt_ is NULL", K(ret)); } else if (OB_ISNULL(query_ctx = stmt_->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("query_ctx is NULL", K(ret)); } else if (!is_oneline && OB_FAIL(BUF_PRINTF(" "))) { } else if (!is_hints && OB_FAIL(BUF_PRINTF("/*+"))) { /* Do nothing */ } else if (OUTLINE_DATA == outline_type && !is_oneline && OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OUTLINE_DATA == outline_type && OB_FAIL(BUF_PRINTF(ObStmtHint::get_outline_indent(is_oneline)))) { /* Do nothing */ } else if (OUTLINE_DATA == outline_type && OB_FAIL(BUF_PRINTF("BEGIN_OUTLINE_DATA"))) { /* Do nothing */ } else if (OB_FAIL(const_cast(this)->plan_tree_traverse(EXPLAIN_WRITE_BUFFER_OUTLINE, &plan))) { LOG_WARN("failed to print output exprs", K(ret)); } else if (OB_FAIL(stmt_->get_stmt_hint().print_global_hint_for_outline(plan, stmt_))) { LOG_WARN("fail to print global hint for outline", K(ret)); } else if (OB_FAIL(query_ctx->print_qb_name_hint(plan))) { LOG_WARN("fail to print qb_name", K(ret)); } else if (OUTLINE_DATA == outline_type && !is_oneline && OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (OUTLINE_DATA == outline_type && OB_FAIL(BUF_PRINTF(ObStmtHint::get_outline_indent(is_oneline)))) { /* Do nothing */ } else if (OUTLINE_DATA == outline_type && OB_FAIL(BUF_PRINTF("END_OUTLINE_DATA"))) { /* Do nothing */ } else if (!is_oneline && OB_FAIL(BUF_PRINTF(NEW_LINE))) { /* Do nothing */ } else if (!is_oneline && OB_FAIL(BUF_PRINTF(" "))) { } else if (!is_hints && OB_FAIL(BUF_PRINTF("*/"))) { /* Do nothing */ } return ret; } int ObLogPlan::print_outline_oneline(char* buf, int64_t buf_len, int64_t& pos) const { int ret = OB_SUCCESS; planText plan(buf, buf_len, EXPLAIN_OUTLINE); plan.is_oneline_ = true; plan.outline_type_ = OUTLINE_DATA; if (OB_FAIL(print_outline(plan))) { LOG_WARN("fail to print outline", K(ret), "buf", ObString(static_cast(plan.pos), buf)); } else { pos = plan.pos; } return ret; } double ObLogPlan::get_expr_selectivity(const ObRawExpr* expr, bool& found) { double sel = 1.0; found = false; if (OB_ISNULL(expr)) { } else { for (int64_t i = 0; !found && i < predicate_selectivities_.count(); ++i) { if (expr == predicate_selectivities_.at(i).expr_) { found = true; sel = predicate_selectivities_.at(i).sel_; } } } return sel; } int ObLogPlan::store_param_expr_selectivity(ObRawExpr* src_expr, ObRawExpr* param_expr, ObEstSelInfo& sel_info) { int ret = OB_SUCCESS; if (OB_ISNULL(src_expr) || OB_ISNULL(param_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(src_expr), K(param_expr)); } else { bool found_sel = false; double sel = get_expr_selectivity(src_expr, found_sel); if (!found_sel) { LOG_TRACE("Not found param expr selectivity"); if (OB_FAIL(ObOptEstSel::clause_selectivity(sel_info, src_expr, sel, &get_predicate_selectivities()))) { LOG_WARN("Failed to calc selectivity", K(ret)); } } if (OB_SUCC(ret)) { int tmp_ret = OB_SUCCESS; if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = add_var_to_array_no_dup( get_predicate_selectivities(), ObExprSelPair(param_expr, sel))))) { LOG_WARN("failed to add selectivity to plan", K(tmp_ret), K(param_expr), K(sel)); } } } return ret; } int ObLogPlan::candi_allocate_subplan_filter_for_where() { int ret = OB_SUCCESS; ObSEArray pushdown_subquery; ObSEArray none_pushdown_subquery; for (int64_t i = 0; i < subquery_filters_.count(); ++i) { ObRawExpr* expr = subquery_filters_.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->has_flag(CNT_SUB_QUERY)) { ret = none_pushdown_subquery.push_back(expr); } else if (OB_FAIL(extract_onetime_subquery_exprs(expr, pushdown_subquery))) { LOG_WARN("failed to extract onetime subquery exprs", K(ret)); } } if (OB_FAIL(ret)) { /*do nothing*/ } else if (OB_FAIL(candi_allocate_subplan_filter(pushdown_subquery, false))) { LOG_WARN("failed to allocate subplan filter", K(ret)); } else if (OB_FAIL(candi_allocate_subplan_filter(none_pushdown_subquery, true))) { LOG_WARN("failed to allocate subplan filter", K(ret)); } else { /*do nothing*/ } return ret; } int ObLogPlan::candi_allocate_subplan_filter(ObIArray& subquery_exprs, const bool is_filter) { int ret = OB_SUCCESS; if (OB_FAIL(candi_allocate_subplan_filter(subquery_exprs, is_filter, candidates_))) { LOG_WARN("failed to allocate subplan filter as top", K(ret)); } else { /*do nothing*/ } return ret; } int ObLogPlan::candi_allocate_subplan_filter( ObIArray& subquery_exprs, const bool is_filter, All_Candidate_Plans& all_plans) { int ret = OB_SUCCESS; ObBitSet<> initplan_idxs; ObBitSet<> onetime_idxs; ObSEArray subquery_ops; ObSEArray, 4> params; ObSEArray, 4> onetime_exprs; ObLogicalOperator* best_plan = NULL; if (OB_FAIL(all_plans.get_best_plan(best_plan))) { LOG_WARN("failed to get best plan", K(ret)); } else if (OB_ISNULL(best_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpectd null", K(ret)); } else if (OB_FAIL(generate_subplan_filter_info( subquery_exprs, best_plan, subquery_ops, params, onetime_exprs, initplan_idxs, onetime_idxs))) { LOG_WARN("failed to generated subplan filter info", K(ret)); } else if (subquery_ops.empty() && !is_filter) { /*do nothing*/ } else if (is_filter && !onetime_exprs.empty() && OB_FAIL(find_and_replace_onetime_expr_with_param(onetime_exprs, subquery_exprs))) { LOG_WARN("failed to find and replace onetime expr with param", K(ret)); } else if (subquery_ops.empty()) { if (OB_FAIL(candi_allocate_filter(subquery_exprs))) { LOG_WARN("failed to allocate filter as top", K(ret)); } else { /*do nothing*/ } } else { double min_cost = 0.0; int64_t min_idx = OB_INVALID_INDEX; ObIArray* filters = NULL; if (is_filter) { filters = &subquery_exprs; } for (int64_t i = 0; OB_SUCC(ret) && i < all_plans.candidate_plans_.count(); ++i) { CandidatePlan& plain_plan = all_plans.candidate_plans_.at(i); if (OB_FAIL(allocate_subplan_filter_as_top( plain_plan.plan_tree_, subquery_ops, params, onetime_exprs, initplan_idxs, onetime_idxs, filters))) { LOG_WARN("failed to allocate filter", K(ret)); } else if (OB_ISNULL(plain_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Plan_tree_ is NULL", K(ret)); } else if (plain_plan.plan_tree_->get_cost() < min_cost || OB_INVALID_INDEX == min_idx) { min_cost = plain_plan.plan_tree_->get_cost(); min_idx = i; } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (OB_UNLIKELY(OB_INVALID_INDEX == min_idx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected index", K(ret), K(min_idx)); } else { all_plans.plain_plan_.second = min_idx; all_plans.plain_plan_.first = min_cost; } } } if (OB_SUCC(ret) && !onetime_exprs.empty()) { if (OB_FAIL(add_onetime_exprs(onetime_exprs))) { LOG_WARN("failed to add onetime exprs", K(ret)); } else if (OB_FAIL(adjust_stmt_onetime_exprs(onetime_exprs))) { LOG_WARN("failed to adjust stme onetime exprs", K(ret)); } else { /*do nothing*/ } } return ret; } int ObLogPlan::generate_subplan_filter_info(const ObIArray& subquery_exprs, ObLogicalOperator* top_node, ObIArray& subquery_ops, ObIArray>& params, ObIArray>& onetime_exprs, ObBitSet<>& initplan_idxs, ObBitSet<>& onetime_idxs) { int ret = OB_SUCCESS; if (OB_ISNULL(top_node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { ObSEArray subplan_infos; ObSEArray temp_subplan_infos; for (int64_t i = 0; OB_SUCC(ret) && i < subquery_exprs.count(); i++) { ObRawExpr* temp_expr = NULL; temp_subplan_infos.reuse(); if (OB_ISNULL(temp_expr = subquery_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(generate_subplan(temp_expr))) { LOG_WARN("failed to generate subplan", K(ret)); } else if (OB_FAIL(get_subplan_info(temp_expr, temp_subplan_infos))) { LOG_WARN("failed to generate subplan info", K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && j < temp_subplan_infos.count(); j++) { bool need_alloc = false; if (OB_FAIL(need_alloc_child_for_subplan_filter(top_node, temp_subplan_infos.at(j)->subplan_, need_alloc))) { LOG_WARN( "failed to check whether need alloc subplan filter", K(need_alloc), K(top_node->get_type()), K(ret)); } else if (need_alloc && OB_FAIL(add_var_to_array_no_dup(subplan_infos, temp_subplan_infos.at(j)))) { LOG_WARN("failed to push back subplan infos", K(ret)); } else { /*do nothing*/ } } } } for (int64_t i = 0; OB_SUCC(ret) && i < subplan_infos.count(); i++) { ObQueryRefRawExpr* ref_subquery_expr = NULL; if (OB_ISNULL(subplan_infos.at(i)) || OB_ISNULL(subplan_infos.at(i)->subplan_) || OB_ISNULL(subplan_infos.at(i)->subplan_->get_plan_root()) || OB_ISNULL(subplan_infos.at(i)->init_expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(subquery_ops.push_back(subplan_infos.at(i)->subplan_->get_plan_root()))) { LOG_WARN("failed to push back child ops", K(ret)); } else if (OB_FAIL(append(params, subplan_infos.at(i)->sp_params_))) { LOG_WARN("failed to append params", K(ret)); } else if (subplan_infos.at(i)->init_plan_ && OB_FAIL(initplan_idxs.add_member(i + 1))) { LOG_WARN("failed to add init plan idxs", K(ret)); } else { ref_subquery_expr = static_cast(subplan_infos.at(i)->init_expr_); ref_subquery_expr->set_ref_id(i + 1); ref_subquery_expr->set_ref_operator(subplan_infos.at(i)->subplan_->get_plan_root()); } } if (OB_SUCC(ret) && !subquery_ops.empty()) { for (int64_t i = 0; OB_SUCC(ret) && i < subquery_exprs.count(); i++) { if (OB_ISNULL(subquery_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(extract_onetime_exprs(subquery_exprs.at(i), onetime_exprs, onetime_idxs))) { LOG_WARN("failed to extract onetime exprs", K(ret)); } else { /*do nothing*/ } } } if (OB_SUCC(ret)) { initplan_idxs.del_members(onetime_idxs); } } return ret; } int ObLogPlan::candi_allocate_filter(const ObIArray& filter_exprs) { int ret = OB_SUCCESS; double sel = 1.0; ObLogicalOperator* best_plan = NULL; if (OB_FAIL(get_current_best_plan(best_plan))) { LOG_WARN("failed to get best plan", K(ret)); } else if (OB_ISNULL(best_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObOptEstSel::calculate_selectivity( *best_plan->get_est_sel_info(), filter_exprs, sel, &get_predicate_selectivities()))) { LOG_WARN("failed to calc selectivity", K(ret)); } else { /*update the number of rows for the top_node*/ for (int64_t i = 0; OB_SUCC(ret) && i < candidates_.candidate_plans_.count(); i++) { ObLogicalOperator* top = candidates_.candidate_plans_.at(i).plan_tree_; if (OB_ISNULL(top)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(append(top->get_filter_exprs(), filter_exprs))) { LOG_WARN("failed to append exprs", K(ret)); } else { top->set_card(top->get_card() * sel); } } } return ret; } int ObLogPlan::find_and_replace_onetime_expr_with_param( const ObIArray>& onetime_exprs, ObIArray& ori_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < ori_exprs.count(); i++) { if (OB_FAIL(find_and_replace_onetime_expr_with_param(onetime_exprs, ori_exprs.at(i)))) { LOG_WARN("failed to find and replace onetime expr with param", K(ret)); } else { /*do nothing*/ } } return ret; } int ObLogPlan::find_and_replace_onetime_expr_with_param( const ObIArray>& onetime_exprs, ObRawExpr*& ori_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(ori_expr) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ori_expr), K(get_stmt()), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < onetime_exprs.count(); ++i) { int64_t param_idx = onetime_exprs.at(i).first; const ObRawExpr* onetime_expr = onetime_exprs.at(i).second; ObRawExpr** addr_matched_expr = NULL; if (ObOptimizerUtil::is_sub_expr(onetime_expr, ori_expr, addr_matched_expr)) { ObRawExpr* exec_param_expr = ObOptimizerUtil::find_param_expr(get_stmt()->get_exec_param_ref_exprs(), param_idx); if (OB_ISNULL(exec_param_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { *addr_matched_expr = exec_param_expr; } } else { /* Do nothing */ } } } return ret; } int ObLogPlan::allocate_subplan_filter_as_top(ObLogicalOperator*& top, const ObIArray& subquery_ops, const ObIArray>& params, const ObIArray>& onetime_exprs, const ObBitSet<>& initplan_idxs, const ObBitSet<>& onetime_idxs, const ObIArray* filters) { int ret = OB_SUCCESS; ObLogSubPlanFilter* spf_node = NULL; if (OB_ISNULL(top)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(top), K(ret)); } else if (OB_ISNULL(spf_node = static_cast( get_log_op_factory().allocate(*this, LOG_SUBPLAN_FILTER)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(spf_node), K(ret)); } else if (OB_FAIL(spf_node->add_child(top))) { LOG_WARN("failed to add child", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < subquery_ops.count(); i++) { if (OB_FAIL(spf_node->add_child(subquery_ops.at(i)))) { LOG_WARN("failed to add children", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (NULL != filters && OB_FAIL(append(spf_node->get_filter_exprs(), *filters))) { LOG_WARN("failed to append filter exprs", K(ret)); } else if (OB_FAIL(spf_node->add_exec_params(params))) { LOG_WARN("failed to add exec params", K(ret)); } else if (OB_FAIL(spf_node->add_onetime_exprs(onetime_exprs))) { LOG_WARN("failed to add onetime exprs", K(ret)); } else if (OB_FAIL(spf_node->add_initplan_idxs(initplan_idxs))) { LOG_WARN("failed to add init plan idxs", K(ret)); } else if (OB_FAIL(spf_node->add_onetime_idxs(onetime_idxs))) { LOG_WARN("failed to add onetime idxs", K(ret)); } else if (OB_FAIL(spf_node->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { top = spf_node; } } } return ret; } int ObLogPlan::allocate_subplan_filter_as_top( ObIArray& subquery_exprs, const bool is_filter, ObLogicalOperator*& top_node) { int ret = OB_SUCCESS; All_Candidate_Plans all_plans; if (OB_ISNULL(top_node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(all_plans.candidate_plans_.push_back(CandidatePlan(top_node)))) { LOG_WARN("failed to push back plans", K(ret)); } else { all_plans.plain_plan_ = std::pair(top_node->get_cost(), 0); if (OB_FAIL(candi_allocate_subplan_filter(subquery_exprs, is_filter, all_plans))) { LOG_WARN("failed to allocate subplan filter", K(ret)); } else if (OB_UNLIKELY(1 != all_plans.candidate_plans_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected arry count", K(ret)); } else { top_node = all_plans.candidate_plans_.at(0).plan_tree_; LOG_TRACE("succeed to allocate subplan filter as top", K(subquery_exprs), K(top_node->get_type())); } } return ret; } int ObLogPlan::adjust_stmt_onetime_exprs(ObIArray>& onetime_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(get_stmt()), K(ret)); } else { ObSEArray old_exprs; ObSEArray new_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < onetime_exprs.count(); i++) { ObRawExpr* temp_expr = NULL; if (OB_ISNULL(onetime_exprs.at(i).second)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(old_exprs.push_back(onetime_exprs.at(i).second))) { LOG_WARN("failed to push back old exprs", K(ret)); } else if (OB_ISNULL(temp_expr = ObOptimizerUtil::find_param_expr( get_stmt()->get_exec_param_ref_exprs(), onetime_exprs.at(i).first))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(new_exprs.push_back(temp_expr))) { LOG_WARN("get unexpected null", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret) && !new_exprs.empty()) { if (OB_FAIL(get_stmt()->replace_inner_stmt_expr(old_exprs, new_exprs))) { LOG_WARN("failed to replace inner stmt expr", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObLogPlan::remove_null_direction_for_order_item( common::ObIArray& order_items, common::ObIArray& directions) { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null stmt", K(ret)); } else { const ObIArray& conditions = get_stmt()->get_condition_exprs(); int64_t N = order_items.count(); bool has_null_reject = false; for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) { OrderItem& order_item = order_items.at(i); if (OB_ISNULL(order_item.expr_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null expr", K(ret), K(order_item.expr_)); } else if (OB_FAIL(ObTransformUtils::has_null_reject_condition(conditions, order_item.expr_, has_null_reject))) { LOG_WARN("failed to check null rejection", K(ret)); } else if (has_null_reject) { if (is_ascending_direction(order_item.order_type_)) { order_item.order_type_ = default_asc_direction(); directions.at(i) = order_item.order_type_; } else { order_item.order_type_ = default_desc_direction(); directions.at(i) = order_item.order_type_; } } } } return ret; } int ObLogPlan::need_alloc_child_for_subplan_filter(ObLogicalOperator* root, ObLogPlan* sub_plan, bool& need) { int ret = OB_SUCCESS; need = true; if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("root is null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && need && i < root->get_num_of_child(); ++i) { if (log_op_def::LOG_SUBPLAN_FILTER == root->get_type() && i > 0) { if (OB_ISNULL(root->get_child(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("root->get_child(i) is null", K(ret), K(i)); } else if (root->get_child(i)->get_plan() == sub_plan) { need = false; } else { /* Do nothing */ } } else { /* Do nothing */ } } for (int64_t i = 0; OB_SUCC(ret) && need && i < root->get_num_of_child(); ++i) { if (OB_FAIL(need_alloc_child_for_subplan_filter(root->get_child(i), sub_plan, need))) { LOG_WARN("need_alloc_subfilter fails", K(ret), K(need)); } else { /* Do nothing */ } } } return ret; } int ObLogPlan::allocate_subplan_filter_as_below(common::ObIArray& exprs, ObLogicalOperator* top_node) { int ret = OB_SUCCESS; ObLogicalOperator* first_child = NULL; ObSEArray subquery_exprs; if (OB_ISNULL(top_node) || OB_ISNULL(first_child = top_node->get_child(ObLogicalOperator::first_child))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(top_node), K(first_child)); } else if (OB_FAIL(ObOptimizerUtil::get_subquery_exprs(exprs, subquery_exprs))) { LOG_WARN("failed to get subquery exprs", K(ret)); } else if (subquery_exprs.empty()) { /*do nothing*/ } else if (OB_FAIL(allocate_subplan_filter_as_top(subquery_exprs, false, first_child))) { LOG_WARN("failed to allocate subplan filter", K(ret)); } else if (OB_ISNULL(first_child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(first_child), K(ret)); } else { top_node->set_child(0, first_child); } return ret; } int ObLogPlan::candi_allocate_count() { int ret = OB_SUCCESS; ObRawExpr* limit_expr = NULL; ObSEArray filter_exprs; ObSEArray start_exprs; ObSEArray subquery_exprs; if (OB_FAIL(ObOptimizerUtil::get_subquery_exprs(get_rownum_exprs(), subquery_exprs))) { LOG_WARN("failed to get subquery exprs", K(ret)); } else if (!subquery_exprs.empty() && OB_FAIL(candi_allocate_subplan_filter(subquery_exprs, false))) { LOG_WARN("failed to allocate subplan filter", K(ret)); } else if (OB_FAIL(classify_rownum_exprs(get_rownum_exprs(), filter_exprs, start_exprs, limit_expr))) { LOG_WARN("failed to classify rownum exprs", K(ret)); } else { double min_cost = 0.0; int64_t min_idx = OB_INVALID_INDEX; for (int64_t i = 0; OB_SUCC(ret) && i < candidates_.candidate_plans_.count(); ++i) { CandidatePlan& plain_plan = candidates_.candidate_plans_.at(i); if (OB_FAIL(allocate_count_as_top(plain_plan.plan_tree_, filter_exprs, start_exprs, limit_expr))) { LOG_WARN("failed to allocate count operator", K(ret)); } else if (OB_ISNULL(plain_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null plan tree", K(ret)); } else if (plain_plan.plan_tree_->get_cost() < min_cost || OB_INVALID_INDEX == min_idx) { min_cost = plain_plan.plan_tree_->get_cost(); min_idx = i; } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (OB_UNLIKELY(OB_INVALID_INDEX == min_idx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Min idx is invalid", K(ret), K(min_idx)); } else { candidates_.plain_plan_.second = min_idx; candidates_.plain_plan_.first = min_cost; } } } return ret; } int ObLogPlan::allocate_count_as_top(ObLogicalOperator*& old_top, const common::ObIArray& filter_exprs, const common::ObIArray& start_exprs, ObRawExpr* limit_expr) { int ret = OB_SUCCESS; ObLogCount* count = NULL; if (OB_ISNULL(old_top) || OB_ISNULL(get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected null stmt", K(ret), K(old_top), K(get_stmt())); } else if (OB_ISNULL(count = static_cast(get_log_op_factory().allocate(*this, LOG_COUNT)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("Allocate memory for ObLogCount Failed", K(ret)); } else if (OB_FAIL(append(count->get_filter_exprs(), filter_exprs))) { LOG_WARN("failed to append filter exprs", K(ret)); } else if (OB_FAIL(append(count->get_startup_exprs(), start_exprs))) { LOG_WARN("failed to append start up exprs", K(ret)); } else { count->set_rownum_limit_expr(limit_expr); count->set_child(ObLogicalOperator::first_child, old_top); // set cost and card if (OB_FAIL(count->set_limit_size())) { LOG_WARN("set limit size error", K(ret)); } else if (OB_FAIL(count->compute_property())) { LOG_WARN("failed to compute property"); } else { old_top = count; } } return ret; } int ObLogPlan::classify_rownum_exprs(const ObIArray& rownum_exprs, ObIArray& filter_exprs, ObIArray& start_exprs, ObRawExpr*& limit_expr) { int ret = OB_SUCCESS; ObItemType limit_rownum_type = T_INVALID; limit_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < rownum_exprs.count(); i++) { ObRawExpr *rownum_expr = rownum_exprs.at(i); ObRawExpr *dummy = NULL; ObRawExpr *const_expr = NULL; ObItemType expr_type = T_INVALID; bool dummy_flag = false; if (OB_FAIL(ObOptimizerUtil::get_rownum_filter_info( rownum_expr, expr_type, dummy, const_expr, dummy_flag))) { LOG_WARN("failed to check is rownum expr used as filter", K(ret)); } else if (OB_FAIL( classify_rownum_expr(expr_type, rownum_expr, const_expr, filter_exprs, start_exprs, limit_expr))) { LOG_WARN("failed to classify rownum expr", K(ret)); } else if (const_expr == limit_expr) { limit_rownum_type = expr_type; } } if (OB_SUCC(ret) && OB_NOT_NULL(limit_expr)) { ObRawExpr* limit_int_expr = NULL; if (OB_FAIL(ObOptimizerUtil::convert_rownum_filter_as_limit(get_optimizer_context().get_expr_factory(), get_optimizer_context().get_session_info(), limit_rownum_type, limit_expr, limit_int_expr))) { LOG_WARN("failed to transform rownum filter as limit", K(ret)); } else { limit_expr = limit_int_expr; } } if (OB_SUCC(ret)) { LOG_TRACE("succeed to classify rownum exprs", K(filter_exprs.count()), K(start_exprs.count()), K(limit_expr)); } return ret; } int ObLogPlan::classify_rownum_expr(const ObItemType expr_type, ObRawExpr* rownum_expr, ObRawExpr* left_const_expr, common::ObIArray& filter_exprs, common::ObIArray& start_exprs, ObRawExpr*& limit_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(rownum_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(rownum_expr), K(ret)); } else if ((expr_type == T_OP_LE || expr_type == T_OP_LT) && NULL == limit_expr && NULL != left_const_expr) { limit_expr = left_const_expr; } else if (expr_type == T_OP_GE || expr_type == T_OP_GT) { if (OB_FAIL(start_exprs.push_back(rownum_expr))) { LOG_WARN("failed to push back rownum expr", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(filter_exprs.push_back(rownum_expr))) { LOG_WARN("failed to push back rownum expr", K(ret)); } else { /*do nothing*/ } } return ret; } int ObLogPlan::get_base_table_ids(ObIArray& dependency_tables) const { int ret = OB_SUCCESS; const ObDMLStmt* stmt = NULL; const ObQueryCtx* query_ctx = NULL; if (OB_ISNULL(stmt = get_stmt()) || OB_ISNULL(query_ctx = stmt->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is invalid", K(stmt), K(query_ctx)); } ARRAY_FOREACH(query_ctx->table_partition_infos_, i) { const ObTablePartitionInfo* tbl_info = query_ctx->table_partition_infos_.at(i); if (OB_ISNULL(tbl_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("tbl_info is null"); } else if (OB_FAIL(dependency_tables.push_back(tbl_info->get_ref_table_id()))) { LOG_WARN("store dependency table failed", K(ret)); } } return ret; } int ObLogPlan::remove_duplicate_constraint(ObLocationConstraintContext& location_constraint, ObSqlCtx& sql_ctx) const { int ret = OB_SUCCESS; if (OB_FAIL(remove_duplicate_base_table_constraint(location_constraint))) { LOG_WARN("failed to remove duplicate base table constraint", K(ret)); } else if (OB_FAIL(remove_duplicate_pwj_constraint(location_constraint.strict_constraints_))) { LOG_WARN("failed to remove duplicate strict pwj constraint", K(ret)); } else if (OB_FAIL(remove_duplicate_pwj_constraint(location_constraint.non_strict_constraints_))) { LOG_WARN("failed to remove duplicate strict pwj constraint", K(ret)); } else if (OB_FAIL(sort_pwj_constraint(location_constraint))) { LOG_WARN("failed to sort pwj constraint", K(ret)); } else if (OB_FAIL(sql_ctx.set_location_constraints(location_constraint, get_allocator()))) { LOG_WARN("failed to set location constraints", K(ret)); } else { LOG_TRACE("duplicated constraints removed", K(location_constraint)); } return ret; } int ObLogPlan::remove_duplicate_base_table_constraint(ObLocationConstraintContext& location_constraint) const { int ret = OB_SUCCESS; ObLocationConstraint& base_constraints = location_constraint.base_table_constraints_; ObLocationConstraint unique_constraint; for (int64_t i = 0; OB_SUCC(ret) && i < base_constraints.count(); ++i) { bool find = false; int64_t j = 0; for (/* do nothing */; !find && j < unique_constraint.count(); ++j) { if (base_constraints.at(i) == unique_constraint.at(j)) { find = true; } } if (find) { --j; if (OB_FAIL(replace_pwj_constraints(location_constraint.strict_constraints_, i, j))) { LOG_WARN("failed to replace pwj constraints", K(ret)); } else if (OB_FAIL(replace_pwj_constraints(location_constraint.non_strict_constraints_, i, j))) { LOG_WARN("failed to replace pwj constraints", K(ret)); } } else if (OB_FAIL(unique_constraint.push_back(base_constraints.at(i)))) { LOG_WARN("failed to push back location constraint", K(ret)); // do nothing } } if (OB_SUCC(ret) && unique_constraint.count() != base_constraints.count()) { if (OB_FAIL(base_constraints.assign(unique_constraint))) { LOG_WARN("failed to assign base constraints", K(ret)); } LOG_TRACE("inner duplicates removed", K(location_constraint)); } return ret; } int ObLogPlan::replace_pwj_constraints( ObIArray& constraints, const int64_t from, const int64_t to) const { int ret = OB_SUCCESS; ObPwjConstraint* cur_cons = NULL; ObSEArray new_constraints; for (int64_t i = 0; OB_SUCC(ret) && i < constraints.count(); ++i) { if (OB_ISNULL(cur_cons = constraints.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < cur_cons->count(); ++j) { if (from == cur_cons->at(j)) { if (OB_FAIL(cur_cons->remove(j))) { LOG_WARN("failed to remove item", K(ret)); } else if (OB_FAIL(add_var_to_array_no_dup(*cur_cons, to))) { LOG_WARN("failed to add var to array no dup"); } } } if (OB_SUCC(ret)) { if (cur_cons->count() > 1 && OB_FAIL(new_constraints.push_back(cur_cons))) { LOG_WARN("failed to push back pwj constraint", K(ret)); } } } if (OB_SUCC(ret) && new_constraints.count() < constraints.count()) { if (OB_FAIL(constraints.assign(new_constraints))) { LOG_WARN("failed to assign new constraints", K(ret)); } } return ret; } int ObLogPlan::remove_duplicate_pwj_constraint(ObIArray& pwj_constraints) const { int ret = OB_SUCCESS; ObPwjConstraint *l_cons = NULL, *r_cons = NULL; ObBitSet<> removed_idx; ObLocationConstraintContext::InclusionType inclusion_result = ObLocationConstraintContext::NotSubset; for (int64_t i = 0; OB_SUCC(ret) && i < pwj_constraints.count(); ++i) { if (OB_ISNULL(l_cons = pwj_constraints.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(i)); } else if (l_cons->count() < 2) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected constraint const", K(ret), K(*l_cons)); } else if (removed_idx.has_member(i)) { // do nothing } else { for (int64_t j = i + 1; OB_SUCC(ret) && j < pwj_constraints.count(); ++j) { if (OB_ISNULL(r_cons = pwj_constraints.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(j)); } else if (OB_FAIL(ObLocationConstraintContext::calc_constraints_inclusion(l_cons, r_cons, inclusion_result))) { LOG_WARN("failed to calculate inclusion relation between constraints", K(ret), K(*l_cons), K(*r_cons)); } else if (ObLocationConstraintContext::LeftIsSuperior == inclusion_result) { // Left containts all the elements of the right, remove j if (OB_FAIL(removed_idx.add_member(j))) { LOG_WARN("failed to add member", K(ret), K(j)); } } else if (ObLocationConstraintContext::RightIsSuperior == inclusion_result) { // Right containts all the elements of the left, remove i if (OB_FAIL(removed_idx.add_member(i))) { LOG_WARN("failed to add member", K(ret), K(i)); } } } } } // get unique pwj constraints if (OB_SUCC(ret) && !removed_idx.is_empty()) { ObSEArray tmp_constraints; if (OB_FAIL(tmp_constraints.assign(pwj_constraints))) { LOG_WARN("failed to assign strict constraints", K(ret)); } else { pwj_constraints.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < tmp_constraints.count(); ++i) { if (!removed_idx.has_member(i) && OB_FAIL(pwj_constraints.push_back(tmp_constraints.at(i)))) { LOG_WARN("failed to push back pwj constraint", K(ret)); } } } } return ret; } int ObLogPlan::set_all_exprs(const ObAllocExprContext& ctx) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < ctx.expr_producers_.count(); i++) { const ObRawExpr* expr = ctx.expr_producers_.at(i).expr_; OZ(all_exprs_.append(const_cast(expr))); } for (int64_t i = 0; OB_SUCC(ret) && i < ctx.group_replaced_exprs_.count(); i++) { ObRawExpr* expr = ctx.group_replaced_exprs_.at(i).first; OZ(all_exprs_.append(expr)); expr = ctx.group_replaced_exprs_.at(i).second; OZ(all_exprs_.append(expr)); } OZ(all_exprs_.append(ctx.not_produced_exprs_.get_expr_array())); return ret; } int ObLogPlan::sort_pwj_constraint(ObLocationConstraintContext& location_constraint) const { int ret = OB_SUCCESS; ObIArray& strict_pwj_cons = location_constraint.strict_constraints_; ObIArray& non_strict_pwj_cons = location_constraint.non_strict_constraints_; ObPwjConstraint* cur_cons = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < strict_pwj_cons.count(); ++i) { if (OB_ISNULL(cur_cons = strict_pwj_cons.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(i)); } else { std::sort(&cur_cons->at(0), &cur_cons->at(0) + cur_cons->count()); } } for (int64_t i = 0; OB_SUCC(ret) && i < non_strict_pwj_cons.count(); ++i) { if (OB_ISNULL(cur_cons = non_strict_pwj_cons.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(i)); } else { std::sort(&cur_cons->at(0), &cur_cons->at(0) + cur_cons->count()); } } return ret; } /* * * Select 1 from t2 connect by level < t2.c1; * We generate a ? expresstion from this level pseudo expr. * Why ? * The level pseudo expr result is generate by connect by join, * and 'level < t2.c1' is a other join condition. * When we generate code for this expression, we will find all input * from children' output. We can find 't2.c1', but we can't find 'level'. * This level pseudo is output of this connect by join. * So finally, we use ? expr to solve this problem. * Just generate this ? expr here, but remember not to replace. * If replace level pesudo expr to ? expr, say 'level < 5' -> '? < 5', * our optimizer will push this exprs down to the lowest level child. * Do replace at code generate. * */ int ObLogPlan::extract_level_pseudo_as_param( const ObIArray& join_condition, ObIArray>& exec_param) { int ret = OB_SUCCESS; ObDMLStmt* stmt = nullptr; ObSEArray level_exprs; ObSQLSessionInfo* session_info = nullptr; for (int64_t i = 0; i < join_condition.count() && OB_SUCC(ret); ++i) { ObRawExpr* qual = join_condition.at(i); if (OB_ISNULL(stmt = get_stmt()) || OB_ISNULL((get_optimizer_context()).get_session_info())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Null poiner passed in", K(stmt), K(ret)); } else if (OB_FAIL(find_connect_by_level(qual, level_exprs))) { LOG_WARN("Failed to find level pseudo", K(ret)); } else if (level_exprs.empty()) { // do nothing } else { ObOptimizerContext& opt_ctx = get_optimizer_context(); session_info = const_cast(opt_ctx.get_session_info()); std::pair param_expr; ObRawExpr* expr_element = level_exprs.at(0); if (OB_FAIL(ObRawExprUtils::create_exec_param_expr( stmt, opt_ctx.get_expr_factory(), expr_element, session_info, param_expr))) { LOG_WARN("Create param for stmt error in extract_params_for_stmt", K(ret)); } else if (FALSE_IT(param_expr.second = expr_element)) { } else if (OB_FAIL(exec_param.push_back(param_expr))) { LOG_WARN("Failed to push back param expr", K(ret)); } else { LOG_TRACE("Get a level pseudo as param", K(param_expr.first), K(*param_expr.second), K(*expr_element)); break; } } } return ret; } int ObLogPlan::find_connect_by_level(ObRawExpr* qual, ObIArray& level_exprs) { int ret = OB_SUCCESS; ObRawConnectByLevelVisitor visitor; if (OB_FAIL(visitor.check_connectby_filter(qual, level_exprs))) { LOG_WARN("Failed to check connectby filter", K(ret)); } else { LOG_TRACE("Find level pseudo", K(level_exprs), K(ret)); } return ret; } int ObLogPlan::update_plans_interesting_order_info(ObIArray& candidate_plans, const int64_t check_scope) { int ret = OB_SUCCESS; int64_t match_info = OrderingFlag::NOT_MATCH; if (check_scope == OrderingCheckScope::NOT_CHECK) { // do nothing } else { for (int64_t i = 0; OB_SUCC(ret) && i < candidate_plans.count(); i++) { CandidatePlan& candidate_plan = candidate_plans.at(i); if (OB_ISNULL(candidate_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::compute_stmt_interesting_order(candidate_plan.plan_tree_->get_op_ordering(), get_stmt(), get_is_subplan_scan(), get_equal_sets(), get_const_exprs(), check_scope, match_info))) { LOG_WARN("failed to update ordering match info", K(ret)); } else { candidate_plan.plan_tree_->set_interesting_order_info(match_info); } } } return ret; } int ObLogPlan::prune_and_keep_best_plans(ObIArray& candidate_plans) { int ret = OB_SUCCESS; candidates_.candidate_plans_.reset(); double min_cost = 0.0; int64_t min_idx = OB_INVALID_INDEX; for (int64_t i = 0; OB_SUCC(ret) && i < candidate_plans.count(); i++) { CandidatePlan& candidate_plan = candidate_plans.at(i); if (OB_FAIL(add_candidate_plan(candidates_.candidate_plans_, candidate_plan))) { LOG_WARN("failed to add candidate plan", K(ret)); } else { /*do nothing*/ } } for (int64_t i = 0; OB_SUCC(ret) && i < candidates_.candidate_plans_.count(); i++) { CandidatePlan& candidate_plan = candidates_.candidate_plans_.at(i); if (min_idx == OB_INVALID_INDEX || candidate_plan.plan_tree_->get_cost() < min_cost) { min_idx = i; min_cost = candidate_plan.plan_tree_->get_cost(); } else { /*do nothing */ } } if (OB_SUCC(ret)) { if (OB_UNLIKELY(min_idx == OB_INVALID_INDEX)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Min idx is invalid", K(ret), K(min_idx)); } else { candidates_.plain_plan_.second = min_idx; candidates_.plain_plan_.first = min_cost; candidates_.first_new_op_ = NULL; } } return ret; } int ObLogPlan::add_candidate_plan(ObIArray& current_plans, const CandidatePlan& new_plan) { int ret = OB_SUCCESS; bool should_add = true; PlanRelationship plan_rel = UNCOMPARABLE; for (int64_t i = current_plans.count() - 1; OB_SUCC(ret) && should_add && i >= 0; --i) { if (OB_FAIL(compute_plan_relationship(current_plans.at(i), new_plan, plan_rel))) { LOG_WARN("failed to compute plan relationship", K(current_plans.at(i)), K(new_plan), K(ret)); } else if (LEFT_DOMINATED == plan_rel || EQUAL == plan_rel) { should_add = false; } else if (RIGHT_DOMINATED == plan_rel) { if (OB_FAIL(current_plans.remove(i))) { LOG_WARN("failed to remove dominated plans", K(i), K(ret)); } else { /* do nothing*/ } } else { /* do nothing */ } } if (OB_SUCC(ret)) { if (should_add) { if (OB_FAIL(current_plans.push_back(new_plan))) { LOG_WARN("failed to add plan", K(ret)); } else { /*do nothing*/ } } else { /*do nothing*/ } } return ret; } int ObLogPlan::compute_plan_relationship( const CandidatePlan& first_plan, const CandidatePlan& second_plan, PlanRelationship& plan_rel) { int ret = OB_SUCCESS; plan_rel = UNCOMPARABLE; const ObDMLStmt* stmt = get_stmt(); if (OB_ISNULL(stmt) || OB_ISNULL(first_plan.plan_tree_) || OB_ISNULL(second_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(stmt), K(first_plan.plan_tree_), K(second_plan.plan_tree_), K(ret)); } else { int64_t left_dominated_count = 0; int64_t right_dominated_count = 0; int64_t uncompareable_count = 0; // compare cost if (fabs(first_plan.plan_tree_->get_cost() - second_plan.plan_tree_->get_cost()) < OB_DOUBLE_EPSINON) { // do nothing } else if (first_plan.plan_tree_->get_cost() < second_plan.plan_tree_->get_cost()) { left_dominated_count++; } else { right_dominated_count++; } // compare interesting bool left_prefix = false; bool right_prefix = false; const EqualSets& equal_sets = first_plan.plan_tree_->get_ordering_output_equal_sets(); bool first_has_interesting_order = first_plan.plan_tree_->has_any_interesting_order_info_flag(); bool second_has_interesting_order = second_plan.plan_tree_->has_any_interesting_order_info_flag(); if (!first_has_interesting_order && !second_has_interesting_order) { // do nothing } else if (first_has_interesting_order && !second_has_interesting_order) { left_dominated_count++; } else if (!first_has_interesting_order && second_has_interesting_order) { right_dominated_count++; } else { if (OB_FAIL(ObOptimizerUtil::is_prefix_ordering(first_plan.plan_tree_->get_op_ordering(), second_plan.plan_tree_->get_op_ordering(), equal_sets, get_const_exprs(), left_prefix))) { LOG_WARN("failed to compute prefix ordering relationship", K(ret), K(first_plan.plan_tree_->get_op_ordering()), K(second_plan.plan_tree_->get_op_ordering())); } else if (OB_FAIL(ObOptimizerUtil::is_prefix_ordering(second_plan.plan_tree_->get_op_ordering(), first_plan.plan_tree_->get_op_ordering(), equal_sets, get_const_exprs(), right_prefix))) { LOG_WARN("failed to compute prefix ordering relationship", K(ret), K(first_plan.plan_tree_->get_op_ordering()), K(second_plan.plan_tree_->get_op_ordering())); } else if (left_prefix && right_prefix) { // do nothing } else if (left_prefix) { right_dominated_count++; } else if (right_prefix) { left_dominated_count++; } else { uncompareable_count++; } } bool is_first_pipeline = false; bool is_second_pipeline = false; // compare pipeline operator if (OB_SUCC(ret) && stmt->has_limit()) { if (OB_FAIL(is_pipeline_operator(first_plan, is_first_pipeline))) { LOG_WARN("failed to examine pipeline operator", K(first_plan), K(ret)); } else if (OB_FAIL(is_pipeline_operator(second_plan, is_second_pipeline))) { LOG_WARN("failed to examine pipeline operator", K(second_plan), K(ret)); } else if (is_first_pipeline == is_second_pipeline) { // do nothing } else if (is_first_pipeline && !is_second_pipeline) { left_dominated_count++; } else { right_dominated_count++; } } // compute final result if (OB_SUCC(ret)) { ObLogicalOperator* first = first_plan.plan_tree_; ObLogicalOperator* second = second_plan.plan_tree_; if (left_dominated_count > 0 && right_dominated_count == 0 && uncompareable_count == 0) { plan_rel = LEFT_DOMINATED; LOG_TRACE("first dominated second", K(first->get_cost()), K(first->get_op_ordering()), K(is_first_pipeline), K(second->get_cost()), K(second->get_op_ordering()), K(is_second_pipeline)); } else if (right_dominated_count > 0 && left_dominated_count == 0 && uncompareable_count == 0) { plan_rel = RIGHT_DOMINATED; LOG_TRACE("second dominated first", K(second->get_cost()), K(second->get_op_ordering()), K(is_second_pipeline), K(first->get_cost()), K(first->get_op_ordering()), K(is_first_pipeline)); } else if (left_dominated_count == 0 && right_dominated_count == 0 && uncompareable_count == 0) { plan_rel = EQUAL; } else { plan_rel = UNCOMPARABLE; } } } return ret; } int ObLogPlan::is_pipeline_operator(const CandidatePlan& first_plan, bool& is_pipeline) { int ret = OB_SUCCESS; is_pipeline = false; // todo set op ? if (OB_ISNULL(first_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null operator", K(ret)); } else if (first_plan.plan_tree_->get_type() == LOG_GROUP_BY) { ObLogGroupBy* group_by = static_cast(first_plan.plan_tree_); ObLogicalOperator* child = group_by->get_child(0); if (OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null child operator", K(ret)); } else if (MERGE_AGGREGATE == group_by->get_algo() && LOG_SORT != child->get_type()) { is_pipeline = true; } else { is_pipeline = false; } } else if (first_plan.plan_tree_->get_type() == LOG_DISTINCT) { ObLogDistinct* distinct = static_cast(first_plan.plan_tree_); ObLogicalOperator* child = distinct->get_child(0); if (OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null child operator", K(ret)); } else if (MERGE_AGGREGATE == distinct->get_algo() && LOG_SORT == child->get_type()) { is_pipeline = false; } else { is_pipeline = true; } } else if (first_plan.plan_tree_->get_type() == LOG_WINDOW_FUNCTION) { ObLogicalOperator* child = first_plan.plan_tree_->get_child(0); if (OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(child)); } else if (LOG_SORT == child->get_type()) { is_pipeline = false; } else { is_pipeline = true; } } else if (first_plan.plan_tree_->get_type() == LOG_SORT || first_plan.plan_tree_->get_type() == LOG_MATERIAL) { is_pipeline = false; } else { is_pipeline = true; } return ret; } int ObLogPlan::calc_plan_resource() { int ret = OB_SUCCESS; const ObDMLStmt* stmt = nullptr; ObLogicalOperator* plan_root = nullptr; int64_t max_parallel_thread_group_count = 0; if (OB_ISNULL(stmt = get_stmt()) || OB_ISNULL(plan_root = get_plan_root())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { ObPxResourceAnalyzer analyzer; if (OB_FAIL(analyzer.analyze(*plan_root, max_parallel_thread_group_count))) { LOG_WARN("fail analyze px stmt thread group reservation count", K(ret)); } else { LOG_TRACE("max parallel thread group count", K(max_parallel_thread_group_count)); set_expected_worker_count(max_parallel_thread_group_count); } } return ret; } // calculate whether all partitions in same server int ObLogPlan::is_partition_in_same_server(const ObIArray& phy_location_infos, bool& is_same, bool& multi_part_table, ObAddr& first_addr) { int ret = OB_SUCCESS; int64_t phy_location_count = phy_location_infos.count(); if (phy_location_count > 0) { bool is_first = true; ObReplicaLocation replica_location; for (int64_t i = 0; OB_SUCC(ret) && is_same && i < phy_location_count; ++i) { int64_t partition_location_count = phy_location_infos.at(i)->get_partition_cnt(); if (partition_location_count >= 2 && !multi_part_table) { multi_part_table = true; } if (partition_location_count > 0) { for (int64_t j = 0; OB_SUCC(ret) && is_same && j < partition_location_count; ++j) { replica_location.reset(); const ObPhyPartitionLocationInfo& phy_part_loc_info = phy_location_infos.at(i)->get_phy_part_loc_info_list().at(j); if (OB_FAIL(phy_part_loc_info.get_selected_replica(replica_location))) { LOG_WARN("fail to get selected replica", K(ret), K(phy_part_loc_info)); } else if (!replica_location.is_valid()) { LOG_WARN("replica_location is invalid", K(ret), K(replica_location)); } else { if (is_first) { // get first replica first_addr = replica_location.server_; is_same = true; is_first = false; LOG_TRACE("part_location first replica", K(ret), K(replica_location)); } else { is_same = (replica_location.server_ == first_addr); LOG_TRACE("part_location replica", K(ret), K(i), K(replica_location)); } } } } else { LOG_DEBUG("there is no partition_locattion in this phy_location", KP(phy_location_infos.at(i))); } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("phy_locations is empty"); } return ret; } int ObLogPlan::collect_partition_location_info( ObLogicalOperator* root, ObIArray& phy_tbl_loc_info_list) { int ret = OB_SUCCESS; int64_t child_count = root->get_num_of_child(); if (child_count != 0) { for (int64_t i = 0; i < child_count && OB_SUCC(ret); ++i) { if (OB_FAIL(collect_partition_location_info(root->get_child(i), phy_tbl_loc_info_list))) { LOG_WARN("fail to get use px", K(ret)); } } } if (OB_SUCC(ret) && LOG_TABLE_SCAN == root->get_type()) { ObLogTableScan* tsc = static_cast(root); const ObTablePartitionInfo* tbl_part_info = tsc->get_table_partition_info(); if (OB_FAIL(phy_tbl_loc_info_list.push_back(&tbl_part_info->get_phy_tbl_location_info()))) { LOG_WARN("fail to push back phy tble loc info", K(ret), K(tbl_part_info->get_phy_tbl_location_info())); } } if (OB_SUCC(ret) && root->is_dml_operator()) { ObLogDelUpd* dml = static_cast(root); const ObTablePartitionInfo* tbl_part_info = &dml->get_table_partition_info(); if (OB_FAIL(phy_tbl_loc_info_list.push_back(&tbl_part_info->get_phy_tbl_location_info()))) { LOG_WARN("fail to push back phy tble loc info", K(ret), K(tbl_part_info->get_phy_tbl_location_info())); } } return ret; } int ObLogPlan::get_max_table_dop_for_plan(ObLogicalOperator* root, bool& disable_table_dop, int64_t& max_table_dop) { int ret = OB_SUCCESS; if (disable_table_dop) { max_table_dop = 1; } else if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("log op is null", K(ret)); } else { log_op_def::ObLogOpType op_type = root->get_type(); if (op_type == log_op_def::LOG_TABLE_SCAN || op_type == log_op_def::LOG_MV_TABLE_SCAN || op_type == log_op_def::LOG_TABLE_LOOKUP || op_type == log_op_def::LOG_INSERT || op_type == log_op_def::LOG_MERGE) { uint64_t index_id = OB_INVALID_ID; if (op_type == log_op_def::LOG_TABLE_LOOKUP) { // LOOK UP ObLogTableLookup* look_up = static_cast(root); index_id = look_up->get_index_id(); } else if (op_type == log_op_def::LOG_TABLE_SCAN || op_type == log_op_def::LOG_MV_TABLE_SCAN) { // SCAN ObLogTableScan* table_scan = static_cast(root); index_id = table_scan->get_index_table_id(); } else { // INSERT, MERGE ObLogDelUpd* dml = static_cast(root); index_id = dml->get_index_tid(); } ObSchemaGetterGuard* schema_guard = NULL; const ObTableSchema* table_schema = NULL; if (index_id == OB_INVALID_ID) { ret = OB_ERR_UNEXPECTED; LOG_WARN("the index id is invalid", K(ret)); } else if (OB_ISNULL(schema_guard = get_optimizer_context().get_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("schema guard is null", K(ret)); } else if (is_link_table_id(index_id)) { max_table_dop = 1; disable_table_dop = true; LOG_TRACE("due to the existence of link table, table dop is disable", K(ret), K(root->get_op_id())); } else if (is_cte_table(index_id)) { max_table_dop = 1; disable_table_dop = true; LOG_TRACE("due to the existence of cte table, table dop is disable", K(ret), K(root->get_op_id())); } else if (OB_FAIL(schema_guard->get_table_schema(index_id, table_schema))) { LOG_WARN("failed get table schema", K(ret), K(index_id)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("the table schema is null", K(ret), K(index_id)); } else if (table_schema->get_dop() > max_table_dop) { max_table_dop = table_schema->get_dop(); } } for (int i = 0; i < root->get_num_of_child() && OB_SUCC(ret) && !disable_table_dop; i++) { ObLogicalOperator* child = root->get_child(i); if (OB_FAIL(get_max_table_dop_for_plan(child, disable_table_dop, max_table_dop))) { LOG_WARN("failed to get max table dop", K(ret)); } } } return ret; } int ObLogPlan::init_plan_info() { int ret = OB_SUCCESS; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(get_stmt()), K(ret)); } else if (OB_FAIL(get_stmt()->get_stmt_equal_sets(equal_sets_, allocator_, false, EQUAL_SET_SCOPE::SCOPE_WHERE))) { LOG_WARN("failed to get stmt equal sets", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(get_stmt()->get_condition_exprs(), get_const_exprs()))) { LOG_WARN("failed to compute const equivalent exprs", K(ret)); } else { /*do nothing*/ } return ret; } EqualSets* ObLogPlan::create_equal_sets() { EqualSets* esets = NULL; void* ptr = NULL; if (OB_LIKELY(NULL != (ptr = get_allocator().alloc(sizeof(EqualSets))))) { esets = new (ptr) EqualSets(); } return esets; } ObEstSelInfo* ObLogPlan::create_est_sel_info(ObLogicalOperator* op) { void* ptr = NULL; ObEstSelInfo* est_sel_info = NULL; if (OB_LIKELY(NULL != (ptr = get_allocator().alloc(sizeof(ObEstSelInfo))))) { est_sel_info = new (ptr) ObEstSelInfo(get_optimizer_context(), get_stmt(), op); } return est_sel_info; } ObJoinOrder* ObLogPlan::create_join_order(PathType type) { void* ptr = NULL; ObJoinOrder* join_order = NULL; if (OB_LIKELY(NULL != (ptr = get_allocator().alloc(sizeof(ObJoinOrder))))) { join_order = new (ptr) ObJoinOrder(&get_allocator(), this, type); } return join_order; } int ObLogPlan::check_enable_plan_expiration(bool& enable) const { int ret = OB_SUCCESS; ObSQLSessionInfo* session = NULL; bool use_acs = false; bool use_spm = false; enable = false; if (OB_ISNULL(get_stmt()) || OB_ISNULL(session = optimizer_context_.get_session_info())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else if (!get_stmt()->is_select_stmt()) { // do nothing } else if (OB_FAIL(session->get_adaptive_cursor_sharing(use_acs))) { LOG_WARN("failed to check is acs enabled", K(ret)); } else if (use_acs) { // do nothing } else if (OB_FAIL(session->get_use_plan_baseline(use_spm))) { LOG_WARN("failed to check is spm enabled", K(ret)); } else if (use_spm) { // do nothing } else if (get_phy_plan_type() != OB_PHY_PLAN_LOCAL && get_phy_plan_type() != OB_PHY_PLAN_DISTRIBUTED) { // do nothing } else { enable = true; } return ret; } bool ObLogPlan::need_consistent_read() const { bool bret = true; if (OB_NOT_NULL(root_) && OB_NOT_NULL(get_stmt()) && OB_NOT_NULL(get_stmt()->get_query_ctx())) { if (stmt::T_INSERT == get_stmt()->get_stmt_type()) { const ObInsertStmt* insert_stmt = static_cast(get_stmt()); if (!insert_stmt->is_replace() && !insert_stmt->get_insert_up()) { uint64_t insert_table_id = insert_stmt->get_insert_table_id(); const ObQueryCtx* query_ctx = get_stmt()->get_query_ctx(); bool found_other_table = false; for (int64_t i = 0; !found_other_table && i < query_ctx->table_partition_infos_.count(); ++i) { ObTablePartitionInfo* part_info = query_ctx->table_partition_infos_.at(i); if (OB_NOT_NULL(part_info) && part_info->get_table_id() != insert_table_id) { found_other_table = true; } } bret = found_other_table; } } } return bret; } int ObLogPlan::check_fullfill_safe_update_mode(ObLogicalOperator* op) { int ret = OB_SUCCESS; bool is_sql_safe_updates = false; bool is_not_fullfill = false; const ObSQLSessionInfo* session_info = NULL; if (OB_ISNULL(session_info = get_optimizer_context().get_session_info())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(get_optimizer_context().get_session_info())); } else if (OB_FAIL(session_info->get_sql_safe_updates(is_sql_safe_updates))) { LOG_WARN("failed to get is safe update mode", K(ret)); } else if (!is_sql_safe_updates) { /*do nothing*/ } else if (OB_FAIL(do_check_fullfill_safe_update_mode(op, is_not_fullfill))) { LOG_WARN("failed to check fullfill safe update mode", K(ret)); } else if (is_not_fullfill) { ret = OB_ERR_SAFE_UPDATE_MODE_NEED_WHERE_OR_LIMIT; LOG_WARN("using safe update mode need WHERE or LIMIT", K(ret)); } return ret; } int ObLogPlan::do_check_fullfill_safe_update_mode(ObLogicalOperator* op, bool& is_not_fullfill) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(op), K(ret)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else if (is_not_fullfill) { /*do nothing*/ } else if (op->get_type() == log_op_def::LOG_TABLE_SCAN) { ObLogTableScan* table_scan = static_cast(op); is_not_fullfill |= table_scan->is_whole_range_scan(); } else { for (int64_t i = 0; OB_SUCC(ret) && !is_not_fullfill && i < op->get_num_of_child(); ++i) { if (OB_FAIL(do_check_fullfill_safe_update_mode(op->get_child(i), is_not_fullfill))) { LOG_WARN("failed to check fullfill safe update mode", K(ret)); } } } return ret; } int ObLogPlan::calc_and_set_exec_pwj_map(ObLocationConstraintContext& location_constraint) const { int ret = OB_SUCCESS; ObExecContext* exec_ctx = get_optimizer_context().get_exec_ctx(); if (OB_ISNULL(exec_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (location_constraint.strict_constraints_.count() > 0 || location_constraint.non_strict_constraints_.count() > 0) { ObIArray& base_location_cons = location_constraint.base_table_constraints_; ObIArray& strict_cons = location_constraint.strict_constraints_; ObIArray& non_strict_cons = location_constraint.non_strict_constraints_; const int64_t tbl_count = location_constraint.base_table_constraints_.count(); ObSEArray pwj_tables; ObPwjComparer strict_pwj_comparer(true); ObPwjComparer non_strict_pwj_comparer(false); PWJPartitionIdMap pwj_map; if (OB_FAIL(pwj_tables.prepare_allocate(tbl_count))) { LOG_WARN("failed to prepare allocate pwj tables", K(ret)); } else if (OB_FAIL(pwj_map.create(8, ObModIds::OB_PLAN_EXECUTE))) { LOG_WARN("create pwj map failed", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < tbl_count; ++i) { for (int64_t j = 0; OB_SUCC(ret) && j < strict_cons.count(); ++j) { const ObPwjConstraint* pwj_cons = strict_cons.at(j); if (OB_ISNULL(pwj_cons) || OB_UNLIKELY(pwj_cons->count() <= 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected pwj constraint", K(ret), K(pwj_cons)); } else if (pwj_cons->at(0) == i) { if (OB_FAIL(check_pwj_cons( *pwj_cons, location_constraint.base_table_constraints_, pwj_tables, strict_pwj_comparer, pwj_map))) { LOG_WARN("failed to check pwj cons", K(ret)); } } } for (int64_t j = 0; OB_SUCC(ret) && j < non_strict_cons.count(); ++j) { const ObPwjConstraint* pwj_cons = non_strict_cons.at(j); if (OB_ISNULL(pwj_cons) || OB_UNLIKELY(pwj_cons->count() <= 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected pwj constraint", K(ret), K(pwj_cons)); } else if (pwj_cons->at(0) == i) { if (OB_FAIL(check_pwj_cons(*pwj_cons, location_constraint.base_table_constraints_, pwj_tables, non_strict_pwj_comparer, pwj_map))) { LOG_WARN("failed to check pwj cons", K(ret)); } } } } if (OB_SUCC(ret)) { PWJPartitionIdMap* exec_pwj_map = NULL; if (OB_FAIL(exec_ctx->get_pwj_map(exec_pwj_map))) { LOG_WARN("failed to get exec pwj map", K(ret)); } else if (OB_FAIL(exec_pwj_map->reuse())) { LOG_WARN("failed to reuse pwj map", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < base_location_cons.count(); ++i) { if (!base_location_cons.at(i).is_multi_part_insert()) { PartitionIdArray partition_id_array; if (OB_FAIL(pwj_map.get_refactored(i, partition_id_array))) { if (OB_HASH_NOT_EXIST == ret) { ret = OB_SUCCESS; } else { LOG_WARN("failed to get refactored", K(ret)); } } else if (OB_FAIL( exec_pwj_map->set_refactored(base_location_cons.at(i).key_.table_id_, partition_id_array))) { LOG_WARN("failed to set refactored", K(ret)); } } } } if (pwj_map.created()) { int tmp_ret = OB_SUCCESS; if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = pwj_map.destroy()))) { LOG_WARN("failed to destroy pwj map", K(tmp_ret)); } } } return ret; } int64_t ObLogPlan::check_pwj_cons(const ObPwjConstraint& pwj_cons, const ObIArray& base_location_cons, ObIArray& pwj_tables, ObPwjComparer& pwj_comparer, PWJPartitionIdMap& pwj_map) const { int ret = OB_SUCCESS; bool is_same = true; ObShardingInfo* first_sharding = base_location_cons.at(pwj_cons.at(0)).sharding_info_; if (OB_ISNULL(first_sharding)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(first_sharding)); } else { if (first_sharding->is_local() || first_sharding->is_remote()) { // all tables in pwj constraint are local or remote // alreay checked, do nothing } else { // distribute partition wise join LOG_DEBUG("check pwj constraint", K(pwj_cons), K(base_location_cons), K(pwj_tables)); pwj_comparer.reset(); for (int64_t i = 0; OB_SUCC(ret) && is_same && i < pwj_cons.count(); ++i) { const int64_t table_idx = pwj_cons.at(i); PwjTable& table = pwj_tables.at(table_idx); bool need_set_refactored = false; if (OB_INVALID_ID == table.ref_table_id_) { // pwj table no init need_set_refactored = true; ObShardingInfo* cur_sharding = base_location_cons.at(table_idx).sharding_info_; if (OB_ISNULL(cur_sharding)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(table.init(*cur_sharding))) { LOG_WARN("failed to init owj table with sharding info", K(ret)); } else { table.ref_table_id_ = base_location_cons.at(table_idx).key_.ref_table_id_; } } else { // pwj table already init, should find partition id array in pwj map PartitionIdArray partition_id_array; if (OB_FAIL(pwj_map.get_refactored(table_idx, partition_id_array))) { if (OB_HASH_NOT_EXIST == ret) { LOG_WARN("get refactored not find partition id array", K(ret)); } else { LOG_WARN("failed to get refactored", K(ret)); } } else if (OB_FAIL(table.ordered_partition_ids_.assign(partition_id_array))) { LOG_WARN("failed to assign partition id array", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(pwj_comparer.add_table(table, is_same))) { LOG_WARN("failed to add table", K(ret)); } else if (!is_same) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get not same table", K(*first_sharding), K(table)); } else if (need_set_refactored && OB_FAIL(pwj_map.set_refactored(table_idx, pwj_comparer.get_partition_id_group().at(i)))) { LOG_WARN("failed to set refactored", K(ret)); } } } } } return ret; }