/** * 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 "ob_optimizer_util.h" #include "share/partition_table/ob_partition_location_cache.h" #include "share/schema/ob_column_schema.h" #include "share/schema/ob_table_schema.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/optimizer/ob_logical_operator.h" #include "sql/optimizer/ob_log_plan.h" #include "sql/optimizer/ob_opt_est_sel.h" #include "sql/engine/table/ob_table_scan.h" #include "sql/ob_sql_mock_schema_utils.h" #include "lib/ob_name_def.h" #include "common/ob_smart_call.h" #include "sql/engine/expr/ob_expr_version.h" #include "sql/rewrite/ob_transform_utils.h" using namespace oceanbase; using namespace sql; using namespace oceanbase::common; using namespace oceanbase::share::schema; using namespace oceanbase::share; int ObOptimizerUtil::is_prefix_ordering(const ObIArray& pre, const ObIArray& full, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_prefix) { int ret = OB_SUCCESS; ObSEArray pre_exprs; ObSEArray pre_directions; if (OB_FAIL(split_expr_direction(pre, pre_exprs, pre_directions))) { LOG_WARN("Failed to construct direction", K(ret)); } else if (OB_FAIL(is_prefix_ordering(pre_exprs, full, equal_sets, const_exprs, is_prefix, &pre_directions))) { LOG_WARN("Failed to check is prefix ordering", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::is_prefix_ordering(const ObIArray& pre, const ObIArray& full, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_prefix, const ObIArray* pre_directions) { int ret = OB_SUCCESS; is_prefix = false; int64_t left_match_count = 0; int64_t right_match_count = 0; if (OB_FAIL(find_common_prefix_ordering( full, pre, equal_sets, const_exprs, left_match_count, right_match_count, pre_directions))) { LOG_WARN("failed to find common prefix", K(ret)); } else if (right_match_count == pre.count()) { is_prefix = true; } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::is_prefix_ordering(const ObIArray& pre, const ObIArray& full, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_prefix, const ObIArray* full_directions) { int ret = OB_SUCCESS; is_prefix = false; int64_t left_match_count = 0; int64_t right_match_count = 0; if (OB_FAIL(find_common_prefix_ordering( pre, full, equal_sets, const_exprs, left_match_count, right_match_count, full_directions))) { LOG_WARN("failed to find common prefix", K(ret)); } else if (left_match_count == pre.count()) { is_prefix = true; } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::find_common_prefix_ordering(const ObIArray& left_side, const ObIArray& right_side, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& left_match_count, int64_t& right_match_count) { int ret = OB_SUCCESS; ObSEArray directions; ObSEArray order_by_exprs; if (OB_FAIL(split_expr_direction(right_side, order_by_exprs, directions))) { LOG_WARN("failed to split expr and directions", K(ret)); } else if (OB_FAIL(find_common_prefix_ordering(left_side, order_by_exprs, equal_sets, const_exprs, left_match_count, right_match_count, &directions))) { LOG_WARN("failed to find common prefix ordering", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::find_common_prefix_ordering(const ObIArray& left_side, const ObIArray& right_side, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& left_match_count, int64_t& right_match_count, const ObIArray* right_directions) { int ret = OB_SUCCESS; left_match_count = 0; right_match_count = 0; bool left_is_const = false; bool right_is_const = false; int64_t N = left_side.count(); int64_t M = right_side.count(); int64_t i = 0; int64_t j = 0; bool is_prefix = true; while (OB_SUCCESS == ret && is_prefix && i < N && j < M) { if ((NULL != right_directions ? left_side.at(i).order_type_ != right_directions->at(j) : false) || (!is_expr_equivalent(right_side.at(j), left_side.at(i).expr_, equal_sets))) { if (OB_FAIL(is_const_or_equivalent_expr(left_side, equal_sets, const_exprs, i, left_is_const))) { LOG_WARN("failed to check is const or equivalent exprs", K(ret)); } else if (OB_FAIL(is_const_or_equivalent_expr(right_side, equal_sets, const_exprs, j, right_is_const))) { LOG_WARN("failed to check is const or equivalent exprs", K(ret)); } else if (!left_is_const && !right_is_const) { is_prefix = false; } else { if (left_is_const) { ++i; } if (right_is_const) { ++j; } } } else { ++i; ++j; } } for (; OB_SUCC(ret) && is_prefix && i < N; i++) { if (OB_FAIL(is_const_or_equivalent_expr(left_side, equal_sets, const_exprs, i, left_is_const))) { LOG_WARN("failed to check is const or equivlent expr", K(ret)); } else if (!left_is_const) { break; } } for (; OB_SUCC(ret) && is_prefix && j < M; j++) { if (OB_FAIL(is_const_or_equivalent_expr(right_side, equal_sets, const_exprs, j, right_is_const))) { LOG_WARN("failed to check is const or equivlent expr", K(ret)); } else if (!right_is_const) { break; } } if (OB_SUCC(ret)) { left_match_count = i; right_match_count = j; LOG_TRACE("succeed to find common prefix", K(left_side), K(right_side), K(left_match_count), K(right_match_count)); } return ret; } int ObOptimizerUtil::is_const_or_equivalent_expr(const common::ObIArray& exprs, const EqualSets& equal_sets, const common::ObIArray& const_exprs, const int64_t& pos, bool& is_const) { int ret = OB_SUCCESS; is_const = false; if (OB_UNLIKELY(pos < 0 || pos >= exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid array pos", K(pos), K(exprs.count()), K(ret)); } else if (OB_ISNULL(exprs.at(pos))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexected null", K(ret)); } else if (OB_FAIL(is_const_expr(exprs.at(pos), equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check const expr", K(exprs.at(pos)), K(ret)); } else if (is_const) { /*do nothing*/ } else { for (int64_t i = 0; OB_SUCC(ret) && !is_const && i < pos; i++) { if (is_expr_equivalent(exprs.at(i), exprs.at(pos), equal_sets)) { is_const = true; } } } return ret; } int ObOptimizerUtil::is_const_or_equivalent_expr(const common::ObIArray& order_items, const EqualSets& equal_sets, const common::ObIArray& const_exprs, const int64_t& pos, bool& is_const) { int ret = OB_SUCCESS; is_const = false; if (OB_UNLIKELY(pos < 0 || pos >= order_items.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid array pos", K(pos), K(order_items.count()), K(ret)); } else if (OB_ISNULL(order_items.at(pos).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexected null", K(ret)); } else if (OB_FAIL(is_const_expr(order_items.at(pos).expr_, equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check const expr", K(order_items.at(pos).expr_), K(ret)); } else if (is_const) { /*do nothing*/ } else { for (int64_t i = 0; OB_SUCC(ret) && !is_const && i < pos; i++) { if (is_expr_equivalent(order_items.at(i).expr_, order_items.at(pos).expr_, equal_sets)) { is_const = true; } } } return ret; } int ObOptimizerUtil::prefix_subset_ids(const ObIArray& pre, const ObIArray& full, bool& is_prefix) { int ret = OB_SUCCESS; is_prefix = true; int64_t N = pre.count(); int64_t M = full.count(); if (N > M) { is_prefix = false; } else { for (int64_t i = 0; OB_SUCC(ret) && is_prefix && i < N; ++i) { bool find = false; for (int64_t j = 0; OB_SUCC(ret) && is_prefix && !find && j < N; ++j) { if (pre.at(i) == full.at(j)) { find = true; } else { is_prefix = false; } } } } return ret; } int ObOptimizerUtil::prefix_subset_exprs(const ObIArray& exprs, const ObIArray& ordering, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_covered, int64_t* match_count) { int ret = OB_SUCCESS; is_covered = false; bool is_break = false; int64_t covered_count = 0; ObBitSet<64> expr_idxs; int64_t key_covered_count = 0; for (int64_t i = 0; OB_SUCC(ret) && !is_break && i < ordering.count(); ++i) { bool is_found = false; for (int64_t j = 0; OB_SUCC(ret) && !is_found && j < exprs.count(); ++j) { if (expr_idxs.has_member(j)) { } else if (is_expr_equivalent(ordering.at(i), exprs.at(j), equal_sets)) { is_found = true; if (OB_FAIL(expr_idxs.add_member(j))) { LOG_WARN("add expr_idxs member", K(ret)); } } } if (OB_SUCC(ret) && is_found) { ++covered_count; key_covered_count = i + 1; } if (OB_SUCC(ret) && !is_found) { bool is_const = false; if (OB_FAIL(is_const_expr(ordering.at(i), equal_sets, const_exprs, is_const))) { LOG_WARN("check expr is const expr failed", K(ret)); } else if (!is_const) { is_break = true; } } } for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (expr_idxs.has_member(i)) { for (int64_t j = 0; OB_SUCC(ret) && j < exprs.count(); ++j) { if (expr_idxs.has_member(j)) { } else if (is_expr_equivalent(exprs.at(i), exprs.at(j), equal_sets)) { if (OB_FAIL(expr_idxs.add_member(j))) { LOG_WARN("add expr_idxs member", K(ret)); } else { ++covered_count; } } } } } if (OB_SUCC(ret)) { if (covered_count == exprs.count()) { is_covered = true; } if (NULL != match_count) { *match_count = key_covered_count; } } return ret; } int ObOptimizerUtil::adjust_exprs_by_ordering(ObIArray& exprs, const ObIArray& ordering, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& ordering_used, ObIArray& directions, ObIArray* match_map /*=NULL*/) { int ret = OB_SUCCESS; ObSEArray adjusted_exprs; ObSEArray order_types; ObSEArray expr_map; ObBitSet<64> expr_idxs; for (int64_t i = 0; OB_SUCC(ret) && i < ordering.count(); ++i) { const OrderItem& sort_key = ordering.at(i); bool is_found = false; for (int64_t j = 0; OB_SUCC(ret) && !is_found && j < exprs.count(); ++j) { if (expr_idxs.has_member(j)) { } else if (is_expr_equivalent(sort_key.expr_, exprs.at(j), equal_sets)) { is_found = true; ordering_used = true; if (OB_FAIL(adjusted_exprs.push_back(exprs.at(j)))) { LOG_WARN("store ordered expr failed", K(ret), K(i), K(j)); } else if (OB_FAIL(expr_map.push_back(j))) { LOG_WARN("failed to push back expr index", K(ret)); } else if (OB_FAIL(order_types.push_back(sort_key.order_type_))) { LOG_WARN("failed to push back order type"); } else if (OB_FAIL(expr_idxs.add_member(j))) { LOG_WARN("add expr idxs member failed", K(ret), K(j)); } } } if (OB_SUCC(ret) && !is_found) { bool is_const = false; if (OB_FAIL(is_const_or_equivalent_expr(ordering, equal_sets, const_exprs, i, is_const))) { LOG_WARN("failed to check is const or equivalent expr", K(ret)); } else if (is_const) { /*do nothing*/ } else { break; } } } for (int64_t j = 0; OB_SUCC(ret) && j < exprs.count(); ++j) { if (expr_idxs.has_member(j)) { } else if (OB_FAIL(adjusted_exprs.push_back(exprs.at(j)))) { LOG_WARN("store ordered expr failed", K(ret), K(j)); } else if (OB_FAIL(expr_map.push_back(j))) { LOG_WARN("failed to push back expr index", K(ret)); } else if (OB_FAIL(order_types.push_back(directions.at(j)))) { LOG_WARN("failed to push back order type", K(ret)); } else if (OB_FAIL(expr_idxs.add_member(j))) { LOG_WARN("add expr idxs member failed", K(ret), K(j)); } } if (OB_SUCC(ret)) { if (adjusted_exprs.count() != exprs.count() || order_types.count() != exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("exprs don't covered completely by ordering", K(adjusted_exprs.count()), K(exprs.count()), K(order_types.count())); } else { exprs.reuse(); if (OB_FAIL(exprs.assign(adjusted_exprs))) { LOG_WARN("assign adjusted exprs failed", K(ret)); } else if (OB_FAIL(directions.assign(order_types))) { LOG_WARN("failed to assign order types", K(ret)); } else if (match_map != NULL && OB_FAIL(match_map->assign(expr_map))) { LOG_WARN("failed to assign expr indexs", K(ret)); } } } return ret; } int ObOptimizerUtil::adjust_exprs_by_mapping(const common::ObIArray& exprs, const common::ObIArray& match_map, common::ObIArray& adjusted_exprs) { int ret = OB_SUCCESS; ObSEArray tmp_array; if (OB_UNLIKELY(exprs.count() != match_map.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("size does not match", K(ret), K(exprs.count()), K(match_map.count())); } for (int64_t i = 0; OB_SUCC(ret) && i < match_map.count(); ++i) { int64_t index = match_map.at(i); if (index < 0 || index >= exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid index", K(ret), K(index)); } else if (OB_FAIL(tmp_array.push_back(exprs.at(index)))) { LOG_WARN("failed to add expr", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(adjusted_exprs.assign(tmp_array))) { LOG_WARN("failed to assign expr array", K(ret)); } } return ret; } bool ObOptimizerUtil::is_same_ordering(const common::ObIArray& ordering1, const common::ObIArray& ordering2, const EqualSets& equal_sets) { bool is_same = true; int64_t N = ordering1.count(); int64_t M = ordering2.count(); if (N != M) { is_same = false; } else { for (int64_t i = 0; is_same && i < N; ++i) { if (!(ordering1.at(i).order_type_ == ordering2.at(i).order_type_ && is_expr_equivalent(ordering1.at(i).expr_, ordering2.at(i).expr_, equal_sets) && is_expr_equivalent(ordering2.at(i).expr_, ordering1.at(i).expr_, equal_sets))) { is_same = false; } } } return is_same; } bool ObOptimizerUtil::is_expr_equivalent(const ObRawExpr* from, const ObRawExpr* to, const EqualSets& equal_sets) { bool found = false; bool is_consistent = false; if (OB_ISNULL(from) || OB_ISNULL(to)) { // do nothing } else if (from == to) { found = true; } else if (!from->is_generalized_column() && from->same_as(*to)) { found = true; } else if (ObRawExprUtils::expr_is_order_consistent(from, to, is_consistent) != OB_SUCCESS) { LOG_WARN("check expr is order consist ent failed"); } else if (is_consistent) { int64_t N = equal_sets.count(); for (int64_t i = 0; !found && i < N; ++i) { if (OB_ISNULL(equal_sets.at(i))) { LOG_WARN("get null equal set"); } else if (find_equal_expr(*equal_sets.at(i), from) && find_equal_expr(*equal_sets.at(i), to)) { found = true; } } } return found; } int ObOptimizerUtil::extract_target_level_query_ref_expr(ObIArray& exprs, const int64_t level, const ObIArray& ignore_exprs, ObIArray& subqueries) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { ret = SMART_CALL(extract_target_level_query_ref_expr(exprs.at(i), level, ignore_exprs, subqueries)); } return ret; } int ObOptimizerUtil::extract_target_level_query_ref_expr(ObIArray& exprs, const int64_t level, const ObIArray& ignore_exprs, ObIArray& subqueries) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { ret = SMART_CALL(extract_target_level_query_ref_expr(exprs.at(i), level, ignore_exprs, subqueries)); } return ret; } int ObOptimizerUtil::extract_target_level_query_ref_expr(ObRawExpr* expr, const int64_t level, const ObIArray& ignore_exprs, ObIArray& subqueries) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (!expr->has_flag(CNT_SUB_QUERY)) { /*do nothing*/ } else if (!expr->is_query_ref_expr()) { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { ret = SMART_CALL(extract_target_level_query_ref_expr(expr->get_param_expr(i), level, ignore_exprs, subqueries)); } } else if (level == expr->get_expr_level() && !find_item(ignore_exprs, expr)) { ret = add_var_to_array_no_dup(subqueries, expr); } else { ObSelectStmt* ref_query = static_cast(expr)->get_ref_stmt(); ObSEArray exprs; if (OB_ISNULL(ref_query)) { /*do nothing*/ } else if (OB_FAIL(ref_query->get_relation_exprs(exprs))) { LOG_WARN("failed to get relation exprs", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { ret = SMART_CALL(extract_target_level_query_ref_expr(exprs.at(i), level, ignore_exprs, subqueries)); } } return ret; } bool ObOptimizerUtil::is_sub_expr(const ObRawExpr* sub_expr, const ObRawExpr* expr) { bool found = false; if (NULL == sub_expr || NULL == expr) { /* do nothing */ } else { if (sub_expr == expr) { found = true; } else if (ObRawExprUtils::is_same_raw_expr(sub_expr, expr)) { found = true; } else { /* do nothing. */ } for (int64_t i = 0; !found && i < expr->get_param_count(); ++i) { found = is_sub_expr(sub_expr, expr->get_param_expr(i)); } } return found; } bool ObOptimizerUtil::is_sub_expr(const ObRawExpr* sub_expr, const ObIArray& exprs) { bool found = false; for (int64_t i = 0; !found && i < exprs.count(); i++) { found = is_sub_expr(sub_expr, exprs.at(i)); } return found; } bool ObOptimizerUtil::is_sub_expr(const ObRawExpr* sub_expr, ObRawExpr*& expr, ObRawExpr**& addr_matched_expr) { bool found = false; if (NULL == sub_expr || NULL == expr) { /* do nothing */ } else if (sub_expr == expr) { found = true; addr_matched_expr = &expr; } else { for (int64_t i = 0; !found && i < expr->get_param_count(); ++i) { found = is_sub_expr(sub_expr, expr->get_param_expr(i), addr_matched_expr); } } return found; } bool ObOptimizerUtil::is_point_based_sub_expr(const ObRawExpr* sub_expr, const ObRawExpr* expr) { bool found = false; if (NULL == sub_expr || NULL == expr) { /* do nothing */ } else if (sub_expr == expr) { found = true; } else { for (int64_t i = 0; !found && i < expr->get_param_count(); ++i) { found = is_point_based_sub_expr(sub_expr, expr->get_param_expr(i)); } } return found; } int ObOptimizerUtil::is_const_expr( const ObRawExpr* expr, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_const) { int ret = OB_SUCCESS; is_const = false; bool is_consistent = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr passed in should not be NULL", K(expr), K(ret)); } else { ObArray found_sets; if (OB_FAIL(find_equal_set(expr, equal_sets, found_sets))) { LOG_WARN("find equal set failed", K(ret)); } else if (found_sets.count() <= 0) { if (OB_FAIL(is_const_expr(expr, const_exprs, is_const))) { LOG_WARN("failed to check if is const expr", K(expr), K(ret)); } } else { for (int64_t i = 0; OB_SUCC(ret) && !is_const && i < found_sets.count(); ++i) { const EqualSet* equal_set = found_sets.at(i); if (OB_ISNULL(equal_set)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("equal set is null"); } for (int64_t j = 0; OB_SUCC(ret) && !is_const && j < equal_set->count(); ++j) { const ObRawExpr* cur_expr = equal_set->at(j); if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr passed in should not be NULL", K(j), K(ret)); } else if (OB_FAIL(ObRawExprUtils::expr_is_order_consistent(cur_expr, expr, is_consistent))) { LOG_WARN("check expr is order consistent failed", K(ret)); } else if (is_consistent && OB_FAIL(is_const_expr(cur_expr, const_exprs, is_const))) { LOG_WARN("failed to check const expr", K(cur_expr), K(ret)); } else { /*do nothing*/ } } } } } return ret; } bool ObOptimizerUtil::is_const_expr(const ObRawExpr* expr, const int64_t stmt_level) { bool bret = false; if (OB_ISNULL(expr)) { // do nothing } else if (expr->has_const_or_const_expr_flag()) { bret = true; } else if (stmt_level < 0) { // do nothing } else if (!expr->get_expr_levels().has_member(stmt_level) && !expr->has_flag(CNT_RAND_FUNC) && !expr->has_flag(CNT_PSEUDO_COLUMN)) { bret = true; } return bret; } int ObOptimizerUtil::is_const_expr(const ObRawExpr* expr, const ObIArray& const_exprs, bool& is_const) { int ret = OB_SUCCESS; is_const = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr passed in should not be NULL", K(expr), K(ret)); } else if (expr->has_const_or_const_expr_flag()) { is_const = true; } else if (find_item(const_exprs, expr)) { is_const = true; } return ret; } int ObOptimizerUtil::compute_const_exprs( const ObIArray& condition_exprs, const int64_t stmt_level, ObIArray& const_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < condition_exprs.count(); ++i) { ObRawExpr* cur_expr = condition_exprs.at(i); if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr passed in should not be NULL", K(i), K(ret)); } else if (T_OP_EQ == cur_expr->get_expr_type() || T_OP_IS == cur_expr->get_expr_type()) { ObRawExpr* param_1 = cur_expr->get_param_expr(0); ObRawExpr* param_2 = cur_expr->get_param_expr(1); bool l_is_lossless = false; bool r_is_lossless = false; if (OB_ISNULL(param_1) || OB_ISNULL(param_2)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(param_1), K(param_2), K(ret)); } else if (OB_FAIL(is_lossless_column_cast(param_1, l_is_lossless))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } else if (OB_FAIL(is_lossless_column_cast(param_2, r_is_lossless))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } else if (l_is_lossless && FALSE_IT(param_1 = param_1->get_param_expr(0))) { } else if (r_is_lossless && FALSE_IT(param_2 = param_2->get_param_expr(0))) { } else { bool left_const = is_const_expr(param_1, stmt_level); bool right_const = is_const_expr(param_2, stmt_level); if (left_const || right_const) { ObRawExpr* const_expr = left_const ? param_1 : param_2; ObRawExpr* common_expr = left_const ? param_2 : param_1; if (T_OP_EQ == cur_expr->get_expr_type()) { bool is_const = true; if (!ob_is_valid_obj_tc(const_expr->get_type_class()) || !ob_is_valid_obj_tc(const_expr->get_type_class())) { // (a, a) = (1, 1); is_const = false; } else if (OB_FAIL(ObObjCaster::is_const_consistent(const_expr->get_result_type().get_obj_meta(), common_expr->get_result_type().get_obj_meta(), cur_expr->get_result_type().get_calc_type(), cur_expr->get_result_type().get_calc_meta().get_collation_type(), is_const))) { LOG_WARN("check expr type is strict monotonic failed", K(ret)); } else if (is_const && OB_FAIL(add_var_to_array_no_dup(const_exprs, common_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } else if (OB_FAIL(add_var_to_array_no_dup(const_exprs, common_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } } } } return ret; } bool ObOptimizerUtil::overlap_exprs(const ObIArray& exprs1, const ObIArray& exprs2) { bool overlap = false; int64_t N = exprs2.count(); for (int64_t i = 0; !overlap && i < N; ++i) { if (find_equal_expr(exprs1, exprs2.at(i))) { overlap = true; } } return overlap; } bool ObOptimizerUtil::subset_exprs(const ObIArray& sort_keys, const ObIArray& exprs) { bool subset = true; int64_t M = sort_keys.count(); int64_t N = exprs.count(); if (M > N) { subset = false; } else { for (int64_t i = 0; subset && i < M; ++i) { if (!find_equal_expr(exprs, sort_keys.at(i).expr_)) { subset = false; } } } return subset; } bool ObOptimizerUtil::subset_exprs( const ObIArray& sub_exprs, const ObIArray& exprs, const EqualSets& equal_sets) { bool subset = true; for (int64_t i = 0; subset && i < sub_exprs.count(); ++i) { if (!find_equal_expr(exprs, sub_exprs.at(i), equal_sets)) { subset = false; } } return subset; } bool ObOptimizerUtil::subset_exprs(const ObIArray& sub_exprs, const ObIArray& exprs) { bool subset = true; for (int64_t i = 0; subset && i < sub_exprs.count(); ++i) { if (!find_equal_expr(exprs, sub_exprs.at(i))) { subset = false; } } return subset; } int ObOptimizerUtil::prefix_subset_exprs(const ObIArray& sub_exprs, const uint64_t subexpr_prefix_count, const ObIArray& exprs, const uint64_t expr_prefix_count, bool& is_subset) { int ret = OB_SUCCESS; is_subset = false; if (subexpr_prefix_count > sub_exprs.count() || expr_prefix_count > exprs.count()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(subexpr_prefix_count), K(sub_exprs.count()), K(expr_prefix_count), K(exprs.count())); } else { ObSEArray prefix_keys; for (int64_t i = 0; OB_SUCC(ret) && i < expr_prefix_count; ++i) { if (OB_FAIL(prefix_keys.push_back(exprs.at(i)))) { LOG_WARN("failed to push back exprs", K(ret)); } } if (OB_SUCC(ret)) { is_subset = true; for (int64_t i = 0; is_subset && i < subexpr_prefix_count; ++i) { if (!find_equal_expr(prefix_keys, sub_exprs.at(i))) { is_subset = false; } } } } return ret; } bool ObOptimizerUtil::subset_exprs( const ObIArray& sort_keys, const ObIArray& exprs2, const EqualSets& equal_sets) { bool subset = true; for (int64_t i = 0; subset && i < sort_keys.count(); ++i) { if (!find_equal_expr(exprs2, sort_keys.at(i).expr_, equal_sets)) { subset = false; } } return subset; } int ObOptimizerUtil::intersect_exprs( ObIArray& first, ObIArray& right, ObIArray& result) { int ret = OB_SUCCESS; ObSEArray tmp; for (int64_t i = 0; OB_SUCC(ret) && i < first.count(); ++i) { if (!find_equal_expr(right, first.at(i))) { // do nothing } else if (OB_FAIL(tmp.push_back(first.at(i)))) { LOG_WARN("failed to push back first expr", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(result.assign(tmp))) { LOG_WARN("failed to assign expr array", K(ret)); } return ret; } int ObOptimizerUtil::except_exprs( ObIArray& first, ObIArray& right, ObIArray& result) { int ret = OB_SUCCESS; ObSEArray tmp; for (int64_t i = 0; OB_SUCC(ret) && i < first.count(); ++i) { if (find_equal_expr(right, first.at(i))) { // do nothing } else if (OB_FAIL(tmp.push_back(first.at(i)))) { LOG_WARN("failed to push back first expr", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(result.assign(tmp))) { LOG_WARN("failed to assign expr array", K(ret)); } return ret; } int ObOptimizerUtil::copy_exprs( ObRawExprFactory& expr_factory, const ObIArray& src, ObIArray& dst) { int ret = OB_SUCCESS; dst.reset(); int64_t N = src.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { ObRawExpr* src_expr = src.at(i); if (OB_ISNULL(src_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("src_expr is NULL", K(ret)); } else if (src_expr->has_flag(CNT_COLUMN) || src_expr->has_flag(CNT_AGG) || src_expr->has_flag(CNT_SUB_QUERY)) { if (OB_FAIL(dst.push_back(src_expr))) { LOG_WARN("push back src expr failed", K(ret)); } } else { ObRawExpr* dst_expr = NULL; if (OB_FAIL(ObRawExprUtils::copy_expr(expr_factory, src_expr, dst_expr, COPY_REF_DEFAULT))) { LOG_WARN("copy expr failed", K(ret)); } else if (OB_FAIL(dst.push_back(dst_expr))) { LOG_WARN("push back src expr failed", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::clone_expr_for_topk(ObRawExprFactory& expr_factory, ObRawExpr* src, ObRawExpr*& dest) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(src)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid src is NULL", 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 { ObRawExpr::ExprClass expr_class = src->get_expr_class(); switch (expr_class) { case ObRawExpr::EXPR_CONST: case ObRawExpr::EXPR_COLUMN_REF: case ObRawExpr::EXPR_AGGR: { dest = src; break; } case ObRawExpr::EXPR_OPERATOR: { ObOpRawExpr* dest_op = NULL; if (OB_FAIL(expr_factory.create_raw_expr(src->get_expr_type(), dest_op))) { LOG_WARN("failed to allocate raw expr", K(ret)); } else if (OB_ISNULL(dest = dest_op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dest operator expr is null", K(ret)); } else { ObOpRawExpr* src_op = static_cast(src); if (OB_ISNULL(src_op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("casted src_op is NULL", K(ret)); } else if (OB_FAIL(dest_op->assign(*src_op))) { LOG_WARN("failed to assign expr", K(ret)); } else { dest_op->clear_child(); int64_t count = src_op->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { ObRawExpr* param_expr = src_op->get_param_expr(i); ObRawExpr* new_param_expr = NULL; if (OB_FAIL(SMART_CALL(clone_expr_for_topk(expr_factory, param_expr, new_param_expr)))) { LOG_WARN("fail to copy_expr", K(ret)); } else if (OB_FAIL(dest_op->add_param_expr(new_param_expr))) { LOG_WARN("fail to add param expr", K(ret)); } else { /*do nothing*/ } } } } break; } case ObRawExpr::EXPR_CASE_OPERATOR: { ObCaseOpRawExpr* dest_case = NULL; if (OB_FAIL(expr_factory.create_raw_expr(src->get_expr_type(), dest_case))) { LOG_WARN("failed to allocate raw expr", K(ret)); } else if (OB_ISNULL(dest = dest_case)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dest case expr is null", K(ret)); } else { ObCaseOpRawExpr* src_case = static_cast(src); if (OB_ISNULL(src_case)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("casted src_case is NULL", K(ret)); } else if (OB_FAIL(dest_case->assign(*src_case))) { LOG_WARN("failed to assign expr", K(ret)); } else { dest_case->clear_child(); ObRawExpr* origin_arg = src_case->get_arg_param_expr(); ObRawExpr* origin_default = src_case->get_default_param_expr(); ObRawExpr* dest_arg = NULL; ObRawExpr* dest_default = NULL; if (OB_FAIL(SMART_CALL(clone_expr_for_topk(expr_factory, origin_arg, dest_arg)))) { LOG_WARN("fail to copy raw expr", K(ret)); } else if (OB_FAIL(SMART_CALL(clone_expr_for_topk(expr_factory, origin_default, dest_default)))) { LOG_WARN("fail to copy raw expr", K(ret)); } else { dest_case->set_arg_param_expr(dest_arg); dest_case->set_default_param_expr(dest_default); int64_t count = src_case->get_when_expr_size(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { ObRawExpr* origin_when = src_case->get_when_param_expr(i); ObRawExpr* origin_then = src_case->get_then_param_expr(i); ObRawExpr* dest_when = NULL; ObRawExpr* dest_then = NULL; if (OB_FAIL(SMART_CALL(clone_expr_for_topk(expr_factory, origin_when, dest_when)))) { LOG_WARN("fail to copy raw expr", K(ret)); } else if (OB_FAIL(dest_case->add_when_param_expr(dest_when))) { LOG_WARN("fail to add raw expr", K(ret)); } else if (OB_FAIL(SMART_CALL(clone_expr_for_topk(expr_factory, origin_then, dest_then)))) { LOG_WARN("fail to copy raw expr", K(ret)); } else if (OB_FAIL(dest_case->add_then_param_expr(dest_then))) { LOG_WARN("fail to add raw expr", K(ret), K(dest_then)); } else { /*do nothing*/ } } } } } break; } case ObRawExpr::EXPR_SYS_FUNC: { ObSysFunRawExpr* dest_sys = NULL; if (OB_FAIL(expr_factory.create_raw_expr(src->get_expr_type(), dest_sys))) { LOG_WARN("failed to allocate raw expr", K(ret)); } else if (OB_ISNULL(dest = dest_sys)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dest sys func is null", K(ret)); } else { ObSysFunRawExpr* src_sys = static_cast(src); if (OB_ISNULL(src_sys)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("casted src sys func is null", K(ret)); } else if (OB_FAIL(dest_sys->assign(*src_sys))) { LOG_WARN("failed to assign expr", K(ret)); } else { dest_sys->clear_child(); int64_t count = src_sys->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { ObRawExpr* param_expr = src_sys->get_param_expr(i); ObRawExpr* new_param_expr = NULL; if (OB_FAIL(SMART_CALL(clone_expr_for_topk(expr_factory, param_expr, new_param_expr)))) { LOG_WARN("fail to copy raw expr", K(ret)); } else if (OB_FAIL(dest_sys->add_param_expr(new_param_expr))) { LOG_WARN("fail to push raw expr", K(ret)); } else { /*do nothing*/ } } } } break; } case ObRawExpr::EXPR_UDF: { ret = OB_NOT_SUPPORTED; break; } case ObRawExpr::EXPR_QUERY_REF: case ObRawExpr::EXPR_WINDOW: case ObRawExpr::EXPR_DOMAIN_INDEX: { ret = OB_NOT_SUPPORTED; LOG_WARN("not support expr class", K(expr_class), K(ret)); break; } default: { // should not reach here ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid expr class", K(expr_class), K(ret)); break; } } } return ret; } int ObOptimizerUtil::copy_sort_keys(const ObIArray& src, ObIArray& dst) { int ret = OB_SUCCESS; dst.reuse(); int64_t N = src.count(); OrderItem key; for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { key.expr_ = src.at(i); ret = dst.push_back(key); } return ret; } bool ObOptimizerUtil::find_equal_expr( const ObIArray& exprs, const ObRawExpr* expr, const EqualSets& equal_sets, int64_t& idx) { bool found = false; int64_t N = exprs.count(); for (int64_t i = 0; !found && i < N; ++i) { if (is_expr_equivalent(exprs.at(i), expr, equal_sets)) { found = true; idx = i; } } return found; } bool ObOptimizerUtil::find_equal_expr( const common::ObIArray& exprs, const ObRawExpr* expr, ObExprParamCheckContext& context, int64_t& idx) { int ret = OB_SUCCESS; bool found = false; int64_t N = exprs.count(); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; } for (int64_t i = 0; OB_SUCC(ret) && !found && i < N; ++i) { if (OB_ISNULL(exprs.at(i))) { ret = OB_ERR_UNEXPECTED; } else if (exprs.at(i)->same_as(*expr, &context)) { found = true; idx = i; } else { /*do nothing*/ } } return found; } int ObOptimizerUtil::find_stmt_expr_direction(const ObDMLStmt& stmt, const common::ObIArray& exprs, const EqualSets& equal_sets, common::ObIArray& directions) { int ret = OB_SUCCESS; ObOrderDirection dir; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); i++) { if (OB_FAIL(find_stmt_expr_direction(stmt, exprs.at(i), equal_sets, dir))) { LOG_WARN("failed to find stmt expr direction", K(ret)); } else if (OB_FAIL(directions.push_back(dir))) { LOG_WARN("failed to push back direction", K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::find_stmt_expr_direction( const ObDMLStmt& stmt, const ObRawExpr* expr, const EqualSets& equal_sets, ObOrderDirection& direction) { int ret = OB_SUCCESS; bool is_find = false; direction = default_asc_direction(); if (stmt.is_select_stmt()) { const ObSelectStmt& select_stmt = static_cast(stmt); // find direction in window function exprs for (int64_t i = 0; OB_SUCC(ret) && !is_find && i < select_stmt.get_window_func_count(); ++i) { const ObWinFunRawExpr* win_expr = NULL; if (OB_ISNULL(win_expr = select_stmt.get_window_func_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("window function is null", K(ret)); } else { is_find = find_expr_direction(win_expr->get_order_items(), expr, equal_sets, direction); } } LOG_TRACE("succeed to check expr direction in window function exprs", K(direction), K(is_find)); } if (OB_SUCC(ret) && !is_find) { // find direction in order by exprs is_find = find_expr_direction(stmt.get_order_items(), expr, equal_sets, direction); LOG_TRACE("succeed to check expr direction in order by exprs", K(direction), K(is_find)); } return ret; } bool ObOptimizerUtil::find_expr_direction( const ObIArray& exprs, const ObRawExpr* expr, const EqualSets& equal_sets, ObOrderDirection& direction) { bool found = false; int64_t N = exprs.count(); for (int64_t i = 0; !found && i < N; ++i) { if (is_expr_equivalent(exprs.at(i).expr_, expr, equal_sets)) { found = true; direction = exprs.at(i).order_type_; } } return found; } uint64_t ObOptimizerUtil::hash_array(uint64_t seed, const ObIArray& data_array) { uint64_t hash_value = seed; int64_t N = data_array.count(); for (int64_t i = 0; i < N; ++i) { hash_value = common::do_hash(data_array.at(i), hash_value); } return hash_value; } bool ObOptimizerUtil::find_expr(ObIArray* ctx, const ObRawExpr& expr) { bool found = false; ExprProducer* producer = NULL; found = find_expr(ctx, expr, producer); return found; } bool ObOptimizerUtil::find_expr(ObIArray* ctx, const ObRawExpr& expr, ExprProducer*& producer) { bool found = false; producer = NULL; int64_t N = NULL == ctx ? 0 : ctx->count(); for (int64_t i = 0; !found && i < N; ++i) { /** * We rely on the assumption that we can compare the two expressions by * comparing their physical addresses. This pointer-based comparison is only * possible if it is guaranteed that the duplicate expressions will not be * allocated again. */ if (ctx->at(i).expr_ == &expr) { found = true; producer = &ctx->at(i); } } return found; } int ObOptimizerUtil::classify_equal_conds( const ObIArray& conds, ObIArray& normal_conds, ObIArray& nullsafe_conds) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < conds.count(); ++i) { if (OB_ISNULL(conds.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("condition is null", K(ret), K(conds.at(i))); } else if (conds.at(i)->get_expr_type() == T_OP_EQ || conds.at(i)->get_expr_type() == T_OP_SQ_EQ) { if (OB_FAIL(normal_conds.push_back(conds.at(i)))) { LOG_WARN("failed to push back normal equal condition", K(ret)); } } else if (conds.at(i)->get_expr_type() == T_OP_NSEQ || conds.at(i)->get_expr_type() == T_OP_SQ_NSEQ) { if (OB_FAIL(nullsafe_conds.push_back(conds.at(i)))) { LOG_WARN("failed to push back nullsafe equal condition", K(ret)); } } } return ret; } int ObOptimizerUtil::get_equal_keys(const ObIArray& exprs, const ObRelIds& left_table_sets, ObIArray& left_keys, ObIArray& right_keys) { int ret = OB_SUCCESS; ObRawExpr* temp_expr = NULL; ObRawExpr* left_expr = NULL; ObRawExpr* right_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_ISNULL(temp_expr = exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (!temp_expr->has_flag(IS_JOIN_COND)) { /*do nothing*/ } else if (!temp_expr->get_relation_ids().overlap(left_table_sets)) { /*do nothing*/ } else if (OB_ISNULL(left_expr = temp_expr->get_param_expr(0)) || OB_ISNULL(right_expr = temp_expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(left_expr), K(right_expr), K(ret)); } else { if (!left_expr->get_relation_ids().is_subset(left_table_sets)) { std::swap(left_expr, right_expr); } if (OB_FAIL(left_keys.push_back(left_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(right_keys.push_back(right_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } } return ret; } ObRawExpr* ObOptimizerUtil::find_exec_param( const ObIArray>& params, const int64_t param_num) { ObRawExpr* expr = NULL; bool found = false; for (int64_t i = 0; !found && i < params.count(); ++i) { if (params.at(i).first == param_num) { expr = params.at(i).second; found = true; } } return expr; } int64_t ObOptimizerUtil::find_exec_param(const ObIArray>& params, const ObRawExpr* expr) { int64_t param_num = -1; bool found = false; for (int64_t i = 0; !found && i < params.count(); ++i) { if (params.at(i).second == expr) { param_num = params.at(i).first; found = true; } } return param_num; } ObRawExpr* ObOptimizerUtil::find_param_expr(const ObIArray& exprs, const int64_t param_num) { ObRawExpr* expr = NULL; bool found = false; for (int64_t i = 0; !found && i < exprs.count(); ++i) { if (OB_UNLIKELY(NULL == exprs.at(i))) { // NULL expr means not found, just continue } else if (exprs.at(i)->has_flag(IS_PARAM) && static_cast(exprs.at(i))->get_value().get_unknown() == param_num) { expr = exprs.at(i); found = true; } } return expr; } int ObOptimizerUtil::extract_params(ObRawExpr* expr, ObIArray& params) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr passed in is NULL", 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 { ObRawExpr::ExprClass expr_class = expr->get_expr_class(); switch (expr_class) { case ObRawExpr::EXPR_CONST: { if (expr->has_flag(IS_PARAM)) { ret = params.push_back(expr); } else { /*do nothing*/ } break; } case ObRawExpr::EXPR_SET_OP: case ObRawExpr::EXPR_QUERY_REF: case ObRawExpr::EXPR_COLUMN_REF: { break; } case ObRawExpr::EXPR_OPERATOR: // fallthrough case ObRawExpr::EXPR_CASE_OPERATOR: // fallthrough case ObRawExpr::EXPR_AGGR: // fallthrough case ObRawExpr::EXPR_SYS_FUNC: case ObRawExpr::EXPR_UDF: { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { ret = SMART_CALL(extract_params(expr->get_param_expr(i), params)); } break; } case ObRawExpr::EXPR_INVALID_CLASS: default: // should not reach here break; } } return ret; } int ObOptimizerUtil::extract_params(common::ObIArray& exprs, common::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), params))) { LOG_WARN("failed to extract params", K(ret)); } } return ret; } int ObOptimizerUtil::extract_equal_exec_params(const ObIArray& exprs, const ObIArray>& params, ObIArray& left_key, ObIArray& right_key) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { ObRawExpr* cur_expr = exprs.at(i); if (OB_ISNULL(cur_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr passed in is NULL", K(ret)); } else if (T_OP_EQ == cur_expr->get_expr_type() || T_OP_NSEQ == cur_expr->get_expr_type()) { ObRawExpr* expr = NULL; if (OB_ISNULL(cur_expr->get_param_expr(0)) || OB_ISNULL(cur_expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid op expr", K(*cur_expr), K(ret)); } else if (cur_expr->get_param_expr(0)->has_flag(IS_PARAM)) { int64_t param_value = static_cast(cur_expr->get_param_expr(0))->get_value().get_unknown(); if (NULL == (expr = find_exec_param(params, param_value))) { } else if (OB_FAIL(left_key.push_back(expr))) { LOG_WARN("push back error", K(ret)); } else if (OB_FAIL(right_key.push_back(cur_expr->get_param_expr(1)))) { LOG_WARN("push back error", K(ret)); } else { /*do nothing*/ } } else if (cur_expr->get_param_expr(1)->has_flag(IS_PARAM)) { int64_t param_value = static_cast(cur_expr->get_param_expr(1))->get_value().get_unknown(); if (NULL == (expr = find_exec_param(params, param_value))) { } else if (OB_FAIL(left_key.push_back(expr))) { LOG_WARN("push back error", K(ret)); } else if (OB_FAIL(right_key.push_back(cur_expr->get_param_expr(0)))) { LOG_WARN("push back error", K(ret)); } else { /*do nothing*/ } } else { /*do nothing*/ } } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::add_col_ids_to_set(const ObIArray& exprs, ObBitSet<>& bitset) { int ret = OB_SUCCESS; for (int i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(add_col_ids_to_set(exprs.at(i), bitset, true))) { LOG_WARN("Failed to extract col expr", K(ret)); } } return ret; } int ObOptimizerUtil::add_col_ids_to_set( const ObRawExpr* expr, ObBitSet<>& bitset, bool check_single_col, bool restrict_table_id, uint64_t target_table_id) { int ret = OB_SUCCESS; ObArray cur_col_refs; if (OB_FAIL(ObRawExprUtils::extract_column_exprs(const_cast(expr), cur_col_refs))) { LOG_WARN("Failed to extract column expr", K(ret)); } else if (check_single_col && cur_col_refs.count() != 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Expect one col ref.", "count", cur_col_refs.count()); } else { for (int64_t i = 0; OB_SUCC(ret) && i < cur_col_refs.count(); ++i) { ObRawExpr* cur_expr = cur_col_refs.at(i); if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL pointer error", K(cur_expr), K(i), K(ret)); } else if (cur_expr->get_expr_type() != T_REF_COLUMN) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Expr type error", K(ret)); } else { ObColumnRefRawExpr* col_ref = reinterpret_cast(cur_expr); if (!restrict_table_id || (restrict_table_id && col_ref->get_table_id() == target_table_id)) { if (OB_FAIL(bitset.add_member(static_cast(col_ref->get_column_id())))) { LOG_WARN("failed to add member", K(bitset), K(col_ref->get_column_id()), K(ret)); } } } } } return ret; } int ObOptimizerUtil::check_if_column_ids_covered(const ObIArray& exprs, const ObBitSet<>& colset, bool restrict_table_id, uint64_t target_table_id, ObIArray& result) { int ret = OB_SUCCESS; result.reset(); for (int i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { bool single_result = false; if (OB_FAIL(check_if_column_ids_covered(exprs.at(i), colset, restrict_table_id, target_table_id, single_result))) { LOG_WARN("Failed to check expr", K(ret)); } else { ret = result.push_back(single_result); } } return ret; } int ObOptimizerUtil::check_if_column_ids_covered( const ObRawExpr* exprs, const ObBitSet<>& colset, bool restrict_table_id, uint64_t target_table_id, bool& result) { int ret = OB_SUCCESS; result = false; ObBitSet<> colSetOfThisExpr; if (OB_FAIL(add_col_ids_to_set(exprs, colSetOfThisExpr, false, restrict_table_id, target_table_id))) { LOG_WARN("Failed to extract col expr", K(ret)); } else { if (colSetOfThisExpr.is_subset(colset)) { result = true; } else { result = false; } } return ret; } int ObOptimizerUtil::generate_rowkey_column_items(ObDMLStmt* stmt, ObRawExprFactory& expr_factory, uint64_t table_id, const share::schema::ObTableSchema& index_table_schema, common::ObIArray& index_columns) { int ret = OB_SUCCESS; // get all the index keys const ObRowkeyInfo* rowkey_info = NULL; const ObColumnSchemaV2* column_schema = NULL; uint64_t column_id = OB_INVALID_ID; if (index_table_schema.is_index_table() && is_virtual_table(index_table_schema.get_data_table_id()) && !index_table_schema.is_ordered()) { // for virtual table and its hash index rowkey_info = &index_table_schema.get_index_info(); } else { rowkey_info = &index_table_schema.get_rowkey_info(); } // if rowid_index is used ,range_column should just be [rowid] bool found_rowid_col = false; for (int col_idx = 0; !found_rowid_col && OB_SUCC(ret) && col_idx < rowkey_info->get_size(); ++col_idx) { if (OB_FAIL(rowkey_info->get_column_id(col_idx, column_id))) { LOG_WARN("Failed to get column id", K(ret)); } else if (OB_ISNULL(column_schema = (index_table_schema.get_column_schema(column_id)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get column schema", K(column_id), K(ret)); } else { ObColumnRefRawExpr* expr = NULL; ColumnItem* col_item = NULL; if (NULL != (col_item = stmt->get_column_item_by_id(table_id, column_id))) { if (OB_FAIL(index_columns.push_back(*col_item))) { LOG_WARN("Failed to add col item", K(ret)); } } else { if (OB_FAIL(generate_rowkey_expr(stmt, expr_factory, table_id, *column_schema, expr, &index_columns))) { LOG_WARN("failed to get row key expr", K(ret)); } } if (OB_SUCC(ret)) { if (column_schema->get_column_id() == OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID) { found_rowid_col = true; } } } } // for end if (OB_SUCC(ret)) { LOG_TRACE("get range columns", K(index_columns)); } return ret; } int ObOptimizerUtil::generate_rowkey_exprs(ObDMLStmt* stmt, ObOptimizerContext& opt_ctx, const uint64_t table_id, const uint64_t ref_table_id, ObIArray& keys, ObIArray& ordering) { int ret = OB_SUCCESS; const ObTableSchema* table_schema = NULL; ObSqlSchemaGuard* schema_guard = NULL; if (OB_ISNULL(schema_guard = opt_ctx.get_sql_schema_guard())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(schema_guard), K(ret)); } else if (OB_FAIL(schema_guard->get_table_schema(ref_table_id, table_schema))) { LOG_WARN("fail to get table schema", K(ref_table_id), K(table_schema), K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("index schema should not be null", K(table_schema), K(ret)); } else if (OB_FAIL( generate_rowkey_exprs(stmt, opt_ctx.get_expr_factory(), table_id, *table_schema, keys, ordering))) { LOG_WARN("failed to get rowkeys raw expr", K(table_id), K(ref_table_id), K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::generate_rowkey_exprs(ObDMLStmt* stmt, ObRawExprFactory& expr_factory, uint64_t table_id, const ObTableSchema& index_table_schema, ObIArray& index_keys, ObIArray& index_ordering) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(stmt), K(ret)); } else { // get all the index keys const ObRowkeyInfo& rowkey_info = index_table_schema.get_rowkey_info(); const ObColumnSchemaV2* column_schema = NULL; ObColumnRefRawExpr* expr = NULL; for (int col_idx = 0; OB_SUCC(ret) && col_idx < rowkey_info.get_size(); ++col_idx) { uint64_t column_id = OB_INVALID_ID; if (OB_FAIL(rowkey_info.get_column_id(col_idx, column_id))) { LOG_WARN("Failed to get column_id from rowkey_info", K(ret)); } else if (OB_ISNULL(column_schema = (index_table_schema.get_column_schema(column_id)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get column schema", K(column_id), K(ret)); } else { ObRawExpr* raw_expr = NULL; //!!!Dangerous. Different Unique indexes' hidden columns have the same column ids. // Now, we haven't thought the trouble this may cause. But, if we do multi-index scan // or other opt need to use different indexes in one logical plan, remember this problem. if (NULL != (raw_expr = stmt->get_column_expr_by_id(table_id, column_id))) { expr = static_cast(raw_expr); } else if (OB_FAIL(generate_rowkey_expr(stmt, expr_factory, table_id, *column_schema, expr))) { LOG_WARN("failed to get row key expr", K(ret)); } else { /*do nothing*/ } if (OB_SUCC(ret)) { if (OB_FAIL(index_keys.push_back(expr))) { LOG_WARN("failed to add row key expr", K(ret)); } else if (index_table_schema.is_ordered() && OB_FAIL(index_ordering.push_back(expr))) { // for virtual table, we have HASH index which offers no ordering on index keys LOG_WARN("failed to push back index ordering expr", K(ret)); } else { LOG_TRACE("add index key expr", K(expr), K(column_id)); } } } } } return ret; } int ObOptimizerUtil::generate_column_exprs(ObDMLStmt* stmt, ObOptimizerContext& opt_ctx, const uint64_t table_id, const uint64_t ref_table_id, const ObIArray& column_ids, ObIArray& column_exprs) { int ret = OB_SUCCESS; const ObTableSchema* table_schema = NULL; ObSqlSchemaGuard* schema_guard = NULL; if (OB_ISNULL(stmt) || OB_ISNULL(schema_guard = opt_ctx.get_sql_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(stmt), K(schema_guard), K(ret)); } else if (OB_FAIL(schema_guard->get_table_schema(ref_table_id, table_schema))) { LOG_WARN("failed to get table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { ObColumnRefRawExpr* column_expr = NULL; const ObColumnSchemaV2* column_schema = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); i++) { if (is_shadow_column(column_ids.at(i))) { continue; } else if (NULL != (column_expr = stmt->get_column_expr_by_id(table_id, column_ids.at(i)))) { /*do nothing*/ } else if (OB_ISNULL(column_schema = table_schema->get_column_schema(column_ids.at(i)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(column_ids.at(i)), K(ret)); } else if (OB_FAIL( generate_rowkey_expr(stmt, opt_ctx.get_expr_factory(), table_id, *column_schema, column_expr))) { LOG_WARN("failed to generate rowkey expr", K(ret)); } else { /*do nothing*/ } if (OB_FAIL(ret)) { /*do nothing*/ } else if (OB_ISNULL(column_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(column_exprs.push_back(column_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::build_range_columns( const ObDMLStmt* stmt, ObIArray& rowkeys, ObIArray& range_columns) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("NULL pointer error", K(stmt), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < rowkeys.count(); ++i) { if (OB_ISNULL(rowkeys.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("rowkey expr passed in is NULL", K(rowkeys), K(i), K(ret)); } else if (!rowkeys.at(i)->is_column_ref_expr()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("rowkey expr passed in is not a column", K(*rowkeys.at(i)), K(i), K(ret)); } else { ObColumnRefRawExpr* expr = static_cast(rowkeys.at(i)); const ColumnItem* column_item = stmt->get_column_item_by_id(expr->get_table_id(), expr->get_column_id()); //@notice: be careful, range column only use the attribute that table_id, column_id and column type // other attributes do not guarantee the correctness if (NULL != column_item) { ret = range_columns.push_back(*column_item); } else { ColumnItem new_column_item; new_column_item.expr_ = expr; new_column_item.table_id_ = expr->get_table_id(); new_column_item.column_id_ = expr->get_column_id(); ret = range_columns.push_back(new_column_item); } } } } return ret; } int ObOptimizerUtil::check_filter_before_indexback(uint64_t index_id, ObSchemaGetterGuard* schema_guard, const ObIArray& filters, bool restrict_table_id, uint64_t target_table_id, ObIArray& filter_before_ib) { int ret = OB_SUCCESS; const ObTableSchema* index_schema = NULL; ObSEArray column_ids; ObBitSet<> index_column_set; if (OB_ISNULL(schema_guard)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(schema_guard), K(ret)); } else if (OB_FAIL(schema_guard->get_table_schema(index_id, index_schema))) { LOG_WARN("failed to get index schema", K(ret)); } else if (OB_ISNULL(index_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null index schema", K(ret)); } else if (OB_FAIL(index_schema->get_column_ids(column_ids))) { LOG_WARN("failed to get column ids", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); i++) { if (OB_FAIL(index_column_set.add_member(column_ids.at(i).col_id_))) { LOG_WARN("failed to add column ids", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (OB_FAIL(check_if_column_ids_covered( filters, index_column_set, restrict_table_id, target_table_id, filter_before_ib))) { LOG_WARN("Failed to check filter index back"); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::generate_rowkey_expr(ObDMLStmt* stmt, ObRawExprFactory& expr_factory, const uint64_t& table_id, const ObColumnSchemaV2& column_schema, ObColumnRefRawExpr*& rowkey, ObIArray* column_items) { int ret = OB_SUCCESS; /* Now, let's create the raw expr */ const TableItem* table_item = NULL; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument passed in", K(stmt), K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_column_expr(expr_factory, column_schema, rowkey))) { LOG_WARN("build column expr failed", K(ret)); } else if (OB_ISNULL(rowkey)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to create raw expr for dummy output", K(ret)); } else if (OB_ISNULL(table_item = stmt->get_table_item_by_id(table_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get table item by id failed", K(table_id)); } else { ColumnItem dummy_col_item; rowkey->set_ref_id(table_id, column_schema.get_column_id()); rowkey->set_column_attr(table_item->get_table_name(), column_schema.get_column_name_str()); dummy_col_item.table_id_ = rowkey->get_table_id(); dummy_col_item.column_id_ = rowkey->get_column_id(); dummy_col_item.base_tid_ = rowkey->get_table_id(); dummy_col_item.base_cid_ = rowkey->get_column_id(); dummy_col_item.column_name_ = rowkey->get_column_name(); dummy_col_item.set_default_value(column_schema.get_cur_default_value()); dummy_col_item.expr_ = rowkey; if (OB_FAIL(stmt->add_column_item(dummy_col_item))) { LOG_WARN("add column item to stmt failed", K(ret)); } else if (FALSE_IT(rowkey->clear_explicited_referece())) { /*do nothing*/ } else if (OB_FAIL(rowkey->formalize(NULL))) { LOG_WARN("formalize rowkey failed", K(ret)); } else if (OB_FAIL(rowkey->pull_relation_id_and_levels(stmt->get_current_level()))) { LOG_WARN("failed to pullup relation ids", K(ret)); } else if (NULL != column_items) { if (OB_FAIL(column_items->push_back(dummy_col_item))) { LOG_WARN("Failed to add dummy column item", K(ret)); } } else { } // do nothing } return ret; } int ObOptimizerUtil::find_equal_set( const ObRawExpr* ordering, const EqualSets& equal_sets, ObIArray& found_sets) { int ret = OB_SUCCESS; if (OB_NOT_NULL(ordering)) { int64_t N = equal_sets.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { if (OB_ISNULL(equal_sets.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null equal set", K(ret)); } else if (find_equal_expr(*equal_sets.at(i), ordering)) { if (OB_FAIL(found_sets.push_back(equal_sets.at(i)))) { LOG_WARN("store found set failed", K(ret)); } } } } return ret; } int ObOptimizerUtil::extract_row_col_idx_for_in(const common::ObIArray& column_ids, const int64_t index_col_pos, const uint64_t table_id, const ObRawExpr& l_expr, const ObRawExpr& r_expr, common::ObBitSet<>& col_idxs, int64_t& min_col_idx, bool& is_table_filter) { int ret = OB_SUCCESS; common::ObBitSet<> init_col_idxs = col_idxs; int64_t init_min_col_idx = min_col_idx; bool init_is_table_filter = false; bool equal = true; for (int64_t i = 0; OB_SUCC(ret) && equal && i < r_expr.get_param_count(); ++i) { const ObRawExpr* expr = r_expr.get_param_expr(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr should not be NULL", K(ret)); } else { bool tmp_is_table_filter = false; common::ObBitSet<> tmp_col_idxs = col_idxs; int64_t tmp_min_col_idx = min_col_idx; if (i == 0) { if (OB_FAIL(extract_row_col_idx(column_ids, index_col_pos, table_id, l_expr, *expr, init_col_idxs, init_min_col_idx, init_is_table_filter))) { LOG_WARN("extract_row_col_idx for vector IN-expr failed", K(ret)); } } else if (OB_FAIL(extract_row_col_idx(column_ids, index_col_pos, table_id, l_expr, *expr, tmp_col_idxs, tmp_min_col_idx, tmp_is_table_filter))) { LOG_WARN("extract_row_col_idx for vector IN-expr failed", K(ret)); } else if (!(tmp_col_idxs == init_col_idxs) || tmp_min_col_idx != init_min_col_idx || tmp_is_table_filter != init_is_table_filter) { equal = false; } else { // do nothing } } } if (OB_SUCC(ret) && equal) { col_idxs = init_col_idxs; min_col_idx = init_min_col_idx; is_table_filter = init_is_table_filter; } return ret; } int ObOptimizerUtil::extract_row_col_idx(const ObIArray& column_ids, const int64_t index_col_pos, const uint64_t table_id, const ObRawExpr& l_expr, const ObRawExpr& r_expr, ObBitSet<>& col_idxs, int64_t& min_col_idx, bool& is_table_filter) { int ret = OB_SUCCESS; if (l_expr.get_param_count() != r_expr.get_param_count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param count is invalid", K(ret), K(l_expr.get_param_count()), K(r_expr.get_param_count())); } else if (T_OP_ROW == l_expr.get_expr_type() && T_OP_ROW == r_expr.get_expr_type()) { const ObRawExpr* column_expr = NULL; bool check_next = true; int64_t cur_col_idx = INITED_VALUE; int64_t last_idx = INITED_VALUE; int64_t i = 0; is_table_filter = true; for (i = 0; check_next && OB_SUCC(ret) && i < l_expr.get_param_count(); ++i) { column_expr = NULL; if (OB_ISNULL(l_expr.get_param_expr(i)) || OB_ISNULL(r_expr.get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param expr i is null", K(ret)); } else if (l_expr.get_param_expr(i)->is_column_ref_expr() && r_expr.get_param_expr(i)->has_flag(IS_CONST)) { column_expr = l_expr.get_param_expr(i); } else if (r_expr.get_param_expr(i)->is_column_ref_expr() && l_expr.get_param_expr(i)->has_flag(IS_CONST)) { column_expr = r_expr.get_param_expr(i); } else { check_next = false; } // add col_idx to bitset if (OB_SUCC(ret) && check_next) { if (OB_FAIL(extract_column_idx(column_ids, index_col_pos, table_id, column_expr, cur_col_idx, col_idxs))) { LOG_WARN("extract column idx failed", K(ret)); } else if (cur_col_idx < 0 || (last_idx >= 0 && last_idx + 1 != cur_col_idx)) { check_next = false; } else if (OB_FAIL(col_idxs.add_member(cur_col_idx))) { LOG_WARN("failed to add idx to ObBitSet", K(ret), K(cur_col_idx)); } else { last_idx = cur_col_idx; if (cur_col_idx < min_col_idx) { min_col_idx = cur_col_idx; } is_table_filter = false; } } } if (is_table_filter) { if (cur_col_idx > TABLE_RELATED) { is_table_filter = false; } } } return ret; } int ObOptimizerUtil::extract_column_idx(const ObIArray& column_ids, const int64_t index_col_pos, const uint64_t table_id, const ObRawExpr* raw_expr, int64_t& col_idx, ObBitSet<>& col_idxs, const bool is_org_filter) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(raw_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid raw expr", K(raw_expr), 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 (T_REF_COLUMN == raw_expr->get_expr_type()) { const ObColumnRefRawExpr* col_ref = static_cast(raw_expr); const uint64_t col_id = col_ref->get_column_id(); if (col_ref->get_table_id() != table_id) { // considered as const value } else { bool found = false; const int64_t N = column_ids.count(); for (int64_t idx = 0; OB_SUCC(ret) && !found && idx < N; ++idx) { if (col_id == column_ids.at(idx)) { if (idx > index_col_pos) { col_idx = INDEX_STORE_RELATED; } else if (col_idx >= 0) { if (col_idx != idx) { col_idx = MUL_INDEX_COL; } } else if (INITED_VALUE == col_idx) { col_idx = is_org_filter ? static_cast(MUL_INDEX_COL) : idx; } else { /*do nothing*/ } found = true; } } if (!found) { col_idx = TABLE_RELATED; } } } else { int64_t N = raw_expr->get_param_count(); ObItemType type = raw_expr->get_expr_type(); if (N > 0 && !is_query_range_op(type)) { col_idx = MUL_INDEX_COL; // cannot be prefix filter } if ((IS_BASIC_CMP_OP(type) || T_OP_IN == type) && N == 2 && (NULL == raw_expr->get_param_expr(0) || NULL == raw_expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid raw expr", K(*raw_expr), K(ret)); } else if ((IS_BASIC_CMP_OP(type) || T_OP_IN == type) && N == 2 && T_OP_ROW == raw_expr->get_param_expr(0)->get_expr_type()) { const ObRawExpr& l_expr = *(raw_expr->get_param_expr(0)); const ObRawExpr& r_expr = *(raw_expr->get_param_expr(1)); int64_t min_col_idx = column_ids.count(); bool is_table_filter = false; if (T_OP_IN == type) { if (OB_FAIL(extract_row_col_idx_for_in( column_ids, index_col_pos, table_id, l_expr, r_expr, col_idxs, min_col_idx, is_table_filter))) { LOG_WARN("Extract colum idx error", K(ret)); } } else { if (OB_FAIL(extract_row_col_idx( column_ids, index_col_pos, table_id, l_expr, r_expr, col_idxs, min_col_idx, is_table_filter))) { LOG_WARN("Extract colum idx error", K(ret)); } } if (OB_SUCC(ret)) { if (min_col_idx == column_ids.count()) { col_idx = TABLE_RELATED; } else if (min_col_idx >= 0) { col_idx = min_col_idx; } else { col_idx = is_table_filter ? TABLE_RELATED : INDEX_STORE_RELATED; } } } else { bool is_related = false; for (int64_t i = 0; OB_SUCC(ret) && !is_related && i < N; ++i) { if (OB_FAIL(SMART_CALL(extract_column_idx( column_ids, index_col_pos, table_id, raw_expr->get_param_expr(i), col_idx, col_idxs)))) { LOG_WARN("Extrac column idx error", K(ret)); } else if (TABLE_RELATED == col_idx) { is_related = true; } else { /*do nothing*/ } } } } return ret; } bool ObOptimizerUtil::is_query_range_op(const ObItemType type) { bool b_ret = false; if (IS_BASIC_CMP_OP(type) || T_OP_LIKE == type || T_OP_IS == type || T_OP_BTW == type || T_OP_NOT_BTW == type || T_OP_IN == type || T_OP_AND == type || T_OP_OR == type || T_OP_ROW == type) { b_ret = true; } return b_ret; } int ObOptimizerUtil::get_child_corresponding_exprs(const ObDMLStmt* upper_stmt, const ObSelectStmt* stmt, const ObIArray& exprs, ObIArray& corr_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(upper_stmt) || OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid stmt", K(upper_stmt), K(stmt), K(ret)); } else { uint64_t subquery_id = OB_INVALID_ID; if (OB_FAIL(get_subquery_id(upper_stmt, stmt, subquery_id))) { LOG_WARN("failed to get select exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_ISNULL(exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid expr", K(exprs.at(i)), K(i), K(ret)); } else if (!exprs.at(i)->is_column_ref_expr()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("not a column expr", K(exprs.at(i)), K(i), K(ret)); } else if (static_cast(exprs.at(i))->get_table_id() != subquery_id) { ret = corr_exprs.push_back(NULL); } else { int64_t idx = static_cast( static_cast(exprs.at(i))->get_column_id() - OB_APP_MIN_COLUMN_ID); ret = corr_exprs.push_back(stmt->get_select_item(idx).expr_); } } } } return ret; } int ObOptimizerUtil::get_child_corresponding_exprs( const TableItem* table, const ObIArray& exprs, ObIArray& corr_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(table) || OB_ISNULL(table->ref_query_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid stmt", KPC(table), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_ISNULL(exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid expr", K(exprs.at(i)), K(i), K(ret)); } else if (!exprs.at(i)->is_column_ref_expr()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("not a column expr", K(exprs.at(i)), K(i), K(ret)); } else if (static_cast(exprs.at(i))->get_table_id() != table->table_id_) { ret = corr_exprs.push_back(NULL); } else { int64_t idx = static_cast(static_cast(exprs.at(i))->get_column_id() - OB_APP_MIN_COLUMN_ID); ret = corr_exprs.push_back(table->ref_query_->get_select_item(idx).expr_); } } } return ret; } int ObOptimizerUtil::get_subquery_id(const ObDMLStmt* upper_stmt, const ObSelectStmt* stmt, uint64_t& id) { int ret = OB_SUCCESS; id = OB_INVALID_ID; if (OB_ISNULL(upper_stmt) || OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid stmt", K(upper_stmt), K(stmt), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && OB_INVALID_ID == id && i < upper_stmt->get_table_size(); ++i) { if (OB_ISNULL(upper_stmt->get_table_item(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid table item", K(upper_stmt->get_table_item(i)), K(ret)); } else if (upper_stmt->get_table_item(i)->is_generated_table() && upper_stmt->get_table_item(i)->ref_query_ == stmt) { id = upper_stmt->get_table_item(i)->table_id_; } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::is_table_on_null_side(const ObDMLStmt* stmt, uint64_t table_id, bool& is_on_null_side) { int ret = OB_SUCCESS; is_on_null_side = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("upper_stmt is null", K(ret)); } else { bool is_in_joined_table = false; for (int64_t i = 0; OB_SUCC(ret) && !is_in_joined_table && i < stmt->get_joined_tables().count(); i++) { JoinedTable* joined_table = stmt->get_joined_tables().at(i); if (OB_FAIL(is_table_on_null_side_recursively(joined_table, table_id, is_in_joined_table, is_on_null_side))) { LOG_WARN("Check for generated table on null side recursively fails", K(is_on_null_side), K(i), K(ret)); } } } return ret; } int ObOptimizerUtil::is_table_on_null_side_recursively( const TableItem* table_item, uint64_t table_id, bool& found, bool& is_on_null_side) { int ret = OB_SUCCESS; bool is_stack_overflow = false; found = false; is_on_null_side = false; if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(table_id), K(table_item), K(is_on_null_side)); } 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(find_table_item(table_item, table_id, found))) { LOG_WARN("Find table item fails", K(ret), K(table_id), K(found)); } else { if (table_item->is_joined_table() && found) { TableItem* left_table = NULL; TableItem* right_table = NULL; const JoinedTable* joined_table = static_cast(table_item); ObJoinType join_type = joined_table->joined_type_; if (OB_ISNULL(left_table = joined_table->left_table_) || OB_ISNULL(right_table = joined_table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(table_id), K(table_item), K(left_table), K(right_table), K(is_on_null_side)); } else if (FULL_OUTER_JOIN == join_type) { is_on_null_side = true; } else if (LEFT_OUTER_JOIN == join_type) { if (OB_FAIL(find_table_item(right_table, table_id, found))) { LOG_WARN("Find in joined table fails", K(ret)); } else if (found) { is_on_null_side = true; } else { if (OB_FAIL(SMART_CALL(is_table_on_null_side_recursively(left_table, table_id, found, is_on_null_side)))) { LOG_WARN("Checking for table on null side recursively fails", K(ret)); } } } else if (RIGHT_OUTER_JOIN == join_type) { if (OB_FAIL(find_table_item(left_table, table_id, found))) { LOG_WARN("Find in joined table fails", K(ret)); } else if (found) { is_on_null_side = true; } else { if (OB_FAIL(SMART_CALL(is_table_on_null_side_recursively(right_table, table_id, found, is_on_null_side)))) { LOG_WARN("Checking for table on null side recursively fails", K(ret)); } } } else { // Other join type if (OB_FAIL(SMART_CALL(is_table_on_null_side_recursively(left_table, table_id, found, is_on_null_side)))) { LOG_WARN("Checking for table on null side recursively fails", K(ret)); } if (OB_SUCC(ret) && !found) { if (OB_FAIL(SMART_CALL(is_table_on_null_side_recursively(right_table, table_id, found, is_on_null_side)))) { LOG_WARN("Checking for table on null side recursively fails", K(ret)); } } } } } return ret; } int ObOptimizerUtil::find_table_item(const TableItem* table_item, uint64_t table_id, bool& found) { int ret = OB_SUCCESS; found = false; if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("joined_table is null", K(ret), K(table_item)); } else if (table_item->is_joined_table()) { const JoinedTable* joined_table = static_cast(table_item); found = find_item(joined_table->single_table_ids_, table_id); } else { found = table_id == table_item->table_id_; } return ret; } int ObOptimizerUtil::get_referenced_columns(const ObDMLStmt* stmt, const uint64_t table_id, const common::ObIArray& keys, common::ObIArray& columns) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_stmt() returns null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_column_size(); ++i) { const ColumnItem* col_item = stmt->get_column_item(i); if (OB_ISNULL(col_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("col_item is null", K(i), K(ret)); } else if (OB_ISNULL(col_item->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else if (col_item->table_id_ == table_id && col_item->expr_->is_explicited_reference() && find_item(keys, col_item->expr_)) { ret = columns.push_back(col_item->expr_); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::get_non_referenced_columns(const ObDMLStmt* stmt, const uint64_t table_id, const common::ObIArray& keys, common::ObIArray& columns) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_stmt() returns null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_column_size(); ++i) { const ColumnItem* col_item = stmt->get_column_item(i); if (OB_ISNULL(col_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("col_item is null", K(i), K(ret)); } else if (OB_ISNULL(col_item->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else if (col_item->table_id_ == table_id && col_item->expr_->is_explicited_reference() && !find_item(keys, col_item->expr_)) { ret = columns.push_back(col_item->expr_); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::is_contain_nl_params( const ObIArray& filters, const int64_t max_param_num, bool& is_contain) { int ret = OB_SUCCESS; is_contain = false; for (int64_t i = 0; OB_SUCC(ret) && !is_contain && i < filters.count(); i++) { ObArray params; if (OB_FAIL(extract_params(filters.at(i), params))) { LOG_WARN("failed to extract_params", K(i), K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && !is_contain && j < params.count(); ++j) { int64_t param_value = -1; if (OB_ISNULL(params.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params.at(j) returns null", K(ret), K(j)); } else { param_value = static_cast(params.at(j))->get_value().get_unknown(); if (OB_SUCC(ret) && param_value >= max_param_num) { is_contain = true; } } } } } return ret; } int ObOptimizerUtil::extract_parameterized_correlated_filters(const ObIArray& filters, const int64_t max_param_num, ObIArray& correlated_filters, ObIArray& uncorrelated_filters) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < filters.count(); ++i) { ObArray params; if (OB_FAIL(extract_params(filters.at(i), params))) { LOG_WARN("failed to extract_params", K(i), K(ret)); } else { bool correlated = false; for (int64_t j = 0; OB_SUCC(ret) && !correlated && j < params.count(); ++j) { int64_t param_value = -1; if (OB_ISNULL(params.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params.at(j) returns null", K(ret), K(j)); } else { param_value = static_cast(params.at(j))->get_value().get_unknown(); } if (OB_SUCC(ret) && param_value >= max_param_num) { correlated = true; if (OB_FAIL(correlated_filters.push_back(filters.at(i)))) { LOG_WARN("failed to push back uncorrelated_filters", K(i), K(j), K(ret)); } } else { /* Do nothing */ } } if (OB_SUCC(ret) && !correlated) { if (OB_FAIL(uncorrelated_filters.push_back(filters.at(i)))) { LOG_WARN("failed to push back uncorrelated_filters", K(i), K(ret)); } } else { /* Do nothing */ } } } // end for return ret; } int ObOptimizerUtil::add_parameterized_expr( ObRawExpr*& target_expr, ObRawExpr* orig_expr, ObRawExpr* child_expr, int64_t child_idx) { int ret = OB_SUCCESS; if (OB_ISNULL(target_expr) || OB_ISNULL(child_expr) || OB_ISNULL(orig_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("null pointer passed in", K(ret)); } else { switch (target_expr->get_expr_class()) { case ObRawExpr::EXPR_CASE_OPERATOR: { ObCaseOpRawExpr* new_expr = static_cast(target_expr); ObCaseOpRawExpr* origin_expr = static_cast(orig_expr); if (0 > child_idx || child_idx >= origin_expr->get_param_count()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid index for case op operator", K(ret)); } else if (T_OP_ARG_CASE == orig_expr->get_expr_type()) { // param vector: arg expr, when expr, then expr ... default expr if (child_idx == 0) { new_expr->set_arg_param_expr(child_expr); } else if (child_idx == origin_expr->get_when_expr_size() + origin_expr->get_then_expr_size() + 1) { new_expr->set_default_param_expr(child_expr); } else if (child_idx & 1) { ret = new_expr->add_when_param_expr(child_expr); } else { ret = new_expr->add_then_param_expr(child_expr); } } else { // param vector: when expr, then expr ... default expr if (child_idx == origin_expr->get_when_expr_size() + origin_expr->get_then_expr_size()) { new_expr->set_default_param_expr(child_expr); } else if (child_idx & 1) { ret = new_expr->add_then_param_expr(child_expr); } else { ret = new_expr->add_when_param_expr(child_expr); } } break; } case ObRawExpr::EXPR_AGGR: { if (child_idx != 0 && T_FUN_GROUP_CONCAT != target_expr->get_expr_type() && T_FUN_COUNT != target_expr->get_expr_type()) { LOG_WARN("invalid index for agg expr except group_concat and count", K(ret), K(*orig_expr)); } else { ObAggFunRawExpr* cur_expr = static_cast(target_expr); // cur_expr->set_param_expr(to_add_expr); if (0 != cur_expr->get_real_param_count() && T_FUN_GROUP_CONCAT != cur_expr->get_expr_type() && T_FUN_COUNT != target_expr->get_expr_type()) { LOG_WARN("except group_concat and count, now, agg expr real param count must be 0", K(ret), K(*cur_expr)); } else if (OB_FAIL(cur_expr->add_real_param_expr(child_expr))) { LOG_WARN("failed to add expr to param expr", K(ret)); } } break; } case ObRawExpr::EXPR_OPERATOR: // fall through case ObRawExpr::EXPR_SYS_FUNC: case ObRawExpr::EXPR_UDF: { ObOpRawExpr* cur_expr = static_cast(target_expr); if (OB_FAIL(cur_expr->add_param_expr(child_expr))) { LOG_WARN("failed to add expr to param expr", K(ret)); } break; } default: ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid expr type passed in", K(ret)); } // switch case end } return ret; } int ObOptimizerUtil::extract_column_ids(const ObRawExpr* expr, const uint64_t table_id, ObIArray& column_ids) { int ret = OB_SUCCESS; ObSEArray columns; if (OB_FAIL(ObRawExprUtils::extract_column_exprs(expr, columns))) { LOG_WARN("failed to extract column exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { if (OB_ISNULL(columns.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column expr is NULL", K(i), K(columns.at(i)), K(ret)); } else if (!columns.at(i)->is_column_ref_expr()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid column expr", K(i), K(*columns.at(i)), K(ret)); } else { ObColumnRefRawExpr* column = static_cast(columns.at(i)); if (column->get_table_id() == table_id) { if (OB_FAIL(column_ids.push_back(column->get_column_id()))) { LOG_WARN("push back error", K(table_id), K(column->get_column_id()), K(ret)); } } } } } return ret; } int ObOptimizerUtil::extract_column_ids(const ObRawExpr* expr, const uint64_t table_id, ObBitSet<>& column_ids) { int ret = OB_SUCCESS; ObSEArray id_array; if (OB_FAIL(extract_column_ids(expr, table_id, id_array))) { LOG_WARN("failed to extract column ids", K(expr), K(table_id), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < id_array.count(); ++i) { if (OB_FAIL(column_ids.add_member(id_array.at(i)))) { LOG_WARN("add member error", K(id_array.at(i)), K(ret)); } } } return ret; } int ObOptimizerUtil::extract_column_ids( const ObIArray& exprs, const uint64_t table_id, ObIArray& column_ids) { int ret = OB_SUCCESS; ObSEArray ids; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(extract_column_ids(exprs.at(i), table_id, ids))) { LOG_WARN("failed to extract column ids", K(exprs.at(i)), K(table_id), K(ret)); } else if (OB_FAIL(append(column_ids, ids))) { LOG_WARN("add members error", K(ids), K(column_ids), K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::extract_column_ids( const ObIArray& exprs, const uint64_t table_id, ObBitSet<>& column_ids) { int ret = OB_SUCCESS; ObBitSet<> ids; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(extract_column_ids(exprs.at(i), table_id, ids))) { LOG_WARN("failed to extract column ids", K(exprs.at(i)), K(table_id), K(ret)); } else if (OB_FAIL(column_ids.add_members(ids))) { LOG_WARN("add members error", K(ids), K(column_ids), K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::is_same_table(const ObIArray& exprs, uint64_t& table_id, bool& is_same) { int ret = OB_SUCCESS; table_id = UINT64_MAX; is_same = false; if (exprs.count() > 0) { is_same = true; for (int64_t i = 0; OB_SUCC(ret) && is_same && i < exprs.count(); ++i) { if (!exprs.at(i).expr_->is_column_ref_expr()) { is_same = false; } else { ObColumnRefRawExpr* column = static_cast(exprs.at(i).expr_); if (UINT64_MAX == table_id) { table_id = column->get_table_id(); } else if (column->get_table_id() != table_id) { is_same = false; } } } } return ret; } int ObOptimizerUtil::make_sort_keys( const ObIArray& sort_exprs, const ObOrderDirection direction, ObIArray& sort_keys) { int ret = OB_SUCCESS; for (int64_t idx = 0; OB_SUCC(ret) && idx < sort_exprs.count(); ++idx) { if (OB_FAIL(sort_keys.push_back(OrderItem(sort_exprs.at(idx), direction)))) { LOG_WARN("Failed to add sort key", K(ret)); } } return ret; } int ObOptimizerUtil::make_sort_keys(const ObIArray& candi_sort_keys, const ObIArray& need_sort_exprs, ObIArray& sort_keys) { int ret = OB_SUCCESS; sort_keys.reset(); for (int64_t i = 0; OB_SUCC(ret) && i < candi_sort_keys.count() && sort_keys.count() < need_sort_exprs.count(); ++i) { if (candi_sort_keys.at(i).expr_ == need_sort_exprs.at(sort_keys.count())) { ret = sort_keys.push_back(candi_sort_keys.at(i)); } } if (OB_SUCC(ret) && sort_keys.count() != need_sort_exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected candi sort key/sort exprs", K(ret), K(candi_sort_keys), K(need_sort_exprs)); } return ret; } int ObOptimizerUtil::make_sort_keys(const ObIArray& candi_sort_exprs, const ObIArray& candi_directions, const ObIArray& need_sort_exprs, ObIArray& sort_keys) { int ret = OB_SUCCESS; sort_keys.reset(); if (candi_directions.count() != candi_sort_exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected candi sort exprs/directions count", K(ret), K(candi_sort_exprs), K(candi_directions)); } for (int64_t i = 0; OB_SUCC(ret) && i < candi_sort_exprs.count() && sort_keys.count() < need_sort_exprs.count(); ++i) { if (candi_sort_exprs.at(i) == need_sort_exprs.at(sort_keys.count())) { ret = sort_keys.push_back(OrderItem(candi_sort_exprs.at(i), candi_directions.at(i))); } } if (sort_keys.count() != need_sort_exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected candi sort key/sort exprs", K(ret), K(candi_sort_exprs), K(need_sort_exprs)); } return ret; } int ObOptimizerUtil::make_sort_keys(const ObIArray& sort_exprs, const ObIArray& directions, ObIArray& sort_keys) { int ret = OB_SUCCESS; if (sort_exprs.count() != directions.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("exprs number dismatches directions number", K(ret), K(sort_exprs.count()), K(directions.count())); } for (int64_t i = 0; OB_SUCC(ret) && i < sort_exprs.count(); ++i) { OrderItem sort_key(sort_exprs.at(i), directions.at(i)); if (OB_FAIL(sort_keys.push_back(sort_key))) { LOG_WARN("failed to add sort key", K(ret)); } } return ret; } int ObOptimizerUtil::split_expr_direction( const ObIArray& order_items, ObIArray& raw_exprs, ObIArray& directions) { int ret = OB_SUCCESS; for (int64_t idx = 0; OB_SUCC(ret) && idx < order_items.count(); ++idx) { if (OB_FAIL(raw_exprs.push_back(order_items.at(idx).expr_))) { LOG_WARN("Failed to add expr", K(ret)); } else if (OB_FAIL(directions.push_back(order_items.at(idx).order_type_))) { LOG_WARN("Failed to add direction", K(ret)); } else { } // do nothing } return ret; } int ObOptimizerUtil::check_equal_query_ranges( const ObIArray& ranges, const int64_t prefix_len, bool& all_prefix_equal, bool& all_full_equal) { int ret = OB_SUCCESS; all_prefix_equal = false; all_full_equal = false; if (prefix_len < 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(prefix_len), K(ret)); } else if (0 == ranges.count()) { // do nothing } else { int64_t rowkey_count = -1; int64_t equal_prefix_count = -1; int64_t equal_prefix_null_count = 0; int64_t range_prefix_count = -1; bool contain_always_false = false; if (OB_ISNULL(ranges.at(0)) || OB_UNLIKELY((rowkey_count = ranges.at(0)->start_key_.length()) <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected error", K(rowkey_count), K(ranges.at(0)), K(ret)); } else if (OB_FAIL(check_prefix_ranges_count( ranges, equal_prefix_count, equal_prefix_null_count, range_prefix_count, contain_always_false))) { LOG_WARN("failed to check ranges prefix count", K(ret)); } else { if (prefix_len <= equal_prefix_count) { all_prefix_equal = true; } if (prefix_len == rowkey_count) { all_full_equal = true; } } } return ret; } int ObOptimizerUtil::check_prefix_ranges_count(const ObIArray& ranges, int64_t& equal_prefix_count, int64_t& equal_prefix_null_count, int64_t& range_prefix_count, bool& contain_always_false) { int ret = OB_SUCCESS; equal_prefix_count = 0; equal_prefix_null_count = 0; range_prefix_count = 0; contain_always_false = false; if (ranges.count() > 0) { equal_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; range_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; for (int64_t i = 0; OB_SUCC(ret) && i < ranges.count(); ++i) { ObNewRange* range = ranges.at(i); int64_t temp_equal_prefix_count = 0; int64_t temp_range_prefix_count = 0; if (OB_ISNULL(range)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null query range", K(ret)); } else if (range->start_key_.length() != range->end_key_.length()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid start and end range key", K(range->start_key_.length()), K(range->end_key_.length()), K(ret)); } else if (range->start_key_.ptr()[0].is_max_value() && range->end_key_.ptr()[0].is_min_value()) { contain_always_false = true; equal_prefix_count = 0; range_prefix_count = 0; } else if (OB_FAIL(check_prefix_range_count(range, temp_equal_prefix_count, temp_range_prefix_count))) { LOG_WARN("failed to check range prefix", K(ret)); } else { equal_prefix_count = std::min(equal_prefix_count, temp_equal_prefix_count); range_prefix_count = std::min(range_prefix_count, temp_range_prefix_count); } } for (int64_t i = 0; OB_SUCC(ret) && i < ranges.count(); ++i) { const ObNewRange* range = ranges.at(i); int64_t temp_equal_prefix_null_count = 0; if (OB_FAIL(check_equal_prefix_null_count(range, equal_prefix_count, temp_equal_prefix_null_count))) { LOG_WARN("failed to check range prefix", K(ret)); } else { equal_prefix_null_count = std::max(equal_prefix_null_count, temp_equal_prefix_null_count); } } } return ret; } int ObOptimizerUtil::check_prefix_ranges_count(const ObIArray& ranges, int64_t& equal_prefix_count, int64_t& equal_prefix_null_count, int64_t& range_prefix_count) { int ret = OB_SUCCESS; equal_prefix_count = 0; equal_prefix_null_count = 0; range_prefix_count = 0; if (ranges.count() > 0) { equal_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; range_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; for (int64_t i = 0; OB_SUCC(ret) && i < ranges.count(); ++i) { const ObNewRange& range = ranges.at(i); int64_t temp_equal_prefix_count = 0; int64_t temp_range_prefix_count = 0; if (range.start_key_.length() != range.end_key_.length()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid start and end range key", K(range.start_key_.length()), K(range.end_key_.length()), K(ret)); } else if (OB_FAIL(check_prefix_range_count(&range, temp_equal_prefix_count, temp_range_prefix_count))) { LOG_WARN("failed to check range prefix", K(ret)); } else { equal_prefix_count = std::min(equal_prefix_count, temp_equal_prefix_count); range_prefix_count = std::min(range_prefix_count, temp_range_prefix_count); } } for (int64_t i = 0; OB_SUCC(ret) && i < ranges.count(); ++i) { const ObNewRange& range = ranges.at(i); int64_t temp_equal_prefix_null_count = 0; if (OB_FAIL(check_equal_prefix_null_count(&range, equal_prefix_count, temp_equal_prefix_null_count))) { LOG_WARN("failed to check range prefix", K(ret)); } else { equal_prefix_null_count = std::max(equal_prefix_null_count, temp_equal_prefix_null_count); } } } return ret; } int ObOptimizerUtil::check_equal_prefix_null_count( const common::ObNewRange* range, const int64_t equal_prefix_count, int64_t& equal_prefix_null_count) { int ret = OB_SUCCESS; equal_prefix_null_count = 0; if (OB_ISNULL(range)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null query range", K(ret)); } else if (range->start_key_.length() != range->end_key_.length() || equal_prefix_count > range->start_key_.length()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid start and end range key", K(ret), K(equal_prefix_count), K(range->start_key_.length()), K(range->end_key_.length())); } for (int64_t i = 0; OB_SUCC(ret) && i < equal_prefix_count; ++i) { if (range->start_key_.ptr()[i] != range->end_key_.ptr()[i]) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected equal range", K(ret), K(range->start_key_.ptr()[i]), K(range->end_key_.ptr()[i])); } else if ((is_oracle_mode() && range->start_key_.ptr()[i].is_null_oracle()) || range->start_key_.ptr()[i].is_null()) { ++equal_prefix_null_count; } else { /* do nothing */ } } return ret; } int ObOptimizerUtil::check_prefix_range_count( const common::ObNewRange* range, int64_t& equal_prefix_count, int64_t& range_prefix_count) { int ret = OB_SUCCESS; equal_prefix_count = 0; range_prefix_count = 0; if (OB_ISNULL(range)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null query range", K(ret)); } else if (range->start_key_.length() != range->end_key_.length()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid start and end range key", K(range->start_key_.length()), K(range->end_key_.length()), K(ret)); } else { equal_prefix_count = range->start_key_.length(); for (int64_t i = 0; OB_SUCC(ret) && i < range->start_key_.length() && equal_prefix_count == range->start_key_.length(); ++i) { if (range->start_key_.ptr()[i].is_min_value() || range->start_key_.ptr()[i].is_max_value() || range->end_key_.ptr()[i].is_min_value() || range->end_key_.ptr()[i].is_max_value()) { equal_prefix_count = i; } else if (range->start_key_.ptr()[i] != range->end_key_.ptr()[i]) { equal_prefix_count = i; } else { /* do nothing */ } } range_prefix_count = range->start_key_.length(); for (int64_t i = 0; OB_SUCC(ret) && i < range->start_key_.length() && range_prefix_count == range->start_key_.length(); ++i) { if ((range->start_key_.ptr()[i].is_min_value() || range->start_key_.ptr()[i].is_max_value()) && (range->end_key_.ptr()[i].is_min_value() || range->end_key_.ptr()[i].is_max_value())) { range_prefix_count = i; } else if (range->start_key_.ptr()[i].is_min_value() || range->start_key_.ptr()[i].is_max_value() || range->end_key_.ptr()[i].is_min_value() || range->end_key_.ptr()[i].is_max_value() || range->start_key_.ptr()[i] != range->end_key_.ptr()[i]) { range_prefix_count = i + 1; } else { /*do nothing*/ } } } return ret; } bool ObOptimizerUtil::same_partition_exprs(const common::ObIArray& l_exprs, const common::ObIArray& r_exprs, const EqualSets& equal_sets) { bool same = true; for (int64_t i = 0; i < l_exprs.count(); ++i) { same = find_equal_expr(r_exprs, l_exprs.at(i), equal_sets); if (!same) { break; } } if (same) { for (int64_t i = 0; i < r_exprs.count(); ++i) { same = find_equal_expr(l_exprs, r_exprs.at(i), equal_sets); if (!same) { break; } } } return same; } int ObOptimizerUtil::classify_subquery_exprs( const ObIArray& exprs, ObIArray& subquery_exprs, ObIArray& non_subquery_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); i++) { ObRawExpr* temp_expr = exprs.at(i); if (OB_ISNULL(temp_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret), K(temp_expr), K(ret)); } else if (temp_expr->has_flag(CNT_SUB_QUERY)) { // used to allocate subplan filter if (OB_FAIL(subquery_exprs.push_back(temp_expr))) { LOG_WARN("failed to push back subquery exprs", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(non_subquery_exprs.push_back(temp_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::get_subquery_exprs(const ObIArray& exprs, ObIArray& subquery_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); i++) { if (OB_ISNULL(exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret)); } else if (exprs.at(i)->has_flag(CNT_SUB_QUERY) && OB_FAIL(subquery_exprs.push_back(exprs.at(i)))) { LOG_WARN("failed to push back exprs", K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::check_is_onetime_expr(const ObIArray>& onetime_exprs, ObRawExpr* expr, ObDMLStmt* stmt, bool& is_onetime_expr) { int ret = OB_SUCCESS; bool contains = false; is_onetime_expr = false; if (OB_ISNULL(expr) || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(expr), K(stmt), K(ret)); } else if (expr->get_expr_levels().has_member(stmt->get_current_level())) { // do nothing } else if (OB_FAIL(check_expr_contain_sharable_subquery( expr, stmt->get_current_level(), onetime_exprs, true, contains))) { LOG_WARN("failed to check expr contain onetime expr", K(ret)); } else if (contains) { /*do nothing*/ } else if (has_psedu_column(*expr) || has_hierarchical_expr(*expr)) { // do nothing } else if (expr->has_flag(IS_SUB_QUERY)) { is_onetime_expr = expr->get_output_column() == 1 && !static_cast(expr)->is_set(); } else if (expr->has_flag(CNT_SUB_QUERY)) { if (T_FUN_COLUMN_CONV != expr->get_expr_type() && expr->get_expr_type() != T_OP_ROW && !expr->is_win_func_expr()) { is_onetime_expr = true; } } if (is_onetime_expr) { bool has_ref_assign_user_var = false; if (OB_FAIL(check_subquery_has_ref_assign_user_var(expr, has_ref_assign_user_var))) { LOG_WARN("failed to check expr on onetime valid", K(ret)); } else if (has_ref_assign_user_var) { is_onetime_expr = false; } else { is_onetime_expr = true; } } LOG_TRACE("succeed to check if expr is onetime", K(stmt->get_current_level()), K(expr->get_expr_levels()), K(*expr), K(contains), K(is_onetime_expr)); return ret; } int ObOptimizerUtil::get_non_const_expr_size(const ObIArray& exprs, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& number) { int ret = OB_SUCCESS; bool is_const = false; number = 0; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(is_const_expr(exprs.at(i), equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check is const expr", K(ret)); } else if (!is_const) { ++number; } } return ret; } int ObOptimizerUtil::classify_get_scan_ranges(const common::ObIArray& input_ranges, common::ObIAllocator& allocator, common::ObIArray& get_ranges, common::ObIArray& scan_ranges, const ObTableSchema* table_schema /* NULL */, const bool should_trans_rowid /* false */) { int ret = OB_SUCCESS; ObArray used_input_ranges; for (int i = 0; OB_SUCC(ret) && i < input_ranges.count(); i++) { bool contain_rowid_range = false; if (!should_trans_rowid) { // do nothing } else if (!input_ranges.at(i).start_key_.is_min_row() && !input_ranges.at(i).start_key_.is_max_row() && input_ranges.at(i).is_valid()) { contain_rowid_range = ob_is_urowid(input_ranges.at(i).start_key_.get_obj_ptr()[0].get_type()); } else if (!input_ranges.at(i).end_key_.is_min_row() && !input_ranges.at(i).end_key_.is_max_row() && input_ranges.at(i).end_key_.is_valid()) { contain_rowid_range = ob_is_urowid(input_ranges.at(i).end_key_.get_obj_ptr()[0].get_type()); } if (contain_rowid_range) { LOG_TRACE("start to transform rowid range to pk range", K(input_ranges.at(i))); ObNewRange tmp_range; ObSEArray rowkey_descs; if (OB_ISNULL(table_schema)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("table_schema is NULL", K(ret)); } else if (OB_FAIL(deep_copy_range(allocator, input_ranges.at(i), tmp_range))) { LOG_WARN("failde to deep copy range", K(ret)); } else if (OB_FAIL(table_schema->get_rowkey_column_ids(rowkey_descs))) { LOG_WARN("get rowkey column desc failed", K(ret)); } else if (OB_FAIL(ObTableScan::transform_rowid_range(allocator, rowkey_descs, tmp_range))) { LOG_WARN("failed to transform rowid range", K(ret)); } else if (OB_FAIL(used_input_ranges.push_back(tmp_range))) { LOG_WARN("failed to push back range", K(ret)); } } else if (OB_FAIL(used_input_ranges.push_back(input_ranges.at(i)))) { LOG_WARN("failde to push back range", K(ret)); } if (OB_SUCC(ret)) { LOG_TRACE("used input range", K(used_input_ranges.at(used_input_ranges.count() - 1))); } } for (int64_t i = 0; OB_SUCC(ret) && i < used_input_ranges.count(); i++) { if (used_input_ranges.at(i).is_single_rowkey()) { if (OB_FAIL(get_ranges.push_back(used_input_ranges.at(i)))) { LOG_WARN("failed to push back ranges", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(scan_ranges.push_back(used_input_ranges.at(i)))) { LOG_WARN("failed to push back scan ranges", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::is_exprs_unique(const ObIArray& ordering, const ObIArray& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& order_unique) { int ret = OB_SUCCESS; ObSEArray order_exprs; ObSEArray order_directions; order_unique = false; if (OB_FAIL(split_expr_direction(ordering, order_exprs, order_directions))) { LOG_WARN("failed to split expr and direction", K(ret)); } else if (OB_FAIL(is_exprs_unique(order_exprs, fd_item_set, equal_sets, const_exprs, order_unique))) { LOG_WARN("failed to check is order unique", K(ret)); } return ret; } int ObOptimizerUtil::is_exprs_unique(const ObIArray& ordering, const ObRelIds& all_tables, const ObIArray& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& order_unique) { int ret = OB_SUCCESS; ObSEArray order_exprs; ObSEArray order_directions; order_unique = false; if (OB_FAIL(split_expr_direction(ordering, order_exprs, order_directions))) { LOG_WARN("failed to split expr and direction", K(ret)); } else if (OB_FAIL(is_exprs_unique(order_exprs, all_tables, fd_item_set, equal_sets, const_exprs, order_unique))) { LOG_WARN("failed to check is order unique", K(ret)); } return ret; } int ObOptimizerUtil::is_exprs_unique(const ObIArray& exprs, const ObRelIds& all_tables, const ObIArray& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_unique) { int ret = OB_SUCCESS; is_unique = false; ObSEArray fd_set_parent_exprs; ObSEArray extend_exprs; if (0 == all_tables.num_members()) { // select RANK() OVER() from dual if (OB_FAIL(is_exprs_unique(exprs, fd_item_set, equal_sets, const_exprs, is_unique))) { LOG_WARN("failed to check is exprs unique", K(ret)); } } else if (OB_FAIL(extend_exprs.assign(exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(get_fd_set_parent_exprs(fd_item_set, fd_set_parent_exprs))) { LOG_WARN("failed to get fd set parent exprs ", K(ret)); } else if (OB_FAIL(remove_item(fd_set_parent_exprs, extend_exprs))) { LOG_WARN("failed to get fd set parent exprs ", K(ret)); } else { ObRelIds remain_tables = all_tables; ObSqlBitSet<> skip_fd; int64_t exprs_count = -1; for (int64_t i = 0; OB_SUCC(ret) && !is_unique && i < 10 && extend_exprs.count() != exprs_count; ++i) { exprs_count = extend_exprs.count(); if (OB_FAIL(is_exprs_unique(extend_exprs, remain_tables, fd_item_set, fd_set_parent_exprs, skip_fd, equal_sets, const_exprs, is_unique))) { LOG_WARN("failed to get fd set parent exprs ", K(ret)); } } } return ret; } int ObOptimizerUtil::is_exprs_unique(ObIArray& extend_exprs, ObRelIds& remain_tables, const ObIArray& fd_item_set, ObIArray& fd_set_parent_exprs, ObSqlBitSet<>& skip_fd, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_unique) { int ret = OB_SUCCESS; bool is_contain = false; ObFdItem* fd_item = NULL; for (int64_t i = 0; OB_SUCC(ret) && !is_unique && i < fd_item_set.count(); ++i) { is_contain = false; if (OB_ISNULL(fd_item = fd_item_set.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (skip_fd.has_member(i)) { /*do nothing*/ } else if (fd_item->is_unique()) { // unique fd item if (OB_FAIL(is_exprs_contain_fd_parent(extend_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("failed to check is order unique", K(ret)); } else if (is_contain) { is_unique = true; } } else if (fd_item->is_table_fd_item()) { // not unique table fd item ObTableFdItem* table_fd_item = static_cast(fd_item); if (!remain_tables.overlap(table_fd_item->get_child_tables())) { /*do nothing*/ } else if (OB_FAIL(is_exprs_contain_fd_parent(extend_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("failed to check is order unique", K(ret)); } else if (!is_contain) { /*do nothing*/ } else if (OB_FAIL(remain_tables.del_members(table_fd_item->get_child_tables()))) { LOG_WARN("failed to delete members", K(ret)); } else if (OB_FAIL(split_child_exprs(fd_item, equal_sets, fd_set_parent_exprs, extend_exprs))) { LOG_WARN("failed to delete members", K(ret)); } is_unique = (0 == remain_tables.num_members()); } else { // not unique expr fd item if (OB_FAIL(is_exprs_contain_fd_parent(extend_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("failed to check is order unique", K(ret)); } else if (is_contain && OB_FAIL(split_child_exprs(fd_item, equal_sets, fd_set_parent_exprs, extend_exprs))) { LOG_WARN("failed to delete members", K(ret)); } } if (OB_SUCC(ret) && is_contain && OB_FAIL(skip_fd.add_member(i))) { LOG_WARN("failed to add member", K(ret)); } } return ret; } int ObOptimizerUtil::is_exprs_unique(const ObIArray& exprs, const ObIArray& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_unique) { int ret = OB_SUCCESS; is_unique = false; for (int64_t i = 0; OB_SUCC(ret) && !is_unique && i < fd_item_set.count(); ++i) { if (OB_ISNULL(fd_item_set.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (!fd_item_set.at(i)->is_unique()) { // do nothing } else if (OB_FAIL(is_exprs_contain_fd_parent(exprs, *fd_item_set.at(i), equal_sets, const_exprs, is_unique))) { LOG_WARN("failed to check is order unique", K(ret)); } } return ret; } int ObOptimizerUtil::get_fd_set_parent_exprs( const ObIArray& fd_item_set, ObIArray& fd_set_parent_exprs) { int ret = OB_SUCCESS; ObFdItem* fd_item = NULL; const ObRawExprSet* parent_exprs = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < fd_item_set.count(); ++i) { if (OB_ISNULL(fd_item = fd_item_set.at(i)) || OB_ISNULL(parent_exprs = fd_item->get_parent_exprs())) { LOG_WARN("unexpected null", K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && j < parent_exprs->count(); ++j) { if (add_var_to_array_no_dup(fd_set_parent_exprs, parent_exprs->at(j))) { LOG_WARN("failed to append array no dup", K(ret)); } } } } return ret; } int ObOptimizerUtil::split_child_exprs(const ObFdItem* fd_item, const EqualSets& equal_sets, ObIArray& exprs, ObIArray& child_exprs) { int ret = OB_SUCCESS; ObSEArray other_exprs; bool is_in_child = false; if (OB_ISNULL(fd_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(fd_item->check_expr_in_child(exprs.at(i), equal_sets, is_in_child))) { LOG_WARN("failed to check expr in child", K(ret)); } else if (is_in_child) { ret = child_exprs.push_back(exprs.at(i)); } else { ret = other_exprs.push_back(exprs.at(i)); } } if (OB_SUCC(ret) && OB_FAIL(exprs.assign(other_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } return ret; } int ObOptimizerUtil::is_exprs_contain_fd_parent(const ObIArray& exprs, const ObFdItem& fd_item, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& is_contain) { int ret = OB_SUCCESS; is_contain = true; bool is_const = false; const ObRawExprSet* parent_exprs = NULL; if (OB_ISNULL(parent_exprs = fd_item.get_parent_exprs())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null parent exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && is_contain && i < parent_exprs->count(); ++i) { if (find_equal_expr(exprs, parent_exprs->at(i), equal_sets)) { // do nothing } else if (OB_FAIL(is_const_expr(parent_exprs->at(i), equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check is const expr", K(ret)); } else if (!is_const) { is_contain = false; } } } return ret; } // n to 1 join, if left side fd item is unique or can function dependent join exprs, // then left side fd item can function dependent right side's table set int ObOptimizerUtil::add_fd_item_set_for_n21_join(ObFdItemFactory& fd_factory, ObIArray& target, const ObIArray& source, const ObIArray& join_exprs, const EqualSets& equal_sets, const ObRelIds& right_table_set) { int ret = OB_SUCCESS; ObLogPlan* plan = NULL; bool is_in_child = false; // if join unique, matched fd item must be table level fd item for (int64_t i = 0; OB_SUCC(ret) && i < source.count(); ++i) { ObFdItem* fd_item = source.at(i); bool fd_other_side = false; if (OB_ISNULL(fd_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (fd_item->is_unique()) { fd_other_side = true; } else if (OB_FAIL(fd_item->check_exprs_in_child(join_exprs, equal_sets, is_in_child))) { LOG_WARN("failed to check exprs in child", K(ret)); } else if (is_in_child) { fd_other_side = true; } if (OB_SUCC(ret)) { if (fd_other_side) { ObTableFdItem* new_fd_item = NULL; if (fd_item->is_table_fd_item()) { // source fd item and matched fd item are both table level if (OB_FAIL(fd_factory.create_table_fd_item(new_fd_item, *static_cast(fd_item)))) { LOG_WARN("failed to copy fd item", K(ret)); } // source fd item is expr level but matched fd item is table level } else if (OB_FAIL(fd_factory.create_table_fd_item( new_fd_item, fd_item->is_unique(), fd_item->get_parent_exprs(), fd_item->get_stmt_level()))) { LOG_WARN("failed to create fd item", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(new_fd_item->get_child_tables().add_members(right_table_set))) { LOG_WARN("failed to add members to child tables", K(ret)); } else if (OB_FAIL(target.push_back(new_fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } } else if (OB_FAIL(target.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } } return ret; } // n to n join, source fd item not unique anymore int ObOptimizerUtil::add_fd_item_set_for_n2n_join( ObFdItemFactory& fd_factory, ObIArray& target, const ObIArray& source) { int ret = OB_SUCCESS; ObFdItem* new_fd_item = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < source.count(); ++i) { const ObFdItem* fd_item = source.at(i); if (OB_ISNULL(fd_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (!fd_item->is_unique()) { new_fd_item = const_cast(fd_item); } else if (OB_FAIL(fd_factory.copy_fd_item(new_fd_item, *fd_item))) { LOG_WARN("failed to copy fd item", K(ret)); } else { new_fd_item->set_is_unique(false); } if (OB_SUCC(ret)) { if (OB_FAIL(target.push_back(new_fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } } return ret; } int ObOptimizerUtil::enhance_fd_item_set(const ObIArray& quals, ObIArray& candi_fd_item_set, ObIArray& fd_item_set, ObIArray& not_null_columns) { int ret = OB_SUCCESS; bool is_happend = false; ObFdItem* fd_item = NULL; ObRawExprSet* parent_exprs = NULL; ObSEArray unused; for (int64_t i = 0; OB_SUCC(ret) && i < candi_fd_item_set.count(); ++i) { if (OB_ISNULL(fd_item = candi_fd_item_set.at(i)) || OB_ISNULL(parent_exprs = fd_item->get_parent_exprs())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else { bool all_not_null = true; bool contain_not_null = false; for (int64_t j = 0; OB_SUCC(ret) && j < parent_exprs->count(); ++j) { ObRawExpr* cur_expr = parent_exprs->at(j); bool has_null_reject = false; if (ObOptimizerUtil::find_item(not_null_columns, cur_expr)) { contain_not_null = true; } else if (OB_FAIL(ObTransformUtils::has_null_reject_condition(quals, cur_expr, has_null_reject))) { LOG_WARN("failed to check has null reject condition", K(ret)); } else if (!has_null_reject) { all_not_null = false; } else if (OB_FAIL(not_null_columns.push_back(cur_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { contain_not_null = true; } } if (OB_SUCC(ret)) { if (all_not_null || (share::is_oracle_mode() && contain_not_null)) { is_happend = true; if (OB_FAIL(fd_item_set.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } else if (OB_FAIL(unused.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } } } if (OB_SUCC(ret) && is_happend) { if (OB_FAIL(candi_fd_item_set.assign(unused))) { LOG_WARN("failed to assign candi fd item set", K(ret)); } } return ret; } int ObOptimizerUtil::try_add_fd_item(ObDMLStmt* stmt, ObFdItemFactory& fd_factory, const uint64_t table_id, ObRelIds& tables, const ObTableSchema* index_schema, const ObIArray& quals, ObIArray& not_null_columns, ObIArray& fd_item_set, ObIArray& candi_fd_item_set) { int ret = OB_SUCCESS; bool all_columns_used = true; bool all_not_null = true; bool contain_not_null = false; TableItem* table = NULL; ObSEArray column_ids; ObSEArray unique_exprs; if (OB_ISNULL(stmt) || OB_ISNULL(index_schema) || OB_ISNULL(table = stmt->get_table_item_by_id(table_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt), K(index_schema)); } else if (is_virtual_table(table->ref_id_)) { } else if (!index_schema->get_rowkey_info().is_valid()) { // do nothing } else if (OB_FAIL(index_schema->get_rowkey_info().get_column_ids(column_ids))) { LOG_WARN("failed to get index cols", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && all_columns_used && i < column_ids.count(); ++i) { ObRawExpr* col_expr = NULL; bool is_not_null = false; if (is_shadow_column(column_ids.at(i))) { continue; } else if (column_ids.at(i) == OB_HIDDEN_PK_PARTITION_COLUMN_ID || column_ids.at(i) == OB_HIDDEN_PK_CLUSTER_COLUMN_ID) { continue; // do nothing } else if (OB_ISNULL(col_expr = stmt->get_column_expr_by_id(table_id, column_ids.at(i)))) { // column is not used by current stmt, skip all_columns_used = false; } else if (OB_FAIL(unique_exprs.push_back(col_expr))) { LOG_WARN("failed to push back unique col", K(ret)); } else if (ObOptimizerUtil::find_item(not_null_columns, col_expr)) { // col_expr is not null contain_not_null = true; continue; } else if ((is_not_null = col_expr->is_not_null())) { // do nothing } else if (OB_FAIL(ObTransformUtils::has_null_reject_condition(quals, col_expr, is_not_null))) { LOG_WARN("failed to check whether has null reject condition", K(ret)); } if (OB_FAIL(ret)) { } else if (!is_not_null) { all_not_null = false; } else if (OB_FAIL(not_null_columns.push_back(col_expr))) { LOG_WARN("failed to add not null col", K(ret)); } else { contain_not_null = true; } } if (OB_SUCC(ret) && all_columns_used && unique_exprs.count() > 0) { ObTableFdItem* fd_item = NULL; if (OB_FAIL(fd_factory.create_table_fd_item(fd_item, true, unique_exprs, stmt->get_current_level(), tables))) { LOG_WARN("failed to create fd item", K(ret)); } else if (all_not_null || (share::is_oracle_mode() && contain_not_null) || index_schema->get_table_id() == table->ref_id_) { if (OB_FAIL(fd_item_set.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } else if (OB_FAIL(candi_fd_item_set.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } } return ret; } int ObOptimizerUtil::convert_subplan_scan_equal_sets(ObIAllocator* allocator, ObRawExprFactory& expr_factory, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, const EqualSets& input_equal_sets, EqualSets& output_equal_sets) { int ret = OB_SUCCESS; EqualSets dummy_equal_sets; ObSEArray raw_eset; for (int64_t i = 0; OB_SUCC(ret) && i < input_equal_sets.count(); ++i) { const EqualSet* input_eset = input_equal_sets.at(i); raw_eset.reuse(); if (OB_ISNULL(input_eset)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::convert_subplan_scan_expr( expr_factory, dummy_equal_sets, table_id, parent_stmt, child_stmt, true, *input_eset, raw_eset))) { LOG_WARN("failed to convert subplan scan expr", K(ret)); } else if (raw_eset.count() > 1 && OB_FAIL(ObRawExprSetUtils::add_expr_set(allocator, raw_eset, output_equal_sets))) { LOG_WARN("failed to push back equal set", K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::convert_subplan_scan_fd_item_sets(ObFdItemFactory& fd_factory, ObRawExprFactory& expr_factory, const EqualSets& equal_sets, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, const ObFdItemSet& input_fd_item_sets, ObFdItemSet& output_fd_item_sets) { int ret = OB_SUCCESS; ObSEArray new_parent_exprs; int32_t stmt_level = parent_stmt.get_current_level(); ObRelIds tables; if (OB_FAIL(tables.add_member(parent_stmt.get_table_bit_index(table_id)))) { LOG_WARN("failed to add relid", K(ret), K(parent_stmt), K(table_id)); } for (int64_t i = 0; OB_SUCC(ret) && i < input_fd_item_sets.count(); ++i) { ObRawExprSet* parent_set = NULL; const ObFdItem* old_fd_item = NULL; new_parent_exprs.reuse(); if (OB_ISNULL(old_fd_item = input_fd_item_sets.at(i)) || OB_ISNULL(old_fd_item->get_parent_exprs())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(old_fd_item)); } else if (OB_FAIL(ObOptimizerUtil::convert_subplan_scan_expr(expr_factory, equal_sets, table_id, parent_stmt, child_stmt, false, *old_fd_item->get_parent_exprs(), new_parent_exprs))) { LOG_WARN("failed to convert subplan scan expr", K(ret)); } else if (new_parent_exprs.empty()) { /*do nothing*/ } else if (old_fd_item->is_unique()) { ObTableFdItem* table_fd_item = NULL; if (OB_FAIL(fd_factory.create_table_fd_item(table_fd_item, true, new_parent_exprs, stmt_level, tables))) { LOG_WARN("failed to create fd item", K(ret)); } else if (OB_FAIL(output_fd_item_sets.push_back(table_fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } else { ObRawExpr* temp_expr = NULL; ObSEArray child_select_exprs; ObSEArray new_child_exprs; ObExprFdItem* expr_fd_item = NULL; if (OB_FAIL(child_stmt.get_select_exprs(child_select_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && j < child_select_exprs.count(); ++j) { bool is_in_child = false; if (OB_FAIL(old_fd_item->check_expr_in_child(child_select_exprs.at(j), equal_sets, is_in_child))) { LOG_WARN("failed to check expr in child"); } else if (!is_in_child) { /*do nothing*/ } else if (NULL == (temp_expr = parent_stmt.get_column_expr_by_id(table_id, OB_APP_MIN_COLUMN_ID + j))) { /*do nothing*/ } else if (OB_FAIL(new_child_exprs.push_back(temp_expr))) { LOG_WARN("failed to push back exprs", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret) && !new_child_exprs.empty()) { if (OB_FAIL( fd_factory.create_expr_fd_item(expr_fd_item, false, new_parent_exprs, stmt_level, new_child_exprs))) { LOG_WARN("failed to create fd item", K(ret)); } else if (OB_FAIL(output_fd_item_sets.push_back(expr_fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } else { /*do nothing*/ } } } } } return ret; } int ObOptimizerUtil::add_fd_item_set_for_left_join(ObFdItemFactory& fd_factory, const ObRelIds& right_tables, const ObIArray& right_join_exprs, const ObIArray& right_const_exprs, const EqualSets& right_equal_sets, const ObIArray& right_fd_item_sets, const ObIArray& all_left_join_exprs, const EqualSets& left_equal_sets, const ObIArray& left_fd_item_sets, const ObIArray& left_candi_fd_item_sets, ObIArray& fd_item_sets, ObIArray& candi_fd_item_sets) { int ret = OB_SUCCESS; bool right_is_unique = false; if (OB_FAIL(is_exprs_unique( right_join_exprs, right_tables, right_fd_item_sets, right_equal_sets, right_const_exprs, right_is_unique))) { LOG_WARN("failed to check is order unique", K(ret)); } else if (right_is_unique) { if (OB_FAIL(add_fd_item_set_for_n21_join( fd_factory, fd_item_sets, left_fd_item_sets, all_left_join_exprs, left_equal_sets, right_tables))) { LOG_WARN("failed to add fd item set for n21 join", K(ret)); } else if (OB_FAIL(add_fd_item_set_for_n21_join(fd_factory, candi_fd_item_sets, left_candi_fd_item_sets, all_left_join_exprs, left_equal_sets, right_tables))) { LOG_WARN("failed to add fd item set for n21 join", K(ret)); } } else if (OB_FAIL(add_fd_item_set_for_n2n_join(fd_factory, fd_item_sets, left_fd_item_sets))) { LOG_WARN("failed to add fd item set for n2n join", K(ret)); } else if (OB_FAIL(add_fd_item_set_for_n2n_join(fd_factory, candi_fd_item_sets, left_candi_fd_item_sets))) { LOG_WARN("failed to add fd item set for n2n join", K(ret)); } return ret; } int ObOptimizerUtil::check_need_sort(const ObIArray& expected_order_items, const ObIArray& input_ordering, const ObFdItemSet& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, const bool is_at_most_one_row, bool& need_sort) { int ret = OB_SUCCESS; ObSEArray expected_order_exprs; ObSEArray expected_order_directions; if (OB_FAIL(split_expr_direction(expected_order_items, expected_order_exprs, expected_order_directions))) { LOG_WARN("failed to split expr and expected_order_directions", K(ret)); } else if (OB_FAIL(check_need_sort(expected_order_exprs, &expected_order_directions, input_ordering, fd_item_set, equal_sets, const_exprs, is_at_most_one_row, need_sort))) { LOG_WARN("failed to check need sort", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::check_need_sort(const ObIArray& expected_order_exprs, const ObIArray* expected_order_directions, const ObIArray& input_ordering, const ObFdItemSet& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, const bool is_at_most_one_row, bool& need_sort) { int ret = OB_SUCCESS; need_sort = true; int64_t left_count = input_ordering.count(); int64_t right_count = expected_order_exprs.count(); int64_t l_idx = 0; int64_t r_idx = 0; ObSqlBitSet<> left_set; ObSqlBitSet<> right_set; ObSqlBitSet<> used_fd; ObSEArray extend_exprs; ObSEArray fd_set_parent_exprs; bool find_unique = false; bool is_match = true; bool left_is_const = false; bool right_is_const = false; if (is_at_most_one_row) { need_sort = false; } else { if (OB_FAIL(get_fd_set_parent_exprs(fd_item_set, fd_set_parent_exprs))) { LOG_WARN("failed to get fd set parent exprs ", K(ret)); } while (OB_SUCC(ret) && is_match && !find_unique && r_idx < right_count) { if (l_idx < left_count && (NULL == expected_order_directions || input_ordering.at(l_idx).order_type_ == expected_order_directions->at(r_idx)) && is_expr_equivalent(expected_order_exprs.at(r_idx), input_ordering.at(l_idx).expr_, equal_sets)) { ret = extend_exprs.push_back(expected_order_exprs.at(r_idx)); ++l_idx; ++r_idx; } else if (l_idx < left_count && OB_FAIL(is_const_or_equivalent_expr(input_ordering, equal_sets, const_exprs, l_idx, left_is_const))) { LOG_WARN("failed to check is const or equivalent exprs", K(ret)); } else if (OB_FAIL(is_const_or_equivalent_expr( expected_order_exprs, equal_sets, const_exprs, r_idx, right_is_const))) { LOG_WARN("failed to check is const or equivalent exprs", K(ret)); } else if (right_is_const || (l_idx < left_count && left_is_const)) { if (l_idx < left_count && left_is_const) { ++l_idx; } if (right_is_const) { ++r_idx; } } else { ObFdItem* fd_item = NULL; int64_t extend_exprs_count = -1; while (OB_SUCC(ret) && !find_unique && extend_exprs.count() > extend_exprs_count) { extend_exprs_count = extend_exprs.count(); for (int64_t fd_idx = 0; OB_SUCC(ret) && !find_unique && fd_idx < fd_item_set.count(); ++fd_idx) { bool is_contain = false; if (OB_ISNULL(fd_item = fd_item_set.at(fd_idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (used_fd.has_member(fd_idx)) { // do nothing } else if (OB_FAIL( is_exprs_contain_fd_parent(extend_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("faield to check is order unique", K(ret)); } else if (!is_contain) { // do nothing } else if (fd_item->is_unique()) { find_unique = true; } else if (used_fd.add_member(fd_idx)) { LOG_WARN("failed to add member to set", K(ret)); } else if (OB_FAIL(split_child_exprs(fd_item, equal_sets, fd_set_parent_exprs, extend_exprs))) { LOG_WARN("failed to delete members", K(ret)); } else if (OB_FAIL(fd_item->check_exprs_in_child(expected_order_exprs, equal_sets, r_idx, right_set))) { LOG_WARN("failed to check exprs in child", K(ret)); } else if (OB_FAIL(fd_item->check_exprs_in_child(input_ordering, equal_sets, l_idx, left_set))) { LOG_WARN("failed to check exprs in child", K(ret)); } } } if (!find_unique && !left_set.has_member(l_idx) && !right_set.has_member(r_idx)) { is_match = false; } } while (left_set.has_member(l_idx)) { ++l_idx; }; while (right_set.has_member(r_idx)) { ++r_idx; }; } if (OB_SUCC(ret)) { if (!is_match) { need_sort = true; } else if (find_unique || expected_order_exprs.count() == r_idx) { need_sort = false; } } } LOG_TRACE("succeed to check need sort", K(need_sort), K(fd_item_set), K(equal_sets), K(const_exprs), K(is_at_most_one_row), K(expected_order_exprs), K(input_ordering), K(l_idx), K(r_idx), K(find_unique)); return ret; } int ObOptimizerUtil::decide_sort_keys_for_merge_style_op(const ObIArray& input_ordering, const ObFdItemSet& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, const bool is_at_most_one_row, const ObIArray& merge_exprs, const ObIArray& merge_directions, MergeKeyInfo& merge_key) { int ret = OB_SUCCESS; bool dummy_ordering_used = false; if (OB_FAIL(merge_key.order_exprs_.assign(merge_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(merge_key.order_directions_.assign(merge_directions))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(adjust_exprs_by_ordering(merge_key.order_exprs_, input_ordering, equal_sets, const_exprs, dummy_ordering_used, merge_key.order_directions_, &merge_key.map_array_))) { LOG_WARN("failed to adjust expr by ordering", K(ret)); } else if (OB_FAIL(check_need_sort(merge_key.order_exprs_, &merge_key.order_directions_, input_ordering, fd_item_set, equal_sets, const_exprs, is_at_most_one_row, merge_key.need_sort_))) { LOG_WARN("failed to check need sort", K(ret)); } else if (OB_FAIL(make_sort_keys(merge_key.order_exprs_, merge_key.order_directions_, merge_key.order_items_))) { LOG_WARN("failed to make sort keys", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::flip_op_type(const ObItemType expr_type, ObItemType& rotated_expr_type) { int ret = OB_SUCCESS; rotated_expr_type = T_INVALID; if (expr_type == T_OP_LE) { rotated_expr_type = T_OP_GE; } else if (expr_type == T_OP_LT) { rotated_expr_type = T_OP_GT; } else if (expr_type == T_OP_GE) { rotated_expr_type = T_OP_LE; } else if (expr_type == T_OP_GT) { rotated_expr_type = T_OP_LT; } else if (expr_type == T_OP_EQ || expr_type == T_OP_NE) { rotated_expr_type = expr_type; } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("unsupported input expr type", K(ret)); } return ret; } int ObOptimizerUtil::get_rownum_filter_info( ObRawExpr* rownum_expr, ObItemType& expr_type, ObRawExpr*& const_expr, bool& is_const_filter) { int ret = OB_SUCCESS; is_const_filter = false; ObRawExpr* first_param = NULL; ObRawExpr* second_param = NULL; if (OB_ISNULL(rownum_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else if (rownum_expr->is_op_expr() && 2 == rownum_expr->get_param_count() && (IS_RANGE_CMP_OP(rownum_expr->get_expr_type()) || T_OP_EQ == rownum_expr->get_expr_type())) { first_param = rownum_expr->get_param_expr(0); second_param = rownum_expr->get_param_expr(1); if (OB_ISNULL(first_param) || OB_ISNULL(second_param)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret), K(first_param), K(second_param)); } else if (first_param->has_flag(IS_ROWNUM) && second_param->has_flag(IS_CONST) && (second_param->get_result_type().is_int() || second_param->get_result_type().is_number())) { expr_type = rownum_expr->get_expr_type(); const_expr = second_param; is_const_filter = true; } else if (first_param->has_flag(IS_CONST) && second_param->has_flag(IS_ROWNUM) && (first_param->get_result_type().is_int() || first_param->get_result_type().is_number())) { if (OB_FAIL(flip_op_type(rownum_expr->get_expr_type(), expr_type))) { LOG_WARN("failed to retate rownum_expr type", K(ret)); } else { const_expr = first_param; is_const_filter = true; } } } return ret; } int ObOptimizerUtil::convert_rownum_filter_as_offset(ObRawExprFactory& expr_factory, ObSQLSessionInfo* session_info, const ObItemType filter_type, ObRawExpr* const_expr, ObRawExpr*& offset_int_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(const_expr) || OB_ISNULL(session_info) || OB_UNLIKELY(filter_type != T_OP_GE && filter_type != T_OP_GT) || OB_UNLIKELY(!const_expr->get_result_type().is_integer_type() && !const_expr->get_result_type().is_number())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(const_expr), K(session_info), K(filter_type)); } else if (T_OP_GT == filter_type) { if (OB_FAIL(floor_number_as_limit_offset_value(expr_factory, session_info, const_expr, offset_int_expr))) { LOG_WARN("failed to floor number as offset value", K(ret)); } } else if (T_OP_GE == filter_type) { if (OB_FAIL(ceil_number_as_limit_offset_value(expr_factory, session_info, const_expr, offset_int_expr))) { LOG_WARN("failed to ceil number as offset value", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(offset_int_expr->formalize(session_info))) { LOG_WARN("failed to formalize offset int expr", K(ret)); } } if (OB_SUCC(ret)) { if (session_info->use_static_typing_engine()) { // cast to int value in static typing engine. ObExprResType dst_type; dst_type.set_int(); ObSysFunRawExpr* cast_expr = NULL; OZ(ObRawExprUtils::create_cast_expr(expr_factory, offset_int_expr, dst_type, cast_expr, session_info)); CK(NULL != cast_expr); if (OB_SUCC(ret)) { offset_int_expr = cast_expr; } } } return ret; } int ObOptimizerUtil::convert_rownum_filter_as_limit(ObRawExprFactory& expr_factory, ObSQLSessionInfo* session_info, const ObItemType filter_type, ObRawExpr* const_expr, ObRawExpr*& limit_int_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(const_expr) || OB_ISNULL(session_info) || OB_UNLIKELY(filter_type != T_OP_LE && filter_type != T_OP_LT) || OB_UNLIKELY(!const_expr->get_result_type().is_integer_type() && !const_expr->get_result_type().is_number() && !const_expr->get_result_type().is_null())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("rownum expr is null", K(ret), K(const_expr), K(session_info), K(filter_type)); } else if (filter_type == T_OP_LE) { if (OB_FAIL(floor_number_as_limit_offset_value(expr_factory, session_info, const_expr, limit_int_expr))) { LOG_WARN("failed to floor number as limit value", K(ret)); } } else if (filter_type == T_OP_LT) { if (OB_FAIL(ceil_number_as_limit_offset_value(expr_factory, session_info, const_expr, limit_int_expr))) { LOG_WARN("failed to ceil number as limit value", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(limit_int_expr->formalize(session_info))) { LOG_WARN("failed to formalize limit int expr", K(ret)); } } if (OB_SUCC(ret)) { if (session_info->use_static_typing_engine()) { // cast to int value in static typing engine. ObExprResType dst_type; dst_type.set_int(); ObSysFunRawExpr* cast_expr = NULL; OZ(ObRawExprUtils::create_cast_expr(expr_factory, limit_int_expr, dst_type, cast_expr, session_info)); CK(NULL != cast_expr); if (OB_SUCC(ret)) { limit_int_expr = cast_expr; } } } return ret; } int ObOptimizerUtil::floor_number_as_limit_offset_value( ObRawExprFactory& expr_factory, ObSQLSessionInfo* session_info, ObRawExpr* num_expr, ObRawExpr*& limit_int) { int ret = OB_SUCCESS; if (OB_ISNULL(session_info) || OB_ISNULL(num_expr) || OB_UNLIKELY(!num_expr->get_result_type().is_integer_type() && !num_expr->get_result_type().is_number() && !num_expr->get_result_type().is_null())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params are invalid", K(ret), K(session_info), K(num_expr)); } else if (num_expr->get_result_type().is_integer_type()) { limit_int = num_expr; } else { ObSysFunRawExpr* floor_expr = NULL; if (OB_FAIL(expr_factory.create_raw_expr(T_FUN_SYS_FLOOR, floor_expr))) { LOG_WARN("failed to create fun sys floor", K(ret)); } else if (OB_ISNULL(floor_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("floor expr is null", K(ret)); } else if (OB_FAIL(floor_expr->set_param_expr(num_expr))) { LOG_WARN("failed to set param expr", K(ret)); } else { floor_expr->set_func_name(ObString::make_string("FLOOR")); limit_int = floor_expr; } } return ret; } int ObOptimizerUtil::ceil_number_as_limit_offset_value( ObRawExprFactory& expr_factory, ObSQLSessionInfo* session_info, ObRawExpr* num_expr, ObRawExpr*& limit_int) { int ret = OB_SUCCESS; if (OB_ISNULL(session_info) || OB_ISNULL(num_expr) || OB_UNLIKELY(!num_expr->get_result_type().is_integer_type() && !num_expr->get_result_type().is_number() && !num_expr->get_result_type().is_null())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params are invalid", K(ret), K(session_info), K(num_expr)); } else if (num_expr->get_result_type().is_number()) { ObSysFunRawExpr* ceil_expr = NULL; if (OB_FAIL(expr_factory.create_raw_expr(T_FUN_SYS_CEIL, ceil_expr))) { LOG_WARN("failed to create fun sys floor", K(ret)); } else if (OB_ISNULL(ceil_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("floor expr is null", K(ret)); } else if (OB_FAIL(ceil_expr->set_param_expr(num_expr))) { LOG_WARN("failed to set param expr", K(ret)); } else { ceil_expr->set_func_name(ObString::make_string("CEIL")); num_expr = ceil_expr; } } if (OB_SUCC(ret) && OB_NOT_NULL(num_expr)) { ObRawExpr* minus_expr = NULL; ObConstRawExpr* const_one = NULL; if (OB_FAIL(ObRawExprUtils::build_const_int_expr(expr_factory, ObIntType, 1L, const_one))) { LOG_WARN("failed to build int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr( expr_factory, session_info, T_OP_MINUS, minus_expr, num_expr, const_one))) { LOG_WARN("failed to decrease const expr value", K(ret)); } else { limit_int = minus_expr; } } return ret; } int ObOptimizerUtil::get_type_safe_join_exprs(const ObIArray& join_quals, const ObRelIds& left_tables, const ObRelIds& right_tables, ObIArray& left_exprs, ObIArray& right_exprs, ObIArray& all_left_exprs, ObIArray& all_right_exprs) { int ret = OB_SUCCESS; ObRawExpr* cur_expr = NULL; ObRawExpr* first_expr = NULL; ObRawExpr* second_expr = NULL; ObRawExpr* left_expr = NULL; ObRawExpr* right_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < join_quals.count(); ++i) { cur_expr = join_quals.at(i); if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("join qual should not be NULL", K(cur_expr), K(ret)); } else if (!cur_expr->has_flag(IS_JOIN_COND)) { // do nothing } else if (OB_ISNULL(first_expr = cur_expr->get_param_expr(0)) || OB_ISNULL(second_expr = cur_expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("join qual should not be NULL", K(*cur_expr), K(first_expr), K(second_expr), K(ret)); } else if (T_OP_ROW == first_expr->get_expr_type() || T_OP_ROW == second_expr->get_expr_type()) { // do nothing } else if (first_expr->get_relation_ids().is_subset(left_tables) && second_expr->get_relation_ids().is_subset(right_tables)) { left_expr = first_expr; right_expr = second_expr; } else if (first_expr->get_relation_ids().is_subset(right_tables) && second_expr->get_relation_ids().is_subset(left_tables)) { right_expr = first_expr; left_expr = second_expr; } if (OB_SUCC(ret) && OB_NOT_NULL(left_expr) && OB_NOT_NULL(right_expr)) { bool is_right_valid = false; bool is_left_valid = false; if (OB_FAIL(ObRelationalExprOperator::is_equivalent(left_expr->get_result_type(), right_expr->get_result_type(), right_expr->get_result_type(), is_right_valid))) { LOG_WARN("failed to check the compare type is the same", K(ret)); } else if (OB_FAIL(ObRelationalExprOperator::is_equivalent(left_expr->get_result_type(), left_expr->get_result_type(), right_expr->get_result_type(), is_left_valid))) { LOG_WARN("failed to check the compare type is the same", K(ret)); } else if (is_left_valid && OB_FAIL(left_exprs.push_back(left_expr))) { LOG_WARN("failed to add left exprs", K(ret)); } else if (is_right_valid && OB_FAIL(right_exprs.push_back(right_expr))) { LOG_WARN("failed to add right exprs", K(ret)); } else if (OB_FAIL(all_left_exprs.push_back(left_expr))) { LOG_WARN("failed to push back left expr", K(ret)); } else if (OB_FAIL(all_right_exprs.push_back(right_expr))) { LOG_WARN("failed to push back right expr", K(ret)); } } } return ret; } int ObOptimizerUtil::split_or_qual_on_table(const ObDMLStmt* stmt, ObOptimizerContext& opt_ctx, const ObRelIds& table_ids, ObOpRawExpr& or_qual, ObOpRawExpr*& new_expr) { int ret = OB_SUCCESS; bool is_valid = false; new_expr = NULL; ObSEArray, 8> sub_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < or_qual.get_param_count(); ++i) { ObSEArray exprs; if (OB_FAIL(sub_exprs.push_back(exprs))) { LOG_WARN("failed to push back se array", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(check_push_down_expr(table_ids, or_qual, sub_exprs, is_valid))) { LOG_WARN("failed to check push down expr", K(ret)); } else if (!is_valid) { /* do nothing */ } else if (OB_FAIL(generate_push_down_expr(stmt, opt_ctx, sub_exprs, new_expr))) { LOG_WARN("failed to generate push down expr", K(ret)); } return ret; } int ObOptimizerUtil::check_push_down_expr( const ObRelIds& table_ids, ObOpRawExpr& or_qual, ObIArray>& sub_exprs, bool& all_contain) { int ret = OB_SUCCESS; all_contain = true; for (int64_t i = 0; OB_SUCC(ret) && all_contain && i < or_qual.get_param_count(); ++i) { ObRawExpr* cur_expr = or_qual.get_param_expr(i); if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr in or expr is null", K(ret)); } else if (T_OP_AND == cur_expr->get_expr_type()) { ObOpRawExpr* and_expr = static_cast(cur_expr); for (int64_t j = 0; OB_SUCC(ret) && j < and_expr->get_param_count(); ++j) { ObRawExpr* cur_and_expr = and_expr->get_param_expr(j); if (OB_ISNULL(cur_and_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr in and expr is null", K(ret)); } else if (!cur_and_expr->has_flag(CNT_SUB_QUERY) && table_ids.is_superset(cur_and_expr->get_relation_ids()) && OB_FAIL(sub_exprs.at(i).push_back(cur_and_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /* do nothing */ } } if (OB_FAIL(ret)) { } else if (sub_exprs.at(i).empty()) { all_contain = false; } } else if (cur_expr->has_flag(CNT_SUB_QUERY) || !table_ids.is_superset(cur_expr->get_relation_ids())) { all_contain = false; } else if (OB_FAIL(sub_exprs.at(i).push_back(cur_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /* do nothing */ } } return ret; } int ObOptimizerUtil::generate_push_down_expr(const ObDMLStmt* stmt, ObOptimizerContext& opt_ctx, ObIArray>& sub_exprs, ObOpRawExpr*& new_expr) { int ret = OB_SUCCESS; new_expr = NULL; ObRawExprFactory& expr_factory = opt_ctx.get_expr_factory(); const ObSQLSessionInfo* session_info = opt_ctx.get_session_info(); if (OB_ISNULL(session_info) || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(session_info), K(stmt)); } else if (OB_FAIL(expr_factory.create_raw_expr(T_OP_OR, new_expr))) { LOG_WARN("failed to create or expr", K(ret)); } else if (OB_ISNULL(new_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < sub_exprs.count(); ++i) { ObIArray& cur_exprs = sub_exprs.at(i); const int64_t N = cur_exprs.count(); if (1 == N) { if (OB_FAIL(new_expr->add_param_expr(cur_exprs.at(0)))) { LOG_WARN("failed to add param expr", K(ret)); } } else { ObOpRawExpr* new_and_expr = NULL; if (OB_FAIL(expr_factory.create_raw_expr(T_OP_AND, new_and_expr))) { LOG_WARN("failed to create and expr", K(ret)); } else if (OB_ISNULL(new_and_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("create expr get null", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < N; ++j) { if (OB_FAIL(new_and_expr->add_param_expr(cur_exprs.at(j)))) { LOG_WARN("failed to add param expr", K(ret)); } } if (OB_FAIL(ret)) { /* do nothing */ } else if (OB_FAIL(new_and_expr->formalize(session_info))) { LOG_WARN("failed to formalize and expr", K(ret)); } else if (OB_FAIL(new_and_expr->pull_relation_id_and_levels(stmt->get_current_level()))) { LOG_WARN("failed to pull relation id and levels", K(ret)); } else if (OB_FAIL(new_expr->add_param_expr(new_and_expr))) { LOG_WARN("failed to add param expr", K(ret)); } } } } if (OB_FAIL(ret)) { /* do nothing */ } else if (OB_FAIL(new_expr->formalize(session_info))) { LOG_WARN("failed to formalize or expr", K(ret)); } else if (OB_FAIL(new_expr->pull_relation_id_and_levels(stmt->get_current_level()))) { LOG_WARN("failed to pull relation id and levels", K(ret)); } return ret; } int ObOptimizerUtil::simplify_exprs(const ObFdItemSet fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, ObIArray& root_exprs, const ObIArray& candi_exprs) { int ret = OB_SUCCESS; ObSEArray unique_fd_items; ObSEArray non_unique_fd_items; ObFdItem* fd_item = NULL; ObRawExprSet* parent_exprs = NULL; int64_t min_parent_count = -1; ObRawExprSet* min_parent_exprs = NULL; bool is_contain = false; bool is_in_child = false; root_exprs.reset(); for (int64_t i = 0; OB_SUCC(ret) && i < fd_item_set.count(); ++i) { if (OB_ISNULL(fd_item = fd_item_set.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (fd_item->is_unique()) { if (OB_FAIL(unique_fd_items.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } else if (OB_FAIL(non_unique_fd_items.push_back(fd_item))) { LOG_WARN("failed to push back fd item", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < unique_fd_items.count(); ++i) { if (OB_ISNULL(fd_item = unique_fd_items.at(i)) || OB_ISNULL(parent_exprs = fd_item->get_parent_exprs())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get get unexpect null", K(ret), K(fd_item)); } else if (-1 == min_parent_count || parent_exprs->count() < min_parent_count) { if (OB_FAIL(is_exprs_contain_fd_parent(candi_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("failed to check is order unique", K(ret)); } else if (is_contain) { min_parent_exprs = parent_exprs; min_parent_count = parent_exprs->count(); } } } if (OB_SUCC(ret) && NULL != min_parent_exprs) { int64_t expr_idx = -1; for (int64_t i = 0; OB_SUCC(ret) && i < min_parent_exprs->count(); ++i) { if (find_equal_expr(candi_exprs, min_parent_exprs->at(i), equal_sets, expr_idx)) { if (OB_FAIL(root_exprs.push_back(candi_exprs.at(expr_idx)))) { LOG_WARN("failed to push back root expr", K(ret)); } } else { /* not find means min_parent_exprs->at(i) is const, do nothing */ } } } if (OB_SUCC(ret) && NULL == min_parent_exprs) { ObSqlBitSet<> eliminate_set; for (int64_t i = 0; OB_SUCC(ret) && eliminate_set.num_members() < candi_exprs.count() && i < non_unique_fd_items.count(); ++i) { if (OB_ISNULL(fd_item = non_unique_fd_items.at(i)) || OB_ISNULL(parent_exprs = fd_item->get_parent_exprs())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpect null", K(ret), K(fd_item), K(parent_exprs)); } else if (OB_FAIL(is_exprs_contain_fd_parent(candi_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("failed to check is order unique", K(ret)); } else if (is_contain) { ObSEArray new_root_exprs; bool eliminate_new = false; int64_t expr_idx = -1; for (int64_t j = 0; OB_SUCC(ret) && j < candi_exprs.count(); ++j) { if (eliminate_set.has_member(j)) { // do nothing } else if (OB_FAIL(fd_item->check_expr_in_child(candi_exprs.at(j), equal_sets, is_in_child))) { LOG_WARN("failed to check expr in child", K(ret)); } else if (!is_in_child) { // do nothing } else if (OB_FAIL(eliminate_set.add_member(j))) { LOG_WARN("failed to add member", K(ret)); } else { eliminate_new = true; } } for (int64_t j = 0; OB_SUCC(ret) && j < root_exprs.count(); ++j) { if (OB_FAIL(fd_item->check_expr_in_child(root_exprs.at(j), equal_sets, is_in_child))) { LOG_WARN("failed to check expr in child", K(ret)); } else if (is_in_child) { } else if (OB_FAIL(new_root_exprs.push_back(root_exprs.at(j)))) { LOG_WARN("failed to push back root expr", K(ret)); } } for (int64_t j = 0; OB_SUCC(ret) && j < parent_exprs->count(); ++j) { if (find_equal_expr(candi_exprs, parent_exprs->at(j), equal_sets, expr_idx)) { if (OB_FAIL(new_root_exprs.push_back(candi_exprs.at(expr_idx)))) { LOG_WARN("failed to push back root expr", K(ret)); } } } if (OB_SUCC(ret) && (eliminate_new || new_root_exprs.count() < root_exprs.count())) { if (OB_FAIL(root_exprs.assign(new_root_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } } } } if (OB_SUCC(ret) && eliminate_set.num_members() < candi_exprs.count()) { for (int64_t i = 0; OB_SUCC(ret) && i < candi_exprs.count(); ++i) { if (eliminate_set.has_member(i)) { // do nothing } else if (OB_FAIL(root_exprs.push_back(candi_exprs.at(i)))) { LOG_WARN("failed to push back candi expr", K(ret)); } } } } return ret; } int ObOptimizerUtil::simplify_ordered_exprs(const ObFdItemSet& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, ObIArray& order_items, const ObIArray& candi_items) { int ret = OB_SUCCESS; ObSEArray candi_exprs; ObSEArray directions; ObSEArray order_exprs; if (OB_FAIL(split_expr_direction(candi_items, candi_exprs, directions))) { LOG_WARN("failed to split expr direction", K(ret)); } else if (OB_FAIL(simplify_ordered_exprs(fd_item_set, equal_sets, const_exprs, order_exprs, candi_exprs))) { LOG_WARN("failed to simplify ordered exprs", K(ret)); } else if (OB_FAIL(make_sort_keys(candi_items, order_exprs, order_items))) { LOG_WARN("failed to make sort keys", K(ret)); } return ret; } int ObOptimizerUtil::simplify_ordered_exprs(const ObFdItemSet& fd_item_set, const EqualSets& equal_sets, const ObIArray& const_exprs, ObIArray& order_exprs, const ObIArray& candi_exprs) { int ret = OB_SUCCESS; ObSqlBitSet<> eliminate_set; ObSqlBitSet<> checked_fd_item; ObFdItem* fd_item = NULL; bool is_contain = false; bool is_in_child = false; bool is_const = false; order_exprs.reset(); ObSEArray extended_order_exprs; ObSEArray fd_set_parent_exprs; if (OB_FAIL(get_fd_set_parent_exprs(fd_item_set, fd_set_parent_exprs))) { LOG_WARN("failed to get fd set parent exprs ", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < candi_exprs.count(); ++i) { ObRawExpr* expr = NULL; if (OB_ISNULL(expr = candi_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (eliminate_set.has_member(i)) { /*do nothing*/ } else if (OB_FAIL(is_const_or_equivalent_expr(candi_exprs, equal_sets, const_exprs, i, is_const))) { LOG_WARN("failed to check is const expr", K(ret)); } else if (is_const) { /*do nothing*/ } else if (OB_FAIL(order_exprs.push_back(expr))) { LOG_WARN("failed to push back exprs", K(ret)); } else if (OB_FAIL(extended_order_exprs.push_back(expr))) { LOG_WARN("failed to push back exprs", K(ret)); } else if (OB_FAIL(remove_item(fd_set_parent_exprs, expr))) { LOG_WARN("failed to remove expr", K(ret)); } else { int64_t last_count = -1; while (extended_order_exprs.count() > last_count) { last_count = extended_order_exprs.count(); for (int64_t fd_idx = 0; OB_SUCC(ret) && fd_idx < fd_item_set.count(); ++fd_idx) { if (checked_fd_item.has_member(fd_idx)) { /*do nothing*/ } else if (OB_ISNULL(fd_item = fd_item_set.at(fd_idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null fd item", K(ret)); } else if (OB_FAIL(is_exprs_contain_fd_parent( extended_order_exprs, *fd_item, equal_sets, const_exprs, is_contain))) { LOG_WARN("failed to check is exprs contain fd parent", K(ret)); } else if (is_contain) { for (int64_t j = i + 1; OB_SUCC(ret) && j < candi_exprs.count(); ++j) { if (eliminate_set.has_member(j)) { /*do nothing*/ } else if (OB_FAIL(fd_item->check_expr_in_child(candi_exprs.at(j), equal_sets, is_in_child))) { LOG_WARN("failed to check expr in fd child", K(ret)); } else if (is_in_child && !candi_exprs.at(j)->has_flag(CNT_SUB_QUERY)) { ret = eliminate_set.add_member(j); } } if (OB_FAIL(ret)) { /*do nothing*/ } else if (checked_fd_item.add_member(fd_idx)) { LOG_WARN("failed to add member", K(ret)); } else if (OB_FAIL(split_child_exprs(fd_item, equal_sets, fd_set_parent_exprs, extended_order_exprs))) { LOG_WARN("failed to delete members", K(ret)); } } } } } } return ret; } int ObOptimizerUtil::remove_equal_exprs( const EqualSets& equal_sets, const ObIArray& target_exprs, ObIArray& exprs) { int ret = OB_SUCCESS; ObSEArray other_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); i++) { if (find_equal_expr(target_exprs, exprs.at(i), equal_sets)) { /*do nothing*/ } else if (other_exprs.push_back(exprs.at(i))) { LOG_WARN("failed to push back exprs", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(exprs.assign(other_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } return ret; } int ObOptimizerUtil::check_subquery_filter(const JoinedTable* table, bool& has) { int ret = OB_SUCCESS; has = false; if (OB_ISNULL(table) || OB_ISNULL(table->left_table_) || OB_ISNULL(table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table is null", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && !has && i < table->get_join_conditions().count(); ++i) { const ObRawExpr* expr = NULL; if (OB_ISNULL(expr = table->get_join_conditions().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret), K(expr)); } else { has = expr->has_flag(CNT_SUB_QUERY); } } if (OB_SUCC(ret) && !has && table->left_table_->is_joined_table()) { if (OB_FAIL(check_subquery_filter(static_cast(table->left_table_), has))) { LOG_WARN("failed to check subquery filter", K(ret)); } } if (OB_SUCC(ret) && !has && table->right_table_->is_joined_table()) { if (OB_FAIL(check_subquery_filter(static_cast(table->right_table_), has))) { LOG_WARN("failed to check subquery filter", K(ret)); } } return ret; } bool ObOptimizerUtil::has_equal_join_conditions(const ObIArray& join_conditions) { int bret = false; for (int64_t i = 0; !bret && i < join_conditions.count(); i++) { if (OB_NOT_NULL(join_conditions.at(i))) { bret = join_conditions.at(i)->has_flag(IS_JOIN_COND); } } return bret; } int ObOptimizerUtil::convert_subplan_scan_expr(ObRawExprFactory& expr_factory, const EqualSets& equal_sets, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, bool skip_invalid, const ObIArray& input_exprs, ObIArray& output_exprs) { int ret = OB_SUCCESS; bool is_valid = true; ObSEArray temp_exprs; for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < input_exprs.count(); i++) { ObRawExpr* expr = NULL; if (OB_ISNULL(input_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(input_exprs.at(i)), K(ret)); } else if (OB_FAIL(convert_subplan_scan_expr( expr_factory, equal_sets, table_id, parent_stmt, child_stmt, input_exprs.at(i), expr))) { LOG_WARN("failed to generate subplan scan expr", K(ret)); } else if (OB_ISNULL(expr)) { if (!skip_invalid) { is_valid = false; } } else if (OB_FAIL(add_var_to_array_no_dup(temp_exprs, expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret) && is_valid && !temp_exprs.empty()) { if (OB_FAIL(output_exprs.assign(temp_exprs))) { LOG_WARN("failed to push back exprs", K(ret)); } else { LOG_TRACE("succeed to convert subplan scan expr", K(input_exprs), K(output_exprs)); } } return ret; } int ObOptimizerUtil::convert_subplan_scan_expr(ObRawExprFactory& expr_factory, const EqualSets& equal_sets, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, const ObRawExpr* input_expr, ObRawExpr*& output_expr) { int ret = OB_SUCCESS; bool is_valid = true; output_expr = NULL; if (OB_FAIL(check_subplan_scan_expr_validity(equal_sets, table_id, parent_stmt, child_stmt, input_expr, is_valid))) { LOG_WARN("failed to check subplan scan expr validity", K(ret)); } else if (!is_valid) { /*do nothing*/ } else if (OB_FAIL(get_parent_stmt_expr(equal_sets, table_id, parent_stmt, child_stmt, input_expr, output_expr))) { LOG_WARN("failed to get parent stmt expr", K(ret)); } else if (NULL != output_expr) { /* * this branch try to optimize the deep copy of input expr, * if we can find the root expr in child stmt, then we should directly get the parent expr */ } else if (OB_FAIL(ObRawExprUtils::copy_expr(expr_factory, input_expr, output_expr, COPY_REF_DEFAULT))) { LOG_WARN("failed to copy expr", K(ret)); } else if (OB_ISNULL(output_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to copy expr", K(ret)); } else if (OB_FAIL(replace_subplan_scan_expr(equal_sets, table_id, parent_stmt, child_stmt, output_expr))) { LOG_WARN("failed to do inner convert subplan scan expr", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::replace_subplan_scan_expr(const EqualSets& equal_sets, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, ObRawExpr*& expr) { int ret = OB_SUCCESS; bool is_stack_overflow = false; ObRawExpr* parent_expr = NULL; 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_const_expr()) { /*do nothing*/ } else if (OB_FAIL(get_parent_stmt_expr(equal_sets, table_id, parent_stmt, child_stmt, expr, parent_expr))) { LOG_WARN("failed to get output expr idx", K(ret)); } else if (NULL != parent_expr) { expr = parent_expr; } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_ISNULL(expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret)); } else if (OB_FAIL(SMART_CALL(replace_subplan_scan_expr( equal_sets, table_id, parent_stmt, child_stmt, expr->get_param_expr(i))))) { LOG_WARN("failed to check subplan scan expr validity", K(ret)); } } } return ret; } int ObOptimizerUtil::check_subplan_scan_expr_validity(const EqualSets& equal_sets, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, const ObRawExpr* input_expr, bool& is_valid) { int ret = OB_SUCCESS; ObRawExpr* parent_expr = NULL; bool is_stack_overflow = false; is_valid = false; if (OB_ISNULL(input_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", 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 (input_expr->is_const_expr()) { is_valid = true; } else if (OB_FAIL(get_parent_stmt_expr(equal_sets, table_id, parent_stmt, child_stmt, input_expr, parent_expr))) { LOG_WARN("failed to get parent stmt expr", K(ret)); } else if (NULL != parent_expr) { is_valid = true; } else if (ObRawExprUtils::is_sharable_expr(*input_expr)) { is_valid = false; } else if (input_expr->get_param_count() == 0) { is_valid = false; } else { is_valid = true; for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < input_expr->get_param_count(); i++) { bool temp_valid = false; if (OB_ISNULL(input_expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret)); } else if (OB_FAIL(SMART_CALL(check_subplan_scan_expr_validity( equal_sets, table_id, parent_stmt, child_stmt, input_expr->get_param_expr(i), temp_valid)))) { LOG_WARN("failed to check subplan scan expr validity", K(ret)); } else { is_valid &= temp_valid; } } } return ret; } int ObOptimizerUtil::get_parent_stmt_expr(const EqualSets& equal_sets, const uint64_t table_id, ObDMLStmt& parent_stmt, const ObSelectStmt& child_stmt, const ObRawExpr* child_expr, ObRawExpr*& parent_expr) { int ret = OB_SUCCESS; parent_expr = NULL; if (OB_ISNULL(child_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && NULL == parent_expr && i < child_stmt.get_select_item_size(); ++i) { const ObRawExpr* expr = child_stmt.get_select_item(i).expr_; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(expr), K(ret)); } else if (ObOptimizerUtil::is_expr_equivalent(expr, child_expr, equal_sets)) { // parent_expr may be null, just ignore parent_expr = parent_stmt.get_column_expr_by_id(table_id, OB_APP_MIN_COLUMN_ID + i); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::compute_stmt_interesting_order(const ObIArray& ordering, const ObDMLStmt* stmt, const bool in_subplan_scan, EqualSets& equal_sets, const ObIArray& const_exprs, const int64_t check_scope, int64_t& match_info, int64_t* max_prefix_count_ptr) { int ret = OB_SUCCESS; ObSEArray ordering_exprs; ObSEArray ordering_directions; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (check_scope == OrderingCheckScope::NOT_CHECK) { // do nothing } else if (OB_FAIL(split_expr_direction(ordering, ordering_exprs, ordering_directions))) { LOG_WARN("failed to split expr direction", K(ret)); } else { int64_t prefix_count = 0; int64_t max_prefix_count = 0; const ObSelectStmt* select_stmt = NULL; bool check_group = (check_scope & OrderingCheckScope::CHECK_GROUP) > 0; bool check_winfunc = (check_scope & OrderingCheckScope::CHECK_WINFUNC) > 0; bool check_distinct = (check_scope & OrderingCheckScope::CHECK_DISTINCT) > 0; bool check_set = (check_scope & OrderingCheckScope::CHECK_SET) > 0; bool check_order = (check_scope & OrderingCheckScope::CHECK_ORDERBY) > 0; bool has_group = false; bool has_distinct = false; bool has_winfunc = false; bool has_orderby = stmt->has_order_by(); bool winfunc_require_sort = false; bool group_match = false; bool winfunc_match = false; bool distinct_match = false; bool set_match = false; bool orderby_match = false; if (stmt->is_select_stmt()) { select_stmt = static_cast(stmt); has_group = select_stmt->get_group_expr_size() > 0 || select_stmt->get_rollup_expr_size() > 0; has_distinct = select_stmt->has_distinct(); has_winfunc = select_stmt->has_window_function(); } if (has_group && check_group) { prefix_count = 0; if (OB_FAIL(is_group_by_match(ordering, select_stmt, equal_sets, const_exprs, prefix_count, group_match))) { LOG_WARN("failed to check is group by match", K(ret)); } else if (group_match) { max_prefix_count = std::max(max_prefix_count, prefix_count); match_info |= OrderingFlag::GROUP_MATCH; LOG_TRACE("ordering is math group by", K(max_prefix_count), K(prefix_count)); } } else if (has_winfunc && check_winfunc) { prefix_count = 0; if (OB_FAIL(is_winfunc_match( ordering, select_stmt, equal_sets, const_exprs, prefix_count, winfunc_match, winfunc_require_sort))) { LOG_WARN("failed to check is winfunc match", K(ret)); } else if (winfunc_match) { max_prefix_count = std::max(max_prefix_count, prefix_count); match_info |= OrderingFlag::WINFUNC_MATCH; LOG_TRACE("ordering is match window function", K(max_prefix_count), K(prefix_count)); } } if (OB_SUCC(ret) && (!check_group || !has_group) && !winfunc_require_sort) { if (has_distinct && check_distinct) { prefix_count = 0; if (OB_FAIL(is_distinct_match( ordering_exprs, select_stmt, equal_sets, const_exprs, prefix_count, distinct_match))) { LOG_WARN("failed to check is distinct match", K(ret)); } else if (distinct_match) { max_prefix_count = std::max(max_prefix_count, prefix_count); match_info |= OrderingFlag::DISTINCT_MATCH; LOG_TRACE("ordering is math distinct", K(max_prefix_count), K(prefix_count)); } } else if (check_set) { prefix_count = 0; if (NULL != select_stmt && select_stmt->is_parent_set_distinct()) { if (OB_FAIL(is_set_match(ordering_exprs, select_stmt, equal_sets, const_exprs, prefix_count, set_match))) { LOG_WARN("failed to check is set match", K(ret)); } else if (set_match) { max_prefix_count = std::max(max_prefix_count, prefix_count); match_info |= OrderingFlag::SET_MATCH; LOG_TRACE("ordering is match set", K(max_prefix_count), K(prefix_count)); } } } /** * stmt without groupby (not just select) */ if (OB_SUCC(ret) && has_orderby && check_order) { prefix_count = 0; if (OB_FAIL(is_order_by_match(ordering, stmt, equal_sets, const_exprs, prefix_count, orderby_match))) { LOG_WARN("failed to check is order by match", K(ret)); } else if (orderby_match) { max_prefix_count = std::max(max_prefix_count, prefix_count); match_info |= OrderingFlag::ORDERBY_MATCH; LOG_TRACE("ordering is math order by", K(max_prefix_count), K(prefix_count)); } } } if (OB_SUCC(ret) && NULL != max_prefix_count_ptr) { *max_prefix_count_ptr = max_prefix_count; } if (OB_SUCC(ret) && in_subplan_scan && !ordering_exprs.empty()) { if ((check_group && has_group && !group_match) || (check_winfunc && winfunc_require_sort) || (check_distinct && has_distinct && !distinct_match) || (check_order && has_orderby && !orderby_match)) { // do nothing } else { match_info |= OrderingFlag::POTENTIAL_MATCH; } } } return ret; } int ObOptimizerUtil::is_group_by_match(const ObIArray& ordering, const ObSelectStmt* select_stmt, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix_count, bool& sort_match) { int ret = OB_SUCCESS; match_prefix_count = 0; sort_match = false; int64_t match_count = 0; bool full_covered = true; ObSEArray ordering_exprs; ObSEArray ordering_directions; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is invalid", K(ret), K(select_stmt)); } else if (OB_FAIL(split_expr_direction(ordering, ordering_exprs, ordering_directions))) { LOG_WARN("failed to split expr direction", K(ret)); } else if (select_stmt->get_group_expr_size() > 0 && OB_FAIL(prefix_subset_exprs(select_stmt->get_group_exprs(), ordering_exprs, equal_sets, const_exprs, full_covered, &match_count))) { LOG_WARN("check is covered by ordering failed", K(ret)); } else if (full_covered && select_stmt->get_rollup_expr_size() > 0) { ObSEArray mock_ordering; for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_rollup_expr_size(); ++i) { OrderItem order_item(select_stmt->get_rollup_exprs().at(i)); if (OB_FAIL(mock_ordering.push_back(order_item))) { LOG_WARN("failed to push back order item", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(match_order_by_against_index( mock_ordering, ordering, match_count, equal_sets, const_exprs, full_covered, match_count, false))) { LOG_WARN("failed to check match order by against index", K(ret)); } } if (OB_SUCC(ret) && match_count > 0) { sort_match = true; match_prefix_count = match_count; } return ret; } int ObOptimizerUtil::is_winfunc_match(const ObIArray& ordering, const ObSelectStmt* select_stmt, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix_count, bool& sort_match, bool& sort_is_required) { int ret = OB_SUCCESS; match_prefix_count = 0; sort_is_required = false; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select_stmt is null", K(ret), K(select_stmt)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_window_func_count(); ++i) { int64_t match_count = 0; bool win_func_sort_match = false; bool win_func_require_sort = false; if (OB_FAIL(is_winfunc_match(ordering, select_stmt, select_stmt->get_window_func_expr(i), equal_sets, const_exprs, match_count, win_func_sort_match, win_func_require_sort))) { LOG_WARN("failed to check is winfunc match", K(ret)); } else { sort_is_required |= win_func_require_sort; if (win_func_sort_match) { sort_match = true; if (match_count > match_prefix_count) { match_prefix_count = match_count; } } } } } return ret; } int ObOptimizerUtil::is_winfunc_match(const ObIArray& ordering, const ObSelectStmt* select_stmt, const ObWinFunRawExpr* win_expr, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix_count, bool& sort_match, bool& sort_is_required) { int ret = OB_SUCCESS; match_prefix_count = 0; sort_match = false; sort_is_required = false; int64_t partition_match_count = 0; int64_t order_match_count = 0; bool full_covered = false; ObSEArray ordering_exprs; ObSEArray ordering_directions; if (OB_ISNULL(select_stmt) || OB_ISNULL(win_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("input parameters have null", K(ret), K(select_stmt), K(win_expr)); } else if (OB_FAIL(split_expr_direction(ordering, ordering_exprs, ordering_directions))) { LOG_WARN("failed to split expr direction", K(ret)); } else if (OB_FAIL(prefix_subset_exprs(win_expr->get_partition_exprs(), ordering_exprs, equal_sets, const_exprs, full_covered, &partition_match_count))) { LOG_WARN("check is covered by ordering failed", K(ret)); } else if (!full_covered) { sort_is_required = true; } else if (OB_FAIL(match_order_by_against_index(win_expr->get_order_items(), ordering, partition_match_count, equal_sets, const_exprs, full_covered, order_match_count))) { LOG_WARN("failed to match order by against index", K(ret)); } else if (!full_covered) { sort_is_required = true; } if (OB_SUCC(ret) && (partition_match_count > 0 || order_match_count > 0)) { match_prefix_count = order_match_count > 0 ? order_match_count : partition_match_count; sort_match = true; } return ret; } int ObOptimizerUtil::match_order_by_against_index(const ObIArray& expect_ordering, const ObIArray& input_ordering, const int64_t input_start_offset, const EqualSets& equal_sets, const ObIArray& const_exprs, bool& full_covered, int64_t& match_count, bool check_direction /* = true */) { int ret = OB_SUCCESS; int64_t expect_offset = expect_ordering.count(); int64_t input_offset = input_start_offset; bool is_const = true; full_covered = false; match_count = input_start_offset; for (int64_t i = 0; OB_SUCC(ret) && is_const && i < expect_ordering.count(); ++i) { if (OB_FAIL(is_const_expr(expect_ordering.at(i).expr_, equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check is_const_expr", K(ret)); } else if (!is_const) { expect_offset = i; } } ObRawExpr* input_expr = NULL; ObRawExpr* expect_expr = NULL; bool direction_match = false; while (OB_SUCC(ret) && input_offset < input_ordering.count() && expect_offset < expect_ordering.count()) { direction_match = check_direction ? is_ascending_direction(expect_ordering.at(expect_offset).order_type_) == is_ascending_direction(input_ordering.at(input_offset).order_type_) : true; if (OB_ISNULL(input_expr = input_ordering.at(input_offset).expr_) || OB_ISNULL(expect_expr = expect_ordering.at(expect_offset).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(input_expr), K(expect_expr)); } else if (is_expr_equivalent(input_expr, expect_expr, equal_sets) && direction_match) { match_count = ++input_offset; ++expect_offset; } else if (OB_FAIL(is_const_expr(expect_expr, equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check expr is const expr", K(ret)); } else if (is_const) { ++expect_offset; } else if (OB_FAIL(is_const_expr(input_expr, equal_sets, const_exprs, is_const))) { LOG_WARN("failed to check expr is const expr", K(ret)); } else if (is_const) { ++input_offset; } else { break; } } if (OB_SUCC(ret)) { full_covered = (expect_offset == expect_ordering.count()); } return ret; } int ObOptimizerUtil::is_set_or_distinct_match(const ObIArray& keys, const ObSelectStmt* select_stmt, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix_count, bool& sort_match) { int ret = OB_SUCCESS; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is invalid", K(ret)); } else { ObSEArray distinct_exprs; sort_match = false; match_prefix_count = 0; if (OB_FAIL(select_stmt->get_select_exprs(distinct_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else { bool full_covered = false; int64_t match_count = 0; if (OB_FAIL(prefix_subset_exprs(distinct_exprs, keys, equal_sets, const_exprs, full_covered, &match_count))) { LOG_WARN("check is covered by ordering failed", K(ret)); } else if (match_count > 0) { sort_match = true; // only consider prefix match_prefix_count = match_count; } } } return ret; } /** * create table t1(c1 int primary key); * select distinct(c1), c2 from t1 */ int ObOptimizerUtil::is_distinct_match(const ObIArray& keys, const ObSelectStmt* stmt, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix_count, bool& sort_match) { int ret = OB_SUCCESS; sort_match = false; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt should not be null", K(ret)); } else if (stmt->has_distinct()) { if (OB_FAIL(is_set_or_distinct_match(keys, stmt, equal_sets, const_exprs, match_prefix_count, sort_match))) { LOG_WARN("check is_set_or_distinct_match failed", K(ret)); } } return ret; } /** * (select c1 from t1) union (select c2 from t2); * the order of c1 can be use by union */ int ObOptimizerUtil::is_set_match(const ObIArray& keys, const ObSelectStmt* stmt, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix_count, bool& sort_match) { return is_set_or_distinct_match(keys, stmt, equal_sets, const_exprs, match_prefix_count, sort_match); } // get max prefix int ObOptimizerUtil::is_order_by_match(const ObIArray& ordering, const ObDMLStmt* stmt, const EqualSets& equal_sets, const ObIArray& const_exprs, int64_t& match_prefix, bool& sort_match) { int ret = OB_SUCCESS; int64_t match_count = 0; bool dummy_full_covered = false; match_prefix = 0; sort_match = false; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt should not be null", K(ret)); } else if (OB_FAIL(match_order_by_against_index(stmt->get_order_items(), ordering, 0, // input ordering offser equal_sets, const_exprs, dummy_full_covered, match_count))) { LOG_WARN("failed to match order by against index", K(ret)); } else if (match_count > 0) { sort_match = true; match_prefix = match_count; } LOG_TRACE("is_orderby match", K(ret), K(match_prefix), K(sort_match)); return ret; } int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr* expr, bool& is_lossless) { int ret = OB_SUCCESS; is_lossless = false; const ObRawExpr* child_expr = NULL; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (T_FUN_SYS_CAST != expr->get_expr_type()) { // do nothing } else if (OB_ISNULL(child_expr = expr->get_param_expr(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (child_expr->is_column_ref_expr()) { ObExprResType column_type = child_expr->get_result_type(); ObObjTypeClass column_tc = column_type.get_type_class(); ObExprResType dst_type = expr->get_result_type(); ObObjTypeClass dst_tc = dst_type.get_type_class(); ObAccuracy dst_acc = dst_type.get_accuracy(); if (!is_oracle_mode()) { if (ObIntTC == column_tc || ObUIntTC == column_tc) { if (ObNumberTC == dst_tc) { // ObAccuracy lossless_acc = // ObAccuracy::DDL_DEFAULT_ACCURACY2[ObCompatibilityMode::MYSQL_MODE][column_type.get_type()]; ObAccuracy lossless_acc = column_type.get_accuracy(); if (dst_acc.get_scale() >= 0 && dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision()) { is_lossless = true; } } } else if (ObFloatTC == column_tc || ObDoubleTC == column_tc) { if (ObDoubleTC == dst_tc) { if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObDateTimeType == column_type.get_type()) { // do nothing } else if (ObTimestampType == column_type.get_type()) { if (ObDateTimeType == dst_type.get_type()) { if (column_type.get_accuracy().get_precision() == dst_acc.get_precision() && column_type.get_accuracy().get_scale() == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObDateTC == column_tc || ObTimeTC == column_tc) { if (ObDateTimeType == dst_type.get_type() || ObTimestampType == dst_type.get_type()) { if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObYearTC == column_tc) { if (ObNumberTC == dst_tc) { ObAccuracy lossless_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[ObCompatibilityMode::MYSQL_MODE][column_type.get_type()]; if (dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision() - lossless_acc.get_scale()) { is_lossless = true; } } else if (ObDoubleTC == dst_tc) { if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObVarcharType == column_type.get_type()) { // varchar, varbinnary } else if (ObCharType == column_type.get_type()) { if (ObVarcharType == dst_type.get_type()) { if (dst_acc.get_length() == column_type.get_accuracy().get_length() && dst_type.get_obj_meta().get_collation_type() == column_type.get_obj_meta().get_collation_type()) { is_lossless = true; } } } } else { // oracle mode, do nothing } } return ret; } int ObOptimizerUtil::gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObSelectStmt& left_stmt, ObSelectStmt& right_stmt, ObSelectStmt* select_stmt) { int ret = OB_SUCCESS; ObSEArray left_stmts; ObSEArray right_stmts; if (OB_FAIL(left_stmts.push_back(&left_stmt)) || OB_FAIL(right_stmts.push_back(&right_stmt))) { LOG_WARN("failed to pushback stmt", K(ret)); } else if (OB_FAIL( gen_set_target_list(allocator, session_info, expr_factory, left_stmts, right_stmts, select_stmt))) { LOG_WARN("failed to get set target list", K(ret)); } return ret; } int ObOptimizerUtil::gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObIArray& left_stmts, ObIArray& right_stmts, ObSelectStmt* select_stmt) { int ret = OB_SUCCESS; UNUSED(allocator); ObSelectStmt* child_stmt = NULL; ObSEArray res_types; if (OB_ISNULL(session_info) || OB_ISNULL(expr_factory) || OB_ISNULL(select_stmt)) { ret = OB_NOT_INIT; LOG_WARN("params is invalid", K(ret)); } else if (OB_FAIL(try_add_cast_to_set_child_list(allocator, session_info, expr_factory, select_stmt->is_set_distinct(), left_stmts, right_stmts, &res_types))) { LOG_WARN("failed to try add cast to set child list", K(ret)); } else if (OB_ISNULL(child_stmt = select_stmt->get_set_query(0)) || OB_UNLIKELY(res_types.count() != child_stmt->get_select_item_size())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected set stmt", K(ret), K(child_stmt)); } else { select_stmt->get_select_items().reset(); ObItemType set_op_type = static_cast(T_OP_SET + select_stmt->get_set_op()); const int64_t num = child_stmt->get_select_item_size(); SelectItem new_select_item; for (int64_t i = 0; OB_SUCC(ret) && i < num; i++) { SelectItem& select_item = child_stmt->get_select_item(i); new_select_item.alias_name_ = select_item.alias_name_; new_select_item.expr_name_ = select_item.expr_name_; new_select_item.default_value_ = select_item.default_value_; new_select_item.default_value_expr_ = select_item.default_value_expr_; new_select_item.is_real_alias_ = true; new_select_item.questions_pos_ = select_item.questions_pos_; new_select_item.params_idx_ = select_item.params_idx_; new_select_item.neg_param_idx_ = select_item.neg_param_idx_; new_select_item.esc_str_flag_ = select_item.esc_str_flag_; new_select_item.is_unpivot_mocked_column_ = select_item.is_unpivot_mocked_column_; new_select_item.paramed_alias_name_ = select_item.paramed_alias_name_; new_select_item.need_check_dup_name_ = select_item.need_check_dup_name_; if (OB_FAIL(ObRawExprUtils::make_set_op_expr( *expr_factory, i, set_op_type, res_types.at(i), session_info, new_select_item.expr_))) { LOG_WARN("create set op expr failed", K(ret)); } else if (OB_FAIL(select_stmt->add_select_item(new_select_item))) { LOG_WARN("push back set select item failed", K(ret)); } else if (OB_ISNULL(new_select_item.expr_) || OB_UNLIKELY(!new_select_item.expr_->is_set_op_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null or is not set op expr", "set op", PC(new_select_item.expr_)); } else { new_select_item.expr_->set_expr_level(child_stmt->get_current_level()); } } } return ret; } int ObOptimizerUtil::gen_set_target_list( ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObSelectStmt* select_stmt) { int ret = OB_SUCCESS; UNUSED(allocator); ObSelectStmt* child_stmt = NULL; ObSEArray res_types; if (OB_ISNULL(session_info) || OB_ISNULL(expr_factory) || OB_ISNULL(select_stmt) || OB_UNLIKELY(select_stmt->get_set_query().empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret)); } else if (OB_FAIL(get_set_res_types(allocator, session_info, select_stmt->get_set_query(), res_types))) { LOG_WARN("failed to get set res types", K(ret)); } else if (OB_ISNULL(child_stmt = select_stmt->get_set_query(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected set stmt", K(ret), K(child_stmt)); } else { select_stmt->get_select_items().reset(); ObItemType set_op_type = static_cast(T_OP_SET + select_stmt->get_set_op()); const int64_t num = child_stmt->get_select_item_size(); SelectItem new_select_item; for (int64_t i = 0; OB_SUCC(ret) && i < num; ++i) { if (OB_FAIL(add_cast_to_set_list(session_info, expr_factory, select_stmt->get_set_query(), res_types.at(i), i))) { LOG_WARN("failed to add add cast to set list", K(ret)); } else { SelectItem& select_item = child_stmt->get_select_item(i); new_select_item.alias_name_ = select_item.alias_name_; new_select_item.expr_name_ = select_item.expr_name_; new_select_item.default_value_ = select_item.default_value_; new_select_item.default_value_expr_ = select_item.default_value_expr_; new_select_item.is_real_alias_ = true; new_select_item.questions_pos_ = select_item.questions_pos_; new_select_item.params_idx_ = select_item.params_idx_; new_select_item.neg_param_idx_ = select_item.neg_param_idx_; new_select_item.esc_str_flag_ = select_item.esc_str_flag_; new_select_item.is_unpivot_mocked_column_ = select_item.is_unpivot_mocked_column_; new_select_item.paramed_alias_name_ = select_item.paramed_alias_name_; new_select_item.need_check_dup_name_ = select_item.need_check_dup_name_; if (OB_FAIL(ObRawExprUtils::make_set_op_expr( *expr_factory, i, set_op_type, res_types.at(i), session_info, new_select_item.expr_))) { LOG_WARN("create set op expr failed", K(ret)); } else if (OB_FAIL(select_stmt->add_select_item(new_select_item))) { LOG_WARN("push back set select item failed", K(ret)); } else if (OB_ISNULL(new_select_item.expr_) || OB_UNLIKELY(!new_select_item.expr_->is_set_op_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null or is not set op expr", "set op", PC(new_select_item.expr_)); } else { new_select_item.expr_->set_expr_level(child_stmt->get_current_level()); } } } } return ret; } int ObOptimizerUtil::get_set_res_types(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObIArray& child_querys, ObIArray& res_types) { int ret = OB_SUCCESS; res_types.reuse(); ObSelectStmt* select_stmt = NULL; ObCollationType coll_type = CS_TYPE_INVALID; if (OB_ISNULL(allocator) || OB_ISNULL(session_info) || OB_UNLIKELY(child_querys.empty()) || OB_ISNULL(select_stmt = child_querys.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(allocator), K(session_info), K(select_stmt)); } else if (OB_FAIL(session_info->get_collation_connection(coll_type))) { LOG_WARN("failed to get collation connection", K(ret)); } else { ObExprVersion dummy_op(*allocator); const ObLengthSemantics length_semantics = session_info->get_actual_nls_length_semantics(); ObSEArray types; ObExprResType res_type; const int64_t child_num = child_querys.count(); const int64_t select_num = select_stmt->get_select_item_size(); ObRawExpr* expr = NULL; for (int64_t i = 1; OB_SUCC(ret) && i < child_num; ++i) { if (OB_ISNULL(child_querys.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected set stmt", K(ret), K(child_querys), K(select_stmt)); } else if (OB_UNLIKELY(select_num != child_querys.at(i)->get_select_item_size())) { ret = OB_ERR_COLUMN_SIZE; LOG_WARN("The used SELECT statements have a different number of columns", K(select_num), K(select_stmt->get_select_item_size())); } } for (int64_t idx = 0; OB_SUCC(ret) && idx < select_num; ++idx) { bool is_all_not_null = true; for (int64_t i = 0; OB_SUCC(ret) && i < child_num; ++i) { types.reuse(); if (OB_ISNULL(expr = select_stmt->get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(expr)); } else if (OB_FAIL(add_var_to_array_no_dup(types, expr->get_result_type()))) { LOG_WARN("unexpected null", K(ret), K(expr->get_result_type())); } else if (is_all_not_null && !expr->get_result_type().has_result_flag(OB_MYSQL_NOT_NULL_FLAG)) { is_all_not_null = false; } } if (OB_FAIL(ret)) { } else if (OB_UNLIKELY(types.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected empty", K(ret), K(types.empty())); } else if (1 == types.count()) { ret = res_types.push_back(types.at(0)); } else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge(res_type, &types.at(0), types.count(), coll_type, is_oracle_mode(), length_semantics, session_info))) { LOG_WARN("failed to aggregate result type for merge", K(ret)); } else if (OB_FAIL(res_types.push_back(res_type))) { LOG_WARN("failed to pushback res type", K(ret)); } if (OB_FAIL(ret)) { } else if (OB_UNLIKELY(res_types.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected empty", K(ret), K(types.empty())); } else if (!is_all_not_null) { res_types.at(res_types.count() - 1).unset_result_flag(OB_MYSQL_NOT_NULL_FLAG); } } } return ret; } int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, const bool is_distinct, ObIArray& left_stmts, ObIArray& right_stmts, ObIArray* res_types) { int ret = OB_SUCCESS; ObExprResType res_type; ObSEArray left_types; ObSEArray right_types; if (OB_ISNULL(allocator) || OB_ISNULL(session_info) || OB_ISNULL(expr_factory)) { ret = OB_NOT_INIT; LOG_WARN("params is invalid", K(ret)); } else if (left_stmts.empty() || right_stmts.empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("empty left/right stmts", K(ret), K(left_stmts), K(right_stmts)); } else if (OB_FAIL(get_set_res_types(allocator, session_info, left_stmts, left_types)) || OB_FAIL(get_set_res_types(allocator, session_info, right_stmts, right_types))) { LOG_WARN("failed to get set res types", K(ret)); } else if (OB_UNLIKELY(left_types.count() != right_types.count())) { ret = OB_ERR_COLUMN_SIZE; LOG_WARN( "The used SELECT statements have a different number of columns", K(left_types.count()), K(right_types.count())); } else { if (NULL != res_types) { res_types->reuse(); } const int64_t num = left_types.count(); for (int64_t i = 0; OB_SUCC(ret) && i < num; i++) { res_type.reset(); ObExprResType& left_type = left_types.at(i); ObExprResType& right_type = right_types.at(i); if (!left_type.has_result_flag(OB_MYSQL_NOT_NULL_FLAG) || !right_type.has_result_flag(OB_MYSQL_NOT_NULL_FLAG)) { left_type.unset_result_flag(OB_MYSQL_NOT_NULL_FLAG); right_type.unset_result_flag(OB_MYSQL_NOT_NULL_FLAG); } if (left_type != right_type || ob_is_enumset_tc(right_type.get_type())) { ObSEArray types; ObExprVersion dummy_op(*allocator); ObCollationType coll_type = CS_TYPE_INVALID; if (share::is_oracle_mode()) { /* * Oracle has more strict constraints for data types used in set operator * https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries004.htm */ // need to refine this when more data type are added in oracle mode if (!((left_type.is_null() && !right_type.is_lob() && !right_type.is_lob_locator()) || (right_type.is_null() && !left_type.is_lob() && !left_type.is_lob_locator()) || (left_type.is_raw() && right_type.is_raw()) || (left_type.is_character_type() && right_type.is_character_type()) || (ob_is_oracle_numeric_type(left_type.get_type()) && ob_is_oracle_numeric_type(right_type.get_type())) || (ob_is_oracle_temporal_type(left_type.get_type()) && (ob_is_oracle_temporal_type(right_type.get_type()))))) { ret = OB_ERR_EXP_NEED_SAME_DATATYPE; LOG_WARN("expression must have same datatype as corresponding expression", K(ret), K(i), K(left_type), K(right_type)); } else if (left_type.is_character_type() && right_type.is_character_type() && (left_type.is_varchar_or_char() != right_type.is_varchar_or_char())) { ret = OB_ERR_CHARACTER_SET_MISMATCH; LOG_WARN("character set mismatch", K(ret), K(left_type), K(right_type)); } else if (left_type.is_string_or_lob_locator_type() && right_type.is_string_or_lob_locator_type()) { ObCharsetType left_cs = left_type.get_charset_type(); ObCharsetType right_cs = right_type.get_charset_type(); if (left_cs != right_cs) { if (CHARSET_UTF8MB4 == left_cs || CHARSET_UTF8MB4 == right_cs) { // sys table column exist utf8 varchar types, let it go } else { ret = OB_ERR_COLLATION_MISMATCH; // ORA-12704 LOG_WARN("character set mismatch", K(ret), K(left_cs), K(right_cs)); } } } LOG_DEBUG("data type check for each select item in set operator", K(left_type), K(right_type)); } const ObLengthSemantics length_semantics = session_info->get_actual_nls_length_semantics(); if (OB_FAIL(ret)) { } else if (OB_FAIL(types.push_back(left_type) || OB_FAIL(types.push_back(right_type)))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(session_info->get_collation_connection(coll_type))) { LOG_WARN("failed to get collation connection", K(ret)); } else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge( res_type, &types.at(0), 2, coll_type, is_oracle_mode(), length_semantics, session_info))) { LOG_WARN("failed to aggregate result type for merge", K(ret)); } else if (ObMaxType == res_type.get_type()) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("column type incompatible", K(left_type), K(right_type)); } else if (left_type != res_type && OB_FAIL(add_cast_to_set_list(session_info, expr_factory, left_stmts, res_type, i))) { LOG_WARN("failed to add add cast to set list", K(ret)); } else if (right_type != res_type && OB_FAIL(add_cast_to_set_list(session_info, expr_factory, right_stmts, res_type, i))) { LOG_WARN("failed to add add cast to set list", K(ret)); } } else if (share::is_oracle_mode() && is_distinct && (left_type.is_lob() || left_type.is_lob_locator())) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("column type incompatible", K(ret), K(left_type), K(right_type)); } else { res_type = left_type; } if (OB_SUCC(ret) && NULL != res_types && OB_FAIL(res_types->push_back(res_type))) { LOG_WARN("failed to push back res type", K(ret)); } } } return ret; } int ObOptimizerUtil::add_cast_to_set_list(ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObIArray& stmts, const ObExprResType& res_type, const int64_t idx) { int ret = OB_SUCCESS; ObRawExpr* src_expr = NULL; ObRawExpr* new_expr = NULL; ObSelectStmt* stmt = NULL; const int64_t num = stmts.count(); if (OB_ISNULL(session_info) || OB_ISNULL(expr_factory)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < num; ++i) { if (OB_ISNULL(stmt = stmts.at(i)) || idx >= stmt->get_select_item_size() || OB_ISNULL(src_expr = stmt->get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected stmt", K(ret), K(stmts.at(i))); } else if (ob_is_enumset_tc(src_expr->get_result_type().get_type())) { ObSysFunRawExpr* cast_expr = NULL; if (src_expr->get_result_type() == res_type) { /*do nothing*/ } else if (OB_FAIL( ObRawExprUtils::create_cast_expr(*expr_factory, src_expr, res_type, cast_expr, session_info))) { LOG_WARN("create cast expr for stmt failed", K(ret)); } else if (OB_FAIL(cast_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else { stmt->get_select_item(idx).expr_ = cast_expr; } } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above( expr_factory, session_info, *src_expr, res_type, new_expr))) { LOG_WARN("create cast expr for stmt failed", K(ret)); } else if (src_expr == new_expr) { /*do nothing*/ } else if (OB_FAIL(new_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else { stmt->get_select_item(idx).expr_ = new_expr; } } return ret; } int ObOptimizerUtil::check_subquery_has_ref_assign_user_var(ObRawExpr* expr, bool& is_has) { int ret = OB_SUCCESS; is_has = false; ObSEArray subqueries; ObQueryRefRawExpr* subquery = NULL; ObLogicalOperator* op = NULL; ObDMLStmt* stmt = NULL; if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(expr, subqueries))) { LOG_WARN("failed to extract query ref expr", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && !is_has && i < subqueries.count(); ++i) { if (OB_ISNULL(subquery = subqueries.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (subquery->is_ref_stmt()) { stmt = subquery->get_ref_stmt(); } else if (OB_ISNULL(op = subquery->get_ref_operator())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { stmt = op->get_stmt(); } if (OB_SUCC(ret)) { if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(stmt->has_ref_assign_user_var(is_has))) { LOG_WARN("failed to check stmt has ref assign user var", K(ret)); } } } } return ret; } bool ObOptimizerUtil::is_param_expr_correspond_subquey( const ObConstRawExpr& const_expr, ObIArray>& onetime_exprs) { bool is_from = false; if (!const_expr.has_flag(IS_PARAM)) { /*do nothing*/ } else { int64_t param_value = const_expr.get_value().get_unknown(); ObRawExpr* init_expr = find_exec_param(onetime_exprs, param_value); if (init_expr == NULL) { // not found, skip it } else if (init_expr->has_flag(CNT_SUB_QUERY)) { is_from = true; } } return is_from; } int ObOptimizerUtil::pushdown_filter_into_subquery(ObDMLStmt& parent_stmt, ObSelectStmt& subquery, ObOptimizerContext& opt_ctx, ObIArray& pushdown_filters, ObIArray& candi_filters, ObIArray& remain_filters, bool& can_pushdown) { int ret = OB_SUCCESS; bool has_rownum = false; bool has_rollup = false; can_pushdown = false; if (subquery.is_set_stmt()) { if (subquery.is_recursive_union() || subquery.has_limit()) { // do nothing } else if (OB_FAIL(check_pushdown_filter( parent_stmt, subquery, opt_ctx, pushdown_filters, candi_filters, remain_filters))) { LOG_WARN("failed to check pushdown filter", K(ret)); } else if (candi_filters.empty()) { // do thing } else { can_pushdown = true; } } else if (subquery.is_hierarchical_query()) { // can not pushdown do nothing } else if (0 == subquery.get_from_item_size()) { // expr value plan can not pushdown } else { has_rollup = subquery.has_rollup(); if (OB_FAIL(subquery.has_rownum(has_rownum))) { LOG_WARN("failed to check stmt has rownum", K(ret)); } else if (subquery.has_limit() || subquery.has_sequence() || subquery.is_contains_assignment() || has_rollup || has_rownum) { // can not pushdown do nothing } else if (OB_FAIL(check_pushdown_filter( parent_stmt, subquery, opt_ctx, pushdown_filters, candi_filters, remain_filters))) { LOG_WARN("failed to check pushdown filter", K(ret)); } else if (candi_filters.empty()) { // do thing } else { can_pushdown = true; } } if (OB_SUCC(ret) && !can_pushdown) { ret = remain_filters.assign(pushdown_filters); } return ret; } int ObOptimizerUtil::check_pushdown_filter(ObDMLStmt& parent_stmt, ObSelectStmt& subquery, ObOptimizerContext& opt_ctx, ObIArray& pushdown_filters, ObIArray& candi_filters, ObIArray& remain_filters) { int ret = OB_SUCCESS; bool is_valid = false; ObSEArray common_exprs; if (!parent_stmt.is_set_stmt() && subquery.is_set_stmt()) { if (OB_FAIL(check_pushdown_filter_overlap_index( parent_stmt, opt_ctx, pushdown_filters, candi_filters, remain_filters))) { LOG_WARN("failed to check pushdown filter overlap index", K(ret)); } } else if (OB_FAIL(get_groupby_win_func_common_exprs(subquery, common_exprs, is_valid))) { LOG_WARN("failed to get common exprs", K(ret)); } else if (is_valid && common_exprs.empty()) { // can not pushdown any filter } else if (parent_stmt.is_set_stmt()) { if (OB_FAIL(check_pushdown_filter_for_set(static_cast(parent_stmt), subquery, common_exprs, pushdown_filters, candi_filters, remain_filters))) { LOG_WARN("failed to check pushdown filter for set stmt", K(ret)); } } else { if (OB_FAIL(check_pushdown_filter_for_subquery(static_cast(parent_stmt), subquery, opt_ctx, common_exprs, pushdown_filters, candi_filters, remain_filters))) { LOG_WARN("failed to check pushdown filter for subquery", K(ret)); } } return ret; } int ObOptimizerUtil::check_pushdown_filter_overlap_index(ObDMLStmt& stmt, ObOptimizerContext& opt_ctx, ObIArray& pushdown_filters, ObIArray& candi_filters, ObIArray& remain_filters) { int ret = OB_SUCCESS; bool is_match_index = false; for (int64_t i = 0; OB_SUCC(ret) && !is_match_index && i < pushdown_filters.count(); ++i) { ObRawExpr* pred = NULL; ObSEArray column_exprs; if (OB_ISNULL(pred = pushdown_filters.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("predicate is null", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(pred, column_exprs))) { LOG_WARN("failed to extract column exprs", K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && !is_match_index && j < column_exprs.count(); ++j) { ObRawExpr* expr = column_exprs.at(j); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (OB_FAIL(ObTransformUtils::check_column_match_index(opt_ctx.get_root_stmt(), &stmt, opt_ctx.get_sql_schema_guard(), static_cast(column_exprs.at(j)), is_match_index))) { LOG_WARN("failed to check select expr is overlap index", K(ret)); } } } } if (OB_FAIL(ret)) { } else if (is_match_index) { ret = candi_filters.assign(pushdown_filters); } else { ret = remain_filters.assign(pushdown_filters); } return ret; } int ObOptimizerUtil::check_pushdown_filter_for_set(ObSelectStmt& parent_stmt, ObSelectStmt& subquery, ObIArray& common_exprs, ObIArray& pushdown_filters, ObIArray& candi_filters, ObIArray& remain_filters) { int ret = OB_SUCCESS; ObSEArray child_select_list; ObSEArray parent_select_list; if (OB_FAIL(subquery.get_select_exprs(child_select_list))) { LOG_WARN("get child stmt select exprs failed", K(ret)); } else if (OB_FAIL(parent_stmt.get_select_exprs(parent_select_list))) { LOG_WARN("get parent stmt select exprs failed", K(ret)); } else if (child_select_list.count() != parent_select_list.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child stmt select exprs size is incorrect", K(child_select_list.count()), K(parent_select_list.count()), K(ret)); } else if (OB_FAIL(ObTransformUtils::replace_exprs(parent_select_list, child_select_list, pushdown_filters))) { LOG_WARN("failed to replace expr", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_filters.count(); ++i) { ObSEArray view_column_exprs; ObRawExpr* expr = pushdown_filters.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->has_flag(CNT_WINDOW_FUNC) || expr->has_flag(CNT_AGG) || expr->has_flag(CNT_SUB_QUERY)) { ret = remain_filters.push_back(expr); } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(expr, view_column_exprs))) { LOG_WARN("failed to extract column exprs", K(ret)); } else if (!common_exprs.empty() && !subset_exprs(view_column_exprs, common_exprs)) { ret = remain_filters.push_back(expr); } else if (OB_FAIL(candi_filters.push_back(expr))) { LOG_WARN("failed to push back predicate", K(ret)); } } if (OB_FAIL(ret)) { // reset exprs for set } else if (OB_FAIL(ObTransformUtils::replace_exprs(child_select_list, parent_select_list, pushdown_filters))) { LOG_WARN("failed to replace expr", K(ret)); } else { LOG_TRACE("success to check_pushdown_filter_for_set", K(pushdown_filters), K(candi_filters), K(remain_filters)); } return ret; } int ObOptimizerUtil::check_pushdown_filter_for_subquery(ObSelectStmt& parent_stmt, ObSelectStmt& subquery, ObOptimizerContext& opt_ctx, ObIArray& common_exprs, ObIArray& pushdown_filters, ObIArray& candi_filters, ObIArray& remain_filters) { int ret = OB_SUCCESS; if (parent_stmt.is_set_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect set stmt here", K(ret)); } else { bool is_match_index = false; for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_filters.count(); ++i) { ObRawExpr* pred = NULL; ObSEArray column_exprs; ObSEArray select_exprs; bool pushed = false; if (OB_ISNULL(pred = pushdown_filters.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("predicate is null", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(pred, column_exprs))) { LOG_WARN("failed to extract column exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::convert_column_expr_to_select_expr(column_exprs, subquery, select_exprs))) { LOG_WARN("failed to convert column exprs to select exprs", K(ret)); } else if (column_exprs.count() != select_exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect column expr count", K(ret)); } else { bool is_simple_expr = true; bool is_match = false; ObSEArray view_column_exprs; for (int64_t j = 0; OB_SUCC(ret) && is_simple_expr && j < select_exprs.count(); ++j) { ObRawExpr* expr = select_exprs.at(j); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->has_flag(CNT_WINDOW_FUNC) || expr->has_flag(CNT_AGG) || expr->has_flag(CNT_SUB_QUERY)) { is_simple_expr = false; } else if (OB_FAIL(ObTransformUtils::check_column_match_index(opt_ctx.get_root_stmt(), &parent_stmt, opt_ctx.get_sql_schema_guard(), static_cast(column_exprs.at(j)), is_match))) { LOG_WARN("failed to check select expr is overlap index", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(expr, view_column_exprs))) { LOG_WARN("failed to extract column exprs", K(ret)); } } if (OB_FAIL(ret)) { } else if (!is_simple_expr) { // can not push down } else if (!common_exprs.empty() && !subset_exprs(view_column_exprs, common_exprs)) { } else if (OB_FAIL(candi_filters.push_back(pred))) { LOG_WARN("failed to push back predicate", K(ret)); } else { pushed = true; if (is_match) { is_match_index = true; } } } if (OB_SUCC(ret) && !pushed) { ret = remain_filters.push_back(pred); } } if (OB_FAIL(ret)) { // do nothing } else if (!is_match_index) { candi_filters.reset(); ret = remain_filters.assign(pushdown_filters); } } return ret; } int ObOptimizerUtil::get_groupby_win_func_common_exprs( ObSelectStmt& subquery, ObIArray& common_exprs, bool& is_valid) { int ret = OB_SUCCESS; bool has_winfunc = false; bool has_group = false; is_valid = true; has_group = subquery.has_group_by(); has_winfunc = subquery.has_window_function(); if (!has_group && !has_winfunc) { is_valid = false; } else { for (int64_t i = 0; OB_SUCC(ret) && i < subquery.get_window_func_count(); ++i) { ObWinFunRawExpr* win_expr = NULL; if (OB_ISNULL(win_expr = subquery.get_window_func_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("window function expr is null", K(ret)); } else if (i == 0) { if (OB_FAIL(common_exprs.assign(win_expr->get_partition_exprs()))) { LOG_WARN("failed to assign partition exprs", K(ret)); } } else if (OB_FAIL(intersect_exprs(common_exprs, win_expr->get_partition_exprs(), common_exprs))) { LOG_WARN("failed to intersect expr array", K(ret)); } else if (common_exprs.empty()) { break; } } if (OB_FAIL(ret)) { } else if (has_group && !has_winfunc && OB_FAIL(append(common_exprs, subquery.get_group_exprs()))) { LOG_WARN("failed to append exprs", K(ret)); } else if (has_group && has_winfunc && OB_FAIL(intersect_exprs(common_exprs, subquery.get_group_exprs(), common_exprs))) { LOG_WARN("failed to intersect expr array", K(ret)); } } return ret; } int ObOptimizerUtil::rename_pushdown_filter(const ObDMLStmt& parent_stmt, const ObSelectStmt& subquery, int64_t table_id, ObSQLSessionInfo* session_info, ObRawExprFactory& expr_factory, ObIArray& candi_filters, ObIArray& rename_filters) { int ret = OB_SUCCESS; if (parent_stmt.is_set_stmt()) { ret = rename_set_op_pushdown_filter(static_cast(parent_stmt), subquery, session_info, expr_factory, candi_filters, rename_filters); } else { ret = rename_subquery_pushdown_filter( parent_stmt, subquery, table_id, session_info, expr_factory, candi_filters, rename_filters); } return ret; } int ObOptimizerUtil::rename_set_op_pushdown_filter(const ObSelectStmt& parent_stmt, const ObSelectStmt& subquery, ObSQLSessionInfo* session_info, ObRawExprFactory& expr_factory, ObIArray& candi_filters, ObIArray& rename_filters) { int ret = OB_SUCCESS; int64_t stmt_level = -1; ObSEArray child_select_list; ObSEArray parent_select_list; if (OB_FAIL(subquery.get_select_exprs(child_select_list))) { LOG_WARN("get child stmt select exprs failed", K(ret)); } else if (OB_FAIL(parent_stmt.get_select_exprs(parent_select_list))) { LOG_WARN("get parent stmt select exprs failed", K(ret)); } else if (child_select_list.count() != parent_select_list.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child stmt select exprs size is incorrect", K(child_select_list.count()), K(parent_select_list.count()), K(ret)); } else { stmt_level = subquery.get_current_level(); } for (int64_t i = 0; OB_SUCC(ret) && i < parent_select_list.count(); ++i) { ObRawExpr* expr = NULL; if (OB_ISNULL(expr = ObTransformUtils::get_expr_in_cast(parent_select_list.at(i)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select expr is null", K(i), K(ret)); } else { parent_select_list.at(i) = expr; } } for (int64_t i = 0; OB_SUCC(ret) && i < candi_filters.count(); ++i) { ObRawExpr* pred = candi_filters.at(i); ObRawExpr* new_pred = NULL; if (OB_ISNULL(pred)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null pred", K(ret)); } else if (OB_FAIL(ObRawExprUtils::copy_expr(expr_factory, pred, new_pred, COPY_REF_DEFAULT))) { LOG_WARN("failed to copy expr", K(ret)); } else if (OB_FAIL(ObTransformUtils::replace_expr(parent_select_list, child_select_list, new_pred))) { LOG_WARN("failed to replace expr", K(ret)); } else if (OB_FAIL(new_pred->formalize(session_info))) { LOG_WARN("failed to formalize expr", K(ret)); } else if (OB_FAIL(new_pred->pull_relation_id_and_levels(stmt_level))) { LOG_WARN("failed to pull relation id and levels", K(ret)); } else { ret = rename_filters.push_back(new_pred); } } return ret; } int ObOptimizerUtil::rename_subquery_pushdown_filter(const ObDMLStmt& parent_stmt, const ObSelectStmt& subquery, int64_t table_id, ObSQLSessionInfo* session_info, ObRawExprFactory& expr_factory, ObIArray& candi_filters, ObIArray& rename_filters) { int ret = OB_SUCCESS; ObSEArray view_select_list; ObSEArray view_column_list; ObSEArray table_columns; int64_t stmt_level = -1; if (parent_stmt.is_set_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect set stmt here", K(ret)); } else if (OB_FAIL(parent_stmt.get_column_exprs(table_id, table_columns))) { LOG_WARN("failed to get column exprs", K(ret)); } else if (OB_FAIL(append(view_column_list, table_columns))) { LOG_WARN("failed to append column exprs", K(ret)); } else { stmt_level = subquery.get_current_level(); } for (int64_t i = 0; OB_SUCC(ret) && i < table_columns.count(); ++i) { ObRawExpr* sel_expr = NULL; ObColumnRefRawExpr* col_expr = table_columns.at(i); int64_t idx = -1; if (OB_ISNULL(col_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column expr is null", K(ret), K(col_expr)); } else if (FALSE_IT(idx = col_expr->get_column_id() - OB_APP_MIN_COLUMN_ID)) { // do nothing } else if (OB_UNLIKELY(idx < 0 || idx >= subquery.get_select_item_size())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select index is invalid", K(ret), K(idx)); } else if (OB_ISNULL(sel_expr = subquery.get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select expr expr is not found", K(ret), K(sel_expr)); } else if (OB_FAIL(view_select_list.push_back(sel_expr))) { LOG_WARN("failed to push back select expr", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < candi_filters.count(); ++i) { ObRawExpr* pred = candi_filters.at(i); ObRawExpr* new_pred = NULL; if (OB_ISNULL(pred)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null pred", K(ret)); } else if (OB_FAIL(ObRawExprUtils::copy_expr(expr_factory, pred, new_pred, COPY_REF_DEFAULT))) { LOG_WARN("failed to copy expr", K(ret)); } else if (OB_FAIL(ObTransformUtils::replace_expr(view_column_list, view_select_list, new_pred))) { LOG_WARN("failed to replace expr", K(ret)); } else if (OB_FAIL(new_pred->formalize(session_info))) { LOG_WARN("failed to formalize expr", K(ret)); } else if (OB_FAIL(new_pred->pull_relation_id_and_levels(stmt_level))) { LOG_WARN("failed to pull relation id and levels", K(ret)); } else { ret = rename_filters.push_back(new_pred); } } return ret; } int ObOptimizerUtil::get_set_op_remain_filter(const ObSelectStmt& stmt, const ObIArray& child_pushdown_preds, ObIArray& output_pushdown_preds, const bool first_child) { int ret = OB_SUCCESS; if (!stmt.is_set_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is not a set stmt", K(ret)); } else if (stmt.is_recursive_union()) { /*do nothing*/ } else if (first_child) { ret = output_pushdown_preds.assign(child_pushdown_preds); } else if (stmt.get_set_op() == ObSelectStmt::UNION) { for (int64_t i = 0; OB_SUCC(ret) && i < child_pushdown_preds.count(); ++i) { if (ObOptimizerUtil::find_equal_expr(output_pushdown_preds, child_pushdown_preds.at(i))) { /*do nothing*/ } else if (OB_FAIL(output_pushdown_preds.push_back(child_pushdown_preds.at(i)))) { LOG_WARN("push back preds failed", K(ret)); } else { /*do nothing*/ } } } else if (stmt.get_set_op() == ObSelectStmt::INTERSECT) { ObSEArray pushdown_preds; for (int64_t i = 0; OB_SUCC(ret) && i < child_pushdown_preds.count(); ++i) { if (!ObOptimizerUtil::find_equal_expr(output_pushdown_preds, child_pushdown_preds.at(i))) { /*do nothing*/ } else if (OB_FAIL(pushdown_preds.push_back(child_pushdown_preds.at(i)))) { LOG_WARN("push back preds failed", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret) && OB_FAIL(output_pushdown_preds.assign(pushdown_preds))) { LOG_WARN("failed to assign exprs", K(ret)); } } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::check_is_null_qual( const ObEstSelInfo& est_sel_info, const ObRelIds& table_ids, const ObRawExpr* qual, bool& is_null_qual) { int ret = OB_SUCCESS; is_null_qual = false; const ParamStore* params = est_sel_info.get_params(); const ObDMLStmt* stmt = est_sel_info.get_stmt(); const ObRawExpr* left_expr = NULL; const ObRawExpr* right_expr = NULL; ObObj result; if (OB_ISNULL(params) || OB_ISNULL(stmt) || OB_ISNULL(qual)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(params), K(stmt), K(qual)); } else if (T_OP_IS != qual->get_expr_type()) { // do nothing } else if (OB_ISNULL(left_expr = qual->get_param_expr(0)) || OB_ISNULL(right_expr = qual->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Left and right expr should not be NULL", K(ret), K(left_expr), K(right_expr)); } else if (!left_expr->is_column_ref_expr()) { // do nothing } else if (!ObOptEstUtils::is_calculable_expr(*right_expr, params->count())) { // do nothing } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(stmt->get_stmt_type(), const_cast(est_sel_info.get_session_info()), right_expr, result, params, const_cast(est_sel_info.get_allocator())))) { LOG_WARN("Failed to calc const or calculable expr", K(ret)); } else if (result.is_null()) { if (table_ids.is_superset(left_expr->get_relation_ids())) { is_null_qual = true; } } return ret; } int ObOptimizerUtil::check_expr_contain_subquery(const ObIArray& exprs, const ObIArray>* onetime_exprs, bool& has_subquery) { int ret = OB_SUCCESS; has_subquery = false; for (int64_t i = 0; OB_SUCC(ret) && !has_subquery && i < exprs.count(); i++) { if (OB_ISNULL(exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::check_expr_contain_subquery(exprs.at(i), onetime_exprs, has_subquery))) { LOG_WARN("failed to check expr contain subquery", K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::check_expr_contain_subquery( const ObRawExpr* expr, const ObIArray>* onetime_exprs, bool& has_subquery) { int ret = OB_SUCCESS; has_subquery = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (expr->has_flag(CNT_SUB_QUERY)) { has_subquery = true; } else if (NULL == onetime_exprs) { /*do nothing*/ } else if (expr->has_flag(IS_EXEC_PARAM)) { const ObConstRawExpr* const_expr = static_cast(expr); int64_t param = const_expr->get_value().get_unknown(); ObRawExpr* exec_expr = ObOptimizerUtil::find_exec_param(*onetime_exprs, param); if (NULL != exec_expr && exec_expr->has_flag(CNT_SUB_QUERY)) { has_subquery = true; } else { /*do nothing*/ } } else { for (int64_t i = 0; OB_SUCC(ret) && !has_subquery && i < expr->get_param_count(); i++) { if (OB_ISNULL(expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(SMART_CALL(ObOptimizerUtil::check_expr_contain_subquery( expr->get_param_expr(i), onetime_exprs, has_subquery)))) { LOG_WARN("failed to check whether expr contain subquery", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::check_expr_contain_sharable_subquery(ObRawExpr* expr, int32_t stmt_level, const ObIArray>& onetime_exprs, const bool ignore_root, bool& contains) { int ret = OB_SUCCESS; contains = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (!expr->has_flag(CNT_EXEC_PARAM) && !expr->has_flag(CNT_SUB_QUERY)) { /*do nothing*/ } else if (expr->has_flag(IS_SUB_QUERY)) { if (!ignore_root && expr->get_ref_count() > 1 && stmt_level == expr->get_expr_level()) { contains = true; } else { ObSEArray stmt_exprs; ObQueryRefRawExpr* query_expr = static_cast(expr); ObSelectStmt* stmt = query_expr->get_ref_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(stmt->get_relation_exprs(stmt_exprs))) { LOG_WARN("failed to get relation exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && !contains && i < stmt_exprs.count(); i++) { if (OB_ISNULL(stmt_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(SMART_CALL(ObOptimizerUtil::check_expr_contain_sharable_subquery( stmt_exprs.at(i), stmt_level, onetime_exprs, false, contains)))) { LOG_WARN("failed to check whether expr contain subquery", K(ret)); } else { /*do nothing*/ } } } } } else if (expr->has_flag(IS_EXEC_PARAM)) { const ObConstRawExpr* const_expr = static_cast(expr); int64_t param = const_expr->get_value().get_unknown(); ObRawExpr* exec_expr = ObOptimizerUtil::find_exec_param(onetime_exprs, param); if (NULL != exec_expr && OB_FAIL(SMART_CALL(ObOptimizerUtil::check_expr_contain_sharable_subquery( exec_expr, stmt_level, onetime_exprs, ignore_root, contains)))) { LOG_WARN("failed to check whether expr contain subquery", K(ret)); } } else { for (int64_t i = 0; OB_SUCC(ret) && !contains && i < expr->get_param_count(); i++) { if (OB_ISNULL(expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(SMART_CALL(ObOptimizerUtil::check_expr_contain_sharable_subquery( expr->get_param_expr(i), stmt_level, onetime_exprs, false, contains)))) { LOG_WARN("failed to check whether expr contain subquery", K(ret)); } else { /*do nothing*/ } } } return ret; } bool ObOptimizerUtil::has_psedu_column(const ObRawExpr& expr) { return expr.has_flag(CNT_ROWNUM) || expr.has_flag(CNT_SEQ_EXPR) || expr.has_flag(CNT_LEVEL) || expr.has_flag(CNT_CONNECT_BY_ISLEAF) || expr.has_flag(CNT_CONNECT_BY_ISCYCLE); } bool ObOptimizerUtil::has_hierarchical_expr(const ObRawExpr& expr) { return expr.has_flag(IS_PRIOR) || expr.has_flag(CNT_PRIOR) || expr.has_flag(CNT_CONNECT_BY_ROOT) || expr.has_flag(CNT_SYS_CONNECT_BY_PATH) || expr.has_flag(CNT_LEVEL) || expr.has_flag(CNT_CONNECT_BY_ISLEAF) || expr.has_flag(CNT_CONNECT_BY_ISCYCLE); } /* int ObOptimizerUtil::check_exprs_cnt_exec_param(const ObIArray &exprs, bool ignore_query_ref, int64_t level, bool &cnt_exec_param) { int ret = OB_SUCCESS; cnt_exec_param = false; for (int64_t i = 0; OB_SUCC(ret) && !cnt_exec_param && i < exprs.count(); ++i) { if (OB_FAIL(check_expr_cnt_exec_param(exprs.at(i), ignore_query_ref, level, cnt_exec_param))) { LOG_WARN("failed to check expr cnt exec param", K(ret)); } } return ret; } int ObOptimizerUtil::check_expr_cnt_exec_param(ObRawExpr *expr, bool ignore_query_ref, int64_t level, bool &cnt_exec_param) { int ret = OB_SUCCESS; cnt_exec_param = false; bool is_correlated = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->has_flag(CNT_EXEC_PARAM) && OB_FAIL(ObTransformUtils::is_correlated_expr(expr, level, is_correlated)) ) { LOG_WARN("failed to check is correlated expr", K(ret)); } else if (is_correlated) { cnt_exec_param = true; } else if (!ignore_query_ref && expr->is_query_ref_expr()) { ObQueryRefRawExpr *ref_query = static_cast(expr); if (ref_query->is_ref_stmt()) { ObSelectStmt *stmt = ref_query->get_ref_stmt(); ret = check_stmt_cnt_exec_param(stmt, level, cnt_exec_param); } else { ObLogicalOperator *log_plan = ref_query->get_ref_operator(); ObDMLStmt *stmt = NULL; if (OB_ISNULL(log_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null plan", K(ret)); } else if (OB_ISNULL( stmt = log_plan->get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else if (!stmt->is_select_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expect select stmt", K(*stmt), K(ret)); } else { ret = check_stmt_cnt_exec_param(static_cast(stmt), level, cnt_exec_param); } } } else { int64_t count = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && !cnt_exec_param && 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(check_expr_cnt_exec_param(expr->get_param_expr(i), ignore_query_ref, level, cnt_exec_param)))) { LOG_WARN("failed to check expr cnt exec param", K(ret)); } } } return ret; } int ObOptimizerUtil::check_stmt_cnt_exec_param(ObSelectStmt *select_stmt, bool ignore_query_ref, int64_t level, bool &cnt_exec_param) { int ret = OB_SUCCESS; cnt_exec_param = false; bool is_stack_overflow = false; ObSEArray relation_exprs; 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_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(select_stmt)); } else if (OB_FAIL(select_stmt->get_relation_exprs(relation_exprs))) { LOG_WARN("failed to get relation exprs", K(ret)); } else if (OB_FAIL(check_exprs_cnt_exec_param(relation_exprs, ignore_query_ref, level, cnt_exec_param))) { LOG_WARN("failed to check exprs cnt exec param", K(ret)); } return ret; } int ObOptimizerUtil::check_stmt_cnt_exec_param(ObSelectStmt *stmt, int64_t level, bool &cnt_exec_param) { int ret = OB_SUCCESS; cnt_exec_param = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else { ObArray child_stmts; if (OB_FAIL(check_stmt_cnt_exec_param(stmt, true, level, cnt_exec_param))) { LOG_WARN("fail to check stmt cnt exec param", 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(check_stmt_cnt_exec_param(child_stmts.at(i), level, cnt_exec_param)))) { LOG_WARN("fail to check stmt cnt exec param", K(ret)); } } } } return ret; } */ int ObOptimizerUtil::check_pushdown_filter_to_base_table(ObLogPlan& plan, const uint64_t table_id, const ObIArray& pushdown_filters, const ObIArray& restrict_infos, bool& can_pushdown) { int ret = OB_SUCCESS; ObSEArray col_exprs; ObSEArray pushdown_col_exprs; ObDMLStmt* stmt = plan.get_stmt(); can_pushdown = false; for (int64_t i = 0; OB_SUCC(ret) && i < restrict_infos.count(); ++i) { if (OB_FAIL(ObTransformUtils::get_simple_filter_column(stmt, restrict_infos.at(i), table_id, col_exprs))) { LOG_WARN("failed to get simple filter column", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_filters.count(); ++i) { if (OB_FAIL( ObTransformUtils::get_simple_filter_column(stmt, pushdown_filters.at(i), table_id, pushdown_col_exprs))) { LOG_WARN("failed to get simple filter column", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && !can_pushdown && i < pushdown_col_exprs.count(); ++i) { ObColumnRefRawExpr* col_expr = pushdown_col_exprs.at(i); if (OB_FAIL(ObTransformUtils::is_match_index( plan.get_optimizer_context().get_sql_schema_guard(), stmt, col_expr, can_pushdown, NULL, &col_exprs))) { LOG_WARN("failed to check is match index", K(ret)); } } LOG_TRACE("check pushdown filter to tables", K(table_id), K(can_pushdown)); return ret; }