/** * 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/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 "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" #include "lib/utility/utility.h" #include "sql/optimizer/ob_opt_selectivity.h" #include "sql/optimizer/ob_log_table_scan.h" #include "share/location_cache/ob_location_service.h" #include "share/ob_order_perserving_encoder.h" #include "sql/rewrite/ob_predicate_deduce.h" using namespace oceanbase; using namespace sql; using namespace oceanbase::common; using namespace oceanbase::share::schema; using namespace oceanbase::share; int MergeKeyInfo::assign(MergeKeyInfo &other) { int ret = OB_SUCCESS; if (OB_FAIL(map_array_.assign(other.map_array_))) { LOG_WARN("failed to assign map array", K(ret)); } else if (OB_FAIL(order_directions_.assign(other.order_directions_))) { LOG_WARN("failed to assign order directions", K(ret)); } else if (OB_FAIL(order_exprs_.assign(other.order_exprs_))) { LOG_WARN("failed to assign order exprs", K(ret)); } else if (OB_FAIL(order_items_.assign(other.order_items_))) { LOG_WARN("failed to assign order exprs", K(ret)); } else { need_sort_ = other.need_sort_; order_needed_ = other.order_needed_; prefix_pos_ = other.prefix_pos_; } return ret; } int ObOptimizerUtil::is_prefix_ordering(const ObIArray &first, const ObIArray &second, const EqualSets &equal_sets, const ObIArray &const_exprs, bool &first_is_prefix, bool &second_is_prefix) { int ret = OB_SUCCESS; ObSEArray first_exprs; ObSEArray first_directions; ObSEArray second_exprs; ObSEArray second_directions; if (OB_FAIL(split_expr_direction(first, first_exprs, first_directions))) { LOG_WARN("Failed to construct direction", K(ret)); } else if (OB_FAIL(split_expr_direction(second, second_exprs, second_directions))) { LOG_WARN("Failed to construct direction", K(ret)); } else if (OB_FAIL(find_common_prefix_ordering(first_exprs, second_exprs, equal_sets, const_exprs, first_is_prefix, second_is_prefix, &first_directions, &second_directions))) { LOG_WARN("Failed to check is 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, bool &left_is_prefix, bool &right_is_prefix, const ObIArray *left_directions, const ObIArray *right_directions) { int ret = OB_SUCCESS; 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_match = true; ObSEArray dummy_exprs; left_is_prefix = false; right_is_prefix = false; while (OB_SUCCESS == ret && is_match && i < N && j < M) { if (((NULL != right_directions && NULL != left_directions) ? left_directions->at(i) != right_directions->at(j) : false) || (!is_expr_equivalent(left_side.at(i), right_side.at(j), equal_sets))) { if (OB_FAIL(is_const_or_equivalent_expr(left_side, equal_sets, const_exprs, dummy_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, dummy_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_match = false; } else { if (left_is_const) { ++i; } if (right_is_const) { ++j; } } } else { ++i; ++j; } } if (OB_SUCC(ret) && is_match) { if (i != N && j != M) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect prefix ordering matching", K(ret)); } else if (i < N) { right_is_prefix = true; for (; OB_SUCC(ret) && i < N; i++) { if (OB_FAIL(is_const_or_equivalent_expr(left_side, equal_sets, const_exprs, dummy_exprs, i, left_is_const))) { LOG_WARN("failed to check is const or equivlent expr", K(ret)); } else if (!left_is_const) { break; } } if (OB_SUCC(ret) && i == N) { left_is_prefix = true; } } else if (j < M) { left_is_prefix = true; for (; OB_SUCC(ret) && j < M; j++) { if (OB_FAIL(is_const_or_equivalent_expr(right_side, equal_sets, const_exprs, dummy_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) && j == M) { right_is_prefix = true; } } else { left_is_prefix = true; right_is_prefix = true; } } return ret; } int ObOptimizerUtil::is_const_or_equivalent_expr(const common::ObIArray &exprs, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_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, exec_ref_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 ObIArray &order_items, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_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, exec_ref_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; } //要求exprs是不含常量表达式的表达式集合 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) { //有一个序的表达式没有在exprs中被匹配,那么需要看这个表达式是否是常量,如果是常量可以跳过 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; } // fast check, just return a bool result int ObOptimizerUtil::prefix_subset_exprs(const ObIArray &exprs, const ObIArray &ordering, const EqualSets &equal_sets, const ObIArray &const_exprs, bool &is_prefix) { int ret = OB_SUCCESS; is_prefix = false; bool is_break = false; for (int64_t i = 0; OB_SUCC(ret) && !is_break && !is_prefix && i < ordering.count(); ++i) { for (int64_t j = 0; OB_SUCC(ret) && !is_prefix && j < exprs.count(); ++j) { if (is_expr_equivalent(ordering.at(i), exprs.at(j), equal_sets)) { is_prefix = true; } } if (OB_SUCC(ret) && !is_prefix) { //有一个序的表达式没有在exprs中被匹配,那么需要看这个表达式是否是常量,如果是常量可以跳过 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; } } } return ret; } //要求exprs是不含常量表达式的表达式集合 int ObOptimizerUtil::adjust_exprs_by_ordering(ObIArray &exprs, const ObIArray &ordering, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_exprs, int64_t &prefix_count, bool &ordering_all_used, ObIArray &directions, ObIArray *match_map /*=NULL*/) { int ret = OB_SUCCESS; prefix_count = -1; ordering_all_used = false; ObSEArray adjusted_exprs; ObSEArray order_types; ObSEArray expr_map; ObBitSet<64> expr_idxs; bool is_found = true; for (int64_t i = 0; OB_SUCC(ret) && is_found && i < ordering.count(); ++i) { const OrderItem &sort_key = ordering.at(i); bool is_const = false; if (OB_FAIL(is_const_or_equivalent_expr(ordering, equal_sets, const_exprs, exec_ref_exprs, i, is_const))) { LOG_WARN("failed to check is const or equivalent expr", K(ret)); } else if (is_const) { is_found = true; } else { 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; 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)) { prefix_count = adjusted_exprs.count(); ordering_all_used = prefix_count > 0; } 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)); } else { ordering_all_used = false; } } 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::in_same_equalset(const ObRawExpr *from, const ObRawExpr *to, const EqualSets &equal_sets) { bool found = false; int64_t N = equal_sets.count(); for (int64_t i = 0; !found && i < N; ++i) { if (OB_ISNULL(equal_sets.at(i))) { LOG_WARN_RET(OB_ERR_UNEXPECTED, "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; } 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 (equal_sets.empty()) { // do nothing } else if (ObRawExprUtils::expr_is_order_consistent(from, to, is_consistent) != OB_SUCCESS) { LOG_WARN_RET(OB_ERR_UNEXPECTED, "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_RET(OB_ERR_UNEXPECTED, "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; } bool ObOptimizerUtil::is_expr_equivalent(const ObRawExpr *from, const ObRawExpr *to) { bool found = 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; } return found; } 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, const ObIArray &exec_ref_exprs, bool &is_const) { int ret = OB_SUCCESS; if (OB_FAIL(is_root_expr_const(expr, equal_sets, const_exprs, exec_ref_exprs, is_const))) { LOG_WARN("failed to check is const expr", K(ret)); } else if (is_const) { // do nothing } else if (OB_FAIL(SMART_CALL(is_const_expr_recursively(expr, exec_ref_exprs, is_const)))) { LOG_WARN("failed to check const expr", K(ret)); } return ret; } int ObOptimizerUtil::is_const_expr_recursively(const ObRawExpr *expr, const ObIArray &exec_ref_exprs, bool &is_const) { int ret = OB_SUCCESS; bool is_const_inherit = true; is_const = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret)); } else if (OB_FAIL(is_const_expr(expr, exec_ref_exprs, is_const))) { LOG_WARN("failed to check const expr", K(ret)); } else if (is_const) { // do nothing } else if (OB_FAIL(expr->is_const_inherit_expr(is_const_inherit, true))) { LOG_WARN("failed to check is const inherit expr", K(ret)); } else if (is_const_inherit && expr->get_param_count() > 0) { bool is_param_const = true; for (int64_t i = 0; OB_SUCC(ret) && is_param_const && i < expr->get_param_count(); ++i) { const ObRawExpr *param_expr = expr->get_param_expr(i); if (OB_FAIL(SMART_CALL(is_const_expr_recursively(param_expr, exec_ref_exprs, is_param_const)))) { LOG_WARN("failed to check param expr is const", K(ret)); } } if (OB_SUCC(ret) && is_param_const) { is_const = true; } } return ret; } int ObOptimizerUtil::is_root_expr_const(const ObRawExpr *expr, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_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 (OB_FAIL(is_const_expr(expr, const_exprs, is_const))) { LOG_WARN("failed to check if is const expr", K(expr), K(ret)); } else if (!is_const && OB_FAIL(is_const_expr(expr, exec_ref_exprs, is_const))) { LOG_WARN("failed to check if is const expr", K(expr), K(ret)); } else if (!is_const) { const EqualSet *equal_set = NULL; const ObRawExpr *cur_expr = NULL; bool is_consistent = false; for (int64_t i = 0; OB_SUCC(ret) && !is_const && i < equal_sets.count(); ++i) { if (OB_ISNULL(equal_set = equal_sets.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("equal set is null"); } else if (find_equal_expr(*equal_set, expr)) { for (int64_t j = 0; OB_SUCC(ret) && !is_const && j < equal_set->count(); ++j) { if (OB_ISNULL(cur_expr = equal_set->at(j))) { 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; } int ObOptimizerUtil::is_const_expr(const ObRawExpr *expr, const EqualSets &equal_sets, const ObIArray &const_exprs, bool &is_const) { int ret = OB_SUCCESS; ObSEArray dummy_exprs; if (OB_FAIL(is_const_expr(expr, equal_sets, const_exprs, dummy_exprs, is_const))) { LOG_WARN("failed to check if is const expr", K(ret)); } return ret; } 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->is_const_expr()) { //为了能够将?+ const这种情况判断出是const,需要使用该函数判断 is_const = true; } else if (find_item(const_exprs, expr)) { is_const = true; } return ret; } int ObOptimizerUtil::compute_const_exprs(const ObIArray &condition_exprs, ObIArray &const_exprs) { int ret = OB_SUCCESS; ObRawExpr *const_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < condition_exprs.count(); ++i) { if (OB_FAIL(compute_const_exprs(condition_exprs.at(i), const_expr))) { LOG_WARN("failed to compute const exprs", K(ret)); } else if (NULL == const_expr) { /*do nothing*/ } else if (OB_FAIL(add_var_to_array_no_dup(const_exprs, const_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else {/*do nothing*/} } return ret; } int ObOptimizerUtil::compute_const_exprs(ObRawExpr *cur_expr, ObRawExpr *&res_const_expr) { int ret = OB_SUCCESS; res_const_expr = NULL; if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr passed in should not be NULL", 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); 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(get_expr_without_lossless_cast(param_1, param_1))) { LOG_WARN("failed to get expr without lossless cast", K(ret)); } else if (OB_FAIL(get_expr_without_lossless_cast(param_2, param_2))) { LOG_WARN("failed to get expr without lossless cast", K(ret)); } else { bool left_const = param_1->is_const_expr(); bool right_const = param_2->is_const_expr(); 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(common_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) { res_const_expr = common_expr; } } else if (T_BOOL == const_expr->get_expr_type()) { // is true/false will not be regarded as const } else { res_const_expr = common_expr; } } } } 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 &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::same_exprs(const common::ObIArray &src_exprs, const common::ObIArray &target_exprs, const EqualSets &equal_sets) { int ret = OB_SUCCESS; if (src_exprs.count() != target_exprs.count()) { return false; } else { return subset_exprs(src_exprs, target_exprs, equal_sets) && subset_exprs(target_exprs, src_exprs, equal_sets); } return ret; } bool ObOptimizerUtil::same_exprs(const common::ObIArray &src_exprs, const common::ObIArray &target_exprs) { int ret = OB_SUCCESS; if (src_exprs.count() != target_exprs.count()) { return false; } else { return subset_exprs(src_exprs, target_exprs) && subset_exprs(target_exprs, src_exprs); } return ret; } int ObOptimizerUtil::intersect_exprs(const ObIArray &first, const ObIArray &right, const EqualSets &equal_sets, 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), equal_sets)) { // 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::intersect_exprs(const ObIArray &first, const 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(const ObIArray &first, const 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::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_EXEC_PARAM: 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: { ObUDFRawExpr *dest_udf = NULL; if (OB_FAIL(expr_factory.create_raw_expr(src->get_expr_type(), dest_udf))) { LOG_WARN("failed to allocate raw expr", K(ret)); } else if (OB_ISNULL(dest = dest_udf)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dest user define function is null", K(ret)); } else { ObUDFRawExpr *src_udf = static_cast(src); if (OB_ISNULL(src_udf)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("casted src user define function is null", K(ret)); } else if (OB_FAIL(dest_udf->assign(*src_udf))) { LOG_WARN("failed to assign expr", K(ret)); } else { dest_udf->clear_child(); int64_t count = src_udf->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { ObRawExpr *param_expr = src_udf->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_udf->add_param_expr(new_param_expr))) { LOG_WARN("fail to push raw expr", K(ret)); } else {/*do nothing*/} } } } break; } case ObRawExpr::EXPR_QUERY_REF : // TODO@nijia.nj : 暂时没有逻辑需要copy window_function, 未来还是需要加上 case ObRawExpr::EXPR_WINDOW: { ret = OB_ERR_UNEXPECTED; 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; } 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 ObIArray &exprs, const ObRawExpr *expr, 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)) { found = true; idx = i; } } 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, ObIArray &null_safe_info) { 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 { bool is_null_safe = (temp_expr->get_expr_type() == T_OP_NSEQ || temp_expr->get_expr_type() == T_OP_SQ_NSEQ); 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 if (OB_FAIL(null_safe_info.push_back(is_null_safe))) { LOG_WARN("failed to push back null safe info", K(ret)); } else { /*do nothing*/ } } } return ret; } bool ObOptimizerUtil::find_exec_param(const common::ObIArray ¶ms, const ObExecParamRawExpr *ele) { bool bret = false; if (NULL != ele) { for (int64_t i = 0; !bret && i < params.count(); ++i) { if (params.at(i) != NULL) { bret = params.at(i)->get_param_index() == ele->get_param_index(); } } } return bret; } int ObOptimizerUtil::get_exec_ref_expr(const ObIArray &exec_params, ObIArray &ref_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exec_params.count(); ++i) { if (OB_ISNULL(exec_params.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("exec param is null", K(ret)); } else if (OB_FAIL(ref_exprs.push_back(exec_params.at(i)->get_ref_expr()))) { LOG_WARN("failed to push back ref expr", K(ret)); } } return ret; } ObRawExpr* ObOptimizerUtil::find_exec_param(const ObIArray > ¶ms, 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 > ¶ms, 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; } int ObOptimizerUtil::extract_equal_exec_params(const ObIArray &exprs, const ObIArray &my_params, ObIArray &left_key, ObIArray &right_key, ObIArray &null_safe_info) { 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()) { bool is_null_safe = (T_OP_NSEQ == cur_expr->get_expr_type()); 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)->is_exec_param_expr()) { ObExecParamRawExpr *exec_param = static_cast(cur_expr->get_param_expr(0)); if (!find_item(my_params, exec_param)) { /* * 在参数列表里没找到,说明这不是一个与自己相关的参数,跳过即可 * 例如NL的内表里有条件b1=? and b2=?,其中第一个?是一个const在parser阶段被参数化出来的,第二个?是外表相关 * 属性a1,那么第一个?在这里是肯定找不到的,跳过即可。 */ } else if (OB_FAIL(left_key.push_back(exec_param->get_ref_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 if (OB_FAIL(null_safe_info.push_back(is_null_safe))) { LOG_WARN("push back error", K(ret)); } else { /*do nothing*/ } } else if (cur_expr->get_param_expr(1)->is_exec_param_expr()) { ObExecParamRawExpr *exec_param = static_cast(cur_expr->get_param_expr(1)); if (!find_item(my_params, exec_param)) { // not my exec param } else if (OB_FAIL(left_key.push_back(exec_param->get_ref_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 if (OB_FAIL(null_safe_info.push_back(is_null_safe))) { LOG_WARN("push back error", K(ret)); } else { /*do nothing*/ } } else { /*do nothing*/ } } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::generate_rowkey_exprs(const 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(table_id, ref_table_id, stmt, 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(const ObDMLStmt* cstmt, ObRawExprFactory &expr_factory, uint64_t table_id, const ObTableSchema &index_table_schema, ObIArray &index_keys, ObIArray &index_ordering) { int ret = OB_SUCCESS; ObDMLStmt *stmt = const_cast(cstmt); 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::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::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; // banliu.zyd: init_xxx 记录第一次extract的结果(即对IN表达式的第一个值) // 我们期望对于IN中的每一项,extract结果都是一致的,如果有不一致,则不放到prefix_filter里 // 如果每一项都是一致的,最终是否放到prefix_filter再由外层决定 common::ObBitSet<> init_col_idxs = col_idxs; int64_t init_min_col_idx = min_col_idx; bool init_is_table_filter = false; // banliu.zyd: tmp_xxx 临时记录extract的结果 // extract的结果是否和第一次结果一致 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; } //row的处理应该作为一个整体来处理,对query range有影响的有效的列应该为按照column_ids有序的索引列 //比如(a,b,c,d) 为索引(a,b) + 主键(c,d) //(a,b) > (1,1) 那么对range有影响的列为a,b //(b,c) > (1,1) 或者 (b,a) > (1,1) b可能对range有影响,会把b放入col_idxs中,外面会再进行判断。 //(b,c) > (a,b) 这种range是判断不出来的,不放入col_idxs中 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)) { // cur_col_idx为抽取的列id在column_idx中的pos 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()) { //不是column可以直接报错了 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); //NULL说明这个表达式找不到child stmt与之对应的表达式 } 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()) { //不是column可以直接报错了 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); //NULL说明这个表达式找不到child stmt与之对应的表达式 } 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; } /** * @brief * given source and target table id, try to find its lowest common joined table * then check if the source table is on the null side of the joined table * @param stmt * @param source_table_id * @param target_table_id * @param is_on_null_side * @return int */ int ObOptimizerUtil::is_table_on_null_side_of_parent(const ObDMLStmt *stmt, uint64_t source_table_id, uint64_t target_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 { JoinedTable *common_joined_table = NULL; for (int64_t i = 0; OB_SUCC(ret) && OB_ISNULL(common_joined_table) && i < stmt->get_joined_tables().count(); ++i) { JoinedTable *joined_table = stmt->get_joined_tables().at(i); bool is_source_in_joined_table = false; if (OB_ISNULL(joined_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(find_common_joined_table(joined_table, source_table_id, target_table_id, common_joined_table))) { LOG_WARN("failed to find target joined table", K(ret)); } else if (common_joined_table != NULL && OB_FAIL(is_table_on_null_side_recursively(common_joined_table, source_table_id, is_source_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::find_common_joined_table(JoinedTable *joined_table, uint64_t source_table_id, uint64_t target_table_id, JoinedTable *&target_joined_table) { int ret = OB_SUCCESS; TableItem *left_table = NULL; TableItem *right_table = NULL; if (OB_ISNULL(joined_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else 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(left_table), K(right_table)); } else if (is_contain(joined_table->single_table_ids_, source_table_id) && is_contain(joined_table->single_table_ids_, target_table_id)) { target_joined_table = joined_table; JoinedTable *left_common_table = NULL; JoinedTable *right_common_table = NULL; if (left_table->is_joined_table() && OB_FAIL(find_common_joined_table(static_cast(left_table), source_table_id, target_table_id, left_common_table))) { LOG_WARN("failed to find left common joined table", K(ret)); } else if (left_common_table != NULL) { target_joined_table = left_common_table; } else if (right_table->is_joined_table() && OB_FAIL(find_common_joined_table(static_cast(right_table), source_table_id, target_table_id, right_common_table))) { LOG_WARN("failed to find right common joined table", K(ret)); } else if (right_common_table != NULL) { target_joined_table = right_common_table; } } 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::extract_parameterized_correlated_filters(const ObIArray &filters, ObIArray &correlated_filters, ObIArray &uncorrelated_filters) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < filters.count(); ++i) { if (OB_ISNULL(filters.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("filter is invalid", K(ret)); } else if (OB_FAIL(filters.at(i)->has_flag(CNT_DYNAMIC_PARAM))) { if (OB_FAIL(correlated_filters.push_back(filters.at(i)))) { LOG_WARN("failed to push back correlated filters", K(ret)); } } else { if (OB_FAIL(uncorrelated_filters.push_back(filters.at(i)))) { LOG_WARN("failed to push back uncorrelated filters", K(ret)); } } }//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::get_default_directions(const int64_t direction_num, ObIArray &directions) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < direction_num; ++i) { if (OB_FAIL(directions.push_back(default_asc_direction()))) { LOG_WARN("failed to push back default asc direction", K(ret)); } } return ret; } int ObOptimizerUtil::make_sort_keys(const ObIArray &sort_exprs, ObIArray &sort_keys) { int ret = OB_SUCCESS; sort_keys.reuse(); OrderItem key; for (int64_t i = 0; OB_SUCC(ret) && i < sort_exprs.count(); ++i) { key.expr_ = sort_exprs.at(i); ret = sort_keys.push_back(key); } 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.reuse(); 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::get_expr_and_types(const common::ObIArray &order_items, ObIArray &order_exprs, ObIArray &order_types) { int ret = OB_SUCCESS; ObRawExpr *expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < order_items.count(); i++) { if (OB_ISNULL(expr = order_items.at(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(expr), K(ret)); } else if (OB_FAIL(order_exprs.push_back(expr))) { LOG_WARN("failed to get order exprs", K(ret)); } else if (OB_FAIL(order_types.push_back(expr->get_result_type()))) { LOG_WARN("failed to push back expr", 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, const bool with_onetime) { 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)); } else if (temp_expr->has_flag(CNT_SUB_QUERY) || (with_onetime && temp_expr->has_flag(CNT_ONETIME))) { // 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, const bool with_onetime /*=true*/) { 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)) { if (OB_FAIL(subquery_exprs.push_back(exprs.at(i)))) { LOG_WARN("failed to push back exprs", K(ret)); } } else if (with_onetime && exprs.at(i)->has_flag(CNT_ONETIME)) { if (OB_FAIL(subquery_exprs.push_back(exprs.at(i)))) { LOG_WARN("failed to push back exprs", K(ret)); } } } return ret; } int ObOptimizerUtil::get_onetime_exprs(ObRawExpr* expr, ObIArray &onetime_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(expr), K(ret)); } else if (expr->has_flag(IS_ONETIME)) { if (OB_FAIL(onetime_exprs.push_back(static_cast(expr)))) { LOG_WARN("failed to push back expr", K(ret)); } } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_FAIL(SMART_CALL(get_onetime_exprs(expr->get_param_expr(i), onetime_exprs)))) { LOG_WARN("failed to get one time expr", K(ret)); } } } return ret; } int ObOptimizerUtil::get_query_ref_exprs(ObIArray &exprs, ObIArray &subqueries, ObIArray &nested_subqueries) { int ret = OB_SUCCESS; ObSEArray tmp; if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(exprs, tmp, false))) { LOG_WARN("failed to extract query ref exprs", K(ret)); } else if (OB_FAIL(append(subqueries, tmp))) { LOG_WARN("failed to append subqueries", K(ret)); } else { tmp.reuse(); } for (int64_t i = 0; OB_SUCC(ret) && i < subqueries.count(); ++i) { ObRawExpr *expr = NULL; if (OB_ISNULL(expr = subqueries.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("subquery expr is null", K(ret), K(expr)); } for (int64_t j = 0; OB_SUCC(ret) && j < expr->get_param_count(); ++j) { if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(expr->get_param_expr(j), tmp, false))) { LOG_WARN("failed to extract nested subqueries", K(ret)); } } } if (OB_SUCC(ret) && OB_FAIL(append(nested_subqueries, tmp))) { LOG_WARN("failed to append nested subqueries", K(ret)); } return ret; } int ObOptimizerUtil::get_nested_exprs(ObIArray &exprs, ObIArray &nested_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("expr is null", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < exprs.at(i)->get_param_count(); ++j) { ObRawExpr *param = NULL; if (OB_ISNULL(param = exprs.at(i)->get_param_expr(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param expr is null", K(ret)); } else if (!param->has_flag(CNT_SUB_QUERY) && !param->has_flag(CNT_ONETIME)) { // do nothing } else if (OB_FAIL(nested_exprs.push_back(param))) { LOG_WARN("failed to push back nested exprs", K(ret)); } } } return ret; } int ObOptimizerUtil::get_non_const_expr_size(const ObIArray &exprs, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_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, exec_ref_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::ObIArray &get_ranges, common::ObIArray &scan_ranges) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < input_ranges.count(); i++) { if (input_ranges.at(i).is_single_rowkey()) { if (OB_FAIL(get_ranges.push_back(input_ranges.at(i)))) { LOG_WARN("failed to push back ranges", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(scan_ranges.push_back(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; //使用 extend_exprs 判断是否 unique, 同时扩充 extend_exprs, 当 extend_exprs 数量增加且未 unique 时, //迭代进行检查, 暂时设定最大迭代次数为 10 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_expr_is_determined(const ObIArray &exprs, const ObFdItemSet &fd_item_set, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObRawExpr *expr, bool &is_determined) { int ret = OB_SUCCESS; is_determined = false; const ObFdItem *fd_item = NULL; for (int64_t fd_idx = 0; OB_SUCC(ret) && !is_determined && fd_idx < fd_item_set.count(); ++fd_idx) { 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(exprs, *fd_item, equal_sets, const_exprs, is_determined))) { LOG_WARN("failed to check is exprs contain fd parent", K(ret)); } else if (is_determined && OB_FAIL(fd_item->check_expr_in_child(expr, equal_sets, is_determined))) { LOG_WARN("failed to check expr in fd child", 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; 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()))) { 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 ¬_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 || (lib::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(const ObDMLStmt *stmt, ObFdItemFactory &fd_factory, const uint64_t table_id, ObRelIds &tables, const ObTableSchema *index_schema, const ObIArray &quals, ObIArray ¬_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; const 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 (OB_ALL_VIRTUAL_TENANT_INFO_TID != table->ref_id_ && is_virtual_table(table->ref_id_)) { /*虚拟表不产生 fd 及 not null 信息*/ } 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)); //new heap table not add partition key in rowkey and the tablet id is unique in partition, //we need check partition key } else if (index_schema->is_heap_table() && index_schema->get_partition_key_info().is_valid() && OB_FAIL(index_schema->get_partition_key_info().get_column_ids(column_ids))) { LOG_WARN("failed to add part column ids", K(ret)); } else if (index_schema->is_heap_table() && index_schema->get_subpartition_key_info().is_valid() && OB_FAIL(index_schema->get_subpartition_key_info().get_column_ids(column_ids))) { LOG_WARN("failed to add subpart column ids", 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 (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_for_read())) { // 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, tables))) { LOG_WARN("failed to create fd item", K(ret)); } else if (all_not_null || (lib::is_oracle_mode() && contain_not_null) || index_schema->get_table_id() == table->ref_id_) { // 1. 在oracle中, unique index (c1,c2) 允许存在多个 (null, null), 但不允许存在多个 (1, null), // 因此oracle模式下只要unique index中有一列是not null的, 该index中就不存在重复的值 // 2. the primary index must be unique even if a partition table may have a nullable part-key // wihch is a part of the primary key. 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, const 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 ObIArray &const_exprs, const uint64_t table_id, const 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; 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) { 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(convert_subplan_scan_fd_parent_exprs(expr_factory, equal_sets, const_exprs, table_id, parent_stmt, child_stmt, *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, 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, 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::convert_subplan_scan_fd_parent_exprs(ObRawExprFactory &expr_factory, const EqualSets &equal_sets, const ObIArray &const_exprs, const uint64_t table_id, const ObDMLStmt &parent_stmt, const ObSelectStmt &child_stmt, const ObIArray &input_exprs, ObIArray &output_exprs) { int ret = OB_SUCCESS; bool is_valid = true; output_exprs.reuse(); ObRawExprCopier copier(expr_factory); 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(copier, 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 (OB_FAIL(is_const_expr(input_exprs.at(i), equal_sets, const_exprs, is_valid))) { LOG_WARN("failed to check is const expr", K(ret)); } else if (!is_valid) { output_exprs.reuse(); } } else if (OB_FAIL(add_var_to_array_no_dup(output_exprs, expr))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret)) { LOG_TRACE("succeed to convert subplan scan expr skip const", K(input_exprs), K(output_exprs)); } return ret; } /** * 1. 根据连接条件将 candi fd item 提升为 fd item * 2. 确定连接是否为 n to 1 连接 * 3. 根据连接性质确定连接结果的 fd item * join_info == NULL means Cartesian join */ 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 ObIArray &exec_ref_exprs, const bool is_at_most_one_row, bool &need_sort, int64_t &prefix_pos) { int ret = OB_SUCCESS; const int64_t part_cnt = 0; return ObOptimizerUtil::check_need_sort(expected_order_items, input_ordering, fd_item_set, equal_sets, const_exprs, exec_ref_exprs, is_at_most_one_row, need_sort, prefix_pos, part_cnt); } 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 ObIArray &exec_ref_exprs, const bool is_at_most_one_row, bool &need_sort, int64_t &prefix_pos, const int64_t part_cnt, const bool check_part_only/* default false */) { 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, exec_ref_exprs, is_at_most_one_row, need_sort, prefix_pos, part_cnt, check_part_only))) { 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 ObIArray &exec_ref_exprs, const bool is_at_most_one_row, bool &need_sort, int64_t &prefix_pos, const int64_t part_cnt, const bool check_part_only/* default false */) { int ret = OB_SUCCESS; need_sort = true; if (!check_part_only && OB_FAIL(ObOptimizerUtil::check_need_sort(expected_order_exprs, expected_order_directions, input_ordering, fd_item_set, equal_sets, const_exprs, exec_ref_exprs, is_at_most_one_row, need_sort, prefix_pos))) { LOG_WARN("failed to check need sort", K(ret)); } else if (need_sort && part_cnt > 0) { // partition sort does not support prefix_pos, so if part_cnt is greater than 0, prefix_pos is always 0 prefix_pos = 0; if (input_ordering.count() > 1 && input_ordering.at(0).expr_->get_expr_type() == T_FUN_SYS_HASH && part_cnt == input_ordering.at(0).expr_->get_children_count()) { int64_t tmp_prefix_pos = 0; common::ObSEArray ordering; for (int64_t i = 1; OB_SUCC(ret) && i < input_ordering.count(); ++i) { if (OB_FAIL(ordering.push_back(input_ordering.at(i)))) { LOG_WARN("failed to add order item", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObOptimizerUtil::check_need_sort(expected_order_exprs, expected_order_directions, ordering, fd_item_set, equal_sets, const_exprs, exec_ref_exprs, is_at_most_one_row, need_sort, tmp_prefix_pos))) { LOG_WARN("failed to check need sort", K(ret)); } } } return ret; } /** * 假定下层序是 input_ordering,检查是否需要为 expected_order_exprs 分配 sort * (排序方向由 expected_order_directions 指定) * 当 input_ordering 能够决定 expected_order_exprs、expected_order_directions 序时不需要再分配 sort: * 1. expected_order_exprs 是 input_ordering 的前缀 * 例如:expected_order_exprs: a,b * input_ordering: a,b,c * 2. expected_order_exprs 与 input_ordering 公共前缀能决定其他expr * 例如:expected_order_exprs: a,b,e * input_ordering: a,b,c * 其中 a,b function dependence c * 这里有一种特殊情况 * expected_order_exprs: e,f,g * input_ordering: a,b,c * 两者没有公共前缀(i.e. right_match_count = 0) * 但假如有一组常量表达式是唯一的。那也不需要排序。 * 常量+唯一意味着只有一行 * 3. 使用函数依赖关系后能够找到公共前缀满足1、2 * 例如:expected_order_exprs: a,f,b * input_ordering: a,b,c * 其中 a,b function dependence c, a function dependence f **/ 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 ObIArray &exec_ref_exprs, const bool is_at_most_one_row, bool &need_sort, int64_t &prefix_pos) { int ret = OB_SUCCESS; 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; 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; need_sort = true; prefix_pos = 0; if (is_at_most_one_row) { need_sort = false; } else { ObBitSet<> left_set; ObBitSet<> right_set; ObBitSet<> used_fd; 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)); } //r_idx < right_count、l_idx == left_count 时仍可对 expected_order_exprs 进行检查 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, exec_ref_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, exec_ref_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 (OB_FAIL(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; prefix_pos = r_idx; } 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; } // try use input ordering // a. if use all input ordering, need not sort // b. if use no input ordering, create merge key use interesting ordering, need sort // c. if use some input ordering, need check need sort int ObOptimizerUtil::decide_sort_keys_for_merge_style_op(const ObDMLStmt *stmt, const EqualSets &stmt_equal_sets, const ObIArray &input_ordering, const ObFdItemSet &fd_item_set, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_exprs, const bool is_at_most_one_row, const ObIArray &merge_exprs, const ObIArray &default_directions, MergeKeyInfo &merge_key, MergeKeyInfo *&interesting_key) { int ret = OB_SUCCESS; int64_t prefix_count = -1; bool input_ordering_all_used = false; ObSEArray order_items; ObSEArray final_items; 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(default_directions))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::adjust_exprs_by_ordering(merge_key.order_exprs_, input_ordering, equal_sets, const_exprs, exec_ref_exprs, prefix_count, input_ordering_all_used, merge_key.order_directions_, &merge_key.map_array_))) { LOG_WARN("failed to adjust expr by ordering", K(ret)); } else if (prefix_count > 0 || input_ordering_all_used || NULL == interesting_key) { if (!input_ordering_all_used && prefix_count <= 0 && OB_FAIL(create_interesting_merge_key(stmt, merge_exprs, stmt_equal_sets, merge_key))) { LOG_WARN("failed to create interesting key", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::make_sort_keys(merge_key.order_exprs_, merge_key.order_directions_, order_items))) { LOG_WARN("failed to make sort keys", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::simplify_ordered_exprs(fd_item_set, equal_sets, const_exprs, exec_ref_exprs, order_items, final_items))) { LOG_WARN("failed to simply ordered exprs", K(ret)); } else if (OB_FAIL(merge_key.order_items_.assign(final_items))) { LOG_WARN("failed to assign final items", K(ret)); } else if (input_ordering_all_used) { merge_key.need_sort_ = false; } else if (OB_FAIL(ObOptimizerUtil::check_need_sort(merge_key.order_items_, input_ordering, fd_item_set, equal_sets, const_exprs, exec_ref_exprs, is_at_most_one_row, merge_key.need_sort_, merge_key.prefix_pos_))) { LOG_WARN("failed to check need sort", K(ret)); } else if (prefix_count > 0) { /*do nothing*/ } else { interesting_key = &merge_key; } } else if (OB_FAIL(merge_key.assign(*interesting_key))) { LOG_WARN("failed to assign merge key", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::create_interesting_merge_key(const ObDMLStmt *stmt, const ObIArray &merge_exprs, const EqualSets &equal_sets, MergeKeyInfo &merge_key) { int ret = OB_SUCCESS; ObSEArray sort_exprs; ObSEArray directions; ObSEArray sort_map; bool is_find = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt)); } else if (stmt->is_select_stmt()) { // find direction in window function exprs const ObSelectStmt *select_stmt = static_cast(stmt); for (int64_t i = 0; OB_SUCC(ret) && sort_exprs.empty() && 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 if (win_expr->get_order_items().empty()) { /* do nothing */ } else if (OB_FAIL(create_interesting_merge_key(merge_exprs, win_expr->get_order_items(), equal_sets, sort_exprs, directions, sort_map))) { LOG_WARN("failed to create interesting key", K(ret)); } } LOG_TRACE("succeed to create merge key use order by items in window function exprs", K(sort_exprs), K(directions)); } if (OB_SUCC(ret) && sort_exprs.empty() && !stmt->get_order_items().empty()) { // find direction in order by exprs if (OB_FAIL(create_interesting_merge_key(merge_exprs, stmt->get_order_items(), equal_sets, sort_exprs, directions, sort_map))) { LOG_WARN("failed to create interesting key", K(ret)); } else { LOG_TRACE("succeed to create merge key use order by items", K(sort_exprs), K(directions)); } } if (OB_SUCC(ret) && sort_exprs.empty()) { for (int64_t i = 0; OB_SUCC(ret) && i < merge_exprs.count(); ++i) { if (OB_FAIL(sort_exprs.push_back(merge_exprs.at(i)))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(directions.push_back(default_asc_direction()))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(sort_map.push_back(i))) { LOG_WARN("failed to push back", K(ret)); } } } if (OB_FAIL(ret)) { } else if (OB_FAIL(merge_key.order_exprs_.assign(sort_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(merge_key.order_directions_.assign(directions))) { LOG_WARN("failed to assign exprs", K(ret)); } else if (OB_FAIL(merge_key.map_array_.assign(sort_map))) { LOG_WARN("failed to assign exprs", K(ret)); } return ret; } int ObOptimizerUtil::create_interesting_merge_key(const ObIArray &merge_exprs, const ObIArray &expect_key, const EqualSets &equal_sets, ObIArray &sort_exprs, ObIArray &directions, ObIArray &sort_map) { int ret = OB_SUCCESS; int64_t index = OB_INVALID_INDEX; if (OB_UNLIKELY(expect_key.empty() || merge_exprs.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected input", K(ret), K(expect_key), K(merge_exprs)); } else if (!ObOptimizerUtil::find_equal_expr(merge_exprs, expect_key.at(0).expr_, equal_sets, index)) { /* do nothing */ } else if (OB_UNLIKELY(index < 0 || index >= merge_exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected index", K(ret), K(index), K(merge_exprs.count())); } else if (OB_FAIL(sort_exprs.push_back(merge_exprs.at(index)))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(directions.push_back(expect_key.at(0).order_type_))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(sort_map.push_back(index))) { LOG_WARN("failed to push back", K(ret)); } else { ObSqlBitSet<> found_bs; bool found_key = true; bool found_join_expr = false; if (OB_FAIL(found_bs.add_member(index))) { LOG_WARN("failed to add member", K(ret)); } for (int64_t i = 1; OB_SUCC(ret) && found_key && i < expect_key.count(); ++i) { found_join_expr = false; for (int64_t j = 0; OB_SUCC(ret) && !found_join_expr && j < merge_exprs.count(); ++j) { if (found_bs.has_member(j)) { /* do nothing */ } else if (!ObOptimizerUtil::is_expr_equivalent(expect_key.at(i).expr_, merge_exprs.at(j), equal_sets)) { /* do nothing */ } else if (OB_FAIL(found_bs.add_member(j))) { LOG_WARN("failed to add member", K(ret)); } else if (OB_FAIL(sort_exprs.push_back(merge_exprs.at(j)))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(directions.push_back(expect_key.at(i).order_type_))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(sort_map.push_back(j))) { LOG_WARN("failed to push back", K(ret)); } else { found_join_expr = true; } } if (OB_SUCC(ret) && !found_join_expr) { found_key = false; } } for (int64_t i = 0; OB_SUCC(ret) && i < merge_exprs.count(); ++i) { if (found_bs.has_member(i)) { /* do nothing */ } else if (OB_FAIL(sort_exprs.push_back(merge_exprs.at(i)))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(directions.push_back(default_asc_direction()))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(sort_map.push_back(i))) { LOG_WARN("failed to push back", K(ret)); } } } 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->is_static_const_expr() && (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->is_static_const_expr() && 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 rotate 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, ObRawExpr *zero_expr, bool &offset_is_not_neg, ObTransformerCtx *ctx) { int ret = OB_SUCCESS; if (OB_ISNULL(const_expr) || OB_ISNULL(session_info) || OB_ISNULL(ctx) || OB_ISNULL(zero_expr) || 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(ObTransformUtils::compare_const_expr_result(ctx, const_expr, T_OP_GE, 0, offset_is_not_neg))) { LOG_WARN("offset value is negative calc failed", K(ret)); } else if (!offset_is_not_neg) { offset_int_expr = zero_expr; } else 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(ObTransformUtils::compare_const_expr_result(ctx, const_expr, T_OP_GE, 0, offset_is_not_neg))) { LOG_WARN("offset value is negative calc failed", K(ret)); } else if (!offset_is_not_neg) { offset_int_expr = zero_expr; } else 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)) { // 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)) { // 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()) { // and expr 中要求至少有一个子expr只涉及到该表的列 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)) { //do nothing } else if (!table_ids.is_superset(cur_and_expr->get_relation_ids())) { //do nothing } else if (cur_and_expr->get_relation_ids().is_empty() && !cur_and_expr->is_const_expr()) { //do nothing } else if (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)) { all_contain = false; } else if (!table_ids.is_superset(cur_expr->get_relation_ids())) { all_contain = false; } else if (cur_expr->get_relation_ids().is_empty() && !cur_expr->is_const_expr()) { 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(); // 在原or expr的子expr上只有一个expr符合条件,直接加入到or expr中即可 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 { // 在原or expr的子expr上有多个expr符合条件,需要生成一个新的and expr 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())) { 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())) { LOG_WARN("failed to pull relation id and levels", K(ret)); } return ret; } /** * @brief ObOptimizerUtil::simplify_exprs * 给定一组 candi_exprs,该函数要找一个最小子集 root_exprs 能够唯一确定所有的 candi_exprs * 1. 尝试从candi exprs中找到一个拥有最小parent set的unique fd item, 如果找到了则root exprs = parent set * 2. 如未找到匹配的unique fd item, 则遍历not unique fd item, 对于parent set在candi exprs中的, * (a) 检查fd item能否决定candi exprs中未匹配的expr * (b) 检查fd item能够决定root exprs中的expr * (c)如果满足(a), 或者fd item parent set的数量小于该 fd item能够决定的root exprs的数量, 则消除root exprs * 中能被决定的root expr, 并添加新的root expr */ int ObOptimizerUtil::simplify_exprs(const ObFdItemSet &fd_item_set, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &candi_exprs, ObIArray &root_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(); // 将 fd item 分为unique的和非unique的 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)); } } // 尝试找到一个parent set数量最少的unique fd item 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(); } } } // 找到一个unique fd item, 直接从candi exprs里找出匹配parent set的expr 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 */ } } } // 没有找到unique fd item, 尝试遍历non unique fd items找到一个最小的root expr集合 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 left_domain; ObSEArray right_domain; int64_t expr_idx = -1; // 生成新的root exprs集合 for (int64_t j = 0; OB_SUCC(ret) && j < root_exprs.count(); ++j) { if (OB_FAIL(left_domain.push_back(root_exprs.at(j)))) { LOG_WARN("failed to push back root expr", K(ret)); } else 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) { // root expr可以被其它expr决定 } else if (OB_FAIL(right_domain.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(right_domain.push_back(candi_exprs.at(expr_idx)))) { LOG_WARN("failed to push back root expr", K(ret)); } else if (eliminate_set.has_member(expr_idx)) { // do nothing } else if (OB_FAIL(left_domain.push_back(candi_exprs.at(expr_idx)))) { LOG_WARN("failed to push back root expr", K(ret)); } } } // 检查当前fd item能否消除新的candi expr 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)); } } // 如果当前fd item消除了新的candi expr或者新的root expr集合比旧的root expr集合数量更少, 则用 // 新的root expr集合替换旧的 if (OB_SUCC(ret)) { ObIArray &new_root_exprs = left_domain.count() <= right_domain.count() ? left_domain : right_domain; if (OB_FAIL(root_exprs.assign(new_root_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } } } } // 所有non unique fd item都遍历过了, 但是还有其它无法被决定的expr, 直接加入到root exprs中 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)); } } } } if (OB_SUCC(ret)) { LOG_TRACE("succeed to simply exprs", K(fd_item_set), K(equal_sets), K(const_exprs), K(candi_exprs), K(root_exprs)); } return ret; } int ObOptimizerUtil::simplify_ordered_exprs(const ObFdItemSet &fd_item_set, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_exprs, const ObIArray &candi_items, ObIArray &order_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, exec_ref_exprs, candi_exprs, order_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; } /** * @brief ObOptimizerUtil::simplify_ordered_exprs * 对给定 candi_exprs, 该函数要找 order_exprs 使得按其排序时等价于 candi_exprs: * 1. 顺序读取 candi_exprs 一个元素 expr, 非 const 且未被标记移除时添加到 order_exprs; * 2. 获取 fd_item_set 中 parent exprs 为 order_exprs 子集的 fd_items; * 3. 标记当前 expr 之后存在于 fd_items child exprs 中的 expr 为待移除; * 4. 返回 1. 继续读取 candi_exprs 并添加得到完整 order_exprs. */ int ObOptimizerUtil::simplify_ordered_exprs(const ObFdItemSet &fd_item_set, const EqualSets &equal_sets, const ObIArray &const_exprs, const ObIArray &exec_ref_exprs, const ObIArray &candi_exprs, ObIArray &order_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; ObRawExpr *first_removed_expr = NULL; 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 (OB_FAIL(is_const_or_equivalent_expr(candi_exprs, equal_sets, const_exprs, exec_ref_exprs, i, is_const))) { LOG_WARN("failed to check is const expr", K(ret)); } else if (is_const) {//const expr 不需要排序 /*do nothing*/ } else if (eliminate_set.has_member(i)) { first_removed_expr = NULL == first_removed_expr ? expr : first_removed_expr; } 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 { //查找目前 extended_order_exprs 中包含的 fd, 并使用 fd 查找并标记 candi_exprs i 位置后需要移除的expr 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)) {//对于已经进行检查的 fd 不再重复检查 /*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) { /*do nothing*/ } else if (candi_exprs.at(j)->has_flag(CNT_SUB_QUERY)) { /* to check output more than one row, do not remove subquery in order expr. */ } else if (OB_FAIL(eliminate_set.add_member(j))) { LOG_WARN("failed to add member", K(ret)); } } if (OB_FAIL(ret)) { /*do nothing*/ } else if (OB_FAIL(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)); } } } } } } if (OB_FAIL(ret) && order_exprs.empty() && NULL != first_removed_expr && OB_FAIL(order_exprs.push_back(first_removed_expr))) { LOG_WARN("failed to push back 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::get_subplan_const_column(const ObDMLStmt &parent_stmt, const uint64_t table_id, const ObSelectStmt &child_stmt, const ObIArray &exec_ref_exprs, ObIArray &output_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < child_stmt.get_select_item_size(); ++i) { const ObRawExpr *expr = child_stmt.get_select_item(i).expr_; ObRawExpr *parent_expr = NULL; bool is_const = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret), K(expr)); } else if (OB_FAIL(is_const_expr_recursively(expr, exec_ref_exprs, is_const))) { LOG_WARN("failed to check expr is const expr", K(ret)); } else if (!is_const) { // do nothing } else if (NULL == (parent_expr = parent_stmt.get_column_expr_by_id(table_id, OB_APP_MIN_COLUMN_ID + i))) { // parent expr is prunned } else if (OB_FAIL(add_var_to_array_no_dup(output_exprs, parent_expr))) { LOG_WARN("failed to add parent expr into output", K(ret)); } } return ret; } int ObOptimizerUtil::convert_subplan_scan_expr(ObRawExprFactory &expr_factory, const EqualSets &equal_sets, const uint64_t table_id, const 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; ObRawExprCopier copier(expr_factory); 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(copier, 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; } class ReplaceSubplanScanExpr : public ObIRawExprReplacer { public: ReplaceSubplanScanExpr(const EqualSets &eset, const uint64_t table_id, const ObDMLStmt &parent, const ObSelectStmt &child) : equal_sets_(eset), table_id_(table_id), parent_stmt_(parent), child_stmt_(child) {} virtual int generate_new_expr(ObRawExprFactory &expr_factory, ObRawExpr *old_expr, ObRawExpr *&new_expr) { int ret = OB_SUCCESS; UNUSED(expr_factory); new_expr = NULL; if (old_expr->is_const_or_param_expr()) { new_expr = old_expr; } else if (OB_FAIL(ObOptimizerUtil::get_parent_stmt_expr(equal_sets_, table_id_, parent_stmt_, child_stmt_, old_expr, new_expr))) { LOG_WARN("failed to get parent stmt expr", K(ret)); } else { // does not replace the old_expr, iterate its child expr } return ret; } private: const EqualSets &equal_sets_; const uint64_t table_id_; const ObDMLStmt &parent_stmt_; const ObSelectStmt &child_stmt_; }; int ObOptimizerUtil::convert_subplan_scan_expr(ObRawExprCopier &copier, const EqualSets &equal_sets, const uint64_t table_id, const ObDMLStmt &parent_stmt, const ObSelectStmt &child_stmt, ObRawExpr *input_expr, ObRawExpr *&output_expr) { int ret = OB_SUCCESS; bool is_valid = true; output_expr = NULL; ReplaceSubplanScanExpr replacer(equal_sets, table_id, parent_stmt, child_stmt); 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) { // do nothing } else if (OB_FAIL(copier.copy_on_replace(input_expr, output_expr, &replacer))) { LOG_WARN("failed to copy and replace expr", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::check_subplan_scan_expr_validity(const EqualSets &equal_sets, const uint64_t table_id, const ObDMLStmt &parent_stmt, const ObSelectStmt &child_stmt, const ObRawExpr *input_expr, bool &is_valid) { int ret = OB_SUCCESS; ObRawExpr *parent_expr = NULL; is_valid = false; if (OB_ISNULL(input_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", 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_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, const 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::get_parent_stmt_exprs(const EqualSets &equal_sets, const uint64_t table_id, const ObDMLStmt &parent_stmt, const ObSelectStmt &child_stmt, const ObIArray &child_exprs, ObIArray &parent_exprs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < child_exprs.count(); i++) { ObRawExpr *parent_expr = NULL; if (OB_FAIL(get_parent_stmt_expr(equal_sets, table_id, parent_stmt, child_stmt, child_exprs.at(i), parent_expr))) { LOG_WARN("get parent stmt expr failed", K(ret)); } else if (OB_FAIL(parent_exprs.push_back(parent_expr))) { LOG_WARN("push back expr failed", K(ret)); } } 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 bool is_parent_set_distinct, 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; //group by 是否匹配索引前缀 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) { //没有group并且窗口函数不需要排序的情况下,看distinct和 order by 和 set 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) { //没有distinct的情况下才看 set(union/interscept) prefix_count = 0; if (NULL != 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)) { 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::compute_stmt_interesting_order(const ObIArray &ordering, const ObDMLStmt *stmt, const bool in_subplan_scan, EqualSets &equal_sets, const ObIArray &const_exprs, const bool is_parent_set_distinct, const int64_t check_scope, int64_t &match_info) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (check_scope == OrderingCheckScope::NOT_CHECK || ordering.empty()) { // do nothing } else { 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 is_match = false; ObSEArray ordering_exprs; ObSEArray ordering_directions; 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 (OB_FAIL(split_expr_direction(ordering, ordering_exprs, ordering_directions))) { LOG_WARN("failed to split expr direction", K(ret)); } else if (has_group && check_group) { if (select_stmt->get_group_expr_size() > 0) { if (OB_FAIL(prefix_subset_exprs(select_stmt->get_group_exprs(), ordering_exprs, equal_sets, const_exprs, is_match))) { LOG_WARN("check is covered by ordering failed", K(ret)); } } else if (select_stmt->get_rollup_expr_size() > 0) { if (OB_FAIL(prefix_subset_exprs(select_stmt->get_rollup_exprs(), ordering_exprs, equal_sets, const_exprs, is_match))) { LOG_WARN("check is covered by ordering failed", K(ret)); } } if (OB_SUCC(ret) && is_match) { match_info |= OrderingFlag::GROUP_MATCH; LOG_TRACE("ordering is math group by"); } } else if (has_winfunc && check_winfunc) { bool winfunc_require_sort = false; if (OB_FAIL(is_winfunc_match(ordering, select_stmt, equal_sets, const_exprs, is_match))) { LOG_WARN("failed to check is winfunc match", K(ret)); } else if (is_match) { match_info |= OrderingFlag::WINFUNC_MATCH; LOG_TRACE("ordering is match window function"); } } else if (has_distinct && check_distinct) { ObSEArray select_exprs; if (OB_FAIL(select_stmt->get_select_exprs(select_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else if (OB_FAIL(prefix_subset_exprs(select_exprs, ordering_exprs, equal_sets, const_exprs, is_match))) { LOG_WARN("check is covered by ordering failed", K(ret)); } else if (is_match) { match_info |= OrderingFlag::DISTINCT_MATCH; LOG_TRACE("ordering is math distinct"); } } else if (check_set && NULL != select_stmt && is_parent_set_distinct) { ObSEArray select_exprs; if (OB_FAIL(select_stmt->get_select_exprs(select_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else if (OB_FAIL(prefix_subset_exprs(select_exprs, ordering_exprs, equal_sets, const_exprs, is_match))) { LOG_WARN("check is covered by ordering failed", K(ret)); } else if (is_match) { match_info |= OrderingFlag::SET_MATCH; LOG_TRACE("ordering is match set"); } } else if (has_orderby && check_order) { if (OB_FAIL(is_order_by_match(stmt->get_order_items(), ordering, equal_sets, const_exprs, is_match))) { LOG_WARN("failed to check is order by match", K(ret)); } else if (is_match) { match_info |= OrderingFlag::ORDERBY_MATCH; LOG_TRACE("ordering is math order by"); } } else if (in_subplan_scan) { 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, bool &is_match) { int ret = OB_SUCCESS; is_match = false; ObSEArray ordering_exprs; ObSEArray ordering_directions; const ObWinFunRawExpr *win_expr = NULL; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select_stmt is null", 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)); } for (int64_t i = 0; OB_SUCC(ret) && !is_match && i < select_stmt->get_window_func_count(); ++i) { if (OB_ISNULL(win_expr = select_stmt->get_window_func_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(win_expr)); } else if (!win_expr->get_partition_exprs().empty()) { if (OB_FAIL(prefix_subset_exprs(win_expr->get_partition_exprs(), ordering_exprs, equal_sets, const_exprs, is_match))) { LOG_WARN("check is covered by ordering failed", K(ret)); } } else if (OB_FAIL(is_order_by_match(win_expr->get_order_items(), ordering, equal_sets, const_exprs, is_match))) { LOG_WARN("failed to check is winfunc match", K(ret)); } } return ret; } int ObOptimizerUtil::is_order_by_match(const ObIArray &expect_ordering, const ObIArray &input_ordering, const EqualSets &equal_sets, const ObIArray &const_exprs, bool &is_match) { int ret = OB_SUCCESS; is_match = false; ObRawExpr *input_expr = NULL; ObRawExpr *expect_expr = NULL; int64_t expect_offset = 0; int64_t input_offset = 0; bool direction_match = false; bool is_const = false; bool finish_check = false; while (OB_SUCC(ret) && !is_match && !finish_check && input_offset < input_ordering.count() && expect_offset < expect_ordering.count()) { direction_match = is_ascending_direction(expect_ordering.at(expect_offset).order_type_) == is_ascending_direction(input_ordering.at(input_offset).order_type_); 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) { is_match = true; } 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 { finish_check = true; } } 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; //找到第一个非const的order项 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; } } //计算index和order项的最大匹配,跳过const表达式 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_conv(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_COLUMN_CONV != expr->get_expr_type()) { // do nothing } else if (OB_ISNULL(child_expr = expr->get_param_expr(4))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { is_lossless = is_lossless_type_conv(child_expr->get_result_type(), expr->get_result_type()); } return ret; } bool ObOptimizerUtil::is_lossless_type_conv(const ObExprResType &child_type, const ObExprResType &dst_type) { bool is_lossless = false; ObObjTypeClass child_tc = child_type.get_type_class(); ObObjTypeClass dst_tc = dst_type.get_type_class(); ObAccuracy dst_acc = dst_type.get_accuracy(); if (child_type.get_type() == dst_type.get_type() && (child_type.get_accuracy().get_precision() == dst_acc.get_precision() || -1 == dst_acc.get_precision()) && (child_type.get_accuracy().get_scale() == dst_acc.get_scale() || -1 == dst_acc.get_scale())) { if (is_oracle_mode() && ObNumberTC == dst_tc && child_type.get_accuracy().get_scale() != child_type.get_accuracy().get_scale()) { //TODO: need to be supplemented for the conversion from number to number } else if (ob_is_string_type(child_type.get_type())) { if (dst_type.get_obj_meta().get_collation_type() == child_type.get_obj_meta().get_collation_type() && (child_type.get_accuracy().get_length() <= dst_acc.get_length() || -1 == dst_acc.get_length())) { is_lossless = true; } } else if (ob_is_numeric_type(child_type.get_type()) || ob_is_temporal_type(child_type.get_type()) || ob_is_otimestampe_tc(child_type.get_type())) { is_lossless = true; } } if (is_lossless) { //do nothing } else if (!is_oracle_mode()) { // mysql模式允许的无损类型转换可以参考 if (ObIntTC == child_tc || ObUIntTC == child_tc || ObNumberTC == child_tc) { if (child_type.get_type() == dst_type.get_type() && ObNumberTC != child_tc) { is_lossless = true; } else if (ObNumberTC == dst_tc) { ObAccuracy lossless_acc = child_type.get_accuracy(); if ((dst_acc.get_scale() >= 0 && dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision()) || (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale())) { is_lossless = true; } } } else if (ObFloatTC == child_tc || ObDoubleTC == child_tc) { if (child_tc == dst_tc || ObDoubleTC == dst_tc) { ObAccuracy lossless_acc = child_type.get_accuracy(); if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { is_lossless = true; } else if (dst_acc.get_precision() >= lossless_acc.get_precision() && dst_acc.get_scale() >= lossless_acc.get_scale()) { is_lossless = true; } } } else if (ObTimestampType == child_type.get_type() || ObDateTimeType == child_type.get_type()) { if (ObDateTimeType == dst_type.get_type() || ObTimestampType == dst_type.get_type()) { if (child_type.get_accuracy().get_precision() == dst_acc.get_precision() && child_type.get_accuracy().get_scale() == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObDateTC == child_tc || ObTimeTC == child_tc) { if (child_tc == dst_tc || 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 == child_tc) { if (ObNumberTC == dst_tc) { ObAccuracy lossless_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[ObCompatibilityMode::MYSQL_MODE][child_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 (child_tc == dst_tc) { is_lossless = true; } // varchar, varbinnary } else if (ObCharType == child_type.get_type() || ObVarcharType == child_type.get_type()) { //in mysql c1 varchar(x) as (func(y)) can not insert data makes length(fun(y)) > x if (child_type.get_type() == dst_type.get_type() && dst_type.get_obj_meta().get_collation_type() == child_type.get_obj_meta().get_collation_type()) { is_lossless = true; } } } else { if (ObIntTC == child_tc || ObUIntTC == child_tc) { //TODO: need to be supplemented for the conversion from number to number if (child_tc == dst_tc || ObNumberTC == dst_tc) { ObAccuracy lossless_acc = child_type.get_accuracy(); if ((dst_acc.get_scale() >= 0 && dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision()) || (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) || (-1 == dst_acc.get_precision() && -85 == dst_acc.get_scale())) { is_lossless = true; } } } else if (ObCharType == child_type.get_type() || ObVarcharType == child_type.get_type() || ObNCharType == child_type.get_type() || ObNVarchar2Type == child_type.get_type()) { //in oracle creating table ... c1 varchar(x) as (func(y)) will ensure that x>=length(y); if (child_type.get_type() == dst_type.get_type() && dst_type.get_obj_meta().get_collation_type() == child_type.get_obj_meta().get_collation_type()) { is_lossless = true; } } } return is_lossless; } 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 { ObExprResType child_type = child_expr->get_result_type(); ObObjTypeClass child_tc = child_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()) { // mysql模式允许的无损类型转换可以参考 if (ObIntTC == child_tc || ObUIntTC == child_tc) { if (ObNumberTC == dst_tc) { // ObAccuracy lossless_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[ObCompatibilityMode::MYSQL_MODE][child_type.get_type()]; ObAccuracy lossless_acc = child_type.get_accuracy(); if ((dst_acc.get_scale() >= 0 && dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision()) || (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale())) { is_lossless = true; } } else if (child_tc == dst_tc) { is_lossless = true; } } else if (ObBitTC == child_tc) { if (ObNumberTC == dst_tc) { const double log10_2 = 0.30103; ObAccuracy lossless_acc = child_type.get_accuracy(); if (dst_acc.get_scale() >= 0 && dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision() * log10_2) { // log10(2) = 0.30102999566398114; log10(2^n) = n*log10(2); // cast(b'111' as decimal(1,0)) is lossless is_lossless = true; } } } else if (ObFloatTC == child_tc || ObDoubleTC == child_tc) { if (child_tc == dst_tc) { ObAccuracy lossless_acc = child_type.get_accuracy(); if (lossless_acc.get_scale() == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObDateTimeType == child_type.get_type()) { // do nothing } else if (ObTimestampType == child_type.get_type()) { if (child_tc == dst_tc || ObDateTimeType == dst_type.get_type()) { if (child_type.get_accuracy().get_precision() == dst_acc.get_precision() && child_type.get_accuracy().get_scale() == dst_acc.get_scale()) { is_lossless = true; } } } else if (ObDateTC == child_tc || ObTimeTC == child_tc) { if (child_tc == dst_tc || 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 == child_tc) { if (ObNumberTC == dst_tc) { ObAccuracy lossless_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[ObCompatibilityMode::MYSQL_MODE][child_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 == child_type.get_type()) { // varchar, varbinnary } else if (ObCharType == child_type.get_type()) { if (child_tc == dst_tc || ObVarcharType == dst_type.get_type()) { if (dst_acc.get_length() == child_type.get_accuracy().get_length() && dst_type.get_obj_meta().get_collation_type() == child_type.get_obj_meta().get_collation_type()) { is_lossless = true; } } } } else { if (ObIntTC == child_tc || ObUIntTC == child_tc) { //TODO: need to be supplemented for the conversion from number to number if (child_tc == dst_tc || ObNumberTC == dst_tc) { ObAccuracy lossless_acc = child_type.get_accuracy(); if ((dst_acc.get_scale() >= 0 && dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision()) || (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale())) { is_lossless = true; } } } } } return ret; } int ObOptimizerUtil::get_expr_without_lossless_cast(const ObRawExpr* ori_expr, const ObRawExpr*& expr) { int ret = OB_SUCCESS; bool is_lossless = false; expr = ori_expr; if (OB_ISNULL(ori_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(is_lossless_column_cast(ori_expr, is_lossless))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } else if (is_lossless) { expr = ori_expr->get_param_expr(0); } return ret; } int ObOptimizerUtil::get_expr_without_lossless_cast(ObRawExpr* ori_expr, ObRawExpr*& expr) { int ret = OB_SUCCESS; bool is_lossless = false; expr = ori_expr; if (OB_ISNULL(ori_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(is_lossless_column_cast(ori_expr, is_lossless))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } else if (is_lossless) { expr = ori_expr->get_param_expr(0); } 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, const bool is_mysql_recursive_union /* false */, ObIArray *rcte_col_name /* null */) { 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, is_mysql_recursive_union, rcte_col_name))) { 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, const bool is_mysql_recursive_union /* false */, ObIArray *rcte_col_name /* null */) { 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, is_mysql_recursive_union, rcte_col_name))) { 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.is_real_alias_ = select_item.is_real_alias_ || ObRawExprUtils::is_column_ref_skip_implicit_cast(select_item.expr_); 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_)); } } } return ret; } // link.zt why this function has two very similar versions 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.is_real_alias_ = select_item.is_real_alias_ || ObRawExprUtils::is_column_ref_skip_implicit_cast(select_item.expr_); 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_)); } } } } 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(); ObSelectStmt *cur_stmt = NULL; bool is_all_not_null = true; bool is_on_null_side = false; ObColumnRefRawExpr *col_expr = NULL; ObRawExpr *expr = NULL; for (int64_t idx = 0; OB_SUCC(ret) && idx < select_num; ++idx) { types.reuse(); is_all_not_null = true; res_type.unset_result_flag(NOT_NULL_FLAG); for (int64_t i = 0; OB_SUCC(ret) && i < child_num; ++i) { if (OB_ISNULL(cur_stmt = child_querys.at(i)) || OB_UNLIKELY(idx >= cur_stmt->get_select_item_size()) || OB_ISNULL(expr = cur_stmt->get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected child stmt", K(ret), K(cur_stmt), K(expr)); } else if (OB_FAIL(add_var_to_array_no_dup(types, expr->get_result_type()))) { LOG_WARN("failed to add var", K(ret), K(expr->get_result_type())); } else if (!is_all_not_null) { /* do nothing */ } else if (!expr->is_column_ref_expr()) { is_all_not_null = false; } else if (OB_FALSE_IT(col_expr = static_cast(expr))) { } else if (!col_expr->get_result_type().has_result_flag(NOT_NULL_FLAG)) { is_all_not_null = false; } else if (NULL == cur_stmt->get_table_item_by_id(col_expr->get_table_id())) { // column expr from upper stmt, ignore NOT NULL FLAG is_all_not_null = false; } else if (OB_FAIL(ObOptimizerUtil::is_table_on_null_side(cur_stmt, col_expr->get_table_id(), is_on_null_side))) { LOG_WARN("check is table on null side failed", K(ret)); } else if (is_on_null_side) { 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(res_types.empty())); } else if (is_all_not_null) { res_types.at(res_types.count()-1).set_result_flag(NOT_NULL_FLAG); } else { res_types.at(res_types.count()-1).unset_result_flag(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, const bool is_mysql_recursive_union /* false */, ObIArray *rcte_col_name /* null */) { 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(NOT_NULL_FLAG) || !right_type.has_result_flag(NOT_NULL_FLAG)) { left_type.unset_result_flag(NOT_NULL_FLAG); right_type.unset_result_flag(NOT_NULL_FLAG); } if (left_type != right_type || ob_is_enumset_tc(right_type.get_type()) || is_mysql_recursive_union) { ObSEArray types; ObExprVersion dummy_op(*allocator); ObCollationType coll_type = CS_TYPE_INVALID; bool skip_add_cast = false; if (lib::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()) || (left_type.is_null() && (right_type.is_lob() || right_type.is_lob_locator()) && !is_distinct) || (right_type.is_null() && !left_type.is_lob() && !left_type.is_lob_locator()) || (right_type.is_null() && (left_type.is_lob() || left_type.is_lob_locator()) && !is_distinct) || (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()))) || (left_type.is_urowid() && right_type.is_urowid()) || (is_oracle_mode() && left_type.is_lob() && right_type.is_lob() && left_type.get_collation_type() == right_type.get_collation_type()) || (is_oracle_mode() && left_type.is_lob_locator() && right_type.is_lob_locator() && left_type.get_collation_type() == right_type.get_collation_type()) || (is_oracle_mode() && (ob_is_user_defined_sql_type(left_type.get_type()) || ob_is_user_defined_pl_type(left_type.get_type())) && (ob_is_user_defined_sql_type(right_type.get_type()) || ob_is_user_defined_pl_type(right_type.get_type()))))) { // || (left_type.is_lob() && right_type.is_lob() && !is_distinct))) { // Originally, cases like "select clob from t union all select blob from t" return error if (session_info->is_varparams_sql_prepare()) { skip_add_cast = true; LOG_WARN("ps prepare stage expression has different datatype", K(i), K(left_type), K(right_type)); } else { ret = OB_ERR_EXP_NEED_SAME_DATATYPE; LOG_WARN("expression must have same datatype as corresponding expression", K(ret), K(session_info->is_varparams_sql_prepare()), K(right_type.is_varchar_or_char()), 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 (is_mysql_recursive_union) { if (left_type.is_null()) { res_type.set_binary(); res_type.set_length(0); res_type.set_collation_level(CS_LEVEL_IMPLICIT); } else { res_type = left_type; } } else if (skip_add_cast) { res_type = left_type; } 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))) { if (session_info->is_varparams_sql_prepare()) { skip_add_cast = true; res_type = left_type; LOG_WARN("failed to deduce type in ps prepare stage", K(types)); } else { LOG_WARN("failed to aggregate result type for merge", K(ret)); } } if (OB_FAIL(ret) || skip_add_cast) { } 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 (!is_mysql_recursive_union && 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 (is_mysql_recursive_union && OB_FAIL(add_column_conv_to_set_list(session_info, expr_factory, right_stmts, res_type, i, rcte_col_name))) { LOG_WARN("failed to add column_conv to set list", K(ret)); } } else if (lib::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 if (lib::is_oracle_mode() && is_distinct && right_type.is_json()) { ret = OB_ERR_INVALID_CMP_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 *to_str_expr = NULL; if (src_expr->get_result_type() == res_type) { /*do nothing*/ } else if (OB_FAIL(ObRawExprUtils::create_type_to_str_expr(*expr_factory, src_expr, to_str_expr, session_info, true))) { LOG_WARN("create to str expr for stmt failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(expr_factory, session_info, *to_str_expr, res_type, new_expr))) { LOG_WARN("create cast expr for stmt failed", K(ret)); } 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; } } 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::add_column_conv_to_set_list(ObSQLSessionInfo *session_info, ObRawExprFactory *expr_factory, ObIArray &stmts, const ObExprResType &res_type, const int64_t idx, ObIArray *rcte_col_name) { 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_FAIL(ObRawExprUtils::build_column_conv_expr(session_info, *expr_factory, res_type.get_type(), res_type.get_collation_type(), res_type.get_accuracy().get_accuracy(), true, NULL != rcte_col_name ? &rcte_col_name->at(idx) : NULL, NULL, stmt->get_select_item(idx).expr_))) { LOG_WARN("failed to build column conv expr", K(ret)); } } return ret; } /** * check_subquery_has_ref_assign_user_var * 检查expr的子查询中是否包含涉及到赋值操作的用户变量 */ 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; const 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)) || OB_ISNULL(stmt = subquery->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(subquery), K(stmt)); } 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; } int ObOptimizerUtil::pushdown_filter_into_subquery(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, ObOptimizerContext &opt_ctx, ObIArray &pushdown_filters, ObIArray &candi_filters, ObIArray &remain_filters, bool &can_pushdown, bool check_match_index/* = true*/) { 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, check_match_index))) { 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() || subquery.is_unpivot_select() || subquery.is_dblink_stmt() || 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, check_match_index))) { LOG_WARN("failed to check pushdown filter", K(ret)); } else if (candi_filters.empty()) { //do thing } else { can_pushdown = true; } } if (OB_SUCC(ret)) { if (can_pushdown) { if (OB_FAIL(remove_special_exprs(candi_filters, remain_filters))) { LOG_WARN("failed to remove special exprs", K(ret)); } } else { if (OB_FAIL(remain_filters.assign(pushdown_filters))) { LOG_WARN("failed to assign exprs", K(ret)); } } } return ret; } int ObOptimizerUtil::check_pushdown_filter(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, ObOptimizerContext &opt_ctx, ObIArray &pushdown_filters, ObIArray &candi_filters, ObIArray &remain_filters, bool check_match_index/* = true*/) { int ret = OB_SUCCESS; bool is_valid = false; ObSEArray common_exprs; if (!parent_stmt.is_set_stmt() && subquery.is_set_stmt()) { //如果子查询是set stmt,只需要检查是否有下推的谓词overlap index if (check_match_index) { 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(candi_filters.assign(pushdown_filters))) { LOG_WARN("failed to assign exprs", 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(parent_stmt, subquery, opt_ctx, common_exprs, pushdown_filters, candi_filters, remain_filters, check_match_index))) { LOG_WARN("failed to check pushdown filter for subquery", K(ret)); } } return ret; } int ObOptimizerUtil::remove_special_exprs(ObIArray &pushdown_filters, ObIArray &remain_filters) { int ret = OB_SUCCESS; ObSEArray normal_filters; for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_filters.count(); ++i) { if (OB_ISNULL(pushdown_filters.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("predicate is null", K(ret)); } else if (ObPredicateDeduce::contain_special_expr(*pushdown_filters.at(i))) { if (OB_FAIL(remain_filters.push_back(pushdown_filters.at(i)))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (OB_FAIL(normal_filters.push_back(pushdown_filters.at(i)))) { LOG_WARN("failed to push back expr", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(pushdown_filters.assign(normal_filters))) { LOG_WARN("failed to assign filters", K(ret)); } return ret; } int ObOptimizerUtil::check_pushdown_filter_overlap_index(const 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) { if (OB_FAIL(candi_filters.assign(pushdown_filters))) { LOG_WARN("failed to assign exprs", K(ret)); } } else { if (OB_FAIL(remain_filters.assign(pushdown_filters))) { LOG_WARN("failed to assign exprs", K(ret)); } } return ret; } int ObOptimizerUtil::check_pushdown_filter_for_set(const ObSelectStmt &parent_stmt, const ObSelectStmt &subquery, ObIArray &common_exprs, ObIArray &pushdown_filters, ObIArray &candi_filters, ObIArray &remain_filters) { int ret = OB_SUCCESS; ObSEArray view_column_exprs; ObSEArray set_op_exprs; ObSEArray select_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_filters.count(); ++i) { ObRawExpr *pred = NULL; bool is_simple_expr = true; bool pushed = false; set_op_exprs.reuse(); select_exprs.reuse(); view_column_exprs.reuse(); 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_set_op_exprs(pred, set_op_exprs))) { LOG_WARN("failed to extract set op exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::check_pushdown_into_set_valid(pred, set_op_exprs, is_simple_expr))) { LOG_WARN("failed to check pushdown into set", K(ret)); } else if (!is_simple_expr) { // can not push down } else if (OB_FAIL(ObTransformUtils::convert_set_op_expr_to_select_expr(set_op_exprs, subquery, select_exprs))) { LOG_WARN("failed to convert set op exprs to select exprs", K(ret)); } else if (set_op_exprs.count() != select_exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect set op expr count", K(ret)); } 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 (ObPredicateDeduce::contain_special_expr(*expr)) { is_simple_expr = false; } else if (expr->has_flag(CNT_WINDOW_FUNC) || expr->has_flag(CNT_AGG) || expr->has_flag(CNT_SUB_QUERY) || expr->has_flag(CNT_ONETIME)) { is_simple_expr = false; } 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)) { //common_exprs为空,说明既没有windown func,也没有group by } else if (OB_FAIL(candi_filters.push_back(pred))) { LOG_WARN("failed to push back predicate", K(ret)); } else { pushed = true; } if (OB_SUCC(ret) && !pushed && OB_FAIL(remain_filters.push_back(pred))) { LOG_WARN("failed to push back expr", K(ret)); } } return ret; } int ObOptimizerUtil::check_pushdown_filter_for_subquery(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, ObOptimizerContext &opt_ctx, ObIArray &common_exprs, ObIArray &pushdown_filters, ObIArray &candi_filters, ObIArray &remain_filters, bool check_match_index/* = true*/) { int ret = OB_SUCCESS; if (parent_stmt.is_set_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect set stmt here", K(ret)); } else { //只要某一个能够下推的谓词match索引,那么所有可以下推的谓词都下推 //否则清空所有可以下推的谓词 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 (ObPredicateDeduce::contain_special_expr(*expr)) { is_simple_expr = false; } 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 (check_match_index && 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)) { //common_exprs为空,说明既没有windown func,也没有group by } 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 (check_match_index && !is_match_index) { candi_filters.reset(); ret = remain_filters.assign(pushdown_filters); } } return ret; } int ObOptimizerUtil::get_groupby_win_func_common_exprs(const 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 { //取所有win func的partition by表达式交集 for (int64_t i = 0; OB_SUCC(ret) && i < subquery.get_window_func_count(); ++i) { const 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; } } //再与group by表达式取交集 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; ObSEArray child_select_list; ObSEArray parent_set_exprs; ObRawExprCopier copier(expr_factory); 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_pure_set_exprs(parent_set_exprs))) { LOG_WARN("failed to get expr in cast", K(ret)); } else if (OB_FAIL(copier.add_replaced_expr(parent_set_exprs, child_select_list))) { LOG_WARN("failed to add exprs", 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; // Given a valid stmt, we only need to call the copy // Given a stmt in transformation, maybe there a column which should be renamed later if (OB_FAIL(copier.copy_on_replace(pred, 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())) { LOG_WARN("failed to pull relation id and levels", K(ret)); } else if (OB_FAIL(rename_filters.push_back(new_pred))) { LOG_WARN("failed to push back renamed filter", K(ret)); } } 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; ObRawExprCopier copier(expr_factory); 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)); } 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)); } } if (OB_SUCC(ret)) { // Given a valid stmt, we only need call copy here // Given a stmt in transformation, we need call copy_on_replace // Because some columns may belongs to the upper stmt, and can not // be renamed at the present, it should be renamed later if (OB_FAIL(copier.add_replaced_expr(view_column_list, view_select_list))) { LOG_WARN("failed to add exprs", K(ret)); } else if (OB_FAIL(copier.copy_on_replace(candi_filters, rename_filters))) { LOG_WARN("failed to copy on replace filters", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < rename_filters.count(); ++i) { if (OB_ISNULL(rename_filters.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else if (OB_FAIL(rename_filters.at(i)->formalize(session_info))) { LOG_WARN("failed to formalize expr", K(ret)); } else if (OB_FAIL(rename_filters.at(i)->pull_relation_id())) { LOG_WARN("failed to pull relation id and levels", K(ret)); } } 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 ParamStore *params, const ObDMLStmt *stmt, ObExecContext *exec_ctx, ObIAllocator &allocator, const ObRelIds &table_ids, const ObRawExpr* qual, bool &is_null_qual) { int ret = OB_SUCCESS; is_null_qual = false; const ObRawExpr *left_expr = NULL; const ObRawExpr *right_expr = NULL; ObObj result; bool got_result = false; 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( exec_ctx, right_expr, result, got_result, allocator))) { LOG_WARN("Failed to calc const or calculable expr", K(ret)); } else if (!got_result) { // do nothing } 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, 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 { has_subquery = exprs.at(i)->has_flag(CNT_SUB_QUERY) || exprs.at(i)->has_flag(CNT_ONETIME); } } 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::compute_ordering_relationship(const bool left_is_interesting, const bool right_is_interesting, const ObIArray &left_ordering, const ObIArray &right_ordering, const EqualSets &equal_sets, const ObIArray &condition_exprs, DominateRelation &relation) { int ret = OB_SUCCESS; bool is_left_prefix = false; bool is_right_prefix = false; relation = DominateRelation::OBJ_UNCOMPARABLE; if (!left_is_interesting && !right_is_interesting) { relation = DominateRelation::OBJ_EQUAL; } else if (left_is_interesting && !right_is_interesting) { relation = DominateRelation::OBJ_LEFT_DOMINATE; } else if (!left_is_interesting && right_is_interesting) { relation = DominateRelation::OBJ_RIGHT_DOMINATE; } else if (OB_FAIL(ObOptimizerUtil::is_prefix_ordering(left_ordering, right_ordering, equal_sets, condition_exprs, is_left_prefix, is_right_prefix))) { LOG_WARN("failed to compute prefix ordering relationship", K(left_ordering), K(right_ordering), K(ret)); } else if (is_left_prefix && is_right_prefix) { relation = DominateRelation::OBJ_EQUAL; } else if (is_left_prefix) { relation = DominateRelation::OBJ_RIGHT_DOMINATE; } else if (is_right_prefix) { relation = DominateRelation::OBJ_LEFT_DOMINATE; } else { relation = DominateRelation::OBJ_UNCOMPARABLE; } return ret; } int ObOptimizerUtil::compute_sharding_relationship(const ObShardingInfo *left_strong_sharding, const ObIArray &left_weak_sharding, const ObShardingInfo *right_strong_sharding, const ObIArray &right_weak_sharding, const EqualSets &equal_sets, DominateRelation &relation) { int ret = OB_SUCCESS; DominateRelation strong_relation; DominateRelation weak_relation; relation = DominateRelation::OBJ_UNCOMPARABLE; if (OB_FAIL(compute_sharding_relationship(left_strong_sharding, right_strong_sharding, equal_sets, strong_relation))) { LOG_WARN("failed to compute sharding relationship", K(ret)); } else if (OB_FAIL(compute_sharding_relationship(left_weak_sharding, right_weak_sharding, equal_sets, weak_relation))) { LOG_WARN("failed to compute sharding relationship", K(ret)); } else if (DominateRelation::OBJ_EQUAL == strong_relation && DominateRelation::OBJ_EQUAL == weak_relation) { relation = DominateRelation::OBJ_EQUAL; } else if ((DominateRelation::OBJ_EQUAL == strong_relation || DominateRelation::OBJ_LEFT_DOMINATE == strong_relation) && (DominateRelation::OBJ_EQUAL == weak_relation || DominateRelation::OBJ_LEFT_DOMINATE == weak_relation)) { relation = DominateRelation::OBJ_LEFT_DOMINATE; } else if ((DominateRelation::OBJ_EQUAL == strong_relation || DominateRelation::OBJ_RIGHT_DOMINATE == strong_relation) && (DominateRelation::OBJ_EQUAL == weak_relation || DominateRelation::OBJ_RIGHT_DOMINATE == weak_relation)) { relation = DominateRelation::OBJ_RIGHT_DOMINATE; } else { relation = DominateRelation::OBJ_UNCOMPARABLE; } return ret; } int ObOptimizerUtil::compute_sharding_relationship(const ObIArray &left_sharding, const ObIArray &right_sharding, const EqualSets &equal_sets, DominateRelation &relation) { int ret = OB_SUCCESS; bool is_left_dominate = false; bool is_right_dominate = false; relation = DominateRelation::OBJ_UNCOMPARABLE; if (OB_FAIL(check_sharding_set_left_dominate(left_sharding, right_sharding, equal_sets, is_left_dominate))) { LOG_WARN("failed to check left dominate relationship", K(ret)); } else if (OB_FAIL(check_sharding_set_left_dominate(right_sharding, left_sharding, equal_sets, is_right_dominate))) { LOG_WARN("failed to check left dominate relationship", K(ret)); } else if (is_left_dominate && is_right_dominate) { relation = DominateRelation::OBJ_EQUAL; } else if (is_left_dominate) { relation = DominateRelation::OBJ_LEFT_DOMINATE; } else if (is_right_dominate) { relation = DominateRelation::OBJ_RIGHT_DOMINATE; } else { relation = DominateRelation::OBJ_UNCOMPARABLE; } return ret; } int ObOptimizerUtil::compute_sharding_relationship(const ObShardingInfo *left_sharding, const ObShardingInfo *right_sharding, const EqualSets &equal_sets, DominateRelation &relation) { int ret = OB_SUCCESS; bool is_equal = false; relation = DominateRelation::OBJ_UNCOMPARABLE; if (OB_FAIL(ObShardingInfo::is_sharding_equal(left_sharding, right_sharding, equal_sets, is_equal))) { LOG_WARN("failed to check whether sharding info is equal", K(ret)); } else if (is_equal) { relation = DominateRelation::OBJ_EQUAL; } else if (NULL == left_sharding && NULL != right_sharding) { relation = DominateRelation::OBJ_RIGHT_DOMINATE; } else if (NULL != left_sharding && NULL == right_sharding) { relation = DominateRelation::OBJ_LEFT_DOMINATE; } else if (left_sharding->is_distributed_with_partitioning() && right_sharding->is_distributed_without_partitioning()) { relation = DominateRelation::OBJ_LEFT_DOMINATE; } else if (left_sharding->is_distributed_without_partitioning() && right_sharding->is_distributed_with_partitioning()) { relation = DominateRelation::OBJ_RIGHT_DOMINATE; } else { relation = DominateRelation::OBJ_UNCOMPARABLE; } return ret; } int ObOptimizerUtil::check_sharding_set_left_dominate(const ObIArray &left_sharding, const ObIArray &right_sharding, const EqualSets &equal_sets, bool &is_left_dominate) { int ret = OB_SUCCESS; is_left_dominate = true; for (int64_t i = 0; OB_SUCC(ret) && is_left_dominate && i < right_sharding.count(); i++) { bool is_find = false; DominateRelation relation = DominateRelation::OBJ_UNCOMPARABLE; for (int64_t j = 0; OB_SUCC(ret) && !is_find && j < left_sharding.count(); j++) { if (OB_FAIL(compute_sharding_relationship(left_sharding.at(j), right_sharding.at(i), equal_sets, relation))) { LOG_WARN("failed to compute sharding relationship", K(ret)); } else if (DominateRelation::OBJ_LEFT_DOMINATE == relation || DominateRelation::OBJ_EQUAL == relation) { is_find = true; } else { /*do nothing*/ } } if (OB_SUCC(ret) && !is_find) { is_left_dominate = false; } } return ret; } int ObOptimizerUtil::get_range_params(ObLogicalOperator *root, ObIArray &range_exprs, ObIArray &all_table_filters) { int ret = OB_SUCCESS; if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null logical operator", K(ret)); } else if (log_op_def::LOG_TABLE_SCAN == root->get_type()) { ObLogTableScan *scan = static_cast(root); const ObCostTableScanInfo *info = scan->get_est_cost_info(); if (NULL != info && info->pushdown_prefix_filters_.count() > 0) { if (OB_FAIL(append(range_exprs, info->pushdown_prefix_filters_))) { LOG_WARN("failed to append range exprs", K(ret)); } else if (OB_FAIL(append(all_table_filters, info->pushdown_prefix_filters_))) { LOG_WARN("failed to append pushdown prefix filters", K(ret)); } else if (OB_FAIL(append(all_table_filters, info->postfix_filters_))) { LOG_WARN("failed to append pushdown prefix filters", K(ret)); } else if (OB_FAIL(append(all_table_filters, info->table_filters_))) { LOG_WARN("failed to append pushdown prefix filters", K(ret)); } } } else { for (int64_t i = 0; OB_SUCC(ret) && i < root->get_num_of_child(); ++i) { ObLogicalOperator *child = root->get_child(i); if (OB_FAIL(SMART_CALL(get_range_params(child, range_exprs, all_table_filters)))) { LOG_WARN("failed to get range params", K(ret)); } } } return ret; } int ObOptimizerUtil::check_basic_sharding_info(const ObAddr &local_addr, const ObIArray &child_ops, bool &is_basic) { int ret = OB_SUCCESS; bool is_remote = false; is_basic = false; if (OB_FAIL(check_basic_sharding_info(local_addr, child_ops, is_basic, is_remote))) { LOG_WARN("failed to check basic sharding info", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::check_basic_sharding_info(const ObAddr &local_addr, const ObIArray &child_ops, bool &is_basic, bool &is_remote) { int ret = OB_SUCCESS; ObSEArray sharding_infos; is_basic = false; is_remote = false; for (int64_t i = 0; OB_SUCC(ret) && i < child_ops.count(); i++) { if (OB_ISNULL(child_ops.at(i)) || OB_ISNULL(child_ops.at(i)->get_sharding())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(sharding_infos.push_back(child_ops.at(i)->get_sharding()))) { LOG_WARN("failed to push back sharding infos", K(ret)); } else { /*do nothing*/ } } if (OB_FAIL(ret)) { /*do nothing*/ } else if (OB_FAIL(check_basic_sharding_info(local_addr, sharding_infos, is_basic, is_remote))) { LOG_WARN("failed to check basic sharding info", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::check_basic_sharding_info(const ObAddr &local_addr, const ObIArray &input_shardings, bool &is_basic) { int ret = OB_SUCCESS; bool is_remote = false; is_basic = false; if (OB_FAIL(check_basic_sharding_info(local_addr, input_shardings, is_basic, is_remote))) { LOG_WARN("failed to check basic sharding info", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::check_basic_sharding_info(const ObAddr &local_addr, const ObIArray &input_shardings, bool &is_basic, bool &is_remote) { int ret = OB_SUCCESS; ObAddr temp_addr; ObAddr remote_addr; int64_t local_num = 0; int64_t remote_num = 0; int64_t match_all_num = 0; int64_t dup_table_num = 0; const ObShardingInfo *sharding = NULL; ObSEArray valid_addrs; ObSEArray intersect_addrs; ObSEArray candidate_addrs; int64_t input_size = input_shardings.count(); is_basic = false; is_remote = false; if (input_size <= 1) { if (OB_ISNULL(sharding = input_shardings.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { is_basic = true; is_remote = sharding->is_remote(); } } else { is_basic = true; for (int64_t i = 0; OB_SUCC(ret) && is_basic && i < input_size; i++) { if (NULL == (sharding = input_shardings.at(i))) { is_basic = false; } else if (sharding->get_can_reselect_replica()) { dup_table_num++; valid_addrs.reuse(); if (OB_ISNULL(sharding->get_phy_table_location_info())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(get_duplicate_table_replica(*sharding->get_phy_table_location_info(), valid_addrs))) { LOG_WARN("failed to get duplicated table replica", K(ret)); } else if (intersect_addrs.empty()) { if (OB_FAIL(intersect_addrs.assign(valid_addrs))) { LOG_WARN("failed to assign addrs", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(intersect(valid_addrs, intersect_addrs, candidate_addrs))) { LOG_WARN("failed to intersect addrs", K(ret)); } else if (candidate_addrs.empty()) { is_basic = false; } else if (OB_FAIL(intersect_addrs.assign(candidate_addrs))) { LOG_WARN("failed to assign addrs", K(ret)); } else { /*do nothing*/ } } } else if (sharding->is_local()) { local_num++; } else if (sharding->is_remote()) { remote_num++; if (OB_FAIL(sharding->get_remote_addr(temp_addr))) { LOG_WARN("failed to get remote addr", K(ret)); } else if (!remote_addr.is_valid()) { remote_addr = temp_addr; } else if (remote_addr != temp_addr) { is_basic = false; } else { /*do nothing*/} } else if (sharding->is_match_all()) { match_all_num++; } else if (sharding->is_distributed()) { is_basic = false; } else { /*do nothing*/ } } if (OB_SUCC(ret) && is_basic) { if (local_num > 0 && (local_num + match_all_num + dup_table_num == input_size)) { if (dup_table_num == 0) { is_basic = true; } else if (find_item(intersect_addrs, local_addr)) { is_basic = true; } else { is_basic = false; } } else if (remote_num > 0 && (remote_num + match_all_num + dup_table_num == input_size)) { if (dup_table_num == 0) { is_basic = true; is_remote = true; } else if (find_item(intersect_addrs, remote_addr)) { is_basic = true; is_remote = true; } else { is_basic = false; } } else if (match_all_num + dup_table_num == input_size) { if (dup_table_num == 0) { is_basic = true; } else if (intersect_addrs.empty()) { is_basic = false; } else { is_basic = true; } } else { is_basic = false; } } } if (OB_SUCC(ret)) { LOG_TRACE("succeed to check basic sharding info", K(is_basic), K(is_remote)); } return ret; } int ObOptimizerUtil::compute_basic_sharding_info(const ObAddr &local_addr, const ObIArray &child_ops, ObIAllocator &allocator, ObIArray &reselected_pos, ObShardingInfo *&result_sharding, int64_t &inherit_sharding_index) { int ret = OB_SUCCESS; ObSEArray sharding_infos; result_sharding = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < child_ops.count(); i++) { if (OB_ISNULL(child_ops.at(i)) || OB_ISNULL(child_ops.at(i)->get_strong_sharding())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(child_ops.at(i)), K(ret)); } else if (OB_FAIL(sharding_infos.push_back(child_ops.at(i)->get_strong_sharding()))) { LOG_WARN("failed to push back sharding infos", K(ret)); } else { /*do nothing*/ } } if (OB_FAIL(ret)) { /*do nothing*/ } else if (OB_FAIL(compute_basic_sharding_info(local_addr, sharding_infos, allocator, reselected_pos, result_sharding, inherit_sharding_index))) { LOG_WARN("failed to compute basic sharding info", K(ret)); } else { /*do nothing*/ } return ret; } int ObOptimizerUtil::compute_basic_sharding_info(const ObAddr &local_addr, const ObIArray &input_shardings, ObIAllocator &allocator, ObIArray &reselected_pos, ObShardingInfo *&result_sharding, int64_t &inherit_sharding_index) { int ret = OB_SUCCESS; result_sharding = NULL; inherit_sharding_index = 0; if (input_shardings.count() <= 1) { result_sharding = input_shardings.at(0); inherit_sharding_index = 0; } else { ObAddr basic_addr; bool has_duplicated = false; bool can_reselect_replica = true; ObShardingInfo *sharding = NULL; ObSEArray valid_addrs; ObSEArray intersect_addrs; ObSEArray candidate_addrs; for (int64_t i = 0; OB_SUCC(ret) && i < input_shardings.count(); i++) { if (OB_ISNULL(sharding = input_shardings.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(sharding), K(ret)); } else if (sharding->get_can_reselect_replica()) { has_duplicated = true; valid_addrs.reuse(); if (OB_ISNULL(sharding->get_phy_table_location_info())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(get_duplicate_table_replica(*sharding->get_phy_table_location_info(), valid_addrs))) { LOG_WARN("failed to get duplicated table replica", K(ret)); } else if (intersect_addrs.empty()) { if (OB_FAIL(intersect_addrs.assign(valid_addrs))) { LOG_WARN("failed to assign addrs", K(ret)); } else { /*do nothing*/ } } else { if (OB_FAIL(ObOptimizerUtil::intersect(valid_addrs, intersect_addrs, candidate_addrs))) { LOG_WARN("failed to intersect addrs", K(ret)); } else if (OB_FALSE_IT(can_reselect_replica = can_reselect_replica && valid_addrs.count() == candidate_addrs.count() && valid_addrs.count() == intersect_addrs.count())) { // do nothing } else if (OB_FAIL(intersect_addrs.assign(candidate_addrs))) { LOG_WARN("failed to assign addrs", K(ret)); } else { /*do nothing*/ } } } else if (result_sharding != NULL) { //do nothing } else if (sharding->is_local()) { basic_addr = local_addr; result_sharding = sharding; inherit_sharding_index = i; } else if (sharding->is_remote()) { if (OB_FAIL(sharding->get_remote_addr(basic_addr))) { LOG_WARN("failed to get remote addr", K(ret)); } else { result_sharding = sharding; inherit_sharding_index = i; } } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (result_sharding == NULL) { if (has_duplicated) { if (OB_UNLIKELY(intersect_addrs.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret)); } else if (ObOptimizerUtil::find_item(intersect_addrs, local_addr)) { basic_addr = local_addr; } else { basic_addr = intersect_addrs.at(0); } } else { result_sharding = input_shardings.at(0); inherit_sharding_index = 0; } } if (OB_FAIL(ret)) { /*do nothing*/ } else if (!has_duplicated) { /*do nothing*/ } else if (OB_FAIL(compute_duplicate_table_replica_pos(basic_addr, input_shardings, reselected_pos))) { LOG_WARN("failed to set duplicated table replica", K(ret)); } else if (NULL != result_sharding) { /*do nothing*/ } else if (OB_UNLIKELY(input_shardings.count() != reselected_pos.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected array count", K(input_shardings.count()), K(reselected_pos.count()), K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && NULL == result_sharding && i < input_shardings.count(); i++) { if (OB_ISNULL(sharding = input_shardings.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (sharding->get_can_reselect_replica() && OB_FAIL(ObOptimizerUtil::compute_duplicate_table_sharding(local_addr, allocator, *input_shardings.at(i), reselected_pos.at(i), can_reselect_replica, result_sharding))) { LOG_WARN("failed to compute duplicate table sharding", K(ret)); } else if (NULL != result_sharding) { inherit_sharding_index = i; } } } } } if (OB_SUCC(ret) && NULL != result_sharding) { LOG_TRACE("succeed to compute basic sharding info", K(*result_sharding), K(input_shardings), K(reselected_pos)); } return ret; } int ObOptimizerUtil::get_duplicate_table_replica(const ObCandiTableLoc &phy_table_loc, ObIArray &valid_addrs) { int ret = OB_SUCCESS; if (OB_UNLIKELY(1 != phy_table_loc.get_partition_cnt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected partition count", K(ret), K(phy_table_loc.get_partition_cnt())); } else { const ObCandiTabletLoc &phy_part_loc = phy_table_loc.get_phy_part_loc_info_list().at(0); const ObIArray &replicas = phy_part_loc.get_partition_location().get_replica_locations(); for (int64_t i = 0; OB_SUCC(ret) && i < replicas.count(); ++i) { if (OB_FAIL(valid_addrs.push_back(replicas.at(i).get_server()))) { LOG_WARN("failed to push back replica address", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::compute_duplicate_table_replica_pos(const ObAddr &addr, const ObIArray &input_shardings, ObIArray &reselected_pos) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < input_shardings.count(); i++) { ObShardingInfo *sharding = NULL; int64_t replica_index = OB_INVALID_INDEX; if (OB_ISNULL(sharding = input_shardings.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(sharding), K(ret)); } else if (!sharding->get_can_reselect_replica()) { /*do nothing*/ } else if (OB_ISNULL(sharding->get_phy_table_location_info()) || OB_UNLIKELY(1 != sharding->get_phy_table_location_info()->get_partition_cnt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret)); } else { share::ObLSReplicaLocation replica_loc; ObCandiTabletLoc &phy_part_loc = sharding->get_phy_table_location_info()->get_phy_part_loc_info_list_for_update().at(0); if (!phy_part_loc.is_server_in_replica(addr, replica_index)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("no replica in this server", K(addr), K(ret)); } else if (OB_UNLIKELY(replica_index == OB_INVALID_INDEX)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid replica index", K(ret)); } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (OB_FAIL(reselected_pos.push_back(replica_index))) { LOG_WARN("failed to push back replica index", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObOptimizerUtil::compute_duplicate_table_sharding(const ObAddr &local_addr, ObIAllocator &allocator, const ObShardingInfo &src_sharding, const int64_t reselected_pos, bool can_reselect_replica, ObShardingInfo *&target_sharding) { int ret = OB_SUCCESS; ObCandiTableLoc *phy_table_loc = NULL; if (OB_ISNULL(target_sharding = reinterpret_cast( allocator.alloc(sizeof(ObShardingInfo))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else if (OB_ISNULL(phy_table_loc = reinterpret_cast( allocator.alloc(sizeof(ObCandiTableLoc))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else { target_sharding = new(target_sharding) ObShardingInfo(); phy_table_loc = new(phy_table_loc) ObCandiTableLoc(); if (OB_FAIL(target_sharding->copy_with_part_keys(src_sharding))) { LOG_WARN("failed to copy sharding info", K(ret)); } else if (OB_FAIL(phy_table_loc->assign(*src_sharding.get_phy_table_location_info()))) { LOG_WARN("failed to assign table location", K(ret)); } else if (OB_UNLIKELY(1 != phy_table_loc->get_partition_cnt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected partition count", K(ret)); } else { share::ObLSReplicaLocation replica_loc; ObCandiTabletLoc &phy_part_loc = phy_table_loc->get_phy_part_loc_info_list_for_update().at(0); phy_part_loc.set_selected_replica_idx(reselected_pos); target_sharding->set_phy_table_location_info(phy_table_loc); target_sharding->set_can_reselect_replica(can_reselect_replica); if (OB_FAIL(phy_part_loc.get_selected_replica(replica_loc))) { LOG_WARN("failed to get selected replica", K(ret)); } else if (replica_loc.get_server() == local_addr) { target_sharding->set_local(); } else { target_sharding->set_remote(); } } } 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; const 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, 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; } int64_t ObOptimizerUtil::get_join_style_parallel(const int64_t left_parallel, const int64_t right_parallel, const DistAlgo join_dist_algo, const bool use_left /* default false */) { int64_t parallel = ObGlobalHint::UNSET_PARALLEL; if (DistAlgo::DIST_BASIC_METHOD == join_dist_algo || DistAlgo::DIST_PULL_TO_LOCAL == join_dist_algo) { parallel = ObGlobalHint::DEFAULT_PARALLEL; } else if (DistAlgo::DIST_HASH_HASH == join_dist_algo || DistAlgo::DIST_PARTITION_WISE == join_dist_algo || DistAlgo::DIST_EXT_PARTITION_WISE == join_dist_algo) { parallel = (use_left || (left_parallel > right_parallel)) ? left_parallel : right_parallel; } else if (DistAlgo::DIST_BROADCAST_NONE == join_dist_algo || DistAlgo::DIST_BC2HOST_NONE == join_dist_algo || DistAlgo::DIST_HASH_NONE == join_dist_algo || DistAlgo::DIST_PARTITION_NONE == join_dist_algo) { parallel = right_parallel; } else { parallel = left_parallel; } return parallel; } bool ObOptimizerUtil::is_left_need_exchange(const ObShardingInfo &sharding, const DistAlgo dist_algo) { return dist_algo == DIST_HASH_HASH || dist_algo == DIST_HASH_NONE || dist_algo == DIST_BROADCAST_NONE || dist_algo == DIST_BC2HOST_NONE || dist_algo == DIST_PARTITION_NONE || (dist_algo == DIST_PULL_TO_LOCAL && sharding.is_sharding()); } bool ObOptimizerUtil::is_right_need_exchange(const ObShardingInfo &sharding, const DistAlgo dist_algo) { return dist_algo == DIST_HASH_HASH || dist_algo == DIST_NONE_BROADCAST || dist_algo == DIST_NONE_PARTITION || dist_algo == DIST_NONE_HASH || (dist_algo == DIST_PULL_TO_LOCAL && sharding.is_sharding()); } ObPQDistributeMethod::Type ObOptimizerUtil::get_left_dist_method(const ObShardingInfo &sharding, const DistAlgo dist_algo) { ObPQDistributeMethod::Type dist_method = ObPQDistributeMethod::NONE; if (DistAlgo::DIST_HASH_HASH == dist_algo) { dist_method = ObPQDistributeMethod::HASH; } else if (DistAlgo::DIST_BROADCAST_NONE == dist_algo) { dist_method = ObPQDistributeMethod::BROADCAST; } else if (DistAlgo::DIST_BC2HOST_NONE == dist_algo) { dist_method = ObPQDistributeMethod::BC2HOST; } else if (DistAlgo::DIST_PARTITION_NONE == dist_algo) { dist_method = ObPQDistributeMethod::PARTITION; } else if (DistAlgo::DIST_HASH_NONE == dist_algo) { dist_method = ObPQDistributeMethod::HASH; } else if (DistAlgo::DIST_PULL_TO_LOCAL == dist_algo && sharding.is_sharding()) { dist_method = ObPQDistributeMethod::LOCAL; } else { dist_method = ObPQDistributeMethod::NONE; } return dist_method; } ObPQDistributeMethod::Type ObOptimizerUtil::get_right_dist_method(const ObShardingInfo &sharding, const DistAlgo dist_algo) { ObPQDistributeMethod::Type dist_method = ObPQDistributeMethod::NONE; if (DistAlgo::DIST_HASH_HASH == dist_algo) { dist_method = ObPQDistributeMethod::HASH; } else if (DistAlgo::DIST_NONE_BROADCAST == dist_algo) { dist_method = ObPQDistributeMethod::BROADCAST; } else if (DistAlgo::DIST_NONE_PARTITION == dist_algo) { dist_method = ObPQDistributeMethod::PARTITION; } else if (DistAlgo::DIST_NONE_HASH == dist_algo) { dist_method = ObPQDistributeMethod::HASH; } else if (DistAlgo::DIST_PULL_TO_LOCAL == dist_algo && sharding.is_sharding()) { dist_method = ObPQDistributeMethod::LOCAL; } else { dist_method = ObPQDistributeMethod::NONE; } return dist_method; } int ObOptimizerUtil::generate_pullup_aggr_expr(ObRawExprFactory &expr_factory, ObSQLSessionInfo *session_info, ObAggFunRawExpr *origin_expr, ObAggFunRawExpr *&pullup_aggr) { int ret = OB_SUCCESS; pullup_aggr = NULL; if (OB_ISNULL(origin_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(origin_expr)); } else if (T_FUN_MAX == origin_expr->get_expr_type() || T_FUN_MIN == origin_expr->get_expr_type() || T_FUN_SUM == origin_expr->get_expr_type() || T_FUN_COUNT == origin_expr->get_expr_type() || T_FUN_COUNT_SUM == origin_expr->get_expr_type() || T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS == origin_expr->get_expr_type() || T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE == origin_expr->get_expr_type() || T_FUN_SYS_BIT_AND == origin_expr->get_expr_type() || T_FUN_SYS_BIT_OR == origin_expr->get_expr_type() || T_FUN_SYS_BIT_XOR == origin_expr->get_expr_type()) { /* MAX(a) -> MAX(MAX(a)), MIN(a) -> MIN(MIN(a)) SUM(a) -> SUM(SUM(a)) */ ObItemType pullup_aggr_type = origin_expr->get_expr_type(); if (T_FUN_COUNT == pullup_aggr_type) { pullup_aggr_type = T_FUN_COUNT_SUM; } else if (T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS == pullup_aggr_type) { pullup_aggr_type = T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE; } if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(expr_factory, session_info, pullup_aggr_type, origin_expr, pullup_aggr))) { LOG_WARN("failed to build common aggr expr", K(ret)); } } else if (T_FUN_GROUPING == origin_expr->get_expr_type() && origin_expr->get_real_param_count() == 1) { ObRawExpr *param_expr = origin_expr->get_real_param_exprs_for_update().at(0); if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(expr_factory, session_info, T_FUN_GROUPING, param_expr, pullup_aggr))) { LOG_WARN("failed to pullup grouping aggr expr", K(ret)); } } else if (T_FUN_TOP_FRE_HIST == origin_expr->get_expr_type()) { if (OB_UNLIKELY(3 != origin_expr->get_real_param_count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("real param count is invalid", K(ret)); } else if (OB_FAIL(expr_factory.create_raw_expr(T_FUN_TOP_FRE_HIST, pullup_aggr))) { LOG_WARN("failed to create top frequency expr", K(ret)); } else if (OB_FAIL(pullup_aggr->add_real_param_expr( origin_expr->get_real_param_exprs_for_update().at(0)))) { LOG_WARN("failed to add real param expr", K(ret)); } else if (OB_FAIL(pullup_aggr->add_real_param_expr( origin_expr))) { LOG_WARN("failed to add real param expr", K(ret)); } else if (OB_FAIL(pullup_aggr->add_real_param_expr( origin_expr->get_real_param_exprs_for_update().at(2)))) { LOG_WARN("failed to add real param expr", K(ret)); } else if (FALSE_IT(pullup_aggr->set_is_need_deserialize_row(true))) { // do nothing } else if (OB_FAIL(pullup_aggr->formalize(session_info))) { LOG_WARN("failed to formalize top fequence expr", K(ret)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected aggr type", K(ret), K(*origin_expr)); } return ret; } int ObOptimizerUtil::check_filter_before_indexback(const ObIArray &filter_exprs, const ObIArray &index_columns, ObIArray &filter_before_index_back) { int ret = OB_SUCCESS; bool contains = false; ObRawExpr *expr = NULL; ObSEArray filter_ids; for (int64_t i = 0; OB_SUCC(ret) && i < filter_exprs.count(); i++) { filter_ids.reuse(); if (OB_ISNULL(expr = filter_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(check_contain_ora_rowscn_expr(expr, contains))) { LOG_WARN("failed to check contains ora rowscan expr", K(ret)); } else if (contains) { if (OB_FAIL(filter_before_index_back.push_back(false))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } } else if (OB_FAIL(ObRawExprUtils::extract_column_ids(expr, filter_ids))) { LOG_WARN("failed to extract column ids", K(ret)); } else { contains = ObOptimizerUtil::is_subset(filter_ids, index_columns); if (OB_FAIL(filter_before_index_back.push_back(contains))) { LOG_WARN("failed to push back element", K(ret)); } else { /*do nothjing*/ } } } 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; dummy_col_item.is_geo_ = column_schema.is_geometry(); 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())) { 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::check_contain_ora_rowscn_expr(const ObRawExpr *expr, bool &contains) { int ret = OB_SUCCESS; bool is_stack_overflow = false; contains = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid raw expr", K(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_ORA_ROWSCN == expr->get_expr_type()) { contains = true; } else { for (int64_t i = 0; OB_SUCC(ret) && !contains && i < expr->get_param_count(); i++) { if (OB_FAIL(check_contain_ora_rowscn_expr(expr->get_param_expr(i), contains))) { LOG_WARN("failed to contain ora_rowscn expr", K(ret)); } else { /*do nothing*/} } } return ret; } int ObOptimizerUtil::allocate_group_id_expr(ObLogPlan *log_plan, ObRawExpr *&group_id_expr) { int ret = OB_SUCCESS; ObOptimizerContext *opt_ctx = NULL; ObOpPseudoColumnRawExpr *tmp_group_id_expr = NULL; group_id_expr = NULL; if (OB_ISNULL(log_plan) || OB_ISNULL(opt_ctx = &log_plan->get_optimizer_context()) || OB_ISNULL(opt_ctx->get_session_info())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get unexpected null", K(ret), K(log_plan), K(opt_ctx)); } else { ObExprResType res_type; res_type.set_type(ObIntType); res_type.set_accuracy(ObAccuracy::MAX_ACCURACY[ObIntType]); if (OB_FAIL(ObRawExprUtils::build_op_pseudo_column_expr(opt_ctx->get_expr_factory(), T_PSEUDO_GROUP_ID, "GROUP_ID", res_type, tmp_group_id_expr))) { } else if (OB_ISNULL(tmp_group_id_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("group expr is null", K(ret)); } else if (OB_FAIL(tmp_group_id_expr->formalize(opt_ctx->get_session_info()))) { LOG_WARN("group expr formalize failed", K(ret)); } else { group_id_expr = tmp_group_id_expr; } } return ret; } int ObOptimizerUtil::check_contribute_query_range(ObLogicalOperator *root, const ObIArray ¶ms, bool &is_valid) { int ret = OB_SUCCESS; is_valid = false; ObSEArray range_exprs; ObSEArray all_table_filters; ObSEArray range_params; ObSEArray pushdown_params; ObSEArray exec_params; if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid root", K(ret)); } else if (params.empty()) { // do nothing } else if (OB_FAIL(append(exec_params, params))) { LOG_WARN("failed to append nl params", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::get_range_params(root, range_exprs, all_table_filters))) { LOG_WARN("failed to get range_exprs", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_params(range_exprs, range_params))) { LOG_WARN("failed to extract range params", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::intersect(exec_params, range_params, pushdown_params))) { LOG_WARN("failed to get intersect params", K(ret)); } else if (pushdown_params.empty()) { // do nothing } else { is_valid = true; LOG_TRACE("pushdown filters can extend query range", K(pushdown_params)); } return ret; } int ObOptimizerUtil::check_pushdown_range_cond(ObLogicalOperator *root, bool &cnt_pd_range_cond) { int ret = OB_SUCCESS; cnt_pd_range_cond = false; if (OB_ISNULL(root)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid root", K(ret)); } else if (root->is_table_scan()) { ObLogTableScan *tsc = static_cast(root); if (OB_FAIL(check_exec_param_filter_exprs(tsc->get_range_conditions(), cnt_pd_range_cond))) { LOG_WARN("failed to check exec param filter", K(ret)); } else {/*do nothing*/} } else { for (int64_t i = 0; OB_SUCC(ret) && !cnt_pd_range_cond && i < root->get_num_of_child(); ++i) { ObLogicalOperator *child = root->get_child(i); if (OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid child", K(ret)); } else if (OB_FAIL(SMART_CALL(check_pushdown_range_cond(child, cnt_pd_range_cond)))) { LOG_WARN("failed to check pd range cond", K(ret)); } else {/*do nothing*/} } } return ret; } int ObOptimizerUtil::check_exec_param_filter_exprs(const ObIArray &input_filters, bool &has_exec_param_filters) { int ret = OB_SUCCESS; has_exec_param_filters = false; for (int i = 0; OB_SUCC(ret) && !has_exec_param_filters && i < input_filters.count(); ++i) { ObRawExpr *expr = input_filters.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->has_flag(CNT_DYNAMIC_PARAM)) { has_exec_param_filters = true; } } return ret; } int ObOptimizerUtil::check_contain_batch_stmt_parameter(ObRawExpr* expr, bool &contain) { int ret = OB_SUCCESS; contain = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (!expr->has_flag(CNT_CONST)) { //do nothing } else if (expr->is_const_raw_expr()) { ObConstRawExpr *const_expr = static_cast(expr); contain = const_expr->is_batch_stmt_parameter(); } else { for (int i = 0; !contain && OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(check_contain_batch_stmt_parameter(expr->get_param_expr(i), contain)))) { LOG_WARN("failed to check contain batch stmt parameter", K(ret)); } } } return ret; } /* Check whether src_expr can be calculated by const exprs and dst_exprs */ int ObOptimizerUtil::expr_calculable_by_exprs(const ObRawExpr *src_expr, const ObIArray &dst_exprs, bool &is_calculable) { int ret = OB_SUCCESS; is_calculable = true; if (OB_ISNULL(src_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret)); } else if (src_expr->is_const_expr()) { } else if (dst_exprs.empty()) { is_calculable = false; } else if (ObOptimizerUtil::find_item(dst_exprs, src_expr)) { } else { int64_t N = src_expr->get_param_count(); if (N > 0) { for (int64_t i = 0; OB_SUCC(ret) && is_calculable && i < N; ++i) { if (OB_FAIL(SMART_CALL(expr_calculable_by_exprs(src_expr->get_param_expr(i), dst_exprs, is_calculable)))) { LOG_WARN("failed to smart call", K(ret)); } } } else { is_calculable = false; } } return ret; } int ObOptimizerUtil::check_contain_my_exec_param(ObRawExpr* expr, const common::ObIArray & my_exec_params, bool &contain) { int ret = OB_SUCCESS; bool is_stack_overflow = false; contain = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null 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 (!expr->has_flag(CNT_DYNAMIC_PARAM)) { //do nothing } else if (expr->is_exec_param_expr()) { const ObExecParamRawExpr *exec_expr = static_cast(expr); contain = find_exec_param(my_exec_params, exec_expr); } else if (expr->is_set_op_expr() || expr->is_query_ref_expr() || expr->is_column_ref_expr()) { //do nothing } else { for (int64_t i = 0; !contain && OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(check_contain_my_exec_param(expr->get_param_expr(i), my_exec_params, contain)))) { LOG_WARN("failed to check contain batch stmt parameter", K(ret)); } } } return ret; } /* get the smallest set from which all exprs can be evaluated */ int ObOptimizerUtil::get_minset_of_exprs(const ObIArray &src_exprs, ObIArray &min_set) { int ret = OB_SUCCESS; //find expr which can not be evaluated by other exprs for (int i = 0; OB_SUCC(ret) && i < src_exprs.count(); ++i) { if (OB_ISNULL(src_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(src_exprs.at(i))); } else if (src_exprs.at(i)->get_param_count() == 0 || src_exprs.at(i)->has_flag(CNT_WINDOW_FUNC) || src_exprs.at(i)->has_flag(CNT_AGG)) { if (OB_FAIL(min_set.push_back(src_exprs.at(i)))) { LOG_WARN("fail to push back expr", K(ret)); } } else { bool calculable = true; for (int64_t j = 0; OB_SUCC(ret) && calculable && j < src_exprs.at(i)->get_param_count(); ++j) { if (OB_FAIL(ObOptimizerUtil::expr_calculable_by_exprs(src_exprs.at(i)->get_param_expr(j), src_exprs, calculable))) { LOG_WARN("fail to check if candi expr is calculable", K(ret)); } } if (OB_SUCC(ret) && !calculable) { if (OB_FAIL(min_set.push_back(src_exprs.at(i)))) { LOG_WARN("failed to push back expr", K(ret)); } } } } return ret; } int ObOptimizerUtil::check_can_encode_sortkey(const common::ObIArray &order_keys, bool &can_sort_opt, ObLogPlan& plan, double card) { int ret = OB_SUCCESS; ObSEArray sort_keys; double avg_len = 0; bool has_hint = false; can_sort_opt = true; bool old_can_opt = false; const ObOptParamHint opt_params = plan.get_optimizer_context().get_global_hint().opt_params_; if (OB_FAIL(opt_params.has_opt_param(ObOptParamHint::ENABLE_NEWSORT, has_hint))) { LOG_WARN("failed to check whether has hint param", K(ret)); } else if (has_hint) { if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::ENABLE_NEWSORT, can_sort_opt))) { LOG_WARN("failed to get bool hint param", K(ret)); } } else { can_sort_opt &= GCONF._enable_newsort; for (int64_t i = 0; OB_SUCC(ret) && can_sort_opt && i < order_keys.count(); i++) { if (!ObOrderPerservingEncoder::can_encode_sortkey( order_keys.at(i).expr_->get_data_type(), order_keys.at(i).expr_->get_collation_type())) { can_sort_opt = false; } else if (OB_FAIL(sort_keys.push_back(order_keys.at(i).expr_))) { LOG_WARN("failed to add sort key expr", K(ret)); } else { /* do nothing */ } } old_can_opt = can_sort_opt; // add width / row size policy, EN_ENABLE_NEWSORT_FORCE tracepoint will skip it if (OB_FAIL(ret)) { // do nothing } else if (!can_sort_opt) { // do nothing } else if (OB_FAIL(ObOptEstCost::estimate_width_for_exprs(plan.get_basic_table_metas(), plan.get_selectivity_ctx(), sort_keys, avg_len))) { LOG_WARN("failed to estimate width for output join column exprs", K(ret)); } else if (avg_len > 256) { can_sort_opt = false; } else if (avg_len < 64 && card < 100000) { can_sort_opt = false; } else if (avg_len > 64 && avg_len < 128 && card < 1500000 ) { can_sort_opt = false; } else { // do nothing } int tmp_ret = OB_SUCCESS; tmp_ret = OB_E(EventTable::EN_ENABLE_NEWSORT_FORCE) OB_SUCCESS; if (OB_SUCCESS != tmp_ret) { can_sort_opt = old_can_opt; } } return ret; } int ObOptimizerUtil::build_rel_ids_by_equal_set(const EqualSet& equal_set, ObRelIds& rel_ids) { int ret = OB_SUCCESS; for (int64_t j = 0; OB_SUCC(ret) && j < equal_set.count(); j++) { ObRawExpr *expr = equal_set.at(j); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (!expr->is_column_ref_expr()) { // do nothing } else if (OB_FAIL(rel_ids.add_members(expr->get_relation_ids()))) { LOG_WARN("failed to add member", K(ret)); } } return ret; } int ObOptimizerUtil::extract_equal_join_conditions(const ObIArray &equal_join_conditions, const ObRelIds &left_tables, ObIArray &left_exprs, ObIArray &right_exprs) { int ret = OB_SUCCESS; for (int64_t j = 0; OB_SUCC(ret) && j < equal_join_conditions.count(); ++j) { ObRawExpr* expr = equal_join_conditions.at(j); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL expr", K(ret)); } else if (!expr->has_flag(IS_JOIN_COND) || 2 != expr->get_param_count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected join condition", K(ret)); } else { ObRawExpr *lexpr = expr->get_param_expr(0); ObRawExpr *rexpr = expr->get_param_expr(1); if (OB_ISNULL(lexpr) || OB_ISNULL(rexpr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret)); } else if (lexpr->get_relation_ids().is_subset(left_tables)) { if (OB_FAIL(left_exprs.push_back(lexpr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(right_exprs.push_back(rexpr))) { LOG_WARN("failed to push back expr", K(ret)); } } else if (rexpr->get_relation_ids().is_subset(left_tables)) { if (OB_FAIL(left_exprs.push_back(rexpr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(right_exprs.push_back(lexpr))) { LOG_WARN("failed to push back expr", K(ret)); } } } } return ret; } int ObOptimizerUtil::build_rel_ids_by_equal_sets(const EqualSets& equal_sets, ObIArray& rel_ids_array) { int ret = OB_SUCCESS; rel_ids_array.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < equal_sets.count(); i++) { EqualSet *equal_set = equal_sets.at(i); ObRelIds rel_ids; if (OB_ISNULL(equal_set)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (OB_FAIL(build_rel_ids_by_equal_set(*equal_set, rel_ids))) { LOG_WARN("failed to build rel ids", K(ret)); } else if (OB_FAIL(rel_ids_array.push_back(rel_ids))) { LOG_WARN("failed to push back", K(ret)); } } return ret; } int ObOptimizerUtil::extract_pushdown_join_filter_quals(const ObIArray &left_quals, const ObIArray &right_quals, const ObSqlBitSet<> &right_tables, ObIArray &pushdown_left_quals, ObIArray &pushdown_right_quals) { int ret = OB_SUCCESS; if (OB_UNLIKELY(left_quals.count() != right_quals.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("quals count unexpected", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < right_quals.count(); ++i) { ObRawExpr *left_qual = left_quals.at(i); ObRawExpr *right_qual = right_quals.at(i); if (OB_ISNULL(left_qual) || OB_ISNULL(right_qual)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexplected null", K(left_qual), K(right_qual), K(ret)); // can not push down expr with subquery } else if (right_qual->has_flag(CNT_PSEUDO_COLUMN) || right_qual->has_flag(CNT_PRIOR) || right_qual->has_flag(CNT_ROWNUM)) { /* do noting */ } else if (!right_qual->get_relation_ids().is_subset(right_tables)) { /* do noting */ } else if (OB_FAIL(pushdown_right_quals.push_back(right_qual))) { LOG_WARN("failed to push back qual", K(ret)); } else if (OB_FAIL(pushdown_left_quals.push_back(left_qual))) { LOG_WARN("failed to push back qual", K(ret)); } else { /*do nothing*/ } } return ret; } int ObOptimizerUtil::pushdown_join_filter_into_subquery(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, const ObIArray &pushdown_left_quals, const ObIArray &pushdown_right_quals, ObIArray &candi_left_quals, ObIArray &candi_right_quals, 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_join_filter_quals(parent_stmt, subquery, pushdown_left_quals, pushdown_right_quals, candi_left_quals, candi_right_quals))) { LOG_WARN("failed to check pushdown filter", K(ret)); } else if (candi_right_quals.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_join_filter_quals(parent_stmt, subquery, pushdown_left_quals, pushdown_right_quals, candi_left_quals, candi_right_quals))) { LOG_WARN("failed to check pushdown filter", K(ret)); } else if (candi_right_quals.empty()) { //do thing } else { can_pushdown = true; } } return ret; } int ObOptimizerUtil::check_pushdown_join_filter_quals(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, const ObIArray &pushdown_left_quals, const ObIArray &pushdown_right_quals, ObIArray &candi_left_quals, ObIArray &candi_right_quals) { int ret = OB_SUCCESS; bool is_valid = false; ObSEArray common_exprs; if (!parent_stmt.is_set_stmt() && subquery.is_set_stmt()) { if (OB_FAIL(candi_left_quals.assign(pushdown_left_quals))) { LOG_WARN("failed to assign quals", K(ret)); } else if (OB_FAIL(candi_right_quals.assign(pushdown_right_quals))) { LOG_WARN("failed to assign quals", 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_join_filter_for_set(static_cast(parent_stmt), subquery, common_exprs, pushdown_left_quals, pushdown_right_quals, candi_left_quals, candi_right_quals))) { LOG_WARN("failed to check pushdown filter for set stmt", K(ret)); } } else { if (OB_FAIL(check_pushdown_join_filter_for_subquery(parent_stmt, subquery, common_exprs, pushdown_left_quals, pushdown_right_quals, candi_left_quals, candi_right_quals))) { LOG_WARN("failed to check pushdown filter for subquery", K(ret)); } } return ret; } int ObOptimizerUtil::check_pushdown_join_filter_for_subquery(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, ObIArray &common_exprs, const ObIArray &pushdown_left_quals, const ObIArray &pushdown_right_quals, ObIArray &candi_left_quals, ObIArray &candi_right_quals) { int ret = OB_SUCCESS; if (parent_stmt.is_set_stmt() || OB_UNLIKELY(pushdown_right_quals.count() != pushdown_left_quals.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect set stmt here", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_right_quals.count(); ++i) { ObRawExpr *pred = NULL; ObSEArray column_exprs; ObSEArray select_exprs; if (OB_ISNULL(pred = pushdown_right_quals.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; 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)) { is_simple_expr = false; } 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)) { //common_exprs为空,说明既没有windown func,也没有group by } else if (OB_FAIL(candi_right_quals.push_back(pred))) { LOG_WARN("failed to push back predicate", K(ret)); } else if (OB_FAIL(candi_left_quals.push_back(pushdown_left_quals.at(i)))) { LOG_WARN("failed to push back predicate", K(ret)); } } } } return ret; } int ObOptimizerUtil::find_expr_in_equal_sets(const EqualSets &equal_sets, const ObRawExpr *target_expr, int64_t &idx) { int ret = OB_SUCCESS; idx = OB_INVALID_ID; for (int64_t j = 0; idx == OB_INVALID_ID && j < equal_sets.count(); j++) { if (OB_ISNULL(equal_sets.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(j)); } else if (find_item(*equal_sets.at(j), target_expr)) { idx = j; } } return ret; } int ObOptimizerUtil::check_pushdown_join_filter_for_set(const ObSelectStmt &parent_stmt, const ObSelectStmt &subquery, ObIArray &common_exprs, const ObIArray &pushdown_left_quals, const ObIArray &pushdown_right_quals, ObIArray &candi_left_quals, ObIArray &candi_right_quals) { int ret = OB_SUCCESS; ObSEArray child_select_list; ObSEArray parent_select_list; if (OB_UNLIKELY(pushdown_right_quals.count() != pushdown_left_quals.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect quals count", K(ret)); } else 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)); } for (int64_t i = 0; OB_SUCC(ret) && i < pushdown_right_quals.count(); ++i) { ObSEArray view_column_exprs; ObRawExpr *expr = pushdown_right_quals.at(i); bool should_add = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (OB_FAIL(ObTransformUtils::replace_expr(parent_select_list, child_select_list, expr))) { SQL_LOG(WARN, "failed to replace expr", K(ret)); } else if (OB_FAIL(expr->extract_info())) { LOG_WARN("failed to extract info", K(ret), K(*expr)); } else if (expr->has_flag(CNT_WINDOW_FUNC) || expr->has_flag(CNT_AGG)) { } 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)) { //common_exprs为空,说明既没有windown func,也没有group by } else { should_add = true; } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObTransformUtils::replace_expr(child_select_list, parent_select_list, expr))) { SQL_LOG(WARN, "failed to replace expr", K(ret)); } else if (OB_FAIL(expr->extract_info())) { LOG_WARN("failed to extract info", K(ret), K(*expr)); } else if (!should_add) { } else if (OB_FAIL(candi_right_quals.push_back(expr))) { LOG_WARN("failed to push back predicate", K(ret)); } else if (OB_FAIL(candi_left_quals.push_back(pushdown_left_quals.at(i)))) { LOG_WARN("failed to push back predicate", K(ret)); } } return ret; } int ObOptimizerUtil::replace_column_with_select_for_partid(const ObInsertStmt *stmt, ObOptimizerContext &opt_ctx, ObRawExpr *&calc_part_id_expr) { int ret = OB_SUCCESS; // get column_item. if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null pointer", K(ret)); } else { ObRawExprCopier copier(opt_ctx.get_expr_factory()); const ObInsertTableInfo &insert_info = stmt->get_insert_table_info(); for (int64_t i = 0; OB_SUCC(ret) && i < insert_info.column_exprs_.count(); ++i) { if (OB_FAIL(copier.add_replaced_expr(insert_info.column_exprs_.at(i), insert_info.column_conv_exprs_.at(i)))) { LOG_WARN("failed to add replace pair", K(ret)); } } if (OB_FAIL(copier.copy_on_replace(calc_part_id_expr, calc_part_id_expr))) { LOG_WARN("failed to copy on replace expr", K(ret)); } } return ret; } int ObOptimizerUtil::replace_gen_column(ObLogPlan *log_plan, ObRawExpr *part_expr, ObRawExpr *&new_part_expr) { int ret = OB_SUCCESS; ObSEArray column_exprs; new_part_expr = part_expr; if (OB_ISNULL(part_expr)) { // do nothing } else if (OB_ISNULL(log_plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(part_expr, column_exprs))) { LOG_WARN("fail to extract column exprs", K(part_expr), K(ret)); } else { ObRawExprCopier copier(log_plan->get_optimizer_context().get_expr_factory()); bool cnt_gen_columns = false; for (int64_t i = 0; OB_SUCC(ret) && i < column_exprs.count(); ++i) { if (OB_ISNULL(column_exprs.at(i)) || OB_UNLIKELY(!column_exprs.at(i)->is_column_ref_expr())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else { ObColumnRefRawExpr *col = static_cast(column_exprs.at(i)); if (!col->is_generated_column()) { // do nothing } else if (OB_ISNULL(col->get_dependant_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dependant expr is null", K(ret), K(*col)); } else if (OB_FAIL(copier.add_replaced_expr(col, col->get_dependant_expr()))) { LOG_WARN("failed to add replace pair", K(ret)); } else { cnt_gen_columns = true; } } } if (OB_SUCC(ret) && cnt_gen_columns) { if (OB_FAIL(copier.copy_on_replace(part_expr, new_part_expr))) { LOG_WARN("failed to copy on replace expr", K(ret)); } } } return ret; } int ObOptimizerUtil::generate_pseudo_trans_info_expr(ObOptimizerContext &opt_ctx, const common::ObString &table_name, ObOpPseudoColumnRawExpr *&expr) { int ret = OB_SUCCESS; ObExprResType res_type; char *pseudo_name = nullptr; res_type.set_type(ObVarcharType); res_type.set_collation_type(CS_TYPE_BINARY); res_type.set_accuracy(ObAccuracy::MAX_ACCURACY[ObVarcharType]); const char *name = ".TRANS_DEBUG_INFO"; int64_t buf_len = table_name.length()+ STRLEN(name) + 1; int64_t pos = 0; if (OB_ISNULL(pseudo_name = static_cast(opt_ctx.get_allocator().alloc(buf_len)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate name buffer failed", K(ret), K(buf_len)); } else if (OB_FAIL(databuff_printf(pseudo_name, buf_len, pos, "%.*s", table_name.length(), table_name.ptr()))) { LOG_WARN("databuff print column name failed", K(ret)); } else if (OB_FAIL(databuff_printf(pseudo_name, buf_len, pos, "%.*s", static_cast(STRLEN(name)), name))) { LOG_WARN("databuff print column name failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_op_pseudo_column_expr(opt_ctx.get_expr_factory(), T_PSEUDO_ROW_TRANS_INFO_COLUMN, pseudo_name, res_type, expr))) { LOG_WARN("build operator pseudo column failed", K(ret)); } else if (OB_FAIL(expr->formalize(opt_ctx.get_session_info()))) { LOG_WARN("expr formalize failed", K(ret)); } return ret; } int ObOptimizerUtil::is_in_range_optimization_enabled(const ObGlobalHint &global_hint, ObSQLSessionInfo *session_info, bool &is_enabled) { int ret = OB_SUCCESS; bool has_hint = false; bool is_hint_enabled = false; if (OB_ISNULL(session_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(global_hint.opt_params_.get_bool_opt_param(ObOptParamHint::ENABLE_IN_RANGE_OPTIMIZATION, is_hint_enabled, has_hint))) { LOG_WARN("failed to check has opt param", K(ret)); } else if (has_hint) { is_enabled = is_hint_enabled; } else { is_enabled = session_info->is_in_range_optimization_enabled(); } return ret; } int ObOptimizerUtil::pushdown_and_rename_filter_into_subquery(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, int64_t table_id, ObOptimizerContext &opt_ctx, ObIArray &input_filters, ObIArray &push_filters, ObIArray &remain_filters, bool check_match_index) { int ret = OB_SUCCESS; ObSEArray candi_filters; bool can_pushdown = false; ObSQLSessionInfo *session_info = opt_ctx.get_session_info(); ObRawExprFactory &expr_factory = opt_ctx.get_expr_factory(); if (!input_filters.empty() && OB_FAIL(pushdown_filter_into_subquery(parent_stmt, subquery, opt_ctx, input_filters, candi_filters, remain_filters, can_pushdown, check_match_index))) { LOG_WARN("pushdown filters into left query failed", K(ret)); } else if (!candi_filters.empty() && OB_FAIL(rename_pushdown_filter(parent_stmt, subquery, table_id, session_info, expr_factory, candi_filters, push_filters))) { LOG_WARN("failed to rename pushdown filter", K(ret)); } for (int64_t i = 0 ; OB_SUCC(ret) && i < remain_filters.count(); i ++){ ObRawExpr *part_push_filter = NULL; bool can_pushdown_all = false; if (OB_FAIL(split_or_filter_into_subquery(parent_stmt, subquery, table_id, opt_ctx, remain_filters.at(i), part_push_filter, can_pushdown_all, check_match_index))) { LOG_WARN("failed to push part of the filter", K(ret)); } else if (OB_UNLIKELY(can_pushdown_all)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("can not push the whole remain filter", K(ret), KPC(remain_filters.at(i))); } else if (NULL != part_push_filter && OB_FAIL(push_filters.push_back(part_push_filter))) { LOG_WARN("failed to push back", K(ret)); } } return ret; } /** * If the filter is an or predicate, * we try to push part of it into the subquery * e.g. * select * from (select a, count(*) as cnt from t1 group by a) v where a = 1 and cnt = 1 or a = 2; * We can not push the whole filter `a = 1 and cnt = 1 or a = 2`, * But we can push `a = 1 or a = 2` into the subquery. */ int ObOptimizerUtil::split_or_filter_into_subquery(const ObDMLStmt &parent_stmt, const ObSelectStmt &subquery, int64_t table_id, ObOptimizerContext &opt_ctx, ObRawExpr *filter, ObRawExpr *&push_filter, bool &can_pushdown_all, bool check_match_index) { int ret = OB_SUCCESS; push_filter = NULL; ObRawExprFactory &expr_factory = opt_ctx.get_expr_factory(); ObSQLSessionInfo *session_info = opt_ctx.get_session_info(); if (OB_ISNULL(filter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret)); } else if (T_OP_OR != filter->get_expr_type()) { // do nothing } else { ObOpRawExpr *or_pred = static_cast(filter); ObSEArray *, 4> or_filter_params; ObSEArray parent_stmts; ObSEArray subqueries; ObSEArray table_ids; ObArenaAllocator tmp_allocator; for (int64_t i = 0; OB_SUCC(ret) && i < or_pred->get_param_count(); ++i) { ObRawExpr *cur_expr = or_pred->get_param_expr(i); ObIArray *param_exprs = NULL; void *ptr = NULL; if (OB_ISNULL(cur_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret), KPC(or_pred)); } else if (OB_ISNULL(ptr = tmp_allocator.alloc(sizeof(ObSEArray)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (FALSE_IT((param_exprs = new (ptr)ObSEArray()))) { } else if (T_OP_AND == cur_expr->get_expr_type()) { ObOpRawExpr *and_pred = static_cast(cur_expr); if (OB_FAIL(param_exprs->assign(and_pred->get_param_exprs()))) { LOG_WARN("failed to assgin predicates", K(ret)); } } else { if (OB_FAIL(param_exprs->push_back(cur_expr))) { LOG_WARN("failed to push back predicate", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(or_filter_params.push_back(param_exprs))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(parent_stmts.push_back(&parent_stmt))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(subqueries.push_back(&subquery))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(table_ids.push_back(table_id))) { LOG_WARN("failed to push back", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(split_or_filter_into_subquery(parent_stmts, subqueries, table_ids, or_filter_params, opt_ctx, push_filter, can_pushdown_all, check_match_index))) { LOG_WARN("failed to split or fitler", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < or_filter_params.count(); i ++) { if (OB_NOT_NULL(or_filter_params.at(i))) { or_filter_params.at(i)->~ObIArray(); } } } return ret; } int ObOptimizerUtil::split_or_filter_into_subquery(ObIArray &parent_stmts, ObIArray &subqueries, ObIArray &table_ids, ObIArray*> &or_filter_params, ObOptimizerContext &opt_ctx, ObRawExpr *&push_filter, bool &can_pushdown_all, bool check_match_index) { int ret = OB_SUCCESS; push_filter = NULL; ObRawExprFactory &expr_factory = opt_ctx.get_expr_factory(); ObSQLSessionInfo *session_info = opt_ctx.get_session_info(); can_pushdown_all = true; bool have_push_filter = true; ObSEArray, 2> final_push_filters; if (OB_UNLIKELY(parent_stmts.count() != subqueries.count()) || OB_UNLIKELY(subqueries.count() != table_ids.count()) || OB_UNLIKELY(table_ids.count() != or_filter_params.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param count", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && have_push_filter && i < or_filter_params.count(); ++i) { ObSEArray push_filters; ObSEArray remain_filters; bool can_push_to_where = false; if (OB_ISNULL(parent_stmts.at(i)) || OB_ISNULL(subqueries.at(i)) || OB_ISNULL(or_filter_params.at(i)) || OB_UNLIKELY(or_filter_params.at(i)->empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null stmt", K(ret)); } else if (OB_FAIL(pushdown_filter_into_subquery(*parent_stmts.at(i), *subqueries.at(i), opt_ctx, *or_filter_params.at(i), push_filters, remain_filters, can_push_to_where, check_match_index))) { LOG_WARN("failed to pushdown filter", K(ret)); } else if (push_filters.empty()){ // AND pred can not be pushed have_push_filter = false; can_pushdown_all = false; } else { // Part/All of AND pred can be pushed can_pushdown_all &= remain_filters.empty(); if (OB_FAIL(final_push_filters.push_back(push_filters))) { LOG_WARN("failed to push back", K(ret)); } } } if (OB_SUCC(ret) && have_push_filter) { ObSEArray rename_and_exprs; ObRawExpr *new_or_expr = NULL; for (int64_t i = 0 ; OB_SUCC(ret) && i < final_push_filters.count() ; i ++) { ObSEArray rename_exprs; ObRawExpr *rename_and_expr = NULL; if (OB_FAIL(rename_pushdown_filter(*parent_stmts.at(i), *subqueries.at(i), table_ids.at(i), session_info, expr_factory, final_push_filters.at(i), rename_exprs))) { LOG_WARN("failed to rename push down preds", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_and_expr(expr_factory, rename_exprs, rename_and_expr))) { LOG_WARN("failed to build and expr", K(ret)); } else if (OB_FAIL(rename_and_exprs.push_back(rename_and_expr))) { LOG_WARN("failed to push back", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObRawExprUtils::build_or_exprs(expr_factory, rename_and_exprs, new_or_expr))) { LOG_WARN("failed to build and expr", K(ret)); } else if (OB_FAIL(new_or_expr->formalize(session_info))) { LOG_WARN("failed to formalize expr", K(ret)); } else if (OB_FAIL(new_or_expr->pull_relation_id())) { LOG_WARN("failed to pull relation id and levels", K(ret)); } else { push_filter = new_or_expr; } } return ret; }